From 201a7ad1d1e258daa5abf853b82227300cbf3fd7 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Wed, 24 Feb 2021 12:01:50 -0600 Subject: [PATCH 001/378] Added prototype VScript hook handler --- sp/src/public/vscript/ivscript.h | 24 +++++- sp/src/vscript/vscript_squirrel.cpp | 111 ++++++++++++++++++++++++++++ sp/src/vscript/vscript_squirrel.nut | 92 +++++++++++++++++++++++ 3 files changed, 225 insertions(+), 2 deletions(-) diff --git a/sp/src/public/vscript/ivscript.h b/sp/src/public/vscript/ivscript.h index a1c1e856..e3744752 100644 --- a/sp/src/public/vscript/ivscript.h +++ b/sp/src/public/vscript/ivscript.h @@ -863,6 +863,15 @@ public: //-------------------------------------------------------- virtual ScriptStatus_t ExecuteFunction( HSCRIPT hFunction, ScriptVariant_t *pArgs, int nArgs, ScriptVariant_t *pReturn, HSCRIPT hScope, bool bWait ) = 0; +#ifdef MAPBASE_VSCRIPT + //-------------------------------------------------------- + // Hooks + //-------------------------------------------------------- + virtual bool ScopeIsHooked( HSCRIPT hScope, const char *pszEventName ) = 0; + virtual HSCRIPT LookupHookFunction( const char *pszEventName, HSCRIPT hScope, bool &bLegacy ) = 0; + virtual ScriptStatus_t ExecuteHookFunction( const char *pszEventName, HSCRIPT hFunction, ScriptVariant_t *pArgs, int nArgs, ScriptVariant_t *pReturn, HSCRIPT hScope, bool bWait ) = 0; +#endif + //-------------------------------------------------------- // External functions //-------------------------------------------------------- @@ -1576,12 +1585,13 @@ struct ScriptHook_t // Cached for when CanRunInScope() is called before Call() HSCRIPT m_hFunc; + bool m_bLegacy; // Checks if there's a function of this name which would run in this scope HSCRIPT CanRunInScope( HSCRIPT hScope ) { extern IScriptVM *g_pScriptVM; - m_hFunc = g_pScriptVM->LookupFunction( m_desc.m_pszScriptName, hScope ); + m_hFunc = g_pScriptVM->LookupHookFunction( m_desc.m_pszScriptName, hScope, m_bLegacy ); return m_hFunc; } @@ -1605,7 +1615,8 @@ struct ScriptHook_t // Make sure we have a function in this scope if (!m_hFunc && !CanRunInScope(hScope)) return false; - else + // Legacy + else if (m_bLegacy) { for (int i = 0; i < m_desc.m_Parameters.Count(); i++) { @@ -1626,6 +1637,15 @@ struct ScriptHook_t return true; } + // New Hook System + else + { + g_pScriptVM->ExecuteHookFunction( m_desc.m_pszScriptName, m_hFunc, pArgs, m_desc.m_Parameters.Count(), pReturn, hScope, true ); + if (bRelease) + g_pScriptVM->ReleaseFunction( m_hFunc ); + m_hFunc = NULL; + return true; + } return false; } diff --git a/sp/src/vscript/vscript_squirrel.cpp b/sp/src/vscript/vscript_squirrel.cpp index 2c80041b..e671f5ff 100644 --- a/sp/src/vscript/vscript_squirrel.cpp +++ b/sp/src/vscript/vscript_squirrel.cpp @@ -161,6 +161,13 @@ public: //-------------------------------------------------------- virtual ScriptStatus_t ExecuteFunction(HSCRIPT hFunction, ScriptVariant_t* pArgs, int nArgs, ScriptVariant_t* pReturn, HSCRIPT hScope, bool bWait) override; + //-------------------------------------------------------- + // Hooks + //-------------------------------------------------------- + virtual bool ScopeIsHooked( HSCRIPT hScope, const char *pszEventName ) override; + virtual HSCRIPT LookupHookFunction( const char *pszEventName, HSCRIPT hScope, bool &bLegacy ) override; + virtual ScriptStatus_t ExecuteHookFunction( const char *pszEventName, HSCRIPT hFunction, ScriptVariant_t *pArgs, int nArgs, ScriptVariant_t *pReturn, HSCRIPT hScope, bool bWait ) override; + //-------------------------------------------------------- // External functions //-------------------------------------------------------- @@ -1986,6 +1993,110 @@ ScriptStatus_t SquirrelVM::ExecuteFunction(HSCRIPT hFunction, ScriptVariant_t* p return SCRIPT_DONE; } +bool SquirrelVM::ScopeIsHooked( HSCRIPT hScope, const char *pszEventName ) +{ + Assert( hScope && hScope != INVALID_HSCRIPT ); + + sq_pushroottable(vm_); + sq_pushstring(vm_, "Hooks", -1); + sq_get(vm_, -2); + sq_pushstring(vm_, "ScopeHookedToEvent", -1); + sq_get(vm_, -2); + sq_push(vm_, -2); + sq_pushobject(vm_, *((HSQOBJECT*)hScope)); + sq_pushstring(vm_, pszEventName, -1); + sq_call(vm_, 3, SQTrue, SQTrue); + + SQBool val; + if (SQ_FAILED(sq_getbool(vm_, -1, &val))) + { + sq_pop(vm_, 3); + return false; + } + + sq_pop(vm_, 3); + return val ? true : false; +} + +HSCRIPT SquirrelVM::LookupHookFunction(const char *pszEventName, HSCRIPT hScope, bool &bLegacy) +{ + HSCRIPT hFunc = LookupFunction( pszEventName, hScope ); + if (hFunc) + { + bLegacy = true; + return hFunc; + } + else + { + bLegacy = false; + } + + if (!ScopeIsHooked(hScope, pszEventName)) + return nullptr; + + sq_pushroottable(vm_); + sq_pushstring(vm_, "Hooks", -1); + sq_get(vm_, -2); + sq_pushstring(vm_, "CallHooks", -1); + sq_get(vm_, -2); + + HSQOBJECT obj; + sq_resetobject(&obj); + sq_getstackobj(vm_, -1, &obj); + sq_addref(vm_, &obj); + sq_pop(vm_, 2); + + HSQOBJECT* pObj = new HSQOBJECT; + *pObj = obj; + return (HSCRIPT)pObj; +} + +ScriptStatus_t SquirrelVM::ExecuteHookFunction(const char *pszEventName, HSCRIPT hFunction, ScriptVariant_t* pArgs, int nArgs, ScriptVariant_t* pReturn, HSCRIPT hScope, bool bWait) +{ + SquirrelSafeCheck safeCheck(vm_); + if (!hFunction) + return SCRIPT_ERROR; + + if (hFunction == INVALID_HSCRIPT) + return SCRIPT_ERROR; + + HSQOBJECT* pFunc = (HSQOBJECT*)hFunction; + sq_pushobject(vm_, *pFunc); + + // TODO: Run in hook scope + sq_pushroottable(vm_); + + sq_pushstring(vm_, pszEventName, -1); + sq_pushobject(vm_, *((HSQOBJECT*)hScope)); + + for (int i = 0; i < nArgs; ++i) + { + PushVariant(vm_, pArgs[i]); + } + + bool hasReturn = pReturn != nullptr; + + if (SQ_FAILED(sq_call(vm_, nArgs + 3, hasReturn, SQTrue))) + { + sq_pop(vm_, 1); + return SCRIPT_ERROR; + } + + if (hasReturn) + { + if (!getVariant(vm_, -1, *pReturn)) + { + sq_pop(vm_, 1); + return SCRIPT_ERROR; + } + + sq_pop(vm_, 1); + } + + sq_pop(vm_, 1); + return SCRIPT_DONE; +} + void SquirrelVM::RegisterFunction(ScriptFunctionBinding_t* pScriptFunction) { SquirrelSafeCheck safeCheck(vm_); diff --git a/sp/src/vscript/vscript_squirrel.nut b/sp/src/vscript/vscript_squirrel.nut index cb929807..bae6bd0d 100644 --- a/sp/src/vscript/vscript_squirrel.nut +++ b/sp/src/vscript/vscript_squirrel.nut @@ -106,6 +106,98 @@ class CSimpleCallChainer chain = null; } +//--------------------------------------------------------- +// Hook handler +//--------------------------------------------------------- +Hooks <- { Registered = {} } + +function Hooks::Add( scope, event, func, name ) +{ + Hooks.Registered[name] <- [event, scope, func]; +} + +function Hooks::Remove( name ) +{ + Hooks.Registered.rawdelete(name); +} + +function Hooks::ScopeHookedToEvent( scope, event ) +{ + //printl("Running ScopeHookedToEvent()") + foreach (elem in Hooks.Registered) + { + if (elem[1] == scope && elem[0] == event) + return true + } + return false +} + +function Hooks::CallHooks(event, scope, ...) +{ + //printl("vargv.len() = " + vargv.len()) + switch (vargv.len()) + { + case 0: + foreach (elem in Hooks.Registered) + { + if (elem[0] == event && elem[1] == scope) + return elem[2]() + } + break; + + case 1: + foreach (elem in Hooks.Registered) + { + if (elem[0] == event && elem[1] == scope) + return elem[2](vargv[0]) + } + break; + + case 2: + foreach (elem in Hooks.Registered) + { + if (elem[0] == event && elem[1] == scope) + return elem[2](vargv[0], vargv[1]) + } + break; + + case 3: + foreach (elem in Hooks.Registered) + { + if (elem[0] == event && elem[1] == scope) + return elem[2](vargv[0], vargv[1], vargv[2]) + } + break; + + case 4: + foreach (elem in Hooks.Registered) + { + if (elem[0] == event && elem[1] == scope) + return elem[2](vargv[0], vargv[1], vargv[2], vargv[3]) + } + break; + + case 5: + foreach (elem in Hooks.Registered) + { + if (elem[0] == event && elem[1] == scope) + return elem[2](vargv[0], vargv[1], vargv[2], vargv[3], vargv[4]) + } + break; + + case 6: + foreach (elem in Hooks.Registered) + { + if (elem[0] == event && elem[1] == scope) + return elem[2](vargv[0], vargv[1], vargv[2], vargv[3], vargv[4], vargv[5]) + } + break; + } +} + +//--------------------------------------------------------- +// Documentation +//--------------------------------------------------------- __Documentation <- {} local DocumentedFuncs = {} From d081a0cee37fd606555d3e5032b40bc8809c23f6 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Mon, 8 Mar 2021 02:11:13 -0600 Subject: [PATCH 002/378] Added prototype Response System library port from the Alien Swarm SDK --- sp/src/game/client/client_base.vpc | 3 +- sp/src/game/client/client_mapbase.vpc | 1 + sp/src/game/server/AI_Criteria.h | 4 + sp/src/game/server/ai_baseactor.cpp | 4 + sp/src/game/server/ai_basenpc.cpp | 4 + sp/src/game/server/ai_basenpc.h | 2 + sp/src/game/server/ai_behavior_lead.h | 7 + sp/src/game/server/ai_expresserfollowup.cpp | 471 +++ sp/src/game/server/ai_playerally.cpp | 69 + sp/src/game/server/ai_playerally.h | 6 + sp/src/game/server/ai_speech.h | 4 + sp/src/game/server/ai_speech_new.cpp | 1473 +++++++++ sp/src/game/server/ai_speech_new.h | 664 ++++ sp/src/game/server/ai_speechqueue.cpp | 475 +++ sp/src/game/server/ai_speechqueue.h | 239 ++ sp/src/game/server/baseentity.cpp | 143 +- sp/src/game/server/baseentity.h | 19 +- sp/src/game/server/baseflex.h | 2 + sp/src/game/server/basemultiplayerplayer.cpp | 11 +- sp/src/game/server/basemultiplayerplayer.h | 2 +- .../game/server/hl2/ai_behavior_actbusy.cpp | 4 + sp/src/game/server/hl2/ai_behavior_police.cpp | 10 + sp/src/game/server/hl2/env_speaker.cpp | 53 + sp/src/game/server/hl2/npc_combine.cpp | 4 + sp/src/game/server/hl2/npc_metropolice.cpp | 4 + sp/src/game/server/hl2/npc_zombie.cpp | 14 +- sp/src/game/server/sceneentity.cpp | 95 + sp/src/game/server/sceneentity.h | 3 + sp/src/game/server/server_base.vpc | 15 +- sp/src/game/server/server_mapbase.vpc | 5 + sp/src/game/shared/ai_criteria_new.cpp | 38 + sp/src/game/shared/ai_criteria_new.h | 41 + sp/src/game/shared/ai_responsesystem_new.cpp | 1271 ++++++++ sp/src/game/shared/ai_responsesystem_new.h | 29 + sp/src/game/shared/ai_speechconcept.cpp | 28 + sp/src/game/shared/ai_speechconcept.h | 45 + sp/src/public/datamap.h | 8 + .../responserules/response_host_interface.h | 66 + sp/src/public/responserules/response_types.h | 458 +++ .../public/responserules/rr_speechconcept.h | 57 + sp/src/public/tier0/basetypes.h | 64 + sp/src/public/tier0/platform.h | 23 - .../{game/shared => public/tier1}/interval.h | 0 sp/src/responserules/runtime/criteriaset.cpp | 477 +++ .../responserules/runtime/response_rules.vpc | 41 + .../responserules/runtime/response_system.cpp | 2829 +++++++++++++++++ .../responserules/runtime/response_system.h | 316 ++ .../responserules/runtime/response_types.cpp | 279 ++ .../runtime/response_types_internal.cpp | 120 + .../runtime/response_types_internal.h | 553 ++++ sp/src/responserules/runtime/rr_convars.cpp | 14 + sp/src/responserules/runtime/rr_response.cpp | 371 +++ .../runtime/rr_speechconcept.cpp | 73 + sp/src/responserules/runtime/rrbase.h | 59 + sp/src/responserules/runtime/rrrlib.cpp | 13 + sp/src/responserules/runtime/stdafx.cpp | 11 + sp/src/{game/shared => tier1}/interval.cpp | 0 sp/src/tier1/tier1.vpc | 1 + sp/src/vpc_scripts/groups.vgc | 16 + sp/src/vpc_scripts/projects.vgc | 5 + sp/src/vpc_scripts/source_base.vpc | 3 + 61 files changed, 11056 insertions(+), 63 deletions(-) create mode 100644 sp/src/game/server/ai_expresserfollowup.cpp create mode 100644 sp/src/game/server/ai_speech_new.cpp create mode 100644 sp/src/game/server/ai_speech_new.h create mode 100644 sp/src/game/server/ai_speechqueue.cpp create mode 100644 sp/src/game/server/ai_speechqueue.h create mode 100644 sp/src/game/shared/ai_criteria_new.cpp create mode 100644 sp/src/game/shared/ai_criteria_new.h create mode 100644 sp/src/game/shared/ai_responsesystem_new.cpp create mode 100644 sp/src/game/shared/ai_responsesystem_new.h create mode 100644 sp/src/game/shared/ai_speechconcept.cpp create mode 100644 sp/src/game/shared/ai_speechconcept.h create mode 100644 sp/src/public/responserules/response_host_interface.h create mode 100644 sp/src/public/responserules/response_types.h create mode 100644 sp/src/public/responserules/rr_speechconcept.h rename sp/src/{game/shared => public/tier1}/interval.h (100%) create mode 100644 sp/src/responserules/runtime/criteriaset.cpp create mode 100644 sp/src/responserules/runtime/response_rules.vpc create mode 100644 sp/src/responserules/runtime/response_system.cpp create mode 100644 sp/src/responserules/runtime/response_system.h create mode 100644 sp/src/responserules/runtime/response_types.cpp create mode 100644 sp/src/responserules/runtime/response_types_internal.cpp create mode 100644 sp/src/responserules/runtime/response_types_internal.h create mode 100644 sp/src/responserules/runtime/rr_convars.cpp create mode 100644 sp/src/responserules/runtime/rr_response.cpp create mode 100644 sp/src/responserules/runtime/rr_speechconcept.cpp create mode 100644 sp/src/responserules/runtime/rrbase.h create mode 100644 sp/src/responserules/runtime/rrrlib.cpp create mode 100644 sp/src/responserules/runtime/stdafx.cpp rename sp/src/{game/shared => tier1}/interval.cpp (100%) diff --git a/sp/src/game/client/client_base.vpc b/sp/src/game/client/client_base.vpc index 29e5acc6..daf5bf41 100644 --- a/sp/src/game/client/client_base.vpc +++ b/sp/src/game/client/client_base.vpc @@ -536,7 +536,6 @@ $Project "$SRCDIR\public\dt_utlvector_recv.cpp" \ "$SRCDIR\public\filesystem_helpers.cpp" \ "$SRCDIR\public\interpolatortypes.cpp" \ - "$SRCDIR\game\shared\interval.cpp" \ "$SRCDIR\common\language.cpp" \ "$SRCDIR\public\networkvar.cpp" \ "$SRCDIR\common\randoverride.cpp" \ @@ -1107,6 +1106,7 @@ $Project $File "$SRCDIR\public\vgui_controls\WizardSubPanel.h" $File "$SRCDIR\public\worldsize.h" $File "$SRCDIR\public\zip_uncompressed.h" + $File "$SRCDIR\public\tier1\interval.h" //Haptics $File "$SRCDIR\public\haptics\ihaptics.h" [$WIN32] $File "$SRCDIR\public\haptics\haptic_utils.h" [$WIN32] @@ -1163,7 +1163,6 @@ $Project $File "$SRCDIR\game\shared\igamesystem.h" $File "$SRCDIR\game\shared\imovehelper.h" $File "$SRCDIR\game\shared\in_buttons.h" - $File "$SRCDIR\game\shared\interval.h" $File "$SRCDIR\game\shared\iplayeranimstate.h" $File "$SRCDIR\game\shared\ipredictionsystem.h" $File "$SRCDIR\game\shared\itempents.h" diff --git a/sp/src/game/client/client_mapbase.vpc b/sp/src/game/client/client_mapbase.vpc index 243324f1..a6d7fe29 100644 --- a/sp/src/game/client/client_mapbase.vpc +++ b/sp/src/game/client/client_mapbase.vpc @@ -12,6 +12,7 @@ $Configuration $PreprocessorDefinitions "$BASE;MAPBASE_RPC;DISCORD_RPC;STEAM_RPC" [$MAPBASE_RPC] $PreprocessorDefinitions "$BASE;MAPBASE_VSCRIPT" [$MAPBASE_VSCRIPT] + $PreprocessorDefinitions "$BASE;NEW_RESPONSE_SYSTEM" [$NEW_RESPONSE_SYSTEM] } } diff --git a/sp/src/game/server/AI_Criteria.h b/sp/src/game/server/AI_Criteria.h index 81ddc169..53277858 100644 --- a/sp/src/game/server/AI_Criteria.h +++ b/sp/src/game/server/AI_Criteria.h @@ -4,6 +4,9 @@ // //=============================================================================// +#ifdef NEW_RESPONSE_SYSTEM +#include "ai_criteria_new.h" +#else #ifndef AI_CRITERIA_H #define AI_CRITERIA_H #ifdef _WIN32 @@ -276,3 +279,4 @@ private: }; #endif // AI_CRITERIA_H +#endif diff --git a/sp/src/game/server/ai_baseactor.cpp b/sp/src/game/server/ai_baseactor.cpp index 2ddc60f7..09940829 100644 --- a/sp/src/game/server/ai_baseactor.cpp +++ b/sp/src/game/server/ai_baseactor.cpp @@ -2033,7 +2033,11 @@ bool CAI_BaseActor::UseSemaphore( void ) CAI_Expresser *CAI_BaseActor::CreateExpresser() { +#ifdef NEW_RESPONSE_SYSTEM + m_pExpresser = new CAI_ExpresserWithFollowup(this); +#else m_pExpresser = new CAI_Expresser(this); +#endif return m_pExpresser; } diff --git a/sp/src/game/server/ai_basenpc.cpp b/sp/src/game/server/ai_basenpc.cpp index 6333ed86..ad174778 100644 --- a/sp/src/game/server/ai_basenpc.cpp +++ b/sp/src/game/server/ai_basenpc.cpp @@ -15233,7 +15233,11 @@ void CAI_BaseNPC::CalculateValidEnemyInteractions( void ) const char *p = STRING(pInteraction->MiscCriteria); while ( p ) { +#ifdef NEW_RESPONSE_SYSTEM + p = SplitContext( p, key, sizeof( key ), value, sizeof( value ), NULL, STRING(pInteraction->MiscCriteria) ); +#else p = SplitContext( p, key, sizeof( key ), value, sizeof( value ), NULL ); +#endif index = set.FindCriterionIndex(key); if (index != -1) diff --git a/sp/src/game/server/ai_basenpc.h b/sp/src/game/server/ai_basenpc.h index c37ba2fc..284a315a 100644 --- a/sp/src/game/server/ai_basenpc.h +++ b/sp/src/game/server/ai_basenpc.h @@ -64,7 +64,9 @@ class CBaseGrenade; class CBaseDoor; class CBasePropDoor; struct AI_Waypoint_t; +#ifndef NEW_RESPONSE_SYSTEM class AI_Response; +#endif class CBaseFilter; typedef CBitVec CAI_ScheduleBits; diff --git a/sp/src/game/server/ai_behavior_lead.h b/sp/src/game/server/ai_behavior_lead.h index 2104b1f2..ef4bb025 100644 --- a/sp/src/game/server/ai_behavior_lead.h +++ b/sp/src/game/server/ai_behavior_lead.h @@ -9,12 +9,19 @@ #include "simtimer.h" #include "ai_behavior.h" +#ifdef NEW_RESPONSE_SYSTEM +#include "ai_speechconcept.h" +#endif #if defined( _WIN32 ) #pragma once #endif +#ifdef NEW_RESPONSE_SYSTEM +typedef CAI_Concept AIConcept_t; +#else typedef const char *AIConcept_t; +#endif // Speak concepts #define TLK_LEAD_START "TLK_LEAD_START" diff --git a/sp/src/game/server/ai_expresserfollowup.cpp b/sp/src/game/server/ai_expresserfollowup.cpp new file mode 100644 index 00000000..ff49d535 --- /dev/null +++ b/sp/src/game/server/ai_expresserfollowup.cpp @@ -0,0 +1,471 @@ +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" + +#include "ai_speech.h" + +#include "game.h" +#include "eventqueue.h" +#include "ai_basenpc.h" +#include "basemultiplayerplayer.h" +#include "ai_baseactor.h" +#include "sceneentity.h" +//#include "flex_expresser.h" +/* +#include "engine/ienginesound.h" +#include "keyvalues.h" +#include "ai_criteria.h" +#include "isaverestore.h" +#include "sceneentity.h" +*/ + + + +// memdbgon must be the last include file in a .cpp file!!! +#include + +static const char *GetResponseName( CBaseEntity *pEnt ) +{ + Assert( pEnt ); + if ( pEnt == NULL ) + return ""; + return STRING( pEnt->GetEntityName() ); +} + +// This is a tiny helper function for below -- what I'd use a lambda for, usually +static void DispatchComeback( CAI_ExpresserWithFollowup *pExpress, CBaseEntity *pSpeaker, CBaseEntity *pRespondent, AI_ResponseFollowup &followup ) +{ + AssertMsg(pSpeaker != NULL, "Response expressor somehow got called with a NULL Outer.\n"); + if ( !pRespondent ) + { + return; + } + + float delay = followup.followup_delay; + if (pSpeaker == pRespondent && delay < 0) + { + Warning("Response rule with a 'self' target specified negative delay, which isn't legal because that would make someone talk over himself."); + delay = 0; + } + + // Msg( "%s: Dispatch comeback about %s to %s\n", pSpeaker->GetBotString(), g_pConceptManager->GetTopicName( handle ), pRespondent->GetBotString() ); + + // build an input event that we will use to force the bot to talk through the IO system + variant_t value; + // Don't send along null contexts + if (followup.followup_contexts && followup.followup_contexts[0] != '\0') + { + value.SetString( MAKE_STRING( followup.followup_contexts ) ); + g_EventQueue.AddEvent( pRespondent, "AddContext", value, delay - 0.01, pSpeaker, pSpeaker ); + } + + /* + value.SetString(MAKE_STRING(followup.followup_concept)); + g_EventQueue.AddEvent( pRespondent, "SpeakResponseConcept", value, delay , pSpeaker, pSpeaker ); + */ + + AI_CriteriaSet criteria; + + // add in the FROM context so dispatchee knows was from me + const char * RESTRICT pszSpeakerName = GetResponseName( pSpeaker ); + criteria.AppendCriteria( "From", pszSpeakerName ); + // if a SUBJECT criteria is missing, put it back in. + if ( criteria.FindCriterionIndex( "Subject" ) == -1 ) + { + criteria.AppendCriteria( "Subject", pszSpeakerName ); + } + + // add in any provided contexts from the parameters onto the ones stored in the followup + criteria.Merge( followup.followup_contexts ); + + // This is kludgy and needs to be fixed in class hierarchy, but for now, try to guess at the most likely + // kinds of targets and dispatch to them. + if (CBaseMultiplayerPlayer *pPlayer = dynamic_cast(pRespondent)) + { + pPlayer->Speak( followup.followup_concept, &criteria ); + } + + else if (CAI_BaseActor *pActor = dynamic_cast(pRespondent)) + { + pActor->Speak( followup.followup_concept, &criteria ); + } +} + +#if 0 +//----------------------------------------------------------------------------- +// Purpose: Placeholder for rules based response system +// Input : concept - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CAI_ExpresserWithFollowup::Speak( AIConcept_t &concept, const char *modifiers /*= NULL*/, char *pszOutResponseChosen /* = NULL*/, size_t bufsize /* = 0 */, IRecipientFilter *filter /* = NULL */ ) +{ + AI_Response *result = SpeakFindResponse( concept, modifiers ); + if ( !result ) + { + return false; + } + + CNPC_CompanionBot *pBot = dynamic_cast(GetOuter()); + if ( pBot ) + { + pBot->SetConversationTopic( g_pConceptManager->GetTopic( handle ) ); + pBot->SetLastSpeaker( g_pConceptManager->GetSpeaker( handle ) ); + // Msg( "%s: Conversing about %s\n", pBot->GetBotString(), g_pConceptManager->GetTopicName( handle ) ); + } + + SpeechMsg( GetOuter(), "%s (%x) spoke %s (%f)\n", STRING(GetOuter()->GetEntityName()), GetOuter(), g_pConceptManager->GetConcept( handle ), gpGlobals->curtime ); + + bool spoke = SpeakDispatchResponse( handle, result, filter ); + if ( pszOutResponseChosen ) + { + result->GetResponse( pszOutResponseChosen, bufsize ); + } + + return spoke; +} +#endif + + +// Work out the character from the "subject" context. +// Right now, this is a simple find by entity name search. +// But you can define arbitrary subject names, like L4D does +// for "biker", "manager", etc. +static CBaseEntity *AscertainSpeechSubjectFromContext( AI_Response *response, AI_CriteriaSet &criteria, const char *pContextName ) +{ + const char *subject = criteria.GetValue( criteria.FindCriterionIndex( pContextName ) ); + if (subject) + { + + return gEntList.FindEntityByName( NULL, subject ); + + } + else + { + return NULL; + } +} + +// TODO: Currently uses awful stricmp. Use symbols! Once I know which ones we want, that is. +static CResponseQueue::CFollowupTargetSpec_t ResolveFollowupTargetToEntity( AIConcept_t &concept, AI_CriteriaSet &criteria, const char * RESTRICT szTarget, AI_Response * RESTRICT response = NULL ) +{ + + + + if ( Q_stricmp(szTarget, "self") == 0 ) + { + return CResponseQueue::CFollowupTargetSpec_t( kDRT_SPECIFIC, concept.GetSpeaker() ); + } + else if ( Q_stricmp(szTarget, "subject") == 0 ) + { + return CResponseQueue::CFollowupTargetSpec_t( AscertainSpeechSubjectFromContext( response, criteria, "Subject" ) ); + } + else if ( Q_stricmp(szTarget, "from") == 0 ) + { + return CResponseQueue::CFollowupTargetSpec_t( AscertainSpeechSubjectFromContext( response, criteria, "From" ) ); + } + else if ( Q_stricmp(szTarget, "any") == 0 ) + { + return CResponseQueue::CFollowupTargetSpec_t( kDRT_ANY, concept.GetSpeaker() ); + } + else if ( Q_stricmp(szTarget, "all") == 0 ) + { + return CResponseQueue::CFollowupTargetSpec_t( kDRT_ALL ); + } + + // last resort, try a named lookup +#ifdef MAPBASE + else if ( CBaseEntity *pSpecific = gEntList.FindEntityByName(NULL, szTarget, concept.GetSpeaker()) ) // it could be anything +#else + else if ( CBaseEntity *pSpecific = gEntList.FindEntityByName(NULL, szTarget) ) // it could be anything +#endif + { + return CResponseQueue::CFollowupTargetSpec_t( pSpecific ); + } + + Warning("Couldn't resolve response target %s\n", szTarget ); + return CResponseQueue::CFollowupTargetSpec_t(); // couldn't resolve. +} + + +// TODO: Currently uses awful stricmp. Use symbols! Once I know which ones we want, that is. +static CResponseQueue::CFollowupTargetSpec_t ResolveFollowupTargetToEntity( AIConcept_t &concept, AI_CriteriaSet &criteria, AI_Response * RESTRICT response, AI_ResponseFollowup * RESTRICT followup ) +{ + const char * RESTRICT szTarget = followup->followup_target; + const CResponseQueue::CFollowupTargetSpec_t INVALID; // default: invalid result + if ( szTarget == NULL ) + return INVALID; + else + return ResolveFollowupTargetToEntity( concept, criteria, szTarget, response ); +} + + +ConVar chet_debug_idle( "chet_debug_idle", "0", FCVAR_ARCHIVE, "If set one, many debug prints to help track down the TLK_IDLE issue. Set two for super verbose info" ); +// extern ConVar chet_debug_idle; +bool CAI_ExpresserWithFollowup::Speak( AIConcept_t &concept, const char *modifiers /*= NULL*/, char *pszOutResponseChosen /* = NULL*/, size_t bufsize /* = 0 */, IRecipientFilter *filter /* = NULL */ ) +{ + VPROF("CAI_Expresser::Speak"); + if ( IsSpeechGloballySuppressed() ) + { + return false; + } + + concept.SetSpeaker(GetOuter()); + AI_CriteriaSet criteria; + GatherCriteria(&criteria, concept, modifiers); + GetOuter()->ModifyOrAppendDerivedCriteria(criteria); + AI_Response result; + if ( !FindResponse( result, concept, &criteria ) ) + { + if (chet_debug_idle.GetBool()) + { + + const char *name = GetOuter()->GetDebugName(); + + Msg( "TLK_IDLE: %s did not FindResponse\n", name ); + } + return false; + } + else + { + if (chet_debug_idle.GetBool()) + { + + + const char *name = GetOuter()->GetDebugName(); + + Msg( "TLK_IDLE: %s SUCCESSFUL FindResponse\n", name ); + } + } + + SpeechMsg( GetOuter(), "%s (%x) spoke %s (%f)", STRING(GetOuter()->GetEntityName()), GetOuter(), (const char*)concept, gpGlobals->curtime ); + // Msg( "%s:%s to %s:%s\n", GetOuter()->GetDebugName(), concept.GetStringConcept(), criteria.GetValue(criteria.FindCriterionIndex("Subject")), pTarget ? pTarget->GetDebugName() : "none" ); + + bool spoke = SpeakDispatchResponse( concept, &result, &criteria, filter ); + if ( pszOutResponseChosen ) + { + result.GetResponse( pszOutResponseChosen, bufsize ); + } + + return spoke; +} + +extern ISoundEmitterSystemBase* soundemitterbase; + +static float GetSpeechDurationForResponse( const AI_Response * RESTRICT response, const char *szActorModel) +{ + switch (response->GetType()) + { + case ResponseRules::RESPONSE_SCENE: + { + char szScene[MAX_PATH]; + soundemitterbase->GenderExpandString(szActorModel, response->GetResponsePtr(), szScene, MAX_PATH); + return GetSceneSpeechDuration(szScene); + } + break; + default: + break; + } + + return 0.f; +} + +//----------------------------------------------------------------------------- +// Purpose: Dispatches the result +// Input : *response - +//----------------------------------------------------------------------------- +bool CAI_ExpresserWithFollowup::SpeakDispatchResponse( AIConcept_t &concept, AI_Response *response, AI_CriteriaSet *criteria, IRecipientFilter *filter ) +{ + // This gives the chance for the other bot to respond. + if ( !concept.GetSpeaker().IsValid() ) + { + concept.SetSpeaker(GetOuter()); + } + + bool bInterrupted = IsSpeaking(); + bool bSuc = CAI_Expresser::SpeakDispatchResponse( concept, response, criteria, filter ); + if (!bSuc) + { + return false; + } + + if ( bInterrupted ) + { + g_ResponseQueueManager.GetQueue()->RemoveSpeechQueuedFor( GetOuter() ); + } + + // Record my followup details so that I may defer its use til end of the speech + AI_ResponseFollowup * RESTRICT followup = response->GetParams()->m_pFollowup; + if ( followup ) + { + if ( followup->followup_entityiotarget && followup->followup_entityioinput ) + { +#ifdef MAPBASE + CBaseEntity * RESTRICT pTarget = ResolveFollowupTargetToEntity( concept, *criteria, followup->followup_entityiotarget, response ).m_hHandle; +#else + CBaseEntity * RESTRICT pTarget = gEntList.FindEntityByName( NULL, followup->followup_entityiotarget ); +#endif + if ( pTarget ) + { + g_EventQueue.AddEvent( pTarget, followup->followup_entityioinput, variant_t(), followup->followup_entityiodelay, GetOuter(), GetOuter() ); + } + } + if ( followup->IsValid() ) + { + // 11th hour change: rather than trigger followups from the end of a VCD, + // instead fire it from the end of the last speech event in the VCD, because + // there's a multisecond facial relax delay built into the scene. + // The speech length is stored in the cache, so we can post the followup now. + if ( response->GetType() == ResponseRules::RESPONSE_SCENE && + followup->followup_delay >= 0 ) + { + float fTimeToLastSpeech = GetSpeechDurationForResponse( response, STRING(GetOuter()->GetModelName()) ); + // failsafe + if ( fTimeToLastSpeech > 0 ) + { + DispatchFollowupThroughQueue( followup->followup_concept, followup->followup_contexts, + ResolveFollowupTargetToEntity( concept, *criteria, response, followup ), + fTimeToLastSpeech + followup->followup_delay, GetOuter() ); + } + else // error + { + // old way, copied from "else" below + m_pPostponedFollowup = followup; + if ( criteria ) + m_followupTarget = ResolveFollowupTargetToEntity( concept, *criteria, response, m_pPostponedFollowup ); + else + { + AI_CriteriaSet tmpCriteria; + m_followupTarget = ResolveFollowupTargetToEntity( concept, tmpCriteria, response, m_pPostponedFollowup ); + } + } + } + else if ( followup->followup_delay < 0 ) + { + // a negative delay has a special meaning. Usually the comeback dispatches after + // the currently said line is finished; the delay is added to that, to provide a + // pause between when character A finishes speaking and B begins. + // A negative delay (-n) actually means "dispatch the comeback n seconds + // after I start talking". + // In this case we do not need to postpone the followup; we just throw it directly + // into the queue. + DispatchFollowupThroughQueue( followup->followup_concept, followup->followup_contexts, + ResolveFollowupTargetToEntity( concept, *criteria, response, followup ), + -followup->followup_delay, GetOuter() ); + } + else if ( response->GetType() == ResponseRules::RESPONSE_PRINT ) + { // zero-duration responses dispatch immediately via the queue (must be the queue bec. + // the m_pPostponedFollowup will never trigger) + DispatchFollowupThroughQueue( followup->followup_concept, followup->followup_contexts, + ResolveFollowupTargetToEntity( concept, *criteria, response, followup ), + followup->followup_delay, GetOuter() ); + } + else + { + // this is kind of a quick patch to immediately deal with the issue of null criteria + // (arose while branching to main) without replumbing a bunch of stuff -- to be fixed + // 5.13.08 egr + m_pPostponedFollowup = followup; + if ( criteria ) + m_followupTarget = ResolveFollowupTargetToEntity( concept, *criteria, response, m_pPostponedFollowup ); + else + { + AI_CriteriaSet tmpCriteria; + m_followupTarget = ResolveFollowupTargetToEntity( concept, tmpCriteria, response, m_pPostponedFollowup ); + } + } + } + } + + + return bSuc; +} + +// This is a gimmick used when a negative delay is specified in a followup, which is a shorthand +// for "this many seconds after the beginning of the line" rather than "this may seconds after the end +// of the line", eg to create a THEN rule when two characters talk over each other. +// It's static to avoid accidental use of the postponed followup/target members. +void CAI_ExpresserWithFollowup::DispatchFollowupThroughQueue( const AIConcept_t &concept, + const char * RESTRICT criteriaStr, + const CResponseQueue::CFollowupTargetSpec_t &target, + float delay, + CBaseEntity * RESTRICT pOuter + ) +{ + AI_CriteriaSet criteria; + // Don't add my own criteria! GatherCriteria( &criteria, followup.followup_concept, followup.followup_contexts ); + + criteria.AppendCriteria( "From", STRING( pOuter->GetEntityName() ) ); + + criteria.Merge( criteriaStr ); + g_ResponseQueueManager.GetQueue()->Add( concept, &criteria, gpGlobals->curtime + delay, target, pOuter ); +} + +//----------------------------------------------------------------------------- +// Purpose: Handles the new concept objects +//----------------------------------------------------------------------------- +void CAI_ExpresserWithFollowup::SpeakDispatchFollowup( AI_ResponseFollowup &followup ) +{ + if ( !m_followupTarget.IsValid() ) + return; + + // If a specific entity target is given, use the old pathway for now + if ( m_followupTarget.m_iTargetType == kDRT_SPECIFIC && followup.followup_delay == 0 ) + { + CBaseEntity *pTarget = m_followupTarget.m_hHandle.Get(); + if (!pTarget) + { + return; + } + DispatchComeback( this, GetOuter(), pTarget, followup ); + } + else + { + DispatchFollowupThroughQueue( followup.followup_concept, followup.followup_contexts, m_followupTarget, followup.followup_delay, GetOuter() ); + } + // clear out the followup member just in case. + m_pPostponedFollowup = NULL; + m_followupTarget.m_iTargetType = kDRT_MAX; +} + +void CAI_ExpresserWithFollowup::OnSpeechFinished() +{ + if (m_pPostponedFollowup && m_pPostponedFollowup->IsValid()) + { + return SpeakDispatchFollowup(*m_pPostponedFollowup); + } +} + + + + +void CC_RR_ForceConcept_f( const CCommand &args ) +{ + if ( args.ArgC() < 3 ) + { + Msg("USAGE: rr_forceconcept \"criteria1:value1,criteria2:value2,...\"\n"); + return; + } + + AI_CriteriaSet criteria; + if ( args.ArgC() >= 3 ) + { + const char *criteriastring = args[3]; + criteria.Merge( criteriastring ); + } + + AIConcept_t concept( args[2] ); + QueueSpeak( concept, ResolveFollowupTargetToEntity( concept, criteria, args[1] ), criteria ); +} + + +static ConCommand rr_forceconcept( "rr_forceconcept", CC_RR_ForceConcept_f, + "fire a response concept directly at a given character.\n" + "USAGE: rr_forceconcept \"criteria1:value1,criteria2:value2,...\"\n" + "criteria values are optional.\n" + + , FCVAR_CHEAT ); diff --git a/sp/src/game/server/ai_playerally.cpp b/sp/src/game/server/ai_playerally.cpp index 25673612..43b82ed4 100644 --- a/sp/src/game/server/ai_playerally.cpp +++ b/sp/src/game/server/ai_playerally.cpp @@ -137,12 +137,23 @@ bool ConceptStringLessFunc( const string_t &lhs, const string_t &rhs ) return CaselessStringLessThan( STRING(lhs), STRING(rhs) ); } +#ifdef NEW_RESPONSE_SYSTEM +bool ConceptInfoStringLessFunc( const AIConcept_t& lhs, const AIConcept_t& rhs ) +{ + return CaselessStringLessThan( lhs.GetStringConcept(), rhs.GetStringConcept() ); +} +#endif + //----------------------------------------------------------------------------- class CConceptInfoMap : public CUtlMap { public: CConceptInfoMap() : +#ifdef NEW_RESPONSE_SYSTEM + CUtlMap( ConceptInfoStringLessFunc ) +#else CUtlMap( CaselessStringLessThan ) +#endif { for ( int i = 0; i < ARRAYSIZE(g_ConceptInfos); i++ ) { @@ -557,7 +568,11 @@ void CAI_PlayerAlly::PrescheduleThink( void ) if ( SelectNonCombatSpeech( &selection ) ) { SetSpeechTarget( selection.hSpeechTarget ); +#ifdef NEW_RESPONSE_SYSTEM + SpeakDispatchResponse( selection.concept.c_str(), &selection.Response ); +#else SpeakDispatchResponse( selection.concept.c_str(), selection.pResponse ); +#endif m_flNextIdleSpeechTime = gpGlobals->curtime + RandomFloat( 20,30 ); } else @@ -599,12 +614,22 @@ bool CAI_PlayerAlly::SelectSpeechResponse( AIConcept_t concept, const char *pszM { if ( IsAllowedToSpeak( concept ) ) { +#ifdef NEW_RESPONSE_SYSTEM + bool result = SpeakFindResponse( pSelection->Response, concept, pszModifiers ); + if ( result ) + { + pSelection->concept = concept; + pSelection->hSpeechTarget = pTarget; + return true; + } +#else AI_Response *pResponse = SpeakFindResponse( concept, pszModifiers ); if ( pResponse ) { pSelection->Set( concept, pResponse, pTarget ); return true; } +#endif } return false; } @@ -614,7 +639,9 @@ bool CAI_PlayerAlly::SelectSpeechResponse( AIConcept_t concept, const char *pszM void CAI_PlayerAlly::SetPendingSpeech( AIConcept_t concept, AI_Response *pResponse ) { m_PendingResponse = *pResponse; +#ifndef NEW_RESPONSE_SYSTEM pResponse->Release(); +#endif m_PendingConcept = concept; m_TimePendingSet = gpGlobals->curtime; } @@ -696,7 +723,11 @@ bool CAI_PlayerAlly::SelectInterjection() if ( SelectIdleSpeech( &selection ) ) { SetSpeechTarget( selection.hSpeechTarget ); +#ifdef NEW_RESPONSE_SYSTEM + SpeakDispatchResponse( selection.concept.c_str(), &selection.Response ); +#else SpeakDispatchResponse( selection.concept.c_str(), selection.pResponse ); +#endif return true; } } @@ -881,6 +912,18 @@ bool CAI_PlayerAlly::AskQuestionNow( CBaseEntity *pSpeechTarget, int iQARandomNu m_iQARandomNumber = RandomInt(0, 100); AISpeechSelection_t selection; +#ifdef NEW_RESPONSE_SYSTEM + if (SelectSpeechResponse( concept, NULL, m_hPotentialSpeechTarget.Get(), &selection )) + { + SetSpeechTarget( selection.hSpeechTarget ); + ClearPendingSpeech(); + + // Speak immediately + return SpeakDispatchResponse( selection.concept.c_str(), &selection.Response ); + } + + return false; +#else SelectSpeechResponse( concept, NULL, m_hPotentialSpeechTarget.Get(), &selection ); SetSpeechTarget( selection.hSpeechTarget ); @@ -891,6 +934,7 @@ bool CAI_PlayerAlly::AskQuestionNow( CBaseEntity *pSpeechTarget, int iQARandomNu // Speak immediately return SpeakDispatchResponse( selection.concept.c_str(), selection.pResponse ); +#endif } //----------------------------------------------------------------------------- @@ -980,7 +1024,11 @@ void CAI_PlayerAlly::AnswerQuestion( CAI_PlayerAlly *pQuestioner, int iQARandomN Assert( selection.pResponse ); SetSpeechTarget( selection.hSpeechTarget ); +#ifdef NEW_RESPONSE_SYSTEM + SpeakDispatchResponse( selection.concept.c_str(), &selection.Response ); +#else SpeakDispatchResponse( selection.concept.c_str(), selection.pResponse ); +#endif // Prevent idle speech for a while DeferAllIdleSpeech( random->RandomFloat( TALKER_DEFER_IDLE_SPEAK_MIN, TALKER_DEFER_IDLE_SPEAK_MAX ), GetSpeechTarget()->MyNPCPointer() ); @@ -1032,7 +1080,11 @@ int CAI_PlayerAlly::SelectNonCombatSpeechSchedule() { Assert( selection.pResponse ); SetSpeechTarget( selection.hSpeechTarget ); +#ifdef NEW_RESPONSE_SYSTEM + SetPendingSpeech( selection.concept.c_str(), &selection.Response ); +#else SetPendingSpeech( selection.concept.c_str(), selection.pResponse ); +#endif } } @@ -1107,9 +1159,13 @@ void CAI_PlayerAlly::StartTask( const Task_t *pTask ) case TASK_TALKER_SPEAK_PENDING: if ( !m_PendingConcept.empty() ) { +#ifdef NEW_RESPONSE_SYSTEM + SpeakDispatchResponse( m_PendingConcept.c_str(), &m_PendingResponse ); +#else AI_Response *pResponse = new AI_Response; *pResponse = m_PendingResponse; SpeakDispatchResponse( m_PendingConcept.c_str(), pResponse ); +#endif m_PendingConcept.erase(); TaskComplete(); } @@ -1844,6 +1900,18 @@ bool CAI_PlayerAlly::RespondedTo( const char *ResponseConcept, bool bForce, bool { // We're being forced to respond to the event, probably because it's the // player dying or something equally important. +#ifdef NEW_RESPONSE_SYSTEM + AI_Response response; + bool result = SpeakFindResponse( response, ResponseConcept, NULL ); + if ( result ) + { + // We've got something to say. Stop any scenes we're in, and speak the response. + if ( bCancelScene ) + RemoveActorFromScriptedScenes( this, false ); + + return SpeakDispatchResponse( ResponseConcept, &response ); + } +#else AI_Response *result = SpeakFindResponse( ResponseConcept, NULL ); if ( result ) { @@ -1854,6 +1922,7 @@ bool CAI_PlayerAlly::RespondedTo( const char *ResponseConcept, bool bForce, bool bool spoke = SpeakDispatchResponse( ResponseConcept, result ); return spoke; } +#endif return false; } diff --git a/sp/src/game/server/ai_playerally.h b/sp/src/game/server/ai_playerally.h index dc9948ce..93448ec7 100644 --- a/sp/src/game/server/ai_playerally.h +++ b/sp/src/game/server/ai_playerally.h @@ -252,6 +252,11 @@ enum AISpeechTargetSearchFlags_t struct AISpeechSelection_t { +#ifdef NEW_RESPONSE_SYSTEM + std::string concept; + AI_Response Response; + EHANDLE hSpeechTarget; +#else AISpeechSelection_t() : pResponse(NULL) { @@ -267,6 +272,7 @@ struct AISpeechSelection_t std::string concept; AI_Response * pResponse; EHANDLE hSpeechTarget; +#endif }; //------------------------------------- diff --git a/sp/src/game/server/ai_speech.h b/sp/src/game/server/ai_speech.h index 5ed12255..99f28624 100644 --- a/sp/src/game/server/ai_speech.h +++ b/sp/src/game/server/ai_speech.h @@ -5,6 +5,9 @@ // $NoKeywords: $ //=============================================================================// +#ifdef NEW_RESPONSE_SYSTEM +#include "ai_speech_new.h" +#else #ifndef AI_SPEECH_H #define AI_SPEECH_H @@ -452,3 +455,4 @@ inline void CAI_ExpresserHost::DispatchResponse( const char *conceptNa //----------------------------------------------------------------------------- #endif // AI_SPEECH_H +#endif diff --git a/sp/src/game/server/ai_speech_new.cpp b/sp/src/game/server/ai_speech_new.cpp new file mode 100644 index 00000000..f6cfaaaa --- /dev/null +++ b/sp/src/game/server/ai_speech_new.cpp @@ -0,0 +1,1473 @@ +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" + +#include "ai_speech.h" + +#include "game.h" +#include "engine/ienginesound.h" +#include "keyvalues.h" +#include "ai_basenpc.h" +#include "ai_criteria.h" +#include "isaverestore.h" +#include "sceneentity.h" +#include "ai_speechqueue.h" +#ifdef MAPBASE +#include "ai_squad.h" +#endif + +// memdbgon must be the last include file in a .cpp file!!! +#include + +#define DEBUG_AISPEECH 1 +#ifdef DEBUG_AISPEECH +ConVar ai_debug_speech( "ai_debug_speech", "0" ); +#define DebuggingSpeech() ai_debug_speech.GetBool() +#else +inline void SpeechMsg( ... ) {} +#define DebuggingSpeech() (false) +#endif + +extern ConVar rr_debugresponses; + +//----------------------------------------------------------------------------- + +CAI_TimedSemaphore g_AIFriendliesTalkSemaphore; +CAI_TimedSemaphore g_AIFoesTalkSemaphore; + +ConceptHistory_t::~ConceptHistory_t() +{ +} + +ConceptHistory_t::ConceptHistory_t( const ConceptHistory_t& src ) +{ + timeSpoken = src.timeSpoken; + m_response = src.m_response ; +} + +ConceptHistory_t& ConceptHistory_t::operator =( const ConceptHistory_t& src ) +{ + if ( this == &src ) + return *this; + + timeSpoken = src.timeSpoken; + m_response = src.m_response ; + + return *this; +} + +BEGIN_SIMPLE_DATADESC( ConceptHistory_t ) + DEFINE_FIELD( timeSpoken, FIELD_TIME ), // Relative to server time + // DEFINE_EMBEDDED( response, FIELD_??? ), // This is manually saved/restored by the ConceptHistory saverestore ops below +END_DATADESC() + +class CConceptHistoriesDataOps : public CDefSaveRestoreOps +{ +public: + virtual void Save( const SaveRestoreFieldInfo_t &fieldInfo, ISave *pSave ) + { + CUtlDict< ConceptHistory_t, int > *ch = ((CUtlDict< ConceptHistory_t, int > *)fieldInfo.pField); + int count = ch->Count(); + pSave->WriteInt( &count ); + for ( int i = 0 ; i < count; i++ ) + { + ConceptHistory_t *pHistory = &(*ch)[ i ]; + + pSave->StartBlock(); + { + + // Write element name + pSave->WriteString( ch->GetElementName( i ) ); + + // Write data + pSave->WriteAll( pHistory ); + // Write response blob + bool hasresponse = !pHistory->m_response.IsEmpty() ; + pSave->WriteBool( &hasresponse ); + if ( hasresponse ) + { + pSave->WriteAll( &pHistory->m_response ); + } + // TODO: Could blat out pHistory->criteria pointer here, if it's needed + } + pSave->EndBlock(); + } + } + + virtual void Restore( const SaveRestoreFieldInfo_t &fieldInfo, IRestore *pRestore ) + { + CUtlDict< ConceptHistory_t, int > *ch = ((CUtlDict< ConceptHistory_t, int > *)fieldInfo.pField); + + int count = pRestore->ReadInt(); + Assert( count >= 0 ); + for ( int i = 0 ; i < count; i++ ) + { + char conceptname[ 512 ]; + conceptname[ 0 ] = 0; + ConceptHistory_t history; + + pRestore->StartBlock(); + { + pRestore->ReadString( conceptname, sizeof( conceptname ), 0 ); + + pRestore->ReadAll( &history ); + + bool hasresponse = false; + + pRestore->ReadBool( &hasresponse ); + if ( hasresponse ) + { + history.m_response; + pRestore->ReadAll( &history.m_response ); + } + else + { + history.m_response.Invalidate(); + } + } + + pRestore->EndBlock(); + + // TODO: Could restore pHistory->criteria pointer here, if it's needed + + // Add to utldict + if ( conceptname[0] != 0 ) + { + ch->Insert( conceptname, history ); + } + else + { + Assert( !"Error restoring ConceptHistory_t, discarding!" ); + } + } + } + + virtual void MakeEmpty( const SaveRestoreFieldInfo_t &fieldInfo ) + { + } + + virtual bool IsEmpty( const SaveRestoreFieldInfo_t &fieldInfo ) + { + CUtlDict< ConceptHistory_t, int > *ch = ((CUtlDict< ConceptHistory_t, int > *)fieldInfo.pField); + return ch->Count() == 0 ? true : false; + } +}; + +CConceptHistoriesDataOps g_ConceptHistoriesSaveDataOps; + +///////////////////////////////////////////////// +// context operators +RR::CApplyContextOperator RR::sm_OpCopy(0); // " +RR::CIncrementOperator RR::sm_OpIncrement(2); // "++" +RR::CDecrementOperator RR::sm_OpDecrement(2); // "--" +RR::CToggleOperator RR::sm_OpToggle(1); // "!" + +RR::CApplyContextOperator *RR::CApplyContextOperator::FindOperator( const char *pContextString ) +{ + if ( !pContextString || pContextString[0] == 0 ) + { + return &sm_OpCopy; + } + + if ( pContextString[0] == '+' && pContextString [1] == '+' && pContextString[2] != '\0' ) + { + return &sm_OpIncrement; + } + else if ( pContextString[0] == '-' && pContextString [1] == '-' && pContextString[2] != '\0' ) + { + return &sm_OpDecrement; + } + else if ( pContextString[0] == '!' ) + { + return &sm_OpToggle; + } + else + { + return &sm_OpCopy; + } +} + +// default is just copy +bool RR::CApplyContextOperator::Apply( const char *pOldValue, const char *pOperator, char *pNewValue, int pNewValBufSize ) +{ + Assert( pOperator && pNewValue && pNewValBufSize > 0 ); + Assert( m_nSkipChars == 0 ); + if ( pOperator ) + { + V_strncpy( pNewValue, pOperator, pNewValBufSize ); + } + else + { + *pNewValue = 0; + } + return true; +} + +bool RR::CIncrementOperator::Apply( const char *pOldValue, const char *pOperator, char *pNewValue, int pNewValBufSize ) +{ + Assert( pOperator[0] == '+' && pOperator[1] == '+' ); + // parse out the old value as a numeric + int nOld = pOldValue ? V_atoi(pOldValue) : 0; + int nInc = V_atoi( pOperator+m_nSkipChars ); + V_snprintf( pNewValue, pNewValBufSize, "%d", nOld+nInc ); + return true; +} + +bool RR::CDecrementOperator::Apply( const char *pOldValue, const char *pOperator, char *pNewValue, int pNewValBufSize ) +{ + Assert( pOperator[0] == '-' && pOperator[1] == '-' ); + // parse out the old value as a numeric + int nOld = pOldValue ? V_atoi(pOldValue) : 0; + int nInc = V_atoi( pOperator+m_nSkipChars ); + V_snprintf( pNewValue, pNewValBufSize, "%d", nOld-nInc ); + return true; +} + +bool RR::CToggleOperator::Apply( const char *pOldValue, const char *pOperator, char *pNewValue, int pNewValBufSize ) +{ + Assert( pOperator[0] == '!' ); + // parse out the old value as a numeric + int nOld = pOldValue ? V_atoi(pOldValue) : 0; + V_snprintf( pNewValue, pNewValBufSize, "%d", nOld ? 0 : 1 ); + return true; +} + + +//----------------------------------------------------------------------------- +// +// CLASS: CAI_Expresser +// + +BEGIN_SIMPLE_DATADESC( CAI_Expresser ) + // m_pSink (reconnected on load) +// DEFINE_FIELD( m_pOuter, CHandle < CBaseFlex > ), + DEFINE_CUSTOM_FIELD( m_ConceptHistories, &g_ConceptHistoriesSaveDataOps ), + DEFINE_FIELD( m_flStopTalkTime, FIELD_TIME ), + DEFINE_FIELD( m_flStopTalkTimeWithoutDelay, FIELD_TIME ), + DEFINE_FIELD( m_flBlockedTalkTime, FIELD_TIME ), + DEFINE_FIELD( m_voicePitch, FIELD_INTEGER ), + DEFINE_FIELD( m_flLastTimeAcceptedSpeak, FIELD_TIME ), +END_DATADESC() + +#ifdef MAPBASE_VSCRIPT +BEGIN_SCRIPTDESC_ROOT( CAI_Expresser, "Expresser class for complex speech." ) + + DEFINE_SCRIPTFUNC( IsSpeaking, "Check if the actor is speaking." ) + DEFINE_SCRIPTFUNC( CanSpeak, "Check if the actor can speak." ) + DEFINE_SCRIPTFUNC( BlockSpeechUntil, "Block speech for a certain amount of time. This is stored in curtime." ) + DEFINE_SCRIPTFUNC( ForceNotSpeaking, "If the actor is speaking, force the system to recognize them as not speaking." ) + + DEFINE_SCRIPTFUNC( GetVoicePitch, "Get the actor's voice pitch. Used in sentences." ) + DEFINE_SCRIPTFUNC( SetVoicePitch, "Set the actor's voice pitch. Used in sentences." ) + + DEFINE_SCRIPTFUNC_NAMED( ScriptSpeakRawScene, "SpeakRawScene", "Speak a raw, instanced VCD scene as though it were played through the Response System. Return whether the scene successfully plays." ) + DEFINE_SCRIPTFUNC_NAMED( ScriptSpeakAutoGeneratedScene, "SpeakAutoGeneratedScene", "Speak an automatically generated, instanced VCD scene for this sound as though it were played through the Response System. Return whether the scene successfully plays." ) + DEFINE_SCRIPTFUNC_NAMED( ScriptSpeakRawSentence, "SpeakRawSentence", "Speak a raw sentence as though it were played through the Response System. Return the sentence's index; -1 if not successfully played." ) + DEFINE_SCRIPTFUNC_NAMED( ScriptSpeak, "Speak", "Speak a response concept with the specified modifiers." ) + +END_SCRIPTDESC(); +#endif + +//------------------------------------- + +bool CAI_Expresser::SemaphoreIsAvailable( CBaseEntity *pTalker ) +{ + if ( !GetSink()->UseSemaphore() ) + return true; + + CAI_TimedSemaphore *pSemaphore = GetMySpeechSemaphore( pTalker->MyNPCPointer() ); + return (pSemaphore ? pSemaphore->IsAvailable( pTalker ) : true); +} + +//------------------------------------- + +float CAI_Expresser::GetSemaphoreAvailableTime( CBaseEntity *pTalker ) +{ + CAI_TimedSemaphore *pSemaphore = GetMySpeechSemaphore( pTalker->MyNPCPointer() ); + return (pSemaphore ? pSemaphore->GetReleaseTime() : 0); +} + +//------------------------------------- + +int CAI_Expresser::GetVoicePitch() const +{ + return m_voicePitch + random->RandomInt(0,3); +} + +#ifdef DEBUG +static int g_nExpressers; +#endif + +/* +inline bool ShouldBeInExpresserQueue( CBaseFlex *pOuter ) +{ + return true; // return IsTerrorPlayer( pOuter, TEAM_SURVIVOR ); +} +*/ + +CAI_Expresser::CAI_Expresser( CBaseFlex *pOuter ) + : m_pOuter( pOuter ), + m_pSink( NULL ), + m_flStopTalkTime( 0 ), + m_flBlockedTalkTime( 0 ), + m_flStopTalkTimeWithoutDelay( 0 ), + m_voicePitch( 100 ), + m_flLastTimeAcceptedSpeak( 0 ) +{ +#ifdef DEBUG + g_nExpressers++; +#endif + if (m_pOuter) + { + // register me with the global expresser queue. + + // L4D: something a little ass backwards is happening here. We only want + // survivors to be in the queue. However, the team number isn't + // specified yet. So, we actually need to do this in the player's ChangeTeam. + g_ResponseQueueManager.GetQueue()->AddExpresserHost(m_pOuter); + + } +} + +CAI_Expresser::~CAI_Expresser() +{ + m_ConceptHistories.Purge(); + + CBaseFlex *RESTRICT outer = GetOuter(); + if ( outer ) + { + CAI_TimedSemaphore *pSemaphore = GetMySpeechSemaphore( outer ); + if ( pSemaphore ) + { + if ( pSemaphore->GetOwner() == outer ) + pSemaphore->Release(); + +#ifdef DEBUG + g_nExpressers--; + if ( g_nExpressers == 0 && pSemaphore->GetOwner() ) + DevMsg( 2, "Speech semaphore being held by non-talker entity\n" ); +#endif + } + + g_ResponseQueueManager.GetQueue()->RemoveExpresserHost(outer); + } +} + +//----------------------------------------------------------------------------- +void CAI_Expresser::TestAllResponses() +{ + IResponseSystem *pResponseSystem = GetOuter()->GetResponseSystem(); + if ( pResponseSystem ) + { + CUtlVector responses; + pResponseSystem->GetAllResponses( &responses ); + for ( int i = 0; i < responses.Count(); i++ ) + { + char response[ 256 ]; + responses[i].GetResponse( response, sizeof( response ) ); + + Msg( "Response: %s\n", response ); + AIConcept_t concept; + SpeakDispatchResponse( concept, &responses[i], NULL ); + } + } +} + +//----------------------------------------------------------------------------- +void CAI_Expresser::SetOuter( CBaseFlex *pOuter ) +{ + // if we're changing outers (which is a strange thing to do) + // unregister the old one from the queue. + if ( m_pOuter && ( m_pOuter != pOuter ) ) + { + AssertMsg2( false, "Expresser is switching its Outer from %s to %s. Why?", m_pOuter->GetDebugName(), pOuter->GetDebugName() ); + // unregister me with the global expresser queue + g_ResponseQueueManager.GetQueue()->RemoveExpresserHost(m_pOuter); + } + + m_pOuter = pOuter; +} + +//----------------------------------------------------------------------------- + +static const int LEN_SPECIFIC_SCENE_MODIFIER = strlen( AI_SPECIFIC_SCENE_MODIFIER ); + + +// This function appends "Global world" criteria that are always added to +// any character doing any match. This represents global concepts like weather, who's +// alive, etc. +static void ModifyOrAppendGlobalCriteria( AI_CriteriaSet * RESTRICT outputSet ) +{ + return; +} + + +void CAI_Expresser::GatherCriteria( AI_CriteriaSet * RESTRICT outputSet, const AIConcept_t &concept, const char * RESTRICT modifiers ) +{ + // Always include the concept name + outputSet->AppendCriteria( "concept", concept, CONCEPT_WEIGHT ); + +#if 1 + outputSet->Merge( modifiers ); +#else + // Always include any optional modifiers + if ( modifiers != NULL ) + { + char copy_modifiers[ 255 ]; + const char *pCopy; + char key[ 128 ] = { 0 }; + char value[ 128 ] = { 0 }; + + Q_strncpy( copy_modifiers, modifiers, sizeof( copy_modifiers ) ); + pCopy = copy_modifiers; + + while( pCopy ) + { + pCopy = SplitContext( pCopy, key, sizeof( key ), value, sizeof( value ), NULL, modifiers ); + + if( *key && *value ) + { + outputSet->AppendCriteria( key, value, CONCEPT_WEIGHT ); + } + } + } +#endif + + // include any global criteria + ModifyOrAppendGlobalCriteria( outputSet ); + + // Let our outer fill in most match criteria + GetOuter()->ModifyOrAppendCriteria( *outputSet ); + + // Append local player criteria to set, but not if this is a player doing the talking + if ( !GetOuter()->IsPlayer() ) + { + CBasePlayer *pPlayer = UTIL_PlayerByIndex( 1 ); + if( pPlayer ) + pPlayer->ModifyOrAppendPlayerCriteria( *outputSet ); + } + +#ifdef MAPBASE + GetOuter()->ReAppendContextCriteria( *outputSet ); +#endif +} + +//----------------------------------------------------------------------------- +// Purpose: Searches for a possible response +// Input : concept - +// NULL - +// Output : AI_Response +//----------------------------------------------------------------------------- +// AI_Response *CAI_Expresser::SpeakFindResponse( AIConcept_t concept, const char *modifiers /*= NULL*/ ) +bool CAI_Expresser::FindResponse( AI_Response &outResponse, AIConcept_t &concept, AI_CriteriaSet *criteria ) +{ + VPROF("CAI_Expresser::FindResponse"); + IResponseSystem *rs = GetOuter()->GetResponseSystem(); + if ( !rs ) + { + Assert( !"No response system installed for CAI_Expresser::GetOuter()!!!" ); + return NULL; + } + + // if I'm dead, I can't possibly match dialog. +#ifndef MAPBASE // Except for...you know...death sounds. + if ( !GetOuter()->IsAlive() ) + { + return false; + } +#endif + +#if 0 // this is the old technique, where we always gathered criteria in this function + AI_CriteriaSet set; + // Always include the concept name + set.AppendCriteria( "concept", concept, CONCEPT_WEIGHT ); + + // Always include any optional modifiers + if ( modifiers != NULL ) + { + char copy_modifiers[ 255 ]; + const char *pCopy; + char key[ 128 ] = { 0 }; + char value[ 128 ] = { 0 }; + + Q_strncpy( copy_modifiers, modifiers, sizeof( copy_modifiers ) ); + pCopy = copy_modifiers; + + while( pCopy ) + { + pCopy = SplitContext( pCopy, key, sizeof( key ), value, sizeof( value ), NULL, modifiers ); + + if( *key && *value ) + { + set.AppendCriteria( key, value, CONCEPT_WEIGHT ); + } + } + } + + // Let our outer fill in most match criteria + GetOuter()->ModifyOrAppendCriteria( set ); + + // Append local player criteria to set, but not if this is a player doing the talking + if ( !GetOuter()->IsPlayer() ) + { + CBasePlayer *pPlayer = UTIL_PlayerByIndex( 1 ); + if( pPlayer ) + pPlayer->ModifyOrAppendPlayerCriteria( set ); + } +#else + AI_CriteriaSet localCriteriaSet; // put it on the stack so we don't deal with new/delete + if (criteria == NULL) + { + GatherCriteria( &localCriteriaSet, concept, NULL ); + criteria = &localCriteriaSet; + } +#endif + + /// intercept any deferred criteria that are being sent to world + AI_CriteriaSet worldWritebackCriteria; + AI_CriteriaSet::InterceptWorldSetContexts( criteria, &worldWritebackCriteria ); + + // Now that we have a criteria set, ask for a suitable response + bool found = rs->FindBestResponse( *criteria, outResponse, this ); + + if ( rr_debugresponses.GetInt() == 4 ) + { + if ( ( GetOuter()->MyNPCPointer() && GetOuter()->m_debugOverlays & OVERLAY_NPC_SELECTED_BIT ) || GetOuter()->IsPlayer() ) + { + const char *pszName; + if ( GetOuter()->IsPlayer() ) + { + pszName = ((CBasePlayer*)GetOuter())->GetPlayerName(); + } + else + { + pszName = GetOuter()->GetDebugName(); + } + + if ( found ) + { + char response[ 256 ]; + outResponse.GetResponse( response, sizeof( response ) ); + + Warning( "RESPONSERULES: %s spoke '%s'. Found response '%s'.\n", pszName, (const char*)concept, response ); + } + else + { + Warning( "RESPONSERULES: %s spoke '%s'. Found no matching response.\n", pszName, (const char*)concept ); + } + } + } + + if ( !found ) + { + return false; + } + else if ( worldWritebackCriteria.GetCount() > 0 ) + { + Assert( CBaseEntity::Instance( INDEXENT( 0 ) )->IsWorld( ) ); + worldWritebackCriteria.WriteToEntity( CBaseEntity::Instance( INDEXENT( 0 ) ) ); + } + + if ( outResponse.IsEmpty() ) + { + // AssertMsg2( false, "RR: %s got empty but valid response for %s", GetOuter()->GetDebugName(), concept.GetStringConcept() ); + return false; + } + else + { + return true; + } +} + +#if 0 +//----------------------------------------------------------------------------- +// Purpose: Searches for a possible response; writes it into a response passed as +// parameter rather than new'ing one up. +// Input : concept - +// NULL - +// Output : bool : true on success, false on fail +//----------------------------------------------------------------------------- +AI_Response *CAI_Expresser::SpeakFindResponse( AI_Response *result, AIConcept_t &concept, AI_CriteriaSet *criteria ) +{ + Assert(response); + + IResponseSystem *rs = GetOuter()->GetResponseSystem(); + if ( !rs ) + { + Assert( !"No response system installed for CAI_Expresser::GetOuter()!!!" ); + return NULL; + } + +#if 0 + AI_CriteriaSet set; + // Always include the concept name + set.AppendCriteria( "concept", concept, CONCEPT_WEIGHT ); + + // Always include any optional modifiers + if ( modifiers != NULL ) + { + char copy_modifiers[ 255 ]; + const char *pCopy; + char key[ 128 ] = { 0 }; + char value[ 128 ] = { 0 }; + + Q_strncpy( copy_modifiers, modifiers, sizeof( copy_modifiers ) ); + pCopy = copy_modifiers; + + while( pCopy ) + { + pCopy = SplitContext( pCopy, key, sizeof( key ), value, sizeof( value ), NULL, modifiers ); + + if( *key && *value ) + { + set.AppendCriteria( key, value, CONCEPT_WEIGHT ); + } + } + } + + // Let our outer fill in most match criteria + GetOuter()->ModifyOrAppendCriteria( set ); + + // Append local player criteria to set, but not if this is a player doing the talking + if ( !GetOuter()->IsPlayer() ) + { + CBasePlayer *pPlayer = UTIL_PlayerByIndex( 1 ); + if( pPlayer ) + pPlayer->ModifyOrAppendPlayerCriteria( set ); + } +#else + AI_CriteriaSet &set = *criteria; +#endif + + // Now that we have a criteria set, ask for a suitable response + bool found = rs->FindBestResponse( set, *result, this ); + + if ( rr_debugresponses.GetInt() == 4 ) + { + if ( ( GetOuter()->MyNPCPointer() && GetOuter()->m_debugOverlays & OVERLAY_NPC_SELECTED_BIT ) || GetOuter()->IsPlayer() ) + { + const char *pszName; + if ( GetOuter()->IsPlayer() ) + { + pszName = ((CBasePlayer*)GetOuter())->GetPlayerName(); + } + else + { + pszName = GetOuter()->GetDebugName(); + } + + if ( found ) + { + char response[ 256 ]; + result->GetResponse( response, sizeof( response ) ); + + Warning( "RESPONSERULES: %s spoke '%s'. Found response '%s'.\n", pszName, concept, response ); + } + else + { + Warning( "RESPONSERULES: %s spoke '%s'. Found no matching response.\n", pszName, concept ); + } + } + } + + if ( !found ) + { + //Assert( !"rs->FindBestResponse: Returned a NULL AI_Response!" ); + return false; + } + + char response[ 256 ]; + result->GetResponse( response, sizeof( response ) ); + + if ( !response[0] ) + { + return false; + } + + return true; +} +#endif + +//----------------------------------------------------------------------------- +// Purpose: Dispatches the result +// Input : *response - +//----------------------------------------------------------------------------- +bool CAI_Expresser::SpeakDispatchResponse( AIConcept_t &concept, AI_Response *result, AI_CriteriaSet *criteria, IRecipientFilter *filter /* = NULL */ ) +{ + char response[ 256 ]; + result->GetResponse( response, sizeof( response ) ); + + float delay = result->GetDelay(); + + bool spoke = false; + + soundlevel_t soundlevel = result->GetSoundLevel(); + + if ( IsSpeaking() && concept[0] != 0 && result->GetType() != ResponseRules::RESPONSE_PRINT ) + { + const char *entityName = STRING( GetOuter()->GetEntityName() ); + if ( GetOuter()->IsPlayer() ) + { + entityName = ToBasePlayer( GetOuter() )->GetPlayerName(); + } + DevMsg( 2, "SpeakDispatchResponse: Entity ( %i/%s ) already speaking, forcing '%s'\n", GetOuter()->entindex(), entityName ? entityName : "UNKNOWN", (const char*)concept ); + + // Tracker 15911: Can break the game if we stop an imported map placed lcs here, so only + // cancel actor out of instanced scripted scenes. ywb + RemoveActorFromScriptedScenes( GetOuter(), true /*instanced scenes only*/ ); + GetOuter()->SentenceStop(); + + if ( IsRunningScriptedScene( GetOuter() ) ) + { + DevMsg( "SpeakDispatchResponse: Entity ( %i/%s ) refusing to speak due to scene entity, tossing '%s'\n", GetOuter()->entindex(), entityName ? entityName : "UNKNOWN", (const char*)concept ); + return false; + } + } + + switch ( result->GetType() ) + { + default: + case ResponseRules::RESPONSE_NONE: + break; + + case ResponseRules::RESPONSE_SPEAK: + { + if ( !result->ShouldntUseScene() ) + { + // This generates a fake CChoreoScene wrapping the sound.txt name + spoke = SpeakAutoGeneratedScene( response, delay ); + } + else + { + float speakTime = GetResponseDuration( result ); + GetOuter()->EmitSound( response ); + + DevMsg( 2, "SpeakDispatchResponse: Entity ( %i/%s ) playing sound '%s'\n", GetOuter()->entindex(), STRING( GetOuter()->GetEntityName() ), response ); + NoteSpeaking( speakTime, delay ); + spoke = true; + } + } + break; + + case ResponseRules::RESPONSE_SENTENCE: + { + spoke = ( -1 != SpeakRawSentence( response, delay, VOL_NORM, soundlevel ) ) ? true : false; + } + break; + + case ResponseRules::RESPONSE_SCENE: + { + spoke = SpeakRawScene( response, delay, result, filter ); + } + break; + + case ResponseRules::RESPONSE_RESPONSE: + { + // This should have been recursively resolved already + Assert( 0 ); + } + break; + case ResponseRules::RESPONSE_PRINT: + { + if ( g_pDeveloper->GetInt() > 0 ) + { + Vector vPrintPos; + GetOuter()->CollisionProp()->NormalizedToWorldSpace( Vector(0.5,0.5,1.0f), &vPrintPos ); + NDebugOverlay::Text( vPrintPos, response, true, 1.5 ); + } + spoke = true; + } + break; + case ResponseRules::RESPONSE_ENTITYIO: + { + return FireEntIOFromResponse( response, GetOuter() ); + } + break; +#ifdef MAPBASE + case ResponseRules::RESPONSE_VSCRIPT: + { + return GetOuter()->RunScript( response, "ResponseScript" ); + } + break; +#endif + } + + if ( spoke ) + { + m_flLastTimeAcceptedSpeak = gpGlobals->curtime; + if ( DebuggingSpeech() && g_pDeveloper->GetInt() > 0 && response && result->GetType() != ResponseRules::RESPONSE_PRINT ) + { + Vector vPrintPos; + GetOuter()->CollisionProp()->NormalizedToWorldSpace( Vector(0.5,0.5,1.0f), &vPrintPos ); + NDebugOverlay::Text( vPrintPos, CFmtStr( "%s: %s", (const char*)concept, response ), true, 1.5 ); + } + +#ifdef MAPBASE + if (result->GetContext()) + { + const char *pszContext = result->GetContext(); + + int iContextFlags = result->GetContextFlags(); + if ( iContextFlags & ResponseRules::APPLYCONTEXT_SQUAD ) + { + CAI_BaseNPC *pNPC = GetOuter()->MyNPCPointer(); + if (pNPC && pNPC->GetSquad()) + { + AISquadIter_t iter; + CAI_BaseNPC *pSquadmate = pNPC->GetSquad()->GetFirstMember( &iter ); + while ( pSquadmate ) + { + pSquadmate->AddContext( pszContext ); + + pSquadmate = pNPC->GetSquad()->GetNextMember( &iter ); + } + } + } + if ( iContextFlags & ResponseRules::APPLYCONTEXT_ENEMY ) + { + CBaseEntity *pEnemy = GetOuter()->GetEnemy(); + if ( pEnemy ) + { + pEnemy->AddContext( pszContext ); + } + } + if ( iContextFlags & ResponseRules::APPLYCONTEXT_WORLD ) + { + CBaseEntity *pEntity = CBaseEntity::Instance( INDEXENT( 0 ) ); + if ( pEntity ) + { + pEntity->AddContext( pszContext ); + } + } + if ( iContextFlags == 0 || iContextFlags & ResponseRules::APPLYCONTEXT_SELF ) + { + GetOuter()->AddContext( pszContext ); + } + } +#else + if ( result->IsApplyContextToWorld() ) + { + CBaseEntity *pEntity = CBaseEntity::Instance( INDEXENT( 0 ) ); + if ( pEntity ) + { + pEntity->AddContext( result->GetContext() ); + } + } + else + { + GetOuter()->AddContext( result->GetContext() ); + } +#endif + SetSpokeConcept( concept, result ); + } + else + { + } + + return spoke; +} + +bool CAI_Expresser::FireEntIOFromResponse( char *response, CBaseEntity *pInitiator ) +{ + // find the space-separator in the response name, then split into entityname, input, and parameter + // may barf in linux; there, should make some StringTokenizer() class that wraps the strtok_s behavior, etc. + char *pszEntname; + char *pszInput; + char *pszParam; + char *strtokContext; + + pszEntname = strtok_s( response, " ", &strtokContext ); + if ( !pszEntname ) + { + Warning( "Response was entityio but had bad value %s\n", response ); + return false; + } + + pszInput = strtok_s( NULL, " ", &strtokContext ); + if ( !pszInput ) + { + Warning( "Response was entityio but had bad value %s\n", response ); + return false; + } + + pszParam = strtok_s( NULL, " ", &strtokContext ); + + // poke entity io + CBaseEntity *pTarget = gEntList.FindEntityByName( NULL, pszEntname, pInitiator ); + if ( !pTarget ) + { + Msg( "Response rule targeted %s with entityio, but that doesn't exist.\n", pszEntname ); + // but this is actually a legit use case, so return true (below). + } + else + { + // pump the action into the target + variant_t variant; + if ( pszParam ) + { + variant.SetString( MAKE_STRING(pszParam) ); + } + pTarget->AcceptInput( pszInput, pInitiator, pInitiator, variant, 0 ); + + } + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *response - +// Output : float +//----------------------------------------------------------------------------- +float CAI_Expresser::GetResponseDuration( AI_Response *result ) +{ + Assert( result ); + char response[ 256 ]; + result->GetResponse( response, sizeof( response ) ); + + switch ( result->GetType() ) + { + case ResponseRules::RESPONSE_SPEAK: + { + return GetOuter()->GetSoundDuration( response, STRING( GetOuter()->GetModelName() ) ); + } + break; + case ResponseRules::RESPONSE_SENTENCE: + { + Assert( 0 ); + return 999.0f; + } + break; + case ResponseRules::RESPONSE_SCENE: + { + return GetSceneDuration( response ); + } + break; + case ResponseRules::RESPONSE_RESPONSE: + { + // This should have been recursively resolved already + Assert( 0 ); + } + break; + case ResponseRules::RESPONSE_PRINT: + { + return 1.0; + } + break; + default: + case ResponseRules::RESPONSE_NONE: + case ResponseRules::RESPONSE_ENTITYIO: + return 0.0f; + } + + return 0.0f; +} + +//----------------------------------------------------------------------------- +// Purpose: Placeholder for rules based response system +// Input : concept - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CAI_Expresser::Speak( AIConcept_t &concept, const char *modifiers /*= NULL*/, char *pszOutResponseChosen /* = NULL*/, size_t bufsize /* = 0 */, IRecipientFilter *filter /* = NULL */ ) +{ + concept.SetSpeaker(GetOuter()); + AI_CriteriaSet criteria; + GatherCriteria(&criteria, concept, modifiers); + + return Speak( concept, &criteria, pszOutResponseChosen, bufsize, filter ); +} + + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CAI_Expresser::Speak( AIConcept_t &concept, AI_CriteriaSet * RESTRICT criteria, char *pszOutResponseChosen , size_t bufsize , IRecipientFilter *filter ) +{ + VPROF("CAI_Expresser::Speak"); + if ( IsSpeechGloballySuppressed() ) + { + return false; + } + + GetOuter()->ModifyOrAppendDerivedCriteria(*criteria); + AI_Response result; + if ( !FindResponse( result, concept, criteria ) ) + { + return false; + } + + SpeechMsg( GetOuter(), "%s (%x) spoke %s (%f)", STRING(GetOuter()->GetEntityName()), GetOuter(), (const char*)concept, gpGlobals->curtime ); + // Msg( "%s:%s to %s:%s\n", GetOuter()->GetDebugName(), concept.GetStringConcept(), criteria.GetValue(criteria.FindCriterionIndex("Subject")), pTarget ? pTarget->GetDebugName() : "none" ); + + bool spoke = SpeakDispatchResponse( concept, &result, criteria, filter ); + if ( pszOutResponseChosen ) + { + result.GetResponse( pszOutResponseChosen, bufsize ); + } + + return spoke; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CAI_Expresser::SpeakRawScene( const char *pszScene, float delay, AI_Response *response, IRecipientFilter *filter /* = NULL */ ) +{ + float sceneLength = GetOuter()->PlayScene( pszScene, delay, response, filter ); + if ( sceneLength > 0 ) + { + SpeechMsg( GetOuter(), "SpeakRawScene( %s, %f) %f\n", pszScene, delay, sceneLength ); + +#if defined( HL2_EPISODIC ) + char szInstanceFilename[256]; + GetOuter()->GenderExpandString( pszScene, szInstanceFilename, sizeof( szInstanceFilename ) ); + // Only mark ourselves as speaking if the scene has speech + if ( GetSceneSpeechCount(szInstanceFilename) > 0 ) + { + NoteSpeaking( sceneLength, delay ); + } +#else + NoteSpeaking( sceneLength, delay ); +#endif + + return true; + } + return false; +} + +// This will create a fake .vcd/CChoreoScene to wrap the sound to be played +bool CAI_Expresser::SpeakAutoGeneratedScene( char const *soundname, float delay ) +{ + float speakTime = GetOuter()->PlayAutoGeneratedSoundScene( soundname ); + if ( speakTime > 0 ) + { + SpeechMsg( GetOuter(), "SpeakAutoGeneratedScene( %s, %f) %f\n", soundname, delay, speakTime ); + NoteSpeaking( speakTime, delay ); + return true; + } + return false; +} + +//------------------------------------- + +int CAI_Expresser::SpeakRawSentence( const char *pszSentence, float delay, float volume, soundlevel_t soundlevel, CBaseEntity *pListener ) +{ + int sentenceIndex = -1; + + if ( !pszSentence ) + return sentenceIndex; + + if ( pszSentence[0] == AI_SP_SPECIFIC_SENTENCE ) + { + sentenceIndex = SENTENCEG_Lookup( pszSentence ); + + if( sentenceIndex == -1 ) + { + // sentence not found + return -1; + } + + CPASAttenuationFilter filter( GetOuter(), soundlevel ); + CBaseEntity::EmitSentenceByIndex( filter, GetOuter()->entindex(), CHAN_VOICE, sentenceIndex, volume, soundlevel, 0, GetVoicePitch()); + } + else + { + sentenceIndex = SENTENCEG_PlayRndSz( GetOuter()->NetworkProp()->edict(), pszSentence, volume, soundlevel, 0, GetVoicePitch() ); + } + + SpeechMsg( GetOuter(), "SpeakRawSentence( %s, %f) %f\n", pszSentence, delay, engine->SentenceLength( sentenceIndex ) ); + NoteSpeaking( engine->SentenceLength( sentenceIndex ), delay ); + + return sentenceIndex; +} + +//------------------------------------- + +void CAI_Expresser::BlockSpeechUntil( float time ) +{ + SpeechMsg( GetOuter(), "BlockSpeechUntil(%f) %f\n", time, time - gpGlobals->curtime ); + m_flBlockedTalkTime = time; +} + + +//------------------------------------- + +void CAI_Expresser::NoteSpeaking( float duration, float delay ) +{ + duration += delay; + + GetSink()->OnStartSpeaking(); + + if ( duration <= 0 ) + { + // no duration :( + m_flStopTalkTime = gpGlobals->curtime + 3; + duration = 0; + } + else + { + m_flStopTalkTime = gpGlobals->curtime + duration; + } + + m_flStopTalkTimeWithoutDelay = m_flStopTalkTime - delay; + + SpeechMsg( GetOuter(), "NoteSpeaking( %f, %f ) (stop at %f)\n", duration, delay, m_flStopTalkTime ); + + if ( GetSink()->UseSemaphore() ) + { + CAI_TimedSemaphore *pSemaphore = GetMySpeechSemaphore( GetOuter() ); + if ( pSemaphore ) + { + pSemaphore->Acquire( duration, GetOuter() ); + } + } +} + +//------------------------------------- + +void CAI_Expresser::ForceNotSpeaking( void ) +{ + if ( IsSpeaking() ) + { + m_flStopTalkTime = gpGlobals->curtime; + m_flStopTalkTimeWithoutDelay = gpGlobals->curtime; + + CAI_TimedSemaphore *pSemaphore = GetMySpeechSemaphore( GetOuter() ); + if ( pSemaphore ) + { + if ( pSemaphore->GetOwner() == GetOuter() ) + { + pSemaphore->Release(); + } + } + } +} + +//------------------------------------- + +bool CAI_Expresser::IsSpeaking( void ) +{ + if ( m_flStopTalkTime > gpGlobals->curtime ) + SpeechMsg( GetOuter(), "IsSpeaking() %f\n", m_flStopTalkTime - gpGlobals->curtime ); + + if ( m_flLastTimeAcceptedSpeak == gpGlobals->curtime ) // only one speak accepted per think + return true; + + return ( m_flStopTalkTime > gpGlobals->curtime ); +} + +//------------------------------------- + +bool CAI_Expresser::CanSpeak() +{ + if ( m_flLastTimeAcceptedSpeak == gpGlobals->curtime ) // only one speak accepted per think + return false; + + float timeOk = MAX( m_flStopTalkTime, m_flBlockedTalkTime ); + return ( timeOk <= gpGlobals->curtime ); +} + +//----------------------------------------------------------------------------- +// Purpose: Returns true if it's ok for this entity to speak after himself. +// The base CanSpeak() includes the default speech delay, and won't +// return true until that delay time has passed after finishing the +// speech. This returns true as soon as the speech finishes. +//----------------------------------------------------------------------------- +bool CAI_Expresser::CanSpeakAfterMyself() +{ + if ( m_flLastTimeAcceptedSpeak == gpGlobals->curtime ) // only one speak accepted per think + return false; + + float timeOk = MAX( m_flStopTalkTimeWithoutDelay, m_flBlockedTalkTime ); + return ( timeOk <= gpGlobals->curtime ); +} + +//------------------------------------- +bool CAI_Expresser::CanSpeakConcept( AIConcept_t concept ) +{ + // Not in history? + int iter = m_ConceptHistories.Find( concept ); + if ( iter == m_ConceptHistories.InvalidIndex() ) + { + return true; + } + + ConceptHistory_t *history = &m_ConceptHistories[iter]; + Assert( history ); + + const AI_Response &response = history->m_response; + if ( response.IsEmpty() ) + return true; + + if ( response.GetSpeakOnce() ) + return false; + + float respeakDelay = response.GetRespeakDelay(); + + if ( respeakDelay != 0.0f ) + { + if ( history->timeSpoken != -1 && ( gpGlobals->curtime < history->timeSpoken + respeakDelay ) ) + return false; + } + + return true; +} + +//------------------------------------- + +bool CAI_Expresser::SpokeConcept( AIConcept_t concept ) +{ + return GetTimeSpokeConcept( concept ) != -1.f; +} + +//------------------------------------- + +float CAI_Expresser::GetTimeSpokeConcept( AIConcept_t concept ) +{ + int iter = m_ConceptHistories.Find( concept ); + if ( iter == m_ConceptHistories.InvalidIndex() ) + return -1; + + ConceptHistory_t *h = &m_ConceptHistories[iter]; + return h->timeSpoken; +} + +//------------------------------------- + +void CAI_Expresser::SetSpokeConcept( AIConcept_t concept, AI_Response *response, bool bCallback ) +{ + int idx = m_ConceptHistories.Find( concept ); + if ( idx == m_ConceptHistories.InvalidIndex() ) + { + ConceptHistory_t h; + h.timeSpoken = gpGlobals->curtime; + idx = m_ConceptHistories.Insert( concept, h ); + } + + ConceptHistory_t *slot = &m_ConceptHistories[ idx ]; + + slot->timeSpoken = gpGlobals->curtime; + // Update response info + if ( response ) + { + slot->m_response = *response; + } + + if ( bCallback ) + GetSink()->OnSpokeConcept( concept, response ); +} + +//------------------------------------- + +void CAI_Expresser::ClearSpokeConcept( AIConcept_t concept ) +{ + m_ConceptHistories.Remove( concept ); +} + +//------------------------------------- + +void CAI_Expresser::DumpHistories() +{ + int c = 1; + for ( int i = m_ConceptHistories.First(); i != m_ConceptHistories.InvalidIndex(); i = m_ConceptHistories.Next(i ) ) + { + ConceptHistory_t *h = &m_ConceptHistories[ i ]; + + DevMsg( "%i: %s at %f\n", c++, m_ConceptHistories.GetElementName( i ), h->timeSpoken ); + } +} + +//------------------------------------- + +bool CAI_Expresser::IsValidResponse( ResponseType_t type, const char *pszValue ) +{ + if ( type == ResponseRules::RESPONSE_SCENE ) + { + char szInstanceFilename[256]; + GetOuter()->GenderExpandString( pszValue, szInstanceFilename, sizeof( szInstanceFilename ) ); + return ( GetSceneDuration( szInstanceFilename ) > 0 ); + } + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CAI_TimedSemaphore *CAI_Expresser::GetMySpeechSemaphore( CBaseEntity *pNpc ) +{ + if ( !pNpc->MyNPCPointer() ) + return false; + + return (pNpc->MyNPCPointer()->IsPlayerAlly() ? &g_AIFriendliesTalkSemaphore : &g_AIFoesTalkSemaphore ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CAI_Expresser::SpeechMsg( CBaseEntity *pFlex, const char *pszFormat, ... ) +{ + if ( !DebuggingSpeech() ) + return; + + if ( pFlex->MyNPCPointer() ) + { + + DevMsg( pFlex->MyNPCPointer(), CFmtStr( &pszFormat ) ); + } + else + { + DevMsg( CFmtStr( &pszFormat ) ); + } + UTIL_LogPrintf( (char *) ( (const char *) CFmtStr( &pszFormat ) ) ); +} + +//----------------------------------------------------------------------------- +// Purpose: returns true when l4d is in credits screen or some other +// speech-forbidden state +//----------------------------------------------------------------------------- +bool CAI_Expresser::IsSpeechGloballySuppressed() +{ + return false; +} + +//----------------------------------------------------------------------------- + +void CAI_ExpresserHost_NPC_DoModifyOrAppendCriteria( CAI_BaseNPC *pSpeaker, AI_CriteriaSet& set ) +{ + // Append current activity name + const char *pActivityName = pSpeaker->GetActivityName( pSpeaker->GetActivity() ); + if ( pActivityName ) + { + set.AppendCriteria( "activity", pActivityName ); + } + + static const char *pStateNames[] = { "None", "Idle", "Alert", "Combat", "Scripted", "PlayDead", "Dead" }; + if ( (int)pSpeaker->m_NPCState < ARRAYSIZE(pStateNames) ) + { + set.AppendCriteria( "npcstate", UTIL_VarArgs( "[NPCState::%s]", pStateNames[pSpeaker->m_NPCState] ) ); + } + + if ( pSpeaker->GetEnemy() ) + { + set.AppendCriteria( "enemy", pSpeaker->GetEnemy()->GetClassname() ); + set.AppendCriteria( "timesincecombat", "-1" ); + } + else + { + if ( pSpeaker->GetLastEnemyTime() == 0.0 ) + set.AppendCriteria( "timesincecombat", "999999.0" ); + else + set.AppendCriteria( "timesincecombat", UTIL_VarArgs( "%f", gpGlobals->curtime - pSpeaker->GetLastEnemyTime() ) ); + } + + set.AppendCriteria( "speed", UTIL_VarArgs( "%.3f", pSpeaker->GetSmoothedVelocity().Length() ) ); + + CBaseCombatWeapon *weapon = pSpeaker->GetActiveWeapon(); + if ( weapon ) + { + set.AppendCriteria( "weapon", weapon->GetClassname() ); + } + else + { + set.AppendCriteria( "weapon", "none" ); + } + + CBasePlayer *pPlayer = AI_GetSinglePlayer(); + if ( pPlayer ) + { + Vector distance = pPlayer->GetAbsOrigin() - pSpeaker->GetAbsOrigin(); + + set.AppendCriteria( "distancetoplayer", UTIL_VarArgs( "%f", distance.Length() ) ); + + } + else + { + set.AppendCriteria( "distancetoplayer", UTIL_VarArgs( "%i", MAX_COORD_RANGE ) ); + } + + if ( pSpeaker->HasCondition( COND_SEE_PLAYER ) ) + { + set.AppendCriteria( "seeplayer", "1" ); + } + else + { + set.AppendCriteria( "seeplayer", "0" ); + } + + if ( pPlayer && pPlayer->FInViewCone( pSpeaker ) && pPlayer->FVisible( pSpeaker ) ) + { + set.AppendCriteria( "seenbyplayer", "1" ); + } + else + { + set.AppendCriteria( "seenbyplayer", "0" ); + } +} + +//----------------------------------------------------------------------------- + +extern CBaseEntity *FindPickerEntity( CBasePlayer *pPlayer ); + +CON_COMMAND( npc_speakall, "Force the npc to try and speak all their responses" ) +{ + CBaseEntity *pEntity; + + if ( args[1] && *args[1] ) + { + pEntity = gEntList.FindEntityByName( NULL, args[1], NULL ); + if ( !pEntity ) + { + pEntity = gEntList.FindEntityByClassname( NULL, args[1] ); + } + } + else + { + pEntity = UTIL_GetCommandClient() ? FindPickerEntity( UTIL_GetCommandClient() ) : NULL; + } + + if ( pEntity ) + { + CAI_BaseNPC *pNPC = pEntity->MyNPCPointer(); + if (pNPC) + { + if ( pNPC->GetExpresser() ) + { + bool save = engine->LockNetworkStringTables( false ); + pNPC->GetExpresser()->TestAllResponses(); + engine->LockNetworkStringTables( save ); + } + } + } +} +//----------------------------------------------------------------------------- + +CMultiplayer_Expresser::CMultiplayer_Expresser( CBaseFlex *pOuter ) : CAI_ExpresserWithFollowup( pOuter ) +{ + m_bAllowMultipleScenes = false; +} + +bool CMultiplayer_Expresser::IsSpeaking( void ) +{ + if ( m_bAllowMultipleScenes ) + { + return false; + } + + return CAI_Expresser::IsSpeaking(); +} + + +void CMultiplayer_Expresser::AllowMultipleScenes() +{ + m_bAllowMultipleScenes = true; +} + +void CMultiplayer_Expresser::DisallowMultipleScenes() +{ + m_bAllowMultipleScenes = false; +} diff --git a/sp/src/game/server/ai_speech_new.h b/sp/src/game/server/ai_speech_new.h new file mode 100644 index 00000000..02501c18 --- /dev/null +++ b/sp/src/game/server/ai_speech_new.h @@ -0,0 +1,664 @@ +//========= Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef AI_SPEECH_H +#define AI_SPEECH_H + +#include "utlmap.h" + +#include "soundflags.h" +#include "AI_Criteria.h" +#include "ai_responsesystem.h" +#include "utldict.h" +#include "ai_speechconcept.h" + +#if defined( _WIN32 ) +#pragma once +#endif + +class KeyValues; + +using ResponseRules::ResponseType_t; +using ResponseRules::AI_ResponseFollowup; + + +//----------------------------------------------------------------------------- +// Purpose: Used to share a global resource or prevent a system stepping on +// own toes. +//----------------------------------------------------------------------------- + +class CAI_TimedSemaphore +{ +public: + CAI_TimedSemaphore() + : m_ReleaseTime( 0 ) + { + m_hCurrentTalker = NULL; + } + + void Acquire( float time, CBaseEntity *pTalker ) { m_ReleaseTime = gpGlobals->curtime + time; m_hCurrentTalker = pTalker; } + void Release() { m_ReleaseTime = 0; m_hCurrentTalker = NULL; } + + // Current owner of the semaphore is always allowed to talk + bool IsAvailable( CBaseEntity *pTalker ) const { return ((gpGlobals->curtime > m_ReleaseTime) || (m_hCurrentTalker == pTalker)); } + float GetReleaseTime() const { return m_ReleaseTime; } + + CBaseEntity *GetOwner() { return m_hCurrentTalker; } + +private: + float m_ReleaseTime; + EHANDLE m_hCurrentTalker; +}; + +//----------------------------------------------------------------------------- + +extern CAI_TimedSemaphore g_AIFriendliesTalkSemaphore; +extern CAI_TimedSemaphore g_AIFoesTalkSemaphore; + +#define GetSpeechSemaphore( pNpc ) (((pNpc)->IsPlayerAlly()) ? &g_AIFriendliesTalkSemaphore : &g_AIFoesTalkSemaphore ) +//----------------------------------------------------------------------------- +// Basic speech system types +//----------------------------------------------------------------------------- + +//------------------------------------- +// Constants + + +const float AIS_NO_DELAY = 0; +const soundlevel_t AIS_DEF_SNDLVL = SNDLVL_TALKING; +#define AI_NULL_CONCEPT NULL + +#define AI_NULL_SENTENCE NULL + +// Sentence prefix constants +#define AI_SP_SPECIFIC_SENTENCE '!' +#define AI_SP_WAVFILE '^' +#define AI_SP_SCENE_GROUP '=' +#define AI_SP_SPECIFIC_SCENE '?' + +#define AI_SPECIFIC_SENTENCE(str_constant) "!" str_constant +#define AI_WAVFILE(str_constant) "^" str_constant +// @Note (toml 09-12-02): as scene groups are not currently implemented, the string is a semi-colon delimited list +#define AI_SCENE_GROUP(str_constant) "=" str_constant +#define AI_SPECIFIC_SCENE(str_constant) "?" str_constant + +// Designer overriding modifiers +#define AI_SPECIFIC_SCENE_MODIFIER "scene:" + +//------------------------------------- + +//------------------------------------- +// An id that represents the core meaning of a spoken phrase, +// eventually to be mapped to a sentence group or scene + +#if AI_CONCEPTS_ARE_STRINGS +typedef const char *AIConcept_t; +inline bool CompareConcepts( AIConcept_t c1, AIConcept_t c2 ) +{ + return ( (void *)c1 == (void *)c2 || ( c1 && c2 && Q_stricmp( c1, c2 ) == 0 ) ); +} +#else +typedef CAI_Concept AIConcept_t; +inline bool CompareConcepts( AIConcept_t c1, AIConcept_t c2 ) +{ + return c1.m_iConcept == c2.m_iConcept; +} +#endif + + +//----------------------------------------------------------------------------- +// CAI_Expresser +// +// Purpose: Provides the functionality of going from abstract concept ("hello") +// to specific sentence/scene/wave +// + +//------------------------------------- +// Sink supports behavior control and receives notifications of internal events + +class CAI_ExpresserSink +{ +public: + virtual void OnSpokeConcept( AIConcept_t concept, AI_Response *response ) {}; + virtual void OnStartSpeaking() {} + virtual bool UseSemaphore() { return true; } +}; + +struct ConceptHistory_t +{ + DECLARE_SIMPLE_DATADESC(); + + ConceptHistory_t(float timeSpoken = -1 ) + : timeSpoken( timeSpoken ), m_response( ) + { + } + + ConceptHistory_t( const ConceptHistory_t& src ); + ConceptHistory_t& operator = ( const ConceptHistory_t& src ); + + ~ConceptHistory_t(); + + float timeSpoken; + AI_Response m_response; +}; +//------------------------------------- + +class CAI_Expresser : public ResponseRules::IResponseFilter +{ +public: + CAI_Expresser( CBaseFlex *pOuter = NULL ); + ~CAI_Expresser(); + + // -------------------------------- + + bool Connect( CAI_ExpresserSink *pSink ) { m_pSink = pSink; return true; } + bool Disconnect( CAI_ExpresserSink *pSink ) { m_pSink = NULL; return true;} + + void TestAllResponses(); + + // -------------------------------- + + bool Speak( AIConcept_t &concept, const char *modifiers = NULL, char *pszOutResponseChosen = NULL, size_t bufsize = 0, IRecipientFilter *filter = NULL ); + bool Speak( AIConcept_t &concept, AI_CriteriaSet *criteria, char *pszOutResponseChosen = NULL, size_t bufsize = 0, IRecipientFilter *filter = NULL ); + + // Given modifiers (which are colon-delimited strings), fill out a criteria set including this + // character's contexts and the ones in the modifier. This lets us hang on to them after a call + // to SpeakFindResponse. + void GatherCriteria( AI_CriteriaSet *outputCritera, const AIConcept_t &concept, const char *modifiers ); + // These two methods allow looking up a response and dispatching it to be two different steps + // AI_Response *SpeakFindResponse( AIConcept_t concept, const char *modifiers = NULL ); + // AI_Response *SpeakFindResponse( AIConcept_t &concept, AI_CriteriaSet *criteria ); + // Find the appropriate response for the given concept. Return false if none found. + // Fills out the response object that you provide. + bool FindResponse( AI_Response &outResponse, AIConcept_t &concept, AI_CriteriaSet *modifiers = NULL ); + virtual bool SpeakDispatchResponse( AIConcept_t &concept, AI_Response *response, AI_CriteriaSet *criteria, IRecipientFilter *filter = NULL ); + float GetResponseDuration( AI_Response *response ); + + virtual int SpeakRawSentence( const char *pszSentence, float delay, float volume = VOL_NORM, soundlevel_t soundlevel = SNDLVL_TALKING, CBaseEntity *pListener = NULL ); + + bool SemaphoreIsAvailable( CBaseEntity *pTalker ); + float GetSemaphoreAvailableTime( CBaseEntity *pTalker ); + + virtual void OnSpeechFinished() {}; + + // This function can be overriden by games to suppress speech altogether during glue screens, etc + static bool IsSpeechGloballySuppressed(); + + // -------------------------------- + + virtual bool IsSpeaking(); + bool CanSpeak(); + bool CanSpeakAfterMyself(); + float GetTimeSpeechComplete() const { return m_flStopTalkTime; } + void BlockSpeechUntil( float time ); + + // -------------------------------- + + bool CanSpeakConcept( AIConcept_t concept ); + bool SpokeConcept( AIConcept_t concept ); + float GetTimeSpokeConcept( AIConcept_t concept ); // returns -1 if never + void SetSpokeConcept( AIConcept_t concept, AI_Response *response, bool bCallback = true ); + void ClearSpokeConcept( AIConcept_t concept ); + + // -------------------------------- + + void SetVoicePitch( int voicePitch ) { m_voicePitch = voicePitch; } + int GetVoicePitch() const; + + void NoteSpeaking( float duration, float delay = 0 ); + + // Force the NPC to release the semaphore & clear next speech time + void ForceNotSpeaking( void ); + +#ifdef MAPBASE_VSCRIPT + bool ScriptSpeakRawScene( char const *soundname, float delay ) { return SpeakRawScene( soundname, delay, NULL ); } + bool ScriptSpeakAutoGeneratedScene( char const *soundname, float delay ) { return SpeakAutoGeneratedScene( soundname, delay ); } + int ScriptSpeakRawSentence( char const *pszSentence, float delay ) { return SpeakRawSentence( pszSentence, delay ); } + bool ScriptSpeak( char const *concept, const char *modifiers ) { return Speak( CAI_Concept( concept ), modifiers[0] != '\0' ? modifiers : NULL ); } +#endif + + // helper used in dealing with RESPONSE_ENTITYIO + // response is the output of AI_Response::GetName + // note: the response string will get stomped on (by strtok) + // returns false on failure (eg, couldn't match parse contents) + static bool FireEntIOFromResponse( char *response, CBaseEntity *pInitiator ); + +protected: + CAI_TimedSemaphore *GetMySpeechSemaphore( CBaseEntity *pNpc ); + + bool SpeakRawScene( const char *pszScene, float delay, AI_Response *response, IRecipientFilter *filter = NULL ); + // This will create a fake .vcd/CChoreoScene to wrap the sound to be played + bool SpeakAutoGeneratedScene( char const *soundname, float delay ); + + void DumpHistories(); + + void SpeechMsg( CBaseEntity *pFlex, const char *pszFormat, ... ); + + // -------------------------------- + + CAI_ExpresserSink *GetSink() { return m_pSink; } + +private: + // -------------------------------- + + virtual bool IsValidResponse( ResponseType_t type, const char *pszValue ); + + // -------------------------------- + + CAI_ExpresserSink *m_pSink; + + // -------------------------------- + // + // Speech concept data structures + // + + CUtlDict< ConceptHistory_t, int > m_ConceptHistories; + + // -------------------------------- + // + // Speaking states + // + + float m_flStopTalkTime; // when in the future that I'll be done saying this sentence. + float m_flStopTalkTimeWithoutDelay; // same as the above, but minus the delay before other people can speak + float m_flBlockedTalkTime; + int m_voicePitch; // pitch of voice for this head + float m_flLastTimeAcceptedSpeak; // because speech may not be blocked until NoteSpeaking called by scene ent, this handles in-think blocking + + DECLARE_SIMPLE_DATADESC(); + + // -------------------------------- + // +public: + void SetOuter( CBaseFlex *pOuter ); + + CBaseFlex * GetOuter() { return m_pOuter; } + const CBaseFlex * GetOuter() const { return m_pOuter; } + +private: + CHandle m_pOuter; +}; + +//----------------------------------------------------------------------------- +// +// An NPC base class to assist a branch of the inheritance graph +// in utilizing CAI_Expresser +// + +template +class CAI_ExpresserHost : public BASE_NPC, protected CAI_ExpresserSink +{ + DECLARE_CLASS_NOFRIEND( CAI_ExpresserHost, BASE_NPC ); + +public: + virtual void NoteSpeaking( float duration, float delay ); + + virtual bool Speak( AIConcept_t concept, const char *modifiers = NULL, char *pszOutResponseChosen = NULL, size_t bufsize = 0, IRecipientFilter *filter = NULL ); + virtual bool Speak( AIConcept_t concept, AI_CriteriaSet *pCriteria, char *pszOutResponseChosen = NULL, size_t bufsize = 0, IRecipientFilter *filter = NULL ); +#ifdef MAPBASE + virtual bool Speak( AIConcept_t concept, AI_CriteriaSet& modifiers, char *pszOutResponseChosen = NULL, size_t bufsize = 0, IRecipientFilter *filter = NULL ) { return Speak( concept, &modifiers, pszOutResponseChosen, bufsize, filter ); } +#endif + + + void GatherCriteria( AI_CriteriaSet *outputCritera, const AIConcept_t &concept, const char *modifiers ); + // These two methods allow looking up a response and dispatching it to be two different steps +#ifdef MAPBASE + //AI_Response *SpeakFindResponse( AIConcept_t concept, const AI_CriteriaSet& modifiers ); + inline bool SpeakDispatchResponse( AIConcept_t concept, AI_Response &response, AI_CriteriaSet *criteria = NULL ) { return SpeakDispatchResponse( concept, &response, criteria ); } +#endif + bool SpeakFindResponse( AI_Response& outResponse, AIConcept_t concept, const char *modifiers = NULL ); + // AI_Response * SpeakFindResponse( AIConcept_t concept, const char *modifiers = NULL ); + // AI_Response *SpeakFindResponse( AIConcept_t concept, AI_CriteriaSet *criteria ); + // AI_Response *SpeakFindResponse( AIConcept_t concept ); + // Find the appropriate response for the given concept. Return false if none found. + // Fills out the response object that you provide. + bool FindResponse( AI_Response &outResponse, AIConcept_t &concept, AI_CriteriaSet *criteria = NULL ); + + bool SpeakDispatchResponse( AIConcept_t concept, AI_Response *response, AI_CriteriaSet *criteria = NULL ); + virtual void PostSpeakDispatchResponse( AIConcept_t concept, AI_Response *response ) { return; } + float GetResponseDuration( AI_Response *response ); + + float GetTimeSpeechComplete() const { return this->GetExpresser()->GetTimeSpeechComplete(); } + + bool IsSpeaking() { return this->GetExpresser()->IsSpeaking(); } + bool CanSpeak() { return this->GetExpresser()->CanSpeak(); } + bool CanSpeakAfterMyself() { return this->GetExpresser()->CanSpeakAfterMyself(); } + + void SetSpokeConcept( AIConcept_t concept, AI_Response *response, bool bCallback = true ) { this->GetExpresser()->SetSpokeConcept( concept, response, bCallback ); } + float GetTimeSpokeConcept( AIConcept_t concept ) { return this->GetExpresser()->GetTimeSpokeConcept( concept ); } + bool SpokeConcept( AIConcept_t concept ) { return this->GetExpresser()->SpokeConcept( concept ); } + +protected: + int PlaySentence( const char *pszSentence, float delay, float volume = VOL_NORM, soundlevel_t soundlevel = SNDLVL_TALKING, CBaseEntity *pListener = NULL ); + virtual void ModifyOrAppendCriteria( AI_CriteriaSet& set ); + + virtual IResponseSystem *GetResponseSystem(); + // Override of base entity response input handler + virtual void DispatchResponse( const char *conceptName ); +}; + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template +inline void CAI_ExpresserHost::NoteSpeaking( float duration, float delay ) +{ + this->GetExpresser()->NoteSpeaking( duration, delay ); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template +inline bool CAI_ExpresserHost::Speak( AIConcept_t concept, const char *modifiers /*= NULL*/, char *pszOutResponseChosen /*=NULL*/, size_t bufsize /* = 0 */, IRecipientFilter *filter /* = NULL */ ) +{ + AssertOnce( this->GetExpresser()->GetOuter() == this ); + return this->GetExpresser()->Speak( concept, modifiers, pszOutResponseChosen, bufsize, filter ); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template +inline bool CAI_ExpresserHost::Speak( AIConcept_t concept, AI_CriteriaSet *pCriteria, char *pszOutResponseChosen /*=NULL*/, size_t bufsize /* = 0 */, IRecipientFilter *filter /* = NULL */ ) +{ + AssertOnce( this->GetExpresser()->GetOuter() == this ); + CAI_Expresser * const RESTRICT pExpresser = this->GetExpresser(); + concept.SetSpeaker(this); + // add in any local criteria to the one passed on the command line. + pExpresser->GatherCriteria( pCriteria, concept, NULL ); + // call the "I have aleady gathered criteria" version of Expresser::Speak + return pExpresser->Speak( concept, pCriteria, pszOutResponseChosen, bufsize, filter ); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template +inline int CAI_ExpresserHost::PlaySentence( const char *pszSentence, float delay, float volume, soundlevel_t soundlevel, CBaseEntity *pListener ) +{ + return this->GetExpresser()->SpeakRawSentence( pszSentence, delay, volume, soundlevel, pListener ); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +extern void CAI_ExpresserHost_NPC_DoModifyOrAppendCriteria( CAI_BaseNPC *pSpeaker, AI_CriteriaSet& criteriaSet ); + +template +inline void CAI_ExpresserHost::ModifyOrAppendCriteria( AI_CriteriaSet& criteriaSet ) +{ + BaseClass::ModifyOrAppendCriteria( criteriaSet ); + + + if ( this->MyNPCPointer() ) + { + CAI_ExpresserHost_NPC_DoModifyOrAppendCriteria( this->MyNPCPointer(), criteriaSet ); + } + +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template +inline IResponseSystem *CAI_ExpresserHost::GetResponseSystem() +{ + extern IResponseSystem *g_pResponseSystem; + // Expressive NPC's use the general response system + return g_pResponseSystem; +} + + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template +inline void CAI_ExpresserHost::GatherCriteria( AI_CriteriaSet *outputCriteria, const AIConcept_t &concept, const char *modifiers ) +{ + return this->GetExpresser()->GatherCriteria( outputCriteria, concept, modifiers ); +} + + +#if 1 +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template +inline bool CAI_ExpresserHost::SpeakFindResponse(AI_Response& outResponse, AIConcept_t concept, const char *modifiers /*= NULL*/ ) +{ + AI_CriteriaSet criteria; + GatherCriteria(&criteria, concept, modifiers); + return FindResponse( outResponse, concept, &criteria ); +} +#else +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template +inline AI_Response *CAI_ExpresserHost::SpeakFindResponse( AIConcept_t concept, const char *modifiers /*= NULL*/ ) +{ + return this->GetExpresser()->SpeakFindResponse( concept, modifiers ); +} +#endif + +#if 0 +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template +inline AI_Response *CAI_ExpresserHost::SpeakFindResponse( AIConcept_t concept, AI_CriteriaSet *criteria /*= NULL*/ ) +{ + return this->GetExpresser()->SpeakFindResponse( concept, criteria ); +} + + +//----------------------------------------------------------------------------- +// In this case we clearly don't care to hang on to the criteria, so make a convenience +// class that generates a one off. +//----------------------------------------------------------------------------- +template +inline AI_Response * CAI_ExpresserHost::SpeakFindResponse( AIConcept_t concept ) +{ + AI_CriteriaSet criteria; + GatherCriteria( &criteria, concept, NULL ); + return this->GetExpresser()->SpeakFindResponse( concept, &criteria ); +} +#endif + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template +inline bool CAI_ExpresserHost::FindResponse( AI_Response &outResponse, AIConcept_t &concept, AI_CriteriaSet *criteria ) +{ + return this->GetExpresser()->FindResponse( outResponse, concept, criteria ); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template +inline bool CAI_ExpresserHost::SpeakDispatchResponse( AIConcept_t concept, AI_Response *response, AI_CriteriaSet *criteria ) +{ + if ( this->GetExpresser()->SpeakDispatchResponse( concept, response, criteria ) ) + { + PostSpeakDispatchResponse( concept, response ); + return true; + } + + return false; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template +inline float CAI_ExpresserHost::GetResponseDuration( AI_Response *response ) +{ + return this->GetExpresser()->GetResponseDuration( response ); +} + +//----------------------------------------------------------------------------- +// Override of base entity response input handler +//----------------------------------------------------------------------------- +template +inline void CAI_ExpresserHost::DispatchResponse( const char *conceptName ) + { + Speak( (AIConcept_t)conceptName ); + } + +//----------------------------------------------------------------------------- + +/// A shim under CAI_ExpresserHost you can use when deriving a new expresser +/// host type under CAI_BaseNPC. This does the extra step of declaring an m_pExpresser +/// member and initializing it from CreateComponents(). If your BASE_NPC class isn't +/// actually an NPC, then CreateComponents() never gets called and you won't have +/// an expresser created. +/// Note: you still need to add m_pExpresser to the Datadesc for your derived type. +/// This is because I couldn't figure out how to make a templatized datadesc declaration +/// that works generically on the template type. +template +class CAI_ExpresserHostWithData : public CAI_ExpresserHost +{ + DECLARE_CLASS_NOFRIEND( CAI_ExpresserHostWithData, CAI_ExpresserHost ); + +public: + CAI_ExpresserHostWithData( ) : m_pExpresser(NULL) {}; + + virtual CAI_Expresser *GetExpresser() { return m_pExpresser; } + const CAI_Expresser *GetExpresser() const { return m_pExpresser; } + + virtual bool CreateComponents() + { + return BaseClass::CreateComponents() && ( CreateExpresser() != NULL ); + } + +protected: + EXPRESSER_TYPE *CreateExpresser( void ) + { + AssertMsg1( m_pExpresser == NULL, "Tried to double-initialize expresser in %s\n", GetDebugName() ); + m_pExpresser = new EXPRESSER_TYPE(this); + if ( !m_pExpresser) + { + AssertMsg1( false, "Creating an expresser failed in %s\n", GetDebugName() ); + return NULL; + } + + m_pExpresser->Connect(this); + return m_pExpresser; + } + + virtual ~CAI_ExpresserHostWithData( void ) + { + delete m_pExpresser; + m_pExpresser = NULL; + } + + EXPRESSER_TYPE *m_pExpresser; +}; + +/// response rules +namespace RR +{ + /// some applycontext clauses have operators preceding them, + /// like ++1 which means "take the current value and increment it + /// by one". These classes detect these cases and do the appropriate + /// thing. + class CApplyContextOperator + { + public: + inline CApplyContextOperator( int nSkipChars ) : m_nSkipChars(nSkipChars) {}; + + /// perform whatever this operator does upon the given context value. + /// Default op is simply to copy old to new. + /// pOldValue should be the currently set value of the context. May be NULL meaning no prior value. + /// pOperator the value that applycontext says to set + /// pNewValue a pointer to a buffer where the real new value will be writ. + /// returns true on success; false on failure (eg, tried to increment a + /// non-numeric value). + virtual bool Apply( const char *pOldValue, const char *pOperator, char *pNewValue, int pNewValBufSize ); + + /// This is the function that should be called from outside, + /// fed the input string, it'll select the right operator + /// to apply. + static CApplyContextOperator *FindOperator( const char *pContextString ); + + protected: + int m_nSkipChars; // how many chars to "skip" in the value string to get past the op specifier to the actual value + // eg, "++3" has a m_nSkipChars of 2, because the op string "++" is two characters. + }; + + class CIncrementOperator : public CApplyContextOperator + { + public: + inline CIncrementOperator( int nSkipChars ) : CApplyContextOperator(nSkipChars) {}; + virtual bool Apply( const char *pOldValue, const char *pOperator, char *pNewValue, int pNewValBufSize ); + }; + + class CDecrementOperator : public CApplyContextOperator + { + public: + inline CDecrementOperator( int nSkipChars ) : CApplyContextOperator(nSkipChars) {}; + virtual bool Apply( const char *pOldValue, const char *pOperator, char *pNewValue, int pNewValBufSize ); + }; + + class CToggleOperator : public CApplyContextOperator + { + public: + inline CToggleOperator( int nSkipChars ) : CApplyContextOperator(nSkipChars) {}; + virtual bool Apply( const char *pOldValue, const char *pOperator, char *pNewValue, int pNewValBufSize ); + }; + + // the singleton operators + extern CApplyContextOperator sm_OpCopy; + extern CIncrementOperator sm_OpIncrement; + extern CDecrementOperator sm_OpDecrement; + extern CToggleOperator sm_OpToggle; +}; + + +//----------------------------------------------------------------------------- +#include "ai_speechqueue.h" + +//----------------------------------------------------------------------------- +// A kind of AI Expresser that can dispatch a follow-up speech event when it +// finishes speaking. +//----------------------------------------------------------------------------- +class CAI_ExpresserWithFollowup : public CAI_Expresser +{ +public: + CAI_ExpresserWithFollowup( CBaseFlex *pOuter = NULL ) : CAI_Expresser(pOuter), + m_pPostponedFollowup(NULL) + {}; + virtual bool Speak( AIConcept_t &concept, const char *modifiers = NULL, char *pszOutResponseChosen = NULL, size_t bufsize = 0, IRecipientFilter *filter = NULL ); + virtual bool SpeakDispatchResponse( AIConcept_t &concept, AI_Response *response, AI_CriteriaSet *criteria, IRecipientFilter *filter = NULL ); + virtual void SpeakDispatchFollowup( AI_ResponseFollowup &followup ); + + virtual void OnSpeechFinished(); + + typedef CAI_Expresser BaseClass; +protected: + static void DispatchFollowupThroughQueue( const AIConcept_t &concept, + const char *criteriaStr, + const CResponseQueue::CFollowupTargetSpec_t &target, + float delay, + CBaseEntity * RESTRICT pOuter ); + + AI_ResponseFollowup *m_pPostponedFollowup; // TODO: save/restore + CResponseQueue::CFollowupTargetSpec_t m_followupTarget; +}; + +class CMultiplayer_Expresser : public CAI_ExpresserWithFollowup +{ +public: + CMultiplayer_Expresser( CBaseFlex *pOuter = NULL ); + //~CMultiplayer_Expresser(); + + virtual bool IsSpeaking(); + + void AllowMultipleScenes(); + void DisallowMultipleScenes(); + +private: + bool m_bAllowMultipleScenes; + +}; + + +#endif // AI_SPEECH_H diff --git a/sp/src/game/server/ai_speechqueue.cpp b/sp/src/game/server/ai_speechqueue.cpp new file mode 100644 index 00000000..46779ad6 --- /dev/null +++ b/sp/src/game/server/ai_speechqueue.cpp @@ -0,0 +1,475 @@ +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" + +#include "basemultiplayerplayer.h" +#include "ai_baseactor.h" +#include "ai_speech.h" +//#include "flex_expresser.h" +// memdbgon must be the last include file in a .cpp file!!! +#include + +extern ConVar ai_debug_speech; +#define DebuggingSpeech() ai_debug_speech.GetBool() +extern ConVar rr_debugresponses; + +ConVar rr_followup_maxdist( "rr_followup_maxdist", "1800", FCVAR_CHEAT, "'then ANY' or 'then ALL' response followups will be dispatched only to characters within this distance." ); + +/////////////////////////////////////////////////////////////////////////////// +// RESPONSE QUEUE DATA STRUCTURE +/////////////////////////////////////////////////////////////////////////////// + +CResponseQueue::CResponseQueue( int queueSize ) : m_Queue(queueSize), m_ExpresserTargets(8,8) +{}; + +/// Add a deferred response. +void CResponseQueue::Add( const AIConcept_t &concept, ///< concept to dispatch + const AI_CriteriaSet * RESTRICT contexts, + float time, ///< when to dispatch it. You can specify a time of zero to mean "immediately." + const CFollowupTargetSpec_t &targetspec, + CBaseEntity *pIssuer + ) +{ + // Add a response. + AssertMsg( m_Queue.Count() < AI_RESPONSE_QUEUE_SIZE, "AI Response queue overfilled." ); + QueueType_t::IndexLocalType_t idx = m_Queue.AddToTail(); + m_Queue[idx].Init( concept, contexts, time, targetspec, pIssuer ); +} + + +/// Remove a deferred response matching the concept and issuer. +void CResponseQueue::Remove( const AIConcept_t &concept, ///< concept to dispatch + CBaseEntity * const RESTRICT pIssuer ///< the entity issuing the response, if one exists. + ) RESTRICT +{ + // walk through the queue until we find a response matching the concept and issuer, then strike it. + QueueType_t::IndexLocalType_t idx = m_Queue.Head(); + while (idx != m_Queue.InvalidIndex()) + { + CDeferredResponse &response = m_Queue[idx]; + QueueType_t::IndexLocalType_t previdx = idx; // advance the index immediately because we may be deleting the "current" element + idx = m_Queue.Next(idx); // is now the next index + if ( CompareConcepts( response.m_concept, concept ) && // if concepts match and + ( !pIssuer || ( response.m_hIssuer.Get() == pIssuer ) ) // issuer is null, or matches the one in the response + ) + { + m_Queue.Remove(previdx); + } + } +} + + +void CResponseQueue::RemoveSpeechQueuedFor( const CBaseEntity *pSpeaker ) +{ + // walk through the queue until we find a response matching the speaker, then strike it. + // because responses are dispatched from inside a loop that is already walking through the + // queue, it's not safe to actually remove the elements. Instead, quash it by replacing it + // with a null event. + + for ( QueueType_t::IndexLocalType_t idx = m_Queue.Head() ; + idx != m_Queue.InvalidIndex() ; + idx = m_Queue.Next(idx) ) // is now the next index + { + CDeferredResponse &response = m_Queue[idx]; + if ( response.m_Target.m_hHandle.Get() == pSpeaker ) + { + response.Quash(); + } + } +} + +// TODO: use a more compact representation. +void CResponseQueue::DeferContextsFromCriteriaSet( DeferredContexts_t &contextsOut, const AI_CriteriaSet * RESTRICT criteriaIn ) +{ + contextsOut.Reset(); + if (criteriaIn) + { + contextsOut.Merge(criteriaIn); + } +} + +void CResponseQueue::PerFrameDispatch() +{ +failsafe: + // Walk through the list, find any messages whose time has come, and dispatch them. Then remove them. + QueueType_t::IndexLocalType_t idx = m_Queue.Head(); + while (idx != m_Queue.InvalidIndex()) + { + // do we need to dispatch this concept? + CDeferredResponse &response = m_Queue[idx]; + QueueType_t::IndexLocalType_t previdx = idx; // advance the index immediately because we may be deleting the "current" element + idx = m_Queue.Next(idx); // is now the next index + + if ( response.IsQuashed() ) + { + // we can delete this entry now + m_Queue.Remove(previdx); + } + else if ( response.m_fDispatchTime <= gpGlobals->curtime ) + { + // dispatch. we've had bugs where dispatches removed things from inside the queue; + // so, as a failsafe, if the queue length changes as a result, start over. + int oldLength = m_Queue.Count(); + DispatchOneResponse(response); + if ( m_Queue.Count() < oldLength ) + { + AssertMsg( false, "Response queue length changed in non-reentrant way! FAILSAFE TRIGGERED" ); + goto failsafe; // ick + } + + // we can delete this entry now + m_Queue.Remove(previdx); + } + } +} + + +/// Add an expressor owner to this queue. +void CResponseQueue::AddExpresserHost(CBaseEntity *host) +{ + EHANDLE ehost(host); + // see if it's in there already + if (m_ExpresserTargets.HasElement(ehost)) + { + AssertMsg1(false, "Tried to add %s to response queue when it was already in there.", host->GetDebugName()); + } + else + { + // zip through the queue front to back, first see if there's any invalid handles to replace + int count = m_ExpresserTargets.Count(); + for (int i = 0 ; i < count ; ++i ) + { + if ( !m_ExpresserTargets[i].Get() ) + { + m_ExpresserTargets[i] = ehost; + return; + } + } + + // if we're down here we didn't find one to replace, so append the host to the end. + m_ExpresserTargets.AddToTail(ehost); + } +} + +/// Remove an expresser host from this queue. +void CResponseQueue::RemoveExpresserHost(CBaseEntity *host) +{ + int idx = m_ExpresserTargets.Find(host); + if (idx == -1) + { + // AssertMsg1(false, "Tried to remove %s from response queue, but it's not in there to begin with!", host->GetDebugName() ); + } + else + { + m_ExpresserTargets.FastRemove(idx); + } +} + +/// Get the expresser for a base entity. +/// TODO: Kind of an ugly hack until I get the class hierarchy straightened out. +static CAI_Expresser *InferExpresserFromBaseEntity(CBaseEntity * RESTRICT pEnt) +{ + if ( CBaseMultiplayerPlayer *pPlayer = dynamic_cast(pEnt) ) + { + return pPlayer->GetExpresser(); + } + else if ( CAI_BaseActor *pActor = dynamic_cast(pEnt) ) + { + return pActor->GetExpresser(); + } + /* + else if ( CFlexExpresser *pFlex = dynamic_cast(pEnt) ) + { + return pFlex->GetExpresser(); + } + */ + else + { + return NULL; + } +} + + +void CResponseQueue::CDeferredResponse::Quash() +{ + m_Target = CFollowupTargetSpec_t(); + m_fDispatchTime = 0; +} + +bool CResponseQueue::DispatchOneResponse(CDeferredResponse &response) +{ + // find the target. + CBaseEntity * RESTRICT pTarget = NULL; + AI_CriteriaSet &deferredCriteria = response.m_contexts; + CAI_Expresser * RESTRICT pEx = NULL; + CBaseEntity * RESTRICT pIssuer = response.m_hIssuer.Get(); // MAY BE NULL + float followupMaxDistSq; + { + /* + CFlexExpresser * RESTRICT pOrator = CFlexExpresser::AsFlexExpresser( pIssuer ); + if ( pOrator ) + { + // max dist is overridden. "0" means infinite distance (for orators only), + // anything else is a finite distance. + if ( pOrator->m_flThenAnyMaxDist > 0 ) + { + followupMaxDistSq = pOrator->m_flThenAnyMaxDist * pOrator->m_flThenAnyMaxDist; + } + else + { + followupMaxDistSq = FLT_MAX; + } + + } + else + */ + { + followupMaxDistSq = rr_followup_maxdist.GetFloat(); // square of max audibility distance + followupMaxDistSq *= followupMaxDistSq; + } + } + + switch (response.m_Target.m_iTargetType) + { + case kDRT_SPECIFIC: + { + pTarget = response.m_Target.m_hHandle.Get(); + } + break; + case kDRT_ANY: + { + return DispatchOneResponse_ThenANY( response, &deferredCriteria, pIssuer, followupMaxDistSq ); + } + break; + case kDRT_ALL: + { + bool bSaidAnything = false; + Vector issuerLocation; + if ( pIssuer ) + { + issuerLocation = pIssuer->GetAbsOrigin(); + } + + // find all characters + int numExprs = GetNumExpresserTargets(); + for ( int i = 0 ; i < numExprs; ++i ) + { + pTarget = GetExpresserHost(i); + float distIssuerToTargetSq = 0.0f; + if ( pIssuer ) + { + distIssuerToTargetSq = (pTarget->GetAbsOrigin() - issuerLocation).LengthSqr(); + if ( distIssuerToTargetSq > followupMaxDistSq ) + continue; // too far + } + + pEx = InferExpresserFromBaseEntity(pTarget); + if ( !pEx || pTarget == pIssuer ) + continue; + AI_CriteriaSet characterCriteria; + pEx->GatherCriteria(&characterCriteria, response.m_concept, NULL); + characterCriteria.Merge(&deferredCriteria); + if ( pIssuer ) + { + characterCriteria.AppendCriteria( "dist_from_issuer", UTIL_VarArgs( "%f", sqrt(distIssuerToTargetSq) ) ); + } + AI_Response prospectiveResponse; + if ( pEx->FindResponse( prospectiveResponse, response.m_concept, &characterCriteria ) ) + { + // dispatch it + bSaidAnything = pEx->SpeakDispatchResponse(response.m_concept, &prospectiveResponse, &deferredCriteria) || bSaidAnything ; + } + } + + return bSaidAnything; + + } + break; + default: + // WTF? + AssertMsg1( false, "Unknown deferred response type %d\n", response.m_Target.m_iTargetType ); + return false; + } + + if (!pTarget) + return false; // we're done right here. + + // Get the expresser for the target. + pEx = InferExpresserFromBaseEntity(pTarget); + if (!pEx) + return false; + + + AI_CriteriaSet characterCriteria; + pEx->GatherCriteria(&characterCriteria, response.m_concept, NULL); + characterCriteria.Merge(&deferredCriteria); + pEx->Speak( response.m_concept, &characterCriteria ); + + return true; +} + +// +ConVar rr_thenany_score_slop( "rr_thenany_score_slop", "0.0", FCVAR_CHEAT, "When computing respondents for a 'THEN ANY' rule, all rule-matching scores within this much of the best score will be considered." ); +#define EXARRAYMAX 32 // maximum number of prospective expressers in the array (hardcoded for simplicity) +bool CResponseQueue::DispatchOneResponse_ThenANY( CDeferredResponse &response, AI_CriteriaSet * RESTRICT pDeferredCriteria, CBaseEntity * const RESTRICT pIssuer, float followupMaxDistSq ) +{ + CBaseEntity * RESTRICT pTarget = NULL; + CAI_Expresser * RESTRICT pEx = NULL; + float bestScore = 0; + float slop = rr_thenany_score_slop.GetFloat(); + Vector issuerLocation; + if ( pIssuer ) + { + issuerLocation = pIssuer->GetAbsOrigin(); + } + + // this is an array of prospective respondents. + CAI_Expresser * RESTRICT pBestEx[EXARRAYMAX]; + AI_Response responseToSay[EXARRAYMAX]; + int numExFound = 0; // and this is the high water mark for the array. + + // Here's the algorithm: we're going to walk through all the characters, finding the + // highest scoring ones for this rule. Let the highest score be called k. + // Because there may be (n) many characters all scoring k, we store an array of + // all characters with score k, then choose randomly from that array at return. + // We also define an allowable error for k in the global cvar + // rr_thenany_score_slop , which may be zero. + + // find all characters (except the issuer) + int numExprs = GetNumExpresserTargets(); + AssertMsg1( numExprs <= EXARRAYMAX, "Response queue has %d possible expresser targets, please increase EXARRAYMAX ", numExprs ); + for ( int i = 0 ; i < numExprs; ++i ) + { + pTarget = GetExpresserHost(i); + if ( pTarget == pIssuer ) + continue; // don't dispatch to myself + + if ( !pTarget->IsAlive() ) + continue; // dead men tell no tales + + float distIssuerToTargetSq = 0.0f; + if ( pIssuer ) + { + distIssuerToTargetSq = (pTarget->GetAbsOrigin() - issuerLocation).LengthSqr(); + if ( distIssuerToTargetSq > followupMaxDistSq ) + continue; // too far + } + + pEx = InferExpresserFromBaseEntity(pTarget); + if ( !pEx ) + continue; + + AI_CriteriaSet characterCriteria; + pEx->GatherCriteria(&characterCriteria, response.m_concept, NULL); + characterCriteria.Merge( pDeferredCriteria ); + pTarget->ModifyOrAppendDerivedCriteria( characterCriteria ); + if ( pIssuer ) + { + characterCriteria.AppendCriteria( "dist_from_issuer", UTIL_VarArgs( "%f", sqrt(distIssuerToTargetSq) ) ); + } + AI_Response prospectiveResponse; + + if ( pEx->FindResponse( prospectiveResponse, response.m_concept, &characterCriteria ) ) + { + float score = prospectiveResponse.GetMatchScore(); + if ( score > 0 && !prospectiveResponse.IsEmpty() ) // ignore scores that are zero, regardless of slop + { + // if this score is better than all we've seen (outside the slop), then replace the array with + // an entry just to this expresser + if ( score > bestScore + slop ) + { + responseToSay[0] = prospectiveResponse; + pBestEx[0] = pEx; + bestScore = score; + numExFound = 1; + } + else if ( score >= bestScore - slop ) // if this score is at least as good as the best we've seen, but not better than all + { + if ( numExFound >= EXARRAYMAX ) + continue; // SAFETY: don't overflow the array + + responseToSay[numExFound] = prospectiveResponse; + pBestEx[numExFound] = pEx; + bestScore = fpmax( score, bestScore ); + numExFound += 1; + } + } + } + } + + // if I have a response, dispatch it. + if ( numExFound > 0 ) + { + // get a random number between 0 and the responses found + int iSelect = numExFound > 1 ? RandomInt( 0, numExFound - 1 ) : 0; + + if ( pBestEx[iSelect] != NULL ) + { + return pBestEx[iSelect]->SpeakDispatchResponse( response.m_concept, responseToSay + iSelect, pDeferredCriteria ); + } + else + { + AssertMsg( false, "Response queue somehow found a response, but no expresser for it.\n" ); + return false; + } + } + else + { // I did not find a response. + return false; + } + + return false; // just in case +} + +void CResponseQueue::Evacuate() +{ + m_Queue.RemoveAll(); +} + +#undef EXARRAYMAX + + +/////////////////////////////////////////////////////////////////////////////// +// RESPONSE QUEUE MANAGER +/////////////////////////////////////////////////////////////////////////////// + + +void CResponseQueueManager::LevelInitPreEntity( void ) +{ + if (m_pQueue == NULL) + { + m_pQueue = new CResponseQueue(AI_RESPONSE_QUEUE_SIZE); + } +} + +CResponseQueueManager::~CResponseQueueManager() +{ + if (m_pQueue != NULL) + { + delete m_pQueue; + m_pQueue = NULL; + } +} + +void CResponseQueueManager::Shutdown() +{ + if (m_pQueue != NULL) + { + delete m_pQueue; + m_pQueue = NULL; + } +} + +void CResponseQueueManager::FrameUpdatePostEntityThink() +{ + Assert(m_pQueue); + m_pQueue->PerFrameDispatch(); +} + +CResponseQueueManager g_ResponseQueueManager( "CResponseQueueManager" ); + diff --git a/sp/src/game/server/ai_speechqueue.h b/sp/src/game/server/ai_speechqueue.h new file mode 100644 index 00000000..15101b70 --- /dev/null +++ b/sp/src/game/server/ai_speechqueue.h @@ -0,0 +1,239 @@ +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: An event queue of AI concepts that dispatches them to appropriate characters. +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef AI_SPEECHQUEUE_H +#define AI_SPEECHQUEUE_H + +#if defined( _WIN32 ) +#pragma once +#endif + +#include "ai_speech.h" + +#define AI_RESPONSE_QUEUE_SIZE 64 + +enum DeferredResponseTarget_t // possible targets for a deferred response +{ + kDRT_ANY, // best matching respondent within range -- except for the one in the m_hTarget handle + kDRT_ALL, // send to everyone in range -- except for the one in the m_hTarget handle + kDRT_SPECIFIC, // a specific entity is targeted + + kDRT_MAX, // high water mark +}; + +// Allows you to postpone AI speech concepts to a later time, or to direct them to +// a specific character, or all of them. +class CResponseQueue +{ + //////////////////// Local types //////////////////// +public: + + // We pack up contexts to send along with the concept. + // For now I'll just copy criteria sets, but it will be better to do something + // more efficient in the future. + typedef AI_CriteriaSet DeferredContexts_t; + + struct CFollowupTargetSpec_t ///< to whom a followup is directed. Can be a specific entity or something more exotic. + { + DeferredResponseTarget_t m_iTargetType; ///< ANY, ALL, or SPECIFIC. If specific, pass through a handle to: + EHANDLE m_hHandle; ///< a specific target for the message, or a specific character to OMIT. + inline bool IsValid( void ) const; + + // constructors/destructors + explicit CFollowupTargetSpec_t(const DeferredResponseTarget_t &targetType, const EHANDLE &handle) + : m_iTargetType(targetType), m_hHandle(handle) + {}; + explicit CFollowupTargetSpec_t(const EHANDLE &handle) + : m_iTargetType(kDRT_SPECIFIC), m_hHandle(handle) + {}; + CFollowupTargetSpec_t(DeferredResponseTarget_t target) // eg, ANY, ALL, etc. + : m_iTargetType(target) + { + AssertMsg(m_iTargetType != kDRT_SPECIFIC, "Response rule followup tried to specify an entity target, but didn't provide the target.\n" ); + } + CFollowupTargetSpec_t(void) // default: invalid + : m_iTargetType(kDRT_MAX) + {}; + }; + + /// A single deferred response. + struct CDeferredResponse + { + AIConcept_t m_concept; + DeferredContexts_t m_contexts; ///< contexts to send along with the concept + float m_fDispatchTime; + EHANDLE m_hIssuer; ///< an entity, if issued by an entity + /* + DeferredResponseTarget_t m_iTargetType; + EHANDLE m_hTarget; // May be invalid. + */ + CFollowupTargetSpec_t m_Target; + + inline void Init( const AIConcept_t &concept, const AI_CriteriaSet * RESTRICT contexts, float dtime, const CFollowupTargetSpec_t &target, CBaseEntity *pIssuer ); + inline bool IsQuashed() { return !m_Target.IsValid(); } + void Quash(); ///< make this response invalid. + }; + /// write + static void DeferContextsFromCriteriaSet( DeferredContexts_t &contextsOut, const AI_CriteriaSet *criteriaIn ); + + //////////////////// Methods //////////////////// +public: + CResponseQueue( int queueSize ); + + /// Add a deferred response. + void Add( const AIConcept_t &concept, ///< concept to dispatch + const AI_CriteriaSet * RESTRICT contexts, ///< the contexts that come with it (may be NULL) + float time, ///< when to dispatch it. You can specify a time of zero to mean "immediately." + const CFollowupTargetSpec_t &targetspec, /// All information necessary to target this response + CBaseEntity *pIssuer = NULL ///< the entity who should not respond if this is a ANY or ALL rule. (eg, don't let people talk to themselves.) + ); + + /// Remove all deferred responses matching the concept and issuer. + void Remove( const AIConcept_t &concept, ///< concept to dispatch + CBaseEntity * const pIssuer = NULL ///< the entity issuing the response, if one exists. + ); + + /// Remove all deferred responses queued to be spoken by given character + void RemoveSpeechQueuedFor( const CBaseEntity *pSpeaker ); + + /// Empty out all pending events + void Evacuate(); + + /// Go through and dispatch any deferred responses. + void PerFrameDispatch(); + + /// Add an expressor owner to this queue. + void AddExpresserHost(CBaseEntity *host); + + /// Remove an expresser host from this queue. + void RemoveExpresserHost(CBaseEntity *host); + + /// Iterate over potential expressers for this queue + inline int GetNumExpresserTargets() const; + inline CBaseEntity *GetExpresserHost(int which) const; + +protected: + /// Actually send off one response to a consumer + /// Return true if dispatch succeeded + bool DispatchOneResponse( CDeferredResponse &response ); + +private: + /// Helper function for one case in DispatchOneResponse + /// (for better organization) + bool DispatchOneResponse_ThenANY( CDeferredResponse &response, AI_CriteriaSet * RESTRICT pDeferredCriteria, CBaseEntity * const RESTRICT pIssuer, float followupMaxDistSq ); + + //////////////////// Data //////////////////// +protected: + typedef CUtlFixedLinkedList< CDeferredResponse > QueueType_t; + QueueType_t m_Queue; // the queue of deferred responses, will eventually be sorted + /// Note about the queue type: if you move to replace it with a sorted priority queue, + /// make sure it is a type such that an iterator is not invalidated by inserts and deletes. + /// CResponseQueue::PerFrameDispatch() iterates over the queue calling DispatchOneResponse + /// on each in turn, and those responses may very easily add new events to the queue. + /// A crash will result if the iterator used in CResponseQueue::PerFrameDispatch()'s loop + /// becomes invalid. + + CUtlVector m_ExpresserTargets; // a list of legitimate expresser targets +}; + +inline void CResponseQueue::CDeferredResponse::Init(const AIConcept_t &concept, const AI_CriteriaSet * RESTRICT contexts, float dtime, const CFollowupTargetSpec_t &target, CBaseEntity *pIssuer ) +{ + m_concept = concept; + m_fDispatchTime = dtime; + /* + m_iTargetType = targetType; + m_hTarget = handle ; + */ + m_Target = target; + m_hIssuer = pIssuer; + DeferContextsFromCriteriaSet(m_contexts, contexts); +} + +int CResponseQueue::GetNumExpresserTargets() const +{ + return m_ExpresserTargets.Count(); +} + +CBaseEntity *CResponseQueue::GetExpresserHost(int which) const +{ + return m_ExpresserTargets[which]; +} + + +// The wrapper game system that contains a response queue, and ticks it each frame. + +class CResponseQueueManager : public CAutoGameSystemPerFrame +{ +public: + CResponseQueueManager(char const *name) : CAutoGameSystemPerFrame( name ) + { + m_pQueue = NULL; + } + virtual ~CResponseQueueManager(void); + virtual void Shutdown(); + virtual void FrameUpdatePostEntityThink( void ); + virtual void LevelInitPreEntity( void ); + + inline CResponseQueue *GetQueue(void) { Assert(m_pQueue); return m_pQueue; } + +protected: + CResponseQueue *m_pQueue; +}; + + +// Valid if the target type enum is within bounds. Furthermore if it +// specifies a specific entity, that handle must be valid. +bool CResponseQueue::CFollowupTargetSpec_t::IsValid( void ) const +{ + if (m_iTargetType >= kDRT_MAX) + return false; + if (m_iTargetType < 0) + return false; + if (m_iTargetType == kDRT_SPECIFIC && !m_hHandle.IsValid()) + return false; + + return true; +} + +extern CResponseQueueManager g_ResponseQueueManager; + + +// Handy global helper funcs + +/// Automatically queue up speech to happen immediately -- calls straight through to response rules add +inline void QueueSpeak( const AIConcept_t &concept, ///< concept name to say + const CResponseQueue::CFollowupTargetSpec_t& targetspec, ///< kDRT_ANY, kDRT_ALL, etc + CBaseEntity *pIssuer = NULL ///< if specifying ANY or ALL, use this to specify the one you *don't* want to speak + ) +{ + return g_ResponseQueueManager.GetQueue()->Add( concept, NULL, 0.0f, targetspec, pIssuer ); +} + +/// Automatically queue up speech to happen immediately -- calls straight through to response rules add +inline void QueueSpeak( const AIConcept_t &concept, ///< concept name to say + const CResponseQueue::CFollowupTargetSpec_t& targetspec, ///< kDRT_ANY, kDRT_ALL, etc + const AI_CriteriaSet &criteria, ///< criteria to pass in + CBaseEntity *pIssuer = NULL ///< if specifying ANY or ALL, use this to specify the one you *don't* want to speak + ) +{ + return g_ResponseQueueManager.GetQueue()->Add( concept, &criteria, 0.0f, targetspec, pIssuer ); +} + +/// Automatically queue up speech to happen immediately -- calls straight through to response rules add +inline void QueueSpeak( const AIConcept_t &concept, ///< concept name to say + const EHANDLE &target, ///< which entity shall speak + float delay, ///< how far in the future to speak + const AI_CriteriaSet &criteria, ///< criteria to pass in + CBaseEntity *pIssuer = NULL ) +{ + return g_ResponseQueueManager.GetQueue()->Add( concept, &criteria, gpGlobals->curtime + delay, + CResponseQueue::CFollowupTargetSpec_t(target), pIssuer ); +} + + + +#endif // AI_SPEECHQUEUE_H diff --git a/sp/src/game/server/baseentity.cpp b/sp/src/game/server/baseentity.cpp index 7284d0d2..dff5ee7f 100644 --- a/sp/src/game/server/baseentity.cpp +++ b/sp/src/game/server/baseentity.cpp @@ -66,6 +66,9 @@ #include "mapbase/matchers.h" #include "mapbase/datadesc_mod.h" #endif +#ifdef NEW_RESPONSE_SYSTEM +#include "ai_speech.h" +#endif #if defined( TF_DLL ) #include "tf_gamerules.h" @@ -7653,7 +7656,11 @@ bool CBaseEntity::HasContext( const char *nameandvalue ) const const char *p = nameandvalue; while ( p ) { +#ifdef NEW_RESPONSE_SYSTEM + p = SplitContext( p, key, sizeof( key ), value, sizeof( value ), NULL, nameandvalue ); +#else p = SplitContext( p, key, sizeof( key ), value, sizeof( value ), NULL ); +#endif return HasContext( key, value ); } @@ -7700,7 +7707,11 @@ void CBaseEntity::RemoveContext( const char *contextName ) while ( p ) { duration = 0.0f; +#ifdef NEW_RESPONSE_SYSTEM + p = SplitContext( p, key, sizeof( key ), value, sizeof( value ), &duration, contextName ); +#else p = SplitContext( p, key, sizeof( key ), value, sizeof( value ), &duration ); +#endif if ( duration ) { duration += gpGlobals->curtime; @@ -8938,56 +8949,76 @@ void CBaseEntity::AddContext( const char *contextName ) { char key[ 128 ]; char value[ 128 ]; - float duration; + float duration = 0.0f; const char *p = contextName; while ( p ) { duration = 0.0f; +#ifdef NEW_RESPONSE_SYSTEM + p = SplitContext( p, key, sizeof( key ), value, sizeof( value ), &duration, contextName ); +#else p = SplitContext( p, key, sizeof( key ), value, sizeof( value ), &duration ); +#endif if ( duration ) { duration += gpGlobals->curtime; } - int iIndex = FindContextByName( key ); - if ( iIndex != -1 ) - { - // Set the existing context to the new value - m_ResponseContexts[iIndex].m_iszValue = AllocPooledString( value ); - m_ResponseContexts[iIndex].m_fExpirationTime = duration; - continue; - } - - ResponseContext_t newContext; - newContext.m_iszName = AllocPooledString( key ); - newContext.m_iszValue = AllocPooledString( value ); - newContext.m_fExpirationTime = duration; - - m_ResponseContexts.AddToTail( newContext ); + AddContext( key, value, duration ); } } -#ifdef MAPBASE void CBaseEntity::AddContext( const char *name, const char *value, float duration ) { int iIndex = FindContextByName( name ); if ( iIndex != -1 ) { // Set the existing context to the new value + +#ifdef NEW_RESPONSE_SYSTEM + char buf[64]; + if ( RR::CApplyContextOperator::FindOperator( value )->Apply( + m_ResponseContexts[iIndex].m_iszValue.ToCStr(), value, buf, sizeof(buf) ) ) + { + m_ResponseContexts[iIndex].m_iszValue = AllocPooledString( buf ); + } + else + { + Warning( "RR: could not apply operator %s to prior value %s\n", + value, m_ResponseContexts[iIndex].m_iszValue.ToCStr() ); + m_ResponseContexts[iIndex].m_iszValue = AllocPooledString( value ); + } +#else m_ResponseContexts[iIndex].m_iszValue = AllocPooledString( value ); - m_ResponseContexts[iIndex].m_fExpirationTime = duration; - return; - } - - ResponseContext_t newContext; - newContext.m_iszName = AllocPooledString( name ); - newContext.m_iszValue = AllocPooledString( value ); - newContext.m_fExpirationTime = duration; - - m_ResponseContexts.AddToTail( newContext ); -} #endif + m_ResponseContexts[iIndex].m_fExpirationTime = duration; + } + else + { + ResponseContext_t newContext; + newContext.m_iszName = AllocPooledString( name ); + +#ifdef NEW_RESPONSE_SYSTEM + char buf[64]; + if ( RR::CApplyContextOperator::FindOperator( value )->Apply( + NULL, value, buf, sizeof(buf) ) ) + { + newContext.m_iszValue = AllocPooledString( buf ); + } + else + { + newContext.m_iszValue = AllocPooledString( value ); + } +#else + newContext.m_iszValue = AllocPooledString( value ); +#endif + + newContext.m_fExpirationTime = duration; + + m_ResponseContexts.AddToTail( newContext ); + } +} //----------------------------------------------------------------------------- // Purpose: @@ -9139,6 +9170,11 @@ void CBaseEntity::InputChangeVariable( inputdata_t &inputdata ) //----------------------------------------------------------------------------- void CBaseEntity::DispatchResponse( const char *conceptName ) { +#ifdef NEW_RESPONSE_SYSTEM + #undef IResponseSystem + using namespace ResponseRules; +#endif + IResponseSystem *rs = GetResponseSystem(); if ( !rs ) return; @@ -9169,6 +9205,56 @@ void CBaseEntity::DispatchResponse( const char *conceptName ) // Handle the response here... char response[ 256 ]; result.GetResponse( response, sizeof( response ) ); +#ifdef NEW_RESPONSE_SYSTEM + switch (result.GetType()) + { + case ResponseRules::RESPONSE_SPEAK: + { + EmitSound(response); + } + break; + case ResponseRules::RESPONSE_SENTENCE: + { + int sentenceIndex = SENTENCEG_Lookup(response); + if (sentenceIndex == -1) + { + // sentence not found + break; + } + + // FIXME: Get pitch from npc? + CPASAttenuationFilter filter(this); + CBaseEntity::EmitSentenceByIndex(filter, entindex(), CHAN_VOICE, sentenceIndex, 1, result.GetSoundLevel(), 0, PITCH_NORM); + } + break; + case ResponseRules::RESPONSE_SCENE: + { + // Try to fire scene w/o an actor + InstancedScriptedScene(NULL, response); + } + break; + case ResponseRules::RESPONSE_PRINT: + { + + } + break; + case ResponseRules::RESPONSE_ENTITYIO: + { + CAI_Expresser::FireEntIOFromResponse(response, this); + break; + } +#ifdef MAPBASE + case ResponseRules::RESPONSE_VSCRIPT: + { + RunScript( response, "ResponseScript" ); + break; + } +#endif + default: + // Don't know how to handle .vcds!!! + break; + } +#else #ifdef MAPBASE if (response[0] == '$') { @@ -9263,6 +9349,7 @@ void CBaseEntity::DispatchResponse( const char *conceptName ) // Don't know how to handle .vcds!!! break; } +#endif } //----------------------------------------------------------------------------- diff --git a/sp/src/game/server/baseentity.h b/sp/src/game/server/baseentity.h index a9c69ca3..358f2037 100644 --- a/sp/src/game/server/baseentity.h +++ b/sp/src/game/server/baseentity.h @@ -20,6 +20,10 @@ #include "ServerNetworkProperty.h" #include "shareddefs.h" #include "engine/ivmodelinfo.h" +#ifdef NEW_RESPONSE_SYSTEM +#include "AI_Criteria.h" +#include "AI_ResponseSystem.h" +#endif #include "vscript/ivscript.h" #include "vscript_server.h" @@ -29,8 +33,10 @@ class CDmgAccumulator; struct CSoundParameters; +#ifndef NEW_RESPONSE_SYSTEM class AI_CriteriaSet; class IResponseSystem; +#endif class IEntitySaveUtils; class CRecipientFilter; class CStudioHdr; @@ -39,6 +45,11 @@ class CStudioHdr; // FIXME: Could do this in the script file by making it required and bumping up weighting there instead... #define CONCEPT_WEIGHT 5.0f +#ifdef NEW_RESPONSE_SYSTEM +// Relax the namespace standard a bit so that less code has to be changed +#define IResponseSystem ResponseRules::IResponseSystem +#endif + typedef CHandle EHANDLE; #define MANUALMODE_GETSET_PROP(type, accessorName, varName) \ @@ -1001,10 +1012,10 @@ public: const char *GetContextValue( const char *contextName ) const; float GetContextExpireTime( const char *name ); void RemoveContext( const char *nameandvalue ); - void AddContext( const char *name, const char *value, float duration = 0.0f ); #endif void AddContext( const char *nameandvalue ); + void AddContext( const char *name, const char *value, float duration = 0.0f ); protected: CUtlVector< ResponseContext_t > m_ResponseContexts; @@ -1294,6 +1305,12 @@ public: #endif virtual void ModifyOrAppendCriteria( AI_CriteriaSet& set ); +#ifdef NEW_RESPONSE_SYSTEM + // this computes criteria that depend on the other criteria having been set. + // needs to be done in a second pass because we may have multiple overrids for + // a context before it all settles out. + virtual void ModifyOrAppendDerivedCriteria( AI_CriteriaSet& set ) {}; +#endif void AppendContextToCriteria( AI_CriteriaSet& set, const char *prefix = "" ); #ifdef MAPBASE void ReAppendContextCriteria( AI_CriteriaSet& set ); diff --git a/sp/src/game/server/baseflex.h b/sp/src/game/server/baseflex.h index 215b13f5..ec809534 100644 --- a/sp/src/game/server/baseflex.h +++ b/sp/src/game/server/baseflex.h @@ -19,7 +19,9 @@ struct flexsettinghdr_t; struct flexsetting_t; +#ifndef NEW_RESPONSE_SYSTEM class AI_Response; +#endif //----------------------------------------------------------------------------- // Purpose: A .vfe referenced by a scene during .vcd playback diff --git a/sp/src/game/server/basemultiplayerplayer.cpp b/sp/src/game/server/basemultiplayerplayer.cpp index b6ecd44c..d5a99514 100644 --- a/sp/src/game/server/basemultiplayerplayer.cpp +++ b/sp/src/game/server/basemultiplayerplayer.cpp @@ -28,6 +28,7 @@ CBaseMultiplayerPlayer::CBaseMultiplayerPlayer() CBaseMultiplayerPlayer::~CBaseMultiplayerPlayer() { m_pAchievementKV->deleteThis(); + delete m_pExpresser; } //----------------------------------------------------------------------------- @@ -87,10 +88,16 @@ IResponseSystem *CBaseMultiplayerPlayer::GetResponseSystem() //----------------------------------------------------------------------------- // Purpose: Doesn't actually speak the concept. Just finds a response in the system. You then have to play it yourself. //----------------------------------------------------------------------------- -AI_Response *CBaseMultiplayerPlayer::SpeakConcept( int iConcept ) +bool CBaseMultiplayerPlayer::SpeakConcept( AI_Response &response, int iConcept ) { m_iCurrentConcept = iConcept; - return SpeakFindResponse( g_pszMPConcepts[iConcept] ); +#ifdef NEW_RESPONSE_SYSTEM + CAI_Concept concept(g_pszMPConcepts[iConcept]); + concept.SetSpeaker(this); + return FindResponse( response, concept ); +#else + return SpeakFindResponse( response, g_pszMPConcepts[iConcept] ); +#endif } //----------------------------------------------------------------------------- diff --git a/sp/src/game/server/basemultiplayerplayer.h b/sp/src/game/server/basemultiplayerplayer.h index 06a0e00d..9550a86a 100644 --- a/sp/src/game/server/basemultiplayerplayer.h +++ b/sp/src/game/server/basemultiplayerplayer.h @@ -28,7 +28,7 @@ public: virtual bool SpeakIfAllowed( AIConcept_t concept, const char *modifiers = NULL, char *pszOutResponseChosen = NULL, size_t bufsize = 0, IRecipientFilter *filter = NULL ); virtual IResponseSystem *GetResponseSystem(); - AI_Response *SpeakConcept( int iConcept ); + bool SpeakConcept( AI_Response &response, int iConcept ); virtual bool SpeakConceptIfAllowed( int iConcept, const char *modifiers = NULL, char *pszOutResponseChosen = NULL, size_t bufsize = 0, IRecipientFilter *filter = NULL ); virtual bool CanHearAndReadChatFrom( CBasePlayer *pPlayer ); diff --git a/sp/src/game/server/hl2/ai_behavior_actbusy.cpp b/sp/src/game/server/hl2/ai_behavior_actbusy.cpp index 9a4f09e6..288e93a0 100644 --- a/sp/src/game/server/hl2/ai_behavior_actbusy.cpp +++ b/sp/src/game/server/hl2/ai_behavior_actbusy.cpp @@ -1755,7 +1755,11 @@ void CAI_ActBusyBehavior::PlaySoundForActBusy( busyanimparts_t AnimPart ) CAI_Expresser *pExpresser = GetOuter()->GetExpresser(); if ( pExpresser ) { +#ifdef NEW_RESPONSE_SYSTEM + CAI_Concept concept = STRING(pBusyAnim->iszSounds[AnimPart]); +#else const char *concept = STRING(pBusyAnim->iszSounds[AnimPart]); +#endif // Must be able to speak the concept if ( !pExpresser->IsSpeaking() && pExpresser->CanSpeakConcept( concept ) ) diff --git a/sp/src/game/server/hl2/ai_behavior_police.cpp b/sp/src/game/server/hl2/ai_behavior_police.cpp index ffb8dd96..8dc5ec40 100644 --- a/sp/src/game/server/hl2/ai_behavior_police.cpp +++ b/sp/src/game/server/hl2/ai_behavior_police.cpp @@ -143,7 +143,12 @@ void CAI_PolicingBehavior::HostSpeakSentence( const char *pSentence, SentencePri } else if ( GetOuter()->GetExpresser() ) { +#ifdef NEW_RESPONSE_SYSTEM + CAI_Concept concept = pSentence; + GetOuter()->GetExpresser()->Speak( concept ); +#else GetOuter()->GetExpresser()->Speak( pSentence ); +#endif } #endif } @@ -168,7 +173,12 @@ void CAI_PolicingBehavior::HostSpeakSentence( const char *pSentence, const char } else if ( GetOuter()->GetExpresser() ) { +#ifdef NEW_RESPONSE_SYSTEM + CAI_Concept concept( pSentence ); + GetOuter()->GetExpresser()->Speak( concept, modifiers ); +#else GetOuter()->GetExpresser()->Speak( pSentence, modifiers ); +#endif } #endif } diff --git a/sp/src/game/server/hl2/env_speaker.cpp b/sp/src/game/server/hl2/env_speaker.cpp index 7b193a9b..25a65017 100644 --- a/sp/src/game/server/hl2/env_speaker.cpp +++ b/sp/src/game/server/hl2/env_speaker.cpp @@ -243,6 +243,58 @@ void CSpeaker::DispatchResponse( const char *conceptName ) PrecacheScriptSound( response ); } +#ifdef NEW_RESPONSE_SYSTEM + switch (result.GetType()) + { + case ResponseRules::RESPONSE_SPEAK: + { + pTarget->EmitSound( response ); + } + break; + case ResponseRules::RESPONSE_SENTENCE: + { + int sentenceIndex = SENTENCEG_Lookup( response ); + if (sentenceIndex == -1) + { + // sentence not found + break; + } + + // FIXME: Get pitch from npc? + CPASAttenuationFilter filter( pTarget ); + CBaseEntity::EmitSentenceByIndex( filter, pTarget->entindex(), CHAN_VOICE, sentenceIndex, 1, result.GetSoundLevel(), 0, PITCH_NORM ); + } + break; + case ResponseRules::RESPONSE_SCENE: + { + CBaseFlex *pFlex = NULL; + if (pTarget != this) + { + // Attempt to get flex on the target + pFlex = dynamic_cast(pTarget); + } + InstancedScriptedScene(pFlex, response); + } + break; + case ResponseRules::RESPONSE_PRINT: + { + + } + break; + case ResponseRules::RESPONSE_ENTITYIO: + { + CAI_Expresser::FireEntIOFromResponse( response, pTarget ); + break; + } + case ResponseRules::RESPONSE_VSCRIPT: + { + pTarget->RunScript( response, "ResponseScript" ); + break; + } + default: + break; + } +#else switch ( result.GetType() ) { case RESPONSE_SPEAK: @@ -283,6 +335,7 @@ void CSpeaker::DispatchResponse( const char *conceptName ) default: break; } +#endif // AllocPooledString? m_OnSpeak.Set(MAKE_STRING(response), pTarget, this); diff --git a/sp/src/game/server/hl2/npc_combine.cpp b/sp/src/game/server/hl2/npc_combine.cpp index 7599a6ac..d4ce19ac 100644 --- a/sp/src/game/server/hl2/npc_combine.cpp +++ b/sp/src/game/server/hl2/npc_combine.cpp @@ -3004,7 +3004,11 @@ bool CNPC_Combine::SpeakIfAllowed( const char *concept, const char *modifiers, S AI_CriteriaSet set; if (modifiers) { +#ifdef NEW_RESPONSE_SYSTEM + GatherCriteria( &set, concept, modifiers ); +#else GetExpresser()->MergeModifiers(set, modifiers); +#endif } return SpeakIfAllowed( concept, set, sentencepriority, sentencecriteria ); } diff --git a/sp/src/game/server/hl2/npc_metropolice.cpp b/sp/src/game/server/hl2/npc_metropolice.cpp index 8588c043..3efb9741 100644 --- a/sp/src/game/server/hl2/npc_metropolice.cpp +++ b/sp/src/game/server/hl2/npc_metropolice.cpp @@ -1156,7 +1156,11 @@ bool CNPC_MetroPolice::SpeakIfAllowed( const char *concept, const char *modifier AI_CriteriaSet set; if (modifiers) { +#ifdef NEW_RESPONSE_SYSTEM + GatherCriteria( &set, concept, modifiers ); +#else GetExpresser()->MergeModifiers(set, modifiers); +#endif } return SpeakIfAllowed( concept, set, sentencepriority, sentencecriteria ); } diff --git a/sp/src/game/server/hl2/npc_zombie.cpp b/sp/src/game/server/hl2/npc_zombie.cpp index 382e2dd2..2191b394 100644 --- a/sp/src/game/server/hl2/npc_zombie.cpp +++ b/sp/src/game/server/hl2/npc_zombie.cpp @@ -1210,16 +1210,28 @@ const char *CZombieCustom::GetMoanSound( int nSound ) // We could probably do this through the response system alone now, but whatever. modifiers.AppendCriteria( "moansound", UTIL_VarArgs("%i", nSound & 4) ); +#ifdef NEW_RESPONSE_SYSTEM + AI_Response response; + CAI_Concept concept = "TLK_ZOMBIE_MOAN"; + concept.SetSpeaker( this ); + if (!FindResponse( response, concept, &modifiers )) + return "NPC_BaseZombie.Moan1"; +#else AI_Response *response = SpeakFindResponse(TLK_ZOMBIE_MOAN, modifiers); if ( !response ) return "NPC_BaseZombie.Moan1"; +#endif // Must be static so it could be returned static char szSound[128]; +#ifdef NEW_RESPONSE_SYSTEM + response.GetName(szSound, sizeof(szSound)); +#else response->GetName(szSound, sizeof(szSound)); - delete response; +#endif + return szSound; } diff --git a/sp/src/game/server/sceneentity.cpp b/sp/src/game/server/sceneentity.cpp index 6914fd19..92914d05 100644 --- a/sp/src/game/server/sceneentity.cpp +++ b/sp/src/game/server/sceneentity.cpp @@ -32,6 +32,7 @@ #include "scenefilecache/ISceneFileCache.h" #include "SceneCache.h" #include "scripted.h" +#include "basemultiplayerplayer.h" #include "env_debughistory.h" #include "team.h" #include "triggers.h" @@ -2348,6 +2349,40 @@ void CSceneEntity::InputInterjectResponse( inputdata_t &inputdata ) } else { +#ifdef NEW_RESPONSE_SYSTEM + CUtlString modifiers("scene:"); + modifiers += STRING( GetEntityName() ); + + while (candidates.Count() > 0) + { + // Pick a random slot in the candidates array. + int slot = RandomInt( 0, candidates.Count() - 1 ); + + CAI_BaseActor *npc = candidates[ slot ]; + + // Try to find the response for this slot. + AI_Response response; + CAI_Concept concept(inputdata.value.String()); + concept.SetSpeaker(npc); + AI_CriteriaSet set; + npc->GatherCriteria(&set, concept, modifiers.Get()); + bool result = npc->FindResponse( response, concept, &set); + if ( result ) + { + float duration = npc->GetResponseDuration( &response ); + + if ( ( duration > 0.0f ) && npc->PermitResponse( duration ) ) + { + // If we could look it up, dispatch it and bail. + npc->SpeakDispatchResponse( concept, &response, &set); + return; + } + } + + // Remove this entry and look for another one. + candidates.FastRemove(slot); + } +#else CUtlVector< NPCInterjection > validResponses; char modifiers[ 512 ]; @@ -2399,6 +2434,7 @@ void CSceneEntity::InputInterjectResponse( inputdata_t &inputdata ) } } } +#endif } } @@ -3019,6 +3055,16 @@ void CSceneEntity::QueueResumePlayback( void ) CAI_BaseActor *pBaseActor = dynamic_cast(pActor); if ( pBaseActor ) { +#ifdef NEW_RESPONSE_SYSTEM + AI_Response response; + CAI_Concept concept(STRING(m_iszResumeSceneFile)); + bool result = pBaseActor->FindResponse( response, concept, NULL ); + if ( result ) + { + const char* szResponse = response.GetResponsePtr(); + bStartedScene = InstancedScriptedScene( NULL, szResponse, &m_hWaitingForThisResumeScene, 0, false ) != 0; + } +#else AI_Response *result = pBaseActor->SpeakFindResponse( STRING(m_iszResumeSceneFile), NULL ); if ( result ) { @@ -3026,6 +3072,7 @@ void CSceneEntity::QueueResumePlayback( void ) result->GetResponse( response, sizeof( response ) ); bStartedScene = InstancedScriptedScene( NULL, response, &m_hWaitingForThisResumeScene, 0, false ) != 0; } +#endif } } } @@ -4783,6 +4830,26 @@ void CSceneEntity::OnSceneFinished( bool canceled, bool fireoutput ) m_OnCompletion.FireOutput( this, this, 0 ); } +#ifdef NEW_RESPONSE_SYSTEM + { + CBaseFlex *pFlex = FindNamedActor( 0 ) ; + if ( pFlex ) + { + CBaseMultiplayerPlayer *pAsPlayer = dynamic_cast(pFlex); + if (pAsPlayer) + { + CAI_Expresser *pExpresser = pAsPlayer->GetExpresser(); + pExpresser->OnSpeechFinished(); + } + else if ( CAI_BaseActor *pActor = dynamic_cast( pFlex ) ) + { + CAI_Expresser *pExpresser = pActor->GetExpresser(); + pExpresser->OnSpeechFinished(); + } + } + } +#endif + // Put face back in neutral pose ClearSceneEvents( m_pScene, canceled ); @@ -5160,6 +5227,34 @@ float GetSceneDuration( char const *pszScene ) return (float)msecs * 0.001f; } +//----------------------------------------------------------------------------- +// Purpose: +// Input : *pszScene - +// Output : float +//----------------------------------------------------------------------------- +float GetSceneSpeechDuration( char const* pszScene ) +{ + float flSecs = 0.0f; + + CChoreoScene* pScene = CSceneEntity::LoadScene( pszScene, nullptr ); + if (pScene) + { + for (int i = pScene->GetNumEvents() - 1; i >= 0; i--) + { + CChoreoEvent* pEvent = pScene->GetEvent( i ); + + if (pEvent->GetType() == CChoreoEvent::SPEAK) + { + flSecs = pEvent->GetStartTime() + pEvent->GetDuration(); + break; + } + } + delete pScene; + } + + return flSecs; +} + //----------------------------------------------------------------------------- // Purpose: // Input : *pszScene - diff --git a/sp/src/game/server/sceneentity.h b/sp/src/game/server/sceneentity.h index 6e005a60..a004c3e1 100644 --- a/sp/src/game/server/sceneentity.h +++ b/sp/src/game/server/sceneentity.h @@ -13,7 +13,9 @@ // List of the last 5 lines of speech from NPCs for bug reports #define SPEECH_LIST_MAX_SOUNDS 5 +#ifndef NEW_RESPONSE_SYSTEM class AI_Response; +#endif struct recentNPCSpeech_t { @@ -44,6 +46,7 @@ bool IsRunningScriptedSceneWithFlexAndNotPaused( CBaseFlex *pActor, bool bIgnore CUtlVector< CHandle< CSceneEntity > > *GetActiveSceneList(); #endif float GetSceneDuration( char const *pszScene ); +float GetSceneSpeechDuration( char const* pszScene ); int GetSceneSpeechCount( char const *pszScene ); bool IsInInterruptableScenes( CBaseFlex *pActor ); diff --git a/sp/src/game/server/server_base.vpc b/sp/src/game/server/server_base.vpc index df35da1e..64558734 100644 --- a/sp/src/game/server/server_base.vpc +++ b/sp/src/game/server/server_base.vpc @@ -126,8 +126,10 @@ $Project $File "ai_concommands.cpp" $File "ai_condition.cpp" $File "ai_condition.h" - $File "AI_Criteria.cpp" + $File "AI_Criteria.cpp" [!$NEW_RESPONSE_SYSTEM] $File "AI_Criteria.h" + $File "$SRCDIR\game\shared\ai_criteria_new.cpp" [$NEW_RESPONSE_SYSTEM] + $File "$SRCDIR\game\shared\ai_criteria_new.h" [$NEW_RESPONSE_SYSTEM] $File "ai_debug.h" $File "$SRCDIR\game\shared\ai_debug_shared.h" $File "ai_default.cpp" @@ -182,8 +184,10 @@ $Project $File "ai_planesolver.h" $File "ai_playerally.cpp" $File "ai_playerally.h" - $File "AI_ResponseSystem.cpp" + $File "AI_ResponseSystem.cpp" [!$NEW_RESPONSE_SYSTEM] $File "AI_ResponseSystem.h" + $File "$SRCDIR\game\shared\ai_responsesystem_new.cpp" [$NEW_RESPONSE_SYSTEM] + $File "$SRCDIR\game\shared\ai_responsesystem_new.h" [$NEW_RESPONSE_SYSTEM] $File "ai_route.cpp" $File "ai_route.h" $File "ai_routedist.h" @@ -197,8 +201,10 @@ $Project $File "ai_senses.h" $File "ai_sentence.cpp" $File "ai_sentence.h" - $File "ai_speech.cpp" + $File "ai_speech.cpp" [!$NEW_RESPONSE_SYSTEM] $File "ai_speech.h" + $File "ai_speech_new.cpp" [$NEW_RESPONSE_SYSTEM] + $File "ai_speech_new.h" [$NEW_RESPONSE_SYSTEM] $File "ai_speechfilter.cpp" $File "ai_speechfilter.h" $File "ai_squad.cpp" @@ -428,7 +434,6 @@ $Project $File "init_factory.h" $File "intermission.cpp" $File "$SRCDIR\public\interpolatortypes.h" - $File "$SRCDIR\game\shared\interval.h" $File "$SRCDIR\public\iregistry.h" $File "$SRCDIR\game\shared\iscenetokenprocessor.h" $File "iservervehicle.h" @@ -686,7 +691,6 @@ $Project "h_export.cpp" \ "init_factory.cpp" \ "$SRCDIR\public\interpolatortypes.cpp" \ - "$SRCDIR\game\shared\interval.cpp" \ "$SRCDIR\public\keyframe\keyframe.cpp" \ "$SRCDIR\common\language.cpp" \ "$SRCDIR\public\map_utils.cpp" \ @@ -1000,6 +1004,7 @@ $Project $File "$SRCDIR\public\winlite.h" $File "$SRCDIR\public\worldsize.h" $File "$SRCDIR\public\zip_uncompressed.h" + $File "$SRCDIR\public\tier1\interval.h" $File "$SRCDIR\game\shared\mp_shareddefs.h" $File "$SRCDIR\game\shared\econ\ihasowner.h" //Haptics diff --git a/sp/src/game/server/server_mapbase.vpc b/sp/src/game/server/server_mapbase.vpc index 37146238..b4672f19 100644 --- a/sp/src/game/server/server_mapbase.vpc +++ b/sp/src/game/server/server_mapbase.vpc @@ -10,6 +10,7 @@ $Configuration { $PreprocessorDefinitions "$BASE;ASW_PROJECTED_TEXTURES;DYNAMIC_RTT_SHADOWS;GLOWS_ENABLE" $PreprocessorDefinitions "$BASE;MAPBASE_VSCRIPT" [$MAPBASE_VSCRIPT] + $PreprocessorDefinitions "$BASE;NEW_RESPONSE_SYSTEM" [$NEW_RESPONSE_SYSTEM] } } @@ -27,6 +28,9 @@ $Project $File "postprocesscontroller.h" $File "env_dof_controller.cpp" $File "env_dof_controller.h" + $File "ai_expresserfollowup.cpp" [$NEW_RESPONSE_SYSTEM] + $File "ai_speechqueue.cpp" [$NEW_RESPONSE_SYSTEM] + $File "ai_speechqueue.h" [$NEW_RESPONSE_SYSTEM] $Folder "Mapbase" { @@ -104,5 +108,6 @@ $Project $Folder "Link Libraries" { $Lib "vscript" [$MAPBASE_VSCRIPT] + $Lib "responserules" [$NEW_RESPONSE_SYSTEM] } } diff --git a/sp/src/game/shared/ai_criteria_new.cpp b/sp/src/game/shared/ai_criteria_new.cpp new file mode 100644 index 00000000..31a5b1ef --- /dev/null +++ b/sp/src/game/shared/ai_criteria_new.cpp @@ -0,0 +1,38 @@ +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// +// +// Purpose: +// +// $NoKeywords: $ +// +//===========================================================================// +#include "cbase.h" +#include "ai_criteria.h" + +#ifdef GAME_DLL +#include "ai_speech.h" +#endif + +#include +#include "engine/ienginesound.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include + + + +BEGIN_SIMPLE_DATADESC( AI_ResponseParams ) + DEFINE_FIELD( flags, FIELD_SHORT ), + DEFINE_FIELD( odds, FIELD_SHORT ), + DEFINE_FIELD( soundlevel, FIELD_CHARACTER ), + DEFINE_FIELD( delay, FIELD_INTEGER ), // These are compressed down to two float16s, so treat as an INT for saverestore + DEFINE_FIELD( respeakdelay, FIELD_INTEGER ), // +END_DATADESC() + +BEGIN_SIMPLE_DATADESC( AI_Response ) + DEFINE_FIELD( m_Type, FIELD_CHARACTER ), + DEFINE_ARRAY( m_szResponseName, FIELD_CHARACTER, AI_Response::MAX_RESPONSE_NAME ), + DEFINE_ARRAY( m_szMatchingRule, FIELD_CHARACTER, AI_Response::MAX_RULE_NAME ), + // DEFINE_FIELD( m_pCriteria, FIELD_??? ), // Don't need to save this probably + DEFINE_EMBEDDED( m_Params ), +END_DATADESC() + diff --git a/sp/src/game/shared/ai_criteria_new.h b/sp/src/game/shared/ai_criteria_new.h new file mode 100644 index 00000000..b5d2c4fd --- /dev/null +++ b/sp/src/game/shared/ai_criteria_new.h @@ -0,0 +1,41 @@ +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef AI_CRITERIA_H +#define AI_CRITERIA_H +#ifdef _WIN32 +#pragma once +#endif + +#include "tier1/utlrbtree.h" +#include "tier1/utlsymbol.h" +#include "tier1/interval.h" +#include "mathlib/compressed_vector.h" +#include "../../public/responserules/response_types.h" + + +using ResponseRules::ResponseType_t; + +extern const char *SplitContext( const char *raw, char *key, int keylen, char *value, int valuelen, float *duration, const char *entireContext ); + +#ifndef AI_CriteriaSet +#define AI_CriteriaSet ResponseRules::CriteriaSet +#endif + +typedef ResponseRules::ResponseParams AI_ResponseParams ; +typedef ResponseRules::CRR_Response AI_Response; + + + +/* +// An AI response that is dynamically new'ed up and returned from SpeakFindResponse. +class AI_ResponseReturnValue : AI_Response +{ + +}; +*/ + +#endif // AI_CRITERIA_H diff --git a/sp/src/game/shared/ai_responsesystem_new.cpp b/sp/src/game/shared/ai_responsesystem_new.cpp new file mode 100644 index 00000000..80cbcca6 --- /dev/null +++ b/sp/src/game/shared/ai_responsesystem_new.cpp @@ -0,0 +1,1271 @@ +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + + +#include "cbase.h" +#include "soundemittersystem/isoundemittersystembase.h" +#include "ai_responsesystem.h" +#include "igamesystem.h" +#include "ai_criteria.h" +#include +#include "filesystem.h" +#include "utldict.h" +#ifdef GAME_DLL +#include "ai_speech.h" +#endif +#include "tier0/icommandline.h" +#include +#include "isaverestore.h" +#include "utlbuffer.h" +#include "stringpool.h" +#include "fmtstr.h" +#include "multiplay_gamerules.h" +#include "characterset.h" +#include "responserules/response_host_interface.h" +#include "../../responserules/runtime/response_types_internal.h" + +#include "scenefilecache/ISceneFileCache.h" + +#ifdef GAME_DLL +#include "sceneentity.h" +#endif + +#include "networkstringtabledefs.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +#undef IResponseSystem +using namespace ResponseRules; + +extern ConVar rr_debugresponses; // ( "rr_debugresponses", "0", FCVAR_NONE, "Show verbose matching output (1 for simple, 2 for rule scoring, 3 for noisy). If set to 4, it will only show response success/failure for npc_selected NPCs." ); +extern ConVar rr_debugrule; // ( "rr_debugrule", "", FCVAR_NONE, "If set to the name of the rule, that rule's score will be shown whenever a concept is passed into the response rules system."); +extern ConVar rr_dumpresponses; // ( "rr_dumpresponses", "0", FCVAR_NONE, "Dump all response_rules.txt and rules (requires restart)" ); +extern ConVar rr_debugresponseconcept; // ( "rr_debugresponseconcept", "", FCVAR_NONE, "If set, rr_debugresponses will print only responses testing for the specified concept" ); + +extern ISceneFileCache *scenefilecache; +extern INetworkStringTable *g_pStringTableClientSideChoreoScenes; + +static characterset_t g_BreakSetIncludingColons; + +// Simple class to initialize breakset +class CBreakInit +{ +public: + CBreakInit() + { + CharacterSetBuild( &g_BreakSetIncludingColons, "{}()':" ); + } +} g_BreakInit; + +inline char rr_tolower( char c ) +{ + if ( c >= 'A' && c <= 'Z' ) + return c - 'A' + 'a'; + return c; +} +// BUG BUG: Note that this function doesn't check for data overruns!!! +// Also, this function lowercases the token as it parses!!! +inline const char *RR_Parse(const char *data, char *token ) +{ + unsigned char c; + int len; + characterset_t *breaks = &g_BreakSetIncludingColons; + len = 0; + token[0] = 0; + + if (!data) + return NULL; + + // skip whitespace +skipwhite: + while ( (c = *data) <= ' ') + { + if (c == 0) + return NULL; // end of file; + data++; + } + + // skip // comments + if (c=='/' && data[1] == '/') + { + while (*data && *data != '\n') + data++; + goto skipwhite; + } + + + // handle quoted strings specially + if (c == '\"') + { + data++; + while (1) + { + c = rr_tolower( *data++ ); + if (c=='\"' || !c) + { + token[len] = 0; + return data; + } + token[len] = c; + len++; + } + } + + // parse single characters + if ( IN_CHARACTERSET( *breaks, c ) ) + { + token[len] = c; + len++; + token[len] = 0; + return data+1; + } + + // parse a regular word + do + { + token[len] = rr_tolower( c ); + data++; + len++; + c = rr_tolower( *data ); + if ( IN_CHARACTERSET( *breaks, c ) ) + break; + } while (c>32); + + token[len] = 0; + return data; +} + +#ifdef MAPBASE +// A version of the above which preserves casing and supports escaped quotes +inline const char *RR_Parse_Preserve(const char *data, char *token ) +{ + unsigned char c; + int len; + characterset_t *breaks = &g_BreakSetIncludingColons; + len = 0; + token[0] = 0; + + if (!data) + return NULL; + + // skip whitespace +skipwhite: + while ( (c = *data) <= ' ') + { + if (c == 0) + return NULL; // end of file; + data++; + } + + // skip // comments + if (c=='/' && data[1] == '/') + { + while (*data && *data != '\n') + data++; + goto skipwhite; + } + + // handle quoted strings specially + if (c == '\"') + { + bool escaped = false; + data++; + while (1) + { + c = *data++; + if ((c=='\"' && !escaped) || !c) + { + token[len] = 0; + return data; + } + + escaped = (c == '\\'); + if (!escaped) + { + token[len] = c; + len++; + } + } + } + + // parse single characters + if ( IN_CHARACTERSET( *breaks, c ) ) + { + token[len] = c; + len++; + token[len] = 0; + return data+1; + } + + // parse a regular word + do + { + token[len] = c; + data++; + len++; + c = *data; + if ( IN_CHARACTERSET( *breaks, c ) ) + break; + } while (c>32); + + token[len] = 0; + return data; +} +#endif + +namespace ResponseRules +{ + extern const char *ResponseCopyString( const char *in ); +} + +// Host functions required by the ResponseRules::IEngineEmulator interface +class CResponseRulesToEngineInterface : public ResponseRules::IEngineEmulator +{ + /// Given an input text buffer data pointer, parses a single token into the variable token and returns the new + /// reading position + virtual const char *ParseFile( const char *data, char *token, int maxlen ) + { + NOTE_UNUSED( maxlen ); + return RR_Parse( data, token ); + } + +#ifdef MAPBASE + /// (Optional) Same as ParseFile, but with casing preserved and escaped quotes supported + virtual const char *ParseFilePreserve( const char *data, char *token, int maxlen ) + { + NOTE_UNUSED( maxlen ); + return RR_Parse_Preserve( data, token ); + } +#endif + + /// Return a pointer to an IFileSystem we can use to read and process scripts. + virtual IFileSystem *GetFilesystem() + { + return filesystem; + } + + /// Return a pointer to an instance of an IUniformRandomStream + virtual IUniformRandomStream *GetRandomStream() + { + return random; + } + + /// Return a pointer to a tier0 ICommandLine + virtual ICommandLine *GetCommandLine() + { + return CommandLine(); + } + + /// Emulates the server's UTIL_LoadFileForMe + virtual byte *LoadFileForMe( const char *filename, int *pLength ) + { + return UTIL_LoadFileForMe( filename, pLength ); + } + + /// Emulates the server's UTIL_FreeFile + virtual void FreeFile( byte *buffer ) + { + return UTIL_FreeFile( buffer ); + } + +}; + +CResponseRulesToEngineInterface g_ResponseRulesEngineWrapper; +IEngineEmulator *IEngineEmulator::s_pSingleton = &g_ResponseRulesEngineWrapper; + + +BEGIN_SIMPLE_DATADESC( ParserResponse ) + // DEFINE_FIELD( type, FIELD_INTEGER ), + // DEFINE_ARRAY( value, FIELD_CHARACTER ), + // DEFINE_FIELD( weight, FIELD_FLOAT ), + DEFINE_FIELD( depletioncount, FIELD_CHARACTER ), + // DEFINE_FIELD( first, FIELD_BOOLEAN ), + // DEFINE_FIELD( last, FIELD_BOOLEAN ), +END_DATADESC() + + +BEGIN_SIMPLE_DATADESC( ResponseGroup ) + // DEFINE_FIELD( group, FIELD_UTLVECTOR ), + // DEFINE_FIELD( rp, FIELD_EMBEDDED ), + // DEFINE_FIELD( m_bDepleteBeforeRepeat, FIELD_BOOLEAN ), + DEFINE_FIELD( m_nDepletionCount, FIELD_CHARACTER ), + // DEFINE_FIELD( m_bHasFirst, FIELD_BOOLEAN ), + // DEFINE_FIELD( m_bHasLast, FIELD_BOOLEAN ), + // DEFINE_FIELD( m_bSequential, FIELD_BOOLEAN ), + // DEFINE_FIELD( m_bNoRepeat, FIELD_BOOLEAN ), + DEFINE_FIELD( m_bEnabled, FIELD_BOOLEAN ), + DEFINE_FIELD( m_nCurrentIndex, FIELD_CHARACTER ), +END_DATADESC() + + +/// Add some game-specific code to the basic response system +/// (eg, the scene precacher, which requires the client and server +/// to work) + +class CGameResponseSystem : public CResponseSystem +{ +public: + CGameResponseSystem(); + + virtual void Precache(); + virtual void PrecacheResponses( bool bEnable ) + { + m_bPrecache = bEnable; + } + bool ShouldPrecache() { return m_bPrecache; } + +protected: + bool m_bPrecache; +}; + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CGameResponseSystem::CGameResponseSystem() : m_bPrecache(true) +{}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- + +#if 0 +class CScenePrecacheSystem : public CAutoGameSystem +{ +public: + CScenePrecacheSystem() : CAutoGameSystem( "CScenePrecacheSystem" ), m_RepeatCounts( 0, 0, DefLessFunc( int ) ) + { + } + + // Level init, shutdown + virtual void LevelShutdownPreEntity() + { + m_RepeatCounts.Purge(); + } + + bool ShouldPrecache( char const *pszScene ) + { + int hash = HashStringCaselessConventional( pszScene ); + + int slot = m_RepeatCounts.Find( hash ); + if ( slot != m_RepeatCounts.InvalidIndex() ) + { + m_RepeatCounts[ slot ]++; + return false; + } + + m_RepeatCounts.Insert( hash, 0 ); + return true; + } + +private: + + CUtlMap< int, int > m_RepeatCounts; +}; + +static CScenePrecacheSystem g_ScenePrecacheSystem; +//----------------------------------------------------------------------------- +// Purpose: Used for precaching instanced scenes +// Input : *pszScene - +//----------------------------------------------------------------------------- +void PrecacheInstancedScene( char const *pszScene ) +{ + static int nMakingReslists = -1; + + if ( !g_ScenePrecacheSystem.ShouldPrecache( pszScene ) ) + return; + + if ( nMakingReslists == -1 ) + { + nMakingReslists = CommandLine()->FindParm( "-makereslists" ) > 0 ? 1 : 0; + } + + if ( nMakingReslists == 1 ) + { + // Just stat the file to add to reslist + g_pFullFileSystem->Size( pszScene ); + } + + // verify existence, cache is pre-populated, should be there + SceneCachedData_t sceneData; + if ( !scenefilecache->GetSceneCachedData( pszScene, &sceneData ) ) + { + // Scenes are sloppy and don't always exist. + // A scene that is not in the pre-built cache image, but on disk, is a true error. + if ( IsX360() && ( g_pFullFileSystem->GetDVDMode() != DVDMODE_STRICT ) && g_pFullFileSystem->FileExists( pszScene, "GAME" ) ) + { + Warning( "PrecacheInstancedScene: Missing scene '%s' from scene image cache.\nRebuild scene image cache!\n", pszScene ); + } + } + else + { + for ( int i = 0; i < sceneData.numSounds; ++i ) + { + short stringId = scenefilecache->GetSceneCachedSound( sceneData.sceneId, i ); + CBaseEntity::PrecacheScriptSound( scenefilecache->GetSceneString( stringId ) ); + } + } + + g_pStringTableClientSideChoreoScenes->AddString( CBaseEntity::IsServer(), pszScene ); +} +#endif + +static void TouchFile( char const *pchFileName ) +{ + IEngineEmulator::Get()->GetFilesystem()->Size( pchFileName ); +} + +void CGameResponseSystem::Precache() +{ + bool bTouchFiles = CommandLine()->FindParm( "-makereslists" ) != 0; + + // enumerate and mark all the scripts so we know they're referenced + for ( int i = 0; i < (int)m_Responses.Count(); i++ ) + { + ResponseGroup &group = m_Responses[i]; + + for ( int j = 0; j < group.group.Count(); j++) + { + ParserResponse &response = group.group[j]; + + switch ( response.type ) + { + default: + break; + case RESPONSE_SCENE: + { + // fixup $gender references + char file[_MAX_PATH]; + Q_strncpy( file, response.value, sizeof(file) ); + char *gender = strstr( file, "$gender" ); + if ( gender ) + { + // replace with male & female + const char *postGender = gender + strlen("$gender"); + *gender = 0; + char genderFile[_MAX_PATH]; + // male + Q_snprintf( genderFile, sizeof(genderFile), "%smale%s", file, postGender); + + PrecacheInstancedScene( genderFile ); + if ( bTouchFiles ) + { + TouchFile( genderFile ); + } + + Q_snprintf( genderFile, sizeof(genderFile), "%sfemale%s", file, postGender); + + PrecacheInstancedScene( genderFile ); + if ( bTouchFiles ) + { + TouchFile( genderFile ); + } + } + else + { + PrecacheInstancedScene( file ); + if ( bTouchFiles ) + { + TouchFile( file ); + } + } + } + break; + case RESPONSE_SPEAK: + { + CBaseEntity::PrecacheScriptSound( response.value ); + } + break; + } + } + } +} + + +//----------------------------------------------------------------------------- +// Purpose: A special purpose response system associated with a custom entity +//----------------------------------------------------------------------------- +class CInstancedResponseSystem : public CGameResponseSystem +{ + typedef CGameResponseSystem BaseClass; + +public: + CInstancedResponseSystem( const char *scriptfile ) : + m_pszScriptFile( 0 ) + { + Assert( scriptfile ); + + int len = Q_strlen( scriptfile ) + 1; + m_pszScriptFile = new char[ len ]; + Assert( m_pszScriptFile ); + Q_strncpy( m_pszScriptFile, scriptfile, len ); + } + + ~CInstancedResponseSystem() + { + delete[] m_pszScriptFile; + } + virtual const char *GetScriptFile( void ) + { + Assert( m_pszScriptFile ); + return m_pszScriptFile; + } + + // CAutoGameSystem + virtual bool Init() + { + const char *basescript = GetScriptFile(); + LoadRuleSet( basescript ); + return true; + } + + virtual void LevelInitPostEntity() + { + ResetResponseGroups(); + } + + virtual void Release() + { + Clear(); + delete this; + } +private: + + char *m_pszScriptFile; +}; + +//----------------------------------------------------------------------------- +// Purpose: The default response system for expressive AIs +//----------------------------------------------------------------------------- +class CDefaultResponseSystem : public CGameResponseSystem, public CAutoGameSystem +{ + typedef CAutoGameSystem BaseClass; + +public: + CDefaultResponseSystem() : CAutoGameSystem( "CDefaultResponseSystem" ) + { + } + + virtual const char *GetScriptFile( void ) + { + return "scripts/talker/response_rules.txt"; + } + + // CAutoServerSystem + virtual bool Init(); + virtual void Shutdown(); + + virtual void LevelInitPostEntity() + { + } + + virtual void Release() + { + Assert( 0 ); + } + + void AddInstancedResponseSystem( const char *scriptfile, CInstancedResponseSystem *sys ) + { + m_InstancedSystems.Insert( scriptfile, sys ); + } + + CInstancedResponseSystem *FindResponseSystem( const char *scriptfile ) + { + int idx = m_InstancedSystems.Find( scriptfile ); + if ( idx == m_InstancedSystems.InvalidIndex() ) + return NULL; + return m_InstancedSystems[ idx ]; + } + + IResponseSystem *PrecacheCustomResponseSystem( const char *scriptfile ) + { + COM_TimestampedLog( "PrecacheCustomResponseSystem %s - Start", scriptfile ); + CInstancedResponseSystem *sys = ( CInstancedResponseSystem * )FindResponseSystem( scriptfile ); + if ( !sys ) + { + sys = new CInstancedResponseSystem( scriptfile ); + if ( !sys ) + { + Error( "Failed to load response system data from %s", scriptfile ); + } + + if ( !sys->Init() ) + { + Error( "CInstancedResponseSystem: Failed to init response system from %s!", scriptfile ); + } + + AddInstancedResponseSystem( scriptfile, sys ); + } + + sys->Precache(); + + COM_TimestampedLog( "PrecacheCustomResponseSystem %s - Finish", scriptfile ); + + return ( IResponseSystem * )sys; + } + + IResponseSystem *BuildCustomResponseSystemGivenCriteria( const char *pszBaseFile, const char *pszCustomName, AI_CriteriaSet &criteriaSet, float flCriteriaScore ); + void DestroyCustomResponseSystems(); + + virtual void LevelInitPreEntity() + { + // This will precache the default system + // All user installed systems are init'd by PrecacheCustomResponseSystem which will call sys->Precache() on the ones being used + + // FIXME: This is SLOW the first time you run the engine (can take 3 - 10 seconds!!!) + if ( ShouldPrecache() ) + { + Precache(); + } + + ResetResponseGroups(); + } + + void ReloadAllResponseSystems() + { + Clear(); + Init(); + + int c = m_InstancedSystems.Count(); + for ( int i = c - 1 ; i >= 0; i-- ) + { + CInstancedResponseSystem *sys = m_InstancedSystems[ i ]; + if ( !IsCustomManagable() ) + { + sys->Clear(); + sys->Init(); + } + else + { + // Custom reponse rules will manage/reload themselves - remove them. + m_InstancedSystems.RemoveAt( i ); + } + } + + // precache sounds in case we added new ones + Precache(); + + } + +private: + + void ClearInstanced() + { + int c = m_InstancedSystems.Count(); + for ( int i = c - 1 ; i >= 0; i-- ) + { + CInstancedResponseSystem *sys = m_InstancedSystems[ i ]; + sys->Release(); + } + m_InstancedSystems.RemoveAll(); + } + + CUtlDict< CInstancedResponseSystem *, int > m_InstancedSystems; + friend void CC_RR_DumpHashInfo( const CCommand &args ); +}; + +IResponseSystem *CDefaultResponseSystem::BuildCustomResponseSystemGivenCriteria( const char *pszBaseFile, const char *pszCustomName, AI_CriteriaSet &criteriaSet, float flCriteriaScore ) +{ + // Create a instanced response system. + CInstancedResponseSystem *pCustomSystem = new CInstancedResponseSystem( pszCustomName ); + if ( !pCustomSystem ) + { + Error( "BuildCustomResponseSystemGivenCriterea: Failed to create custom response system %s!", pszCustomName ); + } + + pCustomSystem->Clear(); + + // Copy the relevant rules and data. + /* + int nRuleCount = m_Rules.Count(); + for ( int iRule = 0; iRule < nRuleCount; ++iRule ) + */ + for ( ResponseRulePartition::tIndex iIdx = m_RulePartitions.First() ; + m_RulePartitions.IsValid(iIdx) ; + iIdx = m_RulePartitions.Next( iIdx ) ) + { + Rule *pRule = &m_RulePartitions[iIdx]; + if ( pRule ) + { + float flScore = 0.0f; + + int nCriteriaCount = pRule->m_Criteria.Count(); + for ( int iCriteria = 0; iCriteria < nCriteriaCount; ++iCriteria ) + { + int iRuleCriteria = pRule->m_Criteria[iCriteria]; + + flScore += LookForCriteria( criteriaSet, iRuleCriteria ); + if ( flScore >= flCriteriaScore ) + { + CopyRuleFrom( pRule, iIdx, pCustomSystem ); + break; + } + } + } + } + + // Set as a custom response system. + m_bCustomManagable = true; + AddInstancedResponseSystem( pszCustomName, pCustomSystem ); + + // pCustomSystem->DumpDictionary( pszCustomName ); + + return pCustomSystem; +} + +void CDefaultResponseSystem::DestroyCustomResponseSystems() +{ + ClearInstanced(); +} + + +static CDefaultResponseSystem defaultresponsesytem; +IResponseSystem *g_pResponseSystem = &defaultresponsesytem; + +CON_COMMAND( rr_reloadresponsesystems, "Reload all response system scripts." ) +{ +#ifdef GAME_DLL + if ( !UTIL_IsCommandIssuedByServerAdmin() ) + return; +#endif + + defaultresponsesytem.ReloadAllResponseSystems(); +} + +#ifdef MAPBASE +// Designed for extern magic, this gives the <, >, etc. of response system criteria to the outside world. +// Mostly just used for Matcher_Match in matchers.h. +bool ResponseSystemCompare( const char *criterion, const char *value ) +{ + Criteria criteria; + criteria.value = criterion; + defaultresponsesytem.ComputeMatcher( &criteria, criteria.matcher ); + return defaultresponsesytem.CompareUsingMatcher( value, criteria.matcher, true ); + + return false; +} + +//----------------------------------------------------------------------------- +// CResponseFilePrecacher +// +// Purpose: Precaches a single talker file. That's it. +// +// It copies from a bunch of the original Response System class and therefore it's really messy. +// Despite the horrors a normal programmer might find in here, I think it performs better than anything else I could've come up with. +//----------------------------------------------------------------------------- +/* +class CResponseFilePrecacher +{ +public: + + // Stuff copied from the Response System. + // Direct copy-pastes are very compact, to say the least. + inline bool ParseToken( void ) + { + if ( m_bUnget ) + { m_bUnget = false; return true; } + if ( m_ScriptStack.Count() <= 0 ) + { return false; } + + m_ScriptStack[ 0 ].currenttoken = engine->ParseFile( m_ScriptStack[ 0 ].currenttoken, token, sizeof( token ) ); + m_ScriptStack[ 0 ].tokencount++; + return m_ScriptStack[ 0 ].currenttoken != NULL ? true : false; + } + + CUtlVector< CResponseSystem::ScriptEntry > m_ScriptStack; + bool m_bUnget; + char token[ 1204 ]; + + + void PrecacheResponse( const char *response, byte type ) + { + switch ( type ) + { + default: + break; + case RESPONSE_SCENE: + { + DevMsg("Precaching scene %s...\n", response); + + // fixup $gender references + char file[_MAX_PATH]; + Q_strncpy( file, response, sizeof(file) ); + char *gender = strstr( file, "$gender" ); + if ( gender ) + { + // replace with male & female + const char *postGender = gender + strlen("$gender"); + *gender = 0; + char genderFile[_MAX_PATH]; + + Q_snprintf( genderFile, sizeof(genderFile), "%smale%s", file, postGender); + PrecacheInstancedScene( genderFile ); + + Q_snprintf( genderFile, sizeof(genderFile), "%sfemale%s", file, postGender); + PrecacheInstancedScene( genderFile ); + } + else + { + PrecacheInstancedScene( file ); + } + } + break; + case RESPONSE_SPEAK: + { + DevMsg("Precaching sound %s...\n", response); + CBaseEntity::PrecacheScriptSound( response ); + } + break; + } + } + + bool IsRootCommand() + { + if (!Q_stricmp( token, "#include" ) || !Q_stricmp( token, "response" ) + || !Q_stricmp( token, "enumeration" ) || !Q_stricmp( token, "criteria" ) + || !Q_stricmp( token, "criterion" ) || !Q_stricmp( token, "rule" )) + return true; + return false; + } + + void ParseResponse( void ) + { + // Must go to response group name + ParseToken(); + + while ( 1 ) + { + ParseToken(); + + if ( !Q_stricmp( token, "{" ) ) + { + while ( 1 ) + { + ParseToken(); + if ( !Q_stricmp( token, "}" ) ) + break; + + byte type = ComputeResponseType( token ); + if (type == RESPONSE_NONE) + continue; + + ParseToken(); + char *value = CopyString( token ); + + PrecacheResponse(value, type); + } + break; + } + + byte type = ComputeResponseType( token ); + if (type == RESPONSE_NONE) + break; + + ParseToken(); + char *value = CopyString( token ); + + PrecacheResponse(value, type); + + break; + } + } + + bool LoadFromBuffer(const char *scriptfile, unsigned char *buffer, CStringPool &includedFiles) + { + includedFiles.Allocate( scriptfile ); + + CResponseSystem::ScriptEntry e; + e.name = filesystem->FindOrAddFileName( scriptfile ); + e.buffer = buffer; + e.currenttoken = (char *)e.buffer; + e.tokencount = 0; + m_ScriptStack.AddToHead( e ); + + while ( 1 ) + { + ParseToken(); + if ( !token[0] ) + { + break; + } + + if ( !Q_stricmp( token, "response" ) ) + { + ParseResponse(); + } + else if ( !Q_stricmp( token, "#include" ) || !Q_stricmp( token, "#base" ) ) + { + // Compacted version of ParseInclude(), including new changes. + // Look at that if you want to read. + char includefile[ 256 ]; + ParseToken(); + if (scriptfile) { size_t len = strlen(scriptfile)-1; + for (size_t i = 0; i < len; i++) + { if (scriptfile[i] == CORRECT_PATH_SEPARATOR || scriptfile[i] == INCORRECT_PATH_SEPARATOR) + { len = i; } + } Q_strncpy(includefile, scriptfile, len+1); + if (len+1 != strlen(scriptfile)) + { Q_snprintf(includefile, sizeof(includefile), "%s/%s", includefile, token); } + else includefile[0] = '\0'; + } if (!includefile[0]) Q_snprintf( includefile, sizeof( includefile ), "scripts/%s", token ); + + if ( includedFiles.Find( includefile ) == NULL ) + { + MEM_ALLOC_CREDIT(); + + // Try and load it + CUtlBuffer buf; + if ( filesystem->ReadFile( includefile, "GAME", buf ) ) + { + LoadFromBuffer( includefile, (unsigned char *)buf.PeekGet(), includedFiles ); + } + } + } + } + + if ( m_ScriptStack.Count() > 0 ) + m_ScriptStack.Remove( 0 ); + + return true; + } +}; +*/ + +// Loads a file directly to the main response system +bool LoadResponseSystemFile(const char *scriptfile) +{ + CUtlBuffer buf; + if ( !filesystem->ReadFile( scriptfile, "GAME", buf ) ) + { + return false; + } + + // This is a really messy and specialized system that precaches the responses and only the responses of a talker file. + /* + CStringPool includedFiles; + CResponseFilePrecacher *rs = new CResponseFilePrecacher(); + if (!rs || !rs->LoadFromBuffer(scriptfile, (unsigned char *)buf.PeekGet(), includedFiles)) + { + Warning( "Failed to load response system data from %s", scriptfile ); + delete rs; + return false; + } + delete rs; + */ + + defaultresponsesytem.LoadFromBuffer(scriptfile, (const char *)buf.PeekGet()); + + return true; +} + +// Called from Mapbase manifests to flush +void ReloadResponseSystem() +{ + defaultresponsesytem.ReloadAllResponseSystems(); +} +#endif + +static short RESPONSESYSTEM_SAVE_RESTORE_VERSION = 1; + +// note: this won't save/restore settings from instanced response systems. Could add that with a CDefSaveRestoreOps implementation if needed +// +class CDefaultResponseSystemSaveRestoreBlockHandler : public CDefSaveRestoreBlockHandler +{ +public: + const char *GetBlockName() + { + return "ResponseSystem"; + } + + void WriteSaveHeaders( ISave *pSave ) + { + pSave->WriteShort( &RESPONSESYSTEM_SAVE_RESTORE_VERSION ); + } + + void ReadRestoreHeaders( IRestore *pRestore ) + { + // No reason why any future version shouldn't try to retain backward compatability. The default here is to not do so. + short version; + pRestore->ReadShort( &version ); + m_fDoLoad = ( version == RESPONSESYSTEM_SAVE_RESTORE_VERSION ); + } + + void Save( ISave *pSave ) + { + CDefaultResponseSystem& rs = defaultresponsesytem; + + int count = rs.m_Responses.Count(); + pSave->WriteInt( &count ); + for ( int i = 0; i < count; ++i ) + { + pSave->StartBlock( "ResponseGroup" ); + + pSave->WriteString( rs.m_Responses.GetElementName( i ) ); + const ResponseGroup *group = &rs.m_Responses[ i ]; + pSave->WriteAll( group ); + + short groupCount = group->group.Count(); + pSave->WriteShort( &groupCount ); + for ( int j = 0; j < groupCount; ++j ) + { + const ParserResponse *response = &group->group[ j ]; + pSave->StartBlock( "Response" ); + pSave->WriteString( response->value ); + pSave->WriteAll( response ); + pSave->EndBlock(); + } + + pSave->EndBlock(); + } + } + + void Restore( IRestore *pRestore, bool createPlayers ) + { + if ( !m_fDoLoad ) + return; + + CDefaultResponseSystem& rs = defaultresponsesytem; + + int count = pRestore->ReadInt(); + for ( int i = 0; i < count; ++i ) + { + char szResponseGroupBlockName[SIZE_BLOCK_NAME_BUF]; + pRestore->StartBlock( szResponseGroupBlockName ); + if ( !Q_stricmp( szResponseGroupBlockName, "ResponseGroup" ) ) + { + + char groupname[ 256 ]; + pRestore->ReadString( groupname, sizeof( groupname ), 0 ); + + // Try and find it + int idx = rs.m_Responses.Find( groupname ); + if ( idx != rs.m_Responses.InvalidIndex() ) + { + ResponseGroup *group = &rs.m_Responses[ idx ]; + pRestore->ReadAll( group ); + + short groupCount = pRestore->ReadShort(); + for ( int j = 0; j < groupCount; ++j ) + { + char szResponseBlockName[SIZE_BLOCK_NAME_BUF]; + + char responsename[ 256 ]; + pRestore->StartBlock( szResponseBlockName ); + if ( !Q_stricmp( szResponseBlockName, "Response" ) ) + { + pRestore->ReadString( responsename, sizeof( responsename ), 0 ); + + // Find it by name + int ri; + for ( ri = 0; ri < group->group.Count(); ++ri ) + { + ParserResponse *response = &group->group[ ri ]; + if ( !Q_stricmp( response->value, responsename ) ) + { + break; + } + } + + if ( ri < group->group.Count() ) + { + ParserResponse *response = &group->group[ ri ]; + pRestore->ReadAll( response ); + } + } + + pRestore->EndBlock(); + } + } + } + + pRestore->EndBlock(); + } + } +private: + + bool m_fDoLoad; + +} g_DefaultResponseSystemSaveRestoreBlockHandler; + +ISaveRestoreBlockHandler *GetDefaultResponseSystemSaveRestoreBlockHandler() +{ + return &g_DefaultResponseSystemSaveRestoreBlockHandler; +} + +//----------------------------------------------------------------------------- +// CResponseSystemSaveRestoreOps +// +// Purpose: Handles save and load for instanced response systems... +// +// BUGBUG: This will save the same response system to file multiple times for "shared" response systems and +// therefore it'll restore the same data onto the same pointer N times on reload (probably benign for now, but we could +// write code to save/restore the instanced ones by filename in the block handler above maybe? +//----------------------------------------------------------------------------- + +class CResponseSystemSaveRestoreOps : public CDefSaveRestoreOps +{ +public: + + virtual void Save( const SaveRestoreFieldInfo_t &fieldInfo, ISave *pSave ) + { + CResponseSystem *pRS = *(CResponseSystem **)fieldInfo.pField; + if ( !pRS || pRS == &defaultresponsesytem ) + return; + + int count = pRS->m_Responses.Count(); + pSave->WriteInt( &count ); + for ( int i = 0; i < count; ++i ) + { + pSave->StartBlock( "ResponseGroup" ); + + pSave->WriteString( pRS->m_Responses.GetElementName( i ) ); + const ResponseGroup *group = &pRS->m_Responses[ i ]; + pSave->WriteAll( group ); + + short groupCount = group->group.Count(); + pSave->WriteShort( &groupCount ); + for ( int j = 0; j < groupCount; ++j ) + { + const ParserResponse *response = &group->group[ j ]; + pSave->StartBlock( "Response" ); + pSave->WriteString( response->value ); + pSave->WriteAll( response ); + pSave->EndBlock(); + } + + pSave->EndBlock(); + } + } + + virtual void Restore( const SaveRestoreFieldInfo_t &fieldInfo, IRestore *pRestore ) + { + CResponseSystem *pRS = *(CResponseSystem **)fieldInfo.pField; + if ( !pRS || pRS == &defaultresponsesytem ) + return; + + int count = pRestore->ReadInt(); + for ( int i = 0; i < count; ++i ) + { + char szResponseGroupBlockName[SIZE_BLOCK_NAME_BUF]; + pRestore->StartBlock( szResponseGroupBlockName ); + if ( !Q_stricmp( szResponseGroupBlockName, "ResponseGroup" ) ) + { + + char groupname[ 256 ]; + pRestore->ReadString( groupname, sizeof( groupname ), 0 ); + + // Try and find it + int idx = pRS->m_Responses.Find( groupname ); + if ( idx != pRS->m_Responses.InvalidIndex() ) + { + ResponseGroup *group = &pRS->m_Responses[ idx ]; + pRestore->ReadAll( group ); + + short groupCount = pRestore->ReadShort(); + for ( int j = 0; j < groupCount; ++j ) + { + char szResponseBlockName[SIZE_BLOCK_NAME_BUF]; + + char responsename[ 256 ]; + pRestore->StartBlock( szResponseBlockName ); + if ( !Q_stricmp( szResponseBlockName, "Response" ) ) + { + pRestore->ReadString( responsename, sizeof( responsename ), 0 ); + + // Find it by name + int ri; + for ( ri = 0; ri < group->group.Count(); ++ri ) + { + ParserResponse *response = &group->group[ ri ]; + if ( !Q_stricmp( response->value, responsename ) ) + { + break; + } + } + + if ( ri < group->group.Count() ) + { + ParserResponse *response = &group->group[ ri ]; + pRestore->ReadAll( response ); + } + } + + pRestore->EndBlock(); + } + } + } + + pRestore->EndBlock(); + } + } + +} g_ResponseSystemSaveRestoreOps; + +ISaveRestoreOps *responseSystemSaveRestoreOps = &g_ResponseSystemSaveRestoreOps; + +//----------------------------------------------------------------------------- +// Purpose: +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CDefaultResponseSystem::Init() +{ + /* + Warning( "sizeof( Response ) == %d\n", sizeof( Response ) ); + Warning( "sizeof( ResponseGroup ) == %d\n", sizeof( ResponseGroup ) ); + Warning( "sizeof( Criteria ) == %d\n", sizeof( Criteria ) ); + Warning( "sizeof( AI_ResponseParams ) == %d\n", sizeof( AI_ResponseParams ) ); + */ + const char *basescript = GetScriptFile(); + + LoadRuleSet( basescript ); + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDefaultResponseSystem::Shutdown() +{ + // Wipe instanced versions + ClearInstanced(); + + // Clear outselves + Clear(); + // IServerSystem chain + BaseClass::Shutdown(); +} + + +//----------------------------------------------------------------------------- +// Purpose: Instance a custom response system +// Input : *scriptfile - +// Output : IResponseSystem +//----------------------------------------------------------------------------- +IResponseSystem *PrecacheCustomResponseSystem( const char *scriptfile ) +{ + return defaultresponsesytem.PrecacheCustomResponseSystem( scriptfile ); +} + +//----------------------------------------------------------------------------- +// Purpose: Instance a custom response system +// Input : *scriptfile - +// set - +// Output : IResponseSystem +//----------------------------------------------------------------------------- +IResponseSystem *BuildCustomResponseSystemGivenCriteria( const char *pszBaseFile, const char *pszCustomName, AI_CriteriaSet &criteriaSet, float flCriteriaScore ) +{ + return defaultresponsesytem.BuildCustomResponseSystemGivenCriteria( pszBaseFile, pszCustomName, criteriaSet, flCriteriaScore ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void DestroyCustomResponseSystems() +{ + defaultresponsesytem.DestroyCustomResponseSystems(); +} diff --git a/sp/src/game/shared/ai_responsesystem_new.h b/sp/src/game/shared/ai_responsesystem_new.h new file mode 100644 index 00000000..a558f79e --- /dev/null +++ b/sp/src/game/shared/ai_responsesystem_new.h @@ -0,0 +1,29 @@ +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#ifndef AI_RESPONSESYSTEM_H +#define AI_RESPONSESYSTEM_H + +#include "utlvector.h" + +#ifdef _WIN32 +#pragma once +#endif + +#include "ai_criteria.h" +#include "../../public/responserules/response_types.h" + +// using ResponseRules::IResponseFilter; +// using ResponseRules::IResponseSystem; + +ResponseRules::IResponseSystem *PrecacheCustomResponseSystem( const char *scriptfile ); +ResponseRules::IResponseSystem *BuildCustomResponseSystemGivenCriteria( const char *pszBaseFile, const char *pszCustomName, AI_CriteriaSet &criteriaSet, float flCriteriaScore ); +void DestroyCustomResponseSystems(); + +class ISaveRestoreBlockHandler *GetDefaultResponseSystemSaveRestoreBlockHandler(); +class ISaveRestoreOps *GetResponseSystemSaveRestoreOps(); + +#endif // AI_RESPONSESYSTEM_H diff --git a/sp/src/game/shared/ai_speechconcept.cpp b/sp/src/game/shared/ai_speechconcept.cpp new file mode 100644 index 00000000..c0ae8e36 --- /dev/null +++ b/sp/src/game/shared/ai_speechconcept.cpp @@ -0,0 +1,28 @@ +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" + +#include "ai_speechconcept.h" + +#ifdef GAME_DLL +#include "game.h" +#include "ai_basenpc.h" +#include "sceneentity.h" +#endif + +#include "engine/ienginesound.h" +#include "keyvalues.h" +#include "ai_criteria.h" +#include "isaverestore.h" + + +// memdbgon must be the last include file in a .cpp file!!! +#include + + +// empty \ No newline at end of file diff --git a/sp/src/game/shared/ai_speechconcept.h b/sp/src/game/shared/ai_speechconcept.h new file mode 100644 index 00000000..41a3cc60 --- /dev/null +++ b/sp/src/game/shared/ai_speechconcept.h @@ -0,0 +1,45 @@ +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: Class data for an AI Concept, an atom of response-driven dialog. +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef AI_SPEECHCONCEPT_H +#define AI_SPEECHCONCEPT_H + +#if defined( _WIN32 ) +#pragma once +#endif + +#include "../../public/responserules/response_types.h" + +class CAI_Concept : public ResponseRules::CRR_Concept +{ +public: + CAI_Concept() {}; + // construct concept from a string. + CAI_Concept(const char *fromString) : CRR_Concept(fromString) {} ; + + // get/set BS + inline EHANDLE GetSpeaker() const { return m_hSpeaker; } + inline void SetSpeaker(EHANDLE val) { m_hSpeaker = val; } + + /* + inline EHANDLE GetTarget() const { return m_hTarget; } + inline void SetTarget(EHANDLE val) { m_hTarget = val; } + inline EHANDLE GetTopic() const { return m_hTopic; } + inline void SetTopic(EHANDLE val) { m_hTopic = val; } + */ + +protected: + EHANDLE m_hSpeaker; + + /* + EHANDLE m_hTarget; + EHANDLE m_hTopic; + */ +}; + + +#endif diff --git a/sp/src/public/datamap.h b/sp/src/public/datamap.h index 34a1caf8..b25bb172 100644 --- a/sp/src/public/datamap.h +++ b/sp/src/public/datamap.h @@ -313,6 +313,12 @@ struct datamap_t static datamap_t *GetBaseMap(); \ template friend void DataMapAccess(T *, datamap_t **p); \ template friend datamap_t *DataMapInit(T *); + +#define DECLARE_SIMPLE_DATADESC_INSIDE_NAMESPACE() \ + static datamap_t m_DataMap; \ + static datamap_t *GetBaseMap(); \ + template friend void ::DataMapAccess(T *, datamap_t **p); \ + template friend datamap_t *::DataMapInit(T *); #define DECLARE_DATADESC() \ DECLARE_SIMPLE_DATADESC() \ @@ -414,6 +420,8 @@ inline void DataMapAccess(T *ignored, datamap_t **p) *p = &T::m_DataMap; } +template datamap_t* DataMapInit(T*); + //----------------------------------------------------------------------------- class CDatadescGeneratedNameHolder diff --git a/sp/src/public/responserules/response_host_interface.h b/sp/src/public/responserules/response_host_interface.h new file mode 100644 index 00000000..fa39bd88 --- /dev/null +++ b/sp/src/public/responserules/response_host_interface.h @@ -0,0 +1,66 @@ +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: Core types for the response rules -- criteria, responses, rules, and matchers. +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef RESPONSE_HOST_INTERFACE_H +#define RESPONSE_HOST_INTERFACE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "filesystem.h" +class IUniformRandomStream; +class ICommandLine; + +namespace ResponseRules +{ + // FUNCTIONS YOU MUST IMPLEMENT IN THE HOST EXECUTABLE: + // These are functions that are mentioned in the header, but need their bodies implemented + // in the .dll that links against this lib. + // This is to wrap functions that previously came from the engine interface + // back when the response rules were inside the server.dll . Now that the rules + // are included into a standalone editor, we don't necessarily have an engine around, + // so there needs to be some other implementation. + abstract_class IEngineEmulator + { + public: + /// Given an input text buffer data pointer, parses a single token into the variable token and returns the new + /// reading position + virtual const char *ParseFile( const char *data, char *token, int maxlen ) = 0; + +#ifdef MAPBASE + /// (Optional) Same as ParseFile, but with casing preserved and escaped quotes supported + virtual const char *ParseFilePreserve( const char *data, char *token, int maxlen ) { return ParseFile( data, token, maxlen ); } +#endif + + /// Return a pointer to an IFileSystem we can use to read and process scripts. + virtual IFileSystem *GetFilesystem() = 0; + + /// Return a pointer to an instance of an IUniformRandomStream + virtual IUniformRandomStream *GetRandomStream() = 0 ; + + /// Return a pointer to a tier0 ICommandLine + virtual ICommandLine *GetCommandLine() = 0; + + /// Emulates the server's UTIL_LoadFileForMe + virtual byte *LoadFileForMe( const char *filename, int *pLength ) = 0; + + /// Emulates the server's UTIL_FreeFile + virtual void FreeFile( byte *buffer ) = 0; + + + /// Somewhere in the host executable you should define this symbol and + /// point it at a singleton instance. + static IEngineEmulator *s_pSingleton; + + // this is just a function that returns the pointer above -- just in + // case we need to define it differently. And I get asserts this way. + static IEngineEmulator *Get(); + }; +}; + + +#endif \ No newline at end of file diff --git a/sp/src/public/responserules/response_types.h b/sp/src/public/responserules/response_types.h new file mode 100644 index 00000000..2e7472c2 --- /dev/null +++ b/sp/src/public/responserules/response_types.h @@ -0,0 +1,458 @@ +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: Core types for the response rules -- criteria, responses, rules, and matchers. +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef RESPONSE_TYPES_H +#define RESPONSE_TYPES_H +#ifdef _WIN32 +#pragma once +#endif + +#include "tier1/utlrbtree.h" +#include "tier1/utlsymbol.h" +#include "tier1/interval.h" +#include "mathlib/compressed_vector.h" +#include "datamap.h" +#include "soundflags.h" +#include "tier1/utlsymbol.h" + +namespace ResponseRules +{ + /// Custom symbol table for the response rules. + extern CUtlSymbolTable g_RS; +}; + +#ifdef _MANAGED +// forward declare some editor types just so we can friend them. +namespace ResponseRulesCLI +{ + ref class ResponseQueryResult; +} +#endif + +namespace ResponseRules +{ + using ::DataMapAccess; + // using ::DataMapInit; + class CResponseSystem; + +#pragma pack(push,1) + template + struct response_interval_t + { + T start; + T range; + + interval_t &ToInterval( interval_t &dest ) const { dest.start = start; dest.range = range; return dest; } + void FromInterval( const interval_t &from ) { start = from.start; range = from.range; } + float Random() const { interval_t temp = { start, range }; return RandomInterval( temp ); } + }; + + typedef response_interval_t responseparams_interval_t; +#pragma pack(pop) + +#pragma pack(push,1) + struct AI_ResponseFollowup + { + + + // TODO: make less wasteful of memory, by using a symbol table. + const char *followup_concept; // 12 -- next response + const char *followup_contexts; // 16 + float followup_delay; // 20 + const char *followup_target; // 24 -- to whom is this despatched? + // AIConceptHandle_t hConcept; + const char *followup_entityiotarget; //< if this rule involves firing entity io + const char *followup_entityioinput; //< if this rule involves firing entity io + float followup_entityiodelay; + bool bFired; + + inline bool IsValid( void ) const { return (followup_concept && followup_contexts); } + inline void Invalidate() { followup_concept = NULL; followup_contexts = NULL; } + inline void SetFired( bool fired ) { bFired = fired; } + inline bool HasBeenFired() { return bFired; } + + AI_ResponseFollowup( void ) : followup_concept(NULL), followup_contexts(NULL), followup_delay(0), followup_target(NULL), followup_entityiotarget(NULL), followup_entityioinput(NULL), followup_entityiodelay(0), bFired(false) + {}; + AI_ResponseFollowup( char *_followup_concept, char *_followup_contexts, float _followup_delay, char *_followup_target, + char *_followup_entityiotarget, char *_followup_entityioinput, float _followup_entityiodelay ) : + followup_concept(_followup_concept), followup_contexts(_followup_contexts), followup_delay(_followup_delay), followup_target(_followup_target), + followup_entityiotarget(_followup_entityiotarget), followup_entityioinput(_followup_entityioinput), followup_entityiodelay(_followup_entityiodelay), + bFired(false) + {}; + }; +#pragma pack(pop) + + + enum ResponseType_t + { + RESPONSE_NONE = 0, + RESPONSE_SPEAK, + RESPONSE_SENTENCE, + RESPONSE_SCENE, + RESPONSE_RESPONSE, // A reference to another response by name + RESPONSE_PRINT, + RESPONSE_ENTITYIO, // poke an input on an entity +#ifdef MAPBASE + RESPONSE_VSCRIPT, // Run VScript code +#endif + + NUM_RESPONSES, + }; + +#ifdef MAPBASE + // The "apply to world" context option has been replaced with a flag-based integer which can apply contexts to more things. + // + // New ones should be implemented in: + // CResponseSystem::BuildDispatchTables() - AI_ResponseSystem.cpp (with their own funcs for m_RuleDispatch) + // CRR_Response::Describe() - rr_response.cpp + // CAI_Expresser::SpeakDispatchResponse() - ai_speech.cpp + enum + { + APPLYCONTEXT_SELF = (1 << 0), // Included for contexts that apply to both self and something else + APPLYCONTEXT_WORLD = (1 << 1), // Apply to world + + APPLYCONTEXT_SQUAD = (1 << 2), // Apply to squad + APPLYCONTEXT_ENEMY = (1 << 3), // Apply to enemy + }; +#endif + + +#pragma pack(push,1) + struct ResponseParams + { + DECLARE_SIMPLE_DATADESC_INSIDE_NAMESPACE(); + + enum + { + RG_DELAYAFTERSPEAK = (1<<0), + RG_SPEAKONCE = (1<<1), + RG_ODDS = (1<<2), + RG_RESPEAKDELAY = (1<<3), + RG_SOUNDLEVEL = (1<<4), + RG_DONT_USE_SCENE = (1<<5), + RG_STOP_ON_NONIDLE = (1<<6), + RG_WEAPONDELAY = (1<<7), + RG_DELAYBEFORESPEAK = (1<<8), + }; + + ResponseParams() + { + flags = 0; + odds = 100; + delay.start = 0; + delay.range = 0; + respeakdelay.start = 0; + respeakdelay.range = 0; + weapondelay.start = 0; + weapondelay.range = 0; + soundlevel = 0; + predelay.start = 0; + predelay.range = 0; + } + responseparams_interval_t delay; //4 + responseparams_interval_t respeakdelay; //8 + responseparams_interval_t weapondelay; //12 + + short odds; //14 + + short flags; //16 + byte soundlevel; //17 + + responseparams_interval_t predelay; //21 + + ALIGN32 AI_ResponseFollowup *m_pFollowup; + + }; +#pragma pack(pop) + + class CriteriaSet + { + public: + typedef CUtlSymbol CritSymbol_t; ///< just to make it clear that some symbols come out of our special static table + public: + CriteriaSet(); + CriteriaSet( const CriteriaSet& src ); + CriteriaSet( const char *criteria, const char *value ) ; // construct initialized with a key/value pair (convenience) + ~CriteriaSet(); + + static CritSymbol_t ComputeCriteriaSymbol( const char *criteria ); + void AppendCriteria( CritSymbol_t criteria, const char *value = "", float weight = 1.0f ); + void AppendCriteria( const char *criteria, const char *value = "", float weight = 1.0f ); + void AppendCriteria( const char *criteria, float value, float weight = 1.0f ); + void RemoveCriteria( const char *criteria ); + + void Describe() const; + + int GetCount() const; + int FindCriterionIndex( CritSymbol_t criteria ) const; + int FindCriterionIndex( const char *name ) const; + inline bool IsValidIndex( int index ) const; + + CritSymbol_t GetNameSymbol( int nIndex ) const; + inline static const char *SymbolToStr( const CritSymbol_t &symbol ); + const char *GetName( int index ) const; + const char *GetValue( int index ) const; + float GetWeight( int index ) const; + + /// Merge another CriteriaSet into this one. + void Merge( const CriteriaSet *otherCriteria ); + void Merge( const char *modifiers ); // add criteria parsed from a text string + + /// add all of the contexts herein onto an entity. all durations are infinite. + void WriteToEntity( CBaseEntity *pEntity ); + + // Accessors to things that need only be done under unusual circumstances. + inline void EnsureCapacity( int num ); + void Reset(); // clear out this criteria (should not be necessary) + + /// When this is true, calls to AppendCriteria on a criteria that already exists + /// will override the existing value. (This is the default behavior). Can be temporarily + /// set false to prevent such overrides. + inline void OverrideOnAppend( bool bOverride ) { m_bOverrideOnAppend = bOverride; } + + // For iteration from beginning to end (also should not be necessary except in + // save/load) + inline int Head() const; + inline int Next( int i ) const; // use with IsValidIndex above + + const static char kAPPLYTOWORLDPREFIX = '$'; + + /// A last minute l4d2 change: deferred contexts prefixed with a '$' + /// character are actually applied to the world. This matches the + /// related hack in CBaseEntity::AppplyContext. + /// This function works IN-PLACE on the "from" parameter. + /// any $-prefixed criteria in pFrom become prefixed by "world", + /// and are also written into pSetOnWorld. + /// *IF* a response matches using the modified criteria, then and only + /// then should you write back the criteria in pSetOnWorld to the world + /// entity, subsequent to the match but BEFORE the dispatch. + /// Returns the number of contexts modified. If it returns 0, then + /// pSetOnWorld is empty. + static int InterceptWorldSetContexts( CriteriaSet * RESTRICT pFrom, + CriteriaSet * RESTRICT pSetOnWorld ); + + private: + void RemoveCriteria( int idx, bool bTestForPrefix ); + + struct CritEntry_t + { + CritEntry_t() : + criterianame( UTL_INVAL_SYMBOL ), + weight( 0.0f ) + { + value[ 0 ] = 0; + } + + CritEntry_t( const CritEntry_t& src ) + { + criterianame = src.criterianame; + value[ 0 ] = 0; + weight = src.weight; + SetValue( src.value ); + } + + CritEntry_t& operator=( const CritEntry_t& src ) + { + if ( this == &src ) + return *this; + + criterianame = src.criterianame; + weight = src.weight; + SetValue( src.value ); + + return *this; + } + + static bool LessFunc( const CritEntry_t& lhs, const CritEntry_t& rhs ) + { + return lhs.criterianame < rhs.criterianame; + } + + void SetValue( char const *str ) + { + if ( !str ) + { + value[ 0 ] = 0; + } + else + { + Q_strncpy( value, str, sizeof( value ) ); + } + } + + CritSymbol_t criterianame; + char value[ 64 ]; + float weight; + }; + + static CUtlSymbolTable sm_CriteriaSymbols; + typedef CUtlRBTree< CritEntry_t, short > Dict_t; + Dict_t m_Lookup; + int m_nNumPrefixedContexts; // number of contexts prefixed with kAPPLYTOWORLDPREFIX + bool m_bOverrideOnAppend; + }; + + inline void CriteriaSet::EnsureCapacity( int num ) + { + m_Lookup.EnsureCapacity(num); + } + + //----------------------------------------------------------------------------- + // Purpose: Generic container for a response to a match to a criteria set + // This is what searching for a response returns + //----------------------------------------------------------------------------- + + class CRR_Response + { + public: + DECLARE_SIMPLE_DATADESC_INSIDE_NAMESPACE(); + + CRR_Response(); + CRR_Response( const CRR_Response &from ); + CRR_Response &operator=( const CRR_Response &from ); + ~CRR_Response(); + private: + void operator delete(void* p); // please do not new or delete CRR_Responses. + public: + + // void Release(); // we no longer encourage new and delete on these things + + void GetName( char *buf, size_t buflen ) const; + void GetResponse( char *buf, size_t buflen ) const; + const char* GetNamePtr() const; + const char* GetResponsePtr() const; + const ResponseParams *GetParams() const { return &m_Params; } + ResponseType_t GetType() const { return (ResponseType_t)m_Type; } + soundlevel_t GetSoundLevel() const; + float GetRespeakDelay() const; + float GetWeaponDelay() const; + bool GetSpeakOnce() const; + bool ShouldntUseScene( ) const; + bool ShouldBreakOnNonIdle( void ) const; + int GetOdds() const; + float GetDelay() const; + float GetPreDelay() const; + + inline bool IsEmpty() const; // true iff my response name is empty + void Invalidate() ; // wipe out my contents, mark me invalid + + // Get/set the contexts we apply to character and world after execution + void SetContext( const char *context ); + const char * GetContext( void ) const { return m_szContext; } + + // Get/set the score I matched with (under certain circumstances) + inline float GetMatchScore( void ) { return m_fMatchScore; } + inline void SetMatchScore( float f ) { m_fMatchScore = f; } + +#ifdef MAPBASE + int GetContextFlags() { return m_iContextFlags; } + bool IsApplyContextToWorld( void ) { return (m_iContextFlags & APPLYCONTEXT_WORLD) != 0; } +#else + bool IsApplyContextToWorld( void ) { return m_bApplyContextToWorld; } +#endif + + void Describe( const CriteriaSet *pDebugCriteria = NULL ); + + void Init( ResponseType_t type, + const char *responseName, + const ResponseParams& responseparams, + const char *matchingRule, + const char *applyContext, + bool bApplyContextToWorld ); + +#ifdef MAPBASE + void Init( ResponseType_t type, + const char *responseName, + const ResponseParams& responseparams, + const char *matchingRule, + const char *applyContext, + int iContextFlags ); +#endif + + static const char *DescribeResponse( ResponseType_t type ); + + enum + { + MAX_RESPONSE_NAME = 64, + MAX_RULE_NAME = 64 + }; + + + private: + byte m_Type; + char m_szResponseName[ MAX_RESPONSE_NAME ]; + char m_szMatchingRule[ MAX_RULE_NAME ]; + + ResponseParams m_Params; + float m_fMatchScore; // when instantiated dynamically in SpeakFindResponse, the score of the rule that matched it. + + char * m_szContext; // context data we apply to character after running +#ifdef MAPBASE + int m_iContextFlags; +#else + bool m_bApplyContextToWorld; +#endif + +#ifdef _MANAGED + friend ref class ResponseRulesCLI::ResponseQueryResult; +#endif + }; + + + + abstract_class IResponseFilter + { + public: + virtual bool IsValidResponse( ResponseType_t type, const char *pszValue ) = 0; + }; + + abstract_class IResponseSystem + { + public: + virtual ~IResponseSystem() {} + + virtual bool FindBestResponse( const CriteriaSet& set, CRR_Response& response, IResponseFilter *pFilter = NULL ) = 0; + virtual void GetAllResponses( CUtlVector *pResponses ) = 0; + virtual void PrecacheResponses( bool bEnable ) = 0; + }; + + + + // INLINE FUNCTIONS + + // Used as a failsafe in finding responses. + bool CRR_Response::IsEmpty() const + { + return m_szResponseName[0] == 0; + } + + inline bool CriteriaSet::IsValidIndex( int index ) const + { + return ( index >= 0 && index < ((int)(m_Lookup.Count())) ); + } + + inline int CriteriaSet::Head() const + { + return m_Lookup.FirstInorder(); + } + + inline int CriteriaSet::Next( int i ) const + { + return m_Lookup.NextInorder(i); + } + + inline const char *CriteriaSet::SymbolToStr( const CritSymbol_t &symbol ) + { + return sm_CriteriaSymbols.String(symbol); + } + +} + +#include "rr_speechconcept.h" +#include "response_host_interface.h" + +#endif diff --git a/sp/src/public/responserules/rr_speechconcept.h b/sp/src/public/responserules/rr_speechconcept.h new file mode 100644 index 00000000..65b1bb6e --- /dev/null +++ b/sp/src/public/responserules/rr_speechconcept.h @@ -0,0 +1,57 @@ +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: Class data for an AI Concept, an atom of response-driven dialog. +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef RR_SPEECHCONCEPT_H +#define RR_SPEECHCONCEPT_H + +#if defined( _WIN32 ) +#pragma once +#endif + +#include "utlsymbol.h" + +#define RR_CONCEPTS_ARE_STRINGS 0 + + +typedef CUtlSymbolTable CRR_ConceptSymbolTable; + +namespace ResponseRules +{ +class CRR_Concept +{ +public: // local typedefs + typedef CUtlSymbol tGenericId; // an int-like type that can be used to refer to all concepts of this type + tGenericId m_iConcept; + +public: + CRR_Concept() {}; + // construct concept from a string. + CRR_Concept(const char *fromString); + + // Return as a string + const char *GetStringConcept() const; + static const char *GetStringForGenericId(tGenericId genericId); + + operator tGenericId() const { return m_iConcept; } + operator const char *() const { return GetStringConcept(); } + inline bool operator==(const CRR_Concept &other) // default is compare by concept ids + { + return m_iConcept == other.m_iConcept; + } + bool operator==(const char *pszConcept); + +protected: + +private: + // dupe a concept + // CRR_Concept& operator=(CRR_Concept &other); + CRR_Concept& operator=(const char *fromString); +}; +}; + + +#endif diff --git a/sp/src/public/tier0/basetypes.h b/sp/src/public/tier0/basetypes.h index e8387b56..a6d1a1a6 100644 --- a/sp/src/public/tier0/basetypes.h +++ b/sp/src/public/tier0/basetypes.h @@ -131,6 +131,70 @@ T Max( T const &val1, T const &val2 ) #define TRUE (!FALSE) #endif +//----------------------------------------------------------------------------- +// fsel +//----------------------------------------------------------------------------- +#ifndef _X360 + +#define fsel(c,x,y) ( (c) >= 0 ? (x) : (y) ) + +// integer conditional move +// if a >= 0, return x, else y +#define isel(a,x,y) ( ((a) >= 0) ? (x) : (y) ) + +// if x = y, return a, else b +#define ieqsel(x,y,a,b) (( (x) == (y) ) ? (a) : (b)) + +// if the nth bit of a is set (counting with 0 = LSB), +// return x, else y +// this is fast if nbit is a compile-time immediate +#define ibitsel(a, nbit, x, y) ( ( ((a) & (1 << (nbit))) != 0 ) ? (x) : (y) ) + +#else + +// __fsel(double fComparand, double fValGE, double fLT) == fComparand >= 0 ? fValGE : fLT +// this is much faster than if ( aFloat > 0 ) { x = .. } +// the XDK defines two intrinsics, one for floats and one for doubles -- it's the same +// opcode, but the __fself version tells the compiler not to do a wasteful unnecessary +// rounding op after each sel. +// #define fsel __fsel +FORCEINLINE double fsel(double fComparand, double fValGE, double fLT) { return __fsel( fComparand, fValGE, fLT ); } +FORCEINLINE float fsel(float fComparand, float fValGE, float fLT) { return __fself( fComparand, fValGE, fLT ); } + +// if a >= 0, return x, else y +FORCEINLINE int isel( int a, int x, int y ) +{ + int mask = a >> 31; // arithmetic shift right, splat out the sign bit + return x + ((y - x) & mask); +}; + +// if a >= 0, return x, else y +FORCEINLINE unsigned isel( int a, unsigned x, unsigned y ) +{ + int mask = a >> 31; // arithmetic shift right, splat out the sign bit + return x + ((y - x) & mask); +}; + +// ( x == y ) ? a : b +FORCEINLINE unsigned ieqsel( unsigned x, unsigned y, unsigned a, unsigned b ) +{ + unsigned mask = (x == y) ? 0 : -1; + return a + ((b - a) & mask); +}; + +// ( x == y ) ? a : b +FORCEINLINE int ieqsel( int x, int y, int a, int b ) +{ + int mask = (x == y) ? 0 : -1; + return a + ((b - a) & mask); +}; + +// if the nth bit of a is set (counting with 0 = LSB), +// return x, else y +// this is fast if nbit is a compile-time immediate +#define ibitsel(a, nbit, x, y) ( (x) + (((y) - (x)) & (((a) & (1 << (nbit))) ? 0 : -1)) ) + +#endif #ifndef DONT_DEFINE_BOOL // Needed for Cocoa stuff to compile. typedef int BOOL; diff --git a/sp/src/public/tier0/platform.h b/sp/src/public/tier0/platform.h index 0e5a3428..422a006f 100644 --- a/sp/src/public/tier0/platform.h +++ b/sp/src/public/tier0/platform.h @@ -704,29 +704,6 @@ typedef uint32 HMODULE; typedef void *HANDLE; #endif -//----------------------------------------------------------------------------- -// fsel -//----------------------------------------------------------------------------- -#ifndef _X360 - -static FORCEINLINE float fsel(float fComparand, float fValGE, float fLT) -{ - return fComparand >= 0 ? fValGE : fLT; -} -static FORCEINLINE double fsel(double fComparand, double fValGE, double fLT) -{ - return fComparand >= 0 ? fValGE : fLT; -} - -#else - -// __fsel(double fComparand, double fValGE, double fLT) == fComparand >= 0 ? fValGE : fLT -// this is much faster than if ( aFloat > 0 ) { x = .. } -#define fsel __fsel - -#endif - - //----------------------------------------------------------------------------- // FP exception handling //----------------------------------------------------------------------------- diff --git a/sp/src/game/shared/interval.h b/sp/src/public/tier1/interval.h similarity index 100% rename from sp/src/game/shared/interval.h rename to sp/src/public/tier1/interval.h diff --git a/sp/src/responserules/runtime/criteriaset.cpp b/sp/src/responserules/runtime/criteriaset.cpp new file mode 100644 index 00000000..3dc5cb20 --- /dev/null +++ b/sp/src/responserules/runtime/criteriaset.cpp @@ -0,0 +1,477 @@ +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// +// +// Purpose: +// +// $NoKeywords: $ +// +//===========================================================================// +#include "rrbase.h" + +#include "utlmap.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include + +using namespace ResponseRules; + +//----------------------------------------------------------------------------- +// Case-insensitive criteria symbol table +//----------------------------------------------------------------------------- +CUtlSymbolTable CriteriaSet::sm_CriteriaSymbols( 1024, 1024, true ); + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *raw - +// *key - +// keylen - +// *value - +// valuelen - +// *duration - +// Output : static bool +//----------------------------------------------------------------------------- +const char *SplitContext( const char *raw, char *key, int keylen, char *value, int valuelen, float *duration, const char *entireContext ) +{ + char *colon1 = Q_strstr( raw, ":" ); + if ( !colon1 ) + { + DevMsg( "SplitContext: warning, ignoring context '%s', missing colon separator!\n", raw ); + *key = *value = 0; + return NULL; + } + + int len = colon1 - raw; + Q_strncpy( key, raw, MIN( len + 1, keylen ) ); + key[ MIN( len, keylen - 1 ) ] = 0; + + bool last = false; + char *end = Q_strstr( colon1 + 1, "," ); + if ( !end ) + { + int remaining = Q_strlen( colon1 + 1 ); + end = colon1 + 1 + remaining; + last = true; + } + + char *colon2 = Q_strstr( colon1 + 1, ":" ); + if ( colon2 && ( colon2 < end ) ) + { + if ( duration ) + *duration = atof( colon2 + 1 ); + + char durationStartChar = *(colon2 + 1); + if ( durationStartChar < '0' || durationStartChar > '9' ) + { + DevMsg( "SplitContext: warning, ignoring context '%s', missing comma separator! Entire context was '%s'.\n", raw, entireContext ); + *key = *value = 0; + return NULL; + } + + len = MIN( colon2 - ( colon1 + 1 ), valuelen - 1 ); + Q_strncpy( value, colon1 + 1, len + 1 ); + value[ len ] = 0; + } + else + { + if ( duration ) + *duration = 0.0; + + len = MIN( end - ( colon1 + 1 ), valuelen - 1 ); + Q_strncpy( value, colon1 + 1, len + 1 ); + value[ len ] = 0; + } + + return last ? NULL : end + 1; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CriteriaSet::CriteriaSet() : m_Lookup( 0, 0, CritEntry_t::LessFunc ), m_bOverrideOnAppend(true), + m_nNumPrefixedContexts(0) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CriteriaSet::CriteriaSet( const CriteriaSet& src ) : m_Lookup( 0, 0, CritEntry_t::LessFunc ), m_nNumPrefixedContexts(src.m_nNumPrefixedContexts) +{ + m_Lookup.EnsureCapacity( src.m_Lookup.Count() ); + for ( short i = src.m_Lookup.FirstInorder(); + i != src.m_Lookup.InvalidIndex(); + i = src.m_Lookup.NextInorder( i ) ) + { + m_Lookup.Insert( src.m_Lookup[ i ] ); + } +} + +CriteriaSet::CriteriaSet( const char *criteria, const char *value ) : m_Lookup( 0, 0, CritEntry_t::LessFunc ), m_bOverrideOnAppend(true) +{ + AppendCriteria(criteria,value); +} + + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CriteriaSet::~CriteriaSet() +{ +} + +//----------------------------------------------------------------------------- +// Computes a symbol for the criteria +//----------------------------------------------------------------------------- +CriteriaSet::CritSymbol_t CriteriaSet::ComputeCriteriaSymbol( const char *criteria ) +{ + return sm_CriteriaSymbols.AddString( criteria ); +} + + +//----------------------------------------------------------------------------- +// Computes a symbol for the criteria +//----------------------------------------------------------------------------- +void CriteriaSet::AppendCriteria( CriteriaSet::CritSymbol_t criteria, const char *value, float weight ) +{ + int idx = FindCriterionIndex( criteria ); + if ( idx == -1 ) + { + CritEntry_t entry; + entry.criterianame = criteria; + MEM_ALLOC_CREDIT(); + idx = m_Lookup.Insert( entry ); + if ( sm_CriteriaSymbols.String(criteria)[0] == kAPPLYTOWORLDPREFIX ) + { + m_nNumPrefixedContexts += 1; + } + } + else // criteria already existed + { + // bail out if override existing criteria is not allowed + if ( !m_bOverrideOnAppend ) + return; + } + + CritEntry_t *entry = &m_Lookup[ idx ]; + entry->SetValue( value ); + entry->weight = weight; +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *criteria - +// "" - +// 1.0f - +//----------------------------------------------------------------------------- +void CriteriaSet::AppendCriteria( const char *pCriteriaName, const char *value /*= ""*/, float weight /*= 1.0f*/ ) +{ + CUtlSymbol criteria = ComputeCriteriaSymbol( pCriteriaName ); + AppendCriteria( criteria, value, weight ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *criteria - +// "" - +// 1.0f - +//----------------------------------------------------------------------------- +void CriteriaSet::AppendCriteria( const char *criteria, float value, float weight /*= 1.0f*/ ) +{ + char buf[32]; + V_snprintf( buf, 32, "%f", value ); + AppendCriteria( criteria, buf, weight ); +} + + +//----------------------------------------------------------------------------- +// Removes criteria in a set +//----------------------------------------------------------------------------- +void CriteriaSet::RemoveCriteria( const char *criteria ) +{ + const int idx = FindCriterionIndex( criteria ); + if ( idx == -1 ) + return; + + if ( criteria[0] == kAPPLYTOWORLDPREFIX ) + { + Assert( m_nNumPrefixedContexts > 0 ); + m_nNumPrefixedContexts = isel( m_nNumPrefixedContexts - 1, m_nNumPrefixedContexts - 1, 0 ); + } + RemoveCriteria( idx, false ); +} + +// bTestForIndex tells us whether the calling function has already checked for a +// $ prefix and decremented m_nNumPrefixedContexts appropriately (false), +// or if this function should do that (true). +void CriteriaSet::RemoveCriteria( int idx, bool bTestForPrefix ) +{ + Assert( m_Lookup.IsValidIndex(idx) ); + if ( bTestForPrefix ) + { + if ( sm_CriteriaSymbols.String( m_Lookup[idx].criterianame )[0] == kAPPLYTOWORLDPREFIX ) + { + Assert( m_nNumPrefixedContexts > 0 ); + m_nNumPrefixedContexts = isel( m_nNumPrefixedContexts - 1, m_nNumPrefixedContexts - 1, 0 ); + } + } + m_Lookup.RemoveAt( idx ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : int +//----------------------------------------------------------------------------- +int CriteriaSet::GetCount() const +{ + return m_Lookup.Count(); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *name - +// Output : int +//----------------------------------------------------------------------------- +int CriteriaSet::FindCriterionIndex( CritSymbol_t criteria ) const +{ + CritEntry_t search; + search.criterianame = criteria; + int idx = m_Lookup.Find( search ); + return ( idx == m_Lookup.InvalidIndex() ) ? -1 : idx; +} + +int CriteriaSet::FindCriterionIndex( const char *name ) const +{ + CUtlSymbol criteria = ComputeCriteriaSymbol( name ); + return FindCriterionIndex( criteria ); +} + + +//----------------------------------------------------------------------------- +// Returns the name symbol +//----------------------------------------------------------------------------- +CriteriaSet::CritSymbol_t CriteriaSet::GetNameSymbol( int nIndex ) const +{ + if ( nIndex < 0 || nIndex >= (int)m_Lookup.Count() ) + return UTL_INVAL_SYMBOL; + + const CritEntry_t *entry = &m_Lookup[ nIndex ]; + return entry->criterianame; +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : index - +// Output : char const +//----------------------------------------------------------------------------- +const char *CriteriaSet::GetName( int index ) const +{ + if ( index < 0 || index >= (int)m_Lookup.Count() ) + return ""; + else + { + const char *pCriteriaName = sm_CriteriaSymbols.String( m_Lookup[ index ].criterianame ); + return pCriteriaName ? pCriteriaName : ""; + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : index - +// Output : char const +//----------------------------------------------------------------------------- +const char *CriteriaSet::GetValue( int index ) const +{ + if ( index < 0 || index >= (int)m_Lookup.Count() ) + return ""; + + const CritEntry_t *entry = &m_Lookup[ index ]; + return entry->value ? entry->value : ""; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : index - +// Output : float +//----------------------------------------------------------------------------- +float CriteriaSet::GetWeight( int index ) const +{ + if ( index < 0 || index >= (int)m_Lookup.Count() ) + return 1.0f; + + const CritEntry_t *entry = &m_Lookup[ index ]; + return entry->weight; +} + + +//----------------------------------------------------------------------------- +// Purpose: Merge another criteria set into this one. +//----------------------------------------------------------------------------- +void CriteriaSet::Merge( const CriteriaSet * RESTRICT otherCriteria ) +{ + Assert(otherCriteria); + if (!otherCriteria) + return; + + // for now, just duplicate everything. + int count = otherCriteria->GetCount(); + EnsureCapacity( count + GetCount() ); + for ( int i = 0 ; i < count ; ++i ) + { + AppendCriteria( otherCriteria->GetNameSymbol(i), otherCriteria->GetValue(i), otherCriteria->GetWeight(i) ); + } +} + +void CriteriaSet::Merge( const char *modifiers ) // add criteria parsed from a text string +{ + // Always include any optional modifiers + if ( modifiers == NULL ) + return; + + char copy_modifiers[ 255 ]; + const char *pCopy; + char key[ 128 ] = { 0 }; + char value[ 128 ] = { 0 }; + + Q_strncpy( copy_modifiers, modifiers, sizeof( copy_modifiers ) ); + pCopy = copy_modifiers; + + while( pCopy ) + { + pCopy = SplitContext( pCopy, key, sizeof( key ), value, sizeof( value ), NULL, modifiers ); + + if( *key && *value ) + { + AppendCriteria( key, value, 1 ); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CriteriaSet::Describe() const +{ + // build an alphabetized representation of the set for printing + typedef CUtlMap tMap; + tMap m_TempMap( 0, m_Lookup.Count(), CaselessStringLessThan ); + + for ( short i = m_Lookup.FirstInorder(); i != m_Lookup.InvalidIndex(); i = m_Lookup.NextInorder( i ) ) + { + const CritEntry_t *entry = &m_Lookup[ i ]; + + m_TempMap.Insert( sm_CriteriaSymbols.String( entry->criterianame ), entry ); + } + + for ( tMap::IndexType_t i = m_TempMap.FirstInorder(); i != m_TempMap.InvalidIndex(); i = m_TempMap.NextInorder( i ) ) + { + // const CritEntry_t *entry = &m_TempMap[ i ]; + // const char *pCriteriaName = sm_CriteriaSymbols.String( entry->criterianame ); + + const char *name = m_TempMap.Key( i ); + const CritEntry_t *entry = m_TempMap.Element( i ); + if ( entry->weight != 1.0f ) + { + DevMsg( " %20s = '%s' (weight %f)\n", name, entry->value ? entry->value : "", entry->weight ); + } + else + { + DevMsg( " %20s = '%s'\n", name, entry->value ? entry->value : "" ); + } + } + + /* + for ( short i = m_Lookup.FirstInorder(); i != m_Lookup.InvalidIndex(); i = m_Lookup.NextInorder( i ) ) + { + const CritEntry_t *entry = &m_Lookup[ i ]; + + const char *pCriteriaName = sm_CriteriaSymbols.String( entry->criterianame ); + if ( entry->weight != 1.0f ) + { + DevMsg( " %20s = '%s' (weight %f)\n", pCriteriaName, entry->value ? entry->value : "", entry->weight ); + } + else + { + DevMsg( " %20s = '%s'\n", pCriteriaName, entry->value ? entry->value : "" ); + } + } + */ +} + + +void CriteriaSet::Reset() +{ + m_Lookup.Purge(); +} + +void CriteriaSet::WriteToEntity( CBaseEntity *pEntity ) +{ +#if 0 + if ( GetCount() < 1 ) + return; + + for ( int i = Head() ; IsValidIndex(i); i = Next(i) ) + { + pEntity->AddContext( GetName(i), GetValue(i), 0 ); + } +#else + AssertMsg( false, "CriteriaSet::WriteToEntity has not been ported from l4d2.\n" ); +#endif +} + +int CriteriaSet::InterceptWorldSetContexts( CriteriaSet * RESTRICT pFrom, CriteriaSet * RESTRICT pSetOnWorld ) +{ + // Assert( pFrom ); Assert( pTo ); Assert( pSetOnWorld ); + Assert( pSetOnWorld != pFrom ); + Assert( pSetOnWorld->GetCount() == 0 ); + + if ( pFrom->m_nNumPrefixedContexts == 0 ) + { + // nothing needs to be done to it. + return 0; + } + +#ifdef DEBUG + // save this off for later error checking. + const int nPrefixedContexts = pFrom->m_nNumPrefixedContexts; +#endif + + // make enough space for the expected output quantity. + pSetOnWorld->EnsureCapacity( pFrom->m_nNumPrefixedContexts ); + + // initialize a buffer with the "world" prefix (so we can use strncpy instead of snprintf and be much faster) + char buf[80] = { 'w', 'o', 'r', 'l', 'd', '\0' }; + const unsigned int PREFIXLEN = 5; // strlen("world") + + // create a second tree that has the appropriately renamed criteria, + // then swap it into pFrom + CriteriaSet rewrite; + rewrite.EnsureCapacity( pFrom->GetCount() + 1 ); + + for ( int i = pFrom->Head(); pFrom->IsValidIndex(i); i = pFrom->Next(i) ) + { + const char *pszName = pFrom->GetName( i ); + if ( pszName[0] == CriteriaSet::kAPPLYTOWORLDPREFIX ) + { // redirect to the world contexts + V_strncpy( buf+PREFIXLEN, pszName+1, sizeof(buf) - PREFIXLEN ); + rewrite.AppendCriteria( buf, pFrom->GetValue(i), pFrom->GetWeight(i) ); + pSetOnWorld->AppendCriteria( pszName+1, pFrom->GetValue(i), pFrom->GetWeight(i) ); + buf[PREFIXLEN] = 0; + } + else + { // does not need to be fiddled; do not write back to world + rewrite.AppendCriteria( pFrom->GetNameSymbol(i), pFrom->GetValue(i), pFrom->GetWeight(i) ); + } + } + AssertMsg2( pSetOnWorld->GetCount() == nPrefixedContexts, "Count of $ persistent RR contexts is inconsistent (%d vs %d)! Call Elan.", + pSetOnWorld->GetCount(), nPrefixedContexts ); + + pFrom->m_nNumPrefixedContexts = 0; + pFrom->m_Lookup.Swap(rewrite.m_Lookup); + return pSetOnWorld->GetCount(); +} diff --git a/sp/src/responserules/runtime/response_rules.vpc b/sp/src/responserules/runtime/response_rules.vpc new file mode 100644 index 00000000..9ab73afa --- /dev/null +++ b/sp/src/responserules/runtime/response_rules.vpc @@ -0,0 +1,41 @@ +//----------------------------------------------------------------------------- +// response_rules.VPC +// +// Project Script +//----------------------------------------------------------------------------- + +$macro SRCDIR "..\.." +$include "$SRCDIR\vpc_scripts\source_lib_base.vpc" + +$Configuration +{ + $Compiler + { + $AdditionalIncludeDirectories "$BASE;..\public\responserules" + $PreprocessorDefinitions "$BASE;RR_RUNTIME" + } +} + +$Project "responserules_runtime" +{ + $Folder "Source Files" + { + $File "criteriaset.cpp" + $File "response_system.cpp" + $File "response_system.h" + $File "response_types.cpp" + $File "response_types_internal.cpp" + $File "response_types_internal.h" + $File "rr_convars.cpp" + $File "rr_response.cpp" + $File "rr_speechconcept.cpp" + $File "rrrlib.cpp" + } + + $Folder "Public Header Files" + { + $File "$SRCDIR\public\responserules\response_host_interface.h" + $File "$SRCDIR\public\responserules\response_types.h" + $File "$SRCDIR\public\responserules\rr_speechconcept.h" + } +} \ No newline at end of file diff --git a/sp/src/responserules/runtime/response_system.cpp b/sp/src/responserules/runtime/response_system.cpp new file mode 100644 index 00000000..afdc40ef --- /dev/null +++ b/sp/src/responserules/runtime/response_system.cpp @@ -0,0 +1,2829 @@ +//========= Copyright © 1996-2010, Valve Corporation, All rights reserved. ============// +// +// Purpose: Core types for the response rules -- criteria, responses, rules, and matchers. +// +// $NoKeywords: $ +//=============================================================================// + +#include "rrbase.h" +#include "vstdlib/random.h" +#include "utlbuffer.h" +#include "tier1/interval.h" +#include "convar.h" +#include "fmtstr.h" +#include "generichash.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +// #pragma optimize( "", off ) + +using namespace ResponseRules; +static void CC_RR_Debug_ResponseConcept_Exclude( const CCommand &args ); +static ConCommand rr_debug_responseconcept_exclude( "rr_debugresponseconcept_exclude", CC_RR_Debug_ResponseConcept_Exclude, "Set a list of concepts to exclude from rr_debugresponseconcept. Separate multiple concepts with spaces. Call with no arguments to see current list. Call 'rr_debug_responseconcept_exclude !' to reset."); +static void CC_RR_DumpHashInfo( const CCommand &args ); + +namespace ResponseRules +{ + // ick + // Wrap string lookup with a hash on the string so that all of the repetitive playerxxx type strings get bucketed out better + #define STRING_BUCKETS_COUNT 64 // Must be power of two + #define STRING_BUCKETS_MASK ( STRING_BUCKETS_COUNT - 1 ) + + CUtlRBTree g_ResponseStrings[ STRING_BUCKETS_COUNT ]; + class CResponseStringBuckets + { + public: + CResponseStringBuckets() + { + for ( int i = 0; i < ARRAYSIZE( g_ResponseStrings ); ++i ) + { + g_ResponseStrings[ i ].SetLessFunc( &StringLessThan ); + } + } + } g_ReponseStringBucketInitializer; + + const char *ResponseCopyString( const char *in ) + { + if ( !in ) + return NULL; + if ( !*in ) + return ""; + + int bucket = ( RR_HASH( in ) & STRING_BUCKETS_MASK ); + + CUtlRBTree &list = g_ResponseStrings[ bucket ]; + + int i = list.Find( in ); + if ( i != list.InvalidIndex() ) +{ + return list[i]; + } + + int len = Q_strlen( in ); + char *out = new char[ len + 1 ]; + Q_memcpy( out, in, len ); + out[ len ] = 0; + list.Insert( out ); + return out; + } +} + +IEngineEmulator *IEngineEmulator::Get() +{ + AssertMsg( IEngineEmulator::s_pSingleton, "Response rules fail: no IEngineEmulator" ); + return IEngineEmulator::s_pSingleton; +} + + +//----------------------------------------------------------------------------- +// Convars +//----------------------------------------------------------------------------- + + +ConVar rr_debugresponses( "rr_debugresponses", "0", FCVAR_NONE, "Show verbose matching output (1 for simple, 2 for rule scoring, 3 for noisy). If set to 4, it will only show response success/failure for npc_selected NPCs." ); +ConVar rr_debugrule( "rr_debugrule", "", FCVAR_NONE, "If set to the name of the rule, that rule's score will be shown whenever a concept is passed into the response rules system."); +ConVar rr_dumpresponses( "rr_dumpresponses", "0", FCVAR_NONE, "Dump all response_rules.txt and rules (requires restart)" ); +ConVar rr_debugresponseconcept( "rr_debugresponseconcept", "", FCVAR_NONE, "If set, rr_debugresponses will print only responses testing for the specified concept" ); +#define RR_DEBUGRESPONSES_SPECIALCASE 4 + + + +//----------------------------------------------------------------------------- +// Copied from SoundParametersInternal.cpp +//----------------------------------------------------------------------------- + +#define SNDLVL_PREFIX "SNDLVL_" + +struct SoundLevelLookup +{ + soundlevel_t level; + char const *name; +}; + +// NOTE: Needs to reflect the soundlevel_t enum defined in soundflags.h +static SoundLevelLookup g_pSoundLevels[] = +{ + { SNDLVL_NONE, "SNDLVL_NONE" }, + { SNDLVL_20dB, "SNDLVL_20dB" }, + { SNDLVL_25dB, "SNDLVL_25dB" }, + { SNDLVL_30dB, "SNDLVL_30dB" }, + { SNDLVL_35dB, "SNDLVL_35dB" }, + { SNDLVL_40dB, "SNDLVL_40dB" }, + { SNDLVL_45dB, "SNDLVL_45dB" }, + { SNDLVL_50dB, "SNDLVL_50dB" }, + { SNDLVL_55dB, "SNDLVL_55dB" }, + { SNDLVL_IDLE, "SNDLVL_IDLE" }, + { SNDLVL_TALKING, "SNDLVL_TALKING" }, + { SNDLVL_60dB, "SNDLVL_60dB" }, + { SNDLVL_65dB, "SNDLVL_65dB" }, + { SNDLVL_STATIC, "SNDLVL_STATIC" }, + { SNDLVL_70dB, "SNDLVL_70dB" }, + { SNDLVL_NORM, "SNDLVL_NORM" }, + { SNDLVL_75dB, "SNDLVL_75dB" }, + { SNDLVL_80dB, "SNDLVL_80dB" }, + { SNDLVL_85dB, "SNDLVL_85dB" }, + { SNDLVL_90dB, "SNDLVL_90dB" }, + { SNDLVL_95dB, "SNDLVL_95dB" }, + { SNDLVL_100dB, "SNDLVL_100dB" }, + { SNDLVL_105dB, "SNDLVL_105dB" }, + { SNDLVL_110dB, "SNDLVL_110dB" }, + { SNDLVL_120dB, "SNDLVL_120dB" }, + { SNDLVL_130dB, "SNDLVL_130dB" }, + { SNDLVL_GUNFIRE, "SNDLVL_GUNFIRE" }, + { SNDLVL_140dB, "SNDLVL_140dB" }, + { SNDLVL_150dB, "SNDLVL_150dB" }, + { SNDLVL_180dB, "SNDLVL_180dB" }, +}; + +static soundlevel_t TextToSoundLevel( const char *key ) +{ + if ( !key ) + { + Assert( 0 ); + return SNDLVL_NORM; + } + + int c = ARRAYSIZE( g_pSoundLevels ); + + int i; + + for ( i = 0; i < c; i++ ) + { + SoundLevelLookup *entry = &g_pSoundLevels[ i ]; + if ( !Q_strcasecmp( key, entry->name ) ) + return entry->level; + } + + if ( !Q_strnicmp( key, SNDLVL_PREFIX, Q_strlen( SNDLVL_PREFIX ) ) ) + { + char const *val = key + Q_strlen( SNDLVL_PREFIX ); + int sndlvl = atoi( val ); + if ( sndlvl > 0 && sndlvl <= 180 ) + { + return ( soundlevel_t )sndlvl; + } + } + + DevMsg( "CSoundEmitterSystem: Unknown sound level %s\n", key ); + + return SNDLVL_NORM; +} + +CResponseSystem::ExcludeList_t CResponseSystem::m_DebugExcludeList( 4, 0 ); + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CResponseSystem::CResponseSystem() : + m_RootCommandHashes( 0, 0, DefLessFunc( unsigned int ) ), + m_FileDispatch( 0, 0, DefLessFunc( unsigned int ) ), + m_RuleDispatch( 0, 0, DefLessFunc( unsigned int ) ), + m_ResponseDispatch( 0, 0, DefLessFunc( unsigned int ) ), + m_ResponseGroupDispatch( 0, 0, DefLessFunc( unsigned int ) ) +{ + token[0] = 0; + m_bUnget = false; + m_bCustomManagable = false; + + BuildDispatchTables(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CResponseSystem::~CResponseSystem() +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : char const +//----------------------------------------------------------------------------- +void CResponseSystem::GetCurrentScript( char *buf, size_t buflen ) +{ + Assert( buf ); + buf[ 0 ] = 0; + if ( m_ScriptStack.Count() <= 0 ) + return; + + if ( IEngineEmulator::Get()->GetFilesystem()->String( m_ScriptStack[ 0 ].name, buf, buflen ) ) + { + return; + } + buf[ 0 ] = 0; +} + +void CResponseSystem::PushScript( const char *scriptfile, unsigned char *buffer ) +{ + ScriptEntry e; + e.name = IEngineEmulator::Get()->GetFilesystem()->FindOrAddFileName( scriptfile ); + e.buffer = buffer; + e.currenttoken = (char *)e.buffer; + e.tokencount = 0; + m_ScriptStack.AddToHead( e ); +} + +void CResponseSystem::PopScript(void) +{ + Assert( m_ScriptStack.Count() >= 1 ); + if ( m_ScriptStack.Count() <= 0 ) + return; + + m_ScriptStack.Remove( 0 ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CResponseSystem::Clear() +{ + m_Responses.RemoveAll(); + m_Criteria.RemoveAll(); + m_RulePartitions.RemoveAll(); + m_Enumerations.RemoveAll(); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *name - +// found - +// Output : float +//----------------------------------------------------------------------------- +float CResponseSystem::LookupEnumeration( const char *name, bool& found ) +{ + int idx = m_Enumerations.Find( name ); + if ( idx == m_Enumerations.InvalidIndex() ) + { + found = false; + return 0.0f; + } + + + found = true; + return m_Enumerations[ idx ].value; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : matcher - +//----------------------------------------------------------------------------- +void CResponseSystem::ResolveToken( Matcher& matcher, char *token, size_t bufsize, char const *rawtoken ) +{ + if ( rawtoken[0] != '[' ) + { + Q_strncpy( token, rawtoken, bufsize ); + return; + } + + // Now lookup enumeration + bool found = false; + float f = LookupEnumeration( rawtoken, found ); + if ( !found ) + { + Q_strncpy( token, rawtoken, bufsize ); + ResponseWarning( "No such enumeration '%s'\n", token ); + return; + } + + Q_snprintf( token, bufsize, "%f", f ); +} + + +static bool AppearsToBeANumber( char const *token ) +{ + if ( atof( token ) != 0.0f ) + return true; + + char const *p = token; + while ( *p ) + { + if ( *p != '0' ) + return false; + + p++; + } + + return true; +} + +void CResponseSystem::ComputeMatcher( Criteria *c, Matcher& matcher ) +{ + const char *s = c->value; + if ( !s ) + { + matcher.valid = false; + return; + } + + const char *in = s; + + char token[ 128 ]; + char rawtoken[ 128 ]; + + token[ 0 ] = 0; + rawtoken[ 0 ] = 0; + + int n = 0; + + bool gt = false; + bool lt = false; + bool eq = false; + bool nt = false; +#ifdef MAPBASE + bool bit = false; +#endif + + bool done = false; + while ( !done ) + { + switch( *in ) + { + case '>': + { + gt = true; + Assert( !lt ); // Can't be both + } + break; + case '<': + { + lt = true; + Assert( !gt ); // Can't be both + } + break; + case '=': + { + eq = true; + } + break; + case ',': + case '\0': + { + rawtoken[ n ] = 0; + n = 0; + + // Convert raw token to real token in case token is an enumerated type specifier + ResolveToken( matcher, token, sizeof( token ), rawtoken ); + +#ifdef MAPBASE + // Bits are an entirely different and independent story + if (bit) + { + matcher.isbit = true; + matcher.notequal = nt; + + matcher.isnumeric = true; + } + else +#endif + // Fill in first data set + if ( gt ) + { + matcher.usemin = true; + matcher.minequals = eq; + matcher.minval = (float)atof( token ); + + matcher.isnumeric = true; + } + else if ( lt ) + { + matcher.usemax = true; + matcher.maxequals = eq; + matcher.maxval = (float)atof( token ); + + matcher.isnumeric = true; + } + else + { + if ( *in == ',' ) + { + // If there's a comma, this better have been a less than or a gt key + Assert( 0 ); + } + + matcher.notequal = nt; + + matcher.isnumeric = AppearsToBeANumber( token ); + } + + gt = lt = eq = nt = false; + + if ( !(*in) ) + { + done = true; + } + } + break; + case '!': + nt = true; + break; +#ifdef MAPBASE + case '~': + nt = true; + case '&': + bit = true; + break; +#endif + default: + rawtoken[ n++ ] = *in; + break; + } + + in++; + } + + matcher.SetToken( token ); + matcher.SetRaw( rawtoken ); + matcher.valid = true; +} + +bool CResponseSystem::CompareUsingMatcher( const char *setValue, Matcher& m, bool verbose /*=false*/ ) +{ + if ( !m.valid ) + return false; + + float v = (float)atof( setValue ); + if ( setValue[0] == '[' ) + { + bool found = false; + v = LookupEnumeration( setValue, found ); + } + +#ifdef MAPBASE + // Bits are always a different story + if (m.isbit) + { + int v1 = v; + int v2 = atoi( m.GetToken() ); + if (m.notequal) + return (v1 & v2) == 0; + else + return (v1 & v2) != 0; + } +#endif + + int minmaxcount = 0; + + if ( m.usemin ) + { + if ( m.minequals ) + { + if ( v < m.minval ) + return false; + } + else + { + if ( v <= m.minval ) + return false; + } + + ++minmaxcount; + } + + if ( m.usemax ) + { + if ( m.maxequals ) + { + if ( v > m.maxval ) + return false; + } + else + { + if ( v >= m.maxval ) + return false; + } + + ++minmaxcount; + } + + // Had one or both criteria and met them + if ( minmaxcount >= 1 ) + { + return true; + } + + if ( m.notequal ) + { + if ( m.isnumeric ) + { + if ( v == (float)atof( m.GetToken() ) ) + return false; + } + else + { + if ( !Q_stricmp( setValue, m.GetToken() ) ) + return false; + } + + return true; + } + + if ( m.isnumeric ) + { + // If the setValue is "", the NPC doesn't have the key at all, + // in which case we shouldn't match "0". + if ( !setValue || !setValue[0] ) + return false; + + return v == (float)atof( m.GetToken() ); + } + + return !Q_stricmp( setValue, m.GetToken() ) ? true : false; +} + +bool CResponseSystem::Compare( const char *setValue, Criteria *c, bool verbose /*= false*/ ) +{ + Assert( c ); + Assert( setValue ); + + bool bret = CompareUsingMatcher( setValue, c->matcher, verbose ); + + if ( verbose ) + { + DevMsg( "'%20s' vs. '%20s' = ", setValue, c->value ); + + { + //DevMsg( "\n" ); + //m.Describe(); + } + } + return bret; +} + +float CResponseSystem::RecursiveScoreSubcriteriaAgainstRule( const CriteriaSet& set, Criteria *parent, bool& exclude, bool verbose /*=false*/ ) +{ + float score = 0.0f; + int subcount = parent->subcriteria.Count(); + for ( int i = 0; i < subcount; i++ ) + { + int icriterion = parent->subcriteria[ i ]; + + bool excludesubrule = false; + if (verbose) + { + DevMsg( "\n" ); + } + score += ScoreCriteriaAgainstRuleCriteria( set, icriterion, excludesubrule, verbose ); + } + + exclude = ( parent->required && score == 0.0f ) ? true : false; + + return score * parent->weight.GetFloat(); +} + +float CResponseSystem::RecursiveLookForCriteria( const CriteriaSet &criteriaSet, Criteria *pParent ) +{ + float flScore = 0.0f; + int nSubCount = pParent->subcriteria.Count(); + for ( int iSub = 0; iSub < nSubCount; ++iSub ) + { + int iCriteria = pParent->subcriteria[iSub]; + flScore += LookForCriteria( criteriaSet, iCriteria ); + } + + return flScore; +} + +float CResponseSystem::LookForCriteria( const CriteriaSet &criteriaSet, int iCriteria ) +{ + Criteria *pCriteria = &m_Criteria[iCriteria]; + if ( pCriteria->IsSubCriteriaType() ) + { + return RecursiveLookForCriteria( criteriaSet, pCriteria ); + } + + int iIndex = criteriaSet.FindCriterionIndex( pCriteria->nameSym ); + if ( iIndex == -1 ) + return 0.0f; + + Assert( criteriaSet.GetValue( iIndex ) ); + if ( Q_stricmp( criteriaSet.GetValue( iIndex ), pCriteria->value ) ) + return 0.0f; + + return 1.0f; +} + +float CResponseSystem::ScoreCriteriaAgainstRuleCriteria( const CriteriaSet& set, int icriterion, bool& exclude, bool verbose /*=false*/ ) +{ + Criteria *c = &m_Criteria[ icriterion ]; + + if ( c->IsSubCriteriaType() ) + { + return RecursiveScoreSubcriteriaAgainstRule( set, c, exclude, verbose ); + } + + if ( verbose ) + { + DevMsg( " criterion '%25s':'%15s' ", m_Criteria.GetElementName( icriterion ), CriteriaSet::SymbolToStr(c->nameSym) ); + } + + exclude = false; + + float score = 0.0f; + + const char *actualValue = ""; + + /* + const char * RESTRICT critname = c->name; + CUtlSymbol sym(critname); + const char * nameDoubleCheck = sym.String(); + */ + int found = set.FindCriterionIndex( c->nameSym ); + if ( found != -1 ) + { + actualValue = set.GetValue( found ); + if ( !actualValue ) + { + Assert( 0 ); + return score; + } + } + + Assert( actualValue ); + + if ( Compare( actualValue, c, verbose ) ) + { + float w = set.GetWeight( found ); + score = w * c->weight.GetFloat(); + + if ( verbose ) + { + DevMsg( "matched, weight %4.2f (s %4.2f x c %4.2f)", + score, w, c->weight.GetFloat() ); + } + } + else + { + if ( c->required ) + { + exclude = true; + if ( verbose ) + { + DevMsg( "failed (+exclude rule)" ); + } + } + else + { + if ( verbose ) + { + DevMsg( "failed" ); + } + } + } + + return score; +} + +float CResponseSystem::ScoreCriteriaAgainstRule( const CriteriaSet& set, ResponseRulePartition::tRuleDict &dict, int irule, bool verbose /*=false*/ ) +{ + Rule * RESTRICT rule = dict[ irule ]; + float score = 0.0f; + + bool bBeingWatched = false; + + // See if we're trying to debug this rule + const char *pszText = rr_debugrule.GetString(); + if ( pszText && pszText[0] && !Q_stricmp( pszText, dict.GetElementName( irule ) ) ) + { + bBeingWatched = true; + } + + if ( !rule->IsEnabled() ) + { + if ( bBeingWatched ) + { + DevMsg("Rule is disabled.\n" ); + } + return 0.0f; + } + + if ( bBeingWatched ) + { + verbose = true; + } + + if ( verbose ) + { + DevMsg( "Scoring rule '%s' (%i)\n{\n", dict.GetElementName( irule ), irule+1 ); + } + + // Iterate set criteria + int count = rule->m_Criteria.Count(); + int i; + for ( i = 0; i < count; i++ ) + { + int icriterion = rule->m_Criteria[ i ]; + + bool exclude = false; + score += ScoreCriteriaAgainstRuleCriteria( set, icriterion, exclude, verbose ); + + if ( verbose ) + { + DevMsg( ", score %4.2f\n", score ); + } + + if ( exclude ) + { + score = 0.0f; + break; + } + } + + if ( verbose ) + { + DevMsg( "}\n" ); + } + + if ( rule->m_nForceWeight > 0 ) + { // this means override the cumulative weight of criteria and just force the rule's total score, + // assuming it matched at all. + return fsel( score - FLT_MIN, rule->m_nForceWeight, 0 ); + } + else + { + return score; +} +} + +void CResponseSystem::DebugPrint( int depth, const char *fmt, ... ) +{ + int indentchars = 3 * depth; + char *indent = (char *) stackalloc( indentchars + 1); + indent[ indentchars ] = 0; + while ( --indentchars >= 0 ) + { + indent[ indentchars ] = ' '; + } + + // Dump text to debugging console. + va_list argptr; + char szText[1024]; + + va_start (argptr, fmt); + Q_vsnprintf (szText, sizeof( szText ), fmt, argptr); + va_end (argptr); + + DevMsg( "%s%s", indent, szText ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CResponseSystem::ResetResponseGroups() +{ + int i; + int c = m_Responses.Count(); + for ( i = 0; i < c; i++ ) + { + m_Responses[ i ].Reset(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Make certain responses unavailable by marking them as depleted +//----------------------------------------------------------------------------- +void CResponseSystem::FakeDepletes( ResponseGroup *g, IResponseFilter *pFilter ) +{ + m_FakedDepletes.RemoveAll(); + + // Fake depletion of unavailable choices + int c = g->group.Count(); + if ( pFilter && g->ShouldCheckRepeats() ) + { + for ( int i = 0; i < c; i++ ) + { + ParserResponse *r = &g->group[ i ]; + if ( r->depletioncount != g->GetDepletionCount() && !pFilter->IsValidResponse( r->GetType(), r->value ) ) + { + m_FakedDepletes.AddToTail( i ); + g->MarkResponseUsed( i ); + } + } + } + + // Fake depletion of choices that fail the odds check + for ( int i = 0; i < c; i++ ) + { + ParserResponse *r = &g->group[ i ]; + if ( RandomInt( 1, 100 ) > r->params.odds ) + { + m_FakedDepletes.AddToTail( i ); + g->MarkResponseUsed( i ); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: Restore responses that were faked as being depleted +//----------------------------------------------------------------------------- +void CResponseSystem::RevertFakedDepletes( ResponseGroup *g ) +{ + for ( int i = 0; i < m_FakedDepletes.Count(); i++ ) + { + g->group[ m_FakedDepletes[ i ] ].depletioncount = 0; + } + m_FakedDepletes.RemoveAll(); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *g - +// Output : int +//----------------------------------------------------------------------------- +int CResponseSystem::SelectWeightedResponseFromResponseGroup( ResponseGroup *g, IResponseFilter *pFilter ) +{ + int c = g->group.Count(); + if ( !c ) + { + Assert( !"Expecting response group with >= 1 elements" ); + return -1; + } + + FakeDepletes( g, pFilter ); + + if ( !g->HasUndepletedChoices() ) + { + g->ResetDepletionCount(); + + FakeDepletes( g, pFilter ); + + if ( !g->HasUndepletedChoices() ) + return -1; + + // Disable the group if we looped through all the way + if ( g->IsNoRepeat() ) + { + g->SetEnabled( false ); + return -1; + } + } + + bool checkrepeats = g->ShouldCheckRepeats(); + int depletioncount = g->GetDepletionCount(); + + float totalweight = 0.0f; + int slot = -1; + + if ( checkrepeats ) + { + int check= -1; + // Snag the first slot right away + if ( g->HasUndepletedFirst( check ) && check != -1 ) + { + slot = check; + } + + if ( slot == -1 && g->HasUndepletedLast( check ) && check != -1 ) + { + // If this is the only undepleted one, use it now + int i; + for ( i = 0; i < c; i++ ) + { + ParserResponse *r = &g->group[ i ]; + if ( checkrepeats && + ( r->depletioncount == depletioncount ) ) + { + continue; + } + + if ( r->last ) + { + Assert( i == check ); + continue; + } + + // There's still another undepleted entry + break; + } + + // No more undepleted so use the r->last slot + if ( i >= c ) + { + slot = check; + } + } + } + + if ( slot == -1 ) + { + for ( int i = 0; i < c; i++ ) + { + ParserResponse *r = &g->group[ i ]; + if ( checkrepeats && + ( r->depletioncount == depletioncount ) ) + { + continue; + } + + // Always skip last entry here since we will deal with it above + if ( checkrepeats && r->last ) + continue; + + int prevSlot = slot; + + if ( !totalweight ) + { + slot = i; + } + + // Always assume very first slot will match + totalweight += r->weight.GetFloat(); + if ( !totalweight || IEngineEmulator::Get()->GetRandomStream()->RandomFloat(0,totalweight) < r->weight.GetFloat() ) + { + slot = i; + } + + if ( !checkrepeats && slot != prevSlot && pFilter && !pFilter->IsValidResponse( r->GetType(), r->value ) ) + { + slot = prevSlot; + totalweight -= r->weight.GetFloat(); + } + } + } + + if ( slot != -1 ) + g->MarkResponseUsed( slot ); + + // Revert fake depletion of unavailable choices + RevertFakedDepletes( g ); + + return slot; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : searchResult - +// depth - +// *name - +// verbose - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CResponseSystem::ResolveResponse( ResponseSearchResult& searchResult, int depth, const char *name, bool verbose /*= false*/, IResponseFilter *pFilter ) +{ + int responseIndex = m_Responses.Find( name ); + if ( responseIndex == m_Responses.InvalidIndex() ) + return false; + + ResponseGroup *g = &m_Responses[ responseIndex ]; + // Group has been disabled + if ( !g->IsEnabled() ) + return false; + + int c = g->group.Count(); + if ( !c ) + return false; + + int idx = 0; + + if ( g->IsSequential() ) + { + // See if next index is valid + int initialIndex = g->GetCurrentIndex(); + bool bFoundValid = false; + + do + { + idx = g->GetCurrentIndex(); + g->SetCurrentIndex( idx + 1 ); + if ( idx >= c ) + { + if ( g->IsNoRepeat() ) + { + g->SetEnabled( false ); + return false; + } + idx = 0; + g->SetCurrentIndex( 0 ); + } + + if ( !pFilter || pFilter->IsValidResponse( g->group[idx].GetType(), g->group[idx].value ) ) + { + bFoundValid = true; + break; + } + + } while ( g->GetCurrentIndex() != initialIndex ); + + if ( !bFoundValid ) + return false; + } + else + { + idx = SelectWeightedResponseFromResponseGroup( g, pFilter ); + if ( idx < 0 ) + return false; + } + + if ( verbose ) + { + DebugPrint( depth, "%s\n", m_Responses.GetElementName( responseIndex ) ); + DebugPrint( depth, "{\n" ); + DescribeResponseGroup( g, idx, depth ); + } + + bool bret = true; + + ParserResponse *result = &g->group[ idx ]; + if ( result->type == RESPONSE_RESPONSE ) + { + // Recurse + bret = ResolveResponse( searchResult, depth + 1, result->value, verbose, pFilter ); + } + else + { + searchResult.action = result; + searchResult.group = g; + } + + if( verbose ) + { + DebugPrint( depth, "}\n" ); + } + + return bret; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *group - +// selected - +// depth - +//----------------------------------------------------------------------------- +void CResponseSystem::DescribeResponseGroup( ResponseGroup *group, int selected, int depth ) +{ + int c = group->group.Count(); + + for ( int i = 0; i < c ; i++ ) + { + ParserResponse *r = &group->group[ i ]; + DebugPrint( depth + 1, "%s%20s : %40s %5.3f\n", + i == selected ? "-> " : " ", + CRR_Response::DescribeResponse( r->GetType() ), + r->value, + r->weight.GetFloat() ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *rule - +// Output : CResponseSystem::Response +//----------------------------------------------------------------------------- +bool CResponseSystem::GetBestResponse( ResponseSearchResult& searchResult, Rule *rule, bool verbose /*=false*/, IResponseFilter *pFilter ) +{ + int c = rule->m_Responses.Count(); + if ( !c ) + return false; + + int index = IEngineEmulator::Get()->GetRandomStream()->RandomInt( 0, c - 1 ); + int groupIndex = rule->m_Responses[ index ]; + + ResponseGroup *g = &m_Responses[ groupIndex ]; + + // Group has been disabled + if ( !g->IsEnabled() ) + return false; + + int count = g->group.Count(); + if ( !count ) + return false; + + int responseIndex = 0; + + if ( g->IsSequential() ) + { + // See if next index is valid + int initialIndex = g->GetCurrentIndex(); + bool bFoundValid = false; + + do + { + responseIndex = g->GetCurrentIndex(); + g->SetCurrentIndex( responseIndex + 1 ); + if ( responseIndex >= count ) + { + if ( g->IsNoRepeat() ) + { + g->SetEnabled( false ); + return false; + } + responseIndex = 0; + g->SetCurrentIndex( 0 ); + } + + if ( !pFilter || pFilter->IsValidResponse( g->group[responseIndex].GetType(), g->group[responseIndex].value ) ) + { + bFoundValid = true; + break; + } + + } while ( g->GetCurrentIndex() != initialIndex ); + + if ( !bFoundValid ) + return false; + } + else + { + responseIndex = SelectWeightedResponseFromResponseGroup( g, pFilter ); + if ( responseIndex < 0 ) + return false; + } + + + ParserResponse *r = &g->group[ responseIndex ]; + + int depth = 0; + + if ( verbose ) + { + DebugPrint( depth, "%s\n", m_Responses.GetElementName( groupIndex ) ); + DebugPrint( depth, "{\n" ); + + DescribeResponseGroup( g, responseIndex, depth ); + } + + bool bret = true; + + if ( r->type == RESPONSE_RESPONSE ) + { + bret = ResolveResponse( searchResult, depth + 1, r->value, verbose, pFilter ); + } + else + { + searchResult.action = r; + searchResult.group = g; + } + + if ( verbose ) + { + DebugPrint( depth, "}\n" ); + } + + return bret; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : set - +// verbose - +// Output : int +// Warning: If you change this, be sure to also change +// ResponseSystemImplementationCLI::FindAllRulesMatchingCriteria(). +//----------------------------------------------------------------------------- +ResponseRulePartition::tIndex CResponseSystem::FindBestMatchingRule( const CriteriaSet& set, bool verbose, float &scoreOfBestMatchingRule ) +{ + CUtlVector< ResponseRulePartition::tIndex > bestrules(16,4); + float bestscore = 0.001f; + scoreOfBestMatchingRule = 0; + + CUtlVectorFixed< ResponseRulePartition::tRuleDict *, 2 > buckets( 0, 2 ); + m_RulePartitions.GetDictsForCriteria( &buckets, set ); + for ( int b = 0 ; b < buckets.Count() ; ++b ) + { + ResponseRulePartition::tRuleDict *prules = buckets[b]; + int c = prules->Count(); + int i; + for ( i = 0; i < c; i++ ) + { + float score = ScoreCriteriaAgainstRule( set, *prules, i, verbose ); + // Check equals so that we keep track of all matching rules + if ( score >= bestscore ) + { + // Reset bucket + if( score != bestscore ) + { + bestscore = score; + bestrules.RemoveAll(); + } + + // Add to bucket + bestrules.AddToTail( m_RulePartitions.IndexFromDictElem( prules, i ) ); + } + } + } + + int bestCount = bestrules.Count(); + if ( bestCount <= 0 ) + return m_RulePartitions.InvalidIdx(); + + scoreOfBestMatchingRule = bestscore ; + if ( bestCount == 1 ) + { + return bestrules[ 0 ] ; + } + else + { + // Randomly pick one of the tied matching rules + int idx = IEngineEmulator::Get()->GetRandomStream()->RandomInt( 0, bestCount - 1 ); + if ( verbose ) + { + DevMsg( "Found %i matching rules, selecting slot %i\n", bestCount, idx ); + } + return bestrules[ idx ] ; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : set - +// Output : CRR_Response +//----------------------------------------------------------------------------- +bool CResponseSystem::FindBestResponse( const CriteriaSet& set, CRR_Response& response, IResponseFilter *pFilter ) +{ + bool valid = false; + + int iDbgResponse = rr_debugresponses.GetInt(); + bool showRules = ( iDbgResponse >= 2 && iDbgResponse < RR_DEBUGRESPONSES_SPECIALCASE ); + bool showResult = ( iDbgResponse >= 1 && iDbgResponse < RR_DEBUGRESPONSES_SPECIALCASE ); + + // Look for match. verbose mode used to be at level 2, but disabled because the writers don't actually care for that info. + float scoreOfBestRule; + ResponseRulePartition::tIndex bestRule = FindBestMatchingRule( set, + ( iDbgResponse >= 3 && iDbgResponse < RR_DEBUGRESPONSES_SPECIALCASE ), + scoreOfBestRule ); + + ResponseType_t responseType = RESPONSE_NONE; + ResponseParams rp; + + char ruleName[ 128 ]; + char responseName[ 128 ]; + const char *context; +#ifdef MAPBASE + int contextflags; +#else + bool bcontexttoworld; +#endif + ruleName[ 0 ] = 0; + responseName[ 0 ] = 0; + context = NULL; +#ifdef MAPBASE + contextflags = 0; +#else + bcontexttoworld = false; +#endif + if ( m_RulePartitions.IsValid( bestRule ) ) + { + Rule * RESTRICT r = &m_RulePartitions[ bestRule ]; + + ResponseSearchResult result; + if ( GetBestResponse( result, r, showResult, pFilter ) ) + { + Q_strncpy( responseName, result.action->value, sizeof( responseName ) ); + responseType = result.action->GetType(); + rp = result.action->params; + rp.m_pFollowup = &result.action->m_followup; + } + + Q_strncpy( ruleName, m_RulePartitions.GetElementName( bestRule ), sizeof( ruleName ) ); + + // Disable the rule if it only allows for matching one time + if ( r->IsMatchOnce() ) + { + r->Disable(); + } + context = r->GetContext(); +#ifdef MAPBASE + contextflags = r->GetContextFlags(); +#else + bcontexttoworld = r->IsApplyContextToWorld(); +#endif + + response.SetMatchScore(scoreOfBestRule); + valid = true; + } + +#ifdef MAPBASE + response.Init( responseType, responseName, rp, ruleName, context, contextflags ); +#else + response.Init( responseType, responseName, rp, ruleName, context, bcontexttoworld ); +#endif + + if ( showResult ) + { + /* + // clipped -- chet doesn't really want this info + if ( valid ) + { + // Rescore the winner and dump to console + ScoreCriteriaAgainstRule( set, bestRule, true ); + } + */ + + + if ( valid || showRules ) + { + const char *pConceptFilter = rr_debugresponseconcept.GetString(); + // Describe the response, too + if ( V_strlen(pConceptFilter) > 0 && !rr_debugresponseconcept.GetBool() ) + { // filter for only one concept + if ( V_stricmp(pConceptFilter, set.GetValue(set.FindCriterionIndex("concept")) ) == 0 ) + { + response.Describe(&set); + } // else don't print + } + else + { + // maybe we need to filter *out* some concepts + if ( m_DebugExcludeList.IsValidIndex( m_DebugExcludeList.Head() ) ) + { + // we are excluding at least one concept + CRR_Concept test( set.GetValue(set.FindCriterionIndex("concept")) ); + if ( ! m_DebugExcludeList.IsValidIndex( m_DebugExcludeList.Find( test ) ) ) + { // if not found in exclude list, then print + response.Describe(&set); + } + } + else + { + // describe everything + response.Describe(&set); + } + } + } + } + + return valid; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CResponseSystem::GetAllResponses( CUtlVector *pResponses ) +{ + for ( int i = 0; i < (int)m_Responses.Count(); i++ ) + { + ResponseGroup &group = m_Responses[i]; + + for ( int j = 0; j < group.group.Count(); j++) + { + ParserResponse &response = group.group[j]; + if ( response.type != RESPONSE_RESPONSE ) + { + /* + CRR_Response *pResponse = new CRR_Response; + pResponse->Init( response.GetType(), response.value, CriteriaSet(), response.params, NULL, NULL, false ); + pResponses->AddToTail(pResponse); + */ + pResponses->Element(pResponses->AddToTail()).Init( response.GetType(), response.value, response.params, NULL, NULL, false ); + } + } + } +} + +void CResponseSystem::ParseInclude() +{ + char includefile[ 256 ]; + ParseToken(); + +#ifdef MAPBASE + char scriptfile[256]; + GetCurrentScript( scriptfile, sizeof( scriptfile ) ); + + // Gets first path + // (for example, an #include from a file in resource/script/resp will return resource) + size_t len = strlen(scriptfile)-1; + for (size_t i = 0; i < len; i++) + { + if (scriptfile[i] == CORRECT_PATH_SEPARATOR || scriptfile[i] == INCORRECT_PATH_SEPARATOR) + { + len = i; + } + } + Q_strncpy(includefile, scriptfile, len+1); + + if (len+1 != strlen(scriptfile)) + { + Q_snprintf(includefile, sizeof(includefile), "%s/%s", includefile, token); + } + else + includefile[0] = '\0'; + + if (!includefile[0]) + Q_snprintf( includefile, sizeof( includefile ), "scripts/%s", token ); +#else + Q_snprintf( includefile, sizeof( includefile ), "scripts/%s", token ); +#endif + + // check if the file is already included + if ( m_IncludedFiles.Find( includefile ) != NULL ) + { + return; + } + + MEM_ALLOC_CREDIT(); + + // Try and load it + CUtlBuffer buf; + if ( !IEngineEmulator::Get()->GetFilesystem()->ReadFile( includefile, "GAME", buf ) ) + { + DevMsg( "Unable to load #included script %s\n", includefile ); + return; + } + + LoadFromBuffer( includefile, (const char *)buf.PeekGet() ); +} + +void CResponseSystem::LoadFromBuffer( const char *scriptfile, const char *buffer ) +{ + COM_TimestampedLog( "CResponseSystem::LoadFromBuffer [%s] - Start", scriptfile ); + m_IncludedFiles.Allocate( scriptfile ); + PushScript( scriptfile, (unsigned char * )buffer ); + + if( rr_dumpresponses.GetBool() ) + { + DevMsg("Reading: %s\n", scriptfile ); + } + + while ( 1 ) + { + ParseToken(); + if ( !token[0] ) + { + break; + } + + unsigned int hash = RR_HASH( token ); + bool bSuccess = Dispatch( token, hash, m_FileDispatch ); + if ( !bSuccess ) + { + int byteoffset = m_ScriptStack[ 0 ].currenttoken - (const char *)m_ScriptStack[ 0 ].buffer; + + Error( "CResponseSystem::LoadFromBuffer: Unknown entry type '%s', expecting 'response', 'criterion', 'enumeration' or 'rules' in file %s(offset:%i)\n", + token, scriptfile, byteoffset ); + break; + } + } + + if ( m_ScriptStack.Count() == 1 ) + { + char cur[ 256 ]; + GetCurrentScript( cur, sizeof( cur ) ); + DevMsg( 1, "CResponseSystem: %s (%i rules, %i criteria, and %i responses)\n", + cur, m_RulePartitions.Count(), m_Criteria.Count(), m_Responses.Count() ); + + if( rr_dumpresponses.GetBool() ) + { + DumpRules(); + } + } + + PopScript(); + COM_TimestampedLog( "CResponseSystem::LoadFromBuffer [%s] - Finish", scriptfile ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CResponseSystem::LoadRuleSet( const char *basescript ) +{ + float flStart = Plat_FloatTime(); + int length = 0; + unsigned char *buffer = (unsigned char *)IEngineEmulator::Get()->LoadFileForMe( basescript, &length ); + if ( length <= 0 || !buffer ) + { + DevMsg( 1, "CResponseSystem: failed to load %s\n", basescript ); + return; + } + + m_IncludedFiles.FreeAll(); + LoadFromBuffer( basescript, (const char *)buffer ); + + IEngineEmulator::Get()->FreeFile( buffer ); + + Assert( m_ScriptStack.Count() == 0 ); + float flEnd = Plat_FloatTime(); + COM_TimestampedLog( "CResponseSystem::LoadRuleSet took %f msec", 1000.0f * ( flEnd - flStart ) ); +} + +inline ResponseType_t ComputeResponseType( const char *s ) +{ + switch ( s[ 0 ] ) + { + default: + break; + case 's': + switch ( s[ 1 ] ) + { + default: + break; + case 'c': + return RESPONSE_SCENE; + case 'e': + return RESPONSE_SENTENCE; + case 'p': + return RESPONSE_SPEAK; + } + break; + case 'r': + return RESPONSE_RESPONSE; + case 'p': + return RESPONSE_PRINT; + case 'e': + return RESPONSE_ENTITYIO; +#ifdef MAPBASE + case 'v': + return RESPONSE_VSCRIPT; +#endif + } + + return RESPONSE_NONE; +} + +void CResponseSystem::ParseResponse_Weight( ParserResponse &newResponse, ResponseGroup& group, AI_ResponseParams *rp ) +{ + ParseToken(); + newResponse.weight.SetFloat( (float)atof( token ) ); +} + +void CResponseSystem::ParseResponse_PreDelay( ParserResponse &newResponse, ResponseGroup& group, AI_ResponseParams *rp ) +{ + ParseToken(); + rp->flags |= AI_ResponseParams::RG_DELAYBEFORESPEAK; + rp->predelay.FromInterval( ReadInterval( token ) ); +} + +void CResponseSystem::ParseResponse_NoDelay( ParserResponse &newResponse, ResponseGroup& group, AI_ResponseParams *rp ) +{ + ParseToken(); + rp->flags |= AI_ResponseParams::RG_DELAYAFTERSPEAK; + rp->delay.start = 0; + rp->delay.range = 0; +} + +void CResponseSystem::ParseResponse_DefaultDelay( ParserResponse &newResponse, ResponseGroup& group, AI_ResponseParams *rp ) +{ + rp->flags |= AI_ResponseParams::RG_DELAYAFTERSPEAK; + rp->delay.start = AIS_DEF_MIN_DELAY; + rp->delay.range = ( AIS_DEF_MAX_DELAY - AIS_DEF_MIN_DELAY ); +} + +void CResponseSystem::ParseResponse_Delay( ParserResponse &newResponse, ResponseGroup& group, AI_ResponseParams *rp ) +{ + ParseToken(); + rp->flags |= AI_ResponseParams::RG_DELAYAFTERSPEAK; + rp->delay.FromInterval( ReadInterval( token ) ); +} + +void CResponseSystem::ParseResponse_SpeakOnce( ParserResponse &newResponse, ResponseGroup& group, AI_ResponseParams *rp ) +{ + rp->flags |= AI_ResponseParams::RG_SPEAKONCE; +} + +void CResponseSystem::ParseResponse_NoScene( ParserResponse &newResponse, ResponseGroup& group, AI_ResponseParams *rp ) +{ + rp->flags |= AI_ResponseParams::RG_DONT_USE_SCENE; +} + +void CResponseSystem::ParseResponse_StopOnNonIdle( ParserResponse &newResponse, ResponseGroup& group, AI_ResponseParams *rp ) +{ + rp->flags |= AI_ResponseParams::RG_STOP_ON_NONIDLE; +} + +void CResponseSystem::ParseResponse_Odds( ParserResponse &newResponse, ResponseGroup& group, AI_ResponseParams *rp ) +{ + ParseToken(); + rp->flags |= AI_ResponseParams::RG_ODDS; + rp->odds = clamp( atoi( token ), 0, 100 ); +} + +void CResponseSystem::ParseResponse_RespeakDelay( ParserResponse &newResponse, ResponseGroup& group, AI_ResponseParams *rp ) +{ + ParseToken(); + rp->flags |= AI_ResponseParams::RG_RESPEAKDELAY; + rp->respeakdelay.FromInterval( ReadInterval( token ) ); +} + +void CResponseSystem::ParseResponse_WeaponDelay( ParserResponse &newResponse, ResponseGroup& group, AI_ResponseParams *rp ) +{ + ParseToken(); + rp->flags |= AI_ResponseParams::RG_WEAPONDELAY; + rp->weapondelay.FromInterval( ReadInterval( token ) ); +} + +void CResponseSystem::ParseResponse_Soundlevel( ParserResponse &newResponse, ResponseGroup& group, AI_ResponseParams *rp ) +{ + ParseToken(); + rp->flags |= AI_ResponseParams::RG_SOUNDLEVEL; + rp->soundlevel = (soundlevel_t)TextToSoundLevel( token ); +} + +void CResponseSystem::ParseResponse_DisplayFirst( ParserResponse &newResponse, ResponseGroup& group, AI_ResponseParams *rp ) +{ + newResponse.first = true; + group.m_bHasFirst = true; +} + +void CResponseSystem::ParseResponse_DisplayLast( ParserResponse &newResponse, ResponseGroup& group, AI_ResponseParams *rp ) +{ + newResponse.last = true; + group.m_bHasLast= true; +} + +void CResponseSystem::ParseResponse_Fire( ParserResponse &newResponse, ResponseGroup& group, AI_ResponseParams *rp ) +{ + // get target name + bool bSuc = ParseToken(); + if (!bSuc) + { + ResponseWarning( "FIRE token in response needs exactly three parameters." ); + return; + } + newResponse.m_followup.followup_entityiotarget = ResponseCopyString(token); + + bSuc = ParseToken(); + if (!bSuc) + { + ResponseWarning( "FIRE token in response needs exactly three parameters." ); + return; + } + newResponse.m_followup.followup_entityioinput = ResponseCopyString(token); + + bSuc = ParseToken(); + if (!bSuc) + { + ResponseWarning( "FIRE token in response needs exactly three parameters." ); + return; + } + newResponse.m_followup.followup_entityiodelay = atof( token ); + /* + m_followup.followup_entityioinput = ResponseCopyString(src.m_followup.followup_entityioinput); + m_followup.followup_entityiotarget = ResponseCopyString(src.m_followup.followup_entityiotarget); + */ +} + +void CResponseSystem::ParseResponse_Then( ParserResponse &newResponse, ResponseGroup& group, AI_ResponseParams *rp ) +{ + // eg, "subject TALK_ANSWER saidunplant:1 3" + bool bSuc = ParseToken(); + if (!bSuc) + { + AssertMsg(false, "THEN token in response lacked any further info.\n"); + ResponseWarning( "THEN token in response lacked any further info.\n" ); + return; + } + + newResponse.m_followup.followup_target = ResponseCopyString(token); + + bSuc = ParseToken(); // get another token + if (!bSuc) + { + AssertMsg1(false, "THEN token in response had a target '%s', but lacked any further info.\n", newResponse.m_followup.followup_target ); + ResponseWarning( "THEN token in response had a target '%s', but lacked any further info.\n", newResponse.m_followup.followup_target ); + return; + } + + newResponse.m_followup.followup_concept = ResponseCopyString( token ); + + + // Okay, this is totally asinine. + // Because the ParseToken() function will split foo:bar into three tokens + // (which is reasonable), but we have no safe way to parse the file otherwise + // because it's all behind an engine interface, it's necessary to parse all + // the tokens to the end of the line and catenate them, except for the last one + // which is the delay. That's crap. + bSuc = ParseToken(); + if (!bSuc) + { + AssertMsg(false, "THEN token in response lacked contexts.\n"); + ResponseWarning( "THEN token in response lacked contexts.\n" ); + return; + } + + // okay, as long as there is at least one more token, catenate the ones we + // see onto a temporary buffer. When we're down to the last token, that is + // the delay. + char buf[4096]; + buf[0] = '\0'; + while ( TokenWaiting() ) + { + Q_strncat( buf, token, 4096 ); + bSuc = ParseToken(); + AssertMsg(bSuc, "Token parsing mysteriously failed."); + } + + // down here, token is the last token, and buf is everything up to there. + newResponse.m_followup.followup_contexts = ResponseCopyString( buf ); + + newResponse.m_followup.followup_delay = atof( token ); +} + +void CResponseSystem::ParseOneResponse( const char *responseGroupName, ResponseGroup& group, ResponseParams *defaultParams ) +{ + ParserResponse &newResponse = group.group[ group.group.AddToTail() ]; + newResponse.weight.SetFloat( 1.0f ); + // inherit from group if appropriate + if (defaultParams) + { + newResponse.params = *defaultParams; + } + + ResponseParams *rp = &newResponse.params; + + newResponse.type = ComputeResponseType( token ); + if ( RESPONSE_NONE == newResponse.type ) +{ + ResponseWarning( "response entry '%s' with unknown response type '%s'\n", responseGroupName, token ); + return; +} + +#ifdef MAPBASE + // HACKHACK: Some response system usage in the pre-Alien Swarm system require response names to preserve casing or even have escaped quotes. + ParseTokenIntact(); +#else + ParseToken(); +#endif + newResponse.value = ResponseCopyString( token ); + + while ( TokenWaiting() ) + { + ParseToken(); + + unsigned int hash = RR_HASH( token ); + if ( DispatchParseResponse( token, hash, m_ResponseDispatch, newResponse, group, rp ) ) + { + continue; + } + + ResponseWarning( "response entry '%s' with unknown command '%s'\n", responseGroupName, token ); + } + +} + +void CResponseSystem::ParseResponseGroup_Start( char const *responseGroupName, ResponseGroup &newGroup, AI_ResponseParams &groupResponseParams ) + { + while ( 1 ) + { + ParseToken(); + if ( !Q_stricmp( token, "}" ) ) + break; + + if ( !Q_stricmp( token, "permitrepeats" ) ) + { + newGroup.m_bDepleteBeforeRepeat = false; + continue; + } + else if ( !Q_stricmp( token, "sequential" ) ) + { + newGroup.SetSequential( true ); + continue; + } + else if ( !Q_stricmp( token, "norepeat" ) ) + { + newGroup.SetNoRepeat( true ); + continue; + } + + ParseOneResponse( responseGroupName, newGroup ); + } + } + +void CResponseSystem::ParseResponseGroup_PreDelay( char const *responseGroupName, ResponseGroup &newGroup, AI_ResponseParams &groupResponseParams ) + { + ParseToken(); + groupResponseParams.flags |= AI_ResponseParams::RG_DELAYBEFORESPEAK; + groupResponseParams.predelay.FromInterval( ReadInterval( token ) ); + } + +void CResponseSystem::ParseResponseGroup_NoDelay( char const *responseGroupName, ResponseGroup &newGroup, AI_ResponseParams &groupResponseParams ) + { + ParseToken(); + groupResponseParams.flags |= AI_ResponseParams::RG_DELAYAFTERSPEAK; + groupResponseParams.delay.start = 0; + groupResponseParams.delay.range = 0; + } + +void CResponseSystem::ParseResponseGroup_DefaultDelay( char const *responseGroupName, ResponseGroup &newGroup, AI_ResponseParams &groupResponseParams ) + { + groupResponseParams.flags |= AI_ResponseParams::RG_DELAYAFTERSPEAK; + groupResponseParams.delay.start = AIS_DEF_MIN_DELAY; + groupResponseParams.delay.range = ( AIS_DEF_MAX_DELAY - AIS_DEF_MIN_DELAY ); + } + +void CResponseSystem::ParseResponseGroup_Delay( char const *responseGroupName, ResponseGroup &newGroup, AI_ResponseParams &groupResponseParams ) + { + ParseToken(); + groupResponseParams.flags |= AI_ResponseParams::RG_DELAYAFTERSPEAK; + groupResponseParams.delay.FromInterval( ReadInterval( token ) ); + } + +void CResponseSystem::ParseResponseGroup_SpeakOnce( char const *responseGroupName, ResponseGroup &newGroup, AI_ResponseParams &groupResponseParams ) + { + groupResponseParams.flags |= AI_ResponseParams::RG_SPEAKONCE; + } + +void CResponseSystem::ParseResponseGroup_NoScene( char const *responseGroupName, ResponseGroup &newGroup, AI_ResponseParams &groupResponseParams ) + { + groupResponseParams.flags |= AI_ResponseParams::RG_DONT_USE_SCENE; + } + +void CResponseSystem::ParseResponseGroup_StopOnNonIdle( char const *responseGroupName, ResponseGroup &newGroup, AI_ResponseParams &groupResponseParams ) + { + groupResponseParams.flags |= AI_ResponseParams::RG_STOP_ON_NONIDLE; + } + +void CResponseSystem::ParseResponseGroup_Odds( char const *responseGroupName, ResponseGroup &newGroup, AI_ResponseParams &groupResponseParams ) + { + ParseToken(); + groupResponseParams.flags |= AI_ResponseParams::RG_ODDS; + groupResponseParams.odds = clamp( atoi( token ), 0, 100 ); + } + +void CResponseSystem::ParseResponseGroup_RespeakDelay( char const *responseGroupName, ResponseGroup &newGroup, AI_ResponseParams &groupResponseParams ) + { + ParseToken(); + groupResponseParams.flags |= AI_ResponseParams::RG_RESPEAKDELAY; + groupResponseParams.respeakdelay.FromInterval( ReadInterval( token ) ); + } + +void CResponseSystem::ParseResponseGroup_WeaponDelay( char const *responseGroupName, ResponseGroup &newGroup, AI_ResponseParams &groupResponseParams ) + { + ParseToken(); + groupResponseParams.flags |= AI_ResponseParams::RG_WEAPONDELAY; + groupResponseParams.weapondelay.FromInterval( ReadInterval( token ) ); + } + +void CResponseSystem::ParseResponseGroup_Soundlevel( char const *responseGroupName, ResponseGroup &newGroup, AI_ResponseParams &groupResponseParams ) + { + ParseToken(); + groupResponseParams.flags |= AI_ResponseParams::RG_SOUNDLEVEL; + groupResponseParams.soundlevel = (soundlevel_t)TextToSoundLevel( token ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CResponseSystem::ParseResponse( void ) +{ + AI_ResponseParams groupResponseParams; // default response parameters inherited from single line format for group + + // Should have groupname at start + ParseToken(); + char responseGroupName[ 128 ]; + Q_strncpy( responseGroupName, token, sizeof( responseGroupName ) ); + + int slot = m_Responses.Insert( responseGroupName ); + ResponseGroup &newGroup = m_Responses[ slot ]; + + while ( 1 ) + { + ParseToken(); + + unsigned int hash = RR_HASH( token ); + + // Oops, part of next definition + if( IsRootCommand( hash ) ) + { + Unget(); + break; + } + + if ( DispatchParseResponseGroup( token, hash, m_ResponseGroupDispatch, responseGroupName, newGroup, groupResponseParams ) ) + { + continue; + } + ParseOneResponse( responseGroupName, newGroup ); + } + } + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *criterion - +//----------------------------------------------------------------------------- +int CResponseSystem::ParseOneCriterion( const char *criterionName ) +{ + char key[ 128 ]; + char value[ 128 ]; + + Criteria *pNewCriterion = NULL; + + int idx; +#ifdef MAPBASE + short existing = m_Criteria.Find( criterionName ); + if ( existing != m_Criteria.InvalidIndex() ) + { + //ResponseWarning( "Additional definition for criteria '%s', overwriting\n", criterionName ); + m_Criteria[existing] = Criteria(); + m_Criteria.SetElementName(existing, criterionName); + idx = existing; + pNewCriterion = &m_Criteria[ idx ]; + } +#else + if ( m_Criteria.Find( criterionName ) != m_Criteria.InvalidIndex() ) + { + static Criteria dummy; + pNewCriterion = &dummy; + + ResponseWarning( "Multiple definitions for criteria '%s' [%d]\n", criterionName, RR_HASH( criterionName ) ); + idx = m_Criteria.InvalidIndex(); + } +#endif + else + { + idx = m_Criteria.Insert( criterionName ); + pNewCriterion = &m_Criteria[ idx ]; + } + + bool gotbody = false; + + while ( TokenWaiting() || !gotbody ) + { + ParseToken(); + + // Oops, part of next definition + if( IsRootCommand() ) + { + Unget(); + break; + } + + if ( !Q_stricmp( token, "{" ) ) + { + gotbody = true; + + while ( 1 ) + { + ParseToken(); + if ( !Q_stricmp( token, "}" ) ) + break; + + // Look up subcriteria index + int idx = m_Criteria.Find( token ); + if ( idx != m_Criteria.InvalidIndex() ) + { + pNewCriterion->subcriteria.AddToTail( idx ); + } + else + { + ResponseWarning( "Skipping unrecongized subcriterion '%s' in '%s'\n", token, criterionName ); + } + } + continue; + } + else if ( !Q_stricmp( token, "required" ) ) + { + pNewCriterion->required = true; + } + else if ( !Q_stricmp( token, "weight" ) ) + { + ParseToken(); + pNewCriterion->weight.SetFloat( (float)atof( token ) ); + } + else + { + Assert( pNewCriterion->subcriteria.Count() == 0 ); + + // Assume it's the math info for a non-subcriteria resposne + Q_strncpy( key, token, sizeof( key ) ); + ParseToken(); + Q_strncpy( value, token, sizeof( value ) ); + + V_strlower( key ); + pNewCriterion->nameSym = CriteriaSet::ComputeCriteriaSymbol( key ); + pNewCriterion->value = ResponseCopyString( value ); + + gotbody = true; + } + } + + if ( !pNewCriterion->IsSubCriteriaType() ) + { + ComputeMatcher( pNewCriterion, pNewCriterion->matcher ); + } + + return idx; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *kv - +//----------------------------------------------------------------------------- +void CResponseSystem::ParseCriterion( void ) +{ + // Should have groupname at start + char criterionName[ 128 ]; + ParseToken(); + Q_strncpy( criterionName, token, sizeof( criterionName ) ); + + ParseOneCriterion( criterionName ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *kv - +//----------------------------------------------------------------------------- +void CResponseSystem::ParseEnumeration( void ) +{ + char enumerationName[ 128 ]; + ParseToken(); + Q_strncpy( enumerationName, token, sizeof( enumerationName ) ); + + ParseToken(); + if ( Q_stricmp( token, "{" ) ) + { + ResponseWarning( "Expecting '{' in enumeration '%s', got '%s'\n", enumerationName, token ); + return; + } + + while ( 1 ) + { + ParseToken(); + if ( !Q_stricmp( token, "}" ) ) + break; + + if ( Q_strlen( token ) <= 0 ) + { + ResponseWarning( "Expecting more tokens in enumeration '%s'\n", enumerationName ); + break; + } + + char key[ 128 ]; + + Q_strncpy( key, token, sizeof( key ) ); + ParseToken(); + float value = (float)atof( token ); + + char sz[ 128 ]; + Q_snprintf( sz, sizeof( sz ), "[%s::%s]", enumerationName, key ); + Q_strlower( sz ); + + Enumeration newEnum; + newEnum.value = value; + + if ( m_Enumerations.Find( sz ) == m_Enumerations.InvalidIndex() ) + { + m_Enumerations.Insert( sz, newEnum ); + } + /* + else + { + ResponseWarning( "Ignoring duplication enumeration '%s'\n", sz ); + } + */ + } +} + +void CResponseSystem::ParseRule_MatchOnce( Rule &newRule ) + { + newRule.m_bMatchOnce = true; + } + +#ifdef MAPBASE +void CResponseSystem::ParseRule_ApplyContextToWorld( Rule &newRule ) + { + newRule.m_iContextFlags |= APPLYCONTEXT_WORLD; + } + +void CResponseSystem::ParseRule_ApplyContextToSquad( Rule &newRule ) + { + newRule.m_iContextFlags |= APPLYCONTEXT_SQUAD; + } + +void CResponseSystem::ParseRule_ApplyContextToEnemy( Rule &newRule ) + { + newRule.m_iContextFlags |= APPLYCONTEXT_ENEMY; + } +#else +void CResponseSystem::ParseRule_ApplyContextToWorld( Rule &newRule ) + { + newRule.m_bApplyContextToWorld = true; + } +#endif + +void CResponseSystem::ParseRule_ApplyContext( Rule &newRule ) + { + ParseToken(); + if ( newRule.GetContext() == NULL ) + { + newRule.SetContext( token ); + } + else + { + CFmtStrN<1024> newContext( "%s,%s", newRule.GetContext(), token ); + newRule.SetContext( newContext ); + } + } + +void CResponseSystem::ParseRule_Response( Rule &newRule ) + { + // Read them until we run out. + while ( TokenWaiting() ) + { + ParseToken(); + int idx = m_Responses.Find( token ); + if ( idx != m_Responses.InvalidIndex() ) + { + MEM_ALLOC_CREDIT(); + newRule.m_Responses.AddToTail( idx ); + } + else + { + m_bParseRuleValid = false; + ResponseWarning( "No such response '%s' for rule '%s'\n", token, m_pParseRuleName ); + } + } +} + +/* +void CResponseSystem::ParseRule_ForceWeight( Rule &newRule ) +{ + ParseToken(); + if ( token[0] == 0 ) + { + // no token followed forceweight? + ResponseWarning( "Forceweight token in rule '%s' did not specify a numerical weight! Ignoring.\n", m_pParseRuleName ); + } + else + { + newRule.m_nForceWeight = atoi(token); + if ( newRule.m_nForceWeight == 0 ) + { + ResponseWarning( "Rule '%s' had forceweight '%s', which doesn't work out to a nonzero number. Ignoring.\n", + m_pParseRuleName, token ); + } + } + } +*/ + +void CResponseSystem::ParseRule_Criteria( Rule &newRule ) + { + // Read them until we run out. + while ( TokenWaiting() ) + { + ParseToken(); + + int idx = m_Criteria.Find( token ); + if ( idx != m_Criteria.InvalidIndex() ) + { + MEM_ALLOC_CREDIT(); + newRule.m_Criteria.AddToTail( idx ); + } + else + { + m_bParseRuleValid = false; + ResponseWarning( "No such criterion '%s' for rule '%s'\n", token, m_pParseRuleName ); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *kv - +//----------------------------------------------------------------------------- +void CResponseSystem::ParseRule( void ) +{ + static int instancedCriteria = 0; + + char ruleName[ 128 ]; + ParseToken(); + Q_strncpy( ruleName, token, sizeof( ruleName ) ); + + ParseToken(); + if ( Q_stricmp( token, "{" ) ) + { + ResponseWarning( "Expecting '{' in rule '%s', got '%s'\n", ruleName, token ); + return; + } + + // entries are "criteria", "response" or an in-line criteria to instance + Rule *newRule = new Rule; + + char sz[ 128 ]; + + m_bParseRuleValid = true; + m_pParseRuleName = ruleName; + while ( 1 ) + { + ParseToken(); + if ( !Q_stricmp( token, "}" ) ) + { + break; + } + + if ( Q_strlen( token ) <= 0 ) + { + ResponseWarning( "Expecting more tokens in rule '%s'\n", ruleName ); + break; + } + + unsigned int hash = RR_HASH( token ); + if ( DispatchParseRule( token, hash, m_RuleDispatch, *newRule ) ) + continue; + + // It's an inline criteria, generate a name and parse it in + Q_snprintf( sz, sizeof( sz ), "[%s%03i]", ruleName, ++instancedCriteria ); + Unget(); + int idx = ParseOneCriterion( sz ); + if ( idx != m_Criteria.InvalidIndex() ) + { + newRule->m_Criteria.AddToTail( idx ); + } + } + + if ( m_bParseRuleValid ) + { + m_RulePartitions.GetDictForRule( this, newRule ).Insert( ruleName, newRule ); + } + else + { + DevMsg( "Discarded rule %s\n", ruleName ); + delete newRule; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int CResponseSystem::GetCurrentToken() const +{ + if ( m_ScriptStack.Count() <= 0 ) + return -1; + + return m_ScriptStack[ 0 ].tokencount; +} + + +void CResponseSystem::ResponseWarning( const char *fmt, ... ) +{ + va_list argptr; + char string[1024]; + + va_start (argptr, fmt); + Q_vsnprintf(string, sizeof(string), fmt,argptr); + va_end (argptr); + + char cur[ 256 ]; + GetCurrentScript( cur, sizeof( cur ) ); + DevMsg( 1, "%s(token %i) : %s", cur, GetCurrentToken(), string ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CResponseSystem::CopyCriteriaFrom( Rule *pSrcRule, Rule *pDstRule, CResponseSystem *pCustomSystem ) +{ + // Add criteria from this rule to global list in custom response system. + int nCriteriaCount = pSrcRule->m_Criteria.Count(); + for ( int iCriteria = 0; iCriteria < nCriteriaCount; ++iCriteria ) + { + int iSrcIndex = pSrcRule->m_Criteria[iCriteria]; + Criteria *pSrcCriteria = &m_Criteria[iSrcIndex]; + if ( pSrcCriteria ) + { + int iIndex = pCustomSystem->m_Criteria.Find( m_Criteria.GetElementName( iSrcIndex ) ); + if ( iIndex != pCustomSystem->m_Criteria.InvalidIndex() ) + { + pDstRule->m_Criteria.AddToTail( iIndex ); + continue; + } + + // Add the criteria. + Criteria dstCriteria; + + dstCriteria.nameSym = pSrcCriteria->nameSym ; + dstCriteria.value = ResponseCopyString( pSrcCriteria->value ); + dstCriteria.weight = pSrcCriteria->weight; + dstCriteria.required = pSrcCriteria->required; + dstCriteria.matcher = pSrcCriteria->matcher; + + int nSubCriteriaCount = pSrcCriteria->subcriteria.Count(); + for ( int iSubCriteria = 0; iSubCriteria < nSubCriteriaCount; ++iSubCriteria ) + { + int iSrcSubIndex = pSrcCriteria->subcriteria[iSubCriteria]; + Criteria *pSrcSubCriteria = &m_Criteria[iSrcSubIndex]; + if ( pSrcCriteria ) + { + int iSubIndex = pCustomSystem->m_Criteria.Find( pSrcSubCriteria->value ); + if ( iSubIndex != pCustomSystem->m_Criteria.InvalidIndex() ) + continue; + + // Add the criteria. + Criteria dstSubCriteria; + + dstSubCriteria.nameSym = pSrcSubCriteria->nameSym ; + dstSubCriteria.value = ResponseCopyString( pSrcSubCriteria->value ); + dstSubCriteria.weight = pSrcSubCriteria->weight; + dstSubCriteria.required = pSrcSubCriteria->required; + dstSubCriteria.matcher = pSrcSubCriteria->matcher; + + int iSubInsertIndex = pCustomSystem->m_Criteria.Insert( pSrcSubCriteria->value, dstSubCriteria ); + dstCriteria.subcriteria.AddToTail( iSubInsertIndex ); + } + } + + int iInsertIndex = pCustomSystem->m_Criteria.Insert( m_Criteria.GetElementName( iSrcIndex ), dstCriteria ); + pDstRule->m_Criteria.AddToTail( iInsertIndex ); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CResponseSystem::CopyResponsesFrom( Rule *pSrcRule, Rule *pDstRule, CResponseSystem *pCustomSystem ) +{ + // Add responses from this rule to global list in custom response system. + int nResponseGroupCount = pSrcRule->m_Responses.Count(); + for ( int iResponseGroup = 0; iResponseGroup < nResponseGroupCount; ++iResponseGroup ) + { + int iSrcResponseGroup = pSrcRule->m_Responses[iResponseGroup]; + ResponseGroup *pSrcResponseGroup = &m_Responses[iSrcResponseGroup]; + if ( pSrcResponseGroup ) + { + // Add response group. + ResponseGroup dstResponseGroup; + + dstResponseGroup.m_bDepleteBeforeRepeat = pSrcResponseGroup->m_bDepleteBeforeRepeat; + dstResponseGroup.m_nDepletionCount = pSrcResponseGroup->m_nDepletionCount; + dstResponseGroup.m_bHasFirst = pSrcResponseGroup->m_bHasFirst; + dstResponseGroup.m_bHasLast = pSrcResponseGroup->m_bHasLast; + dstResponseGroup.m_bSequential = pSrcResponseGroup->m_bSequential; + dstResponseGroup.m_bNoRepeat = pSrcResponseGroup->m_bNoRepeat; + dstResponseGroup.m_bEnabled = pSrcResponseGroup->m_bEnabled; + dstResponseGroup.m_nCurrentIndex = pSrcResponseGroup->m_nCurrentIndex; + + int nSrcResponseCount = pSrcResponseGroup->group.Count(); + for ( int iResponse = 0; iResponse < nSrcResponseCount; ++iResponse ) + { + ParserResponse *pSrcResponse = &pSrcResponseGroup->group[iResponse]; + if ( pSrcResponse ) + { + // Add Response + ParserResponse dstResponse; + + dstResponse.weight = pSrcResponse->weight; + dstResponse.type = pSrcResponse->type; + dstResponse.value = ResponseCopyString( pSrcResponse->value ); + dstResponse.depletioncount = pSrcResponse->depletioncount; + dstResponse.first = pSrcResponse->first; + dstResponse.last = pSrcResponse->last; + + dstResponseGroup.group.AddToTail( dstResponse ); + } + } + + int iInsertIndex = pCustomSystem->m_Responses.Insert( m_Responses.GetElementName( iSrcResponseGroup ), dstResponseGroup ); + pDstRule->m_Responses.AddToTail( iInsertIndex ); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CResponseSystem::CopyEnumerationsFrom( CResponseSystem *pCustomSystem ) +{ + int nEnumerationCount = m_Enumerations.Count(); + for ( int iEnumeration = 0; iEnumeration < nEnumerationCount; ++iEnumeration ) + { + Enumeration *pSrcEnumeration = &m_Enumerations[iEnumeration]; + if ( pSrcEnumeration ) + { + Enumeration dstEnumeration; + dstEnumeration.value = pSrcEnumeration->value; + pCustomSystem->m_Enumerations.Insert( m_Enumerations.GetElementName( iEnumeration ), dstEnumeration ); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CResponseSystem::CopyRuleFrom( Rule *pSrcRule, ResponseRulePartition::tIndex iRule, CResponseSystem *pCustomSystem ) +{ + // Verify data. + Assert( pSrcRule ); + Assert( pCustomSystem ); + if ( !pSrcRule || !pCustomSystem ) + return; + + // New rule + Rule *dstRule = new Rule; + + dstRule->SetContext( pSrcRule->GetContext() ); + dstRule->m_bMatchOnce = pSrcRule->m_bMatchOnce; + dstRule->m_bEnabled = pSrcRule->m_bEnabled; +#ifdef MAPBASE + dstRule->m_iContextFlags = pSrcRule->m_iContextFlags; +#else + dstRule->m_bApplyContextToWorld = pSrcRule->m_bApplyContextToWorld; +#endif + + // Copy off criteria. + CopyCriteriaFrom( pSrcRule, dstRule, pCustomSystem ); + + // Copy off responses. + CopyResponsesFrom( pSrcRule, dstRule, pCustomSystem ); + + // Copy off enumerations - Don't think we use these. + // CopyEnumerationsFrom( pCustomSystem ); + + // Add rule. + pCustomSystem->m_RulePartitions.GetDictForRule( this, dstRule ).Insert( m_RulePartitions.GetElementName( iRule ), dstRule ); +} + + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CResponseSystem::DumpRules() +{ + for ( ResponseRulePartition::tIndex idx = m_RulePartitions.First() ; + m_RulePartitions.IsValid(idx) ; + idx = m_RulePartitions.Next(idx) ) + { + Msg("%s\n", m_RulePartitions.GetElementName( idx ) ); + } +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CResponseSystem::DumpDictionary( const char *pszName ) +{ + Msg( "\nDictionary: %s\n", pszName ); + + // int nRuleCount = m_Rules.Count(); + // for ( int iRule = 0; iRule < nRuleCount; ++iRule ) + for ( ResponseRulePartition::tIndex idx = m_RulePartitions.First() ; + m_RulePartitions.IsValid(idx) ; + idx = m_RulePartitions.Next(idx) ) + { + Msg(" Rule %d/%d: %s\n", m_RulePartitions.BucketFromIdx(idx), m_RulePartitions.PartFromIdx( idx ), m_RulePartitions.GetElementName( idx ) ); + + Rule *pRule = &m_RulePartitions[idx]; + + int nCriteriaCount = pRule->m_Criteria.Count(); + for( int iCriteria = 0; iCriteria < nCriteriaCount; ++iCriteria ) + { + int iRuleCriteria = pRule->m_Criteria[iCriteria]; + Criteria *pCriteria = &m_Criteria[iRuleCriteria]; + Msg( " Criteria %d: %s %s\n", iCriteria, CriteriaSet::SymbolToStr(pCriteria->nameSym), pCriteria->value ); + } + + int nResponseGroupCount = pRule->m_Responses.Count(); + for ( int iResponseGroup = 0; iResponseGroup < nResponseGroupCount; ++iResponseGroup ) + { + int iRuleResponse = pRule->m_Responses[iResponseGroup]; + ResponseGroup *pResponseGroup = &m_Responses[iRuleResponse]; + + Msg( " ResponseGroup %d: %s\n", iResponseGroup, m_Responses.GetElementName( iRuleResponse ) ); + + int nResponseCount = pResponseGroup->group.Count(); + for ( int iResponse = 0; iResponse < nResponseCount; ++iResponse ) + { + ParserResponse *pResponse = &pResponseGroup->group[iResponse]; + Msg( " Response %d: %s\n", iResponse, pResponse->value ); + } + } + } +} + +void CResponseSystem::BuildDispatchTables() +{ + m_RootCommandHashes.Insert( RR_HASH( "#include" ) ); + m_RootCommandHashes.Insert( RR_HASH( "response" ) ); + m_RootCommandHashes.Insert( RR_HASH( "enumeration" ) ); + m_RootCommandHashes.Insert( RR_HASH( "criterion" ) ); + m_RootCommandHashes.Insert( RR_HASH( "criteria" ) ); + m_RootCommandHashes.Insert( RR_HASH( "rule" ) ); + + m_FileDispatch.Insert( RR_HASH( "#include" ), &CResponseSystem::ParseInclude ); + m_FileDispatch.Insert( RR_HASH( "response" ), &CResponseSystem::ParseResponse ); + m_FileDispatch.Insert( RR_HASH( "criterion" ), &CResponseSystem::ParseCriterion ); + m_FileDispatch.Insert( RR_HASH( "criteria" ), &CResponseSystem::ParseCriterion ); + m_FileDispatch.Insert( RR_HASH( "rule" ), &CResponseSystem::ParseRule ); + m_FileDispatch.Insert( RR_HASH( "enumeration" ), &CResponseSystem::ParseEnumeration ); + + m_RuleDispatch.Insert( RR_HASH( "matchonce" ), &CResponseSystem::ParseRule_MatchOnce ); + m_RuleDispatch.Insert( RR_HASH( "applycontexttoworld" ), &CResponseSystem::ParseRule_ApplyContextToWorld ); +#ifdef MAPBASE + m_RuleDispatch.Insert( RR_HASH( "applycontexttosquad" ), &CResponseSystem::ParseRule_ApplyContextToSquad ); + m_RuleDispatch.Insert( RR_HASH( "applycontexttoenemy" ), &CResponseSystem::ParseRule_ApplyContextToEnemy ); +#endif + m_RuleDispatch.Insert( RR_HASH( "applycontext" ), &CResponseSystem::ParseRule_ApplyContext ); + m_RuleDispatch.Insert( RR_HASH( "response" ), &CResponseSystem::ParseRule_Response ); +// m_RuleDispatch.Insert( RR_HASH( "forceweight" ), &CResponseSystem::ParseRule_ForceWeight ); + m_RuleDispatch.Insert( RR_HASH( "criteria" ), &CResponseSystem::ParseRule_Criteria ); + m_RuleDispatch.Insert( RR_HASH( "criterion" ), &CResponseSystem::ParseRule_Criteria ); + + + m_ResponseDispatch.Insert( RR_HASH( "weight" ), &CResponseSystem::ParseResponse_Weight ); + m_ResponseDispatch.Insert( RR_HASH( "predelay" ), &CResponseSystem::ParseResponse_PreDelay ); + m_ResponseDispatch.Insert( RR_HASH( "nodelay" ), &CResponseSystem::ParseResponse_NoDelay ); + m_ResponseDispatch.Insert( RR_HASH( "defaultdelay" ), &CResponseSystem::ParseResponse_DefaultDelay ); + m_ResponseDispatch.Insert( RR_HASH( "delay" ), &CResponseSystem::ParseResponse_Delay ); + m_ResponseDispatch.Insert( RR_HASH( "speakonce" ), &CResponseSystem::ParseResponse_SpeakOnce ); + m_ResponseDispatch.Insert( RR_HASH( "noscene" ), &CResponseSystem::ParseResponse_NoScene ); + m_ResponseDispatch.Insert( RR_HASH( "stop_on_nonidle" ), &CResponseSystem::ParseResponse_StopOnNonIdle ); + m_ResponseDispatch.Insert( RR_HASH( "odds" ), &CResponseSystem::ParseResponse_Odds ); + m_ResponseDispatch.Insert( RR_HASH( "respeakdelay" ), &CResponseSystem::ParseResponse_RespeakDelay ); + m_ResponseDispatch.Insert( RR_HASH( "weapondelay" ), &CResponseSystem::ParseResponse_WeaponDelay ); + m_ResponseDispatch.Insert( RR_HASH( "soundlevel" ), &CResponseSystem::ParseResponse_Soundlevel ); + m_ResponseDispatch.Insert( RR_HASH( "displayfirst" ), &CResponseSystem::ParseResponse_DisplayFirst ); + m_ResponseDispatch.Insert( RR_HASH( "displaylast" ), &CResponseSystem::ParseResponse_DisplayLast ); + m_ResponseDispatch.Insert( RR_HASH( "fire" ), &CResponseSystem::ParseResponse_Fire ); + m_ResponseDispatch.Insert( RR_HASH( "then" ), &CResponseSystem::ParseResponse_Then ); + + m_ResponseGroupDispatch.Insert( RR_HASH( "{" ), &CResponseSystem::ParseResponseGroup_Start ); + m_ResponseGroupDispatch.Insert( RR_HASH( "predelay" ), &CResponseSystem::ParseResponseGroup_PreDelay ); + m_ResponseGroupDispatch.Insert( RR_HASH( "nodelay" ), &CResponseSystem::ParseResponseGroup_NoDelay ); + m_ResponseGroupDispatch.Insert( RR_HASH( "defaultdelay" ), &CResponseSystem::ParseResponseGroup_DefaultDelay ); + m_ResponseGroupDispatch.Insert( RR_HASH( "delay" ), &CResponseSystem::ParseResponseGroup_Delay ); + m_ResponseGroupDispatch.Insert( RR_HASH( "speakonce" ), &CResponseSystem::ParseResponseGroup_SpeakOnce ); + m_ResponseGroupDispatch.Insert( RR_HASH( "noscene" ), &CResponseSystem::ParseResponseGroup_NoScene ); + m_ResponseGroupDispatch.Insert( RR_HASH( "stop_on_nonidle" ), &CResponseSystem::ParseResponseGroup_StopOnNonIdle ); + m_ResponseGroupDispatch.Insert( RR_HASH( "odds" ), &CResponseSystem::ParseResponseGroup_Odds ); + m_ResponseGroupDispatch.Insert( RR_HASH( "respeakdelay" ), &CResponseSystem::ParseResponseGroup_RespeakDelay ); + m_ResponseGroupDispatch.Insert( RR_HASH( "weapondelay" ), &CResponseSystem::ParseResponseGroup_WeaponDelay ); + m_ResponseGroupDispatch.Insert( RR_HASH( "soundlevel" ), &CResponseSystem::ParseResponseGroup_Soundlevel ); +} + +bool CResponseSystem::Dispatch( char const *pToken, unsigned int uiHash, CResponseSystem::DispatchMap_t &rMap ) +{ + int slot = rMap.Find( uiHash ); + if ( slot != rMap.InvalidIndex() ) + { + CResponseSystem::pfnResponseDispatch dispatch = rMap[ slot ]; + (this->*dispatch)(); + return true; + } + + return false; +} + +bool CResponseSystem::DispatchParseRule( char const *pToken, unsigned int uiHash, ParseRuleDispatchMap_t &rMap, Rule &newRule ) +{ + int slot = rMap.Find( uiHash ); + if ( slot != rMap.InvalidIndex() ) + { + CResponseSystem::pfnParseRuleDispatch dispatch = rMap[ slot ]; + (this->*dispatch)( newRule ); + return true; + } + + return false; +} + +bool CResponseSystem::DispatchParseResponse( char const *pToken, unsigned int uiHash, ParseResponseDispatchMap_t &rMap, ParserResponse &newResponse, ResponseGroup& group, AI_ResponseParams *rp ) +{ + int slot = rMap.Find( uiHash ); + if ( slot != rMap.InvalidIndex() ) + { + CResponseSystem::pfnParseResponseDispatch dispatch = rMap[ slot ]; + (this->*dispatch)( newResponse, group, rp ); + return true; + } + + return false; +} + +bool CResponseSystem::DispatchParseResponseGroup( char const *pToken, unsigned int uiHash, ParseResponseGroupDispatchMap_t &rMap, char const *responseGroupName, ResponseGroup& newGroup, AI_ResponseParams &groupResponseParams ) +{ + int slot = rMap.Find( uiHash ); + if ( slot != rMap.InvalidIndex() ) + { + CResponseSystem::pfnParseResponseGroupDispatch dispatch = rMap[ slot ]; + (this->*dispatch)( responseGroupName, newGroup, groupResponseParams ); + return true; + } + + return false; +} + +unsigned int ResponseRulePartition::GetBucketForSpeakerAndConcept( const char *pszSpeaker, const char *pszConcept, const char *pszSubject ) +{ + // make sure is a power of two + COMPILE_TIME_ASSERT( ( N_RESPONSE_PARTITIONS & ( N_RESPONSE_PARTITIONS - 1 ) ) == 0 ); + + // hash together the speaker and concept strings, and mask off by the bucket mask + unsigned hashSpeaker = 0; // pszSpeaker ? HashStringCaseless( pszSpeaker ) : 0; + unsigned hashConcept = pszConcept ? HashStringCaseless( pszConcept ) : 0; + unsigned hashSubject = pszSubject ? HashStringCaseless( pszSubject ) : 0; + unsigned hashBrowns = ( ( hashSubject >> 3 ) ^ (hashSpeaker >> 1) ^ hashConcept ) & ( N_RESPONSE_PARTITIONS - 1 ); + return hashBrowns; +} + +const char *Rule::GetValueForRuleCriterionByName( CResponseSystem * RESTRICT pSystem, const CUtlSymbol &pCritNameSym ) +{ + const char * retval = NULL; + // for each rule criterion... + for ( int i = 0 ; i < m_Criteria.Count() ; ++i ) + { + retval = RecursiveGetValueForRuleCriterionByName( pSystem, &pSystem->m_Criteria[m_Criteria[i]], pCritNameSym ); + if ( retval != NULL ) + { + // we found a result, early out + break; + } + } + + return retval; +} + +const Criteria *Rule::GetPointerForRuleCriterionByName( CResponseSystem *pSystem, const CUtlSymbol &pCritNameSym ) +{ + const Criteria * retval = NULL; + // for each rule criterion... + for ( int i = 0 ; i < m_Criteria.Count() ; ++i ) + { + retval = RecursiveGetPointerForRuleCriterionByName( pSystem, &pSystem->m_Criteria[m_Criteria[i]], pCritNameSym ); + if ( retval != NULL ) + { + // we found a result, early out + break; + } + } + + return retval; +} + +const char *Rule::RecursiveGetValueForRuleCriterionByName( CResponseSystem * RESTRICT pSystem, + const Criteria * RESTRICT pCrit, const CUtlSymbol &pCritNameSym ) +{ + Assert( pCrit ); + if ( !pCrit ) return NULL; + if ( pCrit->IsSubCriteriaType() ) + { + // test each of the children (depth first) + const char *pRet = NULL; + for ( int i = 0 ; i < pCrit->subcriteria.Count() ; ++i ) + { + pRet = RecursiveGetValueForRuleCriterionByName( pSystem, &pSystem->m_Criteria[pCrit->subcriteria[i]], pCritNameSym ); + if ( pRet ) // if found something, early out + return pRet; + } + } + else // leaf criterion + { + if ( pCrit->nameSym == pCritNameSym ) + { + return pCrit->value; + } + else + { + return NULL; + } + } + + return NULL; +} + + +const Criteria *Rule::RecursiveGetPointerForRuleCriterionByName( CResponseSystem *pSystem, const Criteria *pCrit, const CUtlSymbol &pCritNameSym ) +{ + Assert( pCrit ); + if ( !pCrit ) return NULL; + if ( pCrit->IsSubCriteriaType() ) + { + // test each of the children (depth first) + const Criteria *pRet = NULL; + for ( int i = 0 ; i < pCrit->subcriteria.Count() ; ++i ) + { + pRet = RecursiveGetPointerForRuleCriterionByName( pSystem, &pSystem->m_Criteria[pCrit->subcriteria[i]], pCritNameSym ); + if ( pRet ) // if found something, early out + return pRet; + } + } + else // leaf criterion + { + if ( pCrit->nameSym == pCritNameSym ) + { + return pCrit; + } + else + { + return NULL; + } + } + + return NULL; +} + + +static void CC_RR_Debug_ResponseConcept_Exclude( const CCommand &args ) +{ + // shouldn't use this extern elsewhere -- it's meant to be a hidden + // implementation detail + extern CRR_ConceptSymbolTable *g_pRRConceptTable; + Assert( g_pRRConceptTable ); + if ( !g_pRRConceptTable ) return; + + + // different things for different argument lengths + switch ( args.ArgC() ) + { + case 0: + { + AssertMsg( args.ArgC() > 0, "WTF error in ccommand parsing: zero arguments!\n" ); + return; + } + case 1: + { + // print usage info + Msg("Usage: rr_debugresponseconcept_exclude Concept1 Concept2 Concept3...\n"); + Msg("\tseparate multiple concepts with spaces.\n"); + Msg("\tcall with no arguments to see this message and a list of current excludes.\n"); + Msg("\tto reset the exclude list, type \"rr_debugresponseconcept_exclude !\"\n"); + + // print current excludes + Msg("\nCurrent exclude list:\n"); + if ( !CResponseSystem::m_DebugExcludeList.IsValidIndex( CResponseSystem::m_DebugExcludeList.Head() ) ) + { + Msg("\t\n"); + } + else + { + CResponseSystem::ExcludeList_t::IndexLocalType_t i; + for ( i = CResponseSystem::m_DebugExcludeList.Head() ; + CResponseSystem::m_DebugExcludeList.IsValidIndex(i) ; + i = CResponseSystem::m_DebugExcludeList.Next(i) ) + { + Msg( "\t%s\n", CResponseSystem::m_DebugExcludeList[i].GetStringConcept() ); + } + } + return; + } + case 2: + // deal with the erase operator + if ( args[1][0] == '!' ) + { + CResponseSystem::m_DebugExcludeList.Purge(); + Msg( "Exclude list emptied.\n" ); + return; + } + // else, FALL THROUGH: + default: + // add each arg to the exclude list + for ( int i = 1 ; i < args.ArgC() ; ++i ) + { + if ( !g_pRRConceptTable->Find(args[i]).IsValid() ) + { + Msg( "\t'%s' is not a known concept (adding it anyway)\n", args[i] ); + } + CRR_Concept concept( args[i] ); + CResponseSystem::m_DebugExcludeList.AddToTail( concept ); + } + } +} +#if RR_DUMPHASHINFO_ENABLED +static void CC_RR_DumpHashInfo( const CCommand &args ) +{ + defaultresponsesytem.m_InstancedSystems[0]->m_RulePartitions.PrintBucketInfo( defaultresponsesytem.m_InstancedSystems[0] ); +} +static ConCommand rr_dumphashinfo( "rr_dumphashinfo", CC_RR_DumpHashInfo, "Statistics on primary hash bucketing of response rule partitions"); + +void ResponseRulePartition::PrintBucketInfo( CResponseSystem *pSys ) +{ + struct bucktuple_t + { + int nBucket; + int nCount; + bucktuple_t() : nBucket(-1), nCount(-1) {}; + bucktuple_t( int bucket, int count ) : nBucket(bucket), nCount(count) {}; + + static int __cdecl SortCompare( const bucktuple_t * a, const bucktuple_t * b ) + { + return a->nCount - b->nCount; + } + }; + + CUtlVector infos( N_RESPONSE_PARTITIONS, N_RESPONSE_PARTITIONS ); + + float nAverage = 0; + for ( int i = 0 ; i < N_RESPONSE_PARTITIONS ; ++i ) + { + int count = m_RuleParts[i].Count(); + infos.AddToTail( bucktuple_t( i, count ) ); + nAverage += count; + } + nAverage /= N_RESPONSE_PARTITIONS; + infos.Sort( bucktuple_t::SortCompare ); + Msg( "%d buckets, %d total, %.2f average size\n", N_RESPONSE_PARTITIONS, Count(), nAverage ); + Msg( "8 shortest buckets:\n" ); + for ( int i = 0 ; i < 8 ; ++i ) + { + Msg("\t%d: %d\n", infos[i].nBucket, infos[i].nCount ); + } + Msg( "8 longest buckets:\n" ); + for ( int i = infos.Count() - 1 ; i >= infos.Count() - 9 ; --i ) + { + Msg("\t%d: %d\n", infos[i].nBucket, infos[i].nCount ); + } + int nempty = 0; + for ( nempty = 0 ; nempty < infos.Count() ; ++nempty ) + { + if ( infos[nempty].nCount != 0 ) + break; + } + Msg( "%d empty buckets\n", nempty ); + + /* + Msg( " Contents of longest bucket\nwho\tconcept\n" ); + tRuleDict &bucket = m_RuleParts[infos[infos.Count()-1].nBucket]; + for ( tRuleDict::IndexType_t i = bucket.FirstInorder(); bucket.IsValidIndex(i); i = bucket.NextInorder(i) ) + { + Rule &rule = bucket.Element(i) ; + Msg("%s\t%s\n", rule.GetValueForRuleCriterionByName( pSys, "who" ), rule.GetValueForRuleCriterionByName( pSys, CriteriaSet::ComputeCriteriaSymbol("concept") ) ); + } + */ +} +#endif \ No newline at end of file diff --git a/sp/src/responserules/runtime/response_system.h b/sp/src/responserules/runtime/response_system.h new file mode 100644 index 00000000..5fec10de --- /dev/null +++ b/sp/src/responserules/runtime/response_system.h @@ -0,0 +1,316 @@ +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: The CResponseSystem class. Don't include this header; include the response_types +// into which it is transcluded. +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef RESPONSE_SYSTEM_H +#define RESPONSE_SYSTEM_H +#ifdef _WIN32 +#pragma once +#endif + +#include "utldict.h" + +namespace ResponseRules +{ + typedef ResponseParams AI_ResponseParams ; + #define AI_CriteriaSet ResponseRules::CriteriaSet + + //----------------------------------------------------------------------------- + // Purpose: The database of all available responses. + // The Rules are partitioned based on a variety of factors (presently, + // speaker and concept) for faster lookup, basically a seperate-chained hash. + //----------------------------------------------------------------------------- + class CResponseSystem : public IResponseSystem + { + public: + CResponseSystem(); + ~CResponseSystem(); + + typedef void (CResponseSystem::*pfnResponseDispatch)( void ); + typedef void (CResponseSystem::*pfnParseRuleDispatch)( Rule & ); + typedef void (CResponseSystem::*pfnParseResponseDispatch)( ParserResponse &, ResponseGroup&, AI_ResponseParams * ); + typedef void (CResponseSystem::*pfnParseResponseGroupDispatch) ( char const *responseGroupName, ResponseGroup &newGroup, AI_ResponseParams &groupResponseParams ); + + typedef CUtlMap< unsigned,pfnResponseDispatch > DispatchMap_t; + typedef CUtlMap< unsigned,pfnParseRuleDispatch > ParseRuleDispatchMap_t; + typedef CUtlMap< unsigned,pfnParseResponseDispatch > ParseResponseDispatchMap_t; + typedef CUtlMap< unsigned,pfnParseResponseGroupDispatch > ParseResponseGroupDispatchMap_t; + +#pragma region IResponseSystem + // IResponseSystem + virtual bool FindBestResponse( const CriteriaSet& set, CRR_Response& response, IResponseFilter *pFilter = NULL ); + virtual void GetAllResponses( CUtlVector *pResponses ); +#pragma endregion Implement interface from IResponseSystem + + virtual void Release() = 0; + + virtual void DumpRules(); + + bool IsCustomManagable() { return m_bCustomManagable; } + + void Clear(); + + void DumpDictionary( const char *pszName ); + + protected: + + void BuildDispatchTables(); + bool Dispatch( char const *pToken, unsigned int uiHash, DispatchMap_t &rMap ); + bool DispatchParseRule( char const *pToken, unsigned int uiHash, ParseRuleDispatchMap_t &rMap, Rule &newRule ); + bool DispatchParseResponse( char const *pToken, unsigned int uiHash, ParseResponseDispatchMap_t &rMap, ParserResponse &newResponse, ResponseGroup& group, AI_ResponseParams *rp ); + bool DispatchParseResponseGroup( char const *pToken, unsigned int uiHash, ParseResponseGroupDispatchMap_t &rMap, char const *responseGroupName, ResponseGroup& newGroup, AI_ResponseParams &groupResponseParams ); + + virtual const char *GetScriptFile( void ) = 0; + void LoadRuleSet( const char *setname ); + + void ResetResponseGroups(); + + float LookForCriteria( const CriteriaSet &criteriaSet, int iCriteria ); + float RecursiveLookForCriteria( const CriteriaSet &criteriaSet, Criteria *pParent ); + + public: + + void CopyRuleFrom( Rule *pSrcRule, ResponseRulePartition::tIndex iRule, CResponseSystem *pCustomSystem ); + void CopyCriteriaFrom( Rule *pSrcRule, Rule *pDstRule, CResponseSystem *pCustomSystem ); + void CopyResponsesFrom( Rule *pSrcRule, Rule *pDstRule, CResponseSystem *pCustomSystem ); + void CopyEnumerationsFrom( CResponseSystem *pCustomSystem ); + + //private: + + struct Enumeration + { + float value; + }; + + struct ResponseSearchResult + { + ResponseSearchResult() + { + group = NULL; + action = NULL; + } + + ResponseGroup *group; + ParserResponse *action; + }; + + inline bool ParseToken( void ) + { + if ( m_bUnget ) + { + m_bUnget = false; + return true; + } + if ( m_ScriptStack.Count() <= 0 ) + { + Assert( 0 ); + return false; + } + + m_ScriptStack[ 0 ].currenttoken = IEngineEmulator::Get()->ParseFile( m_ScriptStack[ 0 ].currenttoken, token, sizeof( token ) ); + m_ScriptStack[ 0 ].tokencount++; + return m_ScriptStack[ 0 ].currenttoken != NULL ? true : false; + } + +#ifdef MAPBASE + inline bool ParseTokenIntact( void ) + { + if ( m_bUnget ) + { + m_bUnget = false; + return true; + } + if ( m_ScriptStack.Count() <= 0 ) + { + Assert( 0 ); + return false; + } + + m_ScriptStack[ 0 ].currenttoken = IEngineEmulator::Get()->ParseFilePreserve( m_ScriptStack[ 0 ].currenttoken, token, sizeof( token ) ); + m_ScriptStack[ 0 ].tokencount++; + return m_ScriptStack[ 0 ].currenttoken != NULL ? true : false; + } +#endif + + inline void Unget() + { + m_bUnget = true; + } + + inline bool TokenWaiting( void ) + { + if ( m_ScriptStack.Count() <= 0 ) + { + Assert( 0 ); + return false; + } + + const char *p = m_ScriptStack[ 0 ].currenttoken; + + if ( !p ) + { + Error( "AI_ResponseSystem: Unxpected TokenWaiting() with NULL buffer in %s", (char * ) m_ScriptStack[ 0 ].name ); + return false; + } + + + while ( *p && *p!='\n') + { + // Special handler for // comment blocks + if ( *p == '/' && *(p+1) == '/' ) + return false; + + if ( !V_isspace( *p ) || isalnum( *p ) ) + return true; + + p++; + } + + return false; + } + + void ParseOneResponse( const char *responseGroupName, ResponseGroup& group, ResponseParams *defaultParams = NULL ); + + void ParseInclude( void ); + void ParseResponse( void ); + void ParseCriterion( void ); + void ParseRule( void ); + void ParseEnumeration( void ); + + private: + void ParseRule_MatchOnce( Rule &newRule ); + void ParseRule_ApplyContextToWorld( Rule &newRule ); +#ifdef MAPBASE + void ParseRule_ApplyContextToSquad( Rule &newRule ); + void ParseRule_ApplyContextToEnemy( Rule &newRule ); +#endif + void ParseRule_ApplyContext( Rule &newRule ); + void ParseRule_Response( Rule &newRule ); + //void ParseRule_ForceWeight( Rule &newRule ); + void ParseRule_Criteria( Rule &newRule ); + char const *m_pParseRuleName; + bool m_bParseRuleValid; + + void ParseResponse_Weight( ParserResponse &newResponse, ResponseGroup& group, AI_ResponseParams *rp ); + void ParseResponse_PreDelay( ParserResponse &newResponse, ResponseGroup& group, AI_ResponseParams *rp ); + void ParseResponse_NoDelay( ParserResponse &newResponse, ResponseGroup& group, AI_ResponseParams *rp ); + void ParseResponse_DefaultDelay( ParserResponse &newResponse, ResponseGroup& group, AI_ResponseParams *rp ); + void ParseResponse_Delay( ParserResponse &newResponse, ResponseGroup& group, AI_ResponseParams *rp ); + void ParseResponse_SpeakOnce( ParserResponse &newResponse, ResponseGroup& group, AI_ResponseParams *rp ); + void ParseResponse_NoScene( ParserResponse &newResponse, ResponseGroup& group, AI_ResponseParams *rp ); + void ParseResponse_StopOnNonIdle( ParserResponse &newResponse, ResponseGroup& group, AI_ResponseParams *rp ); + void ParseResponse_Odds( ParserResponse &newResponse, ResponseGroup& group, AI_ResponseParams *rp ); + void ParseResponse_RespeakDelay( ParserResponse &newResponse, ResponseGroup& group, AI_ResponseParams *rp ); + void ParseResponse_WeaponDelay( ParserResponse &newResponse, ResponseGroup& group, AI_ResponseParams *rp ); + void ParseResponse_Soundlevel( ParserResponse &newResponse, ResponseGroup& group, AI_ResponseParams *rp ); + void ParseResponse_DisplayFirst( ParserResponse &newResponse, ResponseGroup& group, AI_ResponseParams *rp ); + void ParseResponse_DisplayLast( ParserResponse &newResponse, ResponseGroup& group, AI_ResponseParams *rp ); + void ParseResponse_Fire( ParserResponse &newResponse, ResponseGroup& group, AI_ResponseParams *rp ); + void ParseResponse_Then( ParserResponse &newResponse, ResponseGroup& group, AI_ResponseParams *rp ); + + void ParseResponseGroup_Start( char const *responseGroupName, ResponseGroup &newGroup, AI_ResponseParams &groupResponseParams ); + void ParseResponseGroup_PreDelay( char const *responseGroupName, ResponseGroup &newGroup, AI_ResponseParams &groupResponseParams ); + void ParseResponseGroup_NoDelay( char const *responseGroupName, ResponseGroup &newGroup, AI_ResponseParams &groupResponseParams ); + void ParseResponseGroup_DefaultDelay( char const *responseGroupName, ResponseGroup &newGroup, AI_ResponseParams &groupResponseParams ); + void ParseResponseGroup_Delay( char const *responseGroupName, ResponseGroup &newGroup, AI_ResponseParams &groupResponseParams ); + void ParseResponseGroup_SpeakOnce( char const *responseGroupName, ResponseGroup &newGroup, AI_ResponseParams &groupResponseParams ); + void ParseResponseGroup_NoScene( char const *responseGroupName, ResponseGroup &newGroup, AI_ResponseParams &groupResponseParams ); + void ParseResponseGroup_StopOnNonIdle( char const *responseGroupName, ResponseGroup &newGroup, AI_ResponseParams &groupResponseParams ); + void ParseResponseGroup_Odds( char const *responseGroupName, ResponseGroup &newGroup, AI_ResponseParams &groupResponseParams ); + void ParseResponseGroup_RespeakDelay( char const *responseGroupName, ResponseGroup &newGroup, AI_ResponseParams &groupResponseParams ); + void ParseResponseGroup_WeaponDelay( char const *responseGroupName, ResponseGroup &newGroup, AI_ResponseParams &groupResponseParams ); + void ParseResponseGroup_Soundlevel( char const *responseGroupName, ResponseGroup &newGroup, AI_ResponseParams &groupResponseParams ); + +public: + int ParseOneCriterion( const char *criterionName ); + + bool Compare( const char *setValue, Criteria *c, bool verbose = false ); + bool CompareUsingMatcher( const char *setValue, Matcher& m, bool verbose = false ); + void ComputeMatcher( Criteria *c, Matcher& matcher ); + void ResolveToken( Matcher& matcher, char *token, size_t bufsize, char const *rawtoken ); + float LookupEnumeration( const char *name, bool& found ); + + ResponseRulePartition::tIndex FindBestMatchingRule( const CriteriaSet& set, bool verbose, float &scoreOfBestMatchingRule ); + + float ScoreCriteriaAgainstRule( const CriteriaSet& set, ResponseRulePartition::tRuleDict &dict, int irule, bool verbose = false ); + float RecursiveScoreSubcriteriaAgainstRule( const CriteriaSet& set, Criteria *parent, bool& exclude, bool verbose /*=false*/ ); + float ScoreCriteriaAgainstRuleCriteria( const CriteriaSet& set, int icriterion, bool& exclude, bool verbose = false ); + void FakeDepletes( ResponseGroup *g, IResponseFilter *pFilter ); + void RevertFakedDepletes( ResponseGroup *g ); + bool GetBestResponse( ResponseSearchResult& result, Rule *rule, bool verbose = false, IResponseFilter *pFilter = NULL ); + bool ResolveResponse( ResponseSearchResult& result, int depth, const char *name, bool verbose = false, IResponseFilter *pFilter = NULL ); + int SelectWeightedResponseFromResponseGroup( ResponseGroup *g, IResponseFilter *pFilter ); + void DescribeResponseGroup( ResponseGroup *group, int selected, int depth ); + void DebugPrint( int depth, const char *fmt, ... ); + + void LoadFromBuffer( const char *scriptfile, const char *buffer ); + + void GetCurrentScript( char *buf, size_t buflen ); + int GetCurrentToken() const; + void SetCurrentScript( const char *script ); + + inline bool IsRootCommand( unsigned int hash ) const + { + int slot = m_RootCommandHashes.Find( hash ); + return slot != m_RootCommandHashes.InvalidIndex(); + } + + inline bool IsRootCommand() const + { + return IsRootCommand( RR_HASH( token ) ); + } + + void PushScript( const char *scriptfile, unsigned char *buffer ); + void PopScript(void); + + void ResponseWarning( const char *fmt, ... ); + + CUtlDict< ResponseGroup, short > m_Responses; + CUtlDict< Criteria, short > m_Criteria; + // CUtlDict< Rule, short > m_Rules; + ResponseRulePartition m_RulePartitions; + CUtlDict< Enumeration, short > m_Enumerations; + + CUtlVector m_FakedDepletes; + + char token[ 1204 ]; + + bool m_bUnget; + + bool m_bCustomManagable; + + struct ScriptEntry + { + unsigned char *buffer; + FileNameHandle_t name; + const char *currenttoken; + int tokencount; + }; + + CUtlVector< ScriptEntry > m_ScriptStack; + CStringPool m_IncludedFiles; + + DispatchMap_t m_FileDispatch; + ParseRuleDispatchMap_t m_RuleDispatch; + ParseResponseDispatchMap_t m_ResponseDispatch; + ParseResponseGroupDispatchMap_t m_ResponseGroupDispatch; + CUtlRBTree< unsigned int > m_RootCommandHashes; + + // for debugging purposes only: concepts to be emitted from rr_debugresponses 2 + typedef CUtlLinkedList< CRR_Concept, unsigned short, false, unsigned int > ExcludeList_t; + static ExcludeList_t m_DebugExcludeList; + + friend class CDefaultResponseSystemSaveRestoreBlockHandler; + friend class CResponseSystemSaveRestoreOps; + }; + + // Some globals inherited from AI_Speech.h: + const float AIS_DEF_MIN_DELAY = 2.8; // Minimum amount of time an NPCs will wait after someone has spoken before considering speaking again + const float AIS_DEF_MAX_DELAY = 3.2; // Maximum amount of time an NPCs will wait after someone has spoken before considering speaking again +} + +#endif // RESPONSE_SYSTEM_H \ No newline at end of file diff --git a/sp/src/responserules/runtime/response_types.cpp b/sp/src/responserules/runtime/response_types.cpp new file mode 100644 index 00000000..f18d02f3 --- /dev/null +++ b/sp/src/responserules/runtime/response_types.cpp @@ -0,0 +1,279 @@ +//========= Copyright © 1996-2010, Valve Corporation, All rights reserved. ============// +// +// Purpose: Core types for the response rules -- criteria, responses, rules, and matchers. +// +// $NoKeywords: $ +//=============================================================================// + +#include "rrbase.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +using namespace ResponseRules; + + +// bizarre function handed down from the misty days of yore +// and the original response system. a lot of stuff uses it +// and I can't be arsed to replace everything with the c stdlib +// stuff +namespace ResponseRules +{ + extern const char *ResponseCopyString( const char *in ); +}; + + +//-------------------- MATCHER ---------------------------------------------- + +Matcher::Matcher() +{ + valid = false; + isnumeric = false; + notequal = false; + usemin = false; + minequals = false; + usemax = false; + maxequals = false; +#ifdef MAPBASE + isbit = false; +#endif + maxval = 0.0f; + minval = 0.0f; + + token = UTL_INVAL_SYMBOL; + rawtoken = UTL_INVAL_SYMBOL; +} + +void Matcher::Describe( void ) +{ + if ( !valid ) + { + DevMsg( " invalid!\n" ); + return; + } + char sz[ 128 ]; + + sz[ 0] = 0; + int minmaxcount = 0; + if ( usemin ) + { + Q_snprintf( sz, sizeof( sz ), ">%s%.3f", minequals ? "=" : "", minval ); + minmaxcount++; + } + if ( usemax ) + { + char sz2[ 128 ]; + Q_snprintf( sz2, sizeof( sz2 ), "<%s%.3f", maxequals ? "=" : "", maxval ); + + if ( minmaxcount > 0 ) + { + Q_strncat( sz, " and ", sizeof( sz ), COPY_ALL_CHARACTERS ); + } + Q_strncat( sz, sz2, sizeof( sz ), COPY_ALL_CHARACTERS ); + minmaxcount++; + } + + if ( minmaxcount >= 1 ) + { + DevMsg( " matcher: %s\n", sz ); + return; + } + +#ifdef MAPBASE + if ( isbit ) + { + DevMsg( " matcher: &%s%s\n", notequal ? "~" : "", GetToken() ); + return; + } +#endif + + if ( notequal ) + { + DevMsg( " matcher: !=%s\n", GetToken() ); + return; + } + + DevMsg( " matcher: ==%s\n", GetToken() ); +} + +void Matcher::SetToken( char const *s ) +{ + token = g_RS.AddString( s ); +} + +void Matcher::SetRaw( char const *raw ) +{ + rawtoken = g_RS.AddString( raw ); +} + +char const *Matcher::GetToken() +{ + if ( token.IsValid() ) + { + return g_RS.String( token ); + } + return ""; +} + +char const *Matcher::GetRaw() +{ + if ( rawtoken.IsValid() ) + { + return g_RS.String( rawtoken ); + } + return ""; +} + +//-------------------- CRITERIA ---------------------------------------------- + +Criteria::Criteria() +{ + value = NULL; + weight.SetFloat( 1.0f ); + required = false; +} +Criteria::Criteria(const Criteria& src ) +{ + operator=( src ); +} + +Criteria::~Criteria() +{ + // do nothing because we don't own name and value anymore +} + +Criteria& Criteria::operator =(const Criteria& src ) +{ + if ( this == &src ) + return *this; + + nameSym = src.nameSym; + value = ResponseCopyString( src.value ); + weight = src.weight; + required = src.required; + + matcher = src.matcher; + + int c = src.subcriteria.Count(); + subcriteria.EnsureCapacity( c ); + for ( int i = 0; i < c; i++ ) + { + subcriteria.AddToTail( src.subcriteria[ i ] ); + } + + return *this; +} + + +//-------------------- RESPONSE ---------------------------------------------- + + + +ParserResponse::ParserResponse() : m_followup() +{ + type = RESPONSE_NONE; + value = NULL; + weight.SetFloat( 1.0f ); + depletioncount = 0; + first = false; + last = false; +} + +ParserResponse& ParserResponse::operator =( const ParserResponse& src ) +{ + if ( this == &src ) + return *this; + weight = src.weight; + type = src.type; + value = ResponseCopyString( src.value ); + depletioncount = src.depletioncount; + first = src.first; + last = src.last; + params = src.params; + + m_followup.followup_concept = ResponseCopyString(src.m_followup.followup_concept); + m_followup.followup_contexts = ResponseCopyString(src.m_followup.followup_contexts); + m_followup.followup_target = ResponseCopyString(src.m_followup.followup_target); + m_followup.followup_entityioinput = ResponseCopyString(src.m_followup.followup_entityioinput); + m_followup.followup_entityiotarget = ResponseCopyString(src.m_followup.followup_entityiotarget); + m_followup.followup_delay = src.m_followup.followup_delay; + m_followup.followup_entityiodelay = src.m_followup.followup_entityiodelay; + + return *this; +} + +ParserResponse::ParserResponse( const ParserResponse& src ) +{ + operator=( src ); +} + +ParserResponse::~ParserResponse() +{ + // nothing to do, since we don't own + // the strings anymore +} + +// ------------ RULE --------------- + +Rule::Rule() : m_nForceWeight(0) +{ + m_bMatchOnce = false; + m_bEnabled = true; + m_szContext = NULL; +#ifdef MAPBASE + m_iContextFlags = 0; +#else + m_bApplyContextToWorld = false; +#endif +} + +Rule& Rule::operator =( const Rule& src ) +{ + if ( this == &src ) + return *this; + + int i; + int c; + + c = src.m_Criteria.Count(); + m_Criteria.EnsureCapacity( c ); + for ( i = 0; i < c; i++ ) + { + m_Criteria.AddToTail( src.m_Criteria[ i ] ); + } + + c = src.m_Responses.Count(); + m_Responses.EnsureCapacity( c ); + for ( i = 0; i < c; i++ ) + { + m_Responses.AddToTail( src.m_Responses[ i ] ); + } + + SetContext( src.m_szContext ); + m_bMatchOnce = src.m_bMatchOnce; + m_bEnabled = src.m_bEnabled; +#ifdef MAPBASE + m_iContextFlags = src.m_iContextFlags; +#else + m_bApplyContextToWorld = src.m_bApplyContextToWorld; +#endif + m_nForceWeight = src.m_nForceWeight; + return *this; +} + +Rule::Rule( const Rule& src ) +{ + operator=(src); +} + +Rule::~Rule() +{ +} + +void Rule::SetContext( const char *context ) +{ + // we don't own the data we point to, so just update pointer + m_szContext = ResponseCopyString( context ); +} + + diff --git a/sp/src/responserules/runtime/response_types_internal.cpp b/sp/src/responserules/runtime/response_types_internal.cpp new file mode 100644 index 00000000..2d11bdd2 --- /dev/null +++ b/sp/src/responserules/runtime/response_types_internal.cpp @@ -0,0 +1,120 @@ +//========= Copyright © 1996-2010, Valve Corporation, All rights reserved. ============// +// +// Purpose: Core types for the response rules -- criteria, responses, rules, and matchers. +// +// $NoKeywords: $ +//=============================================================================// + +#include "rrbase.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +using namespace ResponseRules; + + + + +ResponseRulePartition::ResponseRulePartition() +{ + Assert(true); + COMPILE_TIME_ASSERT( kIDX_ELEM_MASK < (1 << 16) ); + COMPILE_TIME_ASSERT( (kIDX_ELEM_MASK & (kIDX_ELEM_MASK + 1)) == 0 ); /// assert is power of two minus one +} + +ResponseRulePartition::~ResponseRulePartition() +{ + RemoveAll(); +} + +ResponseRulePartition::tIndex ResponseRulePartition::IndexFromDictElem( tRuleDict* pDict, int elem ) +{ + Assert( pDict ); + // If this fails, you've tried to build an index for a rule that's not stored + // in this partition + Assert( pDict >= m_RuleParts && pDict < m_RuleParts + N_RESPONSE_PARTITIONS ); + AssertMsg1( elem <= kIDX_ELEM_MASK, "A rule dictionary has %d elements; this exceeds the 255 that can be packed into an index.\n", elem ); + + int bucket = pDict - m_RuleParts; + return ( bucket << 16 ) | ( elem & kIDX_ELEM_MASK ); // this is a native op on PPC +} + + +char const *ResponseRulePartition::GetElementName( const tIndex &i ) const +{ + Assert( IsValid(i) ); + return m_RuleParts[ BucketFromIdx(i) ].GetElementName( PartFromIdx(i) ); +} + + +int ResponseRulePartition::Count( void ) +{ + int count = 0 ; + for ( int bukkit = 0 ; bukkit < N_RESPONSE_PARTITIONS ; ++bukkit ) + { + count += m_RuleParts[bukkit].Count(); + } + + return count; +} + +void ResponseRulePartition::RemoveAll( void ) +{ + for ( int bukkit = 0 ; bukkit < N_RESPONSE_PARTITIONS ; ++bukkit ) + { + for ( int i = m_RuleParts[bukkit].FirstInorder(); i != m_RuleParts[bukkit].InvalidIndex(); i = m_RuleParts[bukkit].NextInorder( i ) ) + { + delete m_RuleParts[bukkit][ i ]; + } + m_RuleParts[bukkit].RemoveAll(); + } +} + +// don't bucket "subject" criteria that prefix with operators, since stripping all that out again would +// be a big pain, and the most important rules that need subjects are tlk_remarks anyway. +static inline bool CanBucketBySubject( const char * RESTRICT pszSubject ) +{ + return pszSubject && + ( ( pszSubject[0] >= 'A' && pszSubject[0] <= 'Z' ) || + ( pszSubject[0] >= 'a' && pszSubject[0] <= 'z' ) ); +} + +ResponseRulePartition::tRuleDict &ResponseRulePartition::GetDictForRule( CResponseSystem *pSystem, Rule *pRule ) +{ + const static CUtlSymbol kWHO = CriteriaSet::ComputeCriteriaSymbol("Who"); + const static CUtlSymbol kCONCEPT = CriteriaSet::ComputeCriteriaSymbol("Concept"); + const static CUtlSymbol kSUBJECT = CriteriaSet::ComputeCriteriaSymbol("Subject"); + + const char *pszSpeaker = pRule->GetValueForRuleCriterionByName( pSystem, kWHO ); + const char *pszConcept = pRule->GetValueForRuleCriterionByName( pSystem, kCONCEPT ); + const Criteria *pSubjCrit = pRule->GetPointerForRuleCriterionByName( pSystem, kSUBJECT ); + + return m_RuleParts[ + GetBucketForSpeakerAndConcept( pszSpeaker, pszConcept, + ( pSubjCrit && pSubjCrit->required && CanBucketBySubject(pSubjCrit->value) ) ? + pSubjCrit->value : + NULL ) + ]; +} + + +void ResponseRulePartition::GetDictsForCriteria( CUtlVectorFixed< ResponseRulePartition::tRuleDict *, 2 > *pResult, const CriteriaSet &criteria ) +{ + pResult->RemoveAll(); + pResult->EnsureCapacity( 2 ); + + // get the values for Who and Concept, which are what we bucket on + int speakerIdx = criteria.FindCriterionIndex( "Who" ); + const char *pszSpeaker = speakerIdx != -1 ? criteria.GetValue( speakerIdx ) : NULL ; + + int conceptIdx = criteria.FindCriterionIndex( "Concept" ); + const char *pszConcept = conceptIdx != -1 ? criteria.GetValue( conceptIdx ) : NULL ; + + int subjectIdx = criteria.FindCriterionIndex( "Subject" ); + const char *pszSubject = subjectIdx != -1 ? criteria.GetValue( subjectIdx ) : NULL ; + + pResult->AddToTail( &m_RuleParts[ GetBucketForSpeakerAndConcept(pszSpeaker, pszConcept, pszSubject) ] ); + // also try the rules not specifying subject + pResult->AddToTail( &m_RuleParts[ GetBucketForSpeakerAndConcept(pszSpeaker, pszConcept, NULL) ] ); + +} \ No newline at end of file diff --git a/sp/src/responserules/runtime/response_types_internal.h b/sp/src/responserules/runtime/response_types_internal.h new file mode 100644 index 00000000..99e766fe --- /dev/null +++ b/sp/src/responserules/runtime/response_types_internal.h @@ -0,0 +1,553 @@ +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: Core types for the response rules -- criteria, responses, rules, and matchers. +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef RESPONSE_TYPES_INTERNAL_H +#define RESPONSE_TYPES_INTERNAL_H +#ifdef _WIN32 +#pragma once +#endif + +#include "responserules/response_types.h" +#include "utldict.h" + + +namespace ResponseRules +{ + + inline unsigned FASTCALL HashStringConventional( const char *pszKey ) + { + unsigned hash = 0xAAAAAAAA; // Alternating 1's and 0's to maximize the effect of the later multiply and add + + for( ; *pszKey ; pszKey++ ) + { + hash = ( ( hash << 5 ) + hash ) + (uint8)(*pszKey); + } + + return hash; + } + + // Note: HashString causes collisions!!! +#define RR_HASH HashStringConventional + +#pragma pack(push,1) + + class Matcher + { + public: + Matcher(); + + void Describe( void ); + + float maxval; + float minval; + + bool valid : 1; //1 + bool isnumeric : 1; //2 + bool notequal : 1; //3 + bool usemin : 1; //4 + bool minequals : 1; //5 + bool usemax : 1; //6 + bool maxequals : 1; //7 +#ifdef MAPBASE + bool isbit : 1; //8 +#endif + + void SetToken( char const *s ); + + char const *GetToken(); + + void SetRaw( char const *raw ); + + char const *GetRaw(); + + private: + CUtlSymbol token; + CUtlSymbol rawtoken; + }; +#pragma pack(pop) + + struct Criteria + { + Criteria(); + Criteria& operator =(const Criteria& src ); + + Criteria(const Criteria& src ); + ~Criteria(); + + // Does this criterion recursively contain more criteria? + inline bool IsSubCriteriaType() const + { + return ( subcriteria.Count() > 0 ) ? true : false; + } + + // const char *name; + CUtlSymbol nameSym; + const char *value; + float16 weight; + bool required; + + Matcher matcher; + + // Indices into sub criteria + CUtlVectorConservative< unsigned short > subcriteria; + }; + +#pragma pack(push,1) + /// This is a response block as read from the file, + /// different from CRR_Response which is what is handed + /// back to queries. + struct ParserResponse + { + DECLARE_SIMPLE_DATADESC_INSIDE_NAMESPACE(); + + ParserResponse(); + ParserResponse( const ParserResponse& src ); + ParserResponse& operator =( const ParserResponse& src ); + ~ParserResponse(); + + ResponseType_t GetType() { return (ResponseType_t)type; } + + ResponseParams params; + + const char *value; // fixed up value spot // 4 + float16 weight; // 6 + + byte depletioncount; // 7 + byte type : 6; // 8 + byte first : 1; // + byte last : 1; // + + ALIGN32 AI_ResponseFollowup m_followup; // info on whether I should force the other guy to say something + }; +#pragma pack(pop) + +#pragma pack(push,1) + struct ResponseGroup + { + DECLARE_SIMPLE_DATADESC_INSIDE_NAMESPACE(); + + ResponseGroup() + { + // By default visit all nodes before repeating + m_bSequential = false; + m_bNoRepeat = false; + m_bEnabled = true; + m_nCurrentIndex = 0; + m_bDepleteBeforeRepeat = true; + m_nDepletionCount = 1; + m_bHasFirst = false; + m_bHasLast = false; + } + + ResponseGroup( const ResponseGroup& src ) + { + int c = src.group.Count(); + for ( int i = 0; i < c; i++ ) + { + group.AddToTail( src.group[ i ] ); + } + + m_bDepleteBeforeRepeat = src.m_bDepleteBeforeRepeat; + m_nDepletionCount = src.m_nDepletionCount; + m_bHasFirst = src.m_bHasFirst; + m_bHasLast = src.m_bHasLast; + m_bSequential = src.m_bSequential; + m_bNoRepeat = src.m_bNoRepeat; + m_bEnabled = src.m_bEnabled; + m_nCurrentIndex = src.m_nCurrentIndex; + } + + ResponseGroup& operator=( const ResponseGroup& src ) + { + if ( this == &src ) + return *this; + int c = src.group.Count(); + for ( int i = 0; i < c; i++ ) + { + group.AddToTail( src.group[ i ] ); + } + + m_bDepleteBeforeRepeat = src.m_bDepleteBeforeRepeat; + m_nDepletionCount = src.m_nDepletionCount; + m_bHasFirst = src.m_bHasFirst; + m_bHasLast = src.m_bHasLast; + m_bSequential = src.m_bSequential; + m_bNoRepeat = src.m_bNoRepeat; + m_bEnabled = src.m_bEnabled; + m_nCurrentIndex = src.m_nCurrentIndex; + return *this; + } + + bool HasUndepletedChoices() const + { + if ( !m_bDepleteBeforeRepeat ) + return true; + + int c = group.Count(); + for ( int i = 0; i < c; i++ ) + { + if ( group[ i ].depletioncount != m_nDepletionCount ) + return true; + } + + return false; + } + + void MarkResponseUsed( int idx ) + { + if ( !m_bDepleteBeforeRepeat ) + return; + + if ( idx < 0 || idx >= group.Count() ) + { + Assert( 0 ); + return; + } + + group[ idx ].depletioncount = m_nDepletionCount; + } + + void ResetDepletionCount() + { + if ( !m_bDepleteBeforeRepeat ) + return; + ++m_nDepletionCount; + } + + void Reset() + { + ResetDepletionCount(); + SetEnabled( true ); + SetCurrentIndex( 0 ); + m_nDepletionCount = 1; + + for ( int i = 0; i < group.Count(); ++i ) + { + group[ i ].depletioncount = 0; + } + } + + bool HasUndepletedFirst( int& index ) + { + index = -1; + + if ( !m_bDepleteBeforeRepeat ) + return false; + + int c = group.Count(); + for ( int i = 0; i < c; i++ ) + { + ParserResponse *r = &group[ i ]; + + if ( ( r->depletioncount != m_nDepletionCount ) && r->first ) + { + index = i; + return true; + } + } + + return false; + } + + bool HasUndepletedLast( int& index ) + { + index = -1; + + if ( !m_bDepleteBeforeRepeat ) + return false; + + int c = group.Count(); + for ( int i = 0; i < c; i++ ) + { + ParserResponse *r = &group[ i ]; + + if ( ( r->depletioncount != m_nDepletionCount ) && r->last ) + { + index = i; + return true; + } + } + + return false; + } + + bool ShouldCheckRepeats() const { return m_bDepleteBeforeRepeat; } + int GetDepletionCount() const { return m_nDepletionCount; } + + bool IsSequential() const { return m_bSequential; } + void SetSequential( bool seq ) { m_bSequential = seq; } + + bool IsNoRepeat() const { return m_bNoRepeat; } + void SetNoRepeat( bool norepeat ) { m_bNoRepeat = norepeat; } + + bool IsEnabled() const { return m_bEnabled; } + void SetEnabled( bool enabled ) { m_bEnabled = enabled; } + + int GetCurrentIndex() const { return m_nCurrentIndex; } + void SetCurrentIndex( byte idx ) { m_nCurrentIndex = idx; } + + CUtlVector< ParserResponse > group; + + bool m_bEnabled; + + byte m_nCurrentIndex; + // Invalidation counter + byte m_nDepletionCount; + + // Use all slots before repeating any + bool m_bDepleteBeforeRepeat : 1; + bool m_bHasFirst : 1; + bool m_bHasLast : 1; + bool m_bSequential : 1; + bool m_bNoRepeat : 1; + }; +#pragma pack(pop) + +#pragma pack(push,1) + struct Rule + { + Rule(); + Rule( const Rule& src ); + ~Rule(); + Rule& operator =( const Rule& src ); + + void SetContext( const char *context ); + + const char *GetContext( void ) const { return m_szContext; } + + inline bool IsEnabled() const { return m_bEnabled; } + inline void Disable() { m_bEnabled = false; } + inline bool IsMatchOnce() const { return m_bMatchOnce; } +#ifdef MAPBASE + inline int GetContextFlags() const { return m_iContextFlags; } + inline bool IsApplyContextToWorld() const { return (m_iContextFlags & APPLYCONTEXT_WORLD) != 0; } +#else + inline bool IsApplyContextToWorld() const { return m_bApplyContextToWorld; } +#endif + + const char *GetValueForRuleCriterionByName( CResponseSystem *pSystem, const CUtlSymbol &pCritNameSym ); + const Criteria *GetPointerForRuleCriterionByName( CResponseSystem *pSystem, const CUtlSymbol &pCritNameSym ); + + // Indices into underlying criteria and response dictionaries + CUtlVectorConservative< unsigned short > m_Criteria; + CUtlVectorConservative< unsigned short> m_Responses; + + const char *m_szContext; + uint8 m_nForceWeight; + +#ifdef MAPBASE + int m_iContextFlags; +#else + bool m_bApplyContextToWorld : 1; +#endif + + bool m_bMatchOnce : 1; + bool m_bEnabled : 1; + + private: + // what is this, lisp? + const char *RecursiveGetValueForRuleCriterionByName( CResponseSystem *pSystem, const Criteria *pCrit, const CUtlSymbol &pCritNameSym ); + const Criteria *RecursiveGetPointerForRuleCriterionByName( CResponseSystem *pSystem, const Criteria *pCrit, const CUtlSymbol &pCritNameSym ); + }; +#pragma pack(pop) + + template + class CResponseDict : public CUtlMap + { + public: + CResponseDict() : CUtlMap( DefLessFunc( unsigned int ) ), m_ReverseMap( DefLessFunc( unsigned int ) ) + { + } + + I Insert( const char *pName, const T &element ) + { + char const *pString = ResponseCopyString( pName ); + unsigned int hash = RR_HASH( pString ); + m_ReverseMap.Insert( hash, pString ); + return CUtlMap::Insert( hash, element ); + } + + I Insert( const char *pName ) + { + char const *pString = ResponseCopyString( pName ); + unsigned int hash = RR_HASH( pString ); + m_ReverseMap.Insert( hash, pString ); + return CUtlMap::Insert( hash ); + } + + I Find( char const *pName ) const + { + unsigned int hash = RR_HASH( pName ); + return CUtlMap::Find( hash ); + } + + const char *GetElementName( I i ) + { + int k = Key( i ); + int slot = m_ReverseMap.Find( k ); + if ( slot == m_ReverseMap.InvalidIndex() ) + return ""; + return m_ReverseMap[ slot ]; + } + + const char *GetElementName( I i ) const + { + int k = Key( i ); + int slot = m_ReverseMap.Find( k ); + if ( slot == m_ReverseMap.InvalidIndex() ) + return ""; + return m_ReverseMap[ slot ]; + } + + private: + CUtlMap< unsigned int, const char * > m_ReverseMap; + + }; + + // define this to 1 to enable printing some occupancy + // information on the response system via concommmand + // rr_dumphashinfo + #define RR_DUMPHASHINFO_ENABLED 0 + // The Rules are partitioned based on a variety of factors (presently, + // speaker and concept) for faster lookup, basically a seperate-chained hash. + struct ResponseRulePartition + { + ResponseRulePartition( void ); + ~ResponseRulePartition(); + + typedef CResponseDict< Rule * > tRuleDict; + typedef uint32 tIndex; // an integer that can be used to find any rule in the dict + + /// get the appropriate m_rules dict for the provided rule + tRuleDict &GetDictForRule( CResponseSystem *pSystem, Rule *pRule ); + + /// get all bucket full of rules that might possibly match the given criteria. + /// (right now they are bucketed such that all rules that can possibly match a + /// criteria are in one of two dictionaries) + void GetDictsForCriteria( CUtlVectorFixed< ResponseRulePartition::tRuleDict *, 2 > *pResult, const CriteriaSet &criteria ); + + // dump everything. + void RemoveAll(); + + inline Rule &operator[]( tIndex idx ); + int Count( void ); // number of elements inside, but you can't iterate from 0 to this + char const *GetElementName( const tIndex &i ) const; + + /// given a dictionary and an element number inside that dict, + /// return a tIndex + tIndex IndexFromDictElem( tRuleDict* pDict, int elem ); + + // for iteration: + inline tIndex First( void ); + inline tIndex Next( const tIndex &idx ); + inline bool IsValid( const tIndex &idx ) const; + inline static tIndex InvalidIdx( void ) + { + return ((tIndex) -1); + } + + // used only for debug prints, do not rely on them otherwise + inline unsigned int BucketFromIdx( const tIndex &idx ) const ; + inline unsigned int PartFromIdx( const tIndex &idx ) const ; + + enum { + N_RESPONSE_PARTITIONS = 256, + kIDX_ELEM_MASK = 0xFFF, ///< this is used to mask the element number part of a ResponseRulePartition::tIndex + }; + +#if RR_DUMPHASHINFO_ENABLED + void PrintBucketInfo( CResponseSystem *pSys ); +#endif + + private: + tRuleDict m_RuleParts[N_RESPONSE_PARTITIONS]; + unsigned int GetBucketForSpeakerAndConcept( const char *pszSpeaker, const char *pszConcept, const char *pszSubject ); + }; + + // // // // // inline functions + + inline ResponseRulePartition::tIndex ResponseRulePartition::First( void ) + { + // find the first bucket that has anything + for ( int bucket = 0 ; bucket < N_RESPONSE_PARTITIONS; bucket++ ) + { + if ( m_RuleParts[bucket].Count() > 0 ) + return bucket << 16; + } + return InvalidIdx(); + } + + inline ResponseRulePartition::tIndex ResponseRulePartition::Next( const tIndex &idx ) + { + int bucket = BucketFromIdx( idx ); + unsigned int elem = PartFromIdx( idx ); + Assert( IsValid(idx) ); + AssertMsg( elem < kIDX_ELEM_MASK, "Too many response rules! Overflow! Doom!" ); + if ( elem + 1 < m_RuleParts[bucket].Count() ) + { + return idx+1; + } + else + { + // walk through the other buckets, skipping empty ones, until we find one with responses and give up. + while ( ++bucket < N_RESPONSE_PARTITIONS ) + { + if ( m_RuleParts[bucket].Count() > 0 ) + { + // 0th element in nth bucket + return bucket << 16; + } + } + + // out of buckets + return InvalidIdx(); + + } + } + + inline Rule &ResponseRulePartition::operator[]( tIndex idx ) + { + Assert( IsValid(idx) ); + return *m_RuleParts[ BucketFromIdx(idx) ][ PartFromIdx(idx) ] ; + } + + inline unsigned int ResponseRulePartition::BucketFromIdx( const tIndex &idx ) const + { + return idx >> 16; + } + + inline unsigned int ResponseRulePartition::PartFromIdx( const tIndex &idx ) const + { + return idx & kIDX_ELEM_MASK; + } + + inline bool ResponseRulePartition::IsValid( const tIndex & idx ) const + { + // make sure that the idx type for the dicts is still short + COMPILE_TIME_ASSERT( sizeof(m_RuleParts[0].FirstInorder()) == 2 ); + + if ( idx == -1 ) + return false; + + int bucket = idx >> 16; + unsigned int elem = idx & kIDX_ELEM_MASK; + + return ( bucket < N_RESPONSE_PARTITIONS && + elem < m_RuleParts[bucket].Count() ); + } + + //----------------------------------------------------------------------------- + // PARSER TYPES -- these are internal to the response system, and represent + // the objects as loaded from disk. + //----------------------------------------------------------------------------- + + +} + +#include "response_system.h" + +#endif \ No newline at end of file diff --git a/sp/src/responserules/runtime/rr_convars.cpp b/sp/src/responserules/runtime/rr_convars.cpp new file mode 100644 index 00000000..986ae0cd --- /dev/null +++ b/sp/src/responserules/runtime/rr_convars.cpp @@ -0,0 +1,14 @@ +//========= Copyright © 1996-2010, Valve Corporation, All rights reserved. ============// +// +// Purpose: Convars used by the response rule system. +// +// $NoKeywords: $ +//=============================================================================// + +#include "rrbase.h" +#include + + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + diff --git a/sp/src/responserules/runtime/rr_response.cpp b/sp/src/responserules/runtime/rr_response.cpp new file mode 100644 index 00000000..a1ff5a8b --- /dev/null +++ b/sp/src/responserules/runtime/rr_response.cpp @@ -0,0 +1,371 @@ +//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// +// +// Purpose: +// +// $NoKeywords: $ +// +//===========================================================================// +#include "rrbase.h" + +#include + +/* +#include "AI_Criteria.h" +#include "ai_speech.h" +#include +#include "engine/IEngineSound.h" +*/ + +// memdbgon must be the last include file in a .cpp file!!! +#include + +using namespace ResponseRules; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CRR_Response::CRR_Response() : m_fMatchScore(0) +{ + m_Type = ResponseRules::RESPONSE_NONE; + m_szResponseName[0] = 0; + m_szMatchingRule[0]=0; + m_szContext = NULL; +#ifdef MAPBASE + m_iContextFlags = 0; +#else + m_bApplyContextToWorld = false; +#endif +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +CRR_Response::CRR_Response( const CRR_Response &from ) : m_fMatchScore(0) +{ + // Assert( (void*)(&m_Type) == (void*)this ); + Invalidate(); + memcpy( this, &from, sizeof(*this) ); + m_szContext = NULL; + SetContext( from.m_szContext ); +#ifdef MAPBASE + m_iContextFlags = from.m_iContextFlags; +#else + m_bApplyContextToWorld = from.m_bApplyContextToWorld; +#endif +} + + +//----------------------------------------------------------------------------- +CRR_Response &CRR_Response::operator=( const CRR_Response &from ) +{ + // Assert( (void*)(&m_Type) == (void*)this ); + Invalidate(); + memcpy( this, &from, sizeof(*this) ); + m_szContext = NULL; + SetContext( from.m_szContext ); +#ifdef MAPBASE + m_iContextFlags = from.m_iContextFlags; +#else + m_bApplyContextToWorld = from.m_bApplyContextToWorld; +#endif + return *this; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CRR_Response::~CRR_Response() +{ + if (m_szContext) + delete[] m_szContext; +} + +void CRR_Response::Invalidate() +{ + if (m_szContext) + { + delete[] m_szContext; + m_szContext = NULL; + } + m_Type = ResponseRules::RESPONSE_NONE; + m_szResponseName[0] = 0; + // not really necessary: + /* + m_szMatchingRule[0]=0; + m_szContext = NULL; + m_bApplyContextToWorld = false; + */ +} + +// please do not new or delete CRR_Responses. +void CRR_Response::operator delete(void* p) +{ + AssertMsg(false, "DO NOT new or delete CRR_Response s."); + free(p); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *response - +// *criteria - +//----------------------------------------------------------------------------- +void CRR_Response::Init( ResponseType_t type, const char *responseName, const ResponseParams& responseparams, const char *ruleName, const char *applyContext, bool bApplyContextToWorld ) +{ + m_Type = type; + Q_strncpy( m_szResponseName, responseName, sizeof( m_szResponseName ) ); + // Copy underlying criteria + Q_strncpy( m_szMatchingRule, ruleName ? ruleName : "NULL", sizeof( m_szMatchingRule ) ); + m_Params = responseparams; + SetContext( applyContext ); +#ifdef MAPBASE + bApplyContextToWorld ? m_iContextFlags = APPLYCONTEXT_WORLD : m_iContextFlags = 0; +#else + m_bApplyContextToWorld = bApplyContextToWorld; +#endif +} + +#ifdef MAPBASE +//----------------------------------------------------------------------------- +// Purpose: +// Input : *response - +// *criteria - +//----------------------------------------------------------------------------- +void CRR_Response::Init( ResponseType_t type, const char *responseName, const ResponseParams& responseparams, const char *ruleName, const char *applyContext, int iContextFlags ) +{ + m_Type = type; + Q_strncpy( m_szResponseName, responseName, sizeof( m_szResponseName ) ); + // Copy underlying criteria + Q_strncpy( m_szMatchingRule, ruleName ? ruleName : "NULL", sizeof( m_szMatchingRule ) ); + m_Params = responseparams; + SetContext( applyContext ); + m_iContextFlags = iContextFlags; +} +#endif + +//----------------------------------------------------------------------------- +// Purpose: Debug-print the response. You can optionally pass in the criteria +// used to come up with this response (usually present in the calling function) +// if you want to print that as well. DO NOT store the entire criteria set in +// CRR_Response just to make this debug print cleaner. +//----------------------------------------------------------------------------- +void CRR_Response::Describe( const CriteriaSet *pDebugCriteria ) +{ + if ( pDebugCriteria ) + { + DevMsg( "Search criteria:\n" ); + pDebugCriteria->Describe(); + } + + if ( m_szMatchingRule[ 0 ] ) + { + DevMsg( "Matched rule '%s', ", m_szMatchingRule ); + } + if ( m_szContext ) + { +#ifdef MAPBASE + DevMsg( "Contexts to set '%s' on ", m_szContext ); + if (m_iContextFlags & APPLYCONTEXT_WORLD) + DevMsg( "world, " ); + else if (m_iContextFlags & APPLYCONTEXT_SQUAD) + DevMsg( "squad, " ); + else if (m_iContextFlags & APPLYCONTEXT_ENEMY) + DevMsg( "enemy, " ); + else + DevMsg( "speaker, " ); +#else + DevMsg( "Contexts to set '%s' on %s, ", m_szContext, m_bApplyContextToWorld ? "world" : "speaker" ); +#endif + } + + DevMsg( "response %s = '%s'\n", DescribeResponse( (ResponseType_t)m_Type ), m_szResponseName ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : char const +//----------------------------------------------------------------------------- +void CRR_Response::GetName( char *buf, size_t buflen ) const +{ + Q_strncpy( buf, m_szResponseName, buflen ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Output : char const +//----------------------------------------------------------------------------- +void CRR_Response::GetResponse( char *buf, size_t buflen ) const +{ + GetName( buf, buflen ); +} + +const char* ResponseRules::CRR_Response::GetNamePtr() const +{ + return m_szResponseName; +} +const char* ResponseRules::CRR_Response::GetResponsePtr() const +{ + return m_szResponseName; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : type - +// Output : char const +//----------------------------------------------------------------------------- +const char *CRR_Response::DescribeResponse( ResponseType_t type ) +{ + if ( (int)type < 0 || (int)type >= ResponseRules::NUM_RESPONSES ) + { + Assert( 0 ); + return "???CRR_Response bogus index"; + } + + switch( type ) + { + default: + { + Assert( 0 ); + } + // Fall through + case ResponseRules::RESPONSE_NONE: + return "RESPONSE_NONE"; + case ResponseRules::RESPONSE_SPEAK: + return "RESPONSE_SPEAK"; + case ResponseRules::RESPONSE_SENTENCE: + return "RESPONSE_SENTENCE"; + case ResponseRules::RESPONSE_SCENE: + return "RESPONSE_SCENE"; + case ResponseRules::RESPONSE_RESPONSE: + return "RESPONSE_RESPONSE"; + case ResponseRules::RESPONSE_PRINT: + return "RESPONSE_PRINT"; + case ResponseRules::RESPONSE_ENTITYIO: + return "RESPONSE_ENTITYIO"; +#ifdef MAPBASE + case ResponseRules::RESPONSE_VSCRIPT: + return "RESPONSE_VSCRIPT"; +#endif + } + + return "RESPONSE_NONE"; +} + +/* +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CRR_Response::Release() +{ + delete this; +} +*/ + +//----------------------------------------------------------------------------- +// Purpose: +// Output : soundlevel_t +//----------------------------------------------------------------------------- +soundlevel_t CRR_Response::GetSoundLevel() const +{ + if ( m_Params.flags & ResponseParams::RG_SOUNDLEVEL ) + { + return (soundlevel_t)m_Params.soundlevel; + } + + return SNDLVL_TALKING; +} + +float CRR_Response::GetRespeakDelay( void ) const +{ + if ( m_Params.flags & ResponseParams::RG_RESPEAKDELAY ) + { + interval_t temp; + m_Params.respeakdelay.ToInterval( temp ); + return RandomInterval( temp ); + } + + return 0.0f; +} + +float CRR_Response::GetWeaponDelay( void ) const +{ + if ( m_Params.flags & ResponseParams::RG_WEAPONDELAY ) + { + interval_t temp; + m_Params.weapondelay.ToInterval( temp ); + return RandomInterval( temp ); + } + + return 0.0f; +} + +bool CRR_Response::GetSpeakOnce( void ) const +{ + if ( m_Params.flags & ResponseParams::RG_SPEAKONCE ) + { + return true; + } + + return false; +} + +bool CRR_Response::ShouldntUseScene( void ) const +{ + return ( m_Params.flags & ResponseParams::RG_DONT_USE_SCENE ) != 0; +} + +bool CRR_Response::ShouldBreakOnNonIdle( void ) const +{ + return ( m_Params.flags & ResponseParams::RG_STOP_ON_NONIDLE ) != 0; +} + +int CRR_Response::GetOdds( void ) const +{ + if ( m_Params.flags & ResponseParams::RG_ODDS ) + { + return m_Params.odds; + } + return 100; +} + +float CRR_Response::GetDelay() const +{ + if ( m_Params.flags & ResponseParams::RG_DELAYAFTERSPEAK ) + { + interval_t temp; + m_Params.delay.ToInterval( temp ); + return RandomInterval( temp ); + } + return 0.0f; +} + +float CRR_Response::GetPreDelay() const +{ + if ( m_Params.flags & ResponseParams::RG_DELAYBEFORESPEAK ) + { + interval_t temp; + m_Params.predelay.ToInterval( temp ); + return RandomInterval( temp ); + } + return 0.0f; +} + +//----------------------------------------------------------------------------- +// Purpose: Sets context string +// Output : void +//----------------------------------------------------------------------------- +void CRR_Response::SetContext( const char *context ) +{ + if (m_szContext) + { + delete[] m_szContext; + m_szContext = NULL; + } + + if ( context ) + { + int len = Q_strlen( context ); + m_szContext = new char[ len + 1 ]; + Q_memcpy( m_szContext, context, len ); + m_szContext[ len ] = 0; + } +} diff --git a/sp/src/responserules/runtime/rr_speechconcept.cpp b/sp/src/responserules/runtime/rr_speechconcept.cpp new file mode 100644 index 00000000..7e1e04ab --- /dev/null +++ b/sp/src/responserules/runtime/rr_speechconcept.cpp @@ -0,0 +1,73 @@ +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#include "rrbase.h" + + +// memdbgon must be the last include file in a .cpp file!!! +#include + +#if RR_CONCEPTS_ARE_STRINGS +#pragma error("RR_CONCEPTS_ARE_STRINGS no longer supported") +#else + +using namespace ResponseRules; + +// Used to turn ad-hoc concept from strings into numbers. +CRR_ConceptSymbolTable *g_pRRConceptTable = NULL; + +// Q&D hack to defer initialization of concept table until I can figure out where it +// really needs to come from. +static void InitializeRRConceptTable() +{ + if (g_pRRConceptTable == NULL) + { + g_pRRConceptTable = new CRR_ConceptSymbolTable( 64, 64, true ); + } +} + +// construct from string +CRR_Concept::CRR_Concept(const char *fromString) +{ + InitializeRRConceptTable(); + m_iConcept = g_pRRConceptTable->AddString(fromString); +} + +CRR_Concept &CRR_Concept::operator=(const char *fromString) +{ + InitializeRRConceptTable(); + m_iConcept = g_pRRConceptTable->AddString(fromString); + return *this; +} + +bool CRR_Concept::operator==(const char *pszConcept) +{ + int otherConcept = g_pRRConceptTable->Find(pszConcept); + return ( otherConcept != UTL_INVAL_SYMBOL && otherConcept == m_iConcept ); +} + +const char *CRR_Concept::GetStringConcept() const +{ + InitializeRRConceptTable(); + AssertMsg( m_iConcept.IsValid(), "AI Concept has invalid string symbol.\n" ); + const char * retval = g_pRRConceptTable->String(m_iConcept); + AssertMsg( retval, "An RR_Concept couldn't find its string in the symbol table!\n" ); + if (retval == NULL) + { + Warning( "An RR_Concept couldn't find its string in the symbol table!\n" ); + retval = ""; + } + return retval; +} + +const char *CRR_Concept::GetStringForGenericId(tGenericId genericId) +{ + InitializeRRConceptTable(); + return g_pRRConceptTable->String(genericId); +} + +#endif diff --git a/sp/src/responserules/runtime/rrbase.h b/sp/src/responserules/runtime/rrbase.h new file mode 100644 index 00000000..e7af74de --- /dev/null +++ b/sp/src/responserules/runtime/rrbase.h @@ -0,0 +1,59 @@ +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#ifndef RRBASE_H +#define RRBASE_H +#ifdef _WIN32 +#pragma once +#endif + +#ifdef _WIN32 +// Silence certain warnings +// #pragma warning(disable : 4244) // int or float down-conversion +// #pragma warning(disable : 4305) // int or float data truncation +// #pragma warning(disable : 4201) // nameless struct/union +// #pragma warning(disable : 4511) // copy constructor could not be generated +// #pragma warning(disable : 4675) // resolved overload was found by argument dependent lookup +#endif + +#ifdef _DEBUG +#define DEBUG 1 +#endif + +// Misc C-runtime library headers +#include +#include +#include + +// tier 0 +#include "tier0/dbg.h" +#include "tier0/platform.h" +#include "basetypes.h" + +// tier 1 +#include "tier1/strtools.h" +#include "utlvector.h" +#include "utlsymbol.h" + +// tier 2 +#include "string_t.h" + +// Shared engine/DLL constants +#include "const.h" +#include "edict.h" + +// app +#if defined(_X360) +#define DISABLE_DEBUG_HISTORY 1 +#endif + +#include "responserules/response_types.h" +#include "response_types_internal.h" +#include "responserules/response_host_interface.h" + + +#endif // CBASE_H diff --git a/sp/src/responserules/runtime/rrrlib.cpp b/sp/src/responserules/runtime/rrrlib.cpp new file mode 100644 index 00000000..0d2c49fd --- /dev/null +++ b/sp/src/responserules/runtime/rrrlib.cpp @@ -0,0 +1,13 @@ +/// PLACEHOLDER FILE FOR RESPONSE RULES RUNTIME LIBRARY + +#include "rrbase.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + +namespace ResponseRules +{ + /// Custom symbol table for the response rules. + CUtlSymbolTable g_RS; +}; \ No newline at end of file diff --git a/sp/src/responserules/runtime/stdafx.cpp b/sp/src/responserules/runtime/stdafx.cpp new file mode 100644 index 00000000..4199359f --- /dev/null +++ b/sp/src/responserules/runtime/stdafx.cpp @@ -0,0 +1,11 @@ +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: Builds the precompiled header for the game DLL +// +// $NoKeywords: $ +//=============================================================================// + + +#include "rrbase.h" + +// NOTE: DO NOT ADD ANY CODE OR HEADERS TO THIS FILE!!! diff --git a/sp/src/game/shared/interval.cpp b/sp/src/tier1/interval.cpp similarity index 100% rename from sp/src/game/shared/interval.cpp rename to sp/src/tier1/interval.cpp diff --git a/sp/src/tier1/tier1.vpc b/sp/src/tier1/tier1.vpc index d7012f3e..17158317 100644 --- a/sp/src/tier1/tier1.vpc +++ b/sp/src/tier1/tier1.vpc @@ -39,6 +39,7 @@ $Project "tier1" $File "generichash.cpp" $File "ilocalize.cpp" $File "interface.cpp" + $File "interval.cpp" $File "KeyValues.cpp" $File "kvpacker.cpp" $File "lzmaDecoder.cpp" diff --git a/sp/src/vpc_scripts/groups.vgc b/sp/src/vpc_scripts/groups.vgc index 7354a28e..2ab187fa 100644 --- a/sp/src/vpc_scripts/groups.vgc +++ b/sp/src/vpc_scripts/groups.vgc @@ -23,6 +23,7 @@ $Group "game" "tier1" "vgui_controls" "vscript" + "responserules" } $Group "shaders" @@ -41,6 +42,7 @@ $Group "everything" "mathlib" "motionmapper" "phonemeextractor" + "responserules" "qc_eyes" "raytrace" "server" @@ -66,3 +68,17 @@ $Group "dedicated" "tier1" } +$Group "maptools" +{ + "vbsp" + "vrad_dll" + "vrad_launcher" + "vvis_dll" + "vvis_launcher" + "fgdlib" + "mathlib" + "raytrace" + "tier1" + "vscript" +} + diff --git a/sp/src/vpc_scripts/projects.vgc b/sp/src/vpc_scripts/projects.vgc index 17f0440e..fdfcc57e 100644 --- a/sp/src/vpc_scripts/projects.vgc +++ b/sp/src/vpc_scripts/projects.vgc @@ -46,6 +46,11 @@ $Project "server" "game\server\server_episodic.vpc" [($WIN32||$X360||$POSIX) && $EPISODIC] } +$Project "responserules" +{ + "responserules\runtime\response_rules.vpc" [($WINDOWS||$X360||$POSIX) && $NEW_RESPONSE_SYSTEM] +} + $Project "mathlib" { "mathlib\mathlib.vpc" [$WINDOWS||$X360||$POSIX] diff --git a/sp/src/vpc_scripts/source_base.vpc b/sp/src/vpc_scripts/source_base.vpc index acf7c9b8..66530a33 100644 --- a/sp/src/vpc_scripts/source_base.vpc +++ b/sp/src/vpc_scripts/source_base.vpc @@ -24,6 +24,9 @@ $Conditional MAPBASE_RPC "1" // Toggles VScript implementation (note: interfaces still exist, just the provided implementation is not present) $Conditional MAPBASE_VSCRIPT "1" + +// Toggles the new Response System library based on the Alien Swarm SDK. +$Conditional NEW_RESPONSE_SYSTEM "1" //----------------------------------------------------------------------------- $Configuration "Debug" From d6b959899c523302efd5cb42991810a3861de982 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Mon, 8 Mar 2021 02:12:53 -0600 Subject: [PATCH 003/378] Missed a file in the initial Response System library port commit --- sp/src/game/server/AI_ResponseSystem.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sp/src/game/server/AI_ResponseSystem.h b/sp/src/game/server/AI_ResponseSystem.h index a34255b2..0b0b6334 100644 --- a/sp/src/game/server/AI_ResponseSystem.h +++ b/sp/src/game/server/AI_ResponseSystem.h @@ -4,6 +4,9 @@ // //=============================================================================// +#ifdef NEW_RESPONSE_SYSTEM +#include "ai_responsesystem_new.h" +#else #ifndef AI_RESPONSESYSTEM_H #define AI_RESPONSESYSTEM_H @@ -39,3 +42,4 @@ class ISaveRestoreBlockHandler *GetDefaultResponseSystemSaveRestoreBlockHandler( class ISaveRestoreOps *GetResponseSystemSaveRestoreOps(); #endif // AI_RESPONSESYSTEM_H +#endif From d4a91fe02715d9d5fac1718027b04c00b50bd8fe Mon Sep 17 00:00:00 2001 From: Blixibon Date: Tue, 9 Mar 2021 10:03:40 -0600 Subject: [PATCH 004/378] Made followup responses more reliable with generic NPCs and added "vscript_file" response type --- sp/src/game/server/ai_expresserfollowup.cpp | 34 ++++++- sp/src/game/server/ai_speech_new.cpp | 99 ++++++++++++++++++- sp/src/game/server/ai_speech_new.h | 13 +++ sp/src/game/server/ai_speechqueue.cpp | 18 +++- sp/src/public/responserules/response_types.h | 17 ++++ .../responserules/runtime/response_system.cpp | 45 ++++++++- .../responserules/runtime/response_system.h | 13 +++ sp/src/responserules/runtime/rr_response.cpp | 2 + 8 files changed, 235 insertions(+), 6 deletions(-) diff --git a/sp/src/game/server/ai_expresserfollowup.cpp b/sp/src/game/server/ai_expresserfollowup.cpp index ff49d535..84db4773 100644 --- a/sp/src/game/server/ai_expresserfollowup.cpp +++ b/sp/src/game/server/ai_expresserfollowup.cpp @@ -74,6 +74,10 @@ static void DispatchComeback( CAI_ExpresserWithFollowup *pExpress, CBaseEntity * // add in the FROM context so dispatchee knows was from me const char * RESTRICT pszSpeakerName = GetResponseName( pSpeaker ); criteria.AppendCriteria( "From", pszSpeakerName ); +#ifdef MAPBASE + // See DispatchFollowupThroughQueue() + criteria.AppendCriteria( "From_idx", CNumStr( pSpeaker->entindex() ) ); +#endif // if a SUBJECT criteria is missing, put it back in. if ( criteria.FindCriterionIndex( "Subject" ) == -1 ) { @@ -140,8 +144,17 @@ static CBaseEntity *AscertainSpeechSubjectFromContext( AI_Response *response, AI const char *subject = criteria.GetValue( criteria.FindCriterionIndex( pContextName ) ); if (subject) { + CBaseEntity *pEnt = gEntList.FindEntityByName( NULL, subject ); - return gEntList.FindEntityByName( NULL, subject ); +#ifdef MAPBASE + // Allow entity indices to be used (see DispatchFollowupThroughQueue() for one particular use case) + if (!pEnt && atoi(subject)) + { + pEnt = CBaseEntity::Instance( atoi( subject ) ); + } +#endif + + return pEnt; } else @@ -166,7 +179,12 @@ static CResponseQueue::CFollowupTargetSpec_t ResolveFollowupTargetToEntity( AICo } else if ( Q_stricmp(szTarget, "from") == 0 ) { +#ifdef MAPBASE + // See DispatchFollowupThroughQueue() + return CResponseQueue::CFollowupTargetSpec_t( AscertainSpeechSubjectFromContext( response, criteria, "From_idx" ) ); +#else return CResponseQueue::CFollowupTargetSpec_t( AscertainSpeechSubjectFromContext( response, criteria, "From" ) ); +#endif } else if ( Q_stricmp(szTarget, "any") == 0 ) { @@ -400,6 +418,14 @@ void CAI_ExpresserWithFollowup::DispatchFollowupThroughQueue( const AIConcept_t // Don't add my own criteria! GatherCriteria( &criteria, followup.followup_concept, followup.followup_contexts ); criteria.AppendCriteria( "From", STRING( pOuter->GetEntityName() ) ); +#ifdef MAPBASE + // The index of the "From" entity. + // In HL2 mods, many followup users would be generic NPCs (e.g. citizens) who might not have any particular significance. + // Those generic NPCs are quite likely to have no name or have a name in common with other entities. As a result, Mapbase + // changes internal operations of the "From" context to search for an entity index. This won't be 100% reliable if the source + // talker dies and another entity is created immediately afterwards, but it's a lot more reliable than a simple entity name search. + criteria.AppendCriteria( "From_idx", CNumStr( pOuter->entindex() ) ); +#endif criteria.Merge( criteriaStr ); g_ResponseQueueManager.GetQueue()->Add( concept, &criteria, gpGlobals->curtime + delay, target, pOuter ); @@ -436,6 +462,12 @@ void CAI_ExpresserWithFollowup::OnSpeechFinished() { if (m_pPostponedFollowup && m_pPostponedFollowup->IsValid()) { +#ifdef MAPBASE + // HACKHACK: Non-scene speech (e.g. noscene speak/sentence) fire OnSpeechFinished() immediately, + // so add the actual speech time to the followup delay + if (GetTimeSpeechCompleteWithoutDelay() > gpGlobals->curtime) + m_pPostponedFollowup->followup_delay += GetTimeSpeechCompleteWithoutDelay() - gpGlobals->curtime; +#endif return SpeakDispatchFollowup(*m_pPostponedFollowup); } } diff --git a/sp/src/game/server/ai_speech_new.cpp b/sp/src/game/server/ai_speech_new.cpp index f6cfaaaa..a7c4ac729 100644 --- a/sp/src/game/server/ai_speech_new.cpp +++ b/sp/src/game/server/ai_speech_new.cpp @@ -750,6 +750,10 @@ bool CAI_Expresser::SpeakDispatchResponse( AIConcept_t &concept, AI_Response *re DevMsg( 2, "SpeakDispatchResponse: Entity ( %i/%s ) playing sound '%s'\n", GetOuter()->entindex(), STRING( GetOuter()->GetEntityName() ), response ); NoteSpeaking( speakTime, delay ); spoke = true; +#ifdef MAPBASE + // Not really any other way of doing this + OnSpeechFinished(); +#endif } } break; @@ -757,6 +761,10 @@ bool CAI_Expresser::SpeakDispatchResponse( AIConcept_t &concept, AI_Response *re case ResponseRules::RESPONSE_SENTENCE: { spoke = ( -1 != SpeakRawSentence( response, delay, VOL_NORM, soundlevel ) ) ? true : false; +#ifdef MAPBASE + // Not really any other way of doing this + OnSpeechFinished(); +#endif } break; @@ -781,17 +789,30 @@ bool CAI_Expresser::SpeakDispatchResponse( AIConcept_t &concept, AI_Response *re NDebugOverlay::Text( vPrintPos, response, true, 1.5 ); } spoke = true; +#ifdef MAPBASE + OnSpeechFinished(); +#endif } break; case ResponseRules::RESPONSE_ENTITYIO: { - return FireEntIOFromResponse( response, GetOuter() ); + spoke = FireEntIOFromResponse( response, GetOuter() ); +#ifdef MAPBASE + OnSpeechFinished(); +#endif } break; -#ifdef MAPBASE +#ifdef MAPBASE_VSCRIPT case ResponseRules::RESPONSE_VSCRIPT: { - return GetOuter()->RunScript( response, "ResponseScript" ); + spoke = RunScriptResponse( GetOuter(), response, criteria, false ); + OnSpeechFinished(); + } + break; + case ResponseRules::RESPONSE_VSCRIPT_FILE: + { + spoke = RunScriptResponse( GetOuter(), response, criteria, true ); + OnSpeechFinished(); } break; #endif @@ -918,6 +939,47 @@ bool CAI_Expresser::FireEntIOFromResponse( char *response, CBaseEntity *pInitiat return true; } +#ifdef MAPBASE_VSCRIPT +bool CAI_Expresser::RunScriptResponse( CBaseEntity *pTarget, const char *response, AI_CriteriaSet *criteria, bool file ) +{ + if (!pTarget->ValidateScriptScope()) + return false; + + ScriptVariant_t varCriteriaTable; + g_pScriptVM->CreateTable( varCriteriaTable ); + + if (criteria) + { + // Sort all of the criteria into a table. + // Letting VScript have access to this is important because not all criteria is appended in ModifyOrAppendCriteria() and + // not all contexts are actually appended as contexts. This is specifically important for followup responses. + int count = criteria->GetCount(); + for ( int i = 0 ; i < count ; ++i ) + { + // TODO: Weight? + g_pScriptVM->SetValue( varCriteriaTable, criteria->GetName(i), criteria->GetValue(i) ); + } + + g_pScriptVM->SetValue( "criteria", varCriteriaTable ); + } + + bool bSuccess = false; + if (file) + { + bSuccess = pTarget->RunScriptFile( response ); + } + else + { + bSuccess = pTarget->RunScript( response, "ResponseScript" ); + } + + g_pScriptVM->ClearValue( "criteria" ); + g_pScriptVM->ReleaseScript( varCriteriaTable ); + + return bSuccess; +} +#endif + //----------------------------------------------------------------------------- // Purpose: // Input : *response - @@ -967,6 +1029,37 @@ float CAI_Expresser::GetResponseDuration( AI_Response *result ) return 0.0f; } +#ifdef MAPBASE +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CAI_Expresser::SetUsingProspectiveResponses( bool bToggle ) +{ + VPROF("CAI_Expresser::SetUsingProspectiveResponses"); + IResponseSystem *rs = GetOuter()->GetResponseSystem(); + if ( !rs ) + { + Assert( !"No response system installed for CAI_Expresser::GetOuter()!!!" ); + return; + } + + rs->SetProspective( bToggle ); +} + +void CAI_Expresser::MarkResponseAsUsed( AI_Response *response ) +{ + VPROF("CAI_Expresser::MarkResponseAsUsed"); + IResponseSystem *rs = GetOuter()->GetResponseSystem(); + if ( !rs ) + { + Assert( !"No response system installed for CAI_Expresser::GetOuter()!!!" ); + return; + } + + rs->MarkResponseAsUsed( response->GetInternalIndices()[0], response->GetInternalIndices()[1] ); +} +#endif + //----------------------------------------------------------------------------- // Purpose: Placeholder for rules based response system // Input : concept - diff --git a/sp/src/game/server/ai_speech_new.h b/sp/src/game/server/ai_speech_new.h index 02501c18..e3c895be 100644 --- a/sp/src/game/server/ai_speech_new.h +++ b/sp/src/game/server/ai_speech_new.h @@ -178,6 +178,11 @@ public: virtual bool SpeakDispatchResponse( AIConcept_t &concept, AI_Response *response, AI_CriteriaSet *criteria, IRecipientFilter *filter = NULL ); float GetResponseDuration( AI_Response *response ); +#ifdef MAPBASE + void SetUsingProspectiveResponses( bool bToggle ); + void MarkResponseAsUsed( AI_Response *response ); +#endif + virtual int SpeakRawSentence( const char *pszSentence, float delay, float volume = VOL_NORM, soundlevel_t soundlevel = SNDLVL_TALKING, CBaseEntity *pListener = NULL ); bool SemaphoreIsAvailable( CBaseEntity *pTalker ); @@ -194,6 +199,9 @@ public: bool CanSpeak(); bool CanSpeakAfterMyself(); float GetTimeSpeechComplete() const { return m_flStopTalkTime; } +#ifdef MAPBASE + float GetTimeSpeechCompleteWithoutDelay() const { return m_flStopTalkTimeWithoutDelay; } +#endif void BlockSpeechUntil( float time ); // -------------------------------- @@ -227,6 +235,11 @@ public: // returns false on failure (eg, couldn't match parse contents) static bool FireEntIOFromResponse( char *response, CBaseEntity *pInitiator ); +#ifdef MAPBASE_VSCRIPT + // Used for RESPONSE_VSCRIPT(_FILE) + static bool RunScriptResponse( CBaseEntity *pTarget, const char *response, AI_CriteriaSet *criteria, bool file ); +#endif + protected: CAI_TimedSemaphore *GetMySpeechSemaphore( CBaseEntity *pNpc ); diff --git a/sp/src/game/server/ai_speechqueue.cpp b/sp/src/game/server/ai_speechqueue.cpp index 46779ad6..79794d4b 100644 --- a/sp/src/game/server/ai_speechqueue.cpp +++ b/sp/src/game/server/ai_speechqueue.cpp @@ -374,6 +374,10 @@ bool CResponseQueue::DispatchOneResponse_ThenANY( CDeferredResponse &response, A } AI_Response prospectiveResponse; +#ifdef MAPBASE + pEx->SetUsingProspectiveResponses( true ); +#endif + if ( pEx->FindResponse( prospectiveResponse, response.m_concept, &characterCriteria ) ) { float score = prospectiveResponse.GetMatchScore(); @@ -390,8 +394,13 @@ bool CResponseQueue::DispatchOneResponse_ThenANY( CDeferredResponse &response, A } else if ( score >= bestScore - slop ) // if this score is at least as good as the best we've seen, but not better than all { - if ( numExFound >= EXARRAYMAX ) + if ( numExFound >= EXARRAYMAX ) + { +#ifdef MAPBASE + pEx->SetUsingProspectiveResponses( false ); +#endif continue; // SAFETY: don't overflow the array + } responseToSay[numExFound] = prospectiveResponse; pBestEx[numExFound] = pEx; @@ -400,6 +409,10 @@ bool CResponseQueue::DispatchOneResponse_ThenANY( CDeferredResponse &response, A } } } + +#ifdef MAPBASE + pEx->SetUsingProspectiveResponses( false ); +#endif } // if I have a response, dispatch it. @@ -410,6 +423,9 @@ bool CResponseQueue::DispatchOneResponse_ThenANY( CDeferredResponse &response, A if ( pBestEx[iSelect] != NULL ) { +#ifdef MAPBASE + pBestEx[iSelect]->MarkResponseAsUsed( responseToSay + iSelect ); +#endif return pBestEx[iSelect]->SpeakDispatchResponse( response.m_concept, responseToSay + iSelect, pDeferredCriteria ); } else diff --git a/sp/src/public/responserules/response_types.h b/sp/src/public/responserules/response_types.h index 2e7472c2..821b0c57 100644 --- a/sp/src/public/responserules/response_types.h +++ b/sp/src/public/responserules/response_types.h @@ -98,6 +98,7 @@ namespace ResponseRules RESPONSE_ENTITYIO, // poke an input on an entity #ifdef MAPBASE RESPONSE_VSCRIPT, // Run VScript code + RESPONSE_VSCRIPT_FILE, // Run a VScript file (bypasses ugliness and character limits when just using IncludeScript() with RESPONSE_VSCRIPT) #endif NUM_RESPONSES, @@ -351,6 +352,9 @@ namespace ResponseRules #ifdef MAPBASE int GetContextFlags() { return m_iContextFlags; } bool IsApplyContextToWorld( void ) { return (m_iContextFlags & APPLYCONTEXT_WORLD) != 0; } + + inline short *GetInternalIndices() { return m_InternalIndices; } + inline void SetInternalIndices( short iGroup, short iWithinGroup ) { m_InternalIndices[0] = iGroup; m_InternalIndices[1] = iWithinGroup; } #else bool IsApplyContextToWorld( void ) { return m_bApplyContextToWorld; } #endif @@ -393,6 +397,10 @@ namespace ResponseRules char * m_szContext; // context data we apply to character after running #ifdef MAPBASE int m_iContextFlags; + + // The response's original indices in the system. [0] is the group's index, [1] is the index within the group. + // For now, this is only set in prospecctive mode. It's used to call back to the ParserResponse and mark a prospectively chosen response as used. + short m_InternalIndices[2]; #else bool m_bApplyContextToWorld; #endif @@ -418,6 +426,15 @@ namespace ResponseRules virtual bool FindBestResponse( const CriteriaSet& set, CRR_Response& response, IResponseFilter *pFilter = NULL ) = 0; virtual void GetAllResponses( CUtlVector *pResponses ) = 0; virtual void PrecacheResponses( bool bEnable ) = 0; + +#ifdef MAPBASE + // (Optional) Call this before and after using FindBestResponse() for a prospective lookup, e.g. a response that might not actually be used + // and should not trigger displayfirst, etc. + virtual void SetProspective( bool bToggle ) {}; + + // (Optional) Marks a prospective response as used + virtual void MarkResponseAsUsed( short iGroup, short iWithinGroup ) {}; +#endif }; diff --git a/sp/src/responserules/runtime/response_system.cpp b/sp/src/responserules/runtime/response_system.cpp index afdc40ef..f517c5a6 100644 --- a/sp/src/responserules/runtime/response_system.cpp +++ b/sp/src/responserules/runtime/response_system.cpp @@ -942,6 +942,10 @@ int CResponseSystem::SelectWeightedResponseFromResponseGroup( ResponseGroup *g, } if ( slot != -1 ) +#ifdef MAPBASE + // Don't mark responses as used in prospective mode + if (m_bInProspective == false) +#endif g->MarkResponseUsed( slot ); // Revert fake depletion of unavailable choices @@ -1284,6 +1288,26 @@ bool CResponseSystem::FindBestResponse( const CriteriaSet& set, CRR_Response& re context = r->GetContext(); #ifdef MAPBASE contextflags = r->GetContextFlags(); + + // Sets the internal indices for the response to call back to later for prospective responses + // (NOTE: Performance not tested; Be wary of turning off the m_bInProspective check!) + if (m_bInProspective) + { + for ( int i = 0; i < (int)m_Responses.Count(); i++ ) + { + if (&m_Responses[i] == result.group) + { + ResponseGroup &group = m_Responses[i]; + for ( int j = 0; j < group.group.Count(); j++) + { + if (&group.group[j] == result.action) + { + response.SetInternalIndices( i, j ); + } + } + } + } + } #else bcontexttoworld = r->IsApplyContextToWorld(); #endif @@ -1369,6 +1393,22 @@ void CResponseSystem::GetAllResponses( CUtlVector *pResponses ) } } +#ifdef MAPBASE +void CResponseSystem::MarkResponseAsUsed( short iGroup, short iWithinGroup ) +{ + if (m_Responses.Count() > (unsigned int)iGroup) + { + ResponseGroup &group = m_Responses[iGroup]; + if (group.group.Count() > (int)iWithinGroup) + { + group.MarkResponseUsed( iWithinGroup ); + + Msg("Marked response %s (%i) used\n", group.group[iWithinGroup].value, iWithinGroup); + } + } +} +#endif + void CResponseSystem::ParseInclude() { char includefile[ 256 ]; @@ -1521,7 +1561,10 @@ inline ResponseType_t ComputeResponseType( const char *s ) return RESPONSE_ENTITYIO; #ifdef MAPBASE case 'v': - return RESPONSE_VSCRIPT; + if (*(s + 7) == '_') + return RESPONSE_VSCRIPT_FILE; + else + return RESPONSE_VSCRIPT; #endif } diff --git a/sp/src/responserules/runtime/response_system.h b/sp/src/responserules/runtime/response_system.h index 5fec10de..9849b5a9 100644 --- a/sp/src/responserules/runtime/response_system.h +++ b/sp/src/responserules/runtime/response_system.h @@ -44,6 +44,12 @@ namespace ResponseRules // IResponseSystem virtual bool FindBestResponse( const CriteriaSet& set, CRR_Response& response, IResponseFilter *pFilter = NULL ); virtual void GetAllResponses( CUtlVector *pResponses ); + +#ifdef MAPBASE + virtual void SetProspective( bool bToggle ) { m_bInProspective = bToggle; } + + virtual void MarkResponseAsUsed( short iGroup, short iWithinGroup ); +#endif #pragma endregion Implement interface from IResponseSystem virtual void Release() = 0; @@ -283,6 +289,13 @@ public: bool m_bCustomManagable; +#ifdef MAPBASE + // This is a hack specifically designed to fix displayfirst, speakonce, etc. in "prospective" response searches, + // especially the prospective lookups in followup responses. + // It works by preventing responses from being marked as "used". + bool m_bInProspective; +#endif + struct ScriptEntry { unsigned char *buffer; diff --git a/sp/src/responserules/runtime/rr_response.cpp b/sp/src/responserules/runtime/rr_response.cpp index a1ff5a8b..6124805c 100644 --- a/sp/src/responserules/runtime/rr_response.cpp +++ b/sp/src/responserules/runtime/rr_response.cpp @@ -244,6 +244,8 @@ const char *CRR_Response::DescribeResponse( ResponseType_t type ) #ifdef MAPBASE case ResponseRules::RESPONSE_VSCRIPT: return "RESPONSE_VSCRIPT"; + case ResponseRules::RESPONSE_VSCRIPT_FILE: + return "RESPONSE_VSCRIPT_FILE"; #endif } From 8033c0dad43fc6889700e0387ca50cbb81df1187 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Tue, 9 Mar 2021 12:30:48 -0600 Subject: [PATCH 005/378] Fixed response group default params, which seem to have been broken in vanilla response system code from the SDK --- sp/src/responserules/runtime/response_system.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sp/src/responserules/runtime/response_system.cpp b/sp/src/responserules/runtime/response_system.cpp index f517c5a6..94660c58 100644 --- a/sp/src/responserules/runtime/response_system.cpp +++ b/sp/src/responserules/runtime/response_system.cpp @@ -1815,7 +1815,7 @@ void CResponseSystem::ParseResponseGroup_Start( char const *responseGroupName, R continue; } - ParseOneResponse( responseGroupName, newGroup ); + ParseOneResponse( responseGroupName, newGroup, &groupResponseParams ); } } @@ -1923,9 +1923,10 @@ void CResponseSystem::ParseResponse( void ) { continue; } - ParseOneResponse( responseGroupName, newGroup ); - } + + ParseOneResponse( responseGroupName, newGroup, &groupResponseParams ); } +} //----------------------------------------------------------------------------- From efec7ab4dbbc01989ff77133f1974943b61ed826 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Tue, 9 Mar 2021 12:37:08 -0600 Subject: [PATCH 006/378] Added Mapbase's enhanced save/restore to new response system + moved aound rr_dumphashinfo code so that it has access to default response system --- sp/src/game/shared/ai_responsesystem_new.cpp | 78 +++++++++++++++++++ .../responserules/runtime/response_system.cpp | 7 -- .../runtime/response_types_internal.cpp | 18 +++++ .../runtime/response_types_internal.h | 1 + 4 files changed, 97 insertions(+), 7 deletions(-) diff --git a/sp/src/game/shared/ai_responsesystem_new.cpp b/sp/src/game/shared/ai_responsesystem_new.cpp index 80cbcca6..efa6d27c 100644 --- a/sp/src/game/shared/ai_responsesystem_new.cpp +++ b/sp/src/game/shared/ai_responsesystem_new.cpp @@ -46,6 +46,12 @@ extern ConVar rr_debugrule; // ( "rr_debugrule", "", FCVAR_NONE, "If set to the extern ConVar rr_dumpresponses; // ( "rr_dumpresponses", "0", FCVAR_NONE, "Dump all response_rules.txt and rules (requires restart)" ); extern ConVar rr_debugresponseconcept; // ( "rr_debugresponseconcept", "", FCVAR_NONE, "If set, rr_debugresponses will print only responses testing for the specified concept" ); +static void CC_RR_DumpHashInfo( const CCommand &args ); + +#ifdef MAPBASE +ConVar rr_enhanced_saverestore( "rr_enhanced_saverestore", "0", FCVAR_NONE, "Enables enhanced save/restore capabilities for the Response System." ); +#endif + extern ISceneFileCache *scenefilecache; extern INetworkStringTable *g_pStringTableClientSideChoreoScenes; @@ -622,6 +628,9 @@ public: Precache(); } +#ifdef MAPBASE + if (!rr_enhanced_saverestore.GetBool() || gpGlobals->eLoadType != MapLoad_Transition) +#endif ResetResponseGroups(); } @@ -736,6 +745,14 @@ CON_COMMAND( rr_reloadresponsesystems, "Reload all response system scripts." ) defaultresponsesytem.ReloadAllResponseSystems(); } +#if RR_DUMPHASHINFO_ENABLED +static void CC_RR_DumpHashInfo( const CCommand &args ) +{ + defaultresponsesytem.m_RulePartitions.PrintBucketInfo( &defaultresponsesytem ); +} +static ConCommand rr_dumphashinfo( "rr_dumphashinfo", CC_RR_DumpHashInfo, "Statistics on primary hash bucketing of response rule partitions"); +#endif + #ifdef MAPBASE // Designed for extern magic, this gives the <, >, etc. of response system criteria to the outside world. // Mostly just used for Matcher_Match in matchers.h. @@ -1021,6 +1038,37 @@ public: pSave->EndBlock(); } + +#ifdef MAPBASE + // Enhanced Response System save/restore + int count2 = 0; + if (rr_enhanced_saverestore.GetBool()) + { + // Rule state save/load + count2 = rs.m_RulePartitions.Count(); + pSave->WriteInt( &count2 ); + for ( ResponseRulePartition::tIndex idx = rs.m_RulePartitions.First() ; + rs.m_RulePartitions.IsValid(idx) ; + idx = rs.m_RulePartitions.Next(idx) ) + { + pSave->StartBlock( "Rule" ); + + pSave->WriteString( rs.m_RulePartitions.GetElementName( idx ) ); + const Rule &rule = rs.m_RulePartitions[ idx ]; + + bool bEnabled = rule.m_bEnabled; + Msg( "%s: %i\n", rs.m_RulePartitions.GetElementName( idx ), idx ); + pSave->WriteBool( &bEnabled ); + + pSave->EndBlock(); + } + } + else + { + // Indicate this isn't using enhanced save/restore + pSave->WriteInt( &count2 ); + } +#endif } void Restore( IRestore *pRestore, bool createPlayers ) @@ -1084,6 +1132,36 @@ public: pRestore->EndBlock(); } + +#ifdef MAPBASE + // Enhanced Response System save/restore + count = pRestore->ReadInt(); + for ( int i = 0; i < count; ++i ) + { + char szRuleBlockName[SIZE_BLOCK_NAME_BUF]; + pRestore->StartBlock( szRuleBlockName ); + if ( !Q_stricmp( szRuleBlockName, "Rule" ) ) + { + char groupname[ 256 ]; + pRestore->ReadString( groupname, sizeof( groupname ), 0 ); + + // Try and find it + Rule *rule = rs.m_RulePartitions.FindByName( groupname ); + if ( rule ) + { + bool bEnabled; + pRestore->ReadBool( &bEnabled ); + rule->m_bEnabled = bEnabled; + } + else + { + Warning("Warning: Can't find rule %s\n", groupname); + } + } + + pRestore->EndBlock(); + } +#endif } private: diff --git a/sp/src/responserules/runtime/response_system.cpp b/sp/src/responserules/runtime/response_system.cpp index 94660c58..37d5f0d9 100644 --- a/sp/src/responserules/runtime/response_system.cpp +++ b/sp/src/responserules/runtime/response_system.cpp @@ -21,7 +21,6 @@ using namespace ResponseRules; static void CC_RR_Debug_ResponseConcept_Exclude( const CCommand &args ); static ConCommand rr_debug_responseconcept_exclude( "rr_debugresponseconcept_exclude", CC_RR_Debug_ResponseConcept_Exclude, "Set a list of concepts to exclude from rr_debugresponseconcept. Separate multiple concepts with spaces. Call with no arguments to see current list. Call 'rr_debug_responseconcept_exclude !' to reset."); -static void CC_RR_DumpHashInfo( const CCommand &args ); namespace ResponseRules { @@ -2809,12 +2808,6 @@ static void CC_RR_Debug_ResponseConcept_Exclude( const CCommand &args ) } } #if RR_DUMPHASHINFO_ENABLED -static void CC_RR_DumpHashInfo( const CCommand &args ) -{ - defaultresponsesytem.m_InstancedSystems[0]->m_RulePartitions.PrintBucketInfo( defaultresponsesytem.m_InstancedSystems[0] ); -} -static ConCommand rr_dumphashinfo( "rr_dumphashinfo", CC_RR_DumpHashInfo, "Statistics on primary hash bucketing of response rule partitions"); - void ResponseRulePartition::PrintBucketInfo( CResponseSystem *pSys ) { struct bucktuple_t diff --git a/sp/src/responserules/runtime/response_types_internal.cpp b/sp/src/responserules/runtime/response_types_internal.cpp index 2d11bdd2..72e7eca5 100644 --- a/sp/src/responserules/runtime/response_types_internal.cpp +++ b/sp/src/responserules/runtime/response_types_internal.cpp @@ -47,6 +47,24 @@ char const *ResponseRulePartition::GetElementName( const tIndex &i ) const } +Rule *ResponseRulePartition::FindByName( char const *name ) const +{ + int count; + + for ( int bukkit = 0 ; bukkit < N_RESPONSE_PARTITIONS ; ++bukkit ) + { + count = m_RuleParts[bukkit].Count(); + for ( int i = 0; i < count; ++i ) + { + if (V_strncmp( m_RuleParts[bukkit].GetElementName(i), name, CRR_Response::MAX_RULE_NAME ) == 0) + return m_RuleParts[bukkit][i]; + } + } + + return NULL; +} + + int ResponseRulePartition::Count( void ) { int count = 0 ; diff --git a/sp/src/responserules/runtime/response_types_internal.h b/sp/src/responserules/runtime/response_types_internal.h index 99e766fe..5222c80d 100644 --- a/sp/src/responserules/runtime/response_types_internal.h +++ b/sp/src/responserules/runtime/response_types_internal.h @@ -436,6 +436,7 @@ namespace ResponseRules inline Rule &operator[]( tIndex idx ); int Count( void ); // number of elements inside, but you can't iterate from 0 to this char const *GetElementName( const tIndex &i ) const; + Rule *FindByName( char const *name ) const; /// given a dictionary and an element number inside that dict, /// return a tIndex From 8966462fee06984a523f6d5fb81d6fce3f545315 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Tue, 9 Mar 2021 12:39:13 -0600 Subject: [PATCH 007/378] Stabilized implementation of some Mapbase code in the new response system --- sp/src/game/shared/ai_responsesystem_new.cpp | 23 ++++++++++++++++++- sp/src/public/responserules/response_types.h | 4 +++- .../runtime/response_types_internal.h | 3 ++- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/sp/src/game/shared/ai_responsesystem_new.cpp b/sp/src/game/shared/ai_responsesystem_new.cpp index efa6d27c..e703775f 100644 --- a/sp/src/game/shared/ai_responsesystem_new.cpp +++ b/sp/src/game/shared/ai_responsesystem_new.cpp @@ -974,7 +974,28 @@ bool LoadResponseSystemFile(const char *scriptfile) delete rs; */ - defaultresponsesytem.LoadFromBuffer(scriptfile, (const char *)buf.PeekGet()); + // HACKHACK: This is not very efficient + /* + CInstancedResponseSystem *tempSys = new CInstancedResponseSystem( scriptfile ); + if ( tempSys && tempSys->Init() ) + { + tempSys->Precache(); + + for ( ResponseRulePartition::tIndex idx = tempSys->m_RulePartitions.First() ; + tempSys->m_RulePartitions.IsValid(idx) ; + idx = tempSys->m_RulePartitions.Next(idx) ) + { + Rule &rule = tempSys->m_RulePartitions[idx]; + tempSys->CopyRuleFrom( &rule, idx, &defaultresponsesytem ); + } + + tempSys->Release(); + } + */ + + // HACKHACK: This is even less efficient + defaultresponsesytem.LoadFromBuffer( scriptfile, (const char *)buf.PeekGet() ); + defaultresponsesytem.Precache(); return true; } diff --git a/sp/src/public/responserules/response_types.h b/sp/src/public/responserules/response_types.h index 821b0c57..4ec62cee 100644 --- a/sp/src/public/responserules/response_types.h +++ b/sp/src/public/responserules/response_types.h @@ -111,7 +111,9 @@ namespace ResponseRules // CResponseSystem::BuildDispatchTables() - AI_ResponseSystem.cpp (with their own funcs for m_RuleDispatch) // CRR_Response::Describe() - rr_response.cpp // CAI_Expresser::SpeakDispatchResponse() - ai_speech.cpp - enum + // + // Also mind that this is 8-bit + enum : uint8 { APPLYCONTEXT_SELF = (1 << 0), // Included for contexts that apply to both self and something else APPLYCONTEXT_WORLD = (1 << 1), // Apply to world diff --git a/sp/src/responserules/runtime/response_types_internal.h b/sp/src/responserules/runtime/response_types_internal.h index 5222c80d..20cc9d54 100644 --- a/sp/src/responserules/runtime/response_types_internal.h +++ b/sp/src/responserules/runtime/response_types_internal.h @@ -340,7 +340,8 @@ namespace ResponseRules uint8 m_nForceWeight; #ifdef MAPBASE - int m_iContextFlags; + // TODO: Could this cause any issues with the code optimization? + uint8 m_iContextFlags; #else bool m_bApplyContextToWorld : 1; #endif From 24ac0806081ac221969c5cddeb7f5d665247813c Mon Sep 17 00:00:00 2001 From: Blixibon Date: Wed, 10 Mar 2021 02:10:22 -0600 Subject: [PATCH 008/378] Added legacy response context operators --- sp/src/game/server/ai_speech_new.cpp | 107 +++++++++++++++++++++++++++ sp/src/game/server/ai_speech_new.h | 28 +++++++ 2 files changed, 135 insertions(+) diff --git a/sp/src/game/server/ai_speech_new.cpp b/sp/src/game/server/ai_speech_new.cpp index a7c4ac729..f04e6d2b 100644 --- a/sp/src/game/server/ai_speech_new.cpp +++ b/sp/src/game/server/ai_speech_new.cpp @@ -165,8 +165,20 @@ CConceptHistoriesDataOps g_ConceptHistoriesSaveDataOps; RR::CApplyContextOperator RR::sm_OpCopy(0); // " RR::CIncrementOperator RR::sm_OpIncrement(2); // "++" RR::CDecrementOperator RR::sm_OpDecrement(2); // "--" +#ifdef MAPBASE +RR::CMultiplyOperator RR::sm_OpMultiply(2); // "**" +RR::CDivideOperator RR::sm_OpDivide(2); // "/=" +#endif RR::CToggleOperator RR::sm_OpToggle(1); // "!" +#ifdef MAPBASE +// LEGACY - See below +RR::CIncrementOperator RR::sm_OpLegacyIncrement(1); // "+" +RR::CDecrementOperator RR::sm_OpLegacyDecrement(1); // "-" +RR::CMultiplyOperator RR::sm_OpLegacyMultiply(1); // "*" +RR::CDivideOperator RR::sm_OpLegacyDivide(1); // "/" +#endif + RR::CApplyContextOperator *RR::CApplyContextOperator::FindOperator( const char *pContextString ) { if ( !pContextString || pContextString[0] == 0 ) @@ -174,6 +186,65 @@ RR::CApplyContextOperator *RR::CApplyContextOperator::FindOperator( const char * return &sm_OpCopy; } +#ifdef MAPBASE + // This is one of those freak coincidences where Mapbase implemented its own context operators with no knowledge of context operators from later versions of the engine. + // Mapbase's context operators only required *one* operator character (e.g. '+' as opposed to '++') and supported multiplication and division. + // Although Valve's system now replaces Mapbase's system, multiplication and division have been added and maintaining the old syntax is needed for legacy support. + // That being said, it's believed that almost nobody knew that Mapbase supported context operators in the first place, so there might not be much legacy to support anyway. + switch (pContextString[0]) + { + case '+': + { + if (pContextString[1] != '+') + { + Warning( "\"%s\" needs another '+' to qualify as a proper operator. This code is regarding it as an operator anyway for legacy support, which might be going away soon!!!\n", pContextString ); + return &sm_OpLegacyIncrement; + } + else if (pContextString[2] == '\0') + break; + return &sm_OpIncrement; + } + case '-': + { + if (pContextString[1] != '-') + { + Warning( "\"%s\" needs another '-' to qualify as a proper operator. This code is regarding it as an operator anyway for legacy support, which might be going away soon!!!\n", pContextString ); + return &sm_OpLegacyDecrement; + } + else if (pContextString[2] == '\0') + break; + return &sm_OpIncrement; + } + case '*': + { + if (pContextString[1] != '*') + { + Warning( "\"%s\" needs another '*' to qualify as a proper operator. This code is regarding it as an operator anyway for legacy support, which might be going away soon!!!\n", pContextString ); + return &sm_OpLegacyMultiply; + } + else if (pContextString[2] == '\0') + break; + return &sm_OpMultiply; + } + case '/': + { + if (pContextString[1] != '=') + { + Warning( "\"%s\" needs a '=' after the '/' to qualify as a proper operator. This code is regarding it as an operator anyway for legacy support, which might be going away soon!!!\n", pContextString ); + return &sm_OpLegacyDivide; + } + else if (pContextString[2] == '\0') + break; + return &sm_OpDivide; + } break; + case '!': + { + return &sm_OpToggle; + } + } + + return &sm_OpCopy; +#else if ( pContextString[0] == '+' && pContextString [1] == '+' && pContextString[2] != '\0' ) { return &sm_OpIncrement; @@ -182,6 +253,16 @@ RR::CApplyContextOperator *RR::CApplyContextOperator::FindOperator( const char * { return &sm_OpDecrement; } +#ifdef MAPBASE + else if ( pContextString[0] == '*' && pContextString [1] == '*' && pContextString[2] != '\0' ) + { + return &sm_OpMultiply; + } + else if ( pContextString[0] == '/' && pContextString [1] == '=' && pContextString[2] != '\0' ) + { + return &sm_OpDivide; + } +#endif else if ( pContextString[0] == '!' ) { return &sm_OpToggle; @@ -190,6 +271,7 @@ RR::CApplyContextOperator *RR::CApplyContextOperator::FindOperator( const char * { return &sm_OpCopy; } +#endif } // default is just copy @@ -228,6 +310,31 @@ bool RR::CDecrementOperator::Apply( const char *pOldValue, const char *pOperator return true; } +#ifdef MAPBASE +bool RR::CMultiplyOperator::Apply( const char *pOldValue, const char *pOperator, char *pNewValue, int pNewValBufSize ) +{ + Assert( pOperator[0] == '*' && pOperator[1] == '*' ); + // parse out the old value as a numeric + int nOld = pOldValue ? V_atoi(pOldValue) : 0; + int nInc = V_atoi( pOperator+m_nSkipChars ); + V_snprintf( pNewValue, pNewValBufSize, "%d", nOld*nInc ); + return true; +} + +bool RR::CDivideOperator::Apply( const char *pOldValue, const char *pOperator, char *pNewValue, int pNewValBufSize ) +{ + Assert( pOperator[0] == '/' && pOperator[1] == '=' ); + // parse out the old value as a numeric + int nOld = pOldValue ? V_atoi(pOldValue) : 0; + int nInc = V_atoi( pOperator+m_nSkipChars ); + if (nInc == 0) + V_strncpy( pNewValue, "0", pNewValBufSize ); + else + V_snprintf( pNewValue, pNewValBufSize, "%d", nOld/nInc ); + return true; +} +#endif + bool RR::CToggleOperator::Apply( const char *pOldValue, const char *pOperator, char *pNewValue, int pNewValBufSize ) { Assert( pOperator[0] == '!' ); diff --git a/sp/src/game/server/ai_speech_new.h b/sp/src/game/server/ai_speech_new.h index e3c895be..fec4f8c2 100644 --- a/sp/src/game/server/ai_speech_new.h +++ b/sp/src/game/server/ai_speech_new.h @@ -611,6 +611,22 @@ namespace RR virtual bool Apply( const char *pOldValue, const char *pOperator, char *pNewValue, int pNewValBufSize ); }; +#ifdef MAPBASE + class CMultiplyOperator : public CApplyContextOperator + { + public: + inline CMultiplyOperator( int nSkipChars ) : CApplyContextOperator(nSkipChars) {}; + virtual bool Apply( const char *pOldValue, const char *pOperator, char *pNewValue, int pNewValBufSize ); + }; + + class CDivideOperator : public CApplyContextOperator + { + public: + inline CDivideOperator( int nSkipChars ) : CApplyContextOperator(nSkipChars) {}; + virtual bool Apply( const char *pOldValue, const char *pOperator, char *pNewValue, int pNewValBufSize ); + }; +#endif + class CToggleOperator : public CApplyContextOperator { public: @@ -622,7 +638,19 @@ namespace RR extern CApplyContextOperator sm_OpCopy; extern CIncrementOperator sm_OpIncrement; extern CDecrementOperator sm_OpDecrement; +#ifdef MAPBASE + extern CMultiplyOperator sm_OpMultiply; + extern CDivideOperator sm_OpDivide; +#endif extern CToggleOperator sm_OpToggle; + +#ifdef MAPBASE + // LEGACY - See CApplyContextOperator::FindOperator() + extern CIncrementOperator sm_OpLegacyIncrement; + extern CDecrementOperator sm_OpLegacyDecrement; + extern CMultiplyOperator sm_OpLegacyMultiply; + extern CDivideOperator sm_OpLegacyDivide; +#endif }; From e10a4d6613d9b8327d54817344f4fd8525e8050d Mon Sep 17 00:00:00 2001 From: Blixibon Date: Wed, 10 Mar 2021 02:11:39 -0600 Subject: [PATCH 009/378] Added VScript file response to base response dispatch code --- sp/src/game/server/baseentity.cpp | 9 +++++++-- sp/src/game/server/hl2/env_speaker.cpp | 9 ++++++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/sp/src/game/server/baseentity.cpp b/sp/src/game/server/baseentity.cpp index dff5ee7f..5302ee6a 100644 --- a/sp/src/game/server/baseentity.cpp +++ b/sp/src/game/server/baseentity.cpp @@ -9243,10 +9243,15 @@ void CBaseEntity::DispatchResponse( const char *conceptName ) CAI_Expresser::FireEntIOFromResponse(response, this); break; } -#ifdef MAPBASE +#ifdef MAPBASE_VSCRIPT case ResponseRules::RESPONSE_VSCRIPT: { - RunScript( response, "ResponseScript" ); + CAI_Expresser::RunScriptResponse( this, response, &set, false ); + break; + } + case ResponseRules::RESPONSE_VSCRIPT_FILE: + { + CAI_Expresser::RunScriptResponse( this, response, &set, true ); break; } #endif diff --git a/sp/src/game/server/hl2/env_speaker.cpp b/sp/src/game/server/hl2/env_speaker.cpp index 25a65017..ad46a25c 100644 --- a/sp/src/game/server/hl2/env_speaker.cpp +++ b/sp/src/game/server/hl2/env_speaker.cpp @@ -286,11 +286,18 @@ void CSpeaker::DispatchResponse( const char *conceptName ) CAI_Expresser::FireEntIOFromResponse( response, pTarget ); break; } +#ifdef MAPBASE_VSCRIPT case ResponseRules::RESPONSE_VSCRIPT: { - pTarget->RunScript( response, "ResponseScript" ); + CAI_Expresser::RunScriptResponse( pTarget, response, &set, false ); break; } + case ResponseRules::RESPONSE_VSCRIPT_FILE: + { + CAI_Expresser::RunScriptResponse( pTarget, response, &set, true ); + break; + } +#endif default: break; } From 4d3f51a7207d5a91de836648202d370b1ed172a2 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Wed, 17 Mar 2021 10:45:31 -0500 Subject: [PATCH 010/378] Fixed a compile error from when NEW_RESPONSE_SYSTEM is disabled --- sp/src/game/server/basemultiplayerplayer.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sp/src/game/server/basemultiplayerplayer.cpp b/sp/src/game/server/basemultiplayerplayer.cpp index d5a99514..d75ec627 100644 --- a/sp/src/game/server/basemultiplayerplayer.cpp +++ b/sp/src/game/server/basemultiplayerplayer.cpp @@ -96,7 +96,10 @@ bool CBaseMultiplayerPlayer::SpeakConcept( AI_Response &response, int iConcept ) concept.SetSpeaker(this); return FindResponse( response, concept ); #else - return SpeakFindResponse( response, g_pszMPConcepts[iConcept] ); + AI_Response *pResponse = SpeakFindResponse( g_pszMPConcepts[iConcept] ); + if (pResponse) + response = *pResponse; + return pResponse != NULL; #endif } From 4b8da761ce7d2da32a5b684e50acdff56e4eef62 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Wed, 17 Mar 2021 16:50:24 -0500 Subject: [PATCH 011/378] Added base Mapbase matchers to tier1 so that the response system library can access them --- sp/src/game/shared/mapbase/matchers.cpp | 185 --------------- sp/src/game/shared/mapbase/matchers.h | 45 +--- sp/src/public/tier1/mapbase_matchers_base.h | 58 +++++ .../responserules/runtime/response_system.cpp | 10 + sp/src/tier1/mapbase_matchers_base.cpp | 217 ++++++++++++++++++ sp/src/tier1/tier1.vpc | 2 + 6 files changed, 289 insertions(+), 228 deletions(-) create mode 100644 sp/src/public/tier1/mapbase_matchers_base.h create mode 100644 sp/src/tier1/mapbase_matchers_base.cpp diff --git a/sp/src/game/shared/mapbase/matchers.cpp b/sp/src/game/shared/mapbase/matchers.cpp index f1f1d26b..b8b915f4 100644 --- a/sp/src/game/shared/mapbase/matchers.cpp +++ b/sp/src/game/shared/mapbase/matchers.cpp @@ -10,16 +10,6 @@ #include "matchers.h" #include "fmtstr.h" -// glibc (Linux) uses these tokens when including , so we must not #define them -#undef max -#undef min -#include -#undef MINMAX_H -#include "minmax.h" - -ConVar mapbase_wildcards_enabled("mapbase_wildcards_enabled", "1", FCVAR_NONE, "Toggles Mapbase's '?' wildcard and true '*' features. Useful for maps that have '?' in their targetnames."); -ConVar mapbase_regex_enabled("mapbase_regex_enabled", "1", FCVAR_NONE, "Toggles Mapbase's regex matching handover."); - #ifdef CLIENT_DLL // FIXME: There is no clientside equivalent to the RS code static bool ResponseSystemCompare(const char *criterion, const char *value) { return Matcher_NamesMatch(criterion, value); } @@ -47,181 +37,6 @@ bool Matcher_Match(const char *pszQuery, const char *szValue) bool Matcher_Match(const char *pszQuery, int iValue) { return Matcher_Match(pszQuery, CNumStr(iValue)); } bool Matcher_Match(const char *pszQuery, float flValue) { return Matcher_Match(pszQuery, CNumStr(flValue)); } -// ------------------------------------------------------------------------------- -// ------------------------------------------------------------------------------- - -// The recursive part of Mapbase's modified version of Valve's NamesMatch(). -bool Matcher_RunCharCompare(const char *pszQuery, const char *szValue) -{ - // This matching model is based off of the ASW SDK - while ( *szValue && *pszQuery ) - { - char cName = *szValue; - char cQuery = *pszQuery; - if ( cName != cQuery && tolower(cName) != tolower(cQuery) ) // people almost always use lowercase, so assume that first - { - // Now we'll try the new and improved Mapbase wildcards! - switch (*pszQuery) - { - case '*': - { - // Return true at classic trailing * - if ( *(pszQuery+1) == 0 ) - return true; - - if (mapbase_wildcards_enabled.GetBool()) - { - // There's text after this * which we need to test. - // This recursion allows for multiple wildcards - int vlen = Q_strlen(szValue); - ++pszQuery; - for (int i = 0; i < vlen; i++) - { - if (Matcher_RunCharCompare(pszQuery, szValue + i)) - return true; - } - } - return false; - } break; - case '?': - // Just skip if we're capable of lazy wildcards - if (mapbase_wildcards_enabled.GetBool()) - break; - default: - return false; - } - } - ++szValue; - ++pszQuery; - } - - // Include a classic trailing * check for when szValue is something like "value" and pszQuery is "value*" - return ( ( *pszQuery == 0 && *szValue == 0 ) || *pszQuery == '*' ); -} - -// Regular expressions based off of the std library. -// The C++ is strong in this one. -bool Matcher_Regex(const char *pszQuery, const char *szValue) -{ - std::regex regex; - - // Since I can't find any other way to check for valid regex, - // use a try-catch here to see if it throws an exception. - try { regex = std::regex(pszQuery); } - catch (std::regex_error &e) - { - Msg("Invalid regex \"%s\" (%s)\n", pszQuery, e.what()); - return false; - } - - std::match_results results; - bool bMatch = std::regex_match( szValue, results, regex ); - if (!bMatch) - return false; - - // Only match the *whole* string - return Q_strlen(results.str(0).c_str()) == Q_strlen(szValue); -} - -// The entry point for Mapbase's modified version of Valve's NamesMatch(). -bool Matcher_NamesMatch(const char *pszQuery, const char *szValue) -{ - if ( szValue == NULL ) - return (*pszQuery == 0 || *pszQuery == '*'); - - // If the pointers are identical, we're identical - if ( szValue == pszQuery ) - return true; - - // Check for regex - if ( *pszQuery == '@' && mapbase_regex_enabled.GetBool() ) - { - // Make sure it has a forward slash - // (prevents confusion with instance fixup escape) - if (*(pszQuery+1) == '/') - { - return Matcher_Regex( pszQuery+2, szValue ); - } - } - - return Matcher_RunCharCompare( pszQuery, szValue ); -} - -bool Matcher_NamesMatch_Classic(const char *pszQuery, const char *szValue) -{ - if ( szValue == NULL ) - return (!pszQuery || *pszQuery == 0 || *pszQuery == '*'); - - // If the pointers are identical, we're identical - if ( szValue == pszQuery ) - return true; - - while ( *szValue && *pszQuery ) - { - unsigned char cName = *szValue; - unsigned char cQuery = *pszQuery; - // simple ascii case conversion - if ( cName == cQuery ) - ; - else if ( cName - 'A' <= (unsigned char)'Z' - 'A' && cName - 'A' + 'a' == cQuery ) - ; - else if ( cName - 'a' <= (unsigned char)'z' - 'a' && cName - 'a' + 'A' == cQuery ) - ; - else - break; - ++szValue; - ++pszQuery; - } - - if ( *pszQuery == 0 && *szValue == 0 ) - return true; - - // @TODO (toml 03-18-03): Perhaps support real wildcards. Right now, only thing supported is trailing * - if ( *pszQuery == '*' ) - return true; - - return false; -} - -bool Matcher_NamesMatch_MutualWildcard(const char *pszQuery, const char *szValue) -{ - if ( szValue == NULL ) - return (!pszQuery || *pszQuery == 0 || *pszQuery == '*'); - - if ( pszQuery == NULL ) - return (!szValue || *szValue == 0 || *szValue == '*'); - - // If the pointers are identical, we're identical - if ( szValue == pszQuery ) - return true; - - while ( *szValue && *pszQuery ) - { - unsigned char cName = *szValue; - unsigned char cQuery = *pszQuery; - // simple ascii case conversion - if ( cName == cQuery ) - ; - else if ( cName - 'A' <= (unsigned char)'Z' - 'A' && cName - 'A' + 'a' == cQuery ) - ; - else if ( cName - 'a' <= (unsigned char)'z' - 'a' && cName - 'a' + 'A' == cQuery ) - ; - else - break; - ++szValue; - ++pszQuery; - } - - if ( *pszQuery == 0 && *szValue == 0 ) - return true; - - // @TODO (toml 03-18-03): Perhaps support real wildcards. Right now, only thing supported is trailing * - if ( *pszQuery == '*' || *szValue == '*' ) - return true; - - return false; -} - // Matcher_Compare is a deprecated alias originally used when Matcher_Match didn't support wildcards. /* bool Matcher_Compare(const char *pszQuery, const char *szValue) diff --git a/sp/src/game/shared/mapbase/matchers.h b/sp/src/game/shared/mapbase/matchers.h index 52e8cc1a..7d86ad63 100644 --- a/sp/src/game/shared/mapbase/matchers.h +++ b/sp/src/game/shared/mapbase/matchers.h @@ -11,8 +11,7 @@ #pragma once #endif - -#define MAPBASE_MATCHERS 1 +#include "tier1/mapbase_matchers_base.h" // Compares with != and the like. Basically hijacks the response system matching. // This also loops back around to Matcher_NamesMatch. @@ -22,47 +21,7 @@ bool Matcher_Match( const char *pszQuery, const char *szValue ); bool Matcher_Match( const char *pszQuery, int iValue ); bool Matcher_Match( const char *pszQuery, float flValue ); -// Regular expressions based off of the std library. -// pszQuery = The regex text. -// szValue = The value that should be matched. -bool Matcher_Regex( const char *pszQuery, const char *szValue ); - -// Compares two strings with support for wildcards or regex. This code is an expanded version of baseentity.cpp's NamesMatch(). -// pszQuery = The value that should have the wildcard. -// szValue = The value tested against the query. -// Use Matcher_Match if you want <, !=, etc. as well. -bool Matcher_NamesMatch( const char *pszQuery, const char *szValue ); - -// Identical to baseentity.cpp's original NamesMatch(). -// pszQuery = The value that should have the wildcard. -// szValue = The value tested against the query. -bool Matcher_NamesMatch_Classic( const char *pszQuery, const char *szValue ); - -// Identical to Matcher_NamesMatch_Classic(), but either value could use a wildcard. -// pszQuery = The value that serves as the query. This value can use wildcards. -// szValue = The value tested against the query. This value can use wildcards as well. -bool Matcher_NamesMatch_MutualWildcard( const char *pszQuery, const char *szValue ); - // Deprecated; do not use -static inline bool Matcher_Compare( const char *pszQuery, const char *szValue ) { return Matcher_Match( pszQuery, szValue ); } - -// Taken from the Response System. -// Checks if the specified string appears to be a number of some sort. -static bool AppearsToBeANumber( char const *token ) -{ - if ( atof( token ) != 0.0f ) - return true; - - char const *p = token; - while ( *p ) - { - if ( *p != '0' ) - return false; - - p++; - } - - return true; -} +//static inline bool Matcher_Compare( const char *pszQuery, const char *szValue ) { return Matcher_Match( pszQuery, szValue ); } #endif diff --git a/sp/src/public/tier1/mapbase_matchers_base.h b/sp/src/public/tier1/mapbase_matchers_base.h new file mode 100644 index 00000000..74b2cbc9 --- /dev/null +++ b/sp/src/public/tier1/mapbase_matchers_base.h @@ -0,0 +1,58 @@ +//========= Mapbase - https://github.com/mapbase-source/source-sdk-2013 ================= +// +// Purpose: General matching functions for things like wildcards and !=. +// +// $NoKeywords: $ +//============================================================================= + +#ifndef MAPBASE_MATCHERS_BASE_H +#define MAPBASE_MATCHERS_BASE_H +#ifdef _WIN32 +#pragma once +#endif + +#include + +#define MAPBASE_MATCHERS 1 + +// Regular expressions based off of the std library. +// pszQuery = The regex text. +// szValue = The value that should be matched. +bool Matcher_Regex( const char *pszQuery, const char *szValue ); + +// Compares two strings with support for wildcards or regex. This code is an expanded version of baseentity.cpp's NamesMatch(). +// pszQuery = The value that should have the wildcard. +// szValue = The value tested against the query. +// Use Matcher_Match if you want <, !=, etc. as well. +bool Matcher_NamesMatch( const char *pszQuery, const char *szValue ); + +// Identical to baseentity.cpp's original NamesMatch(). +// pszQuery = The value that should have the wildcard. +// szValue = The value tested against the query. +bool Matcher_NamesMatch_Classic( const char *pszQuery, const char *szValue ); + +// Identical to Matcher_NamesMatch_Classic(), but either value could use a wildcard. +// pszQuery = The value that serves as the query. This value can use wildcards. +// szValue = The value tested against the query. This value can use wildcards as well. +bool Matcher_NamesMatch_MutualWildcard( const char *pszQuery, const char *szValue ); + +// Taken from the Response System. +// Checks if the specified string appears to be a number of some sort. +static bool AppearsToBeANumber( char const *token ) +{ + if ( atof( token ) != 0.0f ) + return true; + + char const *p = token; + while ( *p ) + { + if ( *p != '0' ) + return false; + + p++; + } + + return true; +} + +#endif diff --git a/sp/src/responserules/runtime/response_system.cpp b/sp/src/responserules/runtime/response_system.cpp index 37d5f0d9..60fedddb 100644 --- a/sp/src/responserules/runtime/response_system.cpp +++ b/sp/src/responserules/runtime/response_system.cpp @@ -289,6 +289,7 @@ void CResponseSystem::ResolveToken( Matcher& matcher, char *token, size_t bufsiz } +#ifndef MAPBASE // Already in mapbase_matchers_base static bool AppearsToBeANumber( char const *token ) { if ( atof( token ) != 0.0f ) @@ -305,6 +306,7 @@ static bool AppearsToBeANumber( char const *token ) return true; } +#endif void CResponseSystem::ComputeMatcher( Criteria *c, Matcher& matcher ) { @@ -510,7 +512,11 @@ bool CResponseSystem::CompareUsingMatcher( const char *setValue, Matcher& m, boo } else { +#ifdef MAPBASE + if ( Matcher_NamesMatch( m.GetToken(), setValue ) ) +#else if ( !Q_stricmp( setValue, m.GetToken() ) ) +#endif return false; } @@ -527,7 +533,11 @@ bool CResponseSystem::CompareUsingMatcher( const char *setValue, Matcher& m, boo return v == (float)atof( m.GetToken() ); } +#ifdef MAPBASE + return Matcher_NamesMatch( m.GetToken(), setValue ); +#else return !Q_stricmp( setValue, m.GetToken() ) ? true : false; +#endif } bool CResponseSystem::Compare( const char *setValue, Criteria *c, bool verbose /*= false*/ ) diff --git a/sp/src/tier1/mapbase_matchers_base.cpp b/sp/src/tier1/mapbase_matchers_base.cpp new file mode 100644 index 00000000..5f10814e --- /dev/null +++ b/sp/src/tier1/mapbase_matchers_base.cpp @@ -0,0 +1,217 @@ +//========= Mapbase - https://github.com/mapbase-source/source-sdk-2013 ================= +// +// Purpose: General matching functions for things like wildcards and !=. +// +// $NoKeywords: $ +//============================================================================= + +#include "mapbase_matchers_base.h" +#include "convar.h" + +// glibc (Linux) uses these tokens when including , so we must not #define them +#undef max +#undef min +#include +#undef MINMAX_H +#include "minmax.h" + +ConVar mapbase_wildcards_enabled("mapbase_wildcards_enabled", "1", FCVAR_NONE, "Toggles Mapbase's '?' wildcard and true '*' features. Useful for maps that have '?' in their targetnames."); +ConVar mapbase_regex_enabled("mapbase_regex_enabled", "1", FCVAR_NONE, "Toggles Mapbase's regex matching handover."); + +//============================================================================= +// These are the "matchers" that compare with wildcards ("any*" for text starting with "any") +// and operators (<3 for numbers less than 3). +// +// Matcher_Regex - Uses regex functions from the std library. +// Matcher_NamesMatch - Based on Valve's original NamesMatch function, using wildcards and regex. +// +// AppearsToBeANumber - Response System-based function which checks if the string might be a number. +//============================================================================= + +// The recursive part of Mapbase's modified version of Valve's NamesMatch(). +bool Matcher_RunCharCompare(const char *pszQuery, const char *szValue) +{ + // This matching model is based off of the ASW SDK + while ( *szValue && *pszQuery ) + { + char cName = *szValue; + char cQuery = *pszQuery; + if ( cName != cQuery && tolower(cName) != tolower(cQuery) ) // people almost always use lowercase, so assume that first + { + // Now we'll try the new and improved Mapbase wildcards! + switch (*pszQuery) + { + case '*': + { + // Return true at classic trailing * + if ( *(pszQuery+1) == 0 ) + return true; + + if (mapbase_wildcards_enabled.GetBool()) + { + // There's text after this * which we need to test. + // This recursion allows for multiple wildcards + int vlen = Q_strlen(szValue); + ++pszQuery; + for (int i = 0; i < vlen; i++) + { + if (Matcher_RunCharCompare(pszQuery, szValue + i)) + return true; + } + } + return false; + } break; + case '?': + // Just skip if we're capable of lazy wildcards + if (mapbase_wildcards_enabled.GetBool()) + break; + default: + return false; + } + } + ++szValue; + ++pszQuery; + } + + // Include a classic trailing * check for when szValue is something like "value" and pszQuery is "value*" + return ( ( *pszQuery == 0 && *szValue == 0 ) || *pszQuery == '*' ); +} + +// Regular expressions based off of the std library. +// The C++ is strong in this one. +bool Matcher_Regex(const char *pszQuery, const char *szValue) +{ + std::regex regex; + + // Since I can't find any other way to check for valid regex, + // use a try-catch here to see if it throws an exception. + try { regex = std::regex(pszQuery); } + catch (std::regex_error &e) + { + Msg("Invalid regex \"%s\" (%s)\n", pszQuery, e.what()); + return false; + } + + std::match_results results; + bool bMatch = std::regex_match( szValue, results, regex ); + if (!bMatch) + return false; + + // Only match the *whole* string + return Q_strlen(results.str(0).c_str()) == Q_strlen(szValue); +} + +// The entry point for Mapbase's modified version of Valve's NamesMatch(). +bool Matcher_NamesMatch(const char *pszQuery, const char *szValue) +{ + if ( szValue == NULL ) + return (*pszQuery == 0 || *pszQuery == '*'); + + // If the pointers are identical, we're identical + if ( szValue == pszQuery ) + return true; + + // Check for regex + if ( *pszQuery == '@' && mapbase_regex_enabled.GetBool() ) + { + // Make sure it has a forward slash + // (prevents confusion with instance fixup escape) + if (*(pszQuery+1) == '/') + { + return Matcher_Regex( pszQuery+2, szValue ); + } + } + + return Matcher_RunCharCompare( pszQuery, szValue ); +} + +bool Matcher_NamesMatch_Classic(const char *pszQuery, const char *szValue) +{ + if ( szValue == NULL ) + return (!pszQuery || *pszQuery == 0 || *pszQuery == '*'); + + // If the pointers are identical, we're identical + if ( szValue == pszQuery ) + return true; + + while ( *szValue && *pszQuery ) + { + unsigned char cName = *szValue; + unsigned char cQuery = *pszQuery; + // simple ascii case conversion + if ( cName == cQuery ) + ; + else if ( cName - 'A' <= (unsigned char)'Z' - 'A' && cName - 'A' + 'a' == cQuery ) + ; + else if ( cName - 'a' <= (unsigned char)'z' - 'a' && cName - 'a' + 'A' == cQuery ) + ; + else + break; + ++szValue; + ++pszQuery; + } + + if ( *pszQuery == 0 && *szValue == 0 ) + return true; + + // @TODO (toml 03-18-03): Perhaps support real wildcards. Right now, only thing supported is trailing * + if ( *pszQuery == '*' ) + return true; + + return false; +} + +bool Matcher_NamesMatch_MutualWildcard(const char *pszQuery, const char *szValue) +{ + if ( szValue == NULL ) + return (!pszQuery || *pszQuery == 0 || *pszQuery == '*'); + + if ( pszQuery == NULL ) + return (!szValue || *szValue == 0 || *szValue == '*'); + + // If the pointers are identical, we're identical + if ( szValue == pszQuery ) + return true; + + while ( *szValue && *pszQuery ) + { + unsigned char cName = *szValue; + unsigned char cQuery = *pszQuery; + // simple ascii case conversion + if ( cName == cQuery ) + ; + else if ( cName - 'A' <= (unsigned char)'Z' - 'A' && cName - 'A' + 'a' == cQuery ) + ; + else if ( cName - 'a' <= (unsigned char)'z' - 'a' && cName - 'a' + 'A' == cQuery ) + ; + else + break; + ++szValue; + ++pszQuery; + } + + if ( *pszQuery == 0 && *szValue == 0 ) + return true; + + // @TODO (toml 03-18-03): Perhaps support real wildcards. Right now, only thing supported is trailing * + if ( *pszQuery == '*' || *szValue == '*' ) + return true; + + return false; +} + +// Matcher_Compare is a deprecated alias originally used when Matcher_Match didn't support wildcards. +/* +bool Matcher_Compare(const char *pszQuery, const char *szValue) +{ + return Matcher_Match(pszQuery, szValue); +#if 0 + // I have to do this so wildcards could test *before* the response system comparison. + // I know it removes the operators twice, but I won't worry about it. + bool match = Matcher_NamesMatch(Matcher_RemoveOperators(pszQuery), szValue); + if (match) + return Matcher_Match(pszQuery, szValue); + return false; +#endif +} +*/ diff --git a/sp/src/tier1/tier1.vpc b/sp/src/tier1/tier1.vpc index 17158317..3d47526a 100644 --- a/sp/src/tier1/tier1.vpc +++ b/sp/src/tier1/tier1.vpc @@ -78,6 +78,7 @@ $Project "tier1" $File "snappy-sinksource.cpp" $File "snappy-stubs-internal.cpp" $File "mapbase_con_groups.cpp" [$MAPBASE] + $File "mapbase_matchers_base.cpp" [$MAPBASE] } $Folder "Header Files" @@ -150,6 +151,7 @@ $Project "tier1" $File "$SRCDIR\public\tier1\utlsymbollarge.h" $File "$SRCDIR\public\tier1\utlvector.h" $File "$SRCDIR\public\tier1\mapbase_con_groups.h" [$MAPBASE] + $File "$SRCDIR\public\tier1\mapbase_matchers_base.h" [$MAPBASE] $File "$SRCDIR\common\xbox\xboxstubs.h" [$WINDOWS] } } From 4e09f4bdf506c34794a244e405ccfb72b8b83420 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Wed, 17 Mar 2021 16:55:54 -0500 Subject: [PATCH 012/378] Added rr_disableemptyrules cvar, which prevents rules from being selected again after their norepeat/speakonce responses are exhausted --- .../responserules/runtime/response_system.cpp | 42 +++++++++++++++++++ .../responserules/runtime/response_system.h | 4 ++ 2 files changed, 46 insertions(+) diff --git a/sp/src/responserules/runtime/response_system.cpp b/sp/src/responserules/runtime/response_system.cpp index 60fedddb..15950b07 100644 --- a/sp/src/responserules/runtime/response_system.cpp +++ b/sp/src/responserules/runtime/response_system.cpp @@ -12,6 +12,9 @@ #include "convar.h" #include "fmtstr.h" #include "generichash.h" +#ifdef MAPBASE +#include "tier1/mapbase_matchers_base.h" +#endif // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -86,6 +89,10 @@ ConVar rr_dumpresponses( "rr_dumpresponses", "0", FCVAR_NONE, "Dump all response ConVar rr_debugresponseconcept( "rr_debugresponseconcept", "", FCVAR_NONE, "If set, rr_debugresponses will print only responses testing for the specified concept" ); #define RR_DEBUGRESPONSES_SPECIALCASE 4 +#ifdef MAPBASE +ConVar rr_disableemptyrules( "rr_disableemptyrules", "0", FCVAR_NONE, "Disables rules with no remaining responses, e.g. rules which use norepeat responses." ); +#endif + //----------------------------------------------------------------------------- @@ -788,6 +795,38 @@ void CResponseSystem::ResetResponseGroups() } } +#ifdef MAPBASE +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CResponseSystem::DisableEmptyRules() +{ + if (rr_disableemptyrules.GetBool() == false) + return; + + for ( ResponseRulePartition::tIndex idx = m_RulePartitions.First() ; + m_RulePartitions.IsValid(idx) ; + idx = m_RulePartitions.Next(idx) ) + { + Rule &rule = m_RulePartitions[ idx ]; + + // Set it as disabled in advance + rule.m_bEnabled = false; + + int c2 = rule.m_Responses.Count(); + for (int s = 0; s < c2; s++) + { + if (m_Responses[rule.m_Responses[s]].IsEnabled()) + { + // Re-enable it if there's any valid responses + rule.m_bEnabled = true; + break; + } + } + } +} +#endif + //----------------------------------------------------------------------------- // Purpose: Make certain responses unavailable by marking them as depleted //----------------------------------------------------------------------------- @@ -863,6 +902,9 @@ int CResponseSystem::SelectWeightedResponseFromResponseGroup( ResponseGroup *g, if ( g->IsNoRepeat() ) { g->SetEnabled( false ); +#ifdef MAPBASE + DisableEmptyRules(); +#endif return -1; } } diff --git a/sp/src/responserules/runtime/response_system.h b/sp/src/responserules/runtime/response_system.h index 9849b5a9..b675e816 100644 --- a/sp/src/responserules/runtime/response_system.h +++ b/sp/src/responserules/runtime/response_system.h @@ -241,6 +241,10 @@ public: float LookupEnumeration( const char *name, bool& found ); ResponseRulePartition::tIndex FindBestMatchingRule( const CriteriaSet& set, bool verbose, float &scoreOfBestMatchingRule ); + +#ifdef MAPBASE + void DisableEmptyRules(); +#endif float ScoreCriteriaAgainstRule( const CriteriaSet& set, ResponseRulePartition::tRuleDict &dict, int irule, bool verbose = false ); float RecursiveScoreSubcriteriaAgainstRule( const CriteriaSet& set, Criteria *parent, bool& exclude, bool verbose /*=false*/ ); From a05503e42bf4d6db58c1050d20f441e0350ce98e Mon Sep 17 00:00:00 2001 From: Blixibon Date: Thu, 18 Mar 2021 00:33:35 -0500 Subject: [PATCH 013/378] Fixed rr_disableemptyrules not always working correctly --- sp/src/responserules/runtime/response_system.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/sp/src/responserules/runtime/response_system.cpp b/sp/src/responserules/runtime/response_system.cpp index 15950b07..7867bda0 100644 --- a/sp/src/responserules/runtime/response_system.cpp +++ b/sp/src/responserules/runtime/response_system.cpp @@ -793,6 +793,15 @@ void CResponseSystem::ResetResponseGroups() { m_Responses[ i ].Reset(); } + +#ifdef MAPBASE + for ( ResponseRulePartition::tIndex idx = m_RulePartitions.First() ; + m_RulePartitions.IsValid(idx) ; + idx = m_RulePartitions.Next(idx) ) + { + m_RulePartitions[ idx ].m_bEnabled = true; + } +#endif } #ifdef MAPBASE @@ -1045,6 +1054,9 @@ bool CResponseSystem::ResolveResponse( ResponseSearchResult& searchResult, int d if ( g->IsNoRepeat() ) { g->SetEnabled( false ); +#ifdef MAPBASE + DisableEmptyRules(); +#endif return false; } idx = 0; @@ -1160,6 +1172,9 @@ bool CResponseSystem::GetBestResponse( ResponseSearchResult& searchResult, Rule if ( g->IsNoRepeat() ) { g->SetEnabled( false ); +#ifdef MAPBASE + DisableEmptyRules(); +#endif return false; } responseIndex = 0; From 8bcb6263f507bc53cb6c0f0b74c865f19cc1cecf Mon Sep 17 00:00:00 2001 From: Blixibon Date: Thu, 18 Mar 2021 00:34:31 -0500 Subject: [PATCH 014/378] Misc. response system code cleanup/QOL changes --- sp/src/game/shared/ai_responsesystem_new.cpp | 1 - sp/src/public/responserules/response_types.h | 3 +++ sp/src/responserules/runtime/rr_response.cpp | 13 +++++++++++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/sp/src/game/shared/ai_responsesystem_new.cpp b/sp/src/game/shared/ai_responsesystem_new.cpp index e703775f..4dbf8222 100644 --- a/sp/src/game/shared/ai_responsesystem_new.cpp +++ b/sp/src/game/shared/ai_responsesystem_new.cpp @@ -1078,7 +1078,6 @@ public: const Rule &rule = rs.m_RulePartitions[ idx ]; bool bEnabled = rule.m_bEnabled; - Msg( "%s: %i\n", rs.m_RulePartitions.GetElementName( idx ), idx ); pSave->WriteBool( &bEnabled ); pSave->EndBlock(); diff --git a/sp/src/public/responserules/response_types.h b/sp/src/public/responserules/response_types.h index 4ec62cee..a3e8fea3 100644 --- a/sp/src/public/responserules/response_types.h +++ b/sp/src/public/responserules/response_types.h @@ -326,6 +326,9 @@ namespace ResponseRules void GetName( char *buf, size_t buflen ) const; void GetResponse( char *buf, size_t buflen ) const; +#ifdef MAPBASE + void GetRule( char *buf, size_t buflen ) const; +#endif const char* GetNamePtr() const; const char* GetResponsePtr() const; const ResponseParams *GetParams() const { return &m_Params; } diff --git a/sp/src/responserules/runtime/rr_response.cpp b/sp/src/responserules/runtime/rr_response.cpp index 6124805c..3be0710e 100644 --- a/sp/src/responserules/runtime/rr_response.cpp +++ b/sp/src/responserules/runtime/rr_response.cpp @@ -198,6 +198,19 @@ void CRR_Response::GetResponse( char *buf, size_t buflen ) const GetName( buf, buflen ); } + +#ifdef MAPBASE +//----------------------------------------------------------------------------- +// Purpose: +// Output : char const +//----------------------------------------------------------------------------- +void CRR_Response::GetRule( char *buf, size_t buflen ) const +{ + Q_strncpy( buf, m_szMatchingRule, buflen ); +} +#endif + + const char* ResponseRules::CRR_Response::GetNamePtr() const { return m_szResponseName; From 6ed8b31091c12b95bcbf3b720f0966190bfb02f5 Mon Sep 17 00:00:00 2001 From: samisalreadytaken <46823719+samisalreadytaken@users.noreply.github.com> Date: Fri, 19 Mar 2021 16:44:12 +0200 Subject: [PATCH 015/378] vscript additions: - Added CBaseEntity::Activate - Added CBaseEntity::SetSolid - Added CBaseEntity::GetSolid - Added C_BaseEntity::UpdateOnRemove - Added hook behaviour on CScriptConCommand - Added more script overridable concommands - Added CScriptConvarAccessor::SetChangeCallback - Added CScriptGlowObjectManager - Added CScriptSteamAPI --- sp/src/game/client/c_baseentity.cpp | 15 +- sp/src/game/client/glow_outline_effect.h | 4 + sp/src/game/server/baseentity.cpp | 7 +- .../shared/mapbase/vscript_singletons.cpp | 298 +++++++++++++++--- sp/src/tier1/convar.cpp | 3 + 5 files changed, 286 insertions(+), 41 deletions(-) diff --git a/sp/src/game/client/c_baseentity.cpp b/sp/src/game/client/c_baseentity.cpp index a3b40378..a7bb37a4 100644 --- a/sp/src/game/client/c_baseentity.cpp +++ b/sp/src/game/client/c_baseentity.cpp @@ -428,6 +428,10 @@ BEGIN_RECV_TABLE_NOBASE( C_BaseEntity, DT_AnimTimeMustBeFirst ) RecvPropInt( RECVINFO(m_flAnimTime), 0, RecvProxy_AnimTime ), END_RECV_TABLE() +#ifdef MAPBASE_VSCRIPT +ScriptHook_t CBaseEntity::g_Hook_UpdateOnRemove; +#endif + BEGIN_ENT_SCRIPTDESC_ROOT( C_BaseEntity, "Root class of all client-side entities" ) DEFINE_SCRIPT_INSTANCE_HELPER( &g_BaseEntityScriptInstanceHelper ) DEFINE_SCRIPTFUNC_NAMED( GetAbsOrigin, "GetOrigin", "" ) @@ -550,7 +554,10 @@ BEGIN_ENT_SCRIPTDESC_ROOT( C_BaseEntity, "Root class of all client-side entities DEFINE_SCRIPTFUNC_NAMED( ScriptSetContextThink, "SetContextThink", "Set a think function on this entity." ) -#endif + + DEFINE_SIMPLE_SCRIPTHOOK( CBaseEntity::g_Hook_UpdateOnRemove, "UpdateOnRemove", FIELD_VOID, "Called when the entity is being removed." ) + +#endif // MAPBASE_VSCRIPT END_SCRIPTDESC(); @@ -1340,6 +1347,12 @@ void C_BaseEntity::Term() if ( m_hScriptInstance ) { +#ifdef MAPBASE_VSCRIPT + if ( m_ScriptScope.IsInitialized() ) + { + g_Hook_UpdateOnRemove.Call( m_ScriptScope, NULL, NULL ); + } +#endif g_pScriptVM->RemoveInstance( m_hScriptInstance ); m_hScriptInstance = NULL; diff --git a/sp/src/game/client/glow_outline_effect.h b/sp/src/game/client/glow_outline_effect.h index aac399d7..11132862 100644 --- a/sp/src/game/client/glow_outline_effect.h +++ b/sp/src/game/client/glow_outline_effect.h @@ -150,6 +150,10 @@ private: static const int ENTRY_IN_USE = -2; }; +#ifdef MAPBASE_VSCRIPT + // For unregistration boundary check +public: +#endif CUtlVector< GlowObjectDefinition_t > m_GlowObjectDefinitions; int m_nFirstFreeSlot; }; diff --git a/sp/src/game/server/baseentity.cpp b/sp/src/game/server/baseentity.cpp index 1b71f9fd..63c96439 100644 --- a/sp/src/game/server/baseentity.cpp +++ b/sp/src/game/server/baseentity.cpp @@ -2311,6 +2311,8 @@ BEGIN_ENT_SCRIPTDESC_ROOT( CBaseEntity, "Root class of all server-side entities" DEFINE_SCRIPTFUNC_NAMED( ScriptGetModelKeyValues, "GetModelKeyValues", "Get a KeyValue class instance on this entity's model") #ifdef MAPBASE_VSCRIPT + DEFINE_SCRIPTFUNC( Activate, "" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptIsVisible, "IsVisible", "Check if the specified position can be visible to this entity." ) 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." ) @@ -2408,7 +2410,10 @@ BEGIN_ENT_SCRIPTDESC_ROOT( CBaseEntity, "Root class of all server-side entities" DEFINE_SCRIPTFUNC( SetFriction, "" ) DEFINE_SCRIPTFUNC( GetMass, "" ) DEFINE_SCRIPTFUNC( SetMass, "" ) - + + DEFINE_SCRIPTFUNC_NAMED( ScriptGetSolid, "GetSolid", "" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptSetSolid, "SetSolid", "" ) + DEFINE_SCRIPTFUNC( GetSolidFlags, "Get solid flags" ) DEFINE_SCRIPTFUNC( AddSolidFlags, "Add solid flags" ) DEFINE_SCRIPTFUNC( RemoveSolidFlags, "Remove solid flags" ) diff --git a/sp/src/game/shared/mapbase/vscript_singletons.cpp b/sp/src/game/shared/mapbase/vscript_singletons.cpp index c5e51499..412723b1 100644 --- a/sp/src/game/shared/mapbase/vscript_singletons.cpp +++ b/sp/src/game/shared/mapbase/vscript_singletons.cpp @@ -30,6 +30,10 @@ #include "c_te_legacytempents.h" #include "iefx.h" #include "dlight.h" + +#if !defined(NO_STEAM) +#include "steam/steam_api.h" +#endif #endif #include "vscript_singletons.h" @@ -2170,12 +2174,13 @@ public: ~CScriptConCommand() { Unregister(); - delete m_cmd; + delete m_pBase; } - CScriptConCommand( const char *name, HSCRIPT fn, const char *helpString, int flags ) + CScriptConCommand( const char *name, HSCRIPT fn, const char *helpString, int flags, ConCommand *pLinked = NULL ) { - m_cmd = new ConCommand( name, this, helpString, flags, 0 ); + m_pBase = new ConCommand( name, this, helpString, flags, 0 ); + m_pLinked = pLinked; m_hCallback = fn; m_hCompletionCallback = NULL; m_nCmdNameLen = V_strlen(name) + 1; @@ -2191,10 +2196,15 @@ public: { vArgv[i] = command[i]; } - if ( g_pScriptVM->ExecuteFunction( m_hCallback, vArgv, count, NULL, NULL, true ) == SCRIPT_ERROR ) + ScriptVariant_t ret; + if ( g_pScriptVM->ExecuteFunction( m_hCallback, vArgv, count, &ret, NULL, true ) == SCRIPT_ERROR ) { DevWarning( 1, "CScriptConCommand: invalid callback for '%s'\n", command[0] ); } + if ( m_pLinked && (ret.m_type == FIELD_BOOLEAN) && ret.m_bool ) + { + m_pLinked->Dispatch( command ); + } } int CommandCompletionCallback( const char *partial, CUtlVector< CUtlString > &commands ) @@ -2249,17 +2259,17 @@ public: if (fn) { - if ( !m_cmd->IsRegistered() ) + if ( !m_pBase->IsRegistered() ) return; - m_cmd->m_pCommandCompletionCallback = this; - m_cmd->m_bHasCompletionCallback = true; + m_pBase->m_pCommandCompletionCallback = this; + m_pBase->m_bHasCompletionCallback = true; m_hCompletionCallback = fn; } else { - m_cmd->m_pCommandCompletionCallback = NULL; - m_cmd->m_bHasCompletionCallback = false; + m_pBase->m_pCommandCompletionCallback = NULL; + m_pBase->m_bHasCompletionCallback = false; m_hCompletionCallback = NULL; } } @@ -2268,7 +2278,7 @@ public: { if (fn) { - if ( !m_cmd->IsRegistered() ) + if ( !m_pBase->IsRegistered() ) Register(); if ( m_hCallback ) @@ -2283,8 +2293,8 @@ public: inline void Unregister() { - if ( g_pCVar && m_cmd->IsRegistered() ) - g_pCVar->UnregisterConCommand( m_cmd ); + if ( g_pCVar && m_pBase->IsRegistered() ) + g_pCVar->UnregisterConCommand( m_pBase ); if ( g_pScriptVM ) { @@ -2301,13 +2311,14 @@ public: inline void Register() { if ( g_pCVar ) - g_pCVar->RegisterConCommand( m_cmd ); + g_pCVar->RegisterConCommand( m_pBase ); } HSCRIPT m_hCallback; HSCRIPT m_hCompletionCallback; int m_nCmdNameLen; - ConCommand *m_cmd; + ConCommand *m_pLinked; + ConCommand *m_pBase; }; class CScriptConVar @@ -2316,30 +2327,58 @@ public: ~CScriptConVar() { Unregister(); - delete m_cvar; + delete m_pBase; } CScriptConVar( const char *pName, const char *pDefaultValue, const char *pHelpString, int flags/*, float fMin, float fMax*/ ) { - m_cvar = new ConVar( pName, pDefaultValue, flags, pHelpString ); + m_pBase = new ConVar( pName, pDefaultValue, flags, pHelpString ); + m_hCallback = NULL; + } + + void SetChangeCallback( HSCRIPT fn ) + { + void ScriptConVarCallback( IConVar*, const char*, float ); + + if ( m_hCallback ) + g_pScriptVM->ReleaseScript( m_hCallback ); + + if (fn) + { + m_hCallback = fn; + m_pBase->InstallChangeCallback( (FnChangeCallback_t)ScriptConVarCallback ); + } + else + { + m_hCallback = NULL; + m_pBase->InstallChangeCallback( NULL ); + } } inline void Unregister() { - if ( g_pCVar && m_cvar->IsRegistered() ) - g_pCVar->UnregisterConCommand( m_cvar ); + if ( g_pCVar && m_pBase->IsRegistered() ) + g_pCVar->UnregisterConCommand( m_pBase ); + + if ( g_pScriptVM ) + { + SetChangeCallback( NULL ); + } } - ConVar *m_cvar; + HSCRIPT m_hCallback; + ConVar *m_pBase; }; +static CUtlMap< unsigned int, bool > g_ConVarsBlocked( DefLessFunc(unsigned int) ); +static CUtlMap< unsigned int, bool > g_ConCommandsOverridable( DefLessFunc(unsigned int) ); +static CUtlMap< unsigned int, CScriptConCommand* > g_ScriptConCommands( DefLessFunc(unsigned int) ); +static CUtlMap< unsigned int, CScriptConVar* > g_ScriptConVars( DefLessFunc(unsigned int) ); + + class CScriptConvarAccessor : public CAutoGameSystem { public: - static CUtlMap< unsigned int, bool > g_ConVarsBlocked; - static CUtlMap< unsigned int, bool > g_ConCommandsOverridable; - static CUtlMap< unsigned int, CScriptConCommand* > g_ScriptConCommands; - static CUtlMap< unsigned int, CScriptConVar* > g_ScriptConVars; static inline unsigned int Hash( const char*sz ){ return HashStringCaseless(sz); } public: @@ -2353,7 +2392,7 @@ public: int idx = g_ConCommandsOverridable.Find( hash ); if ( idx == g_ConCommandsOverridable.InvalidIndex() ) return false; - return g_ConCommandsOverridable[idx]; + return true; } inline void AddBlockedConVar( const char *name ) @@ -2366,7 +2405,7 @@ public: int idx = g_ConVarsBlocked.Find( Hash(name) ); if ( idx == g_ConVarsBlocked.InvalidIndex() ) return false; - return g_ConVarsBlocked[idx]; + return true; } public: @@ -2374,6 +2413,7 @@ public: void SetCompletionCallback( const char *name, HSCRIPT fn ); void UnregisterCommand( const char *name ); void RegisterConvar( const char *name, const char *pDefaultValue, const char *helpString, int flags ); + void SetChangeCallback( const char *name, HSCRIPT fn ); HSCRIPT GetCommandClient() { @@ -2482,18 +2522,14 @@ public: } g_ScriptConvarAccessor; -CUtlMap< unsigned int, bool > CScriptConvarAccessor::g_ConVarsBlocked( DefLessFunc(unsigned int) ); -CUtlMap< unsigned int, bool > CScriptConvarAccessor::g_ConCommandsOverridable( DefLessFunc(unsigned int) ); -CUtlMap< unsigned int, CScriptConCommand* > CScriptConvarAccessor::g_ScriptConCommands( DefLessFunc(unsigned int) ); -CUtlMap< unsigned int, CScriptConVar* > CScriptConvarAccessor::g_ScriptConVars( DefLessFunc(unsigned int) ); - void CScriptConvarAccessor::RegisterCommand( const char *name, HSCRIPT fn, const char *helpString, int flags ) { unsigned int hash = Hash(name); int idx = g_ScriptConCommands.Find(hash); if ( idx == g_ScriptConCommands.InvalidIndex() ) { - if ( g_pCVar->FindVar(name) || ( g_pCVar->FindCommand(name) && !IsOverridable(hash) ) ) + ConCommand *pLinked = NULL; + if ( g_pCVar->FindVar(name) || ( ((pLinked = g_pCVar->FindCommand(name)) != NULL) && !IsOverridable(hash) ) ) { DevWarning( 1, "CScriptConvarAccessor::RegisterCommand unable to register blocked ConCommand: %s\n", name ); return; @@ -2502,14 +2538,13 @@ void CScriptConvarAccessor::RegisterCommand( const char *name, HSCRIPT fn, const if ( !fn ) return; - CScriptConCommand *p = new CScriptConCommand( name, fn, helpString, flags ); + CScriptConCommand *p = new CScriptConCommand( name, fn, helpString, flags, pLinked ); g_ScriptConCommands.Insert( hash, p ); } else { CScriptConCommand *pCmd = g_ScriptConCommands[idx]; pCmd->SetCallback( fn ); - pCmd->m_cmd->AddFlags( flags ); //CGMsg( 1, CON_GROUP_VSCRIPT, "CScriptConvarAccessor::RegisterCommand replacing command already registered: %s\n", name ); } } @@ -2552,11 +2587,39 @@ void CScriptConvarAccessor::RegisterConvar( const char *name, const char *pDefau } else { - g_ScriptConVars[idx]->m_cvar->AddFlags( flags ); //CGMsg( 1, CON_GROUP_VSCRIPT, "CScriptConvarAccessor::RegisterConvar convar %s already registered\n", name ); } } +void CScriptConvarAccessor::SetChangeCallback( const char *name, HSCRIPT fn ) +{ + unsigned int hash = Hash(name); + int idx = g_ScriptConVars.Find(hash); + if ( idx != g_ScriptConVars.InvalidIndex() ) + { + g_ScriptConVars[idx]->SetChangeCallback( fn ); + } +} + +void ScriptConVarCallback( IConVar *var, const char* pszOldValue, float flOldValue ) +{ + ConVar *cvar = (ConVar*)var; + const char *name = cvar->GetName(); + unsigned int hash = CScriptConvarAccessor::Hash( name ); + int idx = g_ScriptConVars.Find(hash); + if ( idx != g_ScriptConVars.InvalidIndex() ) + { + Assert( g_ScriptConVars[idx]->m_hCallback ); + + ScriptVariant_t args[5] = { name, pszOldValue, flOldValue, cvar->GetString(), cvar->GetFloat() }; + if ( g_pScriptVM->ExecuteFunction( g_ScriptConVars[idx]->m_hCallback, args, 5, NULL, NULL, true ) == SCRIPT_ERROR ) + { + DevWarning( 1, "CScriptConVar: invalid change callback for '%s'\n", name ); + } + } +} + + bool CScriptConvarAccessor::Init() { static bool bExecOnce = false; @@ -2584,6 +2647,7 @@ bool CScriptConvarAccessor::Init() AddOverridable( "+grenade1" ); AddOverridable( "+grenade2" ); AddOverridable( "+showscores" ); + AddOverridable( "+voicerecord" ); AddOverridable( "-attack" ); AddOverridable( "-attack2" ); @@ -2605,8 +2669,11 @@ bool CScriptConvarAccessor::Init() AddOverridable( "-grenade1" ); AddOverridable( "-grenade2" ); AddOverridable( "-showscores" ); + AddOverridable( "-voicerecord" ); AddOverridable( "toggle_duck" ); + AddOverridable( "impulse" ); + AddOverridable( "use" ); AddOverridable( "lastinv" ); AddOverridable( "invnext" ); AddOverridable( "invprev" ); @@ -2618,10 +2685,16 @@ bool CScriptConvarAccessor::Init() AddOverridable( "slot5" ); AddOverridable( "slot6" ); AddOverridable( "slot7" ); + AddOverridable( "slot8" ); + AddOverridable( "slot9" ); + AddOverridable( "slot10" ); AddOverridable( "save" ); AddOverridable( "load" ); + AddOverridable( "say" ); + AddOverridable( "say_team" ); + AddBlockedConVar( "con_enable" ); AddBlockedConVar( "cl_allowdownload" ); @@ -2634,7 +2707,8 @@ bool CScriptConvarAccessor::Init() BEGIN_SCRIPTDESC_ROOT_NAMED( CScriptConvarAccessor, "CConvars", SCRIPT_SINGLETON "Provides an interface to convars." ) DEFINE_SCRIPTFUNC( RegisterConvar, "register a new console variable." ) DEFINE_SCRIPTFUNC( RegisterCommand, "register a console command." ) - DEFINE_SCRIPTFUNC( SetCompletionCallback, "callback is called with 3 parameters (cmdname, partial, commands), user strings must be appended to 'commands' array" ) + DEFINE_SCRIPTFUNC( SetCompletionCallback, "callback is called with 3 parameters (cmd, partial, commands), user strings must be appended to 'commands' array" ) + DEFINE_SCRIPTFUNC( SetChangeCallback, "callback is called with 5 parameters (var, szOldValue, flOldValue, szNewValue, flNewValue)" ) DEFINE_SCRIPTFUNC( UnregisterCommand, "unregister a console command." ) DEFINE_SCRIPTFUNC( GetCommandClient, "returns the player who issued this console command." ) #ifdef GAME_DLL @@ -2671,9 +2745,6 @@ END_SCRIPTDESC(); class CEffectsScriptHelper { -private: - C_RecipientFilter filter; - public: void DynamicLight( int index, const Vector& origin, int r, int g, int b, int exponent, float radius, float die, float decay, int style = 0, int flags = 0 ) @@ -2694,6 +2765,7 @@ public: void Explosion( const Vector& pos, float scale, int radius, int magnitude, int flags ) { + C_RecipientFilter filter; filter.AddAllPlayers(); // framerate, modelindex, normal and materialtype are unused // radius for ragdolls @@ -2803,7 +2875,150 @@ BEGIN_SCRIPTDESC_ROOT_NAMED( CEffectsScriptHelper, "CEffects", SCRIPT_SINGLETON DEFINE_SCRIPTFUNC( Sprite, "" ) DEFINE_SCRIPTFUNC( ClientProjectile, "" ) END_SCRIPTDESC(); -#endif + + + +//============================================================================= +//============================================================================= + +extern CGlowObjectManager g_GlowObjectManager; + +class CScriptGlowObjectManager : public CAutoGameSystem +{ +public: + CUtlVector m_RegisteredObjects; + + void LevelShutdownPostEntity() + { + FOR_EACH_VEC( m_RegisteredObjects, i ) + g_GlowObjectManager.UnregisterGlowObject( m_RegisteredObjects[i] ); + m_RegisteredObjects.Purge(); + } + +public: + int Register( HSCRIPT hEntity, int r, int g, int b, int a, bool bRenderWhenOccluded, bool bRenderWhenUnoccluded ) + { + Vector vGlowColor; + vGlowColor.x = r * ( 1.0f / 255.0f ); + vGlowColor.y = g * ( 1.0f / 255.0f ); + vGlowColor.z = b * ( 1.0f / 255.0f ); + float flGlowAlpha = a * ( 1.0f / 255.0f ); + int idx = g_GlowObjectManager.RegisterGlowObject( ToEnt(hEntity), vGlowColor, flGlowAlpha, bRenderWhenOccluded, bRenderWhenUnoccluded, -1 ); + m_RegisteredObjects.AddToTail( idx ); + return idx; + } + + void Unregister( int nGlowObjectHandle ) + { + if ( (nGlowObjectHandle < 0) || (nGlowObjectHandle >= g_GlowObjectManager.m_GlowObjectDefinitions.Count()) ) + return; + g_GlowObjectManager.UnregisterGlowObject( nGlowObjectHandle ); + m_RegisteredObjects.FindAndFastRemove( nGlowObjectHandle ); + } + + void SetEntity( int nGlowObjectHandle, HSCRIPT hEntity ) + { + g_GlowObjectManager.SetEntity( nGlowObjectHandle, ToEnt(hEntity) ); + } + + void SetColor( int nGlowObjectHandle, int r, int g, int b ) + { + Vector vGlowColor; + vGlowColor.x = r * ( 1.0f / 255.0f ); + vGlowColor.y = g * ( 1.0f / 255.0f ); + vGlowColor.z = b * ( 1.0f / 255.0f ); + g_GlowObjectManager.SetColor( nGlowObjectHandle, vGlowColor ); + } + + void SetAlpha( int nGlowObjectHandle, int a ) + { + float flGlowAlpha = a * ( 1.0f / 255.0f ); + g_GlowObjectManager.SetAlpha( nGlowObjectHandle, flGlowAlpha ); + } + + void SetRenderFlags( int nGlowObjectHandle, bool bRenderWhenOccluded, bool bRenderWhenUnoccluded ) + { + g_GlowObjectManager.SetRenderFlags( nGlowObjectHandle, bRenderWhenOccluded, bRenderWhenUnoccluded ); + } + +} g_ScriptGlowObjectManager; + +BEGIN_SCRIPTDESC_ROOT_NAMED( CScriptGlowObjectManager, "CGlowObjectManager", SCRIPT_SINGLETON "" ) + DEFINE_SCRIPTFUNC( Register, "( HSCRIPT hEntity, int r, int g, int b, int a, bool bRenderWhenOccluded, bool bRenderWhenUnoccluded )" ) + DEFINE_SCRIPTFUNC( Unregister, "" ) + DEFINE_SCRIPTFUNC( SetEntity, "" ) + DEFINE_SCRIPTFUNC( SetColor, "" ) + DEFINE_SCRIPTFUNC( SetAlpha, "" ) + DEFINE_SCRIPTFUNC( SetRenderFlags, "" ) +END_SCRIPTDESC(); + + +//============================================================================= +//============================================================================= + + +#if !defined(NO_STEAM) +class CScriptSteamAPI +{ +public: + int GetSecondsSinceComputerActive() + { + if ( !steamapicontext || !steamapicontext->SteamUtils() ) + return 0; + + return steamapicontext->SteamUtils()->GetSecondsSinceComputerActive(); + } + + int GetCurrentBatteryPower() + { + if ( !steamapicontext || !steamapicontext->SteamUtils() ) + return 0; + + return steamapicontext->SteamUtils()->GetCurrentBatteryPower(); + } + + const char *GetIPCountry() + { + if ( !steamapicontext || !steamapicontext->SteamUtils() ) + return NULL; + + const char *get = steamapicontext->SteamUtils()->GetIPCountry(); + if ( !get ) + return NULL; + + static char ret[3]; + V_strncpy( ret, get, 3 ); + + return ret; + } + + const char *GetCurrentGameLanguage() + { + if ( !steamapicontext || !steamapicontext->SteamApps() ) + return NULL; + + const char *lang = steamapicontext->SteamApps()->GetCurrentGameLanguage(); + if ( !lang ) + return NULL; + + static char ret[16]; + V_strncpy( ret, lang, sizeof(ret) ); + + return ret; + } + +} g_ScriptSteamAPI; + +BEGIN_SCRIPTDESC_ROOT_NAMED( CScriptSteamAPI, "CSteamAPI", SCRIPT_SINGLETON "" ) + //DEFINE_SCRIPTFUNC( IsVACBanned, "" ) + DEFINE_SCRIPTFUNC( GetSecondsSinceComputerActive, "Returns the number of seconds since the user last moved the mouse." ) + DEFINE_SCRIPTFUNC( GetCurrentBatteryPower, "Return the amount of battery power left in the current system in % [0..100], 255 for being on AC power" ) + //DEFINE_SCRIPTFUNC( GetIPCountry, "Returns the 2 digit ISO 3166-1-alpha-2 format country code this client is running in (as looked up via an IP-to-location database)" ) + DEFINE_SCRIPTFUNC( GetCurrentGameLanguage, "Gets the current language that the user has set as API language code. This falls back to the Steam UI language if the user hasn't explicitly picked a language for the title." ) +END_SCRIPTDESC(); +#endif // !NO_STEAM + +#endif // CLIENT_DLL void RegisterScriptSingletons() @@ -2831,6 +3046,11 @@ void RegisterScriptSingletons() g_pScriptVM->RegisterInstance( &g_ScriptConvarAccessor, "Convars" ); #ifdef CLIENT_DLL g_pScriptVM->RegisterInstance( &g_ScriptEffectsHelper, "effects" ); + g_pScriptVM->RegisterInstance( &g_ScriptGlowObjectManager, "GlowObjectManager" ); + +#if !defined(NO_STEAM) + g_pScriptVM->RegisterInstance( &g_ScriptSteamAPI, "steam" ); +#endif #endif // Singletons not unique to VScript (not declared or defined here) diff --git a/sp/src/tier1/convar.cpp b/sp/src/tier1/convar.cpp index c49a6efb..fc27eb74 100644 --- a/sp/src/tier1/convar.cpp +++ b/sp/src/tier1/convar.cpp @@ -688,7 +688,10 @@ ConVar::~ConVar( void ) //----------------------------------------------------------------------------- void ConVar::InstallChangeCallback( FnChangeCallback_t callback ) { +#ifndef MAPBASE_VSCRIPT Assert( !m_pParent->m_fnChangeCallback || !callback ); +#endif + m_pParent->m_fnChangeCallback = callback; if ( m_pParent->m_fnChangeCallback ) From 49836ab50a34924fb8cdfbd7a8049ca5ca9aa31f Mon Sep 17 00:00:00 2001 From: Alexander 'z33ky' Hirsch <1zeeky@gmail.com> Date: Wed, 27 Jan 2021 10:27:03 +0100 Subject: [PATCH 016/378] Fix gcc build errors & warnings --- sp/src/game/client/c_baseentity.h | 2 +- sp/src/game/client/c_baselesson.cpp | 37 +++++++-------- sp/src/game/client/c_baselesson.h | 2 +- sp/src/game/client/c_gameinstructor.h | 2 +- sp/src/game/client/hud_locator_target.cpp | 2 +- sp/src/game/client/hud_locator_target.h | 2 +- sp/src/game/client/vgui_movie_display.cpp | 10 ++-- sp/src/game/server/hl2/hl2_player.h | 2 +- .../server/mapbase/logic_externaldata.cpp | 2 +- .../shared/mapbase/vscript_consts_shared.cpp | 3 +- sp/src/public/tier1/convar.h | 2 +- sp/src/public/vscript/ivscript.h | 46 +++++++++++++------ sp/src/tier1/mapbase_con_groups.cpp | 2 +- sp/src/vscript/vscript_squirrel.cpp | 4 +- 14 files changed, 68 insertions(+), 50 deletions(-) diff --git a/sp/src/game/client/c_baseentity.h b/sp/src/game/client/c_baseentity.h index dabfbbd9..f2170be4 100644 --- a/sp/src/game/client/c_baseentity.h +++ b/sp/src/game/client/c_baseentity.h @@ -400,7 +400,7 @@ public: #ifdef MAPBASE_VSCRIPT // "I don't know why but wrapping entindex() works, while calling it directly crashes." - inline int C_BaseEntity::GetEntityIndex() const { return entindex(); } + inline int GetEntityIndex() const { return entindex(); } #endif // This works for client-only entities and returns the GetEntryIndex() of the entity's handle, diff --git a/sp/src/game/client/c_baselesson.cpp b/sp/src/game/client/c_baselesson.cpp index 8a2d9617..ec01575b 100644 --- a/sp/src/game/client/c_baselesson.cpp +++ b/sp/src/game/client/c_baselesson.cpp @@ -15,7 +15,7 @@ #include "ammodef.h" #include "vprof.h" #include "view.h" -#include "vstdlib/ikeyvaluessystem.h" +#include "vstdlib/IKeyValuesSystem.h" #ifdef MAPBASE #include "usermessages.h" #endif @@ -666,7 +666,8 @@ void CIconLesson::UpdateInactive() CUtlBuffer msg_data; msg_data.PutChar( 1 ); msg_data.PutString( m_szHudHint.String() ); - usermessages->DispatchUserMessage( usermessages->LookupUserMessage( "KeyHintText" ), bf_read( msg_data.Base(), msg_data.TellPut() ) ); + bf_read msg( msg_data.Base(), msg_data.TellPut() ); + usermessages->DispatchUserMessage( usermessages->LookupUserMessage( "KeyHintText" ), msg ); } #endif @@ -1039,40 +1040,40 @@ Vector CIconLesson::GetIconTargetPosition( C_BaseEntity *pIconTarget ) #define LESSON_VARIABLE_INIT_SYMBOL( _varEnum, _varName, _varType ) g_n##_varEnum##Symbol = KeyValuesSystem()->GetSymbolForString( #_varEnum ); -#define LESSON_SCRIPT_STRING_ADD_TO_MAP( _varEnum, _varName, _varType ) g_NameToTypeMap.Insert( #_varEnum, LESSON_VARIABLE_##_varEnum## ); +#define LESSON_SCRIPT_STRING_ADD_TO_MAP( _varEnum, _varName, _varType ) g_NameToTypeMap.Insert( #_varEnum, LESSON_VARIABLE_##_varEnum ); // Create enum value -#define LESSON_VARIABLE_ENUM( _varEnum, _varName, _varType ) LESSON_VARIABLE_##_varEnum##, +#define LESSON_VARIABLE_ENUM( _varEnum, _varName, _varType ) LESSON_VARIABLE_##_varEnum, // Init info call -#define LESSON_VARIABLE_INIT_INFO_CALL( _varEnum, _varName, _varType ) g_pLessonVariableInfo[ LESSON_VARIABLE_##_varEnum## ].Init_##_varEnum##(); +#define LESSON_VARIABLE_INIT_INFO_CALL( _varEnum, _varName, _varType ) g_pLessonVariableInfo[ LESSON_VARIABLE_##_varEnum ].Init_##_varEnum(); // Init info #define LESSON_VARIABLE_INIT_INFO( _varEnum, _varName, _varType ) \ - void Init_##_varEnum##() \ + void Init_##_varEnum() \ { \ - iOffset = offsetof( CScriptedIconLesson, CScriptedIconLesson::##_varName## ); \ + iOffset = offsetof( CScriptedIconLesson, CScriptedIconLesson::_varName ); \ varType = LessonParamTypeFromString( #_varType ); \ } #define LESSON_VARIABLE_INIT_INFO_BOOL( _varEnum, _varName, _varType ) \ - void Init_##_varEnum##() \ + void Init_##_varEnum() \ { \ - iOffset = offsetof( CScriptedIconLesson, CScriptedIconLesson::##_varName## ); \ + iOffset = offsetof( CScriptedIconLesson, CScriptedIconLesson::_varName ); \ varType = FIELD_BOOLEAN; \ } #define LESSON_VARIABLE_INIT_INFO_EHANDLE( _varEnum, _varName, _varType ) \ - void Init_##_varEnum##() \ + void Init_##_varEnum() \ { \ - iOffset = offsetof( CScriptedIconLesson, CScriptedIconLesson::##_varName## ); \ + iOffset = offsetof( CScriptedIconLesson, CScriptedIconLesson::_varName ); \ varType = FIELD_EHANDLE; \ } #define LESSON_VARIABLE_INIT_INFO_STRING( _varEnum, _varName, _varType ) \ - void Init_##_varEnum##() \ + void Init_##_varEnum() \ { \ - iOffset = offsetof( CScriptedIconLesson, CScriptedIconLesson::##_varName## ); \ + iOffset = offsetof( CScriptedIconLesson, CScriptedIconLesson::_varName ); \ varType = FIELD_STRING; \ } @@ -1094,15 +1095,15 @@ Vector CIconLesson::GetIconTargetPosition( C_BaseEntity *pIconTarget ) // Process the element action on this variable #define PROCESS_LESSON_ACTION( _varEnum, _varName, _varType ) \ - case LESSON_VARIABLE_##_varEnum##:\ + case LESSON_VARIABLE_##_varEnum:\ return ProcessElementAction( pLessonElement->iAction, pLessonElement->bNot, #_varName, _varName, &pLessonElement->szParam, eventParam_float ); #define PROCESS_LESSON_ACTION_EHANDLE( _varEnum, _varName, _varType ) \ - case LESSON_VARIABLE_##_varEnum##:\ + case LESSON_VARIABLE_##_varEnum:\ return ProcessElementAction( pLessonElement->iAction, pLessonElement->bNot, #_varName, _varName, &pLessonElement->szParam, eventParam_float, eventParam_BaseEntity, eventParam_string ); #define PROCESS_LESSON_ACTION_STRING( _varEnum, _varName, _varType ) \ - case LESSON_VARIABLE_##_varEnum##:\ + case LESSON_VARIABLE_##_varEnum:\ return ProcessElementAction( pLessonElement->iAction, pLessonElement->bNot, #_varName, &_varName, &pLessonElement->szParam, eventParam_string ); // Init the variable from the script (or a convar) @@ -2957,7 +2958,7 @@ bool CScriptedIconLesson::ProcessElementAction( int iAction, bool bNot, const ch { if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) { - ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\t[%s]->HealthFraction() ", pchVarName, pchVarName ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\t[%s]->HealthFraction() ", pchVarName ); ConColorMsg( CBaseLesson::m_rgbaVerboseName, "... " ); ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ( bNot ) ? ( ">= [%s] " ) : ( "< [%s] " ), pchParamName->String() ); ConColorMsg( CBaseLesson::m_rgbaVerboseName, "%f\n", fParam ); @@ -2969,7 +2970,7 @@ bool CScriptedIconLesson::ProcessElementAction( int iAction, bool bNot, const ch if ( gameinstructor_verbose.GetInt() > 0 && ShouldShowSpew() ) { - ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\t[%s]->HealthFraction() ", pchVarName, pchVarName ); + ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, "\t[%s]->HealthFraction() ", pchVarName ); ConColorMsg( CBaseLesson::m_rgbaVerboseName, "%f ", pVar->HealthFraction() ); ConColorMsg( CBaseLesson::m_rgbaVerbosePlain, ( bNot ) ? ( ">= [%s] " ) : ( "< [%s] " ), pchParamName->String() ); ConColorMsg( CBaseLesson::m_rgbaVerboseName, "%f\n", fParam ); diff --git a/sp/src/game/client/c_baselesson.h b/sp/src/game/client/c_baselesson.h index 2cad41ca..b413d282 100644 --- a/sp/src/game/client/c_baselesson.h +++ b/sp/src/game/client/c_baselesson.h @@ -426,7 +426,7 @@ private: LessonEvent_t * AddUpdateEvent( void ); private: - static CUtlDict< int, int > CScriptedIconLesson::LessonActionMap; + static CUtlDict< int, int > LessonActionMap; EHANDLE m_hLocalPlayer; float m_fOutput; diff --git a/sp/src/game/client/c_gameinstructor.h b/sp/src/game/client/c_gameinstructor.h index 00c97c66..14ae908c 100644 --- a/sp/src/game/client/c_gameinstructor.h +++ b/sp/src/game/client/c_gameinstructor.h @@ -9,7 +9,7 @@ #include "GameEventListener.h" -#include "vgui_controls/phandle.h" +#include "vgui_controls/PHandle.h" class CBaseLesson; diff --git a/sp/src/game/client/hud_locator_target.cpp b/sp/src/game/client/hud_locator_target.cpp index 8f0d4c0c..8479b07e 100644 --- a/sp/src/game/client/hud_locator_target.cpp +++ b/sp/src/game/client/hud_locator_target.cpp @@ -10,7 +10,7 @@ #include "iclientmode.h" #include #include -#include +#include #include #include #include diff --git a/sp/src/game/client/hud_locator_target.h b/sp/src/game/client/hud_locator_target.h index 06799325..69939dbb 100644 --- a/sp/src/game/client/hud_locator_target.h +++ b/sp/src/game/client/hud_locator_target.h @@ -34,7 +34,7 @@ #define LOCATOR_ICON_FX_FADE_OUT 0x00000800 // Set when deactivated so it can smoothly vanish #define LOCATOR_ICON_FX_FADE_IN 0x00001000 // Set when activated so it can smoothly appear -#include "tier1/UtlSymbol.h" +#include "tier1/utlsymbol.h" // See comments in UtlSymbol on why this is useful DECLARE_PRIVATE_SYMBOLTYPE( CGameInstructorSymbol ); diff --git a/sp/src/game/client/vgui_movie_display.cpp b/sp/src/game/client/vgui_movie_display.cpp index 0f474323..135ad7f9 100644 --- a/sp/src/game/client/vgui_movie_display.cpp +++ b/sp/src/game/client/vgui_movie_display.cpp @@ -7,16 +7,16 @@ #include "cbase.h" #include "c_vguiscreen.h" #include "vgui_controls/Label.h" -#include "vgui_BitmapPanel.h" -#include +#include "vgui_bitmappanel.h" +#include #include "c_slideshow_display.h" #include "ienginevgui.h" #include "fmtstr.h" #include "vgui_controls/ImagePanel.h" #include #include "video/ivideoservices.h" -#include "engine/ienginesound.h" -#include "VGUIMatSurface/IMatSystemSurface.h" +#include "engine/IEngineSound.h" +#include "VGuiMatSurface/IMatSystemSurface.h" #include "c_movie_display.h" // NOTE: This has to be the last file included! @@ -368,7 +368,7 @@ bool CMovieDisplayScreen::BeginPlayback( const char *pFilename ) Q_strncpy( szMaterialName, pFilename, sizeof(szMaterialName) ); } - const char *pszMaterialName = CFmtStrN<128>( "VideoMaterial_", m_hScreenEntity->GetEntityName() ); + const char *pszMaterialName = CFmtStrN<128>( "VideoMaterial_%s", m_hScreenEntity->GetEntityName() ); m_VideoMaterial = g_pVideo->CreateVideoMaterial( pszMaterialName, pFilename, "GAME", VideoPlaybackFlags::DEFAULT_MATERIAL_OPTIONS, VideoSystem::DETERMINE_FROM_FILE_EXTENSION/*, m_bAllowAlternateMedia*/ ); diff --git a/sp/src/game/server/hl2/hl2_player.h b/sp/src/game/server/hl2/hl2_player.h index 84ae23b9..0ffc68f5 100644 --- a/sp/src/game/server/hl2/hl2_player.h +++ b/sp/src/game/server/hl2/hl2_player.h @@ -303,7 +303,7 @@ public: virtual bool IsHoldingEntity( CBaseEntity *pEnt ); virtual void ForceDropOfCarriedPhysObjects( CBaseEntity *pOnlyIfHoldindThis ); virtual float GetHeldObjectMass( IPhysicsObject *pHeldObject ); - virtual CBaseEntity *CHL2_Player::GetHeldObject( void ); + virtual CBaseEntity *GetHeldObject( void ); virtual bool IsFollowingPhysics( void ) { return (m_afPhysicsFlags & PFLAG_ONBARNACLE) > 0; } void InputForceDropPhysObjects( inputdata_t &data ); diff --git a/sp/src/game/server/mapbase/logic_externaldata.cpp b/sp/src/game/server/mapbase/logic_externaldata.cpp index b28189f7..c13117f5 100644 --- a/sp/src/game/server/mapbase/logic_externaldata.cpp +++ b/sp/src/game/server/mapbase/logic_externaldata.cpp @@ -199,7 +199,7 @@ void CLogicExternalData::InputWriteKeyValue( inputdata_t &inputdata ) // Separate key from value char *delimiter = Q_strstr(szValue, " "); - if (delimiter && (delimiter + 1) != '\0') + if (delimiter && delimiter[1] != '\0') { Q_strncpy(key, szValue, MIN((delimiter - szValue) + 1, sizeof(key))); Q_strncpy(value, delimiter + 1, sizeof(value)); diff --git a/sp/src/game/shared/mapbase/vscript_consts_shared.cpp b/sp/src/game/shared/mapbase/vscript_consts_shared.cpp index 31341fb9..edd30409 100644 --- a/sp/src/game/shared/mapbase/vscript_consts_shared.cpp +++ b/sp/src/game/shared/mapbase/vscript_consts_shared.cpp @@ -483,7 +483,8 @@ void RegisterSharedScriptConstants() //ScriptRegisterConstant( g_pScriptVM, AISS_AUTO_PVS_AFTER_PVS, "" ); ScriptRegisterConstant( g_pScriptVM, AI_SLEEP_FLAGS_NONE, "No sleep flags. (NPC sleep flag used in Add/Remove/HasSleepFlags())" ); ScriptRegisterConstant( g_pScriptVM, AI_SLEEP_FLAG_AUTO_PVS, "Indicates a NPC will sleep upon exiting PVS. (NPC sleep flag used in Add/Remove/HasSleepFlags())" ); - ScriptRegisterConstant( g_pScriptVM, AI_SLEEP_FLAG_AUTO_PVS_AFTER_PVS, "Indicates a NPC will sleep upon exiting PVS after entering PVS for the first time(?????) (NPC sleep flag used in Add/Remove/HasSleepFlags())" ); + // note: the one "?" is escaped to prevent evaluation of a trigraph + ScriptRegisterConstant( g_pScriptVM, AI_SLEEP_FLAG_AUTO_PVS_AFTER_PVS, "Indicates a NPC will sleep upon exiting PVS after entering PVS for the first time(????\?) (NPC sleep flag used in Add/Remove/HasSleepFlags())" ); ScriptRegisterConstantNamed( g_pScriptVM, CAI_BaseNPC::SCRIPT_PLAYING, "SCRIPT_PLAYING", "Playing the action animation." ); ScriptRegisterConstantNamed( g_pScriptVM, CAI_BaseNPC::SCRIPT_WAIT, "SCRIPT_WAIT", "Waiting on everyone in the script to be ready. Plays the pre idle animation if there is one." ); diff --git a/sp/src/public/tier1/convar.h b/sp/src/public/tier1/convar.h index 314ee011..37268cc4 100644 --- a/sp/src/public/tier1/convar.h +++ b/sp/src/public/tier1/convar.h @@ -21,7 +21,7 @@ #include "tier1/utlvector.h" #include "tier1/utlstring.h" #include "icvar.h" -#include "color.h" +#include "Color.h" #ifdef _WIN32 #define FORCEINLINE_CVAR FORCEINLINE diff --git a/sp/src/public/vscript/ivscript.h b/sp/src/public/vscript/ivscript.h index 4b3388df..b2750f5c 100644 --- a/sp/src/public/vscript/ivscript.h +++ b/sp/src/public/vscript/ivscript.h @@ -95,6 +95,9 @@ #ifndef IVSCRIPT_H #define IVSCRIPT_H +#include +#include + #include "platform.h" #include "datamap.h" #include "appframework/IAppSystem.h" @@ -163,20 +166,6 @@ public: // //----------------------------------------------------------------------------- -#ifdef MAPBASE_VSCRIPT -template T *HScriptToClass( HSCRIPT hObj ) -{ - return (hObj) ? (T*)g_pScriptVM->GetInstanceValue( hObj, GetScriptDesc( (T*)NULL ) ) : NULL; -} -#else -DECLARE_POINTER_HANDLE( HSCRIPT ); -#define INVALID_HSCRIPT ((HSCRIPT)-1) -#endif - -//----------------------------------------------------------------------------- -// -//----------------------------------------------------------------------------- - enum ExtendedFieldType { FIELD_TYPEUNKNOWN = FIELD_TYPECOUNT, @@ -645,8 +634,21 @@ struct ScriptEnumDesc_t // //----------------------------------------------------------------------------- +// forwards T (and T&) if T is neither enum or an unsigned integer +// the overload for int below captures enums and unsigned integers and "bends" them to int +template +static inline typename std::enable_if::type>::value && !std::is_unsigned::type>::value, T&&>::type ToConstantVariant(T &&value) +{ + return std::forward(value); +} + +static inline int ToConstantVariant(int value) +{ + return value; +} + #define ScriptRegisterConstant( pVM, constant, description ) ScriptRegisterConstantNamed( pVM, constant, #constant, description ) -#define ScriptRegisterConstantNamed( pVM, constant, scriptName, description ) do { static ScriptConstantBinding_t binding; binding.m_pszScriptName = scriptName; binding.m_pszDescription = description; binding.m_data = constant; pVM->RegisterConstant( &binding ); } while (0) +#define ScriptRegisterConstantNamed( pVM, constant, scriptName, description ) do { static ScriptConstantBinding_t binding; binding.m_pszScriptName = scriptName; binding.m_pszDescription = description; binding.m_data = ToConstantVariant(constant); pVM->RegisterConstant( &binding ); } while (0) // Could probably use a better name. // This is used for registering variants (particularly vectors) not tied to existing variables. @@ -1090,6 +1092,20 @@ public: #endif }; +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- + +#ifdef MAPBASE_VSCRIPT +template T *HScriptToClass( HSCRIPT hObj ) +{ + extern IScriptVM *g_pScriptVM; + return (hObj) ? (T*)g_pScriptVM->GetInstanceValue( hObj, GetScriptDesc( (T*)NULL ) ) : NULL; +} +#else +DECLARE_POINTER_HANDLE( HSCRIPT ); +#define INVALID_HSCRIPT ((HSCRIPT)-1) +#endif //----------------------------------------------------------------------------- // Script scope helper class diff --git a/sp/src/tier1/mapbase_con_groups.cpp b/sp/src/tier1/mapbase_con_groups.cpp index cb01280e..08ca8fc7 100644 --- a/sp/src/tier1/mapbase_con_groups.cpp +++ b/sp/src/tier1/mapbase_con_groups.cpp @@ -162,6 +162,6 @@ void CGMsg( int level, int nGroup, const tchar* pMsg, ... ) } else { - ConColorMsg(level, pGroup->GetColor(), string); + ConColorMsg(level, pGroup->GetColor(), "%s", string); } } diff --git a/sp/src/vscript/vscript_squirrel.cpp b/sp/src/vscript/vscript_squirrel.cpp index af605ea1..0ec23b97 100644 --- a/sp/src/vscript/vscript_squirrel.cpp +++ b/sp/src/vscript/vscript_squirrel.cpp @@ -241,7 +241,7 @@ public: HSQOBJECT regexpClass_; }; -SQUserPointer TYPETAG_VECTOR = "VectorTypeTag"; +static char TYPETAG_VECTOR[] = "VectorTypeTag"; namespace SQVector { @@ -1089,7 +1089,7 @@ void PushVariant(HSQUIRRELVM vm, const ScriptVariant_t& value) sq_createinstance(vm, -1); SQUserPointer p; sq_getinstanceup(vm, -1, &p, 0); - new(p) Vector(value); + new(p) Vector(static_cast(value)); sq_remove(vm, -2); break; } From a5fb07d6ac31139b12583ef71e8bb45afb997b2d Mon Sep 17 00:00:00 2001 From: Alexander 'z33ky' Hirsch <1zeeky@gmail.com> Date: Wed, 27 Jan 2021 10:27:28 +0100 Subject: [PATCH 017/378] Fix gcc9+support.o compilation --- sp/src/devtools/makefile_base_posix.mak | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sp/src/devtools/makefile_base_posix.mak b/sp/src/devtools/makefile_base_posix.mak index 559ee2be..6eda6890 100644 --- a/sp/src/devtools/makefile_base_posix.mak +++ b/sp/src/devtools/makefile_base_posix.mak @@ -6,10 +6,10 @@ MAKEFILE_LINK:=$(THISFILE).link -include $(MAKEFILE_LINK) -$(MAKEFILE_LINK): $(shell which $(CC)) $(THISFILE) - if [ "$(shell printf "$(shell $(CC) -dumpversion)\n8" | sort -Vr | head -1)" = 8 ]; then \ - $(COMPILE.cpp) -o gcc9+support.o gcc9+support.c ;\ +$(MAKEFILE_LINK): $(shell which $(CXX)) $(THISFILE) + @ if [ "$(shell printf "$(shell $(CXX) -dumpversion)\n8" | sort -Vr | head -1)" = 8 ]; then \ ln -sf $(MAKEFILE_BASE).default $@ ;\ else \ + $(COMPILE.cpp) -o $(SRCROOT)/devtools/gcc9+support.o $(SRCROOT)/devtools/gcc9+support.cpp &&\ ln -sf $(MAKEFILE_BASE).gcc8 $@ ;\ fi From 718186f1656b4426fc51905da08129c7767f02a6 Mon Sep 17 00:00:00 2001 From: Alexander 'z33ky' Hirsch <1zeeky@gmail.com> Date: Wed, 27 Jan 2021 13:26:17 +0100 Subject: [PATCH 018/378] Specify gcc9+support.cpp dependency for gcc8+ Makefiles --- sp/src/devtools/makefile_base_posix.mak | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sp/src/devtools/makefile_base_posix.mak b/sp/src/devtools/makefile_base_posix.mak index 6eda6890..21147f21 100644 --- a/sp/src/devtools/makefile_base_posix.mak +++ b/sp/src/devtools/makefile_base_posix.mak @@ -6,7 +6,8 @@ MAKEFILE_LINK:=$(THISFILE).link -include $(MAKEFILE_LINK) -$(MAKEFILE_LINK): $(shell which $(CXX)) $(THISFILE) +# depend on CXX so the correct makefile can be selected when the system is updated +$(MAKEFILE_LINK): $(shell which $(CXX)) $(THISFILE) $(SRCROOT)/devtools/gcc9+support.cpp @ if [ "$(shell printf "$(shell $(CXX) -dumpversion)\n8" | sort -Vr | head -1)" = 8 ]; then \ ln -sf $(MAKEFILE_BASE).default $@ ;\ else \ From e0091261ed226403059df69b674abffcbd1b0e12 Mon Sep 17 00:00:00 2001 From: Alexander 'z33ky' Hirsch <1zeeky@gmail.com> Date: Sat, 20 Mar 2021 13:58:23 +0100 Subject: [PATCH 019/378] Fix Buttons not working on Linux with newer gcc The button mask is created by shifting a bit according to the MouseCode, which is just a renamed ButtonCode_t. Mouse buttons start at 107, which is way out of range for our ints. To fix this, introduce MouseButtonBit(), which checks if a button code corresponds to a mouse button at all and returns a usable bitmask for the corresponding mouse button code. This is then used for the button mask. --- sp/src/public/vgui/MouseCode.h | 9 +++++++++ sp/src/vgui2/vgui_controls/Button.cpp | 6 +++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/sp/src/public/vgui/MouseCode.h b/sp/src/public/vgui/MouseCode.h index 7ba16214..9b13fc81 100644 --- a/sp/src/public/vgui/MouseCode.h +++ b/sp/src/public/vgui/MouseCode.h @@ -18,6 +18,15 @@ namespace vgui { typedef ButtonCode_t MouseCode; + +static inline int MouseButtonBit(MouseCode code) +{ + if (code < MOUSE_FIRST || code > MOUSE_LAST) { + Assert(false); + return 0; + } + return 1 << (code - MOUSE_FIRST); +} } #endif // MOUSECODE_H diff --git a/sp/src/vgui2/vgui_controls/Button.cpp b/sp/src/vgui2/vgui_controls/Button.cpp index cceb8043..406c3e13 100644 --- a/sp/src/vgui2/vgui_controls/Button.cpp +++ b/sp/src/vgui2/vgui_controls/Button.cpp @@ -695,12 +695,12 @@ void Button::SetMouseClickEnabled(MouseCode code,bool state) if(state) { //set bit to 1 - _mouseClickMask|=1<<((int)(code+1)); + _mouseClickMask|=MouseButtonBit(code); } else { //set bit to 0 - _mouseClickMask&=~(1<<((int)(code+1))); + _mouseClickMask&=~MouseButtonBit(code); } } @@ -709,7 +709,7 @@ void Button::SetMouseClickEnabled(MouseCode code,bool state) //----------------------------------------------------------------------------- bool Button::IsMouseClickEnabled(MouseCode code) { - if(_mouseClickMask&(1<<((int)(code+1)))) + if(_mouseClickMask&MouseButtonBit(code)) { return true; } From 761f065d552b5fccefff8bfa8b57fea4a0747a87 Mon Sep 17 00:00:00 2001 From: Alexander 'z33ky' Hirsch <1zeeky@gmail.com> Date: Sat, 20 Mar 2021 14:56:46 +0100 Subject: [PATCH 020/378] Fix stdshaders compilation on Linux --- sp/src/materialsystem/stdshaders/windowimposter_dx90.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sp/src/materialsystem/stdshaders/windowimposter_dx90.cpp b/sp/src/materialsystem/stdshaders/windowimposter_dx90.cpp index 99ac7914..d24ac04b 100644 --- a/sp/src/materialsystem/stdshaders/windowimposter_dx90.cpp +++ b/sp/src/materialsystem/stdshaders/windowimposter_dx90.cpp @@ -7,9 +7,9 @@ #include "BaseVSShader.h" #include "cpp_shader_constant_register_map.h" -#include "sdk_windowimposter_vs20.inc" -#include "sdk_windowimposter_ps20.inc" -#include "sdk_windowimposter_ps20b.inc" +#include "SDK_windowimposter_vs20.inc" +#include "SDK_windowimposter_ps20.inc" +#include "SDK_windowimposter_ps20b.inc" From 28e87ce3d240befea224d524398e3de4916d8525 Mon Sep 17 00:00:00 2001 From: Alexander 'z33ky' Hirsch <1zeeky@gmail.com> Date: Sat, 20 Mar 2021 19:21:53 +0100 Subject: [PATCH 021/378] Fix/Implement VScript FFI for GCC's virtual member functions --- sp/src/public/vscript/vscript_templates.h | 46 ++++++++++++++++------- 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/sp/src/public/vscript/vscript_templates.h b/sp/src/public/vscript/vscript_templates.h index e23a9fe9..2d7058a3 100644 --- a/sp/src/public/vscript/vscript_templates.h +++ b/sp/src/public/vscript/vscript_templates.h @@ -137,29 +137,25 @@ inline void *ScriptConvertFuncPtrToVoid( FUNCPTR_TYPE pFunc ) #elif defined( GNUC ) else if ( ( sizeof( FUNCPTR_TYPE ) == sizeof( void * ) + sizeof( int ) ) ) { - AssertMsg( 0, "Note: This path has not been verified yet. See comments below in #else case." ); - struct GnuMFP { union { void *funcadr; // If vtable_index_2 is even, then this is the function pointer. - int vtable_index_2; // If vtable_index_2 is odd, then this = vindex*2+1. + int vtable_index_2; // If vtable_index_2 is odd, then (vtable_index_2 - 1) * 2 is the index into the vtable. }; - int delta; + int delta; // Offset from this-ptr to vtable }; - + GnuMFP *p = (GnuMFP*)&pFunc; - if ( p->vtable_index_2 & 1 ) - { - char **delta = (char**)p->delta; - char *pCur = *delta + (p->vtable_index_2+1)/2; - return (void*)( pCur + 4 ); - } - else + if ( p->delta == 0 ) { + // No need to check whether this is a direct function pointer or not, + // this gets converted back to a "proper" member-function pointer in + // ScriptConvertFuncPtrFromVoid() to get invoked return p->funcadr; } + AssertMsg( 0, "Function pointer must be from primary vtable" ); } #else #error "Need to implement code to crack non-offset member function pointer case" @@ -257,8 +253,30 @@ inline FUNCPTR_TYPE ScriptConvertFuncPtrFromVoid( void *p ) convert.mfp.m_delta = 0; return convert.pFunc; } -#elif defined( POSIX ) - AssertMsg( 0, "Note: This path has not been implemented yet." ); +#elif defined( GNUC ) + if ( ( sizeof( FUNCPTR_TYPE ) == sizeof( void * ) + sizeof( int ) ) ) + { + struct GnuMFP + { + union + { + void *funcadr; // If vtable_index_2 is even, then this is the function pointer. + int vtable_index_2; // If vtable_index_2 is odd, then (vtable_index_2 - 1) * 2 is the index into the vtable. + }; + int delta; // Offset from this-ptr to vtable + }; + + union FuncPtrConvertGnu + { + GnuMFP mfp; + FUNCPTR_TYPE pFunc; + }; + + FuncPtrConvertGnu convert; + convert.mfp.funcadr = p; + convert.mfp.delta = 0; + return convert.pFunc; + } #else #error "Need to implement code to crack non-offset member function pointer case" #endif From aa4d02fcbfdfbac98074464e7534cab826914185 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Wed, 7 Apr 2021 13:46:26 -0500 Subject: [PATCH 022/378] Added NoteSpeaking and game_text mode for print responses --- sp/src/game/server/ai_expresserfollowup.cpp | 2 + sp/src/game/server/ai_speech_new.cpp | 50 +++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/sp/src/game/server/ai_expresserfollowup.cpp b/sp/src/game/server/ai_expresserfollowup.cpp index 84db4773..838be4ee 100644 --- a/sp/src/game/server/ai_expresserfollowup.cpp +++ b/sp/src/game/server/ai_expresserfollowup.cpp @@ -375,6 +375,7 @@ bool CAI_ExpresserWithFollowup::SpeakDispatchResponse( AIConcept_t &concept, AI_ ResolveFollowupTargetToEntity( concept, *criteria, response, followup ), -followup->followup_delay, GetOuter() ); } +#ifndef MAPBASE // RESPONSE_PRINT now notes speaking time else if ( response->GetType() == ResponseRules::RESPONSE_PRINT ) { // zero-duration responses dispatch immediately via the queue (must be the queue bec. // the m_pPostponedFollowup will never trigger) @@ -382,6 +383,7 @@ bool CAI_ExpresserWithFollowup::SpeakDispatchResponse( AIConcept_t &concept, AI_ ResolveFollowupTargetToEntity( concept, *criteria, response, followup ), followup->followup_delay, GetOuter() ); } +#endif else { // this is kind of a quick patch to immediately deal with the issue of null criteria diff --git a/sp/src/game/server/ai_speech_new.cpp b/sp/src/game/server/ai_speech_new.cpp index f04e6d2b..1edffdb7 100644 --- a/sp/src/game/server/ai_speech_new.cpp +++ b/sp/src/game/server/ai_speech_new.cpp @@ -35,6 +35,10 @@ inline void SpeechMsg( ... ) {} extern ConVar rr_debugresponses; +#ifdef MAPBASE +ConVar ai_speech_print_mode( "ai_speech_print_mode", "1", FCVAR_NONE, "Set this value to 1 to print responses as game_text instead of debug point_message-like text." ); +#endif + //----------------------------------------------------------------------------- CAI_TimedSemaphore g_AIFriendliesTalkSemaphore; @@ -889,6 +893,52 @@ bool CAI_Expresser::SpeakDispatchResponse( AIConcept_t &concept, AI_Response *re break; case ResponseRules::RESPONSE_PRINT: { +#ifdef MAPBASE + // Note speaking for print responses + int responseLen = Q_strlen( response ); + float responseDuration = ((float)responseLen) * 0.1f; + NoteSpeaking( responseDuration, delay ); + + // game_text print responses + hudtextparms_t textParams; + textParams.holdTime = 4.0f + responseDuration; // Give extra padding for the text itself + textParams.fadeinTime = 0.5f; + textParams.fadeoutTime = 0.5f; + + if (ai_speech_print_mode.GetBool() && GetOuter()->GetGameTextSpeechParams( textParams )) + { + CRecipientFilter filter; + filter.AddAllPlayers(); + filter.MakeReliable(); + + UserMessageBegin( filter, "HudMsg" ); + WRITE_BYTE ( textParams.channel & 0xFF ); + WRITE_FLOAT( textParams.x ); + WRITE_FLOAT( textParams.y ); + WRITE_BYTE ( textParams.r1 ); + WRITE_BYTE ( textParams.g1 ); + WRITE_BYTE ( textParams.b1 ); + WRITE_BYTE ( textParams.a1 ); + WRITE_BYTE ( textParams.r2 ); + WRITE_BYTE ( textParams.g2 ); + WRITE_BYTE ( textParams.b2 ); + WRITE_BYTE ( textParams.a2 ); + WRITE_BYTE ( textParams.effect ); + WRITE_FLOAT( textParams.fadeinTime ); + WRITE_FLOAT( textParams.fadeoutTime ); + WRITE_FLOAT( textParams.holdTime ); + WRITE_FLOAT( textParams.fxTime ); + WRITE_STRING( response ); + WRITE_STRING( "" ); // No custom font + WRITE_BYTE ( responseLen ); + MessageEnd(); + + spoke = true; + + OnSpeechFinished(); + } + else +#endif if ( g_pDeveloper->GetInt() > 0 ) { Vector vPrintPos; From 80c26ea1863e4502cf0501d572cd4480af2b920c Mon Sep 17 00:00:00 2001 From: Blixibon Date: Wed, 7 Apr 2021 13:50:05 -0500 Subject: [PATCH 023/378] Fixed new response system sometimes crashing on rule lookup when the system is reloaded by rr_reloadresponsesystems or map-specific talker files --- sp/src/responserules/runtime/response_system.cpp | 5 +++++ .../runtime/response_types_internal.cpp | 14 ++++++++++++++ .../runtime/response_types_internal.h | 3 +++ 3 files changed, 22 insertions(+) diff --git a/sp/src/responserules/runtime/response_system.cpp b/sp/src/responserules/runtime/response_system.cpp index 7867bda0..968f856d 100644 --- a/sp/src/responserules/runtime/response_system.cpp +++ b/sp/src/responserules/runtime/response_system.cpp @@ -246,7 +246,12 @@ void CResponseSystem::Clear() { m_Responses.RemoveAll(); m_Criteria.RemoveAll(); +#ifdef MAPBASE + // Must purge to avoid issues with reloading the system + m_RulePartitions.PurgeAndDeleteElements(); +#else m_RulePartitions.RemoveAll(); +#endif m_Enumerations.RemoveAll(); } diff --git a/sp/src/responserules/runtime/response_types_internal.cpp b/sp/src/responserules/runtime/response_types_internal.cpp index 72e7eca5..fe6d7fd0 100644 --- a/sp/src/responserules/runtime/response_types_internal.cpp +++ b/sp/src/responserules/runtime/response_types_internal.cpp @@ -88,6 +88,20 @@ void ResponseRulePartition::RemoveAll( void ) } } +#ifdef MAPBASE +void ResponseRulePartition::PurgeAndDeleteElements() +{ + for ( int bukkit = 0 ; bukkit < N_RESPONSE_PARTITIONS ; ++bukkit ) + { + for ( int i = m_RuleParts[bukkit].FirstInorder(); i != m_RuleParts[bukkit].InvalidIndex(); i = m_RuleParts[bukkit].NextInorder( i ) ) + { + delete m_RuleParts[bukkit][ i ]; + } + m_RuleParts[bukkit].Purge(); + } +} +#endif + // don't bucket "subject" criteria that prefix with operators, since stripping all that out again would // be a big pain, and the most important rules that need subjects are tlk_remarks anyway. static inline bool CanBucketBySubject( const char * RESTRICT pszSubject ) diff --git a/sp/src/responserules/runtime/response_types_internal.h b/sp/src/responserules/runtime/response_types_internal.h index 20cc9d54..25b6f2d1 100644 --- a/sp/src/responserules/runtime/response_types_internal.h +++ b/sp/src/responserules/runtime/response_types_internal.h @@ -433,6 +433,9 @@ namespace ResponseRules // dump everything. void RemoveAll(); +#ifdef MAPBASE + void PurgeAndDeleteElements(); +#endif inline Rule &operator[]( tIndex idx ); int Count( void ); // number of elements inside, but you can't iterate from 0 to this From bec712f3f9ffbd9b6b8ec6ecbff2292c1f27ae23 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Wed, 7 Apr 2021 13:51:17 -0500 Subject: [PATCH 024/378] Made followup sources attributable by classname --- sp/src/game/server/ai_expresserfollowup.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sp/src/game/server/ai_expresserfollowup.cpp b/sp/src/game/server/ai_expresserfollowup.cpp index 838be4ee..759f5c46 100644 --- a/sp/src/game/server/ai_expresserfollowup.cpp +++ b/sp/src/game/server/ai_expresserfollowup.cpp @@ -77,6 +77,7 @@ static void DispatchComeback( CAI_ExpresserWithFollowup *pExpress, CBaseEntity * #ifdef MAPBASE // See DispatchFollowupThroughQueue() criteria.AppendCriteria( "From_idx", CNumStr( pSpeaker->entindex() ) ); + criteria.AppendCriteria( "From_class", pSpeaker->GetClassname() ); #endif // if a SUBJECT criteria is missing, put it back in. if ( criteria.FindCriterionIndex( "Subject" ) == -1 ) @@ -427,6 +428,9 @@ void CAI_ExpresserWithFollowup::DispatchFollowupThroughQueue( const AIConcept_t // changes internal operations of the "From" context to search for an entity index. This won't be 100% reliable if the source // talker dies and another entity is created immediately afterwards, but it's a lot more reliable than a simple entity name search. criteria.AppendCriteria( "From_idx", CNumStr( pOuter->entindex() ) ); + + // Generic NPCs should also be attributable by classname + criteria.AppendCriteria( "From_class", pOuter->GetClassname() ); #endif criteria.Merge( criteriaStr ); From 1a6f1f0cab2fd372851dbf95be254135baca29c2 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Wed, 7 Apr 2021 13:53:06 -0500 Subject: [PATCH 025/378] Replaced expresser cases involving CBaseMultiplayerPlayer with CBasePlayer to allow singleplayer expressers to be obtained --- sp/src/game/server/ai_speechqueue.cpp | 4 ++++ sp/src/game/server/sceneentity.cpp | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/sp/src/game/server/ai_speechqueue.cpp b/sp/src/game/server/ai_speechqueue.cpp index 79794d4b..7e8bf055 100644 --- a/sp/src/game/server/ai_speechqueue.cpp +++ b/sp/src/game/server/ai_speechqueue.cpp @@ -174,7 +174,11 @@ void CResponseQueue::RemoveExpresserHost(CBaseEntity *host) /// TODO: Kind of an ugly hack until I get the class hierarchy straightened out. static CAI_Expresser *InferExpresserFromBaseEntity(CBaseEntity * RESTRICT pEnt) { +#ifdef MAPBASE + if ( CBasePlayer *pPlayer = ToBasePlayer(pEnt) ) +#else if ( CBaseMultiplayerPlayer *pPlayer = dynamic_cast(pEnt) ) +#endif { return pPlayer->GetExpresser(); } diff --git a/sp/src/game/server/sceneentity.cpp b/sp/src/game/server/sceneentity.cpp index 92914d05..1ff2b18e 100644 --- a/sp/src/game/server/sceneentity.cpp +++ b/sp/src/game/server/sceneentity.cpp @@ -4835,10 +4835,17 @@ void CSceneEntity::OnSceneFinished( bool canceled, bool fireoutput ) CBaseFlex *pFlex = FindNamedActor( 0 ) ; if ( pFlex ) { +#ifdef MAPBASE + CBasePlayer *pAsPlayer = ToBasePlayer(pFlex); +#else CBaseMultiplayerPlayer *pAsPlayer = dynamic_cast(pFlex); +#endif if (pAsPlayer) { CAI_Expresser *pExpresser = pAsPlayer->GetExpresser(); +#ifdef MAPBASE + if (pExpresser) +#endif pExpresser->OnSpeechFinished(); } else if ( CAI_BaseActor *pActor = dynamic_cast( pFlex ) ) From 9510c03ab3b59d0112765293c809035f3042f508 Mon Sep 17 00:00:00 2001 From: James Mitchell Date: Sun, 11 Apr 2021 08:38:02 +1000 Subject: [PATCH 026/378] Fixing bug with vscript restore cache not updating soon enough --- sp/src/vscript/vscript_squirrel.cpp | 37 +++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/sp/src/vscript/vscript_squirrel.cpp b/sp/src/vscript/vscript_squirrel.cpp index af605ea1..e24abb9b 100644 --- a/sp/src/vscript/vscript_squirrel.cpp +++ b/sp/src/vscript/vscript_squirrel.cpp @@ -65,8 +65,16 @@ struct WriteStateMap struct ReadStateMap { CUtlMap cache; +#ifdef _DEBUG + CUtlMap allocated; +#endif HSQUIRRELVM vm_; - ReadStateMap(HSQUIRRELVM vm) : cache(DefLessFunc(int)), vm_(vm) + ReadStateMap(HSQUIRRELVM vm) : + cache(DefLessFunc(int)), +#ifdef _DEBUG + allocated(DefLessFunc(int)), +#endif + vm_(vm) {} ~ReadStateMap() @@ -83,6 +91,16 @@ struct ReadStateMap int marker = pBuffer->GetInt(); auto idx = cache.Find(marker); + +#ifdef _DEBUG + auto allocatedIdx = allocated.Find(marker); + bool hasSeen = allocatedIdx != allocated.InvalidIndex(); + if (!hasSeen) + { + allocated.Insert(marker, true); + } +#endif + if (idx != cache.InvalidIndex()) { sq_pushobject(vm, cache[idx]); @@ -90,6 +108,9 @@ struct ReadStateMap } else { +#ifdef _DEBUG + Assert(!hasSeen); +#endif *outmarker = marker; return false; } @@ -3388,6 +3409,7 @@ void SquirrelVM::WriteState(CUtlBuffer* pBuffer) int count = sq_getsize(vm_, 1); sq_pushnull(vm_); pBuffer->PutInt(count); + while (SQ_SUCCEEDED(sq_next(vm_, -2))) { WriteObject(pBuffer, writeState, -2); @@ -3521,6 +3543,9 @@ void SquirrelVM::ReadObject(CUtlBuffer* pBuffer, ReadStateMap& readState) break; } + vm_->Push(ret); + readState.StoreTopInCache(marker); + int noutervalues = _closure(ret)->_function->_noutervalues; for (int i = 0; i < noutervalues; ++i) { @@ -3542,9 +3567,6 @@ void SquirrelVM::ReadObject(CUtlBuffer* pBuffer, ReadStateMap& readState) _closure(ret)->_defaultparams[i] = obj; sq_poptop(vm_); } - - vm_->Push(ret); - readState.StoreTopInCache(marker); } ReadObject(pBuffer, readState); @@ -3816,16 +3838,17 @@ void SquirrelVM::ReadObject(CUtlBuffer* pBuffer, ReadStateMap& readState) break; } + SQOuter* outer = SQOuter::Create(_ss(vm_), nullptr); + vm_->Push(outer); + readState.StoreTopInCache(marker); + ReadObject(pBuffer, readState); HSQOBJECT inner; sq_resetobject(&inner); sq_getstackobj(vm_, -1, &inner); - SQOuter* outer = SQOuter::Create(_ss(vm_), nullptr); outer->_value = inner; outer->_valptr = &(outer->_value); sq_poptop(vm_); - vm_->Push(outer); - readState.StoreTopInCache(marker); break; } From d7a06e863e86be9f6d58ac4caf681342f56787bd Mon Sep 17 00:00:00 2001 From: samisalreadytaken <46823719+samisalreadytaken@users.noreply.github.com> Date: Sun, 18 Apr 2021 18:43:05 +0200 Subject: [PATCH 027/378] Fix ScriptContextThink precision errors --- sp/src/game/client/c_baseentity.h | 9 +- sp/src/game/server/baseentity.h | 11 +- sp/src/game/shared/baseentity_shared.cpp | 162 ++++++++++------------- 3 files changed, 80 insertions(+), 102 deletions(-) diff --git a/sp/src/game/client/c_baseentity.h b/sp/src/game/client/c_baseentity.h index dabfbbd9..396cd3f0 100644 --- a/sp/src/game/client/c_baseentity.h +++ b/sp/src/game/client/c_baseentity.h @@ -164,10 +164,9 @@ struct thinkfunc_t #ifdef MAPBASE_VSCRIPT struct scriptthinkfunc_t { - int m_nNextThinkTick; - HSCRIPT m_hfnThink; - unsigned short m_iContextHash; - bool m_bNoParam; + float m_flNextThink; + HSCRIPT m_hfnThink; + unsigned m_iContextHash; }; #endif @@ -295,6 +294,8 @@ public: string_t m_iszScriptId; #ifdef MAPBASE_VSCRIPT CScriptScope m_ScriptScope; + + static ScriptHook_t g_Hook_UpdateOnRemove; #endif // IClientUnknown overrides. diff --git a/sp/src/game/server/baseentity.h b/sp/src/game/server/baseentity.h index a96d443b..fc8d232e 100644 --- a/sp/src/game/server/baseentity.h +++ b/sp/src/game/server/baseentity.h @@ -341,10 +341,10 @@ struct thinkfunc_t #ifdef MAPBASE_VSCRIPT struct scriptthinkfunc_t { - int m_nNextThinkTick; - HSCRIPT m_hfnThink; - unsigned short m_iContextHash; - bool m_bNoParam; + float m_flNextThink; + HSCRIPT m_hfnThink; + unsigned m_iContextHash; + bool m_bNoParam; }; #endif @@ -2115,6 +2115,9 @@ public: int ScriptGetMoveType() { return GetMoveType(); } void ScriptSetMoveType( int iMoveType ) { SetMoveType( (MoveType_t)iMoveType ); } + int ScriptGetSolid() { return GetSolid(); } + void ScriptSetSolid( int i ) { SetSolid( (SolidType_t)i ); } + bool ScriptDispatchInteraction( int interactionType, HSCRIPT data, HSCRIPT sourceEnt ); int ScriptGetTakeDamage() { return m_takedamage; } diff --git a/sp/src/game/shared/baseentity_shared.cpp b/sp/src/game/shared/baseentity_shared.cpp index cae3f5d9..207f4544 100644 --- a/sp/src/game/shared/baseentity_shared.cpp +++ b/sp/src/game/shared/baseentity_shared.cpp @@ -2713,13 +2713,20 @@ HSCRIPT CBaseEntity::ScriptGetPhysicsObject( void ) return NULL; } + +#ifdef GAME_DLL +#define SCRIPT_NEVER_THINK TICK_NEVER_THINK +#else +#define SCRIPT_NEVER_THINK CLIENT_THINK_NEVER +#endif + static inline void ScriptStopContextThink( scriptthinkfunc_t *context ) { Assert( context->m_hfnThink ); + Assert( context->m_flNextThink == SCRIPT_NEVER_THINK ); g_pScriptVM->ReleaseScript( context->m_hfnThink ); context->m_hfnThink = NULL; - //context->m_nNextThinkTick = TICK_NEVER_THINK; } //----------------------------------------------------------------------------- @@ -2728,55 +2735,56 @@ static inline void ScriptStopContextThink( scriptthinkfunc_t *context ) void CBaseEntity::ScriptContextThink() { float flNextThink = FLT_MAX; - int nScheduledTick = 0; + float flScheduled = 0.0f; for ( int i = 0; i < m_ScriptThinkFuncs.Count(); ++i ) { scriptthinkfunc_t *cur = m_ScriptThinkFuncs[i]; - if ( cur->m_nNextThinkTick == TICK_NEVER_THINK ) + if ( cur->m_flNextThink == SCRIPT_NEVER_THINK ) { continue; } - if ( cur->m_nNextThinkTick > gpGlobals->tickcount ) + if ( cur->m_flNextThink > gpGlobals->curtime ) { - // There is more to execute, don't stop thinking if the rest are done. - - // Find the shortest schedule - if ( !nScheduledTick || nScheduledTick > cur->m_nNextThinkTick ) + if ( ( flScheduled == 0.0f ) || ( flScheduled > cur->m_flNextThink ) ) { - nScheduledTick = cur->m_nNextThinkTick; + flScheduled = cur->m_flNextThink; } continue; } #ifdef _DEBUG // going to run the script func - cur->m_nNextThinkTick = 0; + cur->m_flNextThink = 0; #endif ScriptVariant_t varReturn; +#ifndef CLIENT_DLL if ( !cur->m_bNoParam ) { +#endif ScriptVariant_t arg = m_hScriptInstance; if ( g_pScriptVM->ExecuteFunction( cur->m_hfnThink, &arg, 1, &varReturn, NULL, true ) == SCRIPT_ERROR ) { - cur->m_nNextThinkTick = TICK_NEVER_THINK; + cur->m_flNextThink = SCRIPT_NEVER_THINK; continue; } +#ifndef CLIENT_DLL } else { if ( g_pScriptVM->ExecuteFunction( cur->m_hfnThink, NULL, 0, &varReturn, NULL, true ) == SCRIPT_ERROR ) { - cur->m_nNextThinkTick = TICK_NEVER_THINK; + cur->m_flNextThink = SCRIPT_NEVER_THINK; continue; } } +#endif - if ( cur->m_nNextThinkTick == TICK_NEVER_THINK ) + if ( cur->m_flNextThink == SCRIPT_NEVER_THINK ) { // stopped from script while thinking continue; @@ -2785,13 +2793,13 @@ void CBaseEntity::ScriptContextThink() float flReturn; if ( !varReturn.AssignTo( &flReturn ) ) { - cur->m_nNextThinkTick = TICK_NEVER_THINK; + cur->m_flNextThink = SCRIPT_NEVER_THINK; continue; } if ( flReturn < 0.0f ) { - cur->m_nNextThinkTick = TICK_NEVER_THINK; + cur->m_flNextThink = SCRIPT_NEVER_THINK; continue; } @@ -2800,95 +2808,60 @@ void CBaseEntity::ScriptContextThink() flNextThink = flReturn; } - cur->m_nNextThinkTick = TIME_TO_TICKS( gpGlobals->curtime + flReturn ); + cur->m_flNextThink = gpGlobals->curtime + flReturn - 0.001; } // deferred safe removal for ( int i = 0; i < m_ScriptThinkFuncs.Count(); ) { - if ( m_ScriptThinkFuncs[i]->m_nNextThinkTick == TICK_NEVER_THINK ) + scriptthinkfunc_t *cur = m_ScriptThinkFuncs[i]; + if ( cur->m_flNextThink == SCRIPT_NEVER_THINK ) { - ScriptStopContextThink( m_ScriptThinkFuncs[i] ); - delete m_ScriptThinkFuncs[i]; + ScriptStopContextThink( cur ); + delete cur; m_ScriptThinkFuncs.Remove(i); } else ++i; } - bool bNewNext = flNextThink < FLT_MAX; - -#ifdef _DEBUG -#ifdef GAME_DLL - int nNextThinkTick = GetNextThinkTick("ScriptContextThink"); // -1 -#else - int nNextThinkTick = GetNextThinkTick(); // 0 -#endif - if ( ( nNextThinkTick <= 0 ) || ( nNextThinkTick >= nScheduledTick ) || ( nNextThinkTick == gpGlobals->tickcount ) ) + if ( flNextThink < FLT_MAX ) { -#endif - if ( nScheduledTick ) + if ( flScheduled > 0.0f ) { - float flScheduledTime = TICKS_TO_TIME( nScheduledTick ); - - if ( bNewNext ) - { - flNextThink = min( gpGlobals->curtime + flNextThink, flScheduledTime ); - } - else - { - flNextThink = flScheduledTime; - } + flNextThink = min( gpGlobals->curtime + flNextThink, flScheduled ); } else { - if ( bNewNext ) - { - flNextThink = gpGlobals->curtime + flNextThink; - } - else - { -#ifdef GAME_DLL - flNextThink = TICK_NEVER_THINK; -#else - flNextThink = CLIENT_THINK_NEVER; -#endif - } + flNextThink = gpGlobals->curtime + flNextThink; } -#ifdef _DEBUG } else { - // Next think was set (from script) to a sooner tick while thinking? - Assert(0); - - if ( nScheduledTick ) + if ( flScheduled > 0.0f ) { - int nNextSchedule = min( nScheduledTick, nNextThinkTick ); - float flNextSchedule = TICKS_TO_TIME( nNextSchedule ); - - if ( bNewNext ) - { - flNextThink = min( gpGlobals->curtime + flNextThink, flNextSchedule ); - } - else - { - flNextThink = flNextSchedule; - } + flNextThink = flScheduled; } else { - float nextthink = TICKS_TO_TIME( nNextThinkTick ); - - if ( bNewNext ) - { - flNextThink = min( gpGlobals->curtime + flNextThink, nextthink ); - } - else - { - flNextThink = nextthink; - } + flNextThink = SCRIPT_NEVER_THINK; } } + +#ifdef _DEBUG +#ifdef GAME_DLL + int nNextThinkTick = GetNextThinkTick("ScriptContextThink"); + float flNextThinkTime = TICKS_TO_TIME(nNextThinkTick); + + // If internal next think tick is earlier than what we have here with flNextThink, + // whoever set that think may fail. In worst case scenario the entity may stop thinking. + if ( nNextThinkTick > gpGlobals->tickcount ) + { + if ( flNextThink == SCRIPT_NEVER_THINK ) + Assert(0); + if ( flNextThinkTime < flNextThink ) + Assert(0); + } +#endif #endif #ifdef GAME_DLL @@ -2898,8 +2871,10 @@ void CBaseEntity::ScriptContextThink() #endif } +#ifndef CLIENT_DLL // see ScriptSetThink static bool s_bScriptContextThinkNoParam = false; +#endif //----------------------------------------------------------------------------- // @@ -2917,7 +2892,7 @@ void CBaseEntity::ScriptSetContextThink( const char* szContext, HSCRIPT hFunc, f #endif scriptthinkfunc_t *pf = NULL; - unsigned short hash = ( szContext && *szContext ) ? HashString( szContext ) : 0; + unsigned hash = szContext ? HashString( szContext ) : 0; FOR_EACH_VEC( m_ScriptThinkFuncs, i ) { @@ -2939,14 +2914,16 @@ void CBaseEntity::ScriptSetContextThink( const char* szContext, HSCRIPT hFunc, f m_ScriptThinkFuncs.SetGrowSize(1); m_ScriptThinkFuncs.AddToTail( pf ); - pf->m_bNoParam = s_bScriptContextThinkNoParam; pf->m_iContextHash = hash; +#ifndef CLIENT_DLL + pf->m_bNoParam = s_bScriptContextThinkNoParam; +#endif } // update existing else { #ifdef _DEBUG - if ( pf->m_nNextThinkTick == 0 ) + if ( pf->m_flNextThink == 0 ) { Warning("Script think ('%s') was changed while it was thinking!\n", szContext); } @@ -2957,31 +2934,29 @@ void CBaseEntity::ScriptSetContextThink( const char* szContext, HSCRIPT hFunc, f float nextthink = gpGlobals->curtime + flTime; pf->m_hfnThink = hFunc; - pf->m_nNextThinkTick = TIME_TO_TICKS( nextthink ); + pf->m_flNextThink = nextthink; #ifdef GAME_DLL int nexttick = GetNextThinkTick( RegisterThinkContext( "ScriptContextThink" ) ); -#else - int nexttick = GetNextThinkTick(); -#endif - - // sooner than next think - if ( nexttick <= 0 || nexttick > pf->m_nNextThinkTick ) + if ( nexttick <= 0 || TICKS_TO_TIME(nexttick) > nextthink ) { -#ifdef GAME_DLL SetContextThink( &CBaseEntity::ScriptContextThink, nextthink, "ScriptContextThink" ); -#else - SetNextClientThink( nextthink ); -#endif } +#else + { + // let it self adjust + SetNextClientThink( gpGlobals->curtime ); + } +#endif } // null func input, think exists else if ( pf ) { - pf->m_nNextThinkTick = TICK_NEVER_THINK; + pf->m_flNextThink = SCRIPT_NEVER_THINK; } } +#ifndef CLIENT_DLL //----------------------------------------------------------------------------- // m_bNoParam and s_bScriptContextThinkNoParam exist only to keep backwards compatibility // and are an alternative to this script closure: @@ -2991,7 +2966,6 @@ void CBaseEntity::ScriptSetContextThink( const char* szContext, HSCRIPT hFunc, f // SetContextThink( "", function(_){ return func() }, time ) // } //----------------------------------------------------------------------------- -#ifndef CLIENT_DLL void CBaseEntity::ScriptSetThink( HSCRIPT hFunc, float time ) { s_bScriptContextThinkNoParam = true; From f580801a3379818488d225fe3b37dd8f3cd34e0b Mon Sep 17 00:00:00 2001 From: Blixibon Date: Wed, 21 Apr 2021 10:53:48 -0500 Subject: [PATCH 028/378] Added I/O/KV for custom healthkits, custom battery models, and health/power multipliers --- sp/src/game/server/ai_basenpc.cpp | 13 +- sp/src/game/server/ai_basenpc.h | 5 - sp/src/game/server/cbase.h | 7 ++ sp/src/game/server/hl2/item_battery.cpp | 24 +++- sp/src/game/server/hl2/item_healthkit.cpp | 147 ++++++++++++++++++++++ sp/src/game/server/items.h | 5 +- 6 files changed, 183 insertions(+), 18 deletions(-) diff --git a/sp/src/game/server/ai_basenpc.cpp b/sp/src/game/server/ai_basenpc.cpp index 0f4e6a35..52147fb3 100644 --- a/sp/src/game/server/ai_basenpc.cpp +++ b/sp/src/game/server/ai_basenpc.cpp @@ -97,6 +97,7 @@ #ifdef MAPBASE #include "mapbase/matchers.h" +#include "items.h" #endif #include "env_debughistory.h" @@ -11509,17 +11510,9 @@ void CAI_BaseNPC::PickupItem( CBaseEntity *pItem ) m_OnItemPickup.Set( pItem, pItem, this ); Assert( pItem != NULL ); - if( FClassnameIs( pItem, "item_healthkit" ) ) + if( FClassnameIs( pItem, "item_health*" ) ) // item_healthkit, item_healthvial, item_healthkit_custom, etc. { - if ( TakeHealth( sk_healthkit.GetFloat(), DMG_GENERIC ) ) - { - RemoveAllDecals(); - UTIL_Remove( pItem ); - } - } - else if( FClassnameIs( pItem, "item_healthvial" ) ) - { - if ( TakeHealth( sk_healthvial.GetFloat(), DMG_GENERIC ) ) + if ( TakeHealth( static_cast(pItem)->GetItemAmount(), DMG_GENERIC ) ) { RemoveAllDecals(); UTIL_Remove( pItem ); diff --git a/sp/src/game/server/ai_basenpc.h b/sp/src/game/server/ai_basenpc.h index 2a2ad03c..9eaf2332 100644 --- a/sp/src/game/server/ai_basenpc.h +++ b/sp/src/game/server/ai_basenpc.h @@ -98,11 +98,6 @@ extern bool AIStrongOpt( void ); #ifdef MAPBASE // Defines Mapbase's extended NPC response system usage. #define EXPANDED_RESPONSE_SYSTEM_USAGE - -// Use the model keyvalue if it is defined -#define DefaultOrCustomModel(defaultModel) GetModelName() != NULL_STRING ? STRING(GetModelName()) : defaultModel -#else -#define DefaultOrCustomModel() defaultModel #endif #ifdef EXPANDED_RESPONSE_SYSTEM_USAGE diff --git a/sp/src/game/server/cbase.h b/sp/src/game/server/cbase.h index 290e3b25..2b00af39 100644 --- a/sp/src/game/server/cbase.h +++ b/sp/src/game/server/cbase.h @@ -104,6 +104,13 @@ extern void FireTargets( const char *targetName, CBaseEntity *pActivator, CBaseE #define MAX_OLD_ENEMIES 4 // how many old enemies to remember +#ifdef MAPBASE +// Use the model keyvalue if it is defined +#define DefaultOrCustomModel(defaultModel) GetModelName() != NULL_STRING ? STRING(GetModelName()) : defaultModel +#else +#define DefaultOrCustomModel() defaultModel +#endif + // used by suit voice to indicate damage sustained and repaired type to player enum diff --git a/sp/src/game/server/hl2/item_battery.cpp b/sp/src/game/server/hl2/item_battery.cpp index 7e299fc5..d5c8b416 100644 --- a/sp/src/game/server/hl2/item_battery.cpp +++ b/sp/src/game/server/hl2/item_battery.cpp @@ -23,12 +23,12 @@ public: void Spawn( void ) { Precache( ); - SetModel( "models/items/battery.mdl" ); + SetModel( DefaultOrCustomModel( "models/items/battery.mdl" ) ); BaseClass::Spawn( ); } void Precache( void ) { - PrecacheModel ("models/items/battery.mdl"); + PrecacheModel( DefaultOrCustomModel( "models/items/battery.mdl" ) ); PrecacheScriptSound( "ItemBattery.Touch" ); @@ -36,10 +36,30 @@ public: bool MyTouch( CBasePlayer *pPlayer ) { CHL2_Player *pHL2Player = dynamic_cast( pPlayer ); +#ifdef MAPBASE + return ( pHL2Player && pHL2Player->ApplyBattery( m_flPowerMultiplier ) ); +#else return ( pHL2Player && pHL2Player->ApplyBattery() ); +#endif } + +#ifdef MAPBASE + void InputSetPowerMultiplier( inputdata_t &inputdata ) { m_flPowerMultiplier = inputdata.value.Float(); } + float m_flPowerMultiplier = 1.0f; + + DECLARE_DATADESC(); +#endif }; LINK_ENTITY_TO_CLASS(item_battery, CItemBattery); PRECACHE_REGISTER(item_battery); +#ifdef MAPBASE +BEGIN_DATADESC( CItemBattery ) + + DEFINE_KEYFIELD( m_flPowerMultiplier, FIELD_FLOAT, "PowerMultiplier" ), + DEFINE_INPUTFUNC( FIELD_FLOAT, "SetPowerMultiplier", InputSetPowerMultiplier ), + +END_DATADESC() +#endif + diff --git a/sp/src/game/server/hl2/item_healthkit.cpp b/sp/src/game/server/hl2/item_healthkit.cpp index 628f873e..54f961c7 100644 --- a/sp/src/game/server/hl2/item_healthkit.cpp +++ b/sp/src/game/server/hl2/item_healthkit.cpp @@ -30,11 +30,29 @@ public: void Spawn( void ); void Precache( void ); bool MyTouch( CBasePlayer *pPlayer ); + +#ifdef MAPBASE + float GetItemAmount() { return sk_healthkit.GetFloat() * m_flHealthMultiplier; } + + void InputSetHealthMultiplier( inputdata_t &inputdata ) { m_flHealthMultiplier = inputdata.value.Float(); } + float m_flHealthMultiplier = 1.0f; + + DECLARE_DATADESC(); +#endif }; LINK_ENTITY_TO_CLASS( item_healthkit, CHealthKit ); PRECACHE_REGISTER(item_healthkit); +#ifdef MAPBASE +BEGIN_DATADESC( CHealthKit ) + + DEFINE_KEYFIELD( m_flHealthMultiplier, FIELD_FLOAT, "HealthMultiplier" ), + DEFINE_INPUTFUNC( FIELD_FLOAT, "SetHealthMultiplier", InputSetHealthMultiplier ), + +END_DATADESC() +#endif + //----------------------------------------------------------------------------- // Purpose: @@ -66,7 +84,11 @@ void CHealthKit::Precache( void ) //----------------------------------------------------------------------------- bool CHealthKit::MyTouch( CBasePlayer *pPlayer ) { +#ifdef MAPBASE + if ( pPlayer->TakeHealth( GetItemAmount(), DMG_GENERIC ) ) +#else if ( pPlayer->TakeHealth( sk_healthkit.GetFloat(), DMG_GENERIC ) ) +#endif { CSingleUserRecipientFilter user( pPlayer ); user.MakeReliable(); @@ -119,7 +141,11 @@ public: bool MyTouch( CBasePlayer *pPlayer ) { +#ifdef MAPBASE + if ( pPlayer->TakeHealth( GetItemAmount(), DMG_GENERIC ) ) +#else if ( pPlayer->TakeHealth( sk_healthvial.GetFloat(), DMG_GENERIC ) ) +#endif { CSingleUserRecipientFilter user( pPlayer ); user.MakeReliable(); @@ -145,11 +171,132 @@ public: return false; } + +#ifdef MAPBASE + float GetItemAmount() { return sk_healthvial.GetFloat() * m_flHealthMultiplier; } + + void InputSetHealthMultiplier( inputdata_t &inputdata ) { m_flHealthMultiplier = inputdata.value.Float(); } + float m_flHealthMultiplier = 1.0f; + + DECLARE_DATADESC(); +#endif }; LINK_ENTITY_TO_CLASS( item_healthvial, CHealthVial ); PRECACHE_REGISTER( item_healthvial ); +#ifdef MAPBASE +BEGIN_DATADESC( CHealthVial ) + + DEFINE_KEYFIELD( m_flHealthMultiplier, FIELD_FLOAT, "HealthMultiplier" ), + DEFINE_INPUTFUNC( FIELD_FLOAT, "SetHealthMultiplier", InputSetHealthMultiplier ), + +END_DATADESC() + + +//----------------------------------------------------------------------------- +// Small health kit. Heals the player when picked up. +//----------------------------------------------------------------------------- +class CHealthKitCustom : public CItem +{ +public: + DECLARE_CLASS( CHealthKitCustom, CItem ); + CHealthKitCustom(); + + void Spawn( void ); + void Precache( void ); + bool MyTouch( CBasePlayer *pPlayer ); + + float GetItemAmount() { return m_flHealthAmount; } + + void InputSetHealthAmount( inputdata_t &inputdata ) { m_flHealthAmount = inputdata.value.Float(); } + + float m_flHealthAmount; + string_t m_iszTouchSound; + + DECLARE_DATADESC(); +}; + +LINK_ENTITY_TO_CLASS( item_healthkit_custom, CHealthKitCustom ); +//PRECACHE_REGISTER(item_healthkit_custom); + +#ifdef MAPBASE +BEGIN_DATADESC( CHealthKitCustom ) + + DEFINE_KEYFIELD( m_flHealthAmount, FIELD_FLOAT, "HealthAmount" ), + DEFINE_KEYFIELD( m_iszTouchSound, FIELD_STRING, "TouchSound" ), + + DEFINE_INPUTFUNC( FIELD_FLOAT, "SetHealthAmount", InputSetHealthAmount ), + +END_DATADESC() +#endif + + +CHealthKitCustom::CHealthKitCustom() +{ + SetModelName( AllocPooledString( "models/items/healthkit.mdl" ) ); + m_flHealthAmount = sk_healthkit.GetFloat(); + m_iszTouchSound = AllocPooledString( "HealthKit.Touch" ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHealthKitCustom::Spawn( void ) +{ + Precache(); + SetModel( STRING( GetModelName() ) ); + + BaseClass::Spawn(); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHealthKitCustom::Precache( void ) +{ + PrecacheModel( STRING( GetModelName() ) ); + + PrecacheScriptSound( STRING( m_iszTouchSound ) ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *pPlayer - +// Output : +//----------------------------------------------------------------------------- +bool CHealthKitCustom::MyTouch( CBasePlayer *pPlayer ) +{ + if ( pPlayer->TakeHealth( GetItemAmount(), DMG_GENERIC ) ) + { + CSingleUserRecipientFilter user( pPlayer ); + user.MakeReliable(); + + UserMessageBegin( user, "ItemPickup" ); + WRITE_STRING( GetClassname() ); + MessageEnd(); + + CPASAttenuationFilter filter( pPlayer, STRING( m_iszTouchSound ) ); + EmitSound( filter, pPlayer->entindex(), STRING( m_iszTouchSound ) ); + + if ( g_pGameRules->ItemShouldRespawn( this ) == GR_ITEM_RESPAWN_YES ) + { + Respawn(); + } + else + { + UTIL_Remove(this); + } + + return true; + } + + return false; +} +#endif + //----------------------------------------------------------------------------- // Wall mounted health kit. Heals the player when used. //----------------------------------------------------------------------------- diff --git a/sp/src/game/server/items.h b/sp/src/game/server/items.h index 2089fa1f..53f440e8 100644 --- a/sp/src/game/server/items.h +++ b/sp/src/game/server/items.h @@ -90,9 +90,12 @@ public: #ifdef MAPBASE // This is in CBaseEntity, but I can't find a use for it anywhere. - // Must not have been fully implemented. Please remove this if it turns out to be something important. + // It may have been originally intended for TF2 or some other game-specific item class. Please remove this if it turns out to be something important. virtual bool IsCombatItem() { return true; } + // Used to access item_healthkit values, etc. from outside of the class + virtual float GetItemAmount() { return 1.0f; } + void InputEnablePlayerPickup( inputdata_t &inputdata ); void InputDisablePlayerPickup( inputdata_t &inputdata ); void InputEnableNPCPickup( inputdata_t &inputdata ); From 138a25c53c5a5fcab8f416c4121b880f3dde33fd Mon Sep 17 00:00:00 2001 From: Blixibon Date: Wed, 21 Apr 2021 14:58:51 -0500 Subject: [PATCH 029/378] Added custom core ball shader --- .../game/client/episodic/c_prop_scalable.cpp | 57 ++++ .../stdshaders/SDK_core_ps2x.fxc | 222 +++++++++++++ .../stdshaders/SDK_core_vs20.fxc | 103 ++++++ sp/src/materialsystem/stdshaders/core_dx9.cpp | 307 ++++++++++++++++++ .../stdshaders/fxctmp9/SDK_core_ps20.inc | 162 +++++++++ .../stdshaders/fxctmp9/SDK_core_ps20b.inc | 187 +++++++++++ .../stdshaders/fxctmp9/SDK_core_vs20.inc | 112 +++++++ .../stdshaders/fxctmp9_tmp/SDK_core_ps20.inc | 162 +++++++++ .../stdshaders/fxctmp9_tmp/SDK_core_ps20b.inc | 187 +++++++++++ .../stdshaders/fxctmp9_tmp/SDK_core_vs20.inc | 112 +++++++ .../stdshaders/game_shader_dx9_mapbase.vpc | 2 + 11 files changed, 1613 insertions(+) create mode 100644 sp/src/materialsystem/stdshaders/SDK_core_ps2x.fxc create mode 100644 sp/src/materialsystem/stdshaders/SDK_core_vs20.fxc create mode 100644 sp/src/materialsystem/stdshaders/core_dx9.cpp create mode 100644 sp/src/materialsystem/stdshaders/fxctmp9/SDK_core_ps20.inc create mode 100644 sp/src/materialsystem/stdshaders/fxctmp9/SDK_core_ps20b.inc create mode 100644 sp/src/materialsystem/stdshaders/fxctmp9/SDK_core_vs20.inc create mode 100644 sp/src/materialsystem/stdshaders/fxctmp9_tmp/SDK_core_ps20.inc create mode 100644 sp/src/materialsystem/stdshaders/fxctmp9_tmp/SDK_core_ps20b.inc create mode 100644 sp/src/materialsystem/stdshaders/fxctmp9_tmp/SDK_core_vs20.inc diff --git a/sp/src/game/client/episodic/c_prop_scalable.cpp b/sp/src/game/client/episodic/c_prop_scalable.cpp index d3902db3..b3134460 100644 --- a/sp/src/game/client/episodic/c_prop_scalable.cpp +++ b/sp/src/game/client/episodic/c_prop_scalable.cpp @@ -5,6 +5,10 @@ //============================================================================= #include "cbase.h" +#ifdef MAPBASE +#include "proxyentity.h" +#include "materialsystem/imaterialvar.h" +#endif class C_PropScalable : public C_BaseAnimating { @@ -194,3 +198,56 @@ void C_PropScalable::GetRenderBounds( Vector &theMins, Vector &theMaxs ) Assert( theMins.IsValid() && theMaxs.IsValid() ); } + +#ifdef MAPBASE +ConVar r_coreball_update_sphere_center( "r_coreball_update_sphere_center", "1", FCVAR_NONE, "Allows prop_coreball to update its center to the entity's origin" ); + +class CCoreBallUpdateMaterialProxy : public CEntityMaterialProxy +{ +public: + CCoreBallUpdateMaterialProxy() + { + m_pMaterial = NULL; + m_pSphereCenter = NULL; + } + virtual ~CCoreBallUpdateMaterialProxy() + { + } + virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues ) + { + m_pMaterial = pMaterial; + bool found; + m_pSphereCenter = m_pMaterial->FindVar( "$spherecenter", &found ); + if( !found ) + { + m_pSphereCenter = NULL; + return false; + } + return true; + } + virtual void OnBind( C_BaseEntity *pC_BaseEntity ) + { + if (r_coreball_update_sphere_center.GetBool()) + { + const Vector &origin = pC_BaseEntity->GetAbsOrigin(); + m_pSphereCenter->SetVecValue( origin.x, origin.y, origin.z ); + } + else + { + // Just continuously bind the old hacked value (TODO: Optimize so it's not just assigning the same value constantly?) + m_pSphereCenter->SetVecValue( 2688.0, 12139.0, 5170.0 ); + } + } + + virtual IMaterial *GetMaterial() + { + return m_pMaterial; + } + +protected: + IMaterial *m_pMaterial; + IMaterialVar *m_pSphereCenter; +}; + +EXPOSE_INTERFACE( CCoreBallUpdateMaterialProxy, IMaterialProxy, "CoreBallUpdate" IMATERIAL_PROXY_INTERFACE_VERSION ); +#endif diff --git a/sp/src/materialsystem/stdshaders/SDK_core_ps2x.fxc b/sp/src/materialsystem/stdshaders/SDK_core_ps2x.fxc new file mode 100644 index 00000000..3db01c24 --- /dev/null +++ b/sp/src/materialsystem/stdshaders/SDK_core_ps2x.fxc @@ -0,0 +1,222 @@ +//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======= +// +// Purpose: +// +//============================================================================= + +// STATIC: "CONVERT_TO_SRGB" "0..1" [ps20b][= g_pHardwareConfig->NeedsShaderSRGBConversion()] [PC] +// STATIC: "CONVERT_TO_SRGB" "0..0" [= 0] [XBOX] +// STATIC: "CUBEMAP" "0..1" +// STATIC: "FLOWMAP" "0..1" +// STATIC: "CORECOLORTEXTURE" "0..1" +// STATIC: "REFRACT" "0..1" +// DYNAMIC: "PIXELFOGTYPE" "0..1" + +// SKIP: ( $REFRACT || $CORECOLORTEXTURE ) && $CUBEMAP + +#include "common_ps_fxc.h" + +sampler RefractSampler : register( s2 ); +sampler NormalSampler : register( s3 ); +#if CUBEMAP +sampler EnvmapSampler : register( s4 ); +#endif +#if FLOWMAP +sampler FlowmapSampler : register( s6 ); +#endif + +#if CORECOLORTEXTURE +sampler CoreColorSampler : register( s7 ); +#endif + +const HALF3 g_EnvmapTint : register( c0 ); +const HALF3 g_RefractTint : register( c1 ); +const HALF3 g_EnvmapContrast : register( c2 ); +const HALF3 g_EnvmapSaturation : register( c3 ); +const HALF2 g_RefractScale : register( c5 ); +#if FLOWMAP +const float g_Time : register( c6 ); +const float2 g_FlowScrollRate : register( c7 ); +const float g_CoreColorTexCoordOffset : register( c9 ); +#endif + +const float3 g_EyePos : register( c8 ); +const float4 g_FogParams : register( c11 ); + + +const float3 g_SphereCenter : register( c12 ); +const float3 g_SphereRadius : register( c15 ); + +float LengthThroughSphere( float3 vecRayOrigin, float3 vecRayDelta, + float3 vecSphereCenter, float flRadius, out float alpha ) +{ + // Solve using the ray equation + the sphere equation + // P = o + dt + // (x - xc)^2 + (y - yc)^2 + (z - zc)^2 = r^2 + // (ox + dx * t - xc)^2 + (oy + dy * t - yc)^2 + (oz + dz * t - zc)^2 = r^2 + // (ox - xc)^2 + 2 * (ox-xc) * dx * t + dx^2 * t^2 + + // (oy - yc)^2 + 2 * (oy-yc) * dy * t + dy^2 * t^2 + + // (oz - zc)^2 + 2 * (oz-zc) * dz * t + dz^2 * t^2 = r^2 + // (dx^2 + dy^2 + dz^2) * t^2 + 2 * ((ox-xc)dx + (oy-yc)dy + (oz-zc)dz) t + + // (ox-xc)^2 + (oy-yc)^2 + (oz-zc)^2 - r^2 = 0 + // or, t = (-b +/- sqrt( b^2 - 4ac)) / 2a + // a = DotProduct( vecRayDelta, vecRayDelta ); + // b = 2 * DotProduct( vecRayOrigin - vecCenter, vecRayDelta ) + // c = DotProduct(vecRayOrigin - vecCenter, vecRayOrigin - vecCenter) - flRadius * flRadius; + + float3 vecSphereToRay; + vecSphereToRay = vecRayOrigin - vecSphereCenter; + + float a = dot( vecRayDelta, vecRayDelta ); + + // This would occur in the case of a zero-length ray + // if ( a == 0.0f ) + // { + // *pT1 = *pT2 = 0.0f; + // return vecSphereToRay.LengthSqr() <= flRadius * flRadius; + // } + + float b = 2 * dot( vecSphereToRay, vecRayDelta ); + float c = dot( vecSphereToRay, vecSphereToRay ) - flRadius * flRadius; + float flDiscrim = b * b - 4 * a * c; + // if ( flDiscrim < 0.0f ) + // return 0.0f; + + float hack = flDiscrim; + flDiscrim = sqrt( flDiscrim ); + float oo2a = 0.5f / a; + + + //if( hack < 0.0f ) + //{ + // alpha = 0.0f; + // return 0.0f; + //} + //else + //{ + // alpha = 1.0f; + // return abs( flDiscrim ) * 2 * oo2a; + //} + + //replacing the if's above because if's in hlsl are bad..... + float fHackGreaterThanZero = step( 0.0f, hack ); + alpha = fHackGreaterThanZero; + return (fHackGreaterThanZero * (abs( flDiscrim ) * 2 * oo2a)); + + + // *pT1 = ( - b - flDiscrim ) * oo2a; + // *pT2 = ( - b + flDiscrim ) * oo2a; + // return true; +} + + +struct PS_INPUT +{ + float2 vBumpTexCoord : TEXCOORD0; // dudvMapAndNormalMapTexCoord + HALF3 vWorldVertToEyeVector : TEXCOORD1; + HALF3x3 tangentSpaceTranspose : TEXCOORD2; + float3 vRefractXYW : TEXCOORD5; + float3 projNormal : TEXCOORD6; + float4 worldPos_projPosZ : TEXCOORD7; +}; + +float4 main( PS_INPUT i ) : COLOR +{ + HALF3 result = 0.0f; + + HALF blend = 1.0f; + +#if FLOWMAP + // Mapbase tries to un-hack some of this code + //float3 g_SphereCenter = { 2688.0f, 12139.0f, 5170.0f }; + //float g_SphereDiameter = 430.0f; + //float g_SphereRadius = g_SphereDiameter * 0.5f; + + float g_SphereDiameter = g_SphereRadius * 2.0f; + + float3 tmp = i.worldPos_projPosZ.xyz - g_SphereCenter; + float hackRadius = 1.05f * sqrt( dot( tmp, tmp ) ); + + float sphereAlpha; + float lengthThroughSphere = LengthThroughSphere( g_EyePos, normalize( i.worldPos_projPosZ.xyz - g_EyePos ), + g_SphereCenter, /*g_SphereRadius*/ hackRadius, sphereAlpha ); + + float normalizedLengthThroughSphere = lengthThroughSphere / g_SphereDiameter; + + + float3 hackWorldSpaceNormal = normalize( i.worldPos_projPosZ.xyz - g_SphereCenter ); + float3 realFuckingNormal = abs( hackWorldSpaceNormal ); + hackWorldSpaceNormal = 0.5f * ( hackWorldSpaceNormal + 1.0f ); + + // hackWorldSpaceNormal = abs( hackWorldSpaceNormal ); + + // return float4( hackWorldSpaceNormal.x, 0.0f, 0.0f, 1.0f ); + + i.vBumpTexCoord.xy = 0.0f; + i.vBumpTexCoord.xy = realFuckingNormal.z * tex2D( FlowmapSampler, hackWorldSpaceNormal.xy ); + i.vBumpTexCoord.xy += realFuckingNormal.y * tex2D( FlowmapSampler, hackWorldSpaceNormal.xz ); + i.vBumpTexCoord.xy += realFuckingNormal.x * tex2D( FlowmapSampler, hackWorldSpaceNormal.yz ); + i.vBumpTexCoord.xy += g_Time * g_FlowScrollRate; + // return float4( i.vBumpTexCoord.xy, 0.0f, 0.0f ); +#endif + + // Load normal and expand range + HALF4 vNormalSample = tex2D( NormalSampler, i.vBumpTexCoord ); + // return vNormalSample; + HALF3 tangentSpaceNormal = vNormalSample * 2.0 - 1.0; + + HALF3 refractTintColor = g_RefractTint; + + // Perform division by W only once + float ooW = 1.0f / i.vRefractXYW.z; + + // Compute coordinates for sampling refraction + float2 vRefractTexCoordNoWarp = i.vRefractXYW.xy * ooW; + float2 vRefractTexCoord = tangentSpaceNormal.xy; + HALF scale = vNormalSample.a * g_RefractScale.x; +#if FLOWMAP + scale *= normalizedLengthThroughSphere; +#endif + vRefractTexCoord *= scale; +#if FLOWMAP + float2 hackOffset = vRefractTexCoord; +#endif + vRefractTexCoord += vRefractTexCoordNoWarp; + + float3 colorWarp = tex2D( RefractSampler, vRefractTexCoord.xy ); + float3 colorNoWarp = tex2D( RefractSampler, vRefractTexCoordNoWarp.xy ); + + colorWarp *= refractTintColor; +#if REFRACT + result = lerp( colorNoWarp, colorWarp, blend ); + // return float4( 1.0f, 0.0f, 0.0f, 1.0f ); +#endif + +#if CUBEMAP + HALF specularFactor = vNormalSample.a; + + HALF3 worldSpaceNormal = mul( i.tangentSpaceTranspose, tangentSpaceNormal ); + + HALF3 reflectVect = CalcReflectionVectorUnnormalized( worldSpaceNormal, i.vWorldVertToEyeVector ); + HALF3 specularLighting = texCUBE( EnvmapSampler, reflectVect ); + specularLighting *= specularFactor; + specularLighting *= g_EnvmapTint; + HALF3 specularLightingSquared = specularLighting * specularLighting; + specularLighting = lerp( specularLighting, specularLightingSquared, g_EnvmapContrast ); + HALF3 greyScale = dot( specularLighting, HALF3( 0.299f, 0.587f, 0.114f ) ); + specularLighting = lerp( greyScale, specularLighting, g_EnvmapSaturation ); + result += specularLighting; +#endif + +#if CORECOLORTEXTURE && FLOWMAP + float4 coreColorTexel = tex2D( CoreColorSampler, hackOffset + float2( normalizedLengthThroughSphere, g_CoreColorTexCoordOffset ) ); + HALF4 rgba = HALF4( lerp( result, coreColorTexel, coreColorTexel.a /*normalizedLengthThroughSphere*/ ), sphereAlpha ); +#else + HALF4 rgba = HALF4( result, vNormalSample.a ); +#endif + + + float fogFactor = CalcPixelFogFactor( PIXELFOGTYPE, g_FogParams, g_EyePos.z, i.worldPos_projPosZ.z, i.worldPos_projPosZ.w ); + return FinalOutput( rgba, fogFactor, PIXELFOGTYPE, TONEMAP_SCALE_NONE ); +} + diff --git a/sp/src/materialsystem/stdshaders/SDK_core_vs20.fxc b/sp/src/materialsystem/stdshaders/SDK_core_vs20.fxc new file mode 100644 index 00000000..9b7c9652 --- /dev/null +++ b/sp/src/materialsystem/stdshaders/SDK_core_vs20.fxc @@ -0,0 +1,103 @@ +// STATIC: "MODEL" "0..1" + +// DYNAMIC: "COMPRESSED_VERTS" "0..1" +// DYNAMIC: "SKINNING" "0..1" + +#include "common_vs_fxc.h" + +static const bool g_bSkinning = SKINNING ? true : false; +static const bool g_bModel = MODEL ? true : false; + +const float4 cBumpTexCoordTransform[2] : register( SHADER_SPECIFIC_CONST_1 ); + +struct VS_INPUT +{ + float4 vPos : POSITION; + float4 vBoneWeights : BLENDWEIGHT; + float4 vBoneIndices : BLENDINDICES; + float4 vNormal : NORMAL; + float4 vBaseTexCoord : TEXCOORD0; +#if !MODEL + float3 vTangentS : TANGENT; + float3 vTangentT : BINORMAL0; +#else + float4 vUserData : TANGENT; +#endif +}; + +struct VS_OUTPUT +{ + float4 vProjPos_POSITION : POSITION; + float vFog : FOG; + float2 vBumpTexCoord : TEXCOORD0; + float3 vTangentEyeVect : TEXCOORD1; + float3x3 tangentSpaceTranspose : TEXCOORD2; + float3 vRefractXYW : TEXCOORD5; + float4 projNormal_screenCoordW : TEXCOORD6; + float4 worldPos_projPosZ : TEXCOORD7; + float4 fogFactorW : COLOR1; +}; + +VS_OUTPUT main( const VS_INPUT v ) +{ + VS_OUTPUT o = ( VS_OUTPUT )0; + + float3 worldNormal, worldPos, worldTangentS, worldTangentT; + + float3 vObjNormal; +#if MODEL + float4 vObjTangent; + DecompressVertex_NormalTangent( v.vNormal, v.vUserData, vObjNormal, vObjTangent ); + + SkinPositionNormalAndTangentSpace( + g_bSkinning, + v.vPos, vObjNormal, vObjTangent, + v.vBoneWeights, v.vBoneIndices, + worldPos, worldNormal, worldTangentS, worldTangentT ); +#else + DecompressVertex_Normal( v.vNormal, vObjNormal ); + + worldPos = mul( v.vPos, cModel[0] ); + worldTangentS = mul( v.vTangentS, ( const float3x3 )cModel[0] ); + worldTangentT = mul( v.vTangentT, ( const float3x3 )cModel[0] ); + worldNormal = mul( vObjNormal, ( float3x3 )cModel[0] ); +#endif + + + // Projected position + float4 vProjPos = mul( float4( worldPos, 1 ), cViewProj ); + o.vProjPos_POSITION = vProjPos; + o.projNormal_screenCoordW.xyz = mul( worldNormal, cViewProj ); + + o.worldPos_projPosZ = float4( worldPos.xyz, vProjPos.z ); + + // Map projected position to the refraction texture + float2 vRefractPos; + vRefractPos.x = vProjPos.x; + vRefractPos.y = -vProjPos.y; // invert Y + vRefractPos = (vRefractPos + vProjPos.w) * 0.5f; + + // Refraction transform + o.vRefractXYW = float3(vRefractPos.x, vRefractPos.y, vProjPos.w); + + // Compute fog based on the position + float3 vWorldPos = mul( v.vPos, cModel[0] ); + o.fogFactorW = o.vFog = CalcFog( vWorldPos, vProjPos, FOGTYPE_RANGE ); + + // Eye vector + float3 vWorldEyeVect = cEyePos - vWorldPos; + // Transform to the tangent space + o.vTangentEyeVect.x = dot( vWorldEyeVect, worldTangentS ); + o.vTangentEyeVect.y = dot( vWorldEyeVect, worldTangentT ); + o.vTangentEyeVect.z = dot( vWorldEyeVect, worldNormal ); + + // Tranform bump coordinates + o.vBumpTexCoord.x = dot( v.vBaseTexCoord, cBumpTexCoordTransform[0] ); + o.vBumpTexCoord.y = dot( v.vBaseTexCoord, cBumpTexCoordTransform[1] ); + + o.tangentSpaceTranspose[0] = worldTangentS; + o.tangentSpaceTranspose[1] = worldTangentT; + o.tangentSpaceTranspose[2] = worldNormal; + + return o; +} diff --git a/sp/src/materialsystem/stdshaders/core_dx9.cpp b/sp/src/materialsystem/stdshaders/core_dx9.cpp new file mode 100644 index 00000000..ceff0563 --- /dev/null +++ b/sp/src/materialsystem/stdshaders/core_dx9.cpp @@ -0,0 +1,307 @@ +//========= Copyright © 1996-2006, Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#include "BaseVSShader.h" +#include "SDK_core_vs20.inc" +#include "SDK_core_ps20.inc" +#include "SDK_core_ps20b.inc" + +#define MAXBLUR 1 + +DEFINE_FALLBACK_SHADER( SDK_Core, SDK_Core_DX90 ) + +BEGIN_VS_SHADER( SDK_Core_DX90, + "Help for Core" ) + + BEGIN_SHADER_PARAMS + SHADER_PARAM_OVERRIDE( COLOR, SHADER_PARAM_TYPE_COLOR, "{255 255 255}", "unused", SHADER_PARAM_NOT_EDITABLE ) + SHADER_PARAM_OVERRIDE( ALPHA, SHADER_PARAM_TYPE_FLOAT, "1.0", "unused", SHADER_PARAM_NOT_EDITABLE ) + SHADER_PARAM( REFRACTAMOUNT, SHADER_PARAM_TYPE_FLOAT, "2", "" ) + SHADER_PARAM( REFRACTTINT, SHADER_PARAM_TYPE_COLOR, "[1 1 1]", "refraction tint" ) + SHADER_PARAM( NORMALMAP, SHADER_PARAM_TYPE_TEXTURE, "models/shadertest/shader1_normal", "normal map" ) + SHADER_PARAM( BUMPFRAME, SHADER_PARAM_TYPE_INTEGER, "0", "frame number for $bumpmap" ) + SHADER_PARAM( BUMPTRANSFORM, SHADER_PARAM_TYPE_MATRIX, "center .5 .5 scale 1 1 rotate 0 translate 0 0", "$bumpmap texcoord transform" ) + SHADER_PARAM( TIME, SHADER_PARAM_TYPE_FLOAT, "0.0f", "" ) + SHADER_PARAM( ENVMAP, SHADER_PARAM_TYPE_TEXTURE, "shadertest/shadertest_env", "envmap" ) + SHADER_PARAM( ENVMAPFRAME, SHADER_PARAM_TYPE_INTEGER, "0", "envmap frame number" ) + SHADER_PARAM( ENVMAPTINT, SHADER_PARAM_TYPE_COLOR, "[1 1 1]", "envmap tint" ) + SHADER_PARAM( ENVMAPCONTRAST, SHADER_PARAM_TYPE_FLOAT, "0.0", "contrast 0 == normal 1 == color*color" ) + SHADER_PARAM( ENVMAPSATURATION, SHADER_PARAM_TYPE_FLOAT, "1.0", "saturation 0 == greyscale 1 == normal" ) + SHADER_PARAM( FLOWMAP, SHADER_PARAM_TYPE_TEXTURE, "", "flowmap" ) + SHADER_PARAM( FLOWMAPFRAME, SHADER_PARAM_TYPE_INTEGER, "0", "frame number for $flowmap" ) + SHADER_PARAM( FLOWMAPSCROLLRATE, SHADER_PARAM_TYPE_VEC2, "[0 0", "2D rate to scroll $flowmap" ) + SHADER_PARAM( CORECOLORTEXTURE, SHADER_PARAM_TYPE_TEXTURE, "", "" ); + SHADER_PARAM( CORECOLORTEXTUREFRAME, SHADER_PARAM_TYPE_INTEGER, "", "" ); + SHADER_PARAM( FLOWMAPTEXCOORDOFFSET, SHADER_PARAM_TYPE_FLOAT, "0.0", "" ); +#ifdef MAPBASE + SHADER_PARAM( SPHERECENTER, SHADER_PARAM_TYPE_VEC3, "2688.0, 12139.0, 5170.0", "The sphere's worldspace center (was previously hardcoded)" ); + SHADER_PARAM( SPHERERADIUS, SHADER_PARAM_TYPE_FLOAT, "215.0", "The sphere's worldspace radius (was previously hardcoded)" ); +#endif + END_SHADER_PARAMS + SHADER_INIT_PARAMS() + { + SET_FLAGS2( MATERIAL_VAR2_NEEDS_TANGENT_SPACES ); + SET_FLAGS( MATERIAL_VAR_TRANSLUCENT ); + if( !params[ENVMAPTINT]->IsDefined() ) + { + params[ENVMAPTINT]->SetVecValue( 1.0f, 1.0f, 1.0f ); + } + if( !params[ENVMAPCONTRAST]->IsDefined() ) + { + params[ENVMAPCONTRAST]->SetFloatValue( 0.0f ); + } + if( !params[ENVMAPSATURATION]->IsDefined() ) + { + params[ENVMAPSATURATION]->SetFloatValue( 1.0f ); + } + if( !params[ENVMAPFRAME]->IsDefined() ) + { + params[ENVMAPFRAME]->SetIntValue( 0 ); + } + if( !params[BASETEXTURE]->IsDefined() ) + { + SET_FLAGS2( MATERIAL_VAR2_NEEDS_POWER_OF_TWO_FRAME_BUFFER_TEXTURE ); + } + } + + SHADER_FALLBACK + { + if( g_pHardwareConfig->GetDXSupportLevel() < 90 ) + return "Core_dx90"; + + return 0; + } + + SHADER_INIT + { + if (params[BASETEXTURE]->IsDefined() ) + { + LoadTexture( BASETEXTURE ); + } + if (params[NORMALMAP]->IsDefined() ) + { + LoadBumpMap( NORMALMAP ); + } + if ( params[ENVMAP]->IsDefined() ) + { + LoadCubeMap( ENVMAP ); + } + if ( params[FLOWMAP]->IsDefined() ) + { + LoadTexture( FLOWMAP ); + } + if ( params[CORECOLORTEXTURE]->IsDefined() ) + { + LoadTexture( CORECOLORTEXTURE ); + } + } + + inline void DrawPass( IMaterialVar **params, IShaderShadow* pShaderShadow, + IShaderDynamicAPI* pShaderAPI, int nPass, VertexCompressionType_t vertexCompression ) + { + bool bIsModel = IS_FLAG_SET( MATERIAL_VAR_MODEL ); + bool bHasEnvmap = params[ENVMAP]->IsTexture(); + bool bHasFlowmap = params[FLOWMAP]->IsTexture(); + bool bHasCoreColorTexture = params[CORECOLORTEXTURE]->IsTexture(); + + SHADOW_STATE + { + SetInitialShadowState( ); + + if( nPass == 0 ) + { + // Alpha test: FIXME: shouldn't this be handled in Shader_t::SetInitialShadowState + pShaderShadow->EnableAlphaTest( IS_FLAG_SET(MATERIAL_VAR_ALPHATEST) ); + } + else + { + pShaderShadow->DepthFunc( SHADER_DEPTHFUNC_EQUAL ); + EnableAlphaBlending( SHADER_BLEND_ONE, SHADER_BLEND_ONE ); + } + + // If envmap is not specified, the alpha channel is the translucency + // (If envmap *is* specified, alpha channel is the reflection amount) + if ( params[NORMALMAP]->IsTexture() && !bHasEnvmap ) + { + SetDefaultBlendingShadowState( NORMALMAP, false ); + } + + // source render target that contains the image that we are warping. + pShaderShadow->EnableTexture( SHADER_SAMPLER2, true ); + if( g_pHardwareConfig->GetHDRType() == HDR_TYPE_INTEGER ) + { + pShaderShadow->EnableSRGBRead( SHADER_SAMPLER2, true ); + } + + // normal map + pShaderShadow->EnableTexture( SHADER_SAMPLER3, true ); + if( bHasEnvmap ) + { + // envmap + pShaderShadow->EnableTexture( SHADER_SAMPLER4, true ); + if( g_pHardwareConfig->GetHDRType() == HDR_TYPE_INTEGER ) + { + pShaderShadow->EnableSRGBRead( SHADER_SAMPLER4, true ); + } + } + + if( bHasFlowmap ) + { + pShaderShadow->EnableTexture( SHADER_SAMPLER6, true ); + } + + if( bHasCoreColorTexture ) + { + pShaderShadow->EnableTexture( SHADER_SAMPLER7, true ); + } + + if( g_pHardwareConfig->GetHDRType() != HDR_TYPE_NONE ) + { + pShaderShadow->EnableSRGBWrite( true ); + } + + unsigned int flags = VERTEX_POSITION | VERTEX_NORMAL; + int userDataSize = 0; + int nTexCoordCount = 1; + if( bIsModel ) + { + userDataSize = 4; + } + else + { + flags |= VERTEX_TANGENT_S | VERTEX_TANGENT_T; + } + + // This shader supports compressed vertices, so OR in that flag: + flags |= VERTEX_FORMAT_COMPRESSED; + + pShaderShadow->VertexShaderVertexFormat( flags, nTexCoordCount, NULL, userDataSize ); + + DECLARE_STATIC_VERTEX_SHADER( sdk_core_vs20 ); + SET_STATIC_VERTEX_SHADER_COMBO( MODEL, bIsModel ); + SET_STATIC_VERTEX_SHADER( sdk_core_vs20 ); + + if ( g_pHardwareConfig->SupportsPixelShaders_2_b() ) + { + DECLARE_STATIC_PIXEL_SHADER( sdk_core_ps20b ); + SET_STATIC_PIXEL_SHADER_COMBO( CUBEMAP, bHasEnvmap && ( nPass == 1 ) ); + SET_STATIC_PIXEL_SHADER_COMBO( FLOWMAP, bHasFlowmap ); + SET_STATIC_PIXEL_SHADER_COMBO( CORECOLORTEXTURE, bHasCoreColorTexture && ( nPass == 0 ) ); + SET_STATIC_PIXEL_SHADER_COMBO( REFRACT, nPass == 0 ); + SET_STATIC_PIXEL_SHADER( sdk_core_ps20b ); + } + else + { + DECLARE_STATIC_PIXEL_SHADER( sdk_core_ps20 ); + SET_STATIC_PIXEL_SHADER_COMBO( CUBEMAP, bHasEnvmap && ( nPass == 1 ) ); + SET_STATIC_PIXEL_SHADER_COMBO( FLOWMAP, bHasFlowmap ); + SET_STATIC_PIXEL_SHADER_COMBO( CORECOLORTEXTURE, bHasCoreColorTexture && ( nPass == 0 ) ); + SET_STATIC_PIXEL_SHADER_COMBO( REFRACT, nPass == 0 ); + SET_STATIC_PIXEL_SHADER( sdk_core_ps20 ); + } + + DefaultFog(); + } + DYNAMIC_STATE + { + pShaderAPI->SetDefaultState(); + + if ( params[BASETEXTURE]->IsTexture() ) + { + BindTexture( SHADER_SAMPLER2, BASETEXTURE, FRAME ); + } + else + { + pShaderAPI->BindStandardTexture( SHADER_SAMPLER2, TEXTURE_FRAME_BUFFER_FULL_TEXTURE_0 ); + } + + BindTexture( SHADER_SAMPLER3, NORMALMAP, BUMPFRAME ); + + if( bHasEnvmap ) + { + BindTexture( SHADER_SAMPLER4, ENVMAP, ENVMAPFRAME ); + } + + if( bHasFlowmap ) + { + BindTexture( SHADER_SAMPLER6, FLOWMAP, FLOWMAPFRAME ); + } + + if( bHasCoreColorTexture ) + { + BindTexture( SHADER_SAMPLER7, CORECOLORTEXTURE, CORECOLORTEXTUREFRAME ); + } + + DECLARE_DYNAMIC_VERTEX_SHADER( sdk_core_vs20 ); + SET_DYNAMIC_VERTEX_SHADER_COMBO( SKINNING, pShaderAPI->GetCurrentNumBones() > 0 ); + SET_DYNAMIC_VERTEX_SHADER_COMBO( COMPRESSED_VERTS, (int)vertexCompression ); + SET_DYNAMIC_VERTEX_SHADER( sdk_core_vs20 ); + + if ( g_pHardwareConfig->SupportsPixelShaders_2_b() ) + { + DECLARE_DYNAMIC_PIXEL_SHADER( sdk_core_ps20b ); + SET_DYNAMIC_PIXEL_SHADER_COMBO( PIXELFOGTYPE, pShaderAPI->GetPixelFogCombo() ); + SET_DYNAMIC_PIXEL_SHADER( sdk_core_ps20b ); + } + else + { + DECLARE_DYNAMIC_PIXEL_SHADER( sdk_core_ps20 ); + SET_DYNAMIC_PIXEL_SHADER_COMBO( PIXELFOGTYPE, pShaderAPI->GetPixelFogCombo() ); + SET_DYNAMIC_PIXEL_SHADER( sdk_core_ps20 ); + } + + SetVertexShaderTextureTransform( VERTEX_SHADER_SHADER_SPECIFIC_CONST_1, BUMPTRANSFORM ); + + if( g_pHardwareConfig->GetHDRType() == HDR_TYPE_NONE ) + { + SetPixelShaderConstant( 0, ENVMAPTINT ); + SetPixelShaderConstant( 1, REFRACTTINT ); + } + else + { + SetPixelShaderConstantGammaToLinear( 0, ENVMAPTINT ); + SetPixelShaderConstantGammaToLinear( 1, REFRACTTINT ); + } + SetPixelShaderConstant( 2, ENVMAPCONTRAST ); + SetPixelShaderConstant( 3, ENVMAPSATURATION ); + float c5[4] = { params[REFRACTAMOUNT]->GetFloatValue(), + params[REFRACTAMOUNT]->GetFloatValue(), 0.0f, 0.0f }; + pShaderAPI->SetPixelShaderConstant( 5, c5, 1 ); + + float eyePos[4]; + s_pShaderAPI->GetWorldSpaceCameraPosition( eyePos ); + s_pShaderAPI->SetPixelShaderConstant( 8, eyePos, 1 ); + pShaderAPI->SetPixelShaderFogParams( 11 ); + + + + if( bHasFlowmap ) + { + float curTime = pShaderAPI->CurrentTime(); + float timeVec[4] = { curTime, curTime, curTime, curTime }; + pShaderAPI->SetPixelShaderConstant( 6, timeVec, 1 ); + + SetPixelShaderConstant( 7, FLOWMAPSCROLLRATE ); + + SetPixelShaderConstant( 9, FLOWMAPTEXCOORDOFFSET ); + } + +#ifdef MAPBASE + SetPixelShaderConstant( 12, SPHERECENTER ); + SetPixelShaderConstant( 15, SPHERERADIUS ); +#endif + } + Draw(); + } + + SHADER_DRAW + { + DrawPass( params, pShaderShadow, pShaderAPI, 0, vertexCompression ); + DrawPass( params, pShaderShadow, pShaderAPI, 1, vertexCompression ); + } +END_SHADER + diff --git a/sp/src/materialsystem/stdshaders/fxctmp9/SDK_core_ps20.inc b/sp/src/materialsystem/stdshaders/fxctmp9/SDK_core_ps20.inc new file mode 100644 index 00000000..d6701fc7 --- /dev/null +++ b/sp/src/materialsystem/stdshaders/fxctmp9/SDK_core_ps20.inc @@ -0,0 +1,162 @@ +#include "shaderlib/cshader.h" +class sdk_core_ps20_Static_Index +{ +private: + int m_nCUBEMAP; +#ifdef _DEBUG + bool m_bCUBEMAP; +#endif +public: + void SetCUBEMAP( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nCUBEMAP = i; +#ifdef _DEBUG + m_bCUBEMAP = true; +#endif + } + void SetCUBEMAP( bool i ) + { + m_nCUBEMAP = i ? 1 : 0; +#ifdef _DEBUG + m_bCUBEMAP = true; +#endif + } +private: + int m_nFLOWMAP; +#ifdef _DEBUG + bool m_bFLOWMAP; +#endif +public: + void SetFLOWMAP( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nFLOWMAP = i; +#ifdef _DEBUG + m_bFLOWMAP = true; +#endif + } + void SetFLOWMAP( bool i ) + { + m_nFLOWMAP = i ? 1 : 0; +#ifdef _DEBUG + m_bFLOWMAP = true; +#endif + } +private: + int m_nCORECOLORTEXTURE; +#ifdef _DEBUG + bool m_bCORECOLORTEXTURE; +#endif +public: + void SetCORECOLORTEXTURE( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nCORECOLORTEXTURE = i; +#ifdef _DEBUG + m_bCORECOLORTEXTURE = true; +#endif + } + void SetCORECOLORTEXTURE( bool i ) + { + m_nCORECOLORTEXTURE = i ? 1 : 0; +#ifdef _DEBUG + m_bCORECOLORTEXTURE = true; +#endif + } +private: + int m_nREFRACT; +#ifdef _DEBUG + bool m_bREFRACT; +#endif +public: + void SetREFRACT( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nREFRACT = i; +#ifdef _DEBUG + m_bREFRACT = true; +#endif + } + void SetREFRACT( bool i ) + { + m_nREFRACT = i ? 1 : 0; +#ifdef _DEBUG + m_bREFRACT = true; +#endif + } +public: + sdk_core_ps20_Static_Index( ) + { +#ifdef _DEBUG + m_bCUBEMAP = false; +#endif // _DEBUG + m_nCUBEMAP = 0; +#ifdef _DEBUG + m_bFLOWMAP = false; +#endif // _DEBUG + m_nFLOWMAP = 0; +#ifdef _DEBUG + m_bCORECOLORTEXTURE = false; +#endif // _DEBUG + m_nCORECOLORTEXTURE = 0; +#ifdef _DEBUG + m_bREFRACT = false; +#endif // _DEBUG + m_nREFRACT = 0; + } + int GetIndex() + { + // Asserts to make sure that we aren't using any skipped combinations. + // Asserts to make sure that we are setting all of the combination vars. +#ifdef _DEBUG + bool bAllStaticVarsDefined = m_bCUBEMAP && m_bFLOWMAP && m_bCORECOLORTEXTURE && m_bREFRACT; + Assert( bAllStaticVarsDefined ); +#endif // _DEBUG + return ( 2 * m_nCUBEMAP ) + ( 4 * m_nFLOWMAP ) + ( 8 * m_nCORECOLORTEXTURE ) + ( 16 * m_nREFRACT ) + 0; + } +}; +#define shaderStaticTest_sdk_core_ps20 psh_forgot_to_set_static_CUBEMAP + psh_forgot_to_set_static_FLOWMAP + psh_forgot_to_set_static_CORECOLORTEXTURE + psh_forgot_to_set_static_REFRACT + 0 +class sdk_core_ps20_Dynamic_Index +{ +private: + int m_nPIXELFOGTYPE; +#ifdef _DEBUG + bool m_bPIXELFOGTYPE; +#endif +public: + void SetPIXELFOGTYPE( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nPIXELFOGTYPE = i; +#ifdef _DEBUG + m_bPIXELFOGTYPE = true; +#endif + } + void SetPIXELFOGTYPE( bool i ) + { + m_nPIXELFOGTYPE = i ? 1 : 0; +#ifdef _DEBUG + m_bPIXELFOGTYPE = true; +#endif + } +public: + sdk_core_ps20_Dynamic_Index() + { +#ifdef _DEBUG + m_bPIXELFOGTYPE = false; +#endif // _DEBUG + m_nPIXELFOGTYPE = 0; + } + int GetIndex() + { + // Asserts to make sure that we aren't using any skipped combinations. + // Asserts to make sure that we are setting all of the combination vars. +#ifdef _DEBUG + bool bAllDynamicVarsDefined = m_bPIXELFOGTYPE; + Assert( bAllDynamicVarsDefined ); +#endif // _DEBUG + return ( 1 * m_nPIXELFOGTYPE ) + 0; + } +}; +#define shaderDynamicTest_sdk_core_ps20 psh_forgot_to_set_dynamic_PIXELFOGTYPE + 0 diff --git a/sp/src/materialsystem/stdshaders/fxctmp9/SDK_core_ps20b.inc b/sp/src/materialsystem/stdshaders/fxctmp9/SDK_core_ps20b.inc new file mode 100644 index 00000000..9b9a843d --- /dev/null +++ b/sp/src/materialsystem/stdshaders/fxctmp9/SDK_core_ps20b.inc @@ -0,0 +1,187 @@ +#include "shaderlib/cshader.h" +class sdk_core_ps20b_Static_Index +{ +private: + int m_nCONVERT_TO_SRGB; +#ifdef _DEBUG + bool m_bCONVERT_TO_SRGB; +#endif +public: + void SetCONVERT_TO_SRGB( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nCONVERT_TO_SRGB = i; +#ifdef _DEBUG + m_bCONVERT_TO_SRGB = true; +#endif + } + void SetCONVERT_TO_SRGB( bool i ) + { + m_nCONVERT_TO_SRGB = i ? 1 : 0; +#ifdef _DEBUG + m_bCONVERT_TO_SRGB = true; +#endif + } +private: + int m_nCUBEMAP; +#ifdef _DEBUG + bool m_bCUBEMAP; +#endif +public: + void SetCUBEMAP( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nCUBEMAP = i; +#ifdef _DEBUG + m_bCUBEMAP = true; +#endif + } + void SetCUBEMAP( bool i ) + { + m_nCUBEMAP = i ? 1 : 0; +#ifdef _DEBUG + m_bCUBEMAP = true; +#endif + } +private: + int m_nFLOWMAP; +#ifdef _DEBUG + bool m_bFLOWMAP; +#endif +public: + void SetFLOWMAP( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nFLOWMAP = i; +#ifdef _DEBUG + m_bFLOWMAP = true; +#endif + } + void SetFLOWMAP( bool i ) + { + m_nFLOWMAP = i ? 1 : 0; +#ifdef _DEBUG + m_bFLOWMAP = true; +#endif + } +private: + int m_nCORECOLORTEXTURE; +#ifdef _DEBUG + bool m_bCORECOLORTEXTURE; +#endif +public: + void SetCORECOLORTEXTURE( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nCORECOLORTEXTURE = i; +#ifdef _DEBUG + m_bCORECOLORTEXTURE = true; +#endif + } + void SetCORECOLORTEXTURE( bool i ) + { + m_nCORECOLORTEXTURE = i ? 1 : 0; +#ifdef _DEBUG + m_bCORECOLORTEXTURE = true; +#endif + } +private: + int m_nREFRACT; +#ifdef _DEBUG + bool m_bREFRACT; +#endif +public: + void SetREFRACT( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nREFRACT = i; +#ifdef _DEBUG + m_bREFRACT = true; +#endif + } + void SetREFRACT( bool i ) + { + m_nREFRACT = i ? 1 : 0; +#ifdef _DEBUG + m_bREFRACT = true; +#endif + } +public: + sdk_core_ps20b_Static_Index( ) + { +#ifdef _DEBUG + m_bCONVERT_TO_SRGB = true; +#endif // _DEBUG + m_nCONVERT_TO_SRGB = g_pHardwareConfig->NeedsShaderSRGBConversion(); +#ifdef _DEBUG + m_bCUBEMAP = false; +#endif // _DEBUG + m_nCUBEMAP = 0; +#ifdef _DEBUG + m_bFLOWMAP = false; +#endif // _DEBUG + m_nFLOWMAP = 0; +#ifdef _DEBUG + m_bCORECOLORTEXTURE = false; +#endif // _DEBUG + m_nCORECOLORTEXTURE = 0; +#ifdef _DEBUG + m_bREFRACT = false; +#endif // _DEBUG + m_nREFRACT = 0; + } + int GetIndex() + { + // Asserts to make sure that we aren't using any skipped combinations. + // Asserts to make sure that we are setting all of the combination vars. +#ifdef _DEBUG + bool bAllStaticVarsDefined = m_bCONVERT_TO_SRGB && m_bCUBEMAP && m_bFLOWMAP && m_bCORECOLORTEXTURE && m_bREFRACT; + Assert( bAllStaticVarsDefined ); +#endif // _DEBUG + return ( 2 * m_nCONVERT_TO_SRGB ) + ( 4 * m_nCUBEMAP ) + ( 8 * m_nFLOWMAP ) + ( 16 * m_nCORECOLORTEXTURE ) + ( 32 * m_nREFRACT ) + 0; + } +}; +#define shaderStaticTest_sdk_core_ps20b psh_forgot_to_set_static_CUBEMAP + psh_forgot_to_set_static_FLOWMAP + psh_forgot_to_set_static_CORECOLORTEXTURE + psh_forgot_to_set_static_REFRACT + 0 +class sdk_core_ps20b_Dynamic_Index +{ +private: + int m_nPIXELFOGTYPE; +#ifdef _DEBUG + bool m_bPIXELFOGTYPE; +#endif +public: + void SetPIXELFOGTYPE( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nPIXELFOGTYPE = i; +#ifdef _DEBUG + m_bPIXELFOGTYPE = true; +#endif + } + void SetPIXELFOGTYPE( bool i ) + { + m_nPIXELFOGTYPE = i ? 1 : 0; +#ifdef _DEBUG + m_bPIXELFOGTYPE = true; +#endif + } +public: + sdk_core_ps20b_Dynamic_Index() + { +#ifdef _DEBUG + m_bPIXELFOGTYPE = false; +#endif // _DEBUG + m_nPIXELFOGTYPE = 0; + } + int GetIndex() + { + // Asserts to make sure that we aren't using any skipped combinations. + // Asserts to make sure that we are setting all of the combination vars. +#ifdef _DEBUG + bool bAllDynamicVarsDefined = m_bPIXELFOGTYPE; + Assert( bAllDynamicVarsDefined ); +#endif // _DEBUG + return ( 1 * m_nPIXELFOGTYPE ) + 0; + } +}; +#define shaderDynamicTest_sdk_core_ps20b psh_forgot_to_set_dynamic_PIXELFOGTYPE + 0 diff --git a/sp/src/materialsystem/stdshaders/fxctmp9/SDK_core_vs20.inc b/sp/src/materialsystem/stdshaders/fxctmp9/SDK_core_vs20.inc new file mode 100644 index 00000000..ef6a680c --- /dev/null +++ b/sp/src/materialsystem/stdshaders/fxctmp9/SDK_core_vs20.inc @@ -0,0 +1,112 @@ +#include "shaderlib/cshader.h" +class sdk_core_vs20_Static_Index +{ +private: + int m_nMODEL; +#ifdef _DEBUG + bool m_bMODEL; +#endif +public: + void SetMODEL( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nMODEL = i; +#ifdef _DEBUG + m_bMODEL = true; +#endif + } + void SetMODEL( bool i ) + { + m_nMODEL = i ? 1 : 0; +#ifdef _DEBUG + m_bMODEL = true; +#endif + } +public: + sdk_core_vs20_Static_Index( ) + { +#ifdef _DEBUG + m_bMODEL = false; +#endif // _DEBUG + m_nMODEL = 0; + } + int GetIndex() + { + // Asserts to make sure that we aren't using any skipped combinations. + // Asserts to make sure that we are setting all of the combination vars. +#ifdef _DEBUG + bool bAllStaticVarsDefined = m_bMODEL; + Assert( bAllStaticVarsDefined ); +#endif // _DEBUG + return ( 4 * m_nMODEL ) + 0; + } +}; +#define shaderStaticTest_sdk_core_vs20 vsh_forgot_to_set_static_MODEL + 0 +class sdk_core_vs20_Dynamic_Index +{ +private: + int m_nCOMPRESSED_VERTS; +#ifdef _DEBUG + bool m_bCOMPRESSED_VERTS; +#endif +public: + void SetCOMPRESSED_VERTS( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nCOMPRESSED_VERTS = i; +#ifdef _DEBUG + m_bCOMPRESSED_VERTS = true; +#endif + } + void SetCOMPRESSED_VERTS( bool i ) + { + m_nCOMPRESSED_VERTS = i ? 1 : 0; +#ifdef _DEBUG + m_bCOMPRESSED_VERTS = true; +#endif + } +private: + int m_nSKINNING; +#ifdef _DEBUG + bool m_bSKINNING; +#endif +public: + void SetSKINNING( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nSKINNING = i; +#ifdef _DEBUG + m_bSKINNING = true; +#endif + } + void SetSKINNING( bool i ) + { + m_nSKINNING = i ? 1 : 0; +#ifdef _DEBUG + m_bSKINNING = true; +#endif + } +public: + sdk_core_vs20_Dynamic_Index() + { +#ifdef _DEBUG + m_bCOMPRESSED_VERTS = false; +#endif // _DEBUG + m_nCOMPRESSED_VERTS = 0; +#ifdef _DEBUG + m_bSKINNING = false; +#endif // _DEBUG + m_nSKINNING = 0; + } + int GetIndex() + { + // Asserts to make sure that we aren't using any skipped combinations. + // Asserts to make sure that we are setting all of the combination vars. +#ifdef _DEBUG + bool bAllDynamicVarsDefined = m_bCOMPRESSED_VERTS && m_bSKINNING; + Assert( bAllDynamicVarsDefined ); +#endif // _DEBUG + return ( 1 * m_nCOMPRESSED_VERTS ) + ( 2 * m_nSKINNING ) + 0; + } +}; +#define shaderDynamicTest_sdk_core_vs20 vsh_forgot_to_set_dynamic_COMPRESSED_VERTS + vsh_forgot_to_set_dynamic_SKINNING + 0 diff --git a/sp/src/materialsystem/stdshaders/fxctmp9_tmp/SDK_core_ps20.inc b/sp/src/materialsystem/stdshaders/fxctmp9_tmp/SDK_core_ps20.inc new file mode 100644 index 00000000..d6701fc7 --- /dev/null +++ b/sp/src/materialsystem/stdshaders/fxctmp9_tmp/SDK_core_ps20.inc @@ -0,0 +1,162 @@ +#include "shaderlib/cshader.h" +class sdk_core_ps20_Static_Index +{ +private: + int m_nCUBEMAP; +#ifdef _DEBUG + bool m_bCUBEMAP; +#endif +public: + void SetCUBEMAP( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nCUBEMAP = i; +#ifdef _DEBUG + m_bCUBEMAP = true; +#endif + } + void SetCUBEMAP( bool i ) + { + m_nCUBEMAP = i ? 1 : 0; +#ifdef _DEBUG + m_bCUBEMAP = true; +#endif + } +private: + int m_nFLOWMAP; +#ifdef _DEBUG + bool m_bFLOWMAP; +#endif +public: + void SetFLOWMAP( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nFLOWMAP = i; +#ifdef _DEBUG + m_bFLOWMAP = true; +#endif + } + void SetFLOWMAP( bool i ) + { + m_nFLOWMAP = i ? 1 : 0; +#ifdef _DEBUG + m_bFLOWMAP = true; +#endif + } +private: + int m_nCORECOLORTEXTURE; +#ifdef _DEBUG + bool m_bCORECOLORTEXTURE; +#endif +public: + void SetCORECOLORTEXTURE( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nCORECOLORTEXTURE = i; +#ifdef _DEBUG + m_bCORECOLORTEXTURE = true; +#endif + } + void SetCORECOLORTEXTURE( bool i ) + { + m_nCORECOLORTEXTURE = i ? 1 : 0; +#ifdef _DEBUG + m_bCORECOLORTEXTURE = true; +#endif + } +private: + int m_nREFRACT; +#ifdef _DEBUG + bool m_bREFRACT; +#endif +public: + void SetREFRACT( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nREFRACT = i; +#ifdef _DEBUG + m_bREFRACT = true; +#endif + } + void SetREFRACT( bool i ) + { + m_nREFRACT = i ? 1 : 0; +#ifdef _DEBUG + m_bREFRACT = true; +#endif + } +public: + sdk_core_ps20_Static_Index( ) + { +#ifdef _DEBUG + m_bCUBEMAP = false; +#endif // _DEBUG + m_nCUBEMAP = 0; +#ifdef _DEBUG + m_bFLOWMAP = false; +#endif // _DEBUG + m_nFLOWMAP = 0; +#ifdef _DEBUG + m_bCORECOLORTEXTURE = false; +#endif // _DEBUG + m_nCORECOLORTEXTURE = 0; +#ifdef _DEBUG + m_bREFRACT = false; +#endif // _DEBUG + m_nREFRACT = 0; + } + int GetIndex() + { + // Asserts to make sure that we aren't using any skipped combinations. + // Asserts to make sure that we are setting all of the combination vars. +#ifdef _DEBUG + bool bAllStaticVarsDefined = m_bCUBEMAP && m_bFLOWMAP && m_bCORECOLORTEXTURE && m_bREFRACT; + Assert( bAllStaticVarsDefined ); +#endif // _DEBUG + return ( 2 * m_nCUBEMAP ) + ( 4 * m_nFLOWMAP ) + ( 8 * m_nCORECOLORTEXTURE ) + ( 16 * m_nREFRACT ) + 0; + } +}; +#define shaderStaticTest_sdk_core_ps20 psh_forgot_to_set_static_CUBEMAP + psh_forgot_to_set_static_FLOWMAP + psh_forgot_to_set_static_CORECOLORTEXTURE + psh_forgot_to_set_static_REFRACT + 0 +class sdk_core_ps20_Dynamic_Index +{ +private: + int m_nPIXELFOGTYPE; +#ifdef _DEBUG + bool m_bPIXELFOGTYPE; +#endif +public: + void SetPIXELFOGTYPE( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nPIXELFOGTYPE = i; +#ifdef _DEBUG + m_bPIXELFOGTYPE = true; +#endif + } + void SetPIXELFOGTYPE( bool i ) + { + m_nPIXELFOGTYPE = i ? 1 : 0; +#ifdef _DEBUG + m_bPIXELFOGTYPE = true; +#endif + } +public: + sdk_core_ps20_Dynamic_Index() + { +#ifdef _DEBUG + m_bPIXELFOGTYPE = false; +#endif // _DEBUG + m_nPIXELFOGTYPE = 0; + } + int GetIndex() + { + // Asserts to make sure that we aren't using any skipped combinations. + // Asserts to make sure that we are setting all of the combination vars. +#ifdef _DEBUG + bool bAllDynamicVarsDefined = m_bPIXELFOGTYPE; + Assert( bAllDynamicVarsDefined ); +#endif // _DEBUG + return ( 1 * m_nPIXELFOGTYPE ) + 0; + } +}; +#define shaderDynamicTest_sdk_core_ps20 psh_forgot_to_set_dynamic_PIXELFOGTYPE + 0 diff --git a/sp/src/materialsystem/stdshaders/fxctmp9_tmp/SDK_core_ps20b.inc b/sp/src/materialsystem/stdshaders/fxctmp9_tmp/SDK_core_ps20b.inc new file mode 100644 index 00000000..9b9a843d --- /dev/null +++ b/sp/src/materialsystem/stdshaders/fxctmp9_tmp/SDK_core_ps20b.inc @@ -0,0 +1,187 @@ +#include "shaderlib/cshader.h" +class sdk_core_ps20b_Static_Index +{ +private: + int m_nCONVERT_TO_SRGB; +#ifdef _DEBUG + bool m_bCONVERT_TO_SRGB; +#endif +public: + void SetCONVERT_TO_SRGB( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nCONVERT_TO_SRGB = i; +#ifdef _DEBUG + m_bCONVERT_TO_SRGB = true; +#endif + } + void SetCONVERT_TO_SRGB( bool i ) + { + m_nCONVERT_TO_SRGB = i ? 1 : 0; +#ifdef _DEBUG + m_bCONVERT_TO_SRGB = true; +#endif + } +private: + int m_nCUBEMAP; +#ifdef _DEBUG + bool m_bCUBEMAP; +#endif +public: + void SetCUBEMAP( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nCUBEMAP = i; +#ifdef _DEBUG + m_bCUBEMAP = true; +#endif + } + void SetCUBEMAP( bool i ) + { + m_nCUBEMAP = i ? 1 : 0; +#ifdef _DEBUG + m_bCUBEMAP = true; +#endif + } +private: + int m_nFLOWMAP; +#ifdef _DEBUG + bool m_bFLOWMAP; +#endif +public: + void SetFLOWMAP( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nFLOWMAP = i; +#ifdef _DEBUG + m_bFLOWMAP = true; +#endif + } + void SetFLOWMAP( bool i ) + { + m_nFLOWMAP = i ? 1 : 0; +#ifdef _DEBUG + m_bFLOWMAP = true; +#endif + } +private: + int m_nCORECOLORTEXTURE; +#ifdef _DEBUG + bool m_bCORECOLORTEXTURE; +#endif +public: + void SetCORECOLORTEXTURE( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nCORECOLORTEXTURE = i; +#ifdef _DEBUG + m_bCORECOLORTEXTURE = true; +#endif + } + void SetCORECOLORTEXTURE( bool i ) + { + m_nCORECOLORTEXTURE = i ? 1 : 0; +#ifdef _DEBUG + m_bCORECOLORTEXTURE = true; +#endif + } +private: + int m_nREFRACT; +#ifdef _DEBUG + bool m_bREFRACT; +#endif +public: + void SetREFRACT( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nREFRACT = i; +#ifdef _DEBUG + m_bREFRACT = true; +#endif + } + void SetREFRACT( bool i ) + { + m_nREFRACT = i ? 1 : 0; +#ifdef _DEBUG + m_bREFRACT = true; +#endif + } +public: + sdk_core_ps20b_Static_Index( ) + { +#ifdef _DEBUG + m_bCONVERT_TO_SRGB = true; +#endif // _DEBUG + m_nCONVERT_TO_SRGB = g_pHardwareConfig->NeedsShaderSRGBConversion(); +#ifdef _DEBUG + m_bCUBEMAP = false; +#endif // _DEBUG + m_nCUBEMAP = 0; +#ifdef _DEBUG + m_bFLOWMAP = false; +#endif // _DEBUG + m_nFLOWMAP = 0; +#ifdef _DEBUG + m_bCORECOLORTEXTURE = false; +#endif // _DEBUG + m_nCORECOLORTEXTURE = 0; +#ifdef _DEBUG + m_bREFRACT = false; +#endif // _DEBUG + m_nREFRACT = 0; + } + int GetIndex() + { + // Asserts to make sure that we aren't using any skipped combinations. + // Asserts to make sure that we are setting all of the combination vars. +#ifdef _DEBUG + bool bAllStaticVarsDefined = m_bCONVERT_TO_SRGB && m_bCUBEMAP && m_bFLOWMAP && m_bCORECOLORTEXTURE && m_bREFRACT; + Assert( bAllStaticVarsDefined ); +#endif // _DEBUG + return ( 2 * m_nCONVERT_TO_SRGB ) + ( 4 * m_nCUBEMAP ) + ( 8 * m_nFLOWMAP ) + ( 16 * m_nCORECOLORTEXTURE ) + ( 32 * m_nREFRACT ) + 0; + } +}; +#define shaderStaticTest_sdk_core_ps20b psh_forgot_to_set_static_CUBEMAP + psh_forgot_to_set_static_FLOWMAP + psh_forgot_to_set_static_CORECOLORTEXTURE + psh_forgot_to_set_static_REFRACT + 0 +class sdk_core_ps20b_Dynamic_Index +{ +private: + int m_nPIXELFOGTYPE; +#ifdef _DEBUG + bool m_bPIXELFOGTYPE; +#endif +public: + void SetPIXELFOGTYPE( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nPIXELFOGTYPE = i; +#ifdef _DEBUG + m_bPIXELFOGTYPE = true; +#endif + } + void SetPIXELFOGTYPE( bool i ) + { + m_nPIXELFOGTYPE = i ? 1 : 0; +#ifdef _DEBUG + m_bPIXELFOGTYPE = true; +#endif + } +public: + sdk_core_ps20b_Dynamic_Index() + { +#ifdef _DEBUG + m_bPIXELFOGTYPE = false; +#endif // _DEBUG + m_nPIXELFOGTYPE = 0; + } + int GetIndex() + { + // Asserts to make sure that we aren't using any skipped combinations. + // Asserts to make sure that we are setting all of the combination vars. +#ifdef _DEBUG + bool bAllDynamicVarsDefined = m_bPIXELFOGTYPE; + Assert( bAllDynamicVarsDefined ); +#endif // _DEBUG + return ( 1 * m_nPIXELFOGTYPE ) + 0; + } +}; +#define shaderDynamicTest_sdk_core_ps20b psh_forgot_to_set_dynamic_PIXELFOGTYPE + 0 diff --git a/sp/src/materialsystem/stdshaders/fxctmp9_tmp/SDK_core_vs20.inc b/sp/src/materialsystem/stdshaders/fxctmp9_tmp/SDK_core_vs20.inc new file mode 100644 index 00000000..ef6a680c --- /dev/null +++ b/sp/src/materialsystem/stdshaders/fxctmp9_tmp/SDK_core_vs20.inc @@ -0,0 +1,112 @@ +#include "shaderlib/cshader.h" +class sdk_core_vs20_Static_Index +{ +private: + int m_nMODEL; +#ifdef _DEBUG + bool m_bMODEL; +#endif +public: + void SetMODEL( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nMODEL = i; +#ifdef _DEBUG + m_bMODEL = true; +#endif + } + void SetMODEL( bool i ) + { + m_nMODEL = i ? 1 : 0; +#ifdef _DEBUG + m_bMODEL = true; +#endif + } +public: + sdk_core_vs20_Static_Index( ) + { +#ifdef _DEBUG + m_bMODEL = false; +#endif // _DEBUG + m_nMODEL = 0; + } + int GetIndex() + { + // Asserts to make sure that we aren't using any skipped combinations. + // Asserts to make sure that we are setting all of the combination vars. +#ifdef _DEBUG + bool bAllStaticVarsDefined = m_bMODEL; + Assert( bAllStaticVarsDefined ); +#endif // _DEBUG + return ( 4 * m_nMODEL ) + 0; + } +}; +#define shaderStaticTest_sdk_core_vs20 vsh_forgot_to_set_static_MODEL + 0 +class sdk_core_vs20_Dynamic_Index +{ +private: + int m_nCOMPRESSED_VERTS; +#ifdef _DEBUG + bool m_bCOMPRESSED_VERTS; +#endif +public: + void SetCOMPRESSED_VERTS( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nCOMPRESSED_VERTS = i; +#ifdef _DEBUG + m_bCOMPRESSED_VERTS = true; +#endif + } + void SetCOMPRESSED_VERTS( bool i ) + { + m_nCOMPRESSED_VERTS = i ? 1 : 0; +#ifdef _DEBUG + m_bCOMPRESSED_VERTS = true; +#endif + } +private: + int m_nSKINNING; +#ifdef _DEBUG + bool m_bSKINNING; +#endif +public: + void SetSKINNING( int i ) + { + Assert( i >= 0 && i <= 1 ); + m_nSKINNING = i; +#ifdef _DEBUG + m_bSKINNING = true; +#endif + } + void SetSKINNING( bool i ) + { + m_nSKINNING = i ? 1 : 0; +#ifdef _DEBUG + m_bSKINNING = true; +#endif + } +public: + sdk_core_vs20_Dynamic_Index() + { +#ifdef _DEBUG + m_bCOMPRESSED_VERTS = false; +#endif // _DEBUG + m_nCOMPRESSED_VERTS = 0; +#ifdef _DEBUG + m_bSKINNING = false; +#endif // _DEBUG + m_nSKINNING = 0; + } + int GetIndex() + { + // Asserts to make sure that we aren't using any skipped combinations. + // Asserts to make sure that we are setting all of the combination vars. +#ifdef _DEBUG + bool bAllDynamicVarsDefined = m_bCOMPRESSED_VERTS && m_bSKINNING; + Assert( bAllDynamicVarsDefined ); +#endif // _DEBUG + return ( 1 * m_nCOMPRESSED_VERTS ) + ( 2 * m_nSKINNING ) + 0; + } +}; +#define shaderDynamicTest_sdk_core_vs20 vsh_forgot_to_set_dynamic_COMPRESSED_VERTS + vsh_forgot_to_set_dynamic_SKINNING + 0 diff --git a/sp/src/materialsystem/stdshaders/game_shader_dx9_mapbase.vpc b/sp/src/materialsystem/stdshaders/game_shader_dx9_mapbase.vpc index 40d64143..d6a8480d 100644 --- a/sp/src/materialsystem/stdshaders/game_shader_dx9_mapbase.vpc +++ b/sp/src/materialsystem/stdshaders/game_shader_dx9_mapbase.vpc @@ -64,6 +64,8 @@ $Project $File "engine_post_dx9.cpp" $File "depthoffield_dx9.cpp" + + $File "core_dx9.cpp" } //$Shaders "mapbase_dx9_20b.txt" From b718f19d45d4f212858f9e5949c750a246bd1f68 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Wed, 21 Apr 2021 15:01:50 -0500 Subject: [PATCH 030/378] Fixed VScriptProxy not working without a renderable and added a GetVarName function --- sp/src/game/client/vscript_client.cpp | 35 +++++++++++++++++++++------ 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/sp/src/game/client/vscript_client.cpp b/sp/src/game/client/vscript_client.cpp index 50c66a92..dccaf2a5 100644 --- a/sp/src/game/client/vscript_client.cpp +++ b/sp/src/game/client/vscript_client.cpp @@ -165,6 +165,8 @@ public: void SetVarFloat( int i, float value ); void SetVarVector( int i, const Vector &value ); + const char *GetVarName( int i ); + private: IMaterialVar *m_MaterialVars[SCRIPT_MAT_PROXY_MAX_VARS]; @@ -194,12 +196,19 @@ BEGIN_SCRIPTDESC_ROOT_NAMED( CScriptMaterialProxy, "CScriptMaterialProxy", "Mate DEFINE_SCRIPTFUNC( SetVarInt, "Sets a material var's int value" ) DEFINE_SCRIPTFUNC( SetVarFloat, "Sets a material var's float value" ) DEFINE_SCRIPTFUNC( SetVarVector, "Sets a material var's vector value" ) + + DEFINE_SCRIPTFUNC( GetVarName, "Gets a material var's name" ) END_SCRIPTDESC(); CScriptMaterialProxy::CScriptMaterialProxy() { m_hScriptInstance = NULL; m_hFuncOnBind = NULL; + + for (int i = 0; i < SCRIPT_MAT_PROXY_MAX_VARS; i++) + { + m_MaterialVars[i] = NULL; + } } CScriptMaterialProxy::~CScriptMaterialProxy() @@ -316,18 +325,20 @@ void CScriptMaterialProxy::TermScript() void CScriptMaterialProxy::OnBind( void *pRenderable ) { - if( !pRenderable ) - return; - if (m_hFuncOnBind != NULL) { - IClientRenderable *pRend = ( IClientRenderable* )pRenderable; - C_BaseEntity *pEnt = pRend->GetIClientUnknown()->GetBaseEntity(); - if ( pEnt ) + C_BaseEntity *pEnt = NULL; + if (pRenderable) { - g_pScriptVM->SetValue( m_ScriptScope, "entity", pEnt->GetScriptInstance() ); + IClientRenderable *pRend = (IClientRenderable*)pRenderable; + pEnt = pRend->GetIClientUnknown()->GetBaseEntity(); + if ( pEnt ) + { + g_pScriptVM->SetValue( m_ScriptScope, "entity", pEnt->GetScriptInstance() ); + } } - else + + if (!pEnt) { // Needs to register as a null value so the script doesn't break if it looks for an entity g_pScriptVM->SetValue( m_ScriptScope, "entity", SCRIPT_VARIANT_NULL ); @@ -414,6 +425,14 @@ void CScriptMaterialProxy::SetVarVector( int i, const Vector &value ) return m_MaterialVars[i]->SetVecValue( value.Base(), 3 ); } +const char *CScriptMaterialProxy::GetVarName( int i ) +{ + if (!ValidateIndex( i ) || !m_MaterialVars[i]) + return NULL; + + return m_MaterialVars[i]->GetName(); +} + EXPOSE_INTERFACE( CScriptMaterialProxy, IMaterialProxy, "VScriptProxy" IMATERIAL_PROXY_INTERFACE_VERSION ); bool CMaterialProxyScriptInstanceHelper::ToString( void *p, char *pBuf, int bufSize ) From 491b258f70d4667e7b48bc226a6eb614be235155 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Wed, 21 Apr 2021 15:09:52 -0500 Subject: [PATCH 031/378] Fixed Vector unary minus operator modifying the instance itself --- sp/src/vscript/vscript_squirrel.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sp/src/vscript/vscript_squirrel.cpp b/sp/src/vscript/vscript_squirrel.cpp index 0ec23b97..afb466f6 100644 --- a/sp/src/vscript/vscript_squirrel.cpp +++ b/sp/src/vscript/vscript_squirrel.cpp @@ -464,7 +464,12 @@ namespace SQVector return sq_throwerror(vm, "Expected (Vector)"); } - v1->Negate(); + sq_getclass(vm, 1); + sq_createinstance(vm, -1); + SQUserPointer p; + sq_getinstanceup(vm, -1, &p, 0); + new(p) Vector(-v1->x, -v1->y, -v1->z); + sq_remove(vm, -2); return 1; } From fc9d699fedec71c24f7061a5912c832c216414b3 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Wed, 21 Apr 2021 15:13:54 -0500 Subject: [PATCH 032/378] Changed VScript custom file read method and increased the max size to 64 MB --- .../shared/mapbase/vscript_singletons.cpp | 35 +++++++++++++------ 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/sp/src/game/shared/mapbase/vscript_singletons.cpp b/sp/src/game/shared/mapbase/vscript_singletons.cpp index c5e51499..47e26bb0 100644 --- a/sp/src/game/shared/mapbase/vscript_singletons.cpp +++ b/sp/src/game/shared/mapbase/vscript_singletons.cpp @@ -985,7 +985,7 @@ void CScriptSaveRestoreUtil::ClearSavedTable( const char *szId ) // Read/Write to File // Based on L4D2/Source 2 API //============================================================================= -#define SCRIPT_MAX_FILE_READ_SIZE (16 * 1024) // 16KB +#define SCRIPT_MAX_FILE_READ_SIZE (64 * 1024 * 1024) // 64MB #define SCRIPT_MAX_FILE_WRITE_SIZE (64 * 1024 * 1024) // 64MB #define SCRIPT_RW_PATH_ID "MOD" #define SCRIPT_RW_FULL_PATH_FMT "vscript_io/%s" @@ -1012,11 +1012,11 @@ public: } private: - static const char *m_pszReturnReadFile; + static char *m_pszReturnReadFile; } g_ScriptReadWrite; -const char *CScriptReadWriteFile::m_pszReturnReadFile = NULL; +char *CScriptReadWriteFile::m_pszReturnReadFile = NULL; //----------------------------------------------------------------------------- // @@ -1074,19 +1074,32 @@ const char *CScriptReadWriteFile::FileRead( const char *szFile ) return NULL; } - CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER ); - if ( !g_pFullFileSystem->ReadFile( pszFullName, SCRIPT_RW_PATH_ID, buf, SCRIPT_MAX_FILE_READ_SIZE ) ) + FileHandle_t file = g_pFullFileSystem->Open( pszFullName, "rb", SCRIPT_RW_PATH_ID ); + if ( !file ) { return NULL; } - // first time calling, allocate - if ( !m_pszReturnReadFile ) - m_pszReturnReadFile = new char[SCRIPT_MAX_FILE_READ_SIZE]; + // Close the previous buffer + if (m_pszReturnReadFile) + g_pFullFileSystem->FreeOptimalReadBuffer( m_pszReturnReadFile ); - V_strncpy( const_cast(m_pszReturnReadFile), (const char*)buf.Base(), buf.Size() ); - buf.Purge(); - return m_pszReturnReadFile; + unsigned bufSize = g_pFullFileSystem->GetOptimalReadSize( file, size + 2 ); + m_pszReturnReadFile = (char*)g_pFullFileSystem->AllocOptimalReadBuffer( file, bufSize ); + + bool bRetOK = ( g_pFullFileSystem->ReadEx( m_pszReturnReadFile, bufSize, size, file ) != 0 ); + g_pFullFileSystem->Close( file ); // close file after reading + + if ( bRetOK ) + { + m_pszReturnReadFile[size] = 0; // null terminate file as EOF + //buffer[size+1] = 0; // double NULL terminating in case this is a unicode file + return m_pszReturnReadFile; + } + else + { + return NULL; + } } //----------------------------------------------------------------------------- From 8b699441e9b5f32a866eaafc450096323e408bd5 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Wed, 21 Apr 2021 15:17:47 -0500 Subject: [PATCH 033/378] Added VScript functions for ropes --- sp/src/game/client/c_rope.cpp | 40 +++++++++++++++++++ sp/src/game/client/c_rope.h | 13 ++++++ .../shared/mapbase/vscript_consts_shared.cpp | 17 ++++++++ .../shared/mapbase/vscript_funcs_shared.cpp | 20 +++++++++- 4 files changed, 89 insertions(+), 1 deletion(-) diff --git a/sp/src/game/client/c_rope.cpp b/sp/src/game/client/c_rope.cpp index 450faf78..636b7c6e 100644 --- a/sp/src/game/client/c_rope.cpp +++ b/sp/src/game/client/c_rope.cpp @@ -73,6 +73,27 @@ IMPLEMENT_CLIENTCLASS_DT_NOBASE( C_RopeKeyframe, DT_RopeKeyframe, CRopeKeyframe RecvPropInt( RECVINFO( m_iParentAttachment ) ), END_RECV_TABLE() +#ifdef MAPBASE_VSCRIPT +BEGIN_ENT_SCRIPTDESC( C_RopeKeyframe, C_BaseEntity, "The clientside class of move_rope and keyframe_rope" ) + DEFINE_SCRIPTFUNC( GetNodePosition, "Gets the position of the specified node index" ) + DEFINE_SCRIPTFUNC( GetNumNodes, "Gets the number of nodes available" ) + + DEFINE_SCRIPTFUNC_NAMED( ScriptGetStartEntity, "GetStartEntity", "Gets the rope's start entity" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptGetEndEntity, "GetEndEntity", "Gets the rope's end entity" ) + + DEFINE_SCRIPTFUNC( SetupHangDistance, "Sets the rope's hang distance" ) + DEFINE_SCRIPTFUNC( SetSlack, "Sets the rope's slack value (extra length)" ) + DEFINE_SCRIPTFUNC( GetRopeFlags, "Gets the rope's flags" ) + DEFINE_SCRIPTFUNC( SetRopeFlags, "Sets the rope's flags" ) + + DEFINE_SCRIPTFUNC( SetColorMod, "Sets the rope's color mod value" ) + + DEFINE_SCRIPTFUNC( ShakeRope, "Shakes the rope with the specified center, radius, and magnitude" ) + + DEFINE_SCRIPTFUNC( AnyPointsMoved, "Returns true if any points have moved recently" ) +END_SCRIPTDESC(); +#endif + #define ROPE_IMPULSE_SCALE 20 #define ROPE_IMPULSE_DECAY 0.95 @@ -2022,6 +2043,25 @@ bool C_RopeKeyframe::GetAttachment( int number, Vector &origin, QAngle &angles ) return false; } +#ifdef MAPBASE +const Vector &C_RopeKeyframe::GetNodePosition( int index ) +{ + int nNodes = m_RopePhysics.NumNodes(); + if ( index >= nNodes || nNodes < 2 ) + { + Warning( "C_RopeKeyframe::GetNodePosition(): Invalid node index %i (number of nodes is %i)\n", index, nNodes ); + return vec3_origin; + } + + return m_RopePhysics.GetNode( index )->m_vPredicted; +} + +int C_RopeKeyframe::GetNumNodes() +{ + return m_RopePhysics.NumNodes(); +} +#endif + bool C_RopeKeyframe::AnyPointsMoved() { #ifdef MAPBASE diff --git a/sp/src/game/client/c_rope.h b/sp/src/game/client/c_rope.h index 3d821081..204b412b 100644 --- a/sp/src/game/client/c_rope.h +++ b/sp/src/game/client/c_rope.h @@ -33,6 +33,9 @@ public: DECLARE_CLASS( C_RopeKeyframe, C_BaseEntity ); DECLARE_CLIENTCLASS(); +#ifdef MAPBASE_VSCRIPT + DECLARE_ENT_SCRIPTDESC(); +#endif private: @@ -142,6 +145,11 @@ public: virtual bool GetAttachment( int number, Vector &origin ); virtual bool GetAttachmentVelocity( int number, Vector &originVel, Quaternion &angleVel ); +#ifdef MAPBASE + const Vector &GetNodePosition( int index ); + int GetNumNodes(); +#endif + private: void FinishInit( const char *pMaterialName ); @@ -166,6 +174,11 @@ private: void ReceiveMessage( int classID, bf_read &msg ); bool CalculateEndPointAttachment( C_BaseEntity *pEnt, int iAttachment, Vector &vPos, QAngle *pAngles ); +#ifdef MAPBASE_VSCRIPT + HSCRIPT ScriptGetStartEntity() { return ToHScript( GetStartEntity() ); } + HSCRIPT ScriptGetEndEntity() { return ToHScript( GetEndEntity() ); } +#endif + private: // Track which links touched something last frame. Used to prevent wind from gusting on them. diff --git a/sp/src/game/shared/mapbase/vscript_consts_shared.cpp b/sp/src/game/shared/mapbase/vscript_consts_shared.cpp index edd30409..5d4675c5 100644 --- a/sp/src/game/shared/mapbase/vscript_consts_shared.cpp +++ b/sp/src/game/shared/mapbase/vscript_consts_shared.cpp @@ -8,6 +8,7 @@ #include "cbase.h" #include "activitylist.h" #include "in_buttons.h" +#include "rope_shared.h" #ifdef CLIENT_DLL #include "c_ai_basenpc.h" #else @@ -310,6 +311,22 @@ void RegisterSharedScriptConstants() ScriptRegisterConstant( g_pScriptVM, MOVETYPE_OBSERVER, "Move type used in GetMoveType(), etc." ); ScriptRegisterConstant( g_pScriptVM, MOVETYPE_CUSTOM, "Move type used in GetMoveType(), etc." ); + // + // Ropes + // + ScriptRegisterConstant( g_pScriptVM, ROPE_RESIZE, "Try to keep the rope dangling the same amount even as the rope length changes. (for use in rope flags)" ); + ScriptRegisterConstant( g_pScriptVM, ROPE_BARBED, "Hack option to draw like a barbed wire. (for use in rope flags)" ); + ScriptRegisterConstant( g_pScriptVM, ROPE_COLLIDE, "Collide with the world. (for use in rope flags)" ); + ScriptRegisterConstant( g_pScriptVM, ROPE_SIMULATE, "Is the rope valid? (for use in rope flags)" ); + ScriptRegisterConstant( g_pScriptVM, ROPE_BREAKABLE, "Can the endpoints detach? (for use in rope flags)" ); + ScriptRegisterConstant( g_pScriptVM, ROPE_USE_WIND, "Wind simulation on this rope. (for use in rope flags)" ); + ScriptRegisterConstant( g_pScriptVM, ROPE_INITIAL_HANG, "By default, ropes will simulate for a bit internally when they are created so they sag, but dynamically created ropes for things like harpoons don't want this. (for use in rope flags)" ); + ScriptRegisterConstant( g_pScriptVM, ROPE_PLAYER_WPN_ATTACH, "If this flag is set, then the second attachment must be a player. The rope will attach to \"buff_attach\" on the player's active weapon. This is a flag because it requires special code on the client to find the weapon. (for use in rope flags)" ); + ScriptRegisterConstant( g_pScriptVM, ROPE_NO_GRAVITY, "Disable gravity on this rope. (for use in rope flags)" ); + ScriptRegisterConstant( g_pScriptVM, ROPE_NUMFLAGS, "The number of rope flags recognized by the game." ); + + ScriptRegisterConstantNamed( g_pScriptVM, Vector( ROPE_GRAVITY ), "ROPE_GRAVITY", "Default rope gravity vector." ); + #ifdef GAME_DLL // // Sound Types, Contexts, and Channels diff --git a/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp b/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp index fed3ea1b..9fb186c2 100644 --- a/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp +++ b/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp @@ -22,7 +22,10 @@ #include "globalstate.h" #include "vscript_server.h" #include "soundent.h" -#endif // !CLIENT_DLL +#include "rope.h" +#else +#include "c_rope.h" +#endif // CLIENT_DLL #include "con_nprint.h" #include "particle_parse.h" @@ -738,6 +741,19 @@ static void ScriptDecalTrace( HSCRIPT hTrace, const char *decalName ) UTIL_DecalTrace( &traceInfo->GetTrace(), decalName ); } +static HSCRIPT ScriptCreateRope( HSCRIPT hStart, HSCRIPT hEnd, int iStartAttachment, int iEndAttachment, float ropeWidth, const char *pMaterialName, int numSegments, int ropeFlags ) +{ +#ifdef CLIENT_DLL + C_RopeKeyframe *pRope = C_RopeKeyframe::Create( ToEnt( hStart ), ToEnt( hEnd ), iStartAttachment, iEndAttachment, ropeWidth, pMaterialName, numSegments, ropeFlags ); +#else + CRopeKeyframe *pRope = CRopeKeyframe::Create( ToEnt( hStart ), ToEnt( hEnd ), iStartAttachment, iEndAttachment, ropeWidth, pMaterialName, numSegments ); + if (pRope) + pRope->m_RopeFlags |= ropeFlags; // HACKHACK +#endif + + return ToHScript( pRope ); +} + //----------------------------------------------------------------------------- // Simple particle effect dispatch //----------------------------------------------------------------------------- @@ -902,6 +918,8 @@ void RegisterSharedScriptFunctions() ScriptRegisterFunctionNamed( g_pScriptVM, ScriptDecalTrace, "DecalTrace", "Creates a dynamic decal based on the given trace info. The trace information can be generated by TraceLineComplex() and the decal name must be from decals_subrect.txt." ); ScriptRegisterFunctionNamed( g_pScriptVM, ScriptDispatchParticleEffect, "DoDispatchParticleEffect", SCRIPT_ALIAS( "DispatchParticleEffect", "Dispatches a one-off particle system" ) ); + ScriptRegisterFunctionNamed( g_pScriptVM, ScriptCreateRope, "CreateRope", "Creates a single rope between two entities. Can optionally follow specific attachments." ); + 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." ); From 62c6c3cb6b7ded4d176f07db8d878e58c630db33 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Wed, 21 Apr 2021 15:19:49 -0500 Subject: [PATCH 034/378] Fixed apparent buffer over-read in SDK_LightmappedGeneric --- .../stdshaders/lightmappedgeneric_dx9_helper.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sp/src/materialsystem/stdshaders/lightmappedgeneric_dx9_helper.cpp b/sp/src/materialsystem/stdshaders/lightmappedgeneric_dx9_helper.cpp index b2a8ddcc..6f64a15d 100644 --- a/sp/src/materialsystem/stdshaders/lightmappedgeneric_dx9_helper.cpp +++ b/sp/src/materialsystem/stdshaders/lightmappedgeneric_dx9_helper.cpp @@ -1566,9 +1566,10 @@ void DrawLightmappedGeneric_DX9_Internal(CBaseVSShader *pShader, IMaterialVar** // Doing it here in the shader itself allows us to retain other properties, like FANCY_BLENDING. else { - // m_SemiStaticCmdsOut wasn't being sent correctly, so we have to assign this to the API directly - float editorBlend = bEditorBlend ? 1.0f : 0.0f; - pContextData->m_SemiStaticCmdsOut.SetPixelShaderConstant( 21, &editorBlend, 1 ); + // TODO: This is inefficient use of a constant; Something should be done about this in the future + static const float editorBlend[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; + static const float regularBlend[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; + pContextData->m_SemiStaticCmdsOut.SetPixelShaderConstant( 21, (bEditorBlend ? editorBlend : regularBlend), 1 ); /* if (bEditorBlend) { From 0b14f5fbcc6ee783b2f892568e97c72b22538af9 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Thu, 22 Apr 2021 01:38:52 -0500 Subject: [PATCH 035/378] Added convar to change weapon pickup autoswitch behavior --- sp/src/game/server/player.cpp | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/sp/src/game/server/player.cpp b/sp/src/game/server/player.cpp index 0f26c252..7efac526 100644 --- a/sp/src/game/server/player.cpp +++ b/sp/src/game/server/player.cpp @@ -7698,6 +7698,10 @@ void CBasePlayer::Weapon_DropSlot( int weaponSlot ) } } +#ifdef MAPBASE +ConVar player_autoswitch_on_first_pickup("player_autoswitch_on_pickup", "1", FCVAR_NONE, "Determines how the player should autoswitch when picking up a new weapon. 0 = no autoswitch, 1 = always (default), 2 = use unused weighting system"); +#endif + //----------------------------------------------------------------------------- // Purpose: Override to add weapon to the hud //----------------------------------------------------------------------------- @@ -7706,24 +7710,25 @@ void CBasePlayer::Weapon_Equip( CBaseCombatWeapon *pWeapon ) BaseClass::Weapon_Equip( pWeapon ); #ifdef MAPBASE - // So, I discovered that BumpWeapon seems to have some deprecated code. - // It automatically switches the player to all new weapons. Sounds normal, right? - // Except that's *also* handled here. Since the BumpWeapon code implied the player could pick up weapons while carrying the mega physcannon, - // I assumed it was some old, deprecated code and, since I needed to remove a piece of (also deprecated) code in it, I decided to remove it entirely - // and hand weapon switching to this alone. Seems straightforward, right? - // - // Well, it turns out, this code was more complicated than I thought and used various weights and stuff to determine if a weapon was worth automatically switching to. - // It doesn't automatically switch to most of the weapons. Even though I seem to be right about that old code being deprecated, - // I got irritated and...uh...replaced the correct Weapon_Equip code with the old deprecated code from BumpWeapon. - // - // Trust me. It was hard and pointless to get used to. You'll thank me later. - - if ( !PlayerHasMegaPhysCannon() ) + // BumpWeapon's code appeared to be deprecated; The same operation is already handled here, but with much more code involved. + // There's also an unused weighting system which was overridden by that deprecated code. The unused weighting code can be enabled + // via player_autoswitch_on_first_pickup. + bool bShouldSwitch = false; + switch (player_autoswitch_on_first_pickup.GetInt()) { - Weapon_Switch( pWeapon ); + // Unused Weighting + case 2: + bShouldSwitch = g_pGameRules->FShouldSwitchWeapon( this, pWeapon ); + break; + + // Always (old behavior) + case 1: + bShouldSwitch = true; + break; } #else bool bShouldSwitch = g_pGameRules->FShouldSwitchWeapon( this, pWeapon ); +#endif #ifdef HL2_DLL if ( bShouldSwitch == false && PhysCannonGetHeldEntity( GetActiveWeapon() ) == pWeapon && @@ -7738,7 +7743,6 @@ void CBasePlayer::Weapon_Equip( CBaseCombatWeapon *pWeapon ) { Weapon_Switch( pWeapon ); } -#endif } #ifdef MAPBASE From ebec14d2b6820a93f8aa7063c87aefd12d042462 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Thu, 22 Apr 2021 01:39:59 -0500 Subject: [PATCH 036/378] Restored unused port of Alyx combat AI speech concepts for all player companions --- sp/src/game/server/hl2/npc_playercompanion.cpp | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/sp/src/game/server/hl2/npc_playercompanion.cpp b/sp/src/game/server/hl2/npc_playercompanion.cpp index 76166b1b..b6aa5062 100644 --- a/sp/src/game/server/hl2/npc_playercompanion.cpp +++ b/sp/src/game/server/hl2/npc_playercompanion.cpp @@ -4223,17 +4223,10 @@ void CNPC_PlayerCompanion::Event_KilledOther( CBaseEntity *pVictim, const CTakeD } //----------------------------------------------------------------------------- -// Purpose: Handles stuff ported from Alyx. -// -// For some reason, I thought Alyx's mobbed AI was used to measure enemy count for criteria stuff, which I wanted citizens to use. -// Now that I realize enemy counting for criteria is elsewhere and this is used for just mobbing in general, I deactivated it -// since it would barely be used and I don't know what kind of an impact it has on performance. -// -// If you want to use it, feel free to re-activate. +// Purpose: Handles custom combat speech stuff ported from Alyx. //----------------------------------------------------------------------------- void CNPC_PlayerCompanion::DoCustomCombatAI( void ) { - /* #define COMPANION_MIN_MOB_DIST_SQR Square(120) // Any enemy closer than this adds to the 'mob' #define COMPANION_MIN_CONSIDER_DIST Square(1200) // Only enemies within this range are counted and considered to generate AI speech @@ -4296,7 +4289,6 @@ void CNPC_PlayerCompanion::DoCustomCombatAI( void ) { SpeakIfAllowed( TLK_MANY_ENEMIES ); } - */ } #endif From 15d04c0b9ba5cd28c86ac1b542f859640a1d57fb Mon Sep 17 00:00:00 2001 From: Blixibon Date: Thu, 22 Apr 2021 11:12:29 -0500 Subject: [PATCH 037/378] Reworked Mapbase console groups to use script files and separate server/client commands instead of cvars and tier1 commands --- sp/src/game/server/ai_speech_new.cpp | 14 +- sp/src/game/shared/mapbase/mapbase_shared.cpp | 38 +++++ sp/src/public/tier1/mapbase_con_groups.h | 49 ++++-- sp/src/tier1/mapbase_con_groups.cpp | 141 ++++++++++-------- 4 files changed, 162 insertions(+), 80 deletions(-) diff --git a/sp/src/game/server/ai_speech_new.cpp b/sp/src/game/server/ai_speech_new.cpp index 1edffdb7..76735a9d 100644 --- a/sp/src/game/server/ai_speech_new.cpp +++ b/sp/src/game/server/ai_speech_new.cpp @@ -461,7 +461,7 @@ CAI_Expresser::~CAI_Expresser() #ifdef DEBUG g_nExpressers--; if ( g_nExpressers == 0 && pSemaphore->GetOwner() ) - DevMsg( 2, "Speech semaphore being held by non-talker entity\n" ); + CGMsg( 2, CON_GROUP_SPEECH_AI, "Speech semaphore being held by non-talker entity\n" ); #endif } @@ -826,7 +826,7 @@ bool CAI_Expresser::SpeakDispatchResponse( AIConcept_t &concept, AI_Response *re { entityName = ToBasePlayer( GetOuter() )->GetPlayerName(); } - DevMsg( 2, "SpeakDispatchResponse: Entity ( %i/%s ) already speaking, forcing '%s'\n", GetOuter()->entindex(), entityName ? entityName : "UNKNOWN", (const char*)concept ); + CGMsg( 2, CON_GROUP_SPEECH_AI, "SpeakDispatchResponse: Entity ( %i/%s ) already speaking, forcing '%s'\n", GetOuter()->entindex(), entityName ? entityName : "UNKNOWN", (const char*)concept ); // Tracker 15911: Can break the game if we stop an imported map placed lcs here, so only // cancel actor out of instanced scripted scenes. ywb @@ -835,7 +835,7 @@ bool CAI_Expresser::SpeakDispatchResponse( AIConcept_t &concept, AI_Response *re if ( IsRunningScriptedScene( GetOuter() ) ) { - DevMsg( "SpeakDispatchResponse: Entity ( %i/%s ) refusing to speak due to scene entity, tossing '%s'\n", GetOuter()->entindex(), entityName ? entityName : "UNKNOWN", (const char*)concept ); + CGMsg( 1, CON_GROUP_SPEECH_AI, "SpeakDispatchResponse: Entity ( %i/%s ) refusing to speak due to scene entity, tossing '%s'\n", GetOuter()->entindex(), entityName ? entityName : "UNKNOWN", (const char*)concept ); return false; } } @@ -858,7 +858,7 @@ bool CAI_Expresser::SpeakDispatchResponse( AIConcept_t &concept, AI_Response *re float speakTime = GetResponseDuration( result ); GetOuter()->EmitSound( response ); - DevMsg( 2, "SpeakDispatchResponse: Entity ( %i/%s ) playing sound '%s'\n", GetOuter()->entindex(), STRING( GetOuter()->GetEntityName() ), response ); + CGMsg( 2, CON_GROUP_SPEECH_AI, "SpeakDispatchResponse: Entity ( %i/%s ) playing sound '%s'\n", GetOuter()->entindex(), STRING( GetOuter()->GetEntityName() ), response ); NoteSpeaking( speakTime, delay ); spoke = true; #ifdef MAPBASE @@ -1079,7 +1079,7 @@ bool CAI_Expresser::FireEntIOFromResponse( char *response, CBaseEntity *pInitiat CBaseEntity *pTarget = gEntList.FindEntityByName( NULL, pszEntname, pInitiator ); if ( !pTarget ) { - Msg( "Response rule targeted %s with entityio, but that doesn't exist.\n", pszEntname ); + CGMsg( 0, CON_GROUP_SPEECH_AI, "Response rule targeted %s with entityio, but that doesn't exist.\n", pszEntname ); // but this is actually a legit use case, so return true (below). } else @@ -1528,7 +1528,7 @@ void CAI_Expresser::DumpHistories() { ConceptHistory_t *h = &m_ConceptHistories[ i ]; - DevMsg( "%i: %s at %f\n", c++, m_ConceptHistories.GetElementName( i ), h->timeSpoken ); + CGMsg( 1, CON_GROUP_SPEECH_AI, "%i: %s at %f\n", c++, m_ConceptHistories.GetElementName( i ), h->timeSpoken ); } } @@ -1571,7 +1571,7 @@ void CAI_Expresser::SpeechMsg( CBaseEntity *pFlex, const char *pszFormat, ... ) } else { - DevMsg( CFmtStr( &pszFormat ) ); + CGMsg( 1, CON_GROUP_SPEECH_AI, CFmtStr( &pszFormat ) ); } UTIL_LogPrintf( (char *) ( (const char *) CFmtStr( &pszFormat ) ) ); } diff --git a/sp/src/game/shared/mapbase/mapbase_shared.cpp b/sp/src/game/shared/mapbase/mapbase_shared.cpp index 5aff896f..e93add3c 100644 --- a/sp/src/game/shared/mapbase/mapbase_shared.cpp +++ b/sp/src/game/shared/mapbase/mapbase_shared.cpp @@ -9,6 +9,7 @@ #include "cbase.h" #include "tier0/icommandline.h" +#include "tier1/mapbase_con_groups.h" #include "igamesystem.h" #include "filesystem.h" #include @@ -151,6 +152,8 @@ public: virtual bool Init() { + InitConsoleGroups( g_pFullFileSystem ); + // Checks gameinfo.txt for additional command line options KeyValues *gameinfo = new KeyValues("GameInfo"); if (GetGameInfoKeyValues(gameinfo)) @@ -626,3 +629,38 @@ BEGIN_DATADESC( CMapbaseManifestEntity ) END_DATADESC() #endif + +//----------------------------------------------------------------------------- + +void CV_IncludeNameChanged( IConVar *pConVar, const char *pOldString, float flOldValue ); + +#ifdef CLIENT_DLL +ConVar con_group_include_name_client( "con_group_include_name_client", "0", FCVAR_NONE, "Includes groups when printing on the client.", CV_IncludeNameChanged ); + +void CV_IncludeNameChanged( IConVar *pConVar, const char *pOldString, float flOldValue ) +{ + SetConsoleGroupIncludeNames( con_group_include_name_client.GetBool() ); +} +#else +ConVar con_group_include_name( "con_group_include_name", "0", FCVAR_NONE, "Includes groups when printing.", CV_IncludeNameChanged ); + +void CV_IncludeNameChanged( IConVar *pConVar, const char *pOldString, float flOldValue ) +{ + SetConsoleGroupIncludeNames( con_group_include_name.GetBool() ); +} +#endif + +CON_COMMAND_SHARED( con_group_reload, "Reloads all console groups." ) +{ + InitConsoleGroups( g_pFullFileSystem ); +} + +CON_COMMAND_SHARED( con_group_list, "Prints a list of all console groups." ) +{ + PrintAllConsoleGroups(); +} + +CON_COMMAND_SHARED( con_group_toggle, "Toggles a console group." ) +{ + ToggleConsoleGroups( args.Arg( 1 ) ); +} diff --git a/sp/src/public/tier1/mapbase_con_groups.h b/sp/src/public/tier1/mapbase_con_groups.h index cdd955c9..7346092e 100644 --- a/sp/src/public/tier1/mapbase_con_groups.h +++ b/sp/src/public/tier1/mapbase_con_groups.h @@ -16,25 +16,48 @@ //static const Color CON_COLOR_DEV_VERBOSE( 192, 128, 192, 255 ); -// General -#define CON_GROUP_MAPBASE_MISC 0 // "Mapbase Misc." -#define CON_GROUP_PHYSICS 1 // "Physics" +enum ConGroupID_t +{ + // General + CON_GROUP_MAPBASE_MISC, // "Mapbase misc." + CON_GROUP_PHYSICS, // "Physics" + CON_GROUP_IO_SYSTEM, // "Entity I/O" + CON_GROUP_RESPONSE_SYSTEM, // "Response System" -// Server -#define CON_GROUP_IO_SYSTEM 2 // "Entity I/O" -#define CON_GROUP_NPC_AI 3 // "NPC AI" -#define CON_GROUP_NPC_SCRIPTS 4 // "NPC Scripts" -#define CON_GROUP_CHOREO 5 // "Choreo" + // Game + CON_GROUP_NPC_AI, // "NPC AI" + CON_GROUP_NPC_SCRIPTS, // "NPC scripts" + CON_GROUP_SPEECH_AI, // "Speech AI" + CON_GROUP_CHOREO, // "Choreo" -// VScript -#define CON_GROUP_VSCRIPT 6 // "VScript" -#define CON_GROUP_VSCRIPT_PRINT 7 // "VScript Print" + // VScript + CON_GROUP_VSCRIPT, // "VScript" + CON_GROUP_VSCRIPT_PRINT, // "VScript print" -#define CON_GROUP_MAX 8 // must always be at the end + //-------------------------- + + // + // Mod groups can be inserted here + // + + //-------------------------- + + CON_GROUP_MAX, // Keep this at the end +}; // Mapbase console group message. -void CGMsg( int level, int nGroup, PRINTF_FORMAT_STRING const tchar* pMsg, ... ) FMTFUNCTION( 3, 4 ); +void CGMsg( int level, ConGroupID_t nGroup, PRINTF_FORMAT_STRING const tchar* pMsg, ... ) FMTFUNCTION( 3, 4 ); #define CGWarning CGMsg +//----------------------------------------------------------------------------- + +class IBaseFileSystem; + +void InitConsoleGroups( IBaseFileSystem *filesystem ); + +void PrintAllConsoleGroups(); +void ToggleConsoleGroups( const char *pszQuery ); +void SetConsoleGroupIncludeNames( bool bToggle ); + #endif diff --git a/sp/src/tier1/mapbase_con_groups.cpp b/sp/src/tier1/mapbase_con_groups.cpp index 08ca8fc7..65bcd21d 100644 --- a/sp/src/tier1/mapbase_con_groups.cpp +++ b/sp/src/tier1/mapbase_con_groups.cpp @@ -11,102 +11,116 @@ #include #include #include "basetypes.h" -#include "tier1/tier1.h" -#include "tier1/utldict.h" +#include "tier1.h" +#include "utldict.h" #include "Color.h" -#include "tier1/mapbase_con_groups.h" - -void CV_ColorChanged( IConVar *pConVar, const char *pOldString, float flOldValue ); +#include "mapbase_con_groups.h" +#include "KeyValues.h" +#include "filesystem.h" +#include "mapbase_matchers_base.h" struct ConGroup_t { - ConGroup_t( const char *_pszName, ConVar *pCvar ) + ConGroup_t( const char *_pszName, const char *_pszDescription ) { pszName = _pszName; - cvar = pCvar; + pszDescription = _pszDescription; + _clr.SetColor( 224, 224, 224, 255 ); // Default to a shade of gray } const Color &GetColor() { - if (_clr.a() == 0) - { - // Read the cvar - int clr[3]; - sscanf( cvar->GetString(), "%i %i %i", &clr[0], &clr[1], &clr[2] ); - _clr.SetColor( clr[0], clr[1], clr[2], 255 ); - } return _clr; } const char *pszName; + const char *pszDescription; Color _clr; - ConVar *cvar; - //bool bDisabled; + bool bDisabled; }; -//----------------------------------------------------------------------------- -// To define a console group, -//----------------------------------------------------------------------------- - -#define DEFINE_CON_GROUP_CVAR(name, def, desc) static ConVar con_group_##name##_color( "con_group_" #name "_color", def, FCVAR_ARCHIVE | FCVAR_REPLICATED, desc, CV_ColorChanged ) - -DEFINE_CON_GROUP_CVAR( mapbase_misc, "192 128 224", "Messages from misc. Mapbase functions, like map-specific files." ); -DEFINE_CON_GROUP_CVAR( physics, "159 209 159", "Messages from physics-related events." ); - -DEFINE_CON_GROUP_CVAR( inputoutput, "220 170 220", "Messages from I/O events. (these display in developer 2)" ); -DEFINE_CON_GROUP_CVAR( npc_ai, "240 160 200", "Messages from NPC AI, etc. which display at various verbse levels." ); -DEFINE_CON_GROUP_CVAR( npc_scripts, "255 115 215", "Messages from scripted_sequence, etc. (these display in developer 2)" ); -DEFINE_CON_GROUP_CVAR( choreo, "240 224 180", "Messages from choreographed scenes and response expressers. (these display in developer 1, 2, etc.)" ); - -DEFINE_CON_GROUP_CVAR( vscript, "192 224 240", "Internal messages from VScript not produced by the user's scripts." ); -DEFINE_CON_GROUP_CVAR( vscript_print, "80 186 255", "Messages from VScript's 'print' function." ); +// TODO: Something more reliable? +static bool g_bIncludeConGroupNames = false; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- -#define DEFINE_CON_GROUP(id, name, codename) { name, &con_group_##codename##_color } +//#define DEFINE_CON_GROUP(id, name, codename) { name, &con_group_##codename##_color } +#define DEFINE_CON_GROUP(id, name, description) { name, description } ConGroup_t g_ConGroups[CON_GROUP_MAX] = { // General - DEFINE_CON_GROUP( CON_GROUP_MAPBASE_MISC, "Mapbase misc.", mapbase_misc ), - DEFINE_CON_GROUP( CON_GROUP_PHYSICS, "Physics", physics ), + DEFINE_CON_GROUP( CON_GROUP_MAPBASE_MISC, "Mapbase misc.", "Messages from misc. Mapbase functions, like map-specific files." ), + DEFINE_CON_GROUP( CON_GROUP_PHYSICS, "Physics", "Messages from physics-related events." ), + DEFINE_CON_GROUP( CON_GROUP_IO_SYSTEM, "Entity IO", "Messages from I/O events. (these display in developer 2)" ), + DEFINE_CON_GROUP( CON_GROUP_RESPONSE_SYSTEM, "Response System", "Messages from the Response System, a library primarily used for NPC speech." ), - // Server - DEFINE_CON_GROUP( CON_GROUP_IO_SYSTEM, "Entity IO", inputoutput ), - DEFINE_CON_GROUP( CON_GROUP_NPC_AI, "NPC AI", npc_ai ), - DEFINE_CON_GROUP( CON_GROUP_NPC_SCRIPTS, "NPC scripts", npc_scripts ), - DEFINE_CON_GROUP( CON_GROUP_CHOREO, "Choreo", choreo ), + // Game + DEFINE_CON_GROUP( CON_GROUP_NPC_AI, "NPC AI", "Messages from NPC AI, etc. which display at various verbose levels." ), + DEFINE_CON_GROUP( CON_GROUP_NPC_SCRIPTS, "NPC scripts", "Messages from scripted_sequence, etc. (these display in developer 2)" ), + DEFINE_CON_GROUP( CON_GROUP_SPEECH_AI, "Speech AI", "Messages from response expressers. (these display in developer 1, 2, etc.)" ), + DEFINE_CON_GROUP( CON_GROUP_CHOREO, "Choreo", "Messages from choreographed scenes. (these display in developer 1, 2, etc.)" ), // VScript - DEFINE_CON_GROUP( CON_GROUP_VSCRIPT, "VScript", vscript ), - DEFINE_CON_GROUP( CON_GROUP_VSCRIPT_PRINT, "VScript print", vscript_print ), + DEFINE_CON_GROUP( CON_GROUP_VSCRIPT, "VScript", "Internal messages from VScript not produced by actual scripts." ), + DEFINE_CON_GROUP( CON_GROUP_VSCRIPT_PRINT, "VScript print", "Messages from VScript's 'print' function." ), }; -void CV_ColorChanged( IConVar *pConVar, const char *pOldString, float flOldValue ) +int FindConGroup( const char *pszName ) { for (int i = 0; i < CON_GROUP_MAX; i++) { - // Reset the alpha to indicate it needs to be refreshed - g_ConGroups[i]._clr[3] = 0; + if (Q_stricmp( pszName, g_ConGroups[i].pszName ) == 0) + return i; } + + return -1; } //----------------------------------------------------------------------------- +// Loads console groups //----------------------------------------------------------------------------- +void LoadConsoleGroupsFromFile( IBaseFileSystem *filesystem, const char *pszFileName, const char *pathID ) +{ + KeyValues *pGroupRoot = new KeyValues( "ConsoleGroups" ); -ConVar con_group_include_name( "con_group_include_name", "0", FCVAR_NONE, "Includes groups when printing." ); + pGroupRoot->LoadFromFile( filesystem, pszFileName, pathID ); -CON_COMMAND( con_group_list, "Prints a list of all console groups." ) + KeyValues *pGroup = NULL; + for ( pGroup = pGroupRoot->GetFirstTrueSubKey(); pGroup; pGroup = pGroup->GetNextTrueSubKey() ) + { + int index = FindConGroup( pGroup->GetName() ); + if (index != -1) + { + g_ConGroups[index]._clr = pGroup->GetColor( "MessageColor" ); + //g_ConGroups[index].bDisabled = pGroup->GetBool( "Disabled", false ); + } + else + { + Warning( "Invalid console group %s (new groups should be defined in the code)\n", pGroup->GetName() ); + } + } + + pGroupRoot->deleteThis(); +} + +void InitConsoleGroups( IBaseFileSystem *filesystem ) +{ + LoadConsoleGroupsFromFile( filesystem, "scripts/mapbase_con_groups.txt", "MOD" ); + LoadConsoleGroupsFromFile( filesystem, "scripts/mod_con_groups.txt", "MOD" ); +} + +void PrintAllConsoleGroups() { Msg( "============================================================\n" ); for (int i = 0; i < CON_GROUP_MAX; i++) { Msg( " # " ); ConColorMsg( g_ConGroups[i].GetColor(), "%s", g_ConGroups[i].pszName ); - Msg( " - %s ", g_ConGroups[i].cvar->GetHelpText() ); + Msg( " - %s ", g_ConGroups[i].pszDescription ); //if (g_ConGroups[i].bDisabled) // Msg("(DISABLED)"); @@ -116,26 +130,33 @@ CON_COMMAND( con_group_list, "Prints a list of all console groups." ) Msg( "============================================================\n" ); } -// TODO: Figure out how this can be done without server/client disparity issues -/* -CON_COMMAND( con_group_toggle, "Toggles a console group." ) +void ToggleConsoleGroups( const char *pszQuery ) { - const char *pszGroup = args.Arg( 1 ); + bool bMatched = false; + for (int i = 0; i < ARRAYSIZE( g_ConGroups ); i++) { - if (V_stricmp(pszGroup, g_ConGroups[i].pszName) == 0) + if (Matcher_NamesMatch( pszQuery, g_ConGroups[i].pszName )) { Msg( "%s is now %s\n", g_ConGroups[i].pszName, g_ConGroups[i].bDisabled ? "enabled" : "disabled" ); g_ConGroups[i].bDisabled = !g_ConGroups[i].bDisabled; - return; + bMatched = true; } } - Msg( "No group named \"%s\"\n", pszGroup ); + if (!bMatched) + Msg( "No groups matching \"%s\"\n", pszQuery ); } -*/ -void CGMsg( int level, int nGroup, const tchar* pMsg, ... ) +void SetConsoleGroupIncludeNames( bool bToggle ) +{ + g_bIncludeConGroupNames = bToggle; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- + +void CGMsg( int level, ConGroupID_t nGroup, const tchar* pMsg, ... ) { // Return early if we're not at this level if (!IsSpewActive("developer", level)) @@ -152,11 +173,11 @@ void CGMsg( int level, int nGroup, const tchar* pMsg, ... ) ConGroup_t *pGroup = &g_ConGroups[nGroup]; - /*if (pGroup->bDisabled) + if (pGroup->bDisabled) { - // Do nothing + // Do nothing } - else*/ if (con_group_include_name.GetBool()) + else if (g_bIncludeConGroupNames) { ConColorMsg(level, pGroup->GetColor(), "[%s] %s", pGroup->pszName, string); } From c5ed394330c7c5197407f960357bb0a761fba10e Mon Sep 17 00:00:00 2001 From: Blixibon Date: Thu, 22 Apr 2021 11:14:18 -0500 Subject: [PATCH 038/378] Added console group for the Response System --- sp/src/responserules/runtime/criteriaset.cpp | 14 ++-- .../responserules/runtime/response_system.cpp | 83 ++++++++++--------- .../responserules/runtime/response_types.cpp | 12 +-- sp/src/responserules/runtime/rr_response.cpp | 17 ++-- 4 files changed, 66 insertions(+), 60 deletions(-) diff --git a/sp/src/responserules/runtime/criteriaset.cpp b/sp/src/responserules/runtime/criteriaset.cpp index 3dc5cb20..6d53e954 100644 --- a/sp/src/responserules/runtime/criteriaset.cpp +++ b/sp/src/responserules/runtime/criteriaset.cpp @@ -9,6 +9,8 @@ #include "utlmap.h" +#include "tier1/mapbase_con_groups.h" + // memdbgon must be the last include file in a .cpp file!!! #include @@ -34,7 +36,7 @@ const char *SplitContext( const char *raw, char *key, int keylen, char *value, i char *colon1 = Q_strstr( raw, ":" ); if ( !colon1 ) { - DevMsg( "SplitContext: warning, ignoring context '%s', missing colon separator!\n", raw ); + CGMsg( 1, CON_GROUP_RESPONSE_SYSTEM, "SplitContext: warning, ignoring context '%s', missing colon separator!\n", raw ); *key = *value = 0; return NULL; } @@ -61,7 +63,7 @@ const char *SplitContext( const char *raw, char *key, int keylen, char *value, i char durationStartChar = *(colon2 + 1); if ( durationStartChar < '0' || durationStartChar > '9' ) { - DevMsg( "SplitContext: warning, ignoring context '%s', missing comma separator! Entire context was '%s'.\n", raw, entireContext ); + CGMsg( 1, CON_GROUP_RESPONSE_SYSTEM, "SplitContext: warning, ignoring context '%s', missing comma separator! Entire context was '%s'.\n", raw, entireContext ); *key = *value = 0; return NULL; } @@ -377,11 +379,11 @@ void CriteriaSet::Describe() const const CritEntry_t *entry = m_TempMap.Element( i ); if ( entry->weight != 1.0f ) { - DevMsg( " %20s = '%s' (weight %f)\n", name, entry->value ? entry->value : "", entry->weight ); + CGMsg( 1, CON_GROUP_RESPONSE_SYSTEM, " %20s = '%s' (weight %f)\n", name, entry->value ? entry->value : "", entry->weight ); } else { - DevMsg( " %20s = '%s'\n", name, entry->value ? entry->value : "" ); + CGMsg( 1, CON_GROUP_RESPONSE_SYSTEM, " %20s = '%s'\n", name, entry->value ? entry->value : "" ); } } @@ -393,11 +395,11 @@ void CriteriaSet::Describe() const const char *pCriteriaName = sm_CriteriaSymbols.String( entry->criterianame ); if ( entry->weight != 1.0f ) { - DevMsg( " %20s = '%s' (weight %f)\n", pCriteriaName, entry->value ? entry->value : "", entry->weight ); + CGMsg( 1, CON_GROUP_RESPONSE_SYSTEM, " %20s = '%s' (weight %f)\n", pCriteriaName, entry->value ? entry->value : "", entry->weight ); } else { - DevMsg( " %20s = '%s'\n", pCriteriaName, entry->value ? entry->value : "" ); + CGMsg( 1, CON_GROUP_RESPONSE_SYSTEM, " %20s = '%s'\n", pCriteriaName, entry->value ? entry->value : "" ); } } */ diff --git a/sp/src/responserules/runtime/response_system.cpp b/sp/src/responserules/runtime/response_system.cpp index 968f856d..156bd45f 100644 --- a/sp/src/responserules/runtime/response_system.cpp +++ b/sp/src/responserules/runtime/response_system.cpp @@ -12,6 +12,7 @@ #include "convar.h" #include "fmtstr.h" #include "generichash.h" +#include "tier1/mapbase_con_groups.h" #ifdef MAPBASE #include "tier1/mapbase_matchers_base.h" #endif @@ -561,7 +562,7 @@ bool CResponseSystem::Compare( const char *setValue, Criteria *c, bool verbose / if ( verbose ) { - DevMsg( "'%20s' vs. '%20s' = ", setValue, c->value ); + CGMsg( 1, CON_GROUP_RESPONSE_SYSTEM, "'%20s' vs. '%20s' = ", setValue, c->value ); { //DevMsg( "\n" ); @@ -635,7 +636,7 @@ float CResponseSystem::ScoreCriteriaAgainstRuleCriteria( const CriteriaSet& set, if ( verbose ) { - DevMsg( " criterion '%25s':'%15s' ", m_Criteria.GetElementName( icriterion ), CriteriaSet::SymbolToStr(c->nameSym) ); + CGMsg( 1, CON_GROUP_RESPONSE_SYSTEM, " criterion '%25s':'%15s' ", m_Criteria.GetElementName( icriterion ), CriteriaSet::SymbolToStr(c->nameSym) ); } exclude = false; @@ -669,7 +670,7 @@ float CResponseSystem::ScoreCriteriaAgainstRuleCriteria( const CriteriaSet& set, if ( verbose ) { - DevMsg( "matched, weight %4.2f (s %4.2f x c %4.2f)", + CGMsg( 1, CON_GROUP_RESPONSE_SYSTEM, "matched, weight %4.2f (s %4.2f x c %4.2f)", score, w, c->weight.GetFloat() ); } } @@ -680,14 +681,14 @@ float CResponseSystem::ScoreCriteriaAgainstRuleCriteria( const CriteriaSet& set, exclude = true; if ( verbose ) { - DevMsg( "failed (+exclude rule)" ); + CGMsg( 1, CON_GROUP_RESPONSE_SYSTEM, "failed (+exclude rule)" ); } } else { if ( verbose ) { - DevMsg( "failed" ); + CGMsg( 1, CON_GROUP_RESPONSE_SYSTEM, "failed" ); } } } @@ -713,7 +714,7 @@ float CResponseSystem::ScoreCriteriaAgainstRule( const CriteriaSet& set, Respons { if ( bBeingWatched ) { - DevMsg("Rule is disabled.\n" ); + CGMsg( 1, CON_GROUP_RESPONSE_SYSTEM, "Rule is disabled.\n" ); } return 0.0f; } @@ -725,7 +726,7 @@ float CResponseSystem::ScoreCriteriaAgainstRule( const CriteriaSet& set, Respons if ( verbose ) { - DevMsg( "Scoring rule '%s' (%i)\n{\n", dict.GetElementName( irule ), irule+1 ); + CGMsg( 1, CON_GROUP_RESPONSE_SYSTEM, "Scoring rule '%s' (%i)\n{\n", dict.GetElementName( irule ), irule+1 ); } // Iterate set criteria @@ -740,7 +741,7 @@ float CResponseSystem::ScoreCriteriaAgainstRule( const CriteriaSet& set, Respons if ( verbose ) { - DevMsg( ", score %4.2f\n", score ); + CGMsg( 1, CON_GROUP_RESPONSE_SYSTEM, ", score %4.2f\n", score ); } if ( exclude ) @@ -752,7 +753,7 @@ float CResponseSystem::ScoreCriteriaAgainstRule( const CriteriaSet& set, Respons if ( verbose ) { - DevMsg( "}\n" ); + CGMsg( 1, CON_GROUP_RESPONSE_SYSTEM, "}\n" ); } if ( rule->m_nForceWeight > 0 ) @@ -784,7 +785,7 @@ void CResponseSystem::DebugPrint( int depth, const char *fmt, ... ) Q_vsnprintf (szText, sizeof( szText ), fmt, argptr); va_end (argptr); - DevMsg( "%s%s", indent, szText ); + CGMsg( 1, CON_GROUP_RESPONSE_SYSTEM, "%s%s", indent, szText ); } //----------------------------------------------------------------------------- @@ -1292,7 +1293,7 @@ ResponseRulePartition::tIndex CResponseSystem::FindBestMatchingRule( const Crite int idx = IEngineEmulator::Get()->GetRandomStream()->RandomInt( 0, bestCount - 1 ); if ( verbose ) { - DevMsg( "Found %i matching rules, selecting slot %i\n", bestCount, idx ); + CGMsg( 1, CON_GROUP_RESPONSE_SYSTEM, "Found %i matching rules, selecting slot %i\n", bestCount, idx ); } return bestrules[ idx ] ; } @@ -1474,7 +1475,7 @@ void CResponseSystem::MarkResponseAsUsed( short iGroup, short iWithinGroup ) { group.MarkResponseUsed( iWithinGroup ); - Msg("Marked response %s (%i) used\n", group.group[iWithinGroup].value, iWithinGroup); + CGMsg( 1, CON_GROUP_RESPONSE_SYSTEM, "Marked response %s (%i) used\n", group.group[iWithinGroup].value, iWithinGroup ); } } } @@ -1526,7 +1527,7 @@ void CResponseSystem::ParseInclude() CUtlBuffer buf; if ( !IEngineEmulator::Get()->GetFilesystem()->ReadFile( includefile, "GAME", buf ) ) { - DevMsg( "Unable to load #included script %s\n", includefile ); + CGMsg( 1, CON_GROUP_RESPONSE_SYSTEM, "Unable to load #included script %s\n", includefile ); return; } @@ -1541,7 +1542,7 @@ void CResponseSystem::LoadFromBuffer( const char *scriptfile, const char *buffer if( rr_dumpresponses.GetBool() ) { - DevMsg("Reading: %s\n", scriptfile ); + CGMsg( 1, CON_GROUP_RESPONSE_SYSTEM,"Reading: %s\n", scriptfile ); } while ( 1 ) @@ -1568,7 +1569,7 @@ void CResponseSystem::LoadFromBuffer( const char *scriptfile, const char *buffer { char cur[ 256 ]; GetCurrentScript( cur, sizeof( cur ) ); - DevMsg( 1, "CResponseSystem: %s (%i rules, %i criteria, and %i responses)\n", + CGMsg( 1, CON_GROUP_RESPONSE_SYSTEM, "CResponseSystem: %s (%i rules, %i criteria, and %i responses)\n", cur, m_RulePartitions.Count(), m_Criteria.Count(), m_Responses.Count() ); if( rr_dumpresponses.GetBool() ) @@ -1591,7 +1592,7 @@ void CResponseSystem::LoadRuleSet( const char *basescript ) unsigned char *buffer = (unsigned char *)IEngineEmulator::Get()->LoadFileForMe( basescript, &length ); if ( length <= 0 || !buffer ) { - DevMsg( 1, "CResponseSystem: failed to load %s\n", basescript ); + CGMsg( 1, CON_GROUP_RESPONSE_SYSTEM, "CResponseSystem: failed to load %s\n", basescript ); return; } @@ -2340,7 +2341,7 @@ void CResponseSystem::ParseRule( void ) } else { - DevMsg( "Discarded rule %s\n", ruleName ); + CGMsg( 1, CON_GROUP_RESPONSE_SYSTEM, "Discarded rule %s\n", ruleName ); delete newRule; } } @@ -2368,7 +2369,7 @@ void CResponseSystem::ResponseWarning( const char *fmt, ... ) char cur[ 256 ]; GetCurrentScript( cur, sizeof( cur ) ); - DevMsg( 1, "%s(token %i) : %s", cur, GetCurrentToken(), string ); + CGMsg( 1, CON_GROUP_RESPONSE_SYSTEM, "%s(token %i) : %s", cur, GetCurrentToken(), string ); } //----------------------------------------------------------------------------- @@ -2546,7 +2547,7 @@ void CResponseSystem::DumpRules() m_RulePartitions.IsValid(idx) ; idx = m_RulePartitions.Next(idx) ) { - Msg("%s\n", m_RulePartitions.GetElementName( idx ) ); + CGMsg( 0, CON_GROUP_RESPONSE_SYSTEM, "%s\n", m_RulePartitions.GetElementName( idx ) ); } } @@ -2554,7 +2555,7 @@ void CResponseSystem::DumpRules() //----------------------------------------------------------------------------- void CResponseSystem::DumpDictionary( const char *pszName ) { - Msg( "\nDictionary: %s\n", pszName ); + CGMsg( 0, CON_GROUP_RESPONSE_SYSTEM, "\nDictionary: %s\n", pszName ); // int nRuleCount = m_Rules.Count(); // for ( int iRule = 0; iRule < nRuleCount; ++iRule ) @@ -2562,7 +2563,7 @@ void CResponseSystem::DumpDictionary( const char *pszName ) m_RulePartitions.IsValid(idx) ; idx = m_RulePartitions.Next(idx) ) { - Msg(" Rule %d/%d: %s\n", m_RulePartitions.BucketFromIdx(idx), m_RulePartitions.PartFromIdx( idx ), m_RulePartitions.GetElementName( idx ) ); + CGMsg( 0, CON_GROUP_RESPONSE_SYSTEM, " Rule %d/%d: %s\n", m_RulePartitions.BucketFromIdx( idx ), m_RulePartitions.PartFromIdx( idx ), m_RulePartitions.GetElementName( idx ) ); Rule *pRule = &m_RulePartitions[idx]; @@ -2571,7 +2572,7 @@ void CResponseSystem::DumpDictionary( const char *pszName ) { int iRuleCriteria = pRule->m_Criteria[iCriteria]; Criteria *pCriteria = &m_Criteria[iRuleCriteria]; - Msg( " Criteria %d: %s %s\n", iCriteria, CriteriaSet::SymbolToStr(pCriteria->nameSym), pCriteria->value ); + CGMsg( 0, CON_GROUP_RESPONSE_SYSTEM, " Criteria %d: %s %s\n", iCriteria, CriteriaSet::SymbolToStr( pCriteria->nameSym ), pCriteria->value ); } int nResponseGroupCount = pRule->m_Responses.Count(); @@ -2580,13 +2581,13 @@ void CResponseSystem::DumpDictionary( const char *pszName ) int iRuleResponse = pRule->m_Responses[iResponseGroup]; ResponseGroup *pResponseGroup = &m_Responses[iRuleResponse]; - Msg( " ResponseGroup %d: %s\n", iResponseGroup, m_Responses.GetElementName( iRuleResponse ) ); + CGMsg( 0, CON_GROUP_RESPONSE_SYSTEM, " ResponseGroup %d: %s\n", iResponseGroup, m_Responses.GetElementName( iRuleResponse ) ); int nResponseCount = pResponseGroup->group.Count(); for ( int iResponse = 0; iResponse < nResponseCount; ++iResponse ) { ParserResponse *pResponse = &pResponseGroup->group[iResponse]; - Msg( " Response %d: %s\n", iResponse, pResponse->value ); + CGMsg( 0, CON_GROUP_RESPONSE_SYSTEM, " Response %d: %s\n", iResponse, pResponse->value ); } } } @@ -2834,16 +2835,16 @@ static void CC_RR_Debug_ResponseConcept_Exclude( const CCommand &args ) case 1: { // print usage info - Msg("Usage: rr_debugresponseconcept_exclude Concept1 Concept2 Concept3...\n"); - Msg("\tseparate multiple concepts with spaces.\n"); - Msg("\tcall with no arguments to see this message and a list of current excludes.\n"); - Msg("\tto reset the exclude list, type \"rr_debugresponseconcept_exclude !\"\n"); + CGMsg( 0, CON_GROUP_RESPONSE_SYSTEM, "Usage: rr_debugresponseconcept_exclude Concept1 Concept2 Concept3...\n"); + CGMsg( 0, CON_GROUP_RESPONSE_SYSTEM, "\tseparate multiple concepts with spaces.\n"); + CGMsg( 0, CON_GROUP_RESPONSE_SYSTEM, "\tcall with no arguments to see this message and a list of current excludes.\n"); + CGMsg( 0, CON_GROUP_RESPONSE_SYSTEM, "\tto reset the exclude list, type \"rr_debugresponseconcept_exclude !\"\n"); // print current excludes - Msg("\nCurrent exclude list:\n"); + CGMsg( 0, CON_GROUP_RESPONSE_SYSTEM, "\nCurrent exclude list:\n" ); if ( !CResponseSystem::m_DebugExcludeList.IsValidIndex( CResponseSystem::m_DebugExcludeList.Head() ) ) { - Msg("\t\n"); + CGMsg( 0, CON_GROUP_RESPONSE_SYSTEM, "\t\n" ); } else { @@ -2852,7 +2853,7 @@ static void CC_RR_Debug_ResponseConcept_Exclude( const CCommand &args ) CResponseSystem::m_DebugExcludeList.IsValidIndex(i) ; i = CResponseSystem::m_DebugExcludeList.Next(i) ) { - Msg( "\t%s\n", CResponseSystem::m_DebugExcludeList[i].GetStringConcept() ); + CGMsg( 0, CON_GROUP_RESPONSE_SYSTEM, "\t%s\n", CResponseSystem::m_DebugExcludeList[i].GetStringConcept() ); } } return; @@ -2862,7 +2863,7 @@ static void CC_RR_Debug_ResponseConcept_Exclude( const CCommand &args ) if ( args[1][0] == '!' ) { CResponseSystem::m_DebugExcludeList.Purge(); - Msg( "Exclude list emptied.\n" ); + CGMsg( 0, CON_GROUP_RESPONSE_SYSTEM, "Exclude list emptied.\n" ); return; } // else, FALL THROUGH: @@ -2872,7 +2873,7 @@ static void CC_RR_Debug_ResponseConcept_Exclude( const CCommand &args ) { if ( !g_pRRConceptTable->Find(args[i]).IsValid() ) { - Msg( "\t'%s' is not a known concept (adding it anyway)\n", args[i] ); + CGMsg( 0, CON_GROUP_RESPONSE_SYSTEM, "\t'%s' is not a known concept (adding it anyway)\n", args[i] ); } CRR_Concept concept( args[i] ); CResponseSystem::m_DebugExcludeList.AddToTail( concept ); @@ -2906,16 +2907,16 @@ void ResponseRulePartition::PrintBucketInfo( CResponseSystem *pSys ) } nAverage /= N_RESPONSE_PARTITIONS; infos.Sort( bucktuple_t::SortCompare ); - Msg( "%d buckets, %d total, %.2f average size\n", N_RESPONSE_PARTITIONS, Count(), nAverage ); - Msg( "8 shortest buckets:\n" ); + CGMsg( 0, CON_GROUP_RESPONSE_SYSTEM, "%d buckets, %d total, %.2f average size\n", N_RESPONSE_PARTITIONS, Count(), nAverage ); + CGMsg( 0, CON_GROUP_RESPONSE_SYSTEM, "8 shortest buckets:\n" ); for ( int i = 0 ; i < 8 ; ++i ) { - Msg("\t%d: %d\n", infos[i].nBucket, infos[i].nCount ); + CGMsg( 0, CON_GROUP_RESPONSE_SYSTEM, "\t%d: %d\n", infos[i].nBucket, infos[i].nCount ); } - Msg( "8 longest buckets:\n" ); + CGMsg( 0, CON_GROUP_RESPONSE_SYSTEM, "8 longest buckets:\n" ); for ( int i = infos.Count() - 1 ; i >= infos.Count() - 9 ; --i ) { - Msg("\t%d: %d\n", infos[i].nBucket, infos[i].nCount ); + CGMsg( 0, CON_GROUP_RESPONSE_SYSTEM, "\t%d: %d\n", infos[i].nBucket, infos[i].nCount ); } int nempty = 0; for ( nempty = 0 ; nempty < infos.Count() ; ++nempty ) @@ -2923,15 +2924,15 @@ void ResponseRulePartition::PrintBucketInfo( CResponseSystem *pSys ) if ( infos[nempty].nCount != 0 ) break; } - Msg( "%d empty buckets\n", nempty ); + CGMsg( 0, CON_GROUP_RESPONSE_SYSTEM, "%d empty buckets\n", nempty ); /* - Msg( " Contents of longest bucket\nwho\tconcept\n" ); + CGMsg( 0, CON_GROUP_RESPONSE_SYSTEM, " Contents of longest bucket\nwho\tconcept\n" ); tRuleDict &bucket = m_RuleParts[infos[infos.Count()-1].nBucket]; for ( tRuleDict::IndexType_t i = bucket.FirstInorder(); bucket.IsValidIndex(i); i = bucket.NextInorder(i) ) { Rule &rule = bucket.Element(i) ; - Msg("%s\t%s\n", rule.GetValueForRuleCriterionByName( pSys, "who" ), rule.GetValueForRuleCriterionByName( pSys, CriteriaSet::ComputeCriteriaSymbol("concept") ) ); + CGMsg( 0, CON_GROUP_RESPONSE_SYSTEM, "%s\t%s\n", rule.GetValueForRuleCriterionByName( pSys, "who" ), rule.GetValueForRuleCriterionByName( pSys, CriteriaSet::ComputeCriteriaSymbol("concept") ) ); } */ } diff --git a/sp/src/responserules/runtime/response_types.cpp b/sp/src/responserules/runtime/response_types.cpp index f18d02f3..1d8f6b31 100644 --- a/sp/src/responserules/runtime/response_types.cpp +++ b/sp/src/responserules/runtime/response_types.cpp @@ -7,6 +7,8 @@ #include "rrbase.h" +#include "tier1/mapbase_con_groups.h" + // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -48,7 +50,7 @@ void Matcher::Describe( void ) { if ( !valid ) { - DevMsg( " invalid!\n" ); + CGMsg( 1, CON_GROUP_RESPONSE_SYSTEM, " invalid!\n" ); return; } char sz[ 128 ]; @@ -75,25 +77,25 @@ void Matcher::Describe( void ) if ( minmaxcount >= 1 ) { - DevMsg( " matcher: %s\n", sz ); + CGMsg( 1, CON_GROUP_RESPONSE_SYSTEM, " matcher: %s\n", sz ); return; } #ifdef MAPBASE if ( isbit ) { - DevMsg( " matcher: &%s%s\n", notequal ? "~" : "", GetToken() ); + CGMsg( 1, CON_GROUP_RESPONSE_SYSTEM, " matcher: &%s%s\n", notequal ? "~" : "", GetToken() ); return; } #endif if ( notequal ) { - DevMsg( " matcher: !=%s\n", GetToken() ); + CGMsg( 1, CON_GROUP_RESPONSE_SYSTEM, " matcher: !=%s\n", GetToken() ); return; } - DevMsg( " matcher: ==%s\n", GetToken() ); + CGMsg( 1, CON_GROUP_RESPONSE_SYSTEM, " matcher: ==%s\n", GetToken() ); } void Matcher::SetToken( char const *s ) diff --git a/sp/src/responserules/runtime/rr_response.cpp b/sp/src/responserules/runtime/rr_response.cpp index 3be0710e..b652e8b3 100644 --- a/sp/src/responserules/runtime/rr_response.cpp +++ b/sp/src/responserules/runtime/rr_response.cpp @@ -8,6 +8,7 @@ #include "rrbase.h" #include +#include "tier1/mapbase_con_groups.h" /* #include "AI_Criteria.h" @@ -151,32 +152,32 @@ void CRR_Response::Describe( const CriteriaSet *pDebugCriteria ) { if ( pDebugCriteria ) { - DevMsg( "Search criteria:\n" ); + CGMsg( 1, CON_GROUP_RESPONSE_SYSTEM, "Search criteria:\n" ); pDebugCriteria->Describe(); } if ( m_szMatchingRule[ 0 ] ) { - DevMsg( "Matched rule '%s', ", m_szMatchingRule ); + CGMsg( 1, CON_GROUP_RESPONSE_SYSTEM, "Matched rule '%s', ", m_szMatchingRule ); } if ( m_szContext ) { #ifdef MAPBASE - DevMsg( "Contexts to set '%s' on ", m_szContext ); + CGMsg( 1, CON_GROUP_RESPONSE_SYSTEM, "Contexts to set '%s' on ", m_szContext ); if (m_iContextFlags & APPLYCONTEXT_WORLD) - DevMsg( "world, " ); + CGMsg( 1, CON_GROUP_RESPONSE_SYSTEM, "world, " ); else if (m_iContextFlags & APPLYCONTEXT_SQUAD) - DevMsg( "squad, " ); + CGMsg( 1, CON_GROUP_RESPONSE_SYSTEM, "squad, " ); else if (m_iContextFlags & APPLYCONTEXT_ENEMY) - DevMsg( "enemy, " ); + CGMsg( 1, CON_GROUP_RESPONSE_SYSTEM, "enemy, " ); else - DevMsg( "speaker, " ); + CGMsg( 1, CON_GROUP_RESPONSE_SYSTEM, "speaker, " ); #else DevMsg( "Contexts to set '%s' on %s, ", m_szContext, m_bApplyContextToWorld ? "world" : "speaker" ); #endif } - DevMsg( "response %s = '%s'\n", DescribeResponse( (ResponseType_t)m_Type ), m_szResponseName ); + CGMsg( 1, CON_GROUP_RESPONSE_SYSTEM, "response %s = '%s'\n", DescribeResponse( (ResponseType_t)m_Type ), m_szResponseName ); } //----------------------------------------------------------------------------- From 4a07831c1aef209980b4d4a108df8abb5fc80997 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Thu, 22 Apr 2021 11:23:08 -0500 Subject: [PATCH 039/378] Removed some old comments --- sp/src/game/client/cdll_util.h | 1 - sp/src/game/server/mapbase/GlobalStrings.h | 10 ++-------- sp/src/public/tier0/basetypes.h | 1 - 3 files changed, 2 insertions(+), 10 deletions(-) diff --git a/sp/src/game/client/cdll_util.h b/sp/src/game/client/cdll_util.h index 44f559b0..26332551 100644 --- a/sp/src/game/client/cdll_util.h +++ b/sp/src/game/client/cdll_util.h @@ -166,7 +166,6 @@ inline bool FStrEq(const char *sz1, const char *sz2) { #ifdef MAPBASE // V_stricmp() already checks if the pointers are equal, so having a comparison here is pointless. - // I had few reasons to do this, but maybe you'll thank me later. return ( V_stricmp(sz1, sz2) == 0 ); #else return ( sz1 == sz2 || V_stricmp(sz1, sz2) == 0 ); diff --git a/sp/src/game/server/mapbase/GlobalStrings.h b/sp/src/game/server/mapbase/GlobalStrings.h index 336ff622..13c4775a 100644 --- a/sp/src/game/server/mapbase/GlobalStrings.h +++ b/sp/src/game/server/mapbase/GlobalStrings.h @@ -18,13 +18,8 @@ // Valve uses global pooled strings in various parts of the code, particularly Episodic code, // so they could get away with integer/pointer comparisons instead of string comparisons. // -// While developing Mapbase, I thought of what it would be like if that system was more uniform and more widely used. -// My OCD ended up taking me over and that thought became real, even though on today's machines these are (for the most part) micro-optimizations -// that just clutter the code. -// -// It was fun and satisfying to do this and I hope you are not judging me for my strange ways. -// I wanted to toggle them via a preprocessor so you could turn them off at will, but that just made things messier. -// I hope this doesn't cause problems for anyone. +// This system was developed early in Mapbase's development as an attempt to make this technique more widely used. +// For the most part, this mainly just serves to apply micro-optimize parts of the code. // // ------------------------------------------------------------- @@ -79,7 +74,6 @@ inline bool EntIsClass( CBaseEntity *ent, string_t str2 ) // Since classnames are pooled, the global string and the entity's classname should point to the same string in memory. // As long as this rule is preserved, we only need a pointer comparison. A string comparison isn't necessary. - // Feel free to correct me if I'm disastrously wrong. return ent->m_iClassname == str2; } diff --git a/sp/src/public/tier0/basetypes.h b/sp/src/public/tier0/basetypes.h index a6d1a1a6..9bcaf90e 100644 --- a/sp/src/public/tier0/basetypes.h +++ b/sp/src/public/tier0/basetypes.h @@ -212,7 +212,6 @@ typedef unsigned short ucs2; #endif #ifdef MAPBASE -// I'm using ThreeState_t a lot more now and I'm tired of typing this out so much. #define TO_THREESTATE(num) static_cast(num) #endif From 48508c4e5c1bfcbf149a505c546bfec9e9cc7a70 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Thu, 22 Apr 2021 11:25:49 -0500 Subject: [PATCH 040/378] Added customizable bucket names for the new response system --- .../runtime/response_types_internal.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/sp/src/responserules/runtime/response_types_internal.cpp b/sp/src/responserules/runtime/response_types_internal.cpp index fe6d7fd0..098801c4 100644 --- a/sp/src/responserules/runtime/response_types_internal.cpp +++ b/sp/src/responserules/runtime/response_types_internal.cpp @@ -6,12 +6,21 @@ //=============================================================================// #include "rrbase.h" +#ifdef MAPBASE +#include "convar.h" +#endif // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" using namespace ResponseRules; +#ifdef MAPBASE +ConVar rr_bucket_name_who( "rr_bucket_name_who", "Classname", FCVAR_NONE, "The name of the criteria to use for the 'Who' bucket." ); // Default changed to "Classname" for HL2 +ConVar rr_bucket_name_concept( "rr_bucket_name_concept", "Concept", FCVAR_NONE, "The name of the criteria to use for the 'Concept' bucket." ); +ConVar rr_bucket_name_subject( "rr_bucket_name_subject", "Subject", FCVAR_NONE, "The name of the criteria to use for the 'Subject' bucket." ); +#endif + @@ -113,9 +122,15 @@ static inline bool CanBucketBySubject( const char * RESTRICT pszSubject ) ResponseRulePartition::tRuleDict &ResponseRulePartition::GetDictForRule( CResponseSystem *pSystem, Rule *pRule ) { +#ifdef MAPBASE + const static CUtlSymbol kWHO = CriteriaSet::ComputeCriteriaSymbol( rr_bucket_name_who.GetString() ); + const static CUtlSymbol kCONCEPT = CriteriaSet::ComputeCriteriaSymbol( rr_bucket_name_concept.GetString() ); + const static CUtlSymbol kSUBJECT = CriteriaSet::ComputeCriteriaSymbol( rr_bucket_name_subject.GetString() ); +#else const static CUtlSymbol kWHO = CriteriaSet::ComputeCriteriaSymbol("Who"); const static CUtlSymbol kCONCEPT = CriteriaSet::ComputeCriteriaSymbol("Concept"); const static CUtlSymbol kSUBJECT = CriteriaSet::ComputeCriteriaSymbol("Subject"); +#endif const char *pszSpeaker = pRule->GetValueForRuleCriterionByName( pSystem, kWHO ); const char *pszConcept = pRule->GetValueForRuleCriterionByName( pSystem, kCONCEPT ); From 4cf360b2596e2cc9d63553cf74fd43adaa6b70a5 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Thu, 22 Apr 2021 11:28:24 -0500 Subject: [PATCH 041/378] Fixed zombie torso ragdolls not using the original zombie skins --- sp/src/game/server/hl2/npc_BaseZombie.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sp/src/game/server/hl2/npc_BaseZombie.cpp b/sp/src/game/server/hl2/npc_BaseZombie.cpp index bbe1f9d0..5d13c5e6 100644 --- a/sp/src/game/server/hl2/npc_BaseZombie.cpp +++ b/sp/src/game/server/hl2/npc_BaseZombie.cpp @@ -1210,6 +1210,10 @@ void CNPC_BaseZombie::DieChopped( const CTakeDamageInfo &info ) if( pAnimating ) { pAnimating->SetBodygroup( ZOMBIE_BODYGROUP_HEADCRAB, !m_fIsHeadless ); +#ifdef MAPBASE + // Inherit some animating properties + pAnimating->m_nSkin = m_nSkin; +#endif } #ifdef MAPBASE From caaf8836a42e3f2037c4e57c8f136cd624901055 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Thu, 22 Apr 2021 11:37:46 -0500 Subject: [PATCH 042/378] Made VScript data variant returned in function stubs free itself --- sp/src/vscript/vscript_squirrel.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sp/src/vscript/vscript_squirrel.cpp b/sp/src/vscript/vscript_squirrel.cpp index afb466f6..a2de0a96 100644 --- a/sp/src/vscript/vscript_squirrel.cpp +++ b/sp/src/vscript/vscript_squirrel.cpp @@ -1368,6 +1368,8 @@ SQInteger function_stub(HSQUIRRELVM vm) PushVariant(vm, retval); + retval.Free(); + return pFunc->m_desc.m_ReturnType != FIELD_VOID; } From 62a6481d0df9a7ff906b95953bce475962d48e4f Mon Sep 17 00:00:00 2001 From: Blixibon Date: Fri, 23 Apr 2021 00:17:08 -0500 Subject: [PATCH 043/378] Added default game_text speech color for every major HL2 character --- sp/src/game/server/ai_speech_new.cpp | 9 +++++++++ sp/src/game/server/baseflex.cpp | 18 +++++++++--------- sp/src/game/server/episodic/npc_magnusson.cpp | 5 +++++ sp/src/game/server/hl2/npc_alyx.h | 3 +++ sp/src/game/server/hl2/npc_alyx_episodic.h | 3 +++ sp/src/game/server/hl2/npc_barney.cpp | 5 +++++ sp/src/game/server/hl2/npc_breen.cpp | 5 +++++ sp/src/game/server/hl2/npc_eli.cpp | 5 +++++ sp/src/game/server/hl2/npc_kleiner.cpp | 5 +++++ sp/src/game/server/hl2/npc_mossman.cpp | 5 +++++ .../game/server/hl2/npc_vortigaunt_episodic.h | 5 +++++ 11 files changed, 59 insertions(+), 9 deletions(-) diff --git a/sp/src/game/server/ai_speech_new.cpp b/sp/src/game/server/ai_speech_new.cpp index 76735a9d..e886ab8f 100644 --- a/sp/src/game/server/ai_speech_new.cpp +++ b/sp/src/game/server/ai_speech_new.cpp @@ -905,6 +905,15 @@ bool CAI_Expresser::SpeakDispatchResponse( AIConcept_t &concept, AI_Response *re textParams.fadeinTime = 0.5f; textParams.fadeoutTime = 0.5f; + textParams.channel = 3; + textParams.x = -1; + textParams.y = 0.6; + textParams.effect = 0; + + textParams.r1 = 255; + textParams.g1 = 255; + textParams.b1 = 255; + if (ai_speech_print_mode.GetBool() && GetOuter()->GetGameTextSpeechParams( textParams )) { CRecipientFilter filter; diff --git a/sp/src/game/server/baseflex.cpp b/sp/src/game/server/baseflex.cpp index d908b15c..8da332cd 100644 --- a/sp/src/game/server/baseflex.cpp +++ b/sp/src/game/server/baseflex.cpp @@ -799,6 +799,15 @@ bool CBaseFlex::StartSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CCh textParams.fadeinTime = 0.5f; textParams.fadeoutTime = 0.5f; + textParams.channel = 3; + textParams.x = -1; + textParams.y = 0.6; + textParams.effect = 0; + + textParams.r1 = 255; + textParams.g1 = 255; + textParams.b1 = 255; + if ( GetGameTextSpeechParams( textParams ) ) { CRecipientFilter filter; @@ -2091,15 +2100,6 @@ float CBaseFlex::PlayAutoGeneratedSoundScene( const char *soundname ) //----------------------------------------------------------------------------- bool CBaseFlex::GetGameTextSpeechParams( hudtextparms_t ¶ms ) { - params.channel = 3; - params.x = -1; - params.y = 0.6; - params.effect = 0; - - params.r1 = 255; - params.g1 = 255; - params.b1 = 255; - ScriptVariant_t varTable; if (g_pScriptVM->GetValue(m_ScriptScope, "m_GameTextSpeechParams", &varTable) && varTable.m_type == FIELD_HSCRIPT) { diff --git a/sp/src/game/server/episodic/npc_magnusson.cpp b/sp/src/game/server/episodic/npc_magnusson.cpp index 31008353..30e1f697 100644 --- a/sp/src/game/server/episodic/npc_magnusson.cpp +++ b/sp/src/game/server/episodic/npc_magnusson.cpp @@ -37,6 +37,11 @@ public: Class_T Classify ( void ); void HandleAnimEvent( animevent_t *pEvent ); int GetSoundInterests ( void ); + +#ifdef MAPBASE + // Use Magnusson's default subtitle color (209,178,178) + bool GetGameTextSpeechParams( hudtextparms_t ¶ms ) { params.r1 = 209; params.g1 = 178; params.b1 = 178; return BaseClass::GetGameTextSpeechParams( params ); } +#endif }; LINK_ENTITY_TO_CLASS( npc_magnusson, CNPC_Magnusson ); diff --git a/sp/src/game/server/hl2/npc_alyx.h b/sp/src/game/server/hl2/npc_alyx.h index 551460b2..266dca6d 100644 --- a/sp/src/game/server/hl2/npc_alyx.h +++ b/sp/src/game/server/hl2/npc_alyx.h @@ -36,6 +36,9 @@ public: // Now that all allies can holster/unholster, this is a precaution in case it breaks anything. // Try OnFoundEnemy > UnholsterWeapon if you want Alyx to automatically unholster in non-episodic HL2 maps. bool CanUnholsterWeapon() { return false; } + + // Use Alyx's default subtitle color (255,212,255) + bool GetGameTextSpeechParams( hudtextparms_t ¶ms ) { params.r1 = 255; params.g1 = 212; params.b1 = 255; return BaseClass::GetGameTextSpeechParams( params ); } #endif EHANDLE m_hEmpTool; diff --git a/sp/src/game/server/hl2/npc_alyx_episodic.h b/sp/src/game/server/hl2/npc_alyx_episodic.h index 9e72fd8d..6d4eb67b 100644 --- a/sp/src/game/server/hl2/npc_alyx_episodic.h +++ b/sp/src/game/server/hl2/npc_alyx_episodic.h @@ -57,6 +57,9 @@ public: #ifdef MAPBASE // This skips CAI_PlayerAlly's CanFlinch() function since Episodic Alyx can flinch to begin with. virtual bool CanFlinch( void ) { return CAI_BaseActor::CanFlinch(); } + + // Use Alyx's default subtitle color (255,212,255) + bool GetGameTextSpeechParams( hudtextparms_t ¶ms ) { params.r1 = 255; params.g1 = 212; params.b1 = 255; return BaseClass::GetGameTextSpeechParams( params ); } #endif virtual float GetJumpGravity() const { return 1.8f; } diff --git a/sp/src/game/server/hl2/npc_barney.cpp b/sp/src/game/server/hl2/npc_barney.cpp index 02afce18..93ca92f0 100644 --- a/sp/src/game/server/hl2/npc_barney.cpp +++ b/sp/src/game/server/hl2/npc_barney.cpp @@ -81,6 +81,11 @@ public: void GatherConditions(); void UseFunc( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); +#ifdef MAPBASE + // Use Barney's default subtitle color (215,255,255) + bool GetGameTextSpeechParams( hudtextparms_t ¶ms ) { params.r1 = 215; params.g1 = 255; params.b1 = 255; return BaseClass::GetGameTextSpeechParams( params ); } +#endif + CAI_FuncTankBehavior m_FuncTankBehavior; COutputEvent m_OnPlayerUse; diff --git a/sp/src/game/server/hl2/npc_breen.cpp b/sp/src/game/server/hl2/npc_breen.cpp index e12bab0c..e1409c80 100644 --- a/sp/src/game/server/hl2/npc_breen.cpp +++ b/sp/src/game/server/hl2/npc_breen.cpp @@ -34,6 +34,11 @@ public: void HandleAnimEvent( animevent_t *pEvent ); int GetSoundInterests ( void ); bool UseSemaphore( void ); + +#ifdef MAPBASE + // Use Breen's default subtitle color (188,188,188) + bool GetGameTextSpeechParams( hudtextparms_t ¶ms ) { params.r1 = 188; params.g1 = 188; params.b1 = 188; return BaseClass::GetGameTextSpeechParams( params ); } +#endif }; LINK_ENTITY_TO_CLASS( npc_breen, CNPC_Breen ); diff --git a/sp/src/game/server/hl2/npc_eli.cpp b/sp/src/game/server/hl2/npc_eli.cpp index 4b42c6c0..c66e9273 100644 --- a/sp/src/game/server/hl2/npc_eli.cpp +++ b/sp/src/game/server/hl2/npc_eli.cpp @@ -37,6 +37,11 @@ public: int GetSoundInterests( void ); void SetupWithoutParent( void ); void PrescheduleThink( void ); + +#ifdef MAPBASE + // Use Eli's default subtitle color (255,208,172) + bool GetGameTextSpeechParams( hudtextparms_t ¶ms ) { params.r1 = 255; params.g1 = 208; params.b1 = 172; return BaseClass::GetGameTextSpeechParams( params ); } +#endif }; LINK_ENTITY_TO_CLASS( npc_eli, CNPC_Eli ); diff --git a/sp/src/game/server/hl2/npc_kleiner.cpp b/sp/src/game/server/hl2/npc_kleiner.cpp index e8081762..4e5e5cf8 100644 --- a/sp/src/game/server/hl2/npc_kleiner.cpp +++ b/sp/src/game/server/hl2/npc_kleiner.cpp @@ -35,6 +35,11 @@ public: Class_T Classify ( void ); void HandleAnimEvent( animevent_t *pEvent ); int GetSoundInterests ( void ); + +#ifdef MAPBASE + // Use Kleiner's default subtitle color (255,255,200) + bool GetGameTextSpeechParams( hudtextparms_t ¶ms ) { params.r1 = 255; params.g1 = 255; params.b1 = 200; return BaseClass::GetGameTextSpeechParams( params ); } +#endif }; LINK_ENTITY_TO_CLASS( npc_kleiner, CNPC_Kleiner ); diff --git a/sp/src/game/server/hl2/npc_mossman.cpp b/sp/src/game/server/hl2/npc_mossman.cpp index ff924cd2..f92a8f51 100644 --- a/sp/src/game/server/hl2/npc_mossman.cpp +++ b/sp/src/game/server/hl2/npc_mossman.cpp @@ -41,6 +41,11 @@ public: bool CreateBehaviors( void ); int SelectSchedule( void ); +#ifdef MAPBASE + // Use Mossman's default subtitle color (220,255,198) + bool GetGameTextSpeechParams( hudtextparms_t ¶ms ) { params.r1 = 220; params.g1 = 255; params.b1 = 198; return BaseClass::GetGameTextSpeechParams( params ); } +#endif + private: CAI_FollowBehavior m_FollowBehavior; }; diff --git a/sp/src/game/server/hl2/npc_vortigaunt_episodic.h b/sp/src/game/server/hl2/npc_vortigaunt_episodic.h index e0da23d3..5c281d59 100644 --- a/sp/src/game/server/hl2/npc_vortigaunt_episodic.h +++ b/sp/src/game/server/hl2/npc_vortigaunt_episodic.h @@ -138,6 +138,11 @@ public: // used so a grub can notify me that I stepped on it. Says a line. void OnSquishedGrub( const CBaseEntity *pGrub ); +#ifdef MAPBASE + // Use the vortigaunts' default subtitle color (188,241,174) + bool GetGameTextSpeechParams( hudtextparms_t ¶ms ) { params.r1 = 188; params.g1 = 241; params.b1 = 174; return BaseClass::GetGameTextSpeechParams( params ); } +#endif + private: int NumAntlionsInRadius( float flRadius ); From 591572cfda3ed0159afb4500664fa5a57c0e4333 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Fri, 23 Apr 2021 00:20:57 -0500 Subject: [PATCH 044/378] Added properly overridden projected texture shadow depth bias cvar values --- sp/src/game/client/c_env_global_light.cpp | 16 +++++++++++----- sp/src/game/client/c_env_projectedtexture.cpp | 4 ++-- sp/src/game/client/clientshadowmgr.cpp | 14 ++++++++++++++ sp/src/game/client/flashlighteffect.cpp | 4 ++-- 4 files changed, 29 insertions(+), 9 deletions(-) diff --git a/sp/src/game/client/c_env_global_light.cpp b/sp/src/game/client/c_env_global_light.cpp index c48803ae..4bbb96d2 100644 --- a/sp/src/game/client/c_env_global_light.cpp +++ b/sp/src/game/client/c_env_global_light.cpp @@ -25,6 +25,9 @@ ConVar cl_globallight_freeze( "cl_globallight_freeze", "0" ); // You can set these as KV anyway. ConVar cl_globallight_xoffset( "cl_globallight_xoffset", "0" ); ConVar cl_globallight_yoffset( "cl_globallight_yoffset", "0" ); + +static ConVar cl_globallight_slopescaledepthbias_shadowmap( "cl_globallight_slopescaledepthbias_shadowmap", "16", FCVAR_CHEAT ); +static ConVar cl_globallight_depthbias_shadowmap( "cl_globallight_depthbias_shadowmap", "0.00001", FCVAR_CHEAT ); #else ConVar cl_globallight_xoffset( "cl_globallight_xoffset", "-800" ); ConVar cl_globallight_yoffset( "cl_globallight_yoffset", "1600" ); @@ -286,16 +289,19 @@ void C_GlobalLight::ClientThink() state.m_bOrtho = false; } -#ifndef MAPBASE // Don't draw that huge debug thing +#ifdef MAPBASE + //state.m_bDrawShadowFrustum = true; // Don't draw that huge debug thing + state.m_flShadowSlopeScaleDepthBias = cl_globallight_slopescaledepthbias_shadowmap.GetFloat(); + state.m_flShadowDepthBias = cl_globallight_depthbias_shadowmap.GetFloat(); + state.m_bEnableShadows = m_bEnableShadows; + state.m_pSpotlightTexture = m_SpotlightTexture; + state.m_nSpotlightTextureFrame = m_nSpotlightTextureFrame; +#else state.m_bDrawShadowFrustum = true; -#endif /*state.m_flShadowSlopeScaleDepthBias = g_pMaterialSystemHardwareConfig->GetShadowSlopeScaleDepthBias();; state.m_flShadowDepthBias = g_pMaterialSystemHardwareConfig->GetShadowDepthBias();*/ state.m_bEnableShadows = m_bEnableShadows; state.m_pSpotlightTexture = m_SpotlightTexture; -#ifdef MAPBASE - state.m_nSpotlightTextureFrame = m_nSpotlightTextureFrame; -#else state.m_nSpotlightTextureFrame = 0; #endif diff --git a/sp/src/game/client/c_env_projectedtexture.cpp b/sp/src/game/client/c_env_projectedtexture.cpp index c78cddb2..a74bb46e 100644 --- a/sp/src/game/client/c_env_projectedtexture.cpp +++ b/sp/src/game/client/c_env_projectedtexture.cpp @@ -25,8 +25,8 @@ #include "tier0/memdbgon.h" #ifdef ASW_PROJECTED_TEXTURES -static ConVar mat_slopescaledepthbias_shadowmap( "mat_slopescaledepthbias_shadowmap", "16", FCVAR_CHEAT ); -static ConVar mat_depthbias_shadowmap( "mat_depthbias_shadowmap", "0.00001", FCVAR_CHEAT ); +extern ConVarRef mat_slopescaledepthbias_shadowmap; +extern ConVarRef mat_depthbias_shadowmap; float C_EnvProjectedTexture::m_flVisibleBBoxMinHeight = -FLT_MAX; diff --git a/sp/src/game/client/clientshadowmgr.cpp b/sp/src/game/client/clientshadowmgr.cpp index 4ac6f31e..81aa16bc 100644 --- a/sp/src/game/client/clientshadowmgr.cpp +++ b/sp/src/game/client/clientshadowmgr.cpp @@ -125,6 +125,11 @@ ConVar r_threaded_client_shadow_manager( "r_threaded_client_shadow_manager", "1" ConVar r_threaded_client_shadow_manager( "r_threaded_client_shadow_manager", "0" ); #endif +#ifdef MAPBASE +ConVarRef mat_slopescaledepthbias_shadowmap( "mat_slopescaledepthbias_shadowmap" ); +ConVarRef mat_depthbias_shadowmap( "mat_depthbias_shadowmap" ); +#endif + #ifdef _WIN32 #pragma warning( disable: 4701 ) #endif @@ -1424,6 +1429,15 @@ bool CClientShadowMgr::Init() materials->AddRestoreFunc( ShadowRestoreFunc ); +#ifdef MAPBASE + // These need to be referenced here since the cvars don't exist in the initial declaration + mat_slopescaledepthbias_shadowmap = ConVarRef( "mat_slopescaledepthbias_shadowmap" ); + mat_depthbias_shadowmap = ConVarRef( "mat_depthbias_shadowmap" ); + + mat_slopescaledepthbias_shadowmap.SetValue( "2" ); + mat_depthbias_shadowmap.SetValue( "0.00005" ); +#endif + return true; } diff --git a/sp/src/game/client/flashlighteffect.cpp b/sp/src/game/client/flashlighteffect.cpp index 6733fc56..9a4af817 100644 --- a/sp/src/game/client/flashlighteffect.cpp +++ b/sp/src/game/client/flashlighteffect.cpp @@ -52,8 +52,8 @@ static ConVar r_flashlightladderdist( "r_flashlightladderdist", "40.0", FCVAR_CH static ConVar mat_slopescaledepthbias_shadowmap( "mat_slopescaledepthbias_shadowmap", "16", FCVAR_CHEAT ); static ConVar mat_depthbias_shadowmap( "mat_depthbias_shadowmap", "0.0005", FCVAR_CHEAT ); #else -static ConVar mat_slopescaledepthbias_shadowmap( "mat_slopescaledepthbias_shadowmap", "4", FCVAR_CHEAT ); -static ConVar mat_depthbias_shadowmap( "mat_depthbias_shadowmap", "0.00001", FCVAR_CHEAT ); +extern ConVarRef mat_slopescaledepthbias_shadowmap; +extern ConVarRef mat_depthbias_shadowmap; #endif #ifdef MAPBASE static ConVar r_flashlighttextureoverride( "r_flashlighttextureoverride", "", FCVAR_CHEAT ); From ee8bee588a20bae2cc915367bb35d5296a040a27 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Fri, 23 Apr 2021 00:25:02 -0500 Subject: [PATCH 045/378] Added "Always transmit to client" flag for info_target --- sp/src/game/shared/beam_shared.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/sp/src/game/shared/beam_shared.cpp b/sp/src/game/shared/beam_shared.cpp index c3e39af8..fcefa3f9 100644 --- a/sp/src/game/shared/beam_shared.cpp +++ b/sp/src/game/shared/beam_shared.cpp @@ -42,6 +42,9 @@ public: DECLARE_CLASS( CInfoTarget, CPointEntity ); void Spawn( void ); +#ifdef MAPBASE + virtual int UpdateTransmitState(); +#endif }; //info targets are like point entities except you can force them to spawn on the client @@ -55,6 +58,19 @@ void CInfoTarget::Spawn( void ) } } +#ifdef MAPBASE +//----------------------------------------------------------------------------- +// Purpose: Always transmitted to clients +//----------------------------------------------------------------------------- +int CInfoTarget::UpdateTransmitState() +{ + // Spawn flags 2 means we always transmit + if ( HasSpawnFlags(0x02) ) + return SetTransmitState( FL_EDICT_ALWAYS ); + return BaseClass::UpdateTransmitState(); +} +#endif + LINK_ENTITY_TO_CLASS( info_target, CInfoTarget ); #endif From e5ffd26fdaa8aada5eab66218294e57c309cfa6a Mon Sep 17 00:00:00 2001 From: Blixibon Date: Fri, 23 Apr 2021 10:04:23 -0500 Subject: [PATCH 046/378] Added ability to disable console groups from the scripts --- sp/src/tier1/mapbase_con_groups.cpp | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/sp/src/tier1/mapbase_con_groups.cpp b/sp/src/tier1/mapbase_con_groups.cpp index 65bcd21d..5f23b3f8 100644 --- a/sp/src/tier1/mapbase_con_groups.cpp +++ b/sp/src/tier1/mapbase_con_groups.cpp @@ -95,8 +95,13 @@ void LoadConsoleGroupsFromFile( IBaseFileSystem *filesystem, const char *pszFile int index = FindConGroup( pGroup->GetName() ); if (index != -1) { - g_ConGroups[index]._clr = pGroup->GetColor( "MessageColor" ); - //g_ConGroups[index].bDisabled = pGroup->GetBool( "Disabled", false ); + Color msgClr = pGroup->GetColor( "MessageColor" ); + + // Make sure the color isn't 0,0,0,0 before assigning + if (msgClr.GetRawColor() != 0) + g_ConGroups[index]._clr = msgClr; + + g_ConGroups[index].bDisabled = pGroup->GetBool( "Disabled", false ); } else { @@ -118,12 +123,12 @@ void PrintAllConsoleGroups() Msg( "============================================================\n" ); for (int i = 0; i < CON_GROUP_MAX; i++) { - Msg( " # " ); - ConColorMsg( g_ConGroups[i].GetColor(), "%s", g_ConGroups[i].pszName ); - Msg( " - %s ", g_ConGroups[i].pszDescription ); + ConColorMsg( g_ConGroups[i].GetColor(), " # %s", g_ConGroups[i].pszName ); - //if (g_ConGroups[i].bDisabled) - // Msg("(DISABLED)"); + if (g_ConGroups[i].bDisabled) + Msg(" [DISABLED]"); + + Msg( " - %s ", g_ConGroups[i].pszDescription ); Msg("\n"); } From 60aacf6df77770c35c07b4a4638d97e37f3ee0cf Mon Sep 17 00:00:00 2001 From: Blixibon Date: Fri, 23 Apr 2021 10:05:06 -0500 Subject: [PATCH 047/378] Added more overridable commands for VScript --- sp/src/game/shared/mapbase/vscript_singletons.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sp/src/game/shared/mapbase/vscript_singletons.cpp b/sp/src/game/shared/mapbase/vscript_singletons.cpp index 47e26bb0..ba2f484a 100644 --- a/sp/src/game/shared/mapbase/vscript_singletons.cpp +++ b/sp/src/game/shared/mapbase/vscript_singletons.cpp @@ -2597,6 +2597,7 @@ bool CScriptConvarAccessor::Init() AddOverridable( "+grenade1" ); AddOverridable( "+grenade2" ); AddOverridable( "+showscores" ); + AddOverridable( "+voicerecord" ); AddOverridable( "-attack" ); AddOverridable( "-attack2" ); @@ -2618,12 +2619,16 @@ bool CScriptConvarAccessor::Init() AddOverridable( "-grenade1" ); AddOverridable( "-grenade2" ); AddOverridable( "-showscores" ); + AddOverridable( "-voicerecord" ); AddOverridable( "toggle_duck" ); AddOverridable( "lastinv" ); AddOverridable( "invnext" ); AddOverridable( "invprev" ); AddOverridable( "phys_swap" ); + AddOverridable( "say" ); + AddOverridable( "say_team" ); + AddOverridable( "slot0" ); AddOverridable( "slot1" ); AddOverridable( "slot2" ); AddOverridable( "slot3" ); @@ -2631,6 +2636,9 @@ bool CScriptConvarAccessor::Init() AddOverridable( "slot5" ); AddOverridable( "slot6" ); AddOverridable( "slot7" ); + AddOverridable( "slot8" ); + AddOverridable( "slot9" ); + AddOverridable( "slot10" ); AddOverridable( "save" ); AddOverridable( "load" ); From 69fa4a00647c66fc48fed6ce9408a500378db40c Mon Sep 17 00:00:00 2001 From: Blixibon Date: Fri, 23 Apr 2021 10:21:40 -0500 Subject: [PATCH 048/378] Fixed SetBloomScaleRange's syntax bug (although it seems the feature itself remains unfinished) --- sp/src/game/server/env_tonemap_controller.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sp/src/game/server/env_tonemap_controller.cpp b/sp/src/game/server/env_tonemap_controller.cpp index 39998e4b..bfd4f5a2 100644 --- a/sp/src/game/server/env_tonemap_controller.cpp +++ b/sp/src/game/server/env_tonemap_controller.cpp @@ -189,7 +189,7 @@ void CEnvTonemapController::InputBlendTonemapScale( inputdata_t &inputdata ) void CEnvTonemapController::InputSetBloomScaleRange( inputdata_t &inputdata ) { float bloom_max=1, bloom_min=1; - int nargs=sscanf("%f %f",inputdata.value.String(), bloom_max, bloom_min ); + int nargs=sscanf( inputdata.value.String(), "%f %f", &bloom_max, &bloom_min ); if (nargs != 2) { Warning("%s (%s) received SetBloomScaleRange input without 2 arguments. Syntax: \n", GetClassname(), GetDebugName() ); @@ -197,6 +197,9 @@ void CEnvTonemapController::InputSetBloomScaleRange( inputdata_t &inputdata ) } m_flCustomBloomScale=bloom_max; m_flCustomBloomScaleMinimum=bloom_min; +#ifdef MAPBASE + m_bUseCustomBloomScale = true; +#endif } //----------------------------------------------------------------------------- From bb030629bbee197012fe503d60e61aefffb28a53 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Fri, 23 Apr 2021 10:23:53 -0500 Subject: [PATCH 049/378] Misc. shader adjustments --- sp/src/materialsystem/stdshaders/SDK_teeth_bump_vs20.fxc | 9 ++++----- .../stdshaders/SDK_windowimposter_ps2x.fxc | 8 ++++---- .../stdshaders/SDK_windowimposter_vs20.fxc | 8 ++++---- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/sp/src/materialsystem/stdshaders/SDK_teeth_bump_vs20.fxc b/sp/src/materialsystem/stdshaders/SDK_teeth_bump_vs20.fxc index 1dd834b5..ddca526a 100644 --- a/sp/src/materialsystem/stdshaders/SDK_teeth_bump_vs20.fxc +++ b/sp/src/materialsystem/stdshaders/SDK_teeth_bump_vs20.fxc @@ -55,7 +55,7 @@ struct VS_INPUT struct VS_OUTPUT { float4 projPos : POSITION; -#if !defined( _X360 ) +#if !defined( _X360 ) && !defined( SHADER_MODEL_VS_3_0 ) && !INTRO float fog : FOG; #endif float2 baseTexCoord : TEXCOORD0; @@ -105,10 +105,9 @@ VS_OUTPUT main( const VS_INPUT v ) o.projPos = vProjPos; vProjPos.z = dot( float4( worldPos, 1 ), cViewProjZ ); - o.worldPos_projPosZ = float4( worldPos, vProjPos.z ); -#if !defined( _X360 ) - // Set fixed-function fog factor - o.fog = CalcFog( worldPos, vProjPos, g_FogType ); + o.worldPos_projPosZ = float4( worldPos.xyz, vProjPos.z ); +#if !defined( _X360 )&& !defined( SHADER_MODEL_VS_3_0 ) && !INTRO + o.fog = CalcFixedFunctionFog( worldPos, g_FogType ); #endif // Needed for specular o.worldVertToEyeVector_Darkening.xyz = cEyePos - worldPos; diff --git a/sp/src/materialsystem/stdshaders/SDK_windowimposter_ps2x.fxc b/sp/src/materialsystem/stdshaders/SDK_windowimposter_ps2x.fxc index fc3ea25a..8863683e 100644 --- a/sp/src/materialsystem/stdshaders/SDK_windowimposter_ps2x.fxc +++ b/sp/src/materialsystem/stdshaders/SDK_windowimposter_ps2x.fxc @@ -24,11 +24,11 @@ struct PS_INPUT float3 eyeToVertVector : TEXCOORD0; float4 vertexColor : COLOR; -#if PARALLAXCORRECT - float3 worldSpaceNormal : TEXCOORD1; -#endif + float4 worldPos_projPosZ : TEXCOORD1; // Necessary for pixel fog - float4 worldPos_projPosZ : TEXCOORD2; // Necessary for pixel fog +#if PARALLAXCORRECT + float3 worldSpaceNormal : TEXCOORD2; +#endif }; float4 main( PS_INPUT i ) : COLOR diff --git a/sp/src/materialsystem/stdshaders/SDK_windowimposter_vs20.fxc b/sp/src/materialsystem/stdshaders/SDK_windowimposter_vs20.fxc index f67676ee..3a6a9334 100644 --- a/sp/src/materialsystem/stdshaders/SDK_windowimposter_vs20.fxc +++ b/sp/src/materialsystem/stdshaders/SDK_windowimposter_vs20.fxc @@ -28,11 +28,11 @@ struct VS_OUTPUT float3 eyeToVertVector : TEXCOORD0; float4 vertexColor : COLOR; -#if PARALLAXCORRECT - float3 worldNormal : TEXCOORD1; -#endif + float4 worldPos_projPosZ : TEXCOORD1; // Necessary for pixel fog - float4 worldPos_projPosZ : TEXCOORD2; // Necessary for pixel fog +#if PARALLAXCORRECT + float3 worldNormal : TEXCOORD2; +#endif }; VS_OUTPUT main( const VS_INPUT v ) From 46b6f456af6d63895d31ae21464212c88af4139c Mon Sep 17 00:00:00 2001 From: Blixibon Date: Fri, 23 Apr 2021 10:33:42 -0500 Subject: [PATCH 050/378] Updated README and mapbase_version for v7.0 --- README | 14 ++++++++++++-- sp/src/game/shared/mapbase/mapbase_shared.cpp | 2 +- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/README b/README index 12ecc545..bf8b01e1 100644 --- a/README +++ b/README @@ -20,6 +20,9 @@ Mapbase's main content in this repository may include: - View rendering changes for drawing 3D skyboxes and RT-based entities - Countless other fixes and improvements +For more information, view this page: +https://github.com/mapbase-source/source-sdk-2013/wiki/Introduction-to-Mapbase + //=================================================================================================================================================== Mapbase is an open-source project and its contents can be distributed and used at the discretion of its users. However, this project represents many parts of @@ -37,7 +40,7 @@ and repositories (especially ones which are specifically published as free sourc or complicated code changes accessible and easy to use for level designers and other kinds of Source modders who would otherwise have no idea how to implement them. *** DISCLAIMER: Mapbase has a strict no-leak-content policy and only allows content created directly by contributors or content originating from open-source repositories. -If you believe any content in Mapbase originates from any leak or unauthorized source (from Valve or otherwise), please contact Blixibon immediately. +If you believe any content in Mapbase originates from any leak or unauthorized source (Valve or otherwise), please contact Blixibon immediately. Mapbase is intended to be usable by everyone, including licensed Source projects and Steam mods. *** -- The Alien Swarm SDK was used to backport features and code from newer branches of Source into a Source 2013/Half-Life 2 environment. @@ -91,7 +94,6 @@ Direct contributions: - https://github.com/mapbase-source/source-sdk-2013/pull/5 (Custom VScript implementation by ReDucTor; was placed into feature branch before being merged in a subsequent PR) - https://github.com/mapbase-source/source-sdk-2013/pull/3 ("playvideo" command playback fix from Avantate) -- https://github.com/mapbase-source/source-sdk-2013/pull/21 (Various GCC/Linux fixes from z33ky) - https://github.com/mapbase-source/source-sdk-2013/pull/60 (Adjustment by RoyaleNoir to one of Saul's VDC changes) - https://github.com/mapbase-source/source-sdk-2013/pull/84 (CS:S viewmodel chirality from 1upD) - Demo autorecord code provided by Klems @@ -108,6 +110,10 @@ Direct contributions: =-- https://github.com/mapbase-source/source-sdk-2013/pull/80 (More VScript changes, including support for extremely flexible client/server messaging) =-- https://github.com/mapbase-source/source-sdk-2013/pull/105 (VScript fixes and optimizations, Vector class extensions, custom convars/commands) +== Contributions from z33ky: +=-- https://github.com/mapbase-source/source-sdk-2013/pull/21 (Various GCC/Linux compilation fixes) +=-- https://github.com/mapbase-source/source-sdk-2013/pull/95 (Additional GCC/Linux compilation fixes) + //--------------------------------------------------------------------------------------------------------------------------------------------------- Other sources: @@ -135,6 +141,10 @@ If there is anything missing from this list, please contact Blixibon. Aside from the content list above, Mapbase has more descriptive and up-to-date credits on this wiki article: https://github.com/mapbase-source/source-sdk-2013/wiki/Mapbase-Credits +Other relevant articles: +* https://github.com/mapbase-source/source-sdk-2013/wiki/Mapbase-Disclaimers +* https://github.com/mapbase-source/source-sdk-2013/wiki/Frequently-Asked-Questions-(FAQ) + //=================================================================================================================================================== Please see the Source SDK 2013 license below: diff --git a/sp/src/game/shared/mapbase/mapbase_shared.cpp b/sp/src/game/shared/mapbase/mapbase_shared.cpp index e93add3c..05872b4e 100644 --- a/sp/src/game/shared/mapbase/mapbase_shared.cpp +++ b/sp/src/game/shared/mapbase/mapbase_shared.cpp @@ -72,7 +72,7 @@ ConVar mapbase_load_actbusy("mapbase_load_actbusy", "1", FCVAR_ARCHIVE, "Should #ifdef GAME_DLL // This cvar should change with each Mapbase update -ConVar mapbase_version( "mapbase_version", "6.3", FCVAR_NONE, "The version of Mapbase currently being used in this mod." ); +ConVar mapbase_version( "mapbase_version", "7.0", FCVAR_NONE, "The version of Mapbase currently being used in this mod." ); extern void MapbaseGameLog_Init(); From 2a24e9782cac96b8c2ff9d6c940622c1cfab7a55 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Fri, 23 Apr 2021 22:52:17 -0500 Subject: [PATCH 051/378] Removed duplicate custom command overridables --- sp/src/game/shared/mapbase/vscript_singletons.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/sp/src/game/shared/mapbase/vscript_singletons.cpp b/sp/src/game/shared/mapbase/vscript_singletons.cpp index 874645e1..a39ac570 100644 --- a/sp/src/game/shared/mapbase/vscript_singletons.cpp +++ b/sp/src/game/shared/mapbase/vscript_singletons.cpp @@ -2691,8 +2691,6 @@ bool CScriptConvarAccessor::Init() AddOverridable( "invnext" ); AddOverridable( "invprev" ); AddOverridable( "phys_swap" ); - AddOverridable( "say" ); - AddOverridable( "say_team" ); AddOverridable( "slot0" ); AddOverridable( "slot1" ); AddOverridable( "slot2" ); From 200001fdb9aa830079c421caabd3d2b5fdfef2fb Mon Sep 17 00:00:00 2001 From: Blixibon Date: Fri, 23 Apr 2021 22:54:20 -0500 Subject: [PATCH 052/378] Fixed a couple obscure crashes --- sp/src/game/server/hl2/npc_metropolice.cpp | 5 +++++ sp/src/game/server/physics_prop_ragdoll.cpp | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/sp/src/game/server/hl2/npc_metropolice.cpp b/sp/src/game/server/hl2/npc_metropolice.cpp index 3efb9741..bf56dc78 100644 --- a/sp/src/game/server/hl2/npc_metropolice.cpp +++ b/sp/src/game/server/hl2/npc_metropolice.cpp @@ -1626,6 +1626,11 @@ bool CNPC_MetroPolice::ShouldAttemptToStitch() //----------------------------------------------------------------------------- Vector CNPC_MetroPolice::StitchAimTarget( const Vector &posSrc, bool bNoisy ) { +#ifdef MAPBASE + if ( !GetEnemy() ) + return vec3_origin; +#endif + // This will make us aim a stitch at the feet of the player so we can see it if ( !GetEnemy()->IsPlayer() ) return GetShootTarget()->BodyTarget( posSrc, bNoisy ); diff --git a/sp/src/game/server/physics_prop_ragdoll.cpp b/sp/src/game/server/physics_prop_ragdoll.cpp index f417175f..3295c1b9 100644 --- a/sp/src/game/server/physics_prop_ragdoll.cpp +++ b/sp/src/game/server/physics_prop_ragdoll.cpp @@ -1363,7 +1363,7 @@ CBaseAnimating *CreateServerRagdollSubmodel( CBaseAnimating *pOwner, const char #ifdef MAPBASE_VSCRIPT // Hook for pre-spawn ragdolling - if (pOwner->m_ScriptScope.IsInitialized() && CBaseAnimating::g_Hook_OnServerRagdoll.CanRunInScope( pOwner->m_ScriptScope )) + if (pOwner && pOwner->m_ScriptScope.IsInitialized() && CBaseAnimating::g_Hook_OnServerRagdoll.CanRunInScope( pOwner->m_ScriptScope )) { // ragdoll, submodel ScriptVariant_t args[] = { ScriptVariant_t( pRagdoll->GetScriptInstance() ), true }; From 45ca64863a2fe010e1299114786e4f590f5a1b26 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Fri, 23 Apr 2021 22:55:52 -0500 Subject: [PATCH 053/378] Increased ragdoll element limit from 24 to 32, reflecting later branches of Source --- sp/src/game/client/ragdoll.cpp | 10 ++++++++++ sp/src/game/server/physics_prop_ragdoll.cpp | 12 ++++++++++++ sp/src/game/shared/ragdoll_shared.h | 4 ++++ 3 files changed, 26 insertions(+) diff --git a/sp/src/game/client/ragdoll.cpp b/sp/src/game/client/ragdoll.cpp index 3457b054..0fc3d0e0 100644 --- a/sp/src/game/client/ragdoll.cpp +++ b/sp/src/game/client/ragdoll.cpp @@ -69,6 +69,16 @@ BEGIN_SIMPLE_DATADESC( CRagdoll ) DEFINE_RAGDOLL_ELEMENT( 21 ), DEFINE_RAGDOLL_ELEMENT( 22 ), DEFINE_RAGDOLL_ELEMENT( 23 ), +#ifdef MAPBASE + DEFINE_RAGDOLL_ELEMENT( 24 ), + DEFINE_RAGDOLL_ELEMENT( 25 ), + DEFINE_RAGDOLL_ELEMENT( 26 ), + DEFINE_RAGDOLL_ELEMENT( 27 ), + DEFINE_RAGDOLL_ELEMENT( 28 ), + DEFINE_RAGDOLL_ELEMENT( 29 ), + DEFINE_RAGDOLL_ELEMENT( 30 ), + DEFINE_RAGDOLL_ELEMENT( 31 ), +#endif END_DATADESC() diff --git a/sp/src/game/server/physics_prop_ragdoll.cpp b/sp/src/game/server/physics_prop_ragdoll.cpp index 3295c1b9..93efddc7 100644 --- a/sp/src/game/server/physics_prop_ragdoll.cpp +++ b/sp/src/game/server/physics_prop_ragdoll.cpp @@ -159,6 +159,16 @@ BEGIN_DATADESC(CRagdollProp) DEFINE_RAGDOLL_ELEMENT( 21 ), DEFINE_RAGDOLL_ELEMENT( 22 ), DEFINE_RAGDOLL_ELEMENT( 23 ), +#ifdef MAPBASE + DEFINE_RAGDOLL_ELEMENT( 24 ), + DEFINE_RAGDOLL_ELEMENT( 25 ), + DEFINE_RAGDOLL_ELEMENT( 26 ), + DEFINE_RAGDOLL_ELEMENT( 27 ), + DEFINE_RAGDOLL_ELEMENT( 28 ), + DEFINE_RAGDOLL_ELEMENT( 29 ), + DEFINE_RAGDOLL_ELEMENT( 30 ), + DEFINE_RAGDOLL_ELEMENT( 31 ), +#endif END_DATADESC() @@ -191,8 +201,10 @@ void CRagdollProp::Spawn( void ) // Starts out as the default fade scale value m_flDefaultFadeScale = m_flFadeScale; +#ifndef MAPBASE // NOTE: If this fires, then the assert or the datadesc is wrong! (see DEFINE_RAGDOLL_ELEMENT above) Assert( RAGDOLL_MAX_ELEMENTS == 24 ); +#endif Precache(); SetModel( STRING( GetModelName() ) ); diff --git a/sp/src/game/shared/ragdoll_shared.h b/sp/src/game/shared/ragdoll_shared.h index f230e99f..758f4719 100644 --- a/sp/src/game/shared/ragdoll_shared.h +++ b/sp/src/game/shared/ragdoll_shared.h @@ -27,7 +27,11 @@ class CBoneAccessor; #include "bone_accessor.h" // UNDONE: Remove and make dynamic? +#ifdef MAPBASE +#define RAGDOLL_MAX_ELEMENTS 32 // Mapbase boosts this limit to the level of later Source games. +#else #define RAGDOLL_MAX_ELEMENTS 24 +#endif #define RAGDOLL_INDEX_BITS 5 // NOTE 1<= RAGDOLL_MAX_ELEMENTS #define CORE_DISSOLVE_FADE_START 0.2f From 425057453bb3d4b13fd32fd012bcd526a294b44a Mon Sep 17 00:00:00 2001 From: Blixibon Date: Fri, 23 Apr 2021 22:57:11 -0500 Subject: [PATCH 054/378] Fixed an issue with the ForceThisNPCToStopBusy input which caused NPCs to keep acting busy when they shouldn't --- sp/src/game/server/hl2/ai_behavior_actbusy.cpp | 11 +++++++++-- sp/src/game/server/hl2/ai_behavior_actbusy.h | 4 ++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/sp/src/game/server/hl2/ai_behavior_actbusy.cpp b/sp/src/game/server/hl2/ai_behavior_actbusy.cpp index 288e93a0..c5ad733d 100644 --- a/sp/src/game/server/hl2/ai_behavior_actbusy.cpp +++ b/sp/src/game/server/hl2/ai_behavior_actbusy.cpp @@ -2742,8 +2742,15 @@ void CAI_ActBusyGoal::InputForceThisNPCToStopBusy( inputdata_t &inputdata ) if ( !pBehavior ) return; - // Just stop busying - pBehavior->StopBusying(); + if (!IsActive() && pBehavior->GetActBusyGoal() == this) + { + pBehavior->Disable(); + } + else + { + // Just stop busying + pBehavior->StopBusying(); + } } #endif diff --git a/sp/src/game/server/hl2/ai_behavior_actbusy.h b/sp/src/game/server/hl2/ai_behavior_actbusy.h index a33dd438..264fdb3d 100644 --- a/sp/src/game/server/hl2/ai_behavior_actbusy.h +++ b/sp/src/game/server/hl2/ai_behavior_actbusy.h @@ -153,6 +153,10 @@ public: bool IsInSafeZone( CBaseEntity *pEntity ); int CountEnemiesInSafeZone(); +#ifdef MAPBASE + CAI_ActBusyGoal *GetActBusyGoal() const { return m_hActBusyGoal; } +#endif + private: virtual int SelectSchedule( void ); int SelectScheduleForLeaving( void ); From 7f423759d52574853612b9b4ffac87370227af7f Mon Sep 17 00:00:00 2001 From: Blixibon Date: Fri, 23 Apr 2021 22:58:16 -0500 Subject: [PATCH 055/378] Added new and experimental clientside worldlight iteration method --- sp/src/game/client/worldlight.cpp | 188 +++++++++++++++++++++++++++++- sp/src/game/client/worldlight.h | 15 +++ 2 files changed, 199 insertions(+), 4 deletions(-) diff --git a/sp/src/game/client/worldlight.cpp b/sp/src/game/client/worldlight.cpp index 66488b11..29e383a7 100644 --- a/sp/src/game/client/worldlight.cpp +++ b/sp/src/game/client/worldlight.cpp @@ -27,6 +27,10 @@ static IVEngineServer *g_pEngineServer = NULL; +#ifdef MAPBASE +ConVar cl_worldlight_use_new_method("cl_worldlight_use_new_method", "1", FCVAR_NONE, "Uses the new world light iteration method which splits lights into multiple lists for each cluster."); +#endif + //----------------------------------------------------------------------------- // Singleton exposure //----------------------------------------------------------------------------- @@ -192,6 +196,83 @@ void CWorldLights::LevelInitPreEntity() g_pFullFileSystem->Close(hFile); DevMsg("CWorldLights: load successful (%d lights at 0x%p)\n", m_nWorldLights, m_pWorldLights); + +#ifdef MAPBASE + // Now that the lights have been gathered, begin separating them into lists for each PVS cluster. + // This code is adapted from the soundscape cluster list code (see soundscape_system.cpp) and is intended to + // reduce frame drops in large maps which use dynamic RTT shadow angles. + CUtlVector clusterbounds; + int clusterCount = g_pEngineServer->GetClusterCount(); + clusterbounds.SetCount( clusterCount ); + g_pEngineServer->GetAllClusterBounds( clusterbounds.Base(), clusterCount ); + m_WorldLightsInCluster.SetCount(clusterCount); + for ( int i = 0; i < clusterCount; i++ ) + { + m_WorldLightsInCluster[i].lightCount = 0; + m_WorldLightsInCluster[i].firstLight = 0; + } + unsigned char myPVS[16 * 1024]; + CUtlVector clusterIndexList; + CUtlVector lightIndexList; + + // Find the clusters visible from each light, then add it to those clusters' light lists + // (Also try to clip for radius if possible) + for (int i = 0; i < m_nWorldLights; ++i) + { + dworldlight_t *light = &m_pWorldLights[i]; + + // Assign the sun to its own pointer + if (light->type == emit_skylight) + { + m_iSunIndex = i; + continue; + } + + float radiusSq = light->radius * light->radius; + if (radiusSq == 0.0f) + { + // TODO: Use intensity instead? + radiusSq = FLT_MAX; + } + + g_pEngineServer->GetPVSForCluster( light->cluster, sizeof( myPVS ), myPVS ); + for ( int j = 0; j < clusterCount; j++ ) + { + if ( myPVS[ j >> 3 ] & (1<<(j&7)) ) + { + float distSq = CalcSqrDistanceToAABB( clusterbounds[j].mins, clusterbounds[j].maxs, light->origin ); + if ( distSq < radiusSq ) + { + m_WorldLightsInCluster[j].lightCount++; + clusterIndexList.AddToTail(j); + lightIndexList.AddToTail(i); + } + } + } + } + + m_WorldLightsIndexList.SetCount(lightIndexList.Count()); + + // Compute the starting index of each cluster + int firstLight = 0; + for ( int i = 0; i < clusterCount; i++ ) + { + m_WorldLightsInCluster[i].firstLight = firstLight; + firstLight += m_WorldLightsInCluster[i].lightCount; + m_WorldLightsInCluster[i].lightCount = 0; + } + + // Now add each light index to the appropriate cluster's list + for ( int i = 0; i < lightIndexList.Count(); i++ ) + { + int cluster = clusterIndexList[i]; + int outIndex = m_WorldLightsInCluster[cluster].lightCount + m_WorldLightsInCluster[cluster].firstLight; + m_WorldLightsInCluster[cluster].lightCount++; + m_WorldLightsIndexList[outIndex] = lightIndexList[i]; + } + + //DevMsg( "CWorldLights: Light clusters list has %i elements; Light index list has %i\n", m_WorldLightsInCluster.Count(), m_WorldLightsIndexList.Count() ); +#endif } //----------------------------------------------------------------------------- @@ -208,6 +289,25 @@ bool CWorldLights::GetBrightestLightSource(const Vector &vecPosition, Vector &ve // Find the size of the PVS for our current position int nCluster = g_pEngineServer->GetClusterForOrigin(vecPosition); + +#ifdef MAPBASE + if (cl_worldlight_use_new_method.GetBool()) + { + FindBrightestLightSourceNew( vecPosition, vecLightPos, vecLightBrightness, nCluster ); + } + else +#endif + { + FindBrightestLightSourceOld( vecPosition, vecLightPos, vecLightBrightness, nCluster ); + } + + //engine->Con_NPrintf(m_nWorldLights, "result: %d", !vecLightBrightness.IsZero()); + return !vecLightBrightness.IsZero(); +} + +void CWorldLights::FindBrightestLightSourceOld( const Vector &vecPosition, Vector &vecLightPos, Vector &vecLightBrightness, int nCluster ) +{ + // Find the size of the PVS for our current position int nPVSSize = g_pEngineServer->GetPVSForCluster(nCluster, 0, NULL); // Get the PVS at our position @@ -257,7 +357,7 @@ bool CWorldLights::GetBrightestLightSource(const Vector &vecPosition, Vector &ve delete[] pvs; - return false; + return; } // Calculate square distance to this worldlight @@ -308,7 +408,87 @@ bool CWorldLights::GetBrightestLightSource(const Vector &vecPosition, Vector &ve } delete[] pvs; +} - //engine->Con_NPrintf(m_nWorldLights, "result: %d", !vecLightBrightness.IsZero()); - return !vecLightBrightness.IsZero(); -} +#ifdef MAPBASE +void CWorldLights::FindBrightestLightSourceNew( const Vector &vecPosition, Vector &vecLightPos, Vector &vecLightBrightness, int nCluster ) +{ + // Handle sun + if (m_iSunIndex != -1) + { + dworldlight_t *light = &m_pWorldLights[m_iSunIndex]; + + // Calculate sun position + Vector vecAbsStart = vecPosition + Vector(0,0,30); + Vector vecAbsEnd = vecAbsStart - (light->normal * MAX_TRACE_LENGTH); + + trace_t tr; + UTIL_TraceLine(vecPosition, vecAbsEnd, MASK_OPAQUE, NULL, COLLISION_GROUP_NONE, &tr); + + // If we didn't hit anything then we have a problem + if(tr.DidHit()) + { + // If we did hit something, and it wasn't the skybox, then skip + // this worldlight + if((tr.surface.flags & SURF_SKY) && (tr.surface.flags & SURF_SKY2D)) + { + // Act like we didn't find any valid worldlights, so the shadow + // manager uses the default shadow direction instead (should be the + // sun direction) + + return; + } + } + } + + // Iterate through all the worldlights + if ( nCluster >= 0 && nCluster < m_WorldLightsInCluster.Count() ) + { + // find all soundscapes that could possibly attach to this player and update them + for ( int j = 0; j < m_WorldLightsInCluster[nCluster].lightCount; j++ ) + { + int ssIndex = m_WorldLightsIndexList[m_WorldLightsInCluster[nCluster].firstLight + j]; + dworldlight_t *light = &m_pWorldLights[ssIndex]; + + // Calculate square distance to this worldlight + Vector vecDelta = light->origin - vecPosition; + float flDistSqr = vecDelta.LengthSqr(); + float flRadiusSqr = light->radius * light->radius; + + // Skip lights that are out of our radius + if(flRadiusSqr > 0 && flDistSqr >= flRadiusSqr) + { + //engine->Con_NPrintf(i, "%d: out-of-radius (dist: %d, radius: %d)", i, sqrt(flDistSqr), light->radius); + continue; + } + + // Calculate intensity at our position + float flRatio = Engine_WorldLightDistanceFalloff(light, vecDelta); + Vector vecIntensity = light->intensity * flRatio; + + // Is this light more intense than the one we already found? + if(vecIntensity.LengthSqr() <= vecLightBrightness.LengthSqr()) + { + //engine->Con_NPrintf(i, "%d: too dim", i); + continue; + } + + // Can we see the light? + trace_t tr; + Vector vecAbsStart = vecPosition + Vector(0,0,30); + UTIL_TraceLine(vecAbsStart, light->origin, MASK_OPAQUE, NULL, COLLISION_GROUP_NONE, &tr); + + if(tr.DidHit()) + { + //engine->Con_NPrintf(i, "%d: trace failed", i); + continue; + } + + vecLightPos = light->origin; + vecLightBrightness = vecIntensity; + + //engine->Con_NPrintf(i, "%d: set (%.2f)", i, vecIntensity.Length()); + } + } +} +#endif diff --git a/sp/src/game/client/worldlight.h b/sp/src/game/client/worldlight.h index 65a13ea7..b621ce1f 100644 --- a/sp/src/game/client/worldlight.h +++ b/sp/src/game/client/worldlight.h @@ -27,7 +27,9 @@ public: // Find the brightest light source at a point //------------------------------------------------------------------------- bool GetBrightestLightSource(const Vector &vecPosition, Vector &vecLightPos, Vector &vecLightBrightness); + void FindBrightestLightSourceOld( const Vector &vecPosition, Vector &vecLightPos, Vector &vecLightBrightness, int nCluster ); #ifdef MAPBASE + void FindBrightestLightSourceNew(const Vector &vecPosition, Vector &vecLightPos, Vector &vecLightBrightness, int nCluster); bool GetCumulativeLightSource(const Vector &vecPosition, Vector &vecLightPos, float flMinBrightnessSqr); #endif @@ -42,6 +44,19 @@ private: int m_nWorldLights; dworldlight_t *m_pWorldLights; + +#ifdef MAPBASE + int m_iSunIndex = -1; // The sun's personal index + + struct clusterLightList_t + { + unsigned short lightCount; + unsigned short firstLight; + }; + + CUtlVector m_WorldLightsInCluster; + CUtlVector m_WorldLightsIndexList; +#endif }; //----------------------------------------------------------------------------- From a92ca7ceacbd71341aa8a94dee712be243625dcc Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sat, 24 Apr 2021 11:44:51 -0500 Subject: [PATCH 056/378] Added weakref() and getclass() for Vector and other C++ instances in VScript --- sp/src/vscript/vscript_squirrel.cpp | 36 +++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/sp/src/vscript/vscript_squirrel.cpp b/sp/src/vscript/vscript_squirrel.cpp index 79160a49..b1e250b1 100644 --- a/sp/src/vscript/vscript_squirrel.cpp +++ b/sp/src/vscript/vscript_squirrel.cpp @@ -495,6 +495,19 @@ namespace SQVector return 1; } + SQInteger weakref(HSQUIRRELVM vm) + { + sq_weakref(vm, 1); + return 1; + } + + SQInteger getclass(HSQUIRRELVM vm) + { + sq_getclass(vm, 1); + sq_push(vm, -1); + return 1; + } + // multi purpose - copy from input vector, or init with 3 float input SQInteger Set(HSQUIRRELVM vm) { @@ -985,6 +998,8 @@ namespace SQVector {_SC("_mul"), _multiply, 2, _SC("..")}, {_SC("_div"), _divide, 2, _SC("..")}, {_SC("_unm"), _unm, 1, _SC(".")}, + {_SC("weakref"), weakref, 1, _SC(".")}, + {_SC("getclass"), getclass, 1, _SC(".")}, {_SC("Set"), Set, -2, _SC("..nn")}, {_SC("Add"), Add, 2, _SC("..")}, {_SC("Subtract"), Subtract, 2, _SC("..")}, @@ -1648,6 +1663,19 @@ SQInteger IsValid_stub(HSQUIRRELVM vm) return 1; } +SQInteger weakref_stub(HSQUIRRELVM vm) +{ + sq_weakref(vm, 1); + return 1; +} + +SQInteger getclass_stub(HSQUIRRELVM vm) +{ + sq_getclass(vm, 1); + sq_push(vm, -1); + return 1; +} + struct SquirrelSafeCheck { SquirrelSafeCheck(HSQUIRRELVM vm, int outputCount = 0) : @@ -2390,6 +2418,14 @@ bool SquirrelVM::RegisterClass(ScriptClassDesc_t* pClassDesc) sq_newclosure(vm_, IsValid_stub, 0); sq_newslot(vm_, -3, SQFalse); + sq_pushstring(vm_, "weakref", -1); + sq_newclosure(vm_, weakref_stub, 0); + sq_newslot(vm_, -3, SQFalse); + + sq_pushstring(vm_, "getclass", -1); + sq_newclosure(vm_, getclass_stub, 0); + sq_newslot(vm_, -3, SQFalse); + for (int i = 0; i < pClassDesc->m_FunctionBindings.Count(); ++i) { From 5eda2f692f2dfeb82cbe0045371ae06f7576410b Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sat, 24 Apr 2021 11:47:41 -0500 Subject: [PATCH 057/378] Had to change mat_slopescaledepthbias_shadowmap back to 16 due to issues with objects like citizens looking strange up close --- sp/src/game/client/clientshadowmgr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sp/src/game/client/clientshadowmgr.cpp b/sp/src/game/client/clientshadowmgr.cpp index 81aa16bc..9dc2a5fe 100644 --- a/sp/src/game/client/clientshadowmgr.cpp +++ b/sp/src/game/client/clientshadowmgr.cpp @@ -1434,7 +1434,7 @@ bool CClientShadowMgr::Init() mat_slopescaledepthbias_shadowmap = ConVarRef( "mat_slopescaledepthbias_shadowmap" ); mat_depthbias_shadowmap = ConVarRef( "mat_depthbias_shadowmap" ); - mat_slopescaledepthbias_shadowmap.SetValue( "2" ); + mat_slopescaledepthbias_shadowmap.SetValue( "16" ); // Would do something like 2 here, but it causes citizens to look weird under flashlights mat_depthbias_shadowmap.SetValue( "0.00005" ); #endif From ae4e26f03b508a62cce33fa00a3cf1c73f25bc23 Mon Sep 17 00:00:00 2001 From: Alivebyte Date: Sun, 25 Apr 2021 15:48:29 +0300 Subject: [PATCH 058/378] Added sound support for vgui_movie_display --- sp/src/game/client/c_movie_display.cpp | 1 + sp/src/game/client/c_movie_display.h | 2 ++ sp/src/game/client/vgui_movie_display.cpp | 18 +++++++++++++----- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/sp/src/game/client/c_movie_display.cpp b/sp/src/game/client/c_movie_display.cpp index 2285b97e..27327403 100644 --- a/sp/src/game/client/c_movie_display.cpp +++ b/sp/src/game/client/c_movie_display.cpp @@ -13,6 +13,7 @@ IMPLEMENT_CLIENTCLASS_DT( C_MovieDisplay, DT_MovieDisplay, CMovieDisplay ) RecvPropBool( RECVINFO( m_bEnabled ) ), RecvPropBool( RECVINFO( m_bLooping ) ), + RecvPropBool( RECVINFO( m_bMuted ) ), RecvPropString( RECVINFO( m_szMovieFilename ) ), RecvPropString( RECVINFO( m_szGroupName ) ), END_RECV_TABLE() diff --git a/sp/src/game/client/c_movie_display.h b/sp/src/game/client/c_movie_display.h index d133e82e..55d0211f 100644 --- a/sp/src/game/client/c_movie_display.h +++ b/sp/src/game/client/c_movie_display.h @@ -20,6 +20,7 @@ public: bool IsEnabled( void ) const { return m_bEnabled; } bool IsLooping( void ) const { return m_bLooping; } + bool IsMuted(void) const { return m_bMuted; } const char *GetMovieFilename( void ) const { return m_szMovieFilename; } const char *GetGroupName( void ) const { return m_szGroupName; } @@ -27,6 +28,7 @@ public: private: bool m_bEnabled; bool m_bLooping; + bool m_bMuted; char m_szMovieFilename[128]; char m_szGroupName[128]; }; diff --git a/sp/src/game/client/vgui_movie_display.cpp b/sp/src/game/client/vgui_movie_display.cpp index 0f474323..8524a338 100644 --- a/sp/src/game/client/vgui_movie_display.cpp +++ b/sp/src/game/client/vgui_movie_display.cpp @@ -81,7 +81,7 @@ private: bool m_bBlackBackground; bool m_bSlaved; bool m_bInitialized; - + bool m_bStopAllSounds; bool m_bLastActiveState; // HACK: I'd rather get a real callback... // VGUI specifics @@ -110,10 +110,10 @@ CMovieDisplayScreen::CMovieDisplayScreen( vgui::Panel *parent, const char *panel m_bBlackBackground = true; m_bSlaved = false; m_bInitialized = false; - + m_bStopAllSounds = true; // Add ourselves to the global list of movie displays g_MovieDisplays.AddToTail( this ); - + //m_VideoMaterial->SetMuted(true); m_bLastActiveState = IsActive(); } @@ -295,6 +295,11 @@ void CMovieDisplayScreen::UpdateMovie( void ) // OnVideoOver(); // StopPlayback(); } + + if (!m_hScreenEntity->IsMuted()) + { + m_VideoMaterial->SetMuted(false); + } } } @@ -376,14 +381,17 @@ bool CMovieDisplayScreen::BeginPlayback( const char *pFilename ) if ( m_VideoMaterial == NULL ) return false; - m_VideoMaterial->SetMuted( true ); // FIXME: Allow? + + + m_VideoMaterial->SetMuted(true); // FIXME: Allow? + if ( m_hScreenEntity->IsLooping() ) { m_VideoMaterial->SetLooping( true ); } - if ( m_VideoMaterial->HasAudio() ) + if ( m_VideoMaterial->HasAudio() && m_bStopAllSounds) { // We want to be the sole audio source enginesound->NotifyBeginMoviePlayback(); From f458ac122372b7ddeb3d4c0af537b55350fc3189 Mon Sep 17 00:00:00 2001 From: rzkid Date: Sun, 25 Apr 2021 17:27:26 +0300 Subject: [PATCH 059/378] removed stopallsounds --- sp/src/game/client/vgui_movie_display.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sp/src/game/client/vgui_movie_display.cpp b/sp/src/game/client/vgui_movie_display.cpp index 8524a338..8cc2c0db 100644 --- a/sp/src/game/client/vgui_movie_display.cpp +++ b/sp/src/game/client/vgui_movie_display.cpp @@ -81,7 +81,6 @@ private: bool m_bBlackBackground; bool m_bSlaved; bool m_bInitialized; - bool m_bStopAllSounds; bool m_bLastActiveState; // HACK: I'd rather get a real callback... // VGUI specifics @@ -110,7 +109,6 @@ CMovieDisplayScreen::CMovieDisplayScreen( vgui::Panel *parent, const char *panel m_bBlackBackground = true; m_bSlaved = false; m_bInitialized = false; - m_bStopAllSounds = true; // Add ourselves to the global list of movie displays g_MovieDisplays.AddToTail( this ); //m_VideoMaterial->SetMuted(true); @@ -391,7 +389,7 @@ bool CMovieDisplayScreen::BeginPlayback( const char *pFilename ) m_VideoMaterial->SetLooping( true ); } - if ( m_VideoMaterial->HasAudio() && m_bStopAllSounds) + if ( m_VideoMaterial->HasAudio()) { // We want to be the sole audio source enginesound->NotifyBeginMoviePlayback(); From 5bc2d7cb83d02eece650d0c180efdb01877be260 Mon Sep 17 00:00:00 2001 From: Alivebyte Date: Sun, 25 Apr 2021 17:35:45 +0300 Subject: [PATCH 060/378] Added missing movie_display.cpp --- sp/src/game/server/movie_display.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sp/src/game/server/movie_display.cpp b/sp/src/game/server/movie_display.cpp index 5c31fb23..01236f1c 100644 --- a/sp/src/game/server/movie_display.cpp +++ b/sp/src/game/server/movie_display.cpp @@ -53,6 +53,7 @@ private: private: CNetworkVar( bool, m_bEnabled ); CNetworkVar( bool, m_bLooping ); + CNetworkVar( bool, m_bMuted); CNetworkString( m_szDisplayText, 128 ); @@ -93,6 +94,7 @@ BEGIN_DATADESC( CMovieDisplay ) DEFINE_KEYFIELD( m_iScreenWidth, FIELD_INTEGER, "width" ), DEFINE_KEYFIELD( m_iScreenHeight, FIELD_INTEGER, "height" ), DEFINE_KEYFIELD( m_bLooping, FIELD_BOOLEAN, "looping" ), + DEFINE_KEYFIELD( m_bMuted, FIELD_BOOLEAN, "muted"), DEFINE_FIELD( m_bDoFullTransmit, FIELD_BOOLEAN ), @@ -108,6 +110,7 @@ END_DATADESC() IMPLEMENT_SERVERCLASS_ST( CMovieDisplay, DT_MovieDisplay ) SendPropBool( SENDINFO( m_bEnabled ) ), SendPropBool( SENDINFO( m_bLooping ) ), + SendPropBool( SENDINFO( m_bMuted ) ), SendPropString( SENDINFO( m_szMovieFilename ) ), SendPropString( SENDINFO( m_szGroupName ) ), END_SEND_TABLE() From 578257471170ee6fd5ada87a4d2ff4f6cfb67f87 Mon Sep 17 00:00:00 2001 From: Alivebyte Date: Sun, 25 Apr 2021 18:56:49 +0300 Subject: [PATCH 061/378] Added constructor for movie_display to mute sound by default --- sp/src/game/server/movie_display.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sp/src/game/server/movie_display.cpp b/sp/src/game/server/movie_display.cpp index 01236f1c..b5a4476c 100644 --- a/sp/src/game/server/movie_display.cpp +++ b/sp/src/game/server/movie_display.cpp @@ -21,6 +21,8 @@ public: DECLARE_DATADESC(); DECLARE_SERVERCLASS(); + CMovieDisplay() { m_bMuted = true; } + virtual ~CMovieDisplay(); virtual bool KeyValue( const char *szKeyName, const char *szValue ); @@ -123,6 +125,7 @@ CMovieDisplay::~CMovieDisplay() //----------------------------------------------------------------------------- // Read in Hammer data //----------------------------------------------------------------------------- + bool CMovieDisplay::KeyValue( const char *szKeyName, const char *szValue ) { // NOTE: Have to do these separate because they set two values instead of one From dddcf642aad3ce5aeeeb36889157a28dfe36ca3a Mon Sep 17 00:00:00 2001 From: Alexander 'z33ky' Hirsch <1zeeky@gmail.com> Date: Sun, 25 Apr 2021 22:00:08 +0200 Subject: [PATCH 062/378] Fix gcc build errors & warnings --- sp/src/game/server/ai_expresserfollowup.cpp | 6 +- sp/src/game/server/ai_playerally.cpp | 8 +-- sp/src/game/server/ai_speech_new.cpp | 49 +++++++++------- sp/src/game/server/ai_speech_new.h | 56 +++++++++---------- sp/src/game/server/genericactor.cpp | 3 +- sp/src/game/server/hl2/npc_zombie.cpp | 3 +- sp/src/game/shared/ai_criteria_new.cpp | 6 +- sp/src/game/shared/ai_responsesystem_new.cpp | 8 +-- sp/src/game/shared/ai_responsesystem_new.h | 2 +- sp/src/game/shared/ai_speechconcept.h | 2 +- sp/src/public/tier1/strtools.h | 10 ++++ .../runtime/response_types_internal.h | 6 +- sp/src/tier1/convar.cpp | 2 +- 13 files changed, 91 insertions(+), 70 deletions(-) diff --git a/sp/src/game/server/ai_expresserfollowup.cpp b/sp/src/game/server/ai_expresserfollowup.cpp index 759f5c46..65575709 100644 --- a/sp/src/game/server/ai_expresserfollowup.cpp +++ b/sp/src/game/server/ai_expresserfollowup.cpp @@ -225,7 +225,7 @@ static CResponseQueue::CFollowupTargetSpec_t ResolveFollowupTargetToEntity( AICo ConVar chet_debug_idle( "chet_debug_idle", "0", FCVAR_ARCHIVE, "If set one, many debug prints to help track down the TLK_IDLE issue. Set two for super verbose info" ); // extern ConVar chet_debug_idle; -bool CAI_ExpresserWithFollowup::Speak( AIConcept_t &concept, const char *modifiers /*= NULL*/, char *pszOutResponseChosen /* = NULL*/, size_t bufsize /* = 0 */, IRecipientFilter *filter /* = NULL */ ) +bool CAI_ExpresserWithFollowup::Speak( AIConcept_t concept, const char *modifiers /*= NULL*/, char *pszOutResponseChosen /* = NULL*/, size_t bufsize /* = 0 */, IRecipientFilter *filter /* = NULL */ ) { VPROF("CAI_Expresser::Speak"); if ( IsSpeechGloballySuppressed() ) @@ -261,7 +261,7 @@ bool CAI_ExpresserWithFollowup::Speak( AIConcept_t &concept, const char *modifie } } - SpeechMsg( GetOuter(), "%s (%x) spoke %s (%f)", STRING(GetOuter()->GetEntityName()), GetOuter(), (const char*)concept, gpGlobals->curtime ); + SpeechMsg( GetOuter(), "%s (%p) spoke %s (%f)", STRING(GetOuter()->GetEntityName()), GetOuter(), (const char*)concept, gpGlobals->curtime ); // Msg( "%s:%s to %s:%s\n", GetOuter()->GetDebugName(), concept.GetStringConcept(), criteria.GetValue(criteria.FindCriterionIndex("Subject")), pTarget ? pTarget->GetDebugName() : "none" ); bool spoke = SpeakDispatchResponse( concept, &result, &criteria, filter ); @@ -297,7 +297,7 @@ static float GetSpeechDurationForResponse( const AI_Response * RESTRICT response // Purpose: Dispatches the result // Input : *response - //----------------------------------------------------------------------------- -bool CAI_ExpresserWithFollowup::SpeakDispatchResponse( AIConcept_t &concept, AI_Response *response, AI_CriteriaSet *criteria, IRecipientFilter *filter ) +bool CAI_ExpresserWithFollowup::SpeakDispatchResponse( AIConcept_t concept, AI_Response *response, AI_CriteriaSet *criteria, IRecipientFilter *filter ) { // This gives the chance for the other bot to respond. if ( !concept.GetSpeaker().IsValid() ) diff --git a/sp/src/game/server/ai_playerally.cpp b/sp/src/game/server/ai_playerally.cpp index 43b82ed4..f7594feb 100644 --- a/sp/src/game/server/ai_playerally.cpp +++ b/sp/src/game/server/ai_playerally.cpp @@ -792,11 +792,11 @@ void CAI_PlayerAlly::PostSpeakDispatchResponse( AIConcept_t concept, AI_Response { if ( bSaidHelloToNPC ) { - Warning("Q&A: '%s' said Hello to '%s' (concept %s)\n", GetDebugName(), GetSpeechTarget()->GetDebugName(), concept ); + Warning("Q&A: '%s' said Hello to '%s' (concept %s)\n", GetDebugName(), GetSpeechTarget()->GetDebugName(), (const char*)concept ); } else { - Warning("Q&A: '%s' questioned '%s' (concept %s)\n", GetDebugName(), GetSpeechTarget()->GetDebugName(), concept ); + Warning("Q&A: '%s' questioned '%s' (concept %s)\n", GetDebugName(), GetSpeechTarget()->GetDebugName(), (const char*)concept ); } NDebugOverlay::HorzArrow( GetAbsOrigin(), GetSpeechTarget()->GetAbsOrigin(), 8, 0, 255, 0, 64, true, duration ); } @@ -1022,11 +1022,11 @@ void CAI_PlayerAlly::AnswerQuestion( CAI_PlayerAlly *pQuestioner, int iQARandomN } } - Assert( selection.pResponse ); SetSpeechTarget( selection.hSpeechTarget ); #ifdef NEW_RESPONSE_SYSTEM SpeakDispatchResponse( selection.concept.c_str(), &selection.Response ); #else + Assert( selection.pResponse ); SpeakDispatchResponse( selection.concept.c_str(), selection.pResponse ); #endif @@ -1078,11 +1078,11 @@ int CAI_PlayerAlly::SelectNonCombatSpeechSchedule() AISpeechSelection_t selection; if ( SelectNonCombatSpeech( &selection ) ) { - Assert( selection.pResponse ); SetSpeechTarget( selection.hSpeechTarget ); #ifdef NEW_RESPONSE_SYSTEM SetPendingSpeech( selection.concept.c_str(), &selection.Response ); #else + Assert( selection.pResponse ); SetPendingSpeech( selection.concept.c_str(), selection.pResponse ); #endif } diff --git a/sp/src/game/server/ai_speech_new.cpp b/sp/src/game/server/ai_speech_new.cpp index e886ab8f..41fe6182 100644 --- a/sp/src/game/server/ai_speech_new.cpp +++ b/sp/src/game/server/ai_speech_new.cpp @@ -10,10 +10,10 @@ #include "ai_speech.h" #include "game.h" -#include "engine/ienginesound.h" -#include "keyvalues.h" +#include "engine/IEngineSound.h" +#include "KeyValues.h" #include "ai_basenpc.h" -#include "ai_criteria.h" +#include "AI_Criteria.h" #include "isaverestore.h" #include "sceneentity.h" #include "ai_speechqueue.h" @@ -575,7 +575,7 @@ void CAI_Expresser::GatherCriteria( AI_CriteriaSet * RESTRICT outputSet, const A // Output : AI_Response //----------------------------------------------------------------------------- // AI_Response *CAI_Expresser::SpeakFindResponse( AIConcept_t concept, const char *modifiers /*= NULL*/ ) -bool CAI_Expresser::FindResponse( AI_Response &outResponse, AIConcept_t &concept, AI_CriteriaSet *criteria ) +bool CAI_Expresser::FindResponse( AI_Response &outResponse, const AIConcept_t &concept, AI_CriteriaSet *criteria ) { VPROF("CAI_Expresser::FindResponse"); IResponseSystem *rs = GetOuter()->GetResponseSystem(); @@ -703,7 +703,7 @@ bool CAI_Expresser::FindResponse( AI_Response &outResponse, AIConcept_t &concept // NULL - // Output : bool : true on success, false on fail //----------------------------------------------------------------------------- -AI_Response *CAI_Expresser::SpeakFindResponse( AI_Response *result, AIConcept_t &concept, AI_CriteriaSet *criteria ) +AI_Response *CAI_Expresser::SpeakFindResponse( AI_Response *result, const AIConcept_t &concept, AI_CriteriaSet *criteria ) { Assert(response); @@ -808,7 +808,7 @@ AI_Response *CAI_Expresser::SpeakFindResponse( AI_Response *result, AIConcept_t // Purpose: Dispatches the result // Input : *response - //----------------------------------------------------------------------------- -bool CAI_Expresser::SpeakDispatchResponse( AIConcept_t &concept, AI_Response *result, AI_CriteriaSet *criteria, IRecipientFilter *filter /* = NULL */ ) +bool CAI_Expresser::SpeakDispatchResponse( AIConcept_t concept, AI_Response *result, AI_CriteriaSet *criteria, IRecipientFilter *filter /* = NULL */ ) { char response[ 256 ]; result->GetResponse( response, sizeof( response ) ); @@ -1068,21 +1068,21 @@ bool CAI_Expresser::FireEntIOFromResponse( char *response, CBaseEntity *pInitiat char *pszParam; char *strtokContext; - pszEntname = strtok_s( response, " ", &strtokContext ); + pszEntname = V_strtok_s( response, " ", &strtokContext ); if ( !pszEntname ) { Warning( "Response was entityio but had bad value %s\n", response ); return false; } - pszInput = strtok_s( NULL, " ", &strtokContext ); + pszInput = V_strtok_s( NULL, " ", &strtokContext ); if ( !pszInput ) { Warning( "Response was entityio but had bad value %s\n", response ); return false; } - pszParam = strtok_s( NULL, " ", &strtokContext ); + pszParam = V_strtok_s( NULL, " ", &strtokContext ); // poke entity io CBaseEntity *pTarget = gEntList.FindEntityByName( NULL, pszEntname, pInitiator ); @@ -1231,7 +1231,7 @@ void CAI_Expresser::MarkResponseAsUsed( AI_Response *response ) // Input : concept - // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- -bool CAI_Expresser::Speak( AIConcept_t &concept, const char *modifiers /*= NULL*/, char *pszOutResponseChosen /* = NULL*/, size_t bufsize /* = 0 */, IRecipientFilter *filter /* = NULL */ ) +bool CAI_Expresser::Speak( AIConcept_t concept, const char *modifiers /*= NULL*/, char *pszOutResponseChosen /* = NULL*/, size_t bufsize /* = 0 */, IRecipientFilter *filter /* = NULL */ ) { concept.SetSpeaker(GetOuter()); AI_CriteriaSet criteria; @@ -1245,7 +1245,7 @@ bool CAI_Expresser::Speak( AIConcept_t &concept, const char *modifiers /*= NULL* //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- -bool CAI_Expresser::Speak( AIConcept_t &concept, AI_CriteriaSet * RESTRICT criteria, char *pszOutResponseChosen , size_t bufsize , IRecipientFilter *filter ) +bool CAI_Expresser::Speak( const AIConcept_t &concept, AI_CriteriaSet * RESTRICT criteria, char *pszOutResponseChosen , size_t bufsize , IRecipientFilter *filter ) { VPROF("CAI_Expresser::Speak"); if ( IsSpeechGloballySuppressed() ) @@ -1260,7 +1260,7 @@ bool CAI_Expresser::Speak( AIConcept_t &concept, AI_CriteriaSet * RESTRICT crite return false; } - SpeechMsg( GetOuter(), "%s (%x) spoke %s (%f)", STRING(GetOuter()->GetEntityName()), GetOuter(), (const char*)concept, gpGlobals->curtime ); + SpeechMsg( GetOuter(), "%s (%p) spoke %s (%f)", STRING(GetOuter()->GetEntityName()), GetOuter(), (const char*)concept, gpGlobals->curtime ); // Msg( "%s:%s to %s:%s\n", GetOuter()->GetDebugName(), concept.GetStringConcept(), criteria.GetValue(criteria.FindCriterionIndex("Subject")), pTarget ? pTarget->GetDebugName() : "none" ); bool spoke = SpeakDispatchResponse( concept, &result, criteria, filter ); @@ -1447,7 +1447,7 @@ bool CAI_Expresser::CanSpeakAfterMyself() } //------------------------------------- -bool CAI_Expresser::CanSpeakConcept( AIConcept_t concept ) +bool CAI_Expresser::CanSpeakConcept( const AIConcept_t &concept ) { // Not in history? int iter = m_ConceptHistories.Find( concept ); @@ -1479,14 +1479,14 @@ bool CAI_Expresser::CanSpeakConcept( AIConcept_t concept ) //------------------------------------- -bool CAI_Expresser::SpokeConcept( AIConcept_t concept ) +bool CAI_Expresser::SpokeConcept( const AIConcept_t &concept ) { return GetTimeSpokeConcept( concept ) != -1.f; } //------------------------------------- -float CAI_Expresser::GetTimeSpokeConcept( AIConcept_t concept ) +float CAI_Expresser::GetTimeSpokeConcept( const AIConcept_t &concept ) { int iter = m_ConceptHistories.Find( concept ); if ( iter == m_ConceptHistories.InvalidIndex() ) @@ -1498,7 +1498,7 @@ float CAI_Expresser::GetTimeSpokeConcept( AIConcept_t concept ) //------------------------------------- -void CAI_Expresser::SetSpokeConcept( AIConcept_t concept, AI_Response *response, bool bCallback ) +void CAI_Expresser::SetSpokeConcept( const AIConcept_t &concept, AI_Response *response, bool bCallback ) { int idx = m_ConceptHistories.Find( concept ); if ( idx == m_ConceptHistories.InvalidIndex() ) @@ -1523,7 +1523,7 @@ void CAI_Expresser::SetSpokeConcept( AIConcept_t concept, AI_Response *response, //------------------------------------- -void CAI_Expresser::ClearSpokeConcept( AIConcept_t concept ) +void CAI_Expresser::ClearSpokeConcept( const AIConcept_t &concept ) { m_ConceptHistories.Remove( concept ); } @@ -1560,7 +1560,7 @@ bool CAI_Expresser::IsValidResponse( ResponseType_t type, const char *pszValue ) CAI_TimedSemaphore *CAI_Expresser::GetMySpeechSemaphore( CBaseEntity *pNpc ) { if ( !pNpc->MyNPCPointer() ) - return false; + return NULL; return (pNpc->MyNPCPointer()->IsPlayerAlly() ? &g_AIFriendliesTalkSemaphore : &g_AIFoesTalkSemaphore ); } @@ -1573,16 +1573,23 @@ void CAI_Expresser::SpeechMsg( CBaseEntity *pFlex, const char *pszFormat, ... ) if ( !DebuggingSpeech() ) return; + va_list arg_ptr; + + va_start(arg_ptr, pszFormat); + CFmtStr formatted; + formatted.sprintf_argv(pszFormat, arg_ptr); + va_end(arg_ptr); + if ( pFlex->MyNPCPointer() ) { - DevMsg( pFlex->MyNPCPointer(), CFmtStr( &pszFormat ) ); + DevMsg( pFlex->MyNPCPointer(), "%s", formatted.Get() ); } else { - CGMsg( 1, CON_GROUP_SPEECH_AI, CFmtStr( &pszFormat ) ); + CGMsg( 1, CON_GROUP_SPEECH_AI, "%s", formatted.Get() ); } - UTIL_LogPrintf( (char *) ( (const char *) CFmtStr( &pszFormat ) ) ); + UTIL_LogPrintf( "%s", formatted.Get() ); } //----------------------------------------------------------------------------- diff --git a/sp/src/game/server/ai_speech_new.h b/sp/src/game/server/ai_speech_new.h index fec4f8c2..1882e66e 100644 --- a/sp/src/game/server/ai_speech_new.h +++ b/sp/src/game/server/ai_speech_new.h @@ -12,7 +12,7 @@ #include "soundflags.h" #include "AI_Criteria.h" -#include "ai_responsesystem.h" +#include "AI_ResponseSystem.h" #include "utldict.h" #include "ai_speechconcept.h" @@ -162,8 +162,8 @@ public: // -------------------------------- - bool Speak( AIConcept_t &concept, const char *modifiers = NULL, char *pszOutResponseChosen = NULL, size_t bufsize = 0, IRecipientFilter *filter = NULL ); - bool Speak( AIConcept_t &concept, AI_CriteriaSet *criteria, char *pszOutResponseChosen = NULL, size_t bufsize = 0, IRecipientFilter *filter = NULL ); + bool Speak( AIConcept_t concept, const char *modifiers = NULL, char *pszOutResponseChosen = NULL, size_t bufsize = 0, IRecipientFilter *filter = NULL ); + bool Speak( const AIConcept_t &concept, AI_CriteriaSet *criteria, char *pszOutResponseChosen = NULL, size_t bufsize = 0, IRecipientFilter *filter = NULL ); // Given modifiers (which are colon-delimited strings), fill out a criteria set including this // character's contexts and the ones in the modifier. This lets us hang on to them after a call @@ -174,8 +174,8 @@ public: // AI_Response *SpeakFindResponse( AIConcept_t &concept, AI_CriteriaSet *criteria ); // Find the appropriate response for the given concept. Return false if none found. // Fills out the response object that you provide. - bool FindResponse( AI_Response &outResponse, AIConcept_t &concept, AI_CriteriaSet *modifiers = NULL ); - virtual bool SpeakDispatchResponse( AIConcept_t &concept, AI_Response *response, AI_CriteriaSet *criteria, IRecipientFilter *filter = NULL ); + bool FindResponse( AI_Response &outResponse, const AIConcept_t &concept, AI_CriteriaSet *modifiers = NULL ); + virtual bool SpeakDispatchResponse( AIConcept_t concept, AI_Response *response, AI_CriteriaSet *criteria, IRecipientFilter *filter = NULL ); float GetResponseDuration( AI_Response *response ); #ifdef MAPBASE @@ -206,11 +206,11 @@ public: // -------------------------------- - bool CanSpeakConcept( AIConcept_t concept ); - bool SpokeConcept( AIConcept_t concept ); - float GetTimeSpokeConcept( AIConcept_t concept ); // returns -1 if never - void SetSpokeConcept( AIConcept_t concept, AI_Response *response, bool bCallback = true ); - void ClearSpokeConcept( AIConcept_t concept ); + bool CanSpeakConcept( const AIConcept_t &concept ); + bool SpokeConcept( const AIConcept_t &concept ); + float GetTimeSpokeConcept( const AIConcept_t &concept ); // returns -1 if never + void SetSpokeConcept( const AIConcept_t &concept, AI_Response *response, bool bCallback = true ); + void ClearSpokeConcept( const AIConcept_t &concept ); // -------------------------------- @@ -226,7 +226,7 @@ public: bool ScriptSpeakRawScene( char const *soundname, float delay ) { return SpeakRawScene( soundname, delay, NULL ); } bool ScriptSpeakAutoGeneratedScene( char const *soundname, float delay ) { return SpeakAutoGeneratedScene( soundname, delay ); } int ScriptSpeakRawSentence( char const *pszSentence, float delay ) { return SpeakRawSentence( pszSentence, delay ); } - bool ScriptSpeak( char const *concept, const char *modifiers ) { return Speak( CAI_Concept( concept ), modifiers[0] != '\0' ? modifiers : NULL ); } + bool ScriptSpeak( char const *concept, const char *modifiers ) { return Speak( concept, modifiers[0] != '\0' ? modifiers : NULL ); } #endif // helper used in dealing with RESPONSE_ENTITYIO @@ -249,7 +249,7 @@ protected: void DumpHistories(); - void SpeechMsg( CBaseEntity *pFlex, const char *pszFormat, ... ); + void SpeechMsg( CBaseEntity *pFlex, PRINTF_FORMAT_STRING const char *pszFormat, ... ) FMTFUNCTION(3, 4); // -------------------------------- @@ -321,15 +321,15 @@ public: // These two methods allow looking up a response and dispatching it to be two different steps #ifdef MAPBASE //AI_Response *SpeakFindResponse( AIConcept_t concept, const AI_CriteriaSet& modifiers ); - inline bool SpeakDispatchResponse( AIConcept_t concept, AI_Response &response, AI_CriteriaSet *criteria = NULL ) { return SpeakDispatchResponse( concept, &response, criteria ); } + inline bool SpeakDispatchResponse( const AIConcept_t &concept, AI_Response &response, AI_CriteriaSet *criteria = NULL ) { return SpeakDispatchResponse( concept, &response, criteria ); } #endif - bool SpeakFindResponse( AI_Response& outResponse, AIConcept_t concept, const char *modifiers = NULL ); + bool SpeakFindResponse( AI_Response& outResponse, const AIConcept_t &concept, const char *modifiers = NULL ); // AI_Response * SpeakFindResponse( AIConcept_t concept, const char *modifiers = NULL ); // AI_Response *SpeakFindResponse( AIConcept_t concept, AI_CriteriaSet *criteria ); // AI_Response *SpeakFindResponse( AIConcept_t concept ); // Find the appropriate response for the given concept. Return false if none found. // Fills out the response object that you provide. - bool FindResponse( AI_Response &outResponse, AIConcept_t &concept, AI_CriteriaSet *criteria = NULL ); + bool FindResponse( AI_Response &outResponse, const AIConcept_t &concept, AI_CriteriaSet *criteria = NULL ); bool SpeakDispatchResponse( AIConcept_t concept, AI_Response *response, AI_CriteriaSet *criteria = NULL ); virtual void PostSpeakDispatchResponse( AIConcept_t concept, AI_Response *response ) { return; } @@ -436,7 +436,7 @@ inline void CAI_ExpresserHost::GatherCriteria( AI_CriteriaSet *outputC //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- template -inline bool CAI_ExpresserHost::SpeakFindResponse(AI_Response& outResponse, AIConcept_t concept, const char *modifiers /*= NULL*/ ) +inline bool CAI_ExpresserHost::SpeakFindResponse(AI_Response& outResponse, const AIConcept_t &concept, const char *modifiers /*= NULL*/ ) { AI_CriteriaSet criteria; GatherCriteria(&criteria, concept, modifiers); @@ -446,7 +446,7 @@ inline bool CAI_ExpresserHost::SpeakFindResponse(AI_Response& outRespo //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- template -inline AI_Response *CAI_ExpresserHost::SpeakFindResponse( AIConcept_t concept, const char *modifiers /*= NULL*/ ) +inline AI_Response *CAI_ExpresserHost::SpeakFindResponse( const AIConcept_t &concept, const char *modifiers /*= NULL*/ ) { return this->GetExpresser()->SpeakFindResponse( concept, modifiers ); } @@ -456,7 +456,7 @@ inline AI_Response *CAI_ExpresserHost::SpeakFindResponse( AIConcept_t //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- template -inline AI_Response *CAI_ExpresserHost::SpeakFindResponse( AIConcept_t concept, AI_CriteriaSet *criteria /*= NULL*/ ) +inline AI_Response *CAI_ExpresserHost::SpeakFindResponse( const AIConcept_t &concept, AI_CriteriaSet *criteria /*= NULL*/ ) { return this->GetExpresser()->SpeakFindResponse( concept, criteria ); } @@ -467,7 +467,7 @@ inline AI_Response *CAI_ExpresserHost::SpeakFindResponse( AIConcept_t // class that generates a one off. //----------------------------------------------------------------------------- template -inline AI_Response * CAI_ExpresserHost::SpeakFindResponse( AIConcept_t concept ) +inline AI_Response * CAI_ExpresserHost::SpeakFindResponse( const AIConcept_t &concept ) { AI_CriteriaSet criteria; GatherCriteria( &criteria, concept, NULL ); @@ -479,7 +479,7 @@ inline AI_Response * CAI_ExpresserHost::SpeakFindResponse( AIConcept_t //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- template -inline bool CAI_ExpresserHost::FindResponse( AI_Response &outResponse, AIConcept_t &concept, AI_CriteriaSet *criteria ) +inline bool CAI_ExpresserHost::FindResponse( AI_Response &outResponse, const AIConcept_t &concept, AI_CriteriaSet *criteria ) { return this->GetExpresser()->FindResponse( outResponse, concept, criteria ); } @@ -512,9 +512,9 @@ inline float CAI_ExpresserHost::GetResponseDuration( AI_Response *resp //----------------------------------------------------------------------------- template inline void CAI_ExpresserHost::DispatchResponse( const char *conceptName ) - { - Speak( (AIConcept_t)conceptName ); - } +{ + Speak( AIConcept_t( conceptName ) ); +} //----------------------------------------------------------------------------- @@ -529,7 +529,7 @@ inline void CAI_ExpresserHost::DispatchResponse( const char *conceptNa template class CAI_ExpresserHostWithData : public CAI_ExpresserHost { - DECLARE_CLASS_NOFRIEND( CAI_ExpresserHostWithData, CAI_ExpresserHost ); + DECLARE_CLASS_NOFRIEND( CAI_ExpresserHostWithData, CAI_ExpresserHost ); public: CAI_ExpresserHostWithData( ) : m_pExpresser(NULL) {}; @@ -545,11 +545,11 @@ public: protected: EXPRESSER_TYPE *CreateExpresser( void ) { - AssertMsg1( m_pExpresser == NULL, "Tried to double-initialize expresser in %s\n", GetDebugName() ); + AssertMsg1( m_pExpresser == NULL, "Tried to double-initialize expresser in %s\n", this->GetDebugName() ); m_pExpresser = new EXPRESSER_TYPE(this); if ( !m_pExpresser) { - AssertMsg1( false, "Creating an expresser failed in %s\n", GetDebugName() ); + AssertMsg1( false, "Creating an expresser failed in %s\n", this->GetDebugName() ); return NULL; } @@ -667,8 +667,8 @@ public: CAI_ExpresserWithFollowup( CBaseFlex *pOuter = NULL ) : CAI_Expresser(pOuter), m_pPostponedFollowup(NULL) {}; - virtual bool Speak( AIConcept_t &concept, const char *modifiers = NULL, char *pszOutResponseChosen = NULL, size_t bufsize = 0, IRecipientFilter *filter = NULL ); - virtual bool SpeakDispatchResponse( AIConcept_t &concept, AI_Response *response, AI_CriteriaSet *criteria, IRecipientFilter *filter = NULL ); + virtual bool Speak( AIConcept_t concept, const char *modifiers = NULL, char *pszOutResponseChosen = NULL, size_t bufsize = 0, IRecipientFilter *filter = NULL ); + virtual bool SpeakDispatchResponse( AIConcept_t concept, AI_Response *response, AI_CriteriaSet *criteria, IRecipientFilter *filter = NULL ); virtual void SpeakDispatchFollowup( AI_ResponseFollowup &followup ); virtual void OnSpeechFinished(); diff --git a/sp/src/game/server/genericactor.cpp b/sp/src/game/server/genericactor.cpp index bb0dfe0b..8f606519 100644 --- a/sp/src/game/server/genericactor.cpp +++ b/sp/src/game/server/genericactor.cpp @@ -277,7 +277,8 @@ bool CGenericActorCustom::KeyValue( const char *szKeyName, const char *szValue ) //----------------------------------------------------------------------------- void CGenericActorCustom::SpeakIfAllowed( const char *concept, AI_CriteriaSet *modifiers ) { - Speak( concept, modifiers ? *modifiers : AI_CriteriaSet() ); + AI_CriteriaSet empty; + Speak( concept, modifiers ? *modifiers : empty ); } //----------------------------------------------------------------------------- diff --git a/sp/src/game/server/hl2/npc_zombie.cpp b/sp/src/game/server/hl2/npc_zombie.cpp index 2191b394..83a6ed9e 100644 --- a/sp/src/game/server/hl2/npc_zombie.cpp +++ b/sp/src/game/server/hl2/npc_zombie.cpp @@ -1263,7 +1263,8 @@ void CZombieCustom::AttackSound( void ) //----------------------------------------------------------------------------- void CZombieCustom::SpeakIfAllowed(const char *concept, AI_CriteriaSet *modifiers) { - Speak( concept, modifiers ? *modifiers : AI_CriteriaSet() ); + AI_CriteriaSet empty; + Speak( concept, modifiers ? *modifiers : empty ); } //----------------------------------------------------------------------------- diff --git a/sp/src/game/shared/ai_criteria_new.cpp b/sp/src/game/shared/ai_criteria_new.cpp index 31a5b1ef..837c61aa 100644 --- a/sp/src/game/shared/ai_criteria_new.cpp +++ b/sp/src/game/shared/ai_criteria_new.cpp @@ -6,14 +6,14 @@ // //===========================================================================// #include "cbase.h" -#include "ai_criteria.h" +#include "AI_Criteria.h" #ifdef GAME_DLL #include "ai_speech.h" #endif -#include -#include "engine/ienginesound.h" +#include +#include "engine/IEngineSound.h" // memdbgon must be the last include file in a .cpp file!!! #include diff --git a/sp/src/game/shared/ai_responsesystem_new.cpp b/sp/src/game/shared/ai_responsesystem_new.cpp index 4dbf8222..6c3301bb 100644 --- a/sp/src/game/shared/ai_responsesystem_new.cpp +++ b/sp/src/game/shared/ai_responsesystem_new.cpp @@ -6,11 +6,11 @@ #include "cbase.h" -#include "soundemittersystem/isoundemittersystembase.h" -#include "ai_responsesystem.h" +#include "SoundEmitterSystem/isoundemittersystembase.h" +#include "AI_ResponseSystem.h" #include "igamesystem.h" -#include "ai_criteria.h" -#include +#include "AI_Criteria.h" +#include #include "filesystem.h" #include "utldict.h" #ifdef GAME_DLL diff --git a/sp/src/game/shared/ai_responsesystem_new.h b/sp/src/game/shared/ai_responsesystem_new.h index a558f79e..9d2fff6b 100644 --- a/sp/src/game/shared/ai_responsesystem_new.h +++ b/sp/src/game/shared/ai_responsesystem_new.h @@ -13,7 +13,7 @@ #pragma once #endif -#include "ai_criteria.h" +#include "AI_Criteria.h" #include "../../public/responserules/response_types.h" // using ResponseRules::IResponseFilter; diff --git a/sp/src/game/shared/ai_speechconcept.h b/sp/src/game/shared/ai_speechconcept.h index 41a3cc60..3e375a0a 100644 --- a/sp/src/game/shared/ai_speechconcept.h +++ b/sp/src/game/shared/ai_speechconcept.h @@ -12,7 +12,7 @@ #pragma once #endif -#include "../../public/responserules/response_types.h" +#include "responserules/response_types.h" class CAI_Concept : public ResponseRules::CRR_Concept { diff --git a/sp/src/public/tier1/strtools.h b/sp/src/public/tier1/strtools.h index d3f1c65b..0872539d 100644 --- a/sp/src/public/tier1/strtools.h +++ b/sp/src/public/tier1/strtools.h @@ -470,6 +470,16 @@ inline void V_wcscat( INOUT_Z_CAP(cchDest) wchar_t *dest, const wchar_t *src, in V_wcsncat( dest, src, cchDest, COPY_ALL_CHARACTERS ); } +// Reentrant strtok +inline static char* V_strtok_s( char *str, const char *delimiters, char **context ) +{ +#ifdef _MSC_VER + return strtok_s( str, delimiters, context ); +#elif POSIX + return strtok_r( str, delimiters, context ); +#endif +} + //----------------------------------------------------------------------------- // generic unique name helper functions //----------------------------------------------------------------------------- diff --git a/sp/src/responserules/runtime/response_types_internal.h b/sp/src/responserules/runtime/response_types_internal.h index 25b6f2d1..08f31185 100644 --- a/sp/src/responserules/runtime/response_types_internal.h +++ b/sp/src/responserules/runtime/response_types_internal.h @@ -366,6 +366,7 @@ namespace ResponseRules I Insert( const char *pName, const T &element ) { + extern const char *ResponseCopyString( const char *in ); char const *pString = ResponseCopyString( pName ); unsigned int hash = RR_HASH( pString ); m_ReverseMap.Insert( hash, pString ); @@ -374,6 +375,7 @@ namespace ResponseRules I Insert( const char *pName ) { + extern const char *ResponseCopyString( const char *in ); char const *pString = ResponseCopyString( pName ); unsigned int hash = RR_HASH( pString ); m_ReverseMap.Insert( hash, pString ); @@ -388,7 +390,7 @@ namespace ResponseRules const char *GetElementName( I i ) { - int k = Key( i ); + int k = this->Key( i ); int slot = m_ReverseMap.Find( k ); if ( slot == m_ReverseMap.InvalidIndex() ) return ""; @@ -397,7 +399,7 @@ namespace ResponseRules const char *GetElementName( I i ) const { - int k = Key( i ); + int k = this->Key( i ); int slot = m_ReverseMap.Find( k ); if ( slot == m_ReverseMap.InvalidIndex() ) return ""; diff --git a/sp/src/tier1/convar.cpp b/sp/src/tier1/convar.cpp index fc27eb74..9d606520 100644 --- a/sp/src/tier1/convar.cpp +++ b/sp/src/tier1/convar.cpp @@ -594,7 +594,7 @@ void ConCommand::Dispatch( const CCommand &command ) } // Command without callback!!! - AssertMsg( 0, ( "Encountered ConCommand '%s' without a callback!\n", GetName() ) ); + AssertMsg( 0, "Encountered ConCommand '%s' without a callback!\n", GetName() ); } From a75b0b7d58b5c78dc527a7be16864a74c8d5c492 Mon Sep 17 00:00:00 2001 From: Alexander 'z33ky' Hirsch <1zeeky@gmail.com> Date: Sun, 25 Apr 2021 22:00:55 +0200 Subject: [PATCH 063/378] Fix spacing --- sp/src/public/responserules/response_types.h | 138 +++++++++---------- 1 file changed, 69 insertions(+), 69 deletions(-) diff --git a/sp/src/public/responserules/response_types.h b/sp/src/public/responserules/response_types.h index a3e8fea3..2e80cc5a 100644 --- a/sp/src/public/responserules/response_types.h +++ b/sp/src/public/responserules/response_types.h @@ -65,16 +65,16 @@ namespace ResponseRules float followup_delay; // 20 const char *followup_target; // 24 -- to whom is this despatched? // AIConceptHandle_t hConcept; - const char *followup_entityiotarget; //< if this rule involves firing entity io - const char *followup_entityioinput; //< if this rule involves firing entity io + const char *followup_entityiotarget; //< if this rule involves firing entity io + const char *followup_entityioinput; //< if this rule involves firing entity io float followup_entityiodelay; bool bFired; - inline bool IsValid( void ) const { return (followup_concept && followup_contexts); } - inline void Invalidate() { followup_concept = NULL; followup_contexts = NULL; } - inline void SetFired( bool fired ) { bFired = fired; } - inline bool HasBeenFired() { return bFired; } - + inline bool IsValid( void ) const { return (followup_concept && followup_contexts); } + inline void Invalidate() { followup_concept = NULL; followup_contexts = NULL; } + inline void SetFired( bool fired ) { bFired = fired; } + inline bool HasBeenFired() { return bFired; } + AI_ResponseFollowup( void ) : followup_concept(NULL), followup_contexts(NULL), followup_delay(0), followup_target(NULL), followup_entityiotarget(NULL), followup_entityioinput(NULL), followup_entityiodelay(0), bFired(false) {}; AI_ResponseFollowup( char *_followup_concept, char *_followup_contexts, float _followup_delay, char *_followup_target, @@ -235,67 +235,67 @@ namespace ResponseRules /// entity, subsequent to the match but BEFORE the dispatch. /// Returns the number of contexts modified. If it returns 0, then /// pSetOnWorld is empty. - static int InterceptWorldSetContexts( CriteriaSet * RESTRICT pFrom, - CriteriaSet * RESTRICT pSetOnWorld ); + static int InterceptWorldSetContexts( CriteriaSet * RESTRICT pFrom, + CriteriaSet * RESTRICT pSetOnWorld ); private: - void RemoveCriteria( int idx, bool bTestForPrefix ); + void RemoveCriteria( int idx, bool bTestForPrefix ); struct CritEntry_t { CritEntry_t() : - criterianame( UTL_INVAL_SYMBOL ), - weight( 0.0f ) - { - value[ 0 ] = 0; - } - - CritEntry_t( const CritEntry_t& src ) - { - criterianame = src.criterianame; - value[ 0 ] = 0; - weight = src.weight; - SetValue( src.value ); - } - - CritEntry_t& operator=( const CritEntry_t& src ) - { - if ( this == &src ) - return *this; - - criterianame = src.criterianame; - weight = src.weight; - SetValue( src.value ); - - return *this; - } - - static bool LessFunc( const CritEntry_t& lhs, const CritEntry_t& rhs ) - { - return lhs.criterianame < rhs.criterianame; - } - - void SetValue( char const *str ) - { - if ( !str ) + criterianame( UTL_INVAL_SYMBOL ), + weight( 0.0f ) { value[ 0 ] = 0; } - else - { - Q_strncpy( value, str, sizeof( value ) ); - } - } - CritSymbol_t criterianame; - char value[ 64 ]; - float weight; + CritEntry_t( const CritEntry_t& src ) + { + criterianame = src.criterianame; + value[ 0 ] = 0; + weight = src.weight; + SetValue( src.value ); + } + + CritEntry_t& operator=( const CritEntry_t& src ) + { + if ( this == &src ) + return *this; + + criterianame = src.criterianame; + weight = src.weight; + SetValue( src.value ); + + return *this; + } + + static bool LessFunc( const CritEntry_t& lhs, const CritEntry_t& rhs ) + { + return lhs.criterianame < rhs.criterianame; + } + + void SetValue( char const *str ) + { + if ( !str ) + { + value[ 0 ] = 0; + } + else + { + Q_strncpy( value, str, sizeof( value ) ); + } + } + + CritSymbol_t criterianame; + char value[ 64 ]; + float weight; }; static CUtlSymbolTable sm_CriteriaSymbols; - typedef CUtlRBTree< CritEntry_t, short > Dict_t; - Dict_t m_Lookup; - int m_nNumPrefixedContexts; // number of contexts prefixed with kAPPLYTOWORLDPREFIX + typedef CUtlRBTree< CritEntry_t, short > Dict_t; + Dict_t m_Lookup; + int m_nNumPrefixedContexts; // number of contexts prefixed with kAPPLYTOWORLDPREFIX bool m_bOverrideOnAppend; }; @@ -457,20 +457,20 @@ namespace ResponseRules return ( index >= 0 && index < ((int)(m_Lookup.Count())) ); } - inline int CriteriaSet::Head() const - { - return m_Lookup.FirstInorder(); - } - - inline int CriteriaSet::Next( int i ) const - { - return m_Lookup.NextInorder(i); - } - - inline const char *CriteriaSet::SymbolToStr( const CritSymbol_t &symbol ) - { - return sm_CriteriaSymbols.String(symbol); - } + inline int CriteriaSet::Head() const + { + return m_Lookup.FirstInorder(); + } + + inline int CriteriaSet::Next( int i ) const + { + return m_Lookup.NextInorder(i); + } + + inline const char *CriteriaSet::SymbolToStr( const CritSymbol_t &symbol ) + { + return sm_CriteriaSymbols.String(symbol); + } } From 036fbda90673c8fd9a5b0d9fde6e7e325ee09be0 Mon Sep 17 00:00:00 2001 From: Alexander 'z33ky' Hirsch <1zeeky@gmail.com> Date: Sun, 25 Apr 2021 22:47:55 +0200 Subject: [PATCH 064/378] Fix strdup() leaks --- sp/src/game/server/ai_speech.cpp | 2 +- sp/src/game/server/effects.cpp | 15 +++---- sp/src/game/server/mapbase/ai_monitor.cpp | 51 +++++++++++++---------- sp/src/game/shared/mapbase/MapEdit.cpp | 7 ++-- 4 files changed, 43 insertions(+), 32 deletions(-) diff --git a/sp/src/game/server/ai_speech.cpp b/sp/src/game/server/ai_speech.cpp index dafad41e..10e7fcfe 100644 --- a/sp/src/game/server/ai_speech.cpp +++ b/sp/src/game/server/ai_speech.cpp @@ -1240,7 +1240,7 @@ char *CAI_Expresser::ParseApplyContext( const char *szContext ) { // If it's really 0, then this is a waste of time Warning("\"%s\" was detected by applyContext operators as an operable number, but it's not.\n", szValue); - return strdup(szContext); + return szContext; } // This is the existing value; will be operated upon and become the final assignment diff --git a/sp/src/game/server/effects.cpp b/sp/src/game/server/effects.cpp index 7b07e157..a07ae1bd 100644 --- a/sp/src/game/server/effects.cpp +++ b/sp/src/game/server/effects.cpp @@ -2511,7 +2511,7 @@ class CBreakableGibShooter : public CBaseEntity DECLARE_DATADESC(); public: - const char *GetRandomTemplateModel( CPointTemplate *pTemplate ); + int GetRandomTemplateModelIndex( CPointTemplate *pTemplate ); void Precache( void ); @@ -2560,19 +2560,20 @@ END_DATADESC() LINK_ENTITY_TO_CLASS( env_break_shooter, CBreakableGibShooter ); -const char *CBreakableGibShooter::GetRandomTemplateModel( CPointTemplate *pTemplate ) +int CBreakableGibShooter::GetRandomTemplateModelIndex( CPointTemplate *pTemplate ) { int iIndex = RandomInt( 0, pTemplate->GetNumTemplates() ); - char *iszTemplate = (char*)(STRING(Templates_FindByIndex(pTemplate->GetTemplateIndexForTemplate(iIndex)))); + char *iszTemplate = strdup(STRING(Templates_FindByIndex(pTemplate->GetTemplateIndexForTemplate(iIndex)))); CEntityMapData entData( iszTemplate ); // This might seem a little messy, but I think it's cheaper than creating the entity. char szModel[MAPKEY_MAXLENGTH]; - if (!entData.ExtractValue("model", szModel)) - return NULL; + bool modelExtracted = entData.ExtractValue("model", szModel); - return strdup(szModel); + free(iszTemplate); + + return modelinfo->GetModelIndex( modelExtracted ? szModel : NULL ); } void CBreakableGibShooter::Precache( void ) @@ -2604,7 +2605,7 @@ void CBreakableGibShooter::Shoot( void ) if (m_iModelType == MODELTYPE_BREAKABLECHUNKS) iModelIndex = modelinfo->GetModelIndex( g_PropDataSystem.GetRandomChunkModel( STRING( GetModelName() ) ) ); else if (m_iModelType == MODELTYPE_TEMPLATE) - iModelIndex = modelinfo->GetModelIndex( GetRandomTemplateModel(pTemplate) ); + iModelIndex = GetRandomTemplateModelIndex( pTemplate ); // All objects except the first one in this run are marked as slaves... int slaveFlag = 0; diff --git a/sp/src/game/server/mapbase/ai_monitor.cpp b/sp/src/game/server/mapbase/ai_monitor.cpp index 754ff56d..fa11a203 100644 --- a/sp/src/game/server/mapbase/ai_monitor.cpp +++ b/sp/src/game/server/mapbase/ai_monitor.cpp @@ -672,6 +672,33 @@ int CAI_Monitor::TranslateScheduleString(const char *schedName) return 0; } +template +static void SetForEachDelimited( CAI_Monitor &monitor, const char *szValue, const char *delimiters, void (CAI_Monitor::*setter)(int), Translator translator) +{ + char *value = strdup(szValue); + char *token = strtok(value, ":"); + while (token) + { + (monitor.*setter)(translator(token)); + + token = strtok(NULL, ":"); + } + free(value); +} + +template +struct CAI_MonitorTranslator +{ + CAI_Monitor &monitor; + + CAI_MonitorTranslator(CAI_Monitor &monitor) : monitor(monitor) {} + + int operator()(const char *value) + { + return (monitor.*translator)(value); + } +}; + //----------------------------------------------------------------------------- // Purpose: Cache user entity field values until spawn is called. // Input : szKeyName - Key to handle. @@ -688,13 +715,7 @@ bool CAI_Monitor::KeyValue( const char *szKeyName, const char *szValue ) } else if (FStrEq(szKeyName, "Conditions")) { - char *token = strtok(strdup(szValue), ":"); - while (token) - { - SetCondition(TranslateConditionString(token)); - - token = strtok(NULL, ":"); - } + SetForEachDelimited(*this, szValue, ":", &CAI_Monitor::SetCondition, CAI_MonitorTranslator<&CAI_Monitor::TranslateConditionString>(*this)); } else if (FStrEq(szKeyName, "SchedulesSimple")) { @@ -703,13 +724,7 @@ bool CAI_Monitor::KeyValue( const char *szKeyName, const char *szValue ) } else if (FStrEq(szKeyName, "Schedules")) { - char *token = strtok(strdup(szValue), ":"); - while (token) - { - SetSchedule(TranslateScheduleString(token)); - - token = strtok(NULL, ":"); - } + SetForEachDelimited(*this, szValue, ":", &CAI_Monitor::SetSchedule, CAI_MonitorTranslator<&CAI_Monitor::TranslateScheduleString>(*this)); } else if (FStrEq(szKeyName, "HintsSimple")) { @@ -718,13 +733,7 @@ bool CAI_Monitor::KeyValue( const char *szKeyName, const char *szValue ) } else if (FStrEq(szKeyName, "Hints")) { - char *token = strtok(strdup(szValue), ":"); - while (token) - { - SetHint(atoi(szValue)); - - token = strtok(NULL, ":"); - } + SetForEachDelimited(*this, szValue, ":", &CAI_Monitor::SetHint, atoi); } else return CBaseEntity::KeyValue( szKeyName, szValue ); diff --git a/sp/src/game/shared/mapbase/MapEdit.cpp b/sp/src/game/shared/mapbase/MapEdit.cpp index 32659964..9ff1db60 100644 --- a/sp/src/game/shared/mapbase/MapEdit.cpp +++ b/sp/src/game/shared/mapbase/MapEdit.cpp @@ -464,7 +464,7 @@ public: { pNodeName = pName->GetName(); - const char *pInputName = NULL; + string_t pInputName = NULL_STRING; variant_t varInputParam; float flInputDelay = 0.0f; CBaseEntity *pActivator = NULL; @@ -480,7 +480,7 @@ public: { // Input name case 0: - pInputName = inputparams; break; + pInputName = AllocPooledString(inputparams); break; // Input parameter case 1: varInputParam.SetString(AllocPooledString(inputparams)); break; @@ -500,9 +500,10 @@ public: iter++; inputparams = strtok(NULL, ","); } + free(pszValue); DebugMsg("MapEdit Debug: Firing input %s on %s\n", pInputName, pNodeName); - g_EventQueue.AddEvent(pNodeName, pInputName, varInputParam, flInputDelay, pActivator, pCaller, iOutputID); + g_EventQueue.AddEvent(pNodeName, STRING(pInputName), varInputParam, flInputDelay, pActivator, pCaller, iOutputID); pName = pName->GetNextKey(); } From d0b6998637e28b23fc9bb30b3e8093b06340c3e8 Mon Sep 17 00:00:00 2001 From: Alexander 'z33ky' Hirsch <1zeeky@gmail.com> Date: Mon, 26 Apr 2021 09:44:12 +0200 Subject: [PATCH 065/378] Simplify CBreakableGibShooter::GetRandomTemplateModelIndex MapEntity_ExtractValue(), as opposed to CEntityMapData, does not require a mutable string. --- sp/src/game/server/effects.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/sp/src/game/server/effects.cpp b/sp/src/game/server/effects.cpp index a07ae1bd..cbe05190 100644 --- a/sp/src/game/server/effects.cpp +++ b/sp/src/game/server/effects.cpp @@ -2563,15 +2563,11 @@ LINK_ENTITY_TO_CLASS( env_break_shooter, CBreakableGibShooter ); int CBreakableGibShooter::GetRandomTemplateModelIndex( CPointTemplate *pTemplate ) { int iIndex = RandomInt( 0, pTemplate->GetNumTemplates() ); - char *iszTemplate = strdup(STRING(Templates_FindByIndex(pTemplate->GetTemplateIndexForTemplate(iIndex)))); - - CEntityMapData entData( iszTemplate ); + const char *szTemplate = STRING(Templates_FindByIndex(pTemplate->GetTemplateIndexForTemplate(iIndex))); // This might seem a little messy, but I think it's cheaper than creating the entity. char szModel[MAPKEY_MAXLENGTH]; - bool modelExtracted = entData.ExtractValue("model", szModel); - - free(iszTemplate); + bool modelExtracted = MapEntity_ExtractValue(szTemplate, "model", szModel); return modelinfo->GetModelIndex( modelExtracted ? szModel : NULL ); } From 54c43dd6ce830158719c3a5aa8c75de68932ed6c Mon Sep 17 00:00:00 2001 From: Blixibon Date: Tue, 27 Apr 2021 10:55:33 -0500 Subject: [PATCH 066/378] Fixed unreliable string pointer in CLogicPlayerProxy::AcceptInput() --- sp/src/game/server/hl2/hl2_player.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sp/src/game/server/hl2/hl2_player.cpp b/sp/src/game/server/hl2/hl2_player.cpp index fe523806..a43cfe32 100644 --- a/sp/src/game/server/hl2/hl2_player.cpp +++ b/sp/src/game/server/hl2/hl2_player.cpp @@ -4734,7 +4734,8 @@ bool CLogicPlayerProxy::AcceptInput( const char *szInputName, CBaseEntity *pActi { DevMsg("logic_playerproxy: Player not found!\n"); - g_EventQueue.AddEvent("!player", szInputName, Value, 0.01f, pActivator, pCaller); + // Need to allocate the string here in case szInputName is freed before the input fires + g_EventQueue.AddEvent("!player", STRING( AllocPooledString(szInputName) ), Value, 0.01f, pActivator, pCaller); } } From 3cd50a6ed4ef6169183d83d365c8fb8bc9ff4058 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Tue, 27 Apr 2021 10:59:39 -0500 Subject: [PATCH 067/378] Added sound pitch scaling and env_microphone detection for sentences --- sp/src/game/server/baseentity.cpp | 2 + sp/src/game/server/baseentity.h | 6 +- sp/src/game/server/envmicrophone.cpp | 122 +++++++++++++++++----- sp/src/game/server/envmicrophone.h | 15 +++ sp/src/game/shared/SoundEmitterSystem.cpp | 39 +++++++ 5 files changed, 159 insertions(+), 25 deletions(-) diff --git a/sp/src/game/server/baseentity.cpp b/sp/src/game/server/baseentity.cpp index d23ba924..95adce8e 100644 --- a/sp/src/game/server/baseentity.cpp +++ b/sp/src/game/server/baseentity.cpp @@ -9523,6 +9523,7 @@ void CBaseEntity::RemoveRecipientsIfNotCloseCaptioning( CRecipientFilter& filter } } +#ifndef MAPBASE // Moved to SoundEmitterSystem.cpp //----------------------------------------------------------------------------- // Purpose: Wrapper to emit a sentence and also a close caption token for the sentence as appropriate. // Input : filter - @@ -9545,6 +9546,7 @@ void CBaseEntity::EmitSentenceByIndex( IRecipientFilter& filter, int iEntIndex, enginesound->EmitSentenceByIndex( filter, iEntIndex, iChannel, iSentenceIndex, flVolume, iSoundlevel, iFlags, iPitch, 0, pOrigin, pDirection, &dummy, bUpdatePositions, soundtime ); } +#endif void CBaseEntity::SetRefEHandle( const CBaseHandle &handle ) diff --git a/sp/src/game/server/baseentity.h b/sp/src/game/server/baseentity.h index 05858b6a..4b5449d6 100644 --- a/sp/src/game/server/baseentity.h +++ b/sp/src/game/server/baseentity.h @@ -1563,7 +1563,11 @@ public: static void EmitCloseCaption( IRecipientFilter& filter, int entindex, char const *token, CUtlVector< Vector >& soundorigins, float duration, bool warnifmissing = false ); static void EmitSentenceByIndex( IRecipientFilter& filter, int iEntIndex, int iChannel, int iSentenceIndex, float flVolume, soundlevel_t iSoundlevel, int iFlags = 0, int iPitch = PITCH_NORM, - const Vector *pOrigin = NULL, const Vector *pDirection = NULL, bool bUpdatePositions = true, float soundtime = 0.0f ); + const Vector *pOrigin = NULL, const Vector *pDirection = NULL, bool bUpdatePositions = true, float soundtime = 0.0f +#ifdef MAPBASE + , int iSpecialDSP = 0, int iSpeakerIndex = 0 // Needed for env_microphone +#endif + ); static bool IsPrecacheAllowed(); static void SetAllowPrecache( bool allow ); diff --git a/sp/src/game/server/envmicrophone.cpp b/sp/src/game/server/envmicrophone.cpp index 29a59ead..23b1758c 100644 --- a/sp/src/game/server/envmicrophone.cpp +++ b/sp/src/game/server/envmicrophone.cpp @@ -19,6 +19,9 @@ #include "soundflags.h" #include "engine/IEngineSound.h" #include "filters.h" +#ifdef MAPBASE +#include "fmtstr.h" +#endif // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -27,6 +30,10 @@ const float MICROPHONE_SETTLE_EPSILON = 0.005; +#ifdef MAPBASE +static ConVar sv_microphones_always_pickup_sentences( "sv_microphones_always_pickup_sentences", "0", FCVAR_NONE, "Allows env_microphones to always detect and play back sentences, regardless of their keyvalues." ); +#endif + // List of env_microphones who want to be told whenever a sound is started static CUtlVector< CHandle > s_Microphones; @@ -236,7 +243,11 @@ void CEnvMicrophone::InputDisable( inputdata_t &inputdata ) m_bDisabled = true; if ( m_hSpeaker ) { +#ifdef MAPBASE + CBaseEntity::StopSound( m_hSpeaker->entindex(), m_nChannel, m_szLastSound ); +#else CBaseEntity::StopSound( m_hSpeaker->entindex(), CHAN_STATIC, m_szLastSound ); +#endif m_szLastSound[0] = 0; // Remove ourselves from the list of active mics @@ -554,31 +565,41 @@ MicrophoneResult_t CEnvMicrophone::SoundPlayed( int entindex, const char *soundn CPASAttenuationFilter filter( m_hSpeaker ); EmitSound_t ep; -#ifdef MAPBASE - ep.m_nChannel = m_nChannel; - if (m_flVolumeScale != 1.0f) - ep.m_flVolume = (flVolume * m_flVolumeScale); -#else - ep.m_nChannel = CHAN_STATIC; - ep.m_flVolume = flVolume; -#endif - ep.m_pSoundName = soundname; - ep.m_SoundLevel = soundlevel; - ep.m_nFlags = iFlags; -#ifdef MAPBASE - if (m_flPitchScale != 1.0f) - ep.m_nPitch = (int)((float)iPitch * m_flPitchScale); - else - ep.m_nPitch = iPitch; - ep.m_pOrigin = &vecOrigin; -#else - ep.m_nPitch = iPitch; - ep.m_pOrigin = &m_hSpeaker->GetAbsOrigin(); -#endif - ep.m_flSoundTime = soundtime; - ep.m_nSpeakerEntity = entindex; - CBaseEntity::EmitSound( filter, m_hSpeaker->entindex(), ep ); +#ifdef MAPBASE + if (m_bHearingSentence) + { + CBaseEntity::EmitSentenceByIndex( filter, m_hSpeaker->entindex(), m_nChannel, atoi(soundname), flVolume, soundlevel, 0, iPitch, &vecOrigin, NULL, true, soundtime, + m_iSpeakerDSPPreset, entindex ); + } + else +#endif + { +#ifdef MAPBASE + ep.m_nChannel = m_nChannel; + if (m_flVolumeScale != 1.0f) + ep.m_flVolume = (flVolume * m_flVolumeScale); + else + ep.m_flVolume = flVolume; + if (m_flPitchScale != 1.0f) + ep.m_nPitch = (int)((float)iPitch * m_flPitchScale); + else + ep.m_nPitch = iPitch; + ep.m_pOrigin = &vecOrigin; +#else + ep.m_nChannel = CHAN_STATIC; + ep.m_flVolume = flVolume; + ep.m_nPitch = iPitch; + ep.m_pOrigin = &m_hSpeaker->GetAbsOrigin(); +#endif + ep.m_pSoundName = soundname; + ep.m_SoundLevel = soundlevel; + ep.m_nFlags = iFlags; + ep.m_flSoundTime = soundtime; + ep.m_nSpeakerEntity = entindex; + + CBaseEntity::EmitSound( filter, m_hSpeaker->entindex(), ep ); + } Q_strncpy( m_szLastSound, soundname, sizeof(m_szLastSound) ); m_OnRoutedSound.FireOutput( this, this, 0 ); @@ -646,3 +667,56 @@ bool CEnvMicrophone::OnSoundPlayed( int entindex, const char *soundname, soundle return bSwallowed; } + +#ifdef MAPBASE +//----------------------------------------------------------------------------- +// Purpose: Called by the sound system whenever a sentence is played so that +// active microphones can have a chance to pick up the sound. +// Output : Returns whether or not the sentence was swallowed by the microphone. +// Swallowed sentences should not be played by the sound system. +//----------------------------------------------------------------------------- +bool CEnvMicrophone::OnSentencePlayed( int entindex, int sentenceIndex, soundlevel_t soundlevel, float flVolume, int iFlags, int iPitch, const Vector *pOrigin, float soundtime, CUtlVector< Vector >& soundorigins ) +{ + bool bSwallowed = false; + + // Loop through all registered microphones and tell them the sound was just played + int iCount = s_Microphones.Count(); + if ( iCount > 0 ) + { + CNumStr szSentenceStr( sentenceIndex ); + + // Iterate backwards because we might be deleting microphones. + for ( int i = iCount - 1; i >= 0; i-- ) + { + if ( s_Microphones[i] && (s_Microphones[i]->ShouldHearSentences() || sv_microphones_always_pickup_sentences.GetBool()) ) + { + // HACKHACK: Don't want to duplicate all of the code, so just use the same function with a new member variable + s_Microphones[i]->ToggleHearingSentence( true ); + MicrophoneResult_t eResult = s_Microphones[i]->SoundPlayed( + entindex, + szSentenceStr, + soundlevel, + flVolume, + iFlags, + iPitch, + pOrigin, + soundtime, + soundorigins ); + s_Microphones[i]->ToggleHearingSentence( false ); + + if ( eResult == MicrophoneResult_Swallow ) + { + // Microphone told us to swallow it + bSwallowed = true; + } + else if ( eResult == MicrophoneResult_Remove ) + { + s_Microphones.FastRemove( i ); + } + } + } + } + + return bSwallowed; +} +#endif diff --git a/sp/src/game/server/envmicrophone.h b/sp/src/game/server/envmicrophone.h index 11527d58..e330099c 100644 --- a/sp/src/game/server/envmicrophone.h +++ b/sp/src/game/server/envmicrophone.h @@ -20,6 +20,9 @@ const int SF_MICROPHONE_SOUND_BULLET_IMPACT = 0x08; const int SF_MICROPHONE_SWALLOW_ROUTED_SOUNDS = 0x10; const int SF_MICROPHONE_SOUND_EXPLOSION = 0x20; const int SF_MICROPHONE_IGNORE_NONATTENUATED = 0x40; +#ifdef MAPBASE +const int SF_MICROPHONE_SOUND_SENTENCE = 0x80; +#endif // Return codes from SoundPlayed @@ -50,6 +53,10 @@ public: void SetSensitivity( float flSensitivity ); void SetSpeakerName( string_t iszSpeakerName ); +#ifdef MAPBASE + bool ShouldHearSentences() const { return HasSpawnFlags( SF_MICROPHONE_SOUND_SENTENCE ); } + inline void ToggleHearingSentence( bool bToggle ) { m_bHearingSentence = bToggle; } +#endif void InputEnable( inputdata_t &inputdata ); void InputDisable( inputdata_t &inputdata ); @@ -67,6 +74,12 @@ public: static bool OnSoundPlayed( int entindex, const char *soundname, soundlevel_t soundlevel, float flVolume, int iFlags, int iPitch, const Vector *pOrigin, float soundtime, CUtlVector< Vector >& soundorigins ); +#ifdef MAPBASE + // Same as above, except for sentences. + static bool OnSentencePlayed( int entindex, int sentenceIndex, soundlevel_t soundlevel, + float flVolume, int iFlags, int iPitch, const Vector *pOrigin, float soundtime, CUtlVector< Vector >& soundorigins ); +#endif + private: // Per-microphone notification that a sound has played. @@ -91,6 +104,8 @@ private: float m_flPitchScale = 1.0f; float m_flVolumeScale = 1.0f; int m_nChannel = CHAN_STATIC; + + bool m_bHearingSentence; // HACKHACK: Allows SoundPlayed() to know when to play a sentence instead #endif COutputFloat m_SoundLevel; // Fired when the sampled volume level changes. diff --git a/sp/src/game/shared/SoundEmitterSystem.cpp b/sp/src/game/shared/SoundEmitterSystem.cpp index e1072b78..76a855d9 100644 --- a/sp/src/game/shared/SoundEmitterSystem.cpp +++ b/sp/src/game/shared/SoundEmitterSystem.cpp @@ -1417,6 +1417,45 @@ int SENTENCEG_Lookup(const char *sample) } #endif +#if defined(MAPBASE) && defined(GAME_DLL) +//----------------------------------------------------------------------------- +// Purpose: Wrapper to emit a sentence and also a close caption token for the sentence as appropriate. +// Input : filter - +// iEntIndex - +// iChannel - +// iSentenceIndex - +// flVolume - +// iSoundlevel - +// iFlags - +// iPitch - +// bUpdatePositions - +// soundtime - +//----------------------------------------------------------------------------- +void CBaseEntity::EmitSentenceByIndex( IRecipientFilter& filter, int iEntIndex, int iChannel, int iSentenceIndex, + float flVolume, soundlevel_t iSoundlevel, int iFlags /*= 0*/, int iPitch /*=PITCH_NORM*/, + const Vector *pOrigin /*=NULL*/, const Vector *pDirection /*=NULL*/, + bool bUpdatePositions /*=true*/, float soundtime /*=0.0f*/, int iSpecialDSP /*= 0*/, int iSpeakerIndex /*= 0*/ ) +{ + CUtlVector< Vector > soundOrigins; + + bool bSwallowed = CEnvMicrophone::OnSentencePlayed( + iEntIndex, + iSentenceIndex, + iSoundlevel, + flVolume, + iFlags, + iPitch, + pOrigin, + soundtime, + soundOrigins ); + if ( bSwallowed ) + return; + + enginesound->EmitSentenceByIndex( filter, iEntIndex, iChannel, iSentenceIndex, + flVolume, iSoundlevel, iFlags, iPitch * GetSoundPitchScale(), iSpecialDSP, pOrigin, pDirection, &soundOrigins, bUpdatePositions, soundtime, iSpeakerIndex ); +} +#endif + void UTIL_EmitAmbientSound( int entindex, const Vector &vecOrigin, const char *samp, float vol, soundlevel_t soundlevel, int fFlags, int pitch, float soundtime /*= 0.0f*/, float *duration /*=NULL*/ ) { #ifdef STAGING_ONLY From 59cb73d1c11e5cf7efa9de6f01fcb142f5ac5815 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Tue, 27 Apr 2021 11:08:17 -0500 Subject: [PATCH 068/378] Clarified what happens when the contributing guidelines are violated --- .github/CONTRIBUTING.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 48256d92..77fa8112 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -34,6 +34,13 @@ All contributions must follow the following rules: use the custom "Mapbase - Source 2013" header used in other Mapbase files as of Mapbase v5.0. You are encouraged to append an "Author(s)" part to that header in your file in order to clarify who wrote it. +Contributions which do not follow these guidelines cannot be accepted into Mapbase. + +Attempting to contribute content which seriously violates the rules above can lead to being blocked from contributing, +especially if done repeatedly. + +--- + If your contribution is accepted, you may be listed in Mapbase's credits and the README's external content list: https://github.com/mapbase-source/source-sdk-2013/wiki/Mapbase-Credits#Contributors https://github.com/mapbase-source/source-sdk-2013/blob/master/README From 8bf258eb75a93b6368895d469edbfbe2d3b5d79c Mon Sep 17 00:00:00 2001 From: Blixibon Date: Tue, 27 Apr 2021 11:08:46 -0500 Subject: [PATCH 069/378] Updated README to reflect recent contributions --- README | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README b/README index bf8b01e1..33cdd010 100644 --- a/README +++ b/README @@ -96,6 +96,7 @@ Direct contributions: - https://github.com/mapbase-source/source-sdk-2013/pull/3 ("playvideo" command playback fix from Avantate) - https://github.com/mapbase-source/source-sdk-2013/pull/60 (Adjustment by RoyaleNoir to one of Saul's VDC changes) - https://github.com/mapbase-source/source-sdk-2013/pull/84 (CS:S viewmodel chirality from 1upD) +- https://github.com/mapbase-source/source-sdk-2013/pull/116 (vgui_movie_display mute keyvalue from Alivebyte/rzkid) - Demo autorecord code provided by Klems - cc_emit crash fix provided by 1upD - Custom HL2 ammo crate models created by Rara (Textures created by Blixibon; This is asset-based and, aside from the SLAM crate, not reflected in the code) @@ -109,10 +110,12 @@ Direct contributions: =-- https://github.com/mapbase-source/source-sdk-2013/pull/59 (New VScript functions and singletons based on API documentation in later Source/Source 2 games) =-- https://github.com/mapbase-source/source-sdk-2013/pull/80 (More VScript changes, including support for extremely flexible client/server messaging) =-- https://github.com/mapbase-source/source-sdk-2013/pull/105 (VScript fixes and optimizations, Vector class extensions, custom convars/commands) +=-- https://github.com/mapbase-source/source-sdk-2013/pull/114 (VScript fixes and extensions) == Contributions from z33ky: =-- https://github.com/mapbase-source/source-sdk-2013/pull/21 (Various GCC/Linux compilation fixes) =-- https://github.com/mapbase-source/source-sdk-2013/pull/95 (Additional GCC/Linux compilation fixes) +=-- https://github.com/mapbase-source/source-sdk-2013/pull/117 (Additional GCC/Linux compilation fixes) //--------------------------------------------------------------------------------------------------------------------------------------------------- From b95c72eb3fb8db4efeb0c0d47f57bad68ec5c1ed Mon Sep 17 00:00:00 2001 From: Alexander 'z33ky' Hirsch <1zeeky@gmail.com> Date: Thu, 29 Apr 2021 18:06:36 +0200 Subject: [PATCH 070/378] Fix viewmodel flip on zoom The fabs() was incorrectly applied only to the viewmodel's FOV instead of the result of that subtracted by the FOV offset. Further it doesn't seem to make sense to use the absolute value of that subtraction; Yes, it does prevent flipping, but it will zoom out again as the FOV decreases. Instead just limit the result of the subtraction to non-negative numbers. --- sp/src/game/client/view.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sp/src/game/client/view.cpp b/sp/src/game/client/view.cpp index 21294735..c78c76fd 100644 --- a/sp/src/game/client/view.cpp +++ b/sp/src/game/client/view.cpp @@ -745,7 +745,7 @@ void CViewRender::SetUpViews() //Adjust the viewmodel's FOV to move with any FOV offsets on the viewer's end #ifdef MAPBASE - view.fovViewmodel = fabs(g_pClientMode->GetViewModelFOV()) - flFOVOffset; + view.fovViewmodel = max(0.001f, g_pClientMode->GetViewModelFOV() - flFOVOffset); #else view.fovViewmodel = g_pClientMode->GetViewModelFOV() - flFOVOffset; #endif From 3b51405cacf457b66fc883c2ae1d703842224dcc Mon Sep 17 00:00:00 2001 From: samisalreadytaken <46823719+samisalreadytaken@users.noreply.github.com> Date: Sat, 8 May 2021 15:16:59 +0300 Subject: [PATCH 071/378] Minor adjustments and cleanup --- sp/src/game/client/vscript_client.nut | 8 +- sp/src/game/server/vscript_server.nut | 8 +- sp/src/game/shared/baseentity_shared.cpp | 18 ++-- .../shared/mapbase/vscript_funcs_shared.cpp | 15 +--- .../shared/mapbase/vscript_singletons.cpp | 83 +++++++++---------- sp/src/vscript/vscript_squirrel.cpp | 5 +- 6 files changed, 61 insertions(+), 76 deletions(-) diff --git a/sp/src/game/client/vscript_client.nut b/sp/src/game/client/vscript_client.nut index 505395da..7b4f2810 100644 --- a/sp/src/game/client/vscript_client.nut +++ b/sp/src/game/client/vscript_client.nut @@ -24,7 +24,13 @@ function IncludeScript( name, scope = null ) function DispatchParticleEffect( particleName, origin, angles, entity = null ) { - DoDispatchParticleEffect( particleName, origin, angles, entity ); + return DoDispatchParticleEffect( particleName, origin, angles, entity ); } +function ImpulseScale( flTargetMass, flDesiredSpeed ) +{ + return flTargetMass * flDesiredSpeed; +} +__Documentation.RegisterHelp( "ImpulseScale", "float ImpulseScale(float, float)", "Returns an impulse scale required to push an object." ); + )vscript"; \ No newline at end of file diff --git a/sp/src/game/server/vscript_server.nut b/sp/src/game/server/vscript_server.nut index deeacf5d..1846cfdd 100644 --- a/sp/src/game/server/vscript_server.nut +++ b/sp/src/game/server/vscript_server.nut @@ -63,10 +63,14 @@ function EntFireByHandle( target, action, value = null, delay = 0.0, activator = function DispatchParticleEffect( particleName, origin, angles, entity = null ) { - DoDispatchParticleEffect( particleName, origin, angles, entity ); + return DoDispatchParticleEffect( particleName, origin, angles, entity ); } -__Documentation.RegisterHelp( "CConvars::GetClientConvarValue", "CConvars::GetClientConvarValue(string, int)", "Returns the convar value for the entindex as a string. Only works with client convars with the FCVAR_USERINFO flag." ); +function ImpulseScale( flTargetMass, flDesiredSpeed ) +{ + return flTargetMass * flDesiredSpeed; +} +__Documentation.RegisterHelp( "ImpulseScale", "float ImpulseScale(float, float)", "Returns an impulse scale required to push an object." ); function __ReplaceClosures( script, scope ) { diff --git a/sp/src/game/shared/baseentity_shared.cpp b/sp/src/game/shared/baseentity_shared.cpp index 207f4544..6b802a25 100644 --- a/sp/src/game/shared/baseentity_shared.cpp +++ b/sp/src/game/shared/baseentity_shared.cpp @@ -2737,6 +2737,8 @@ void CBaseEntity::ScriptContextThink() float flNextThink = FLT_MAX; float flScheduled = 0.0f; + ScriptVariant_t arg = m_hScriptInstance; + for ( int i = 0; i < m_ScriptThinkFuncs.Count(); ++i ) { scriptthinkfunc_t *cur = m_ScriptThinkFuncs[i]; @@ -2766,21 +2768,12 @@ void CBaseEntity::ScriptContextThink() if ( !cur->m_bNoParam ) { #endif - ScriptVariant_t arg = m_hScriptInstance; - if ( g_pScriptVM->ExecuteFunction( cur->m_hfnThink, &arg, 1, &varReturn, NULL, true ) == SCRIPT_ERROR ) - { - cur->m_flNextThink = SCRIPT_NEVER_THINK; - continue; - } + g_pScriptVM->ExecuteFunction( cur->m_hfnThink, &arg, 1, &varReturn, NULL, true ); #ifndef CLIENT_DLL } else { - if ( g_pScriptVM->ExecuteFunction( cur->m_hfnThink, NULL, 0, &varReturn, NULL, true ) == SCRIPT_ERROR ) - { - cur->m_flNextThink = SCRIPT_NEVER_THINK; - continue; - } + g_pScriptVM->ExecuteFunction( cur->m_hfnThink, NULL, 0, &varReturn, NULL, true ); } #endif @@ -2793,6 +2786,7 @@ void CBaseEntity::ScriptContextThink() float flReturn; if ( !varReturn.AssignTo( &flReturn ) ) { + varReturn.Free(); cur->m_flNextThink = SCRIPT_NEVER_THINK; continue; } @@ -2808,7 +2802,7 @@ void CBaseEntity::ScriptContextThink() flNextThink = flReturn; } - cur->m_flNextThink = gpGlobals->curtime + flReturn - 0.001; + cur->m_flNextThink = gpGlobals->curtime + flReturn - 0.001f; } // deferred safe removal diff --git a/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp b/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp index 9fb186c2..e564d2b4 100644 --- a/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp +++ b/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp @@ -679,16 +679,6 @@ static void AddPhysVelocity( HSCRIPT hPhys, const Vector& vecVelocity, const Vec //============================================================================= //============================================================================= -static int ScriptPrecacheModel( const char *modelname ) -{ - return CBaseEntity::PrecacheModel( modelname ); -} - -static void ScriptPrecacheOther( const char *classname ) -{ - UTIL_PrecacheOther( classname ); -} - #ifndef CLIENT_DLL // TODO: Move this? static void ScriptInsertSound( int iType, const Vector &vecOrigin, int iVolume, float flDuration, HSCRIPT hOwner, int soundChannelIndex, HSCRIPT hSoundTarget ) @@ -873,7 +863,6 @@ void RegisterSharedScriptFunctions() 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." ); @@ -896,10 +885,10 @@ void RegisterSharedScriptFunctions() // // Precaching // - ScriptRegisterFunctionNamed( g_pScriptVM, ScriptPrecacheModel, "PrecacheModel", "Precaches a model for later usage." ); + ScriptRegisterFunctionNamed( g_pScriptVM, CBaseEntity::PrecacheModel, "PrecacheModel", "Precaches a model for later usage." ); ScriptRegisterFunction( g_pScriptVM, PrecacheMaterial, "Precaches a material for later usage." ); ScriptRegisterFunction( g_pScriptVM, PrecacheParticleSystem, "Precaches a particle system for later usage." ); - ScriptRegisterFunctionNamed( g_pScriptVM, ScriptPrecacheOther, "PrecacheOther", "Precaches an entity class for later usage." ); + ScriptRegisterFunctionNamed( g_pScriptVM, UTIL_PrecacheOther, "PrecacheOther", "Precaches an entity class for later usage." ); // // NPCs diff --git a/sp/src/game/shared/mapbase/vscript_singletons.cpp b/sp/src/game/shared/mapbase/vscript_singletons.cpp index a39ac570..6aba49af 100644 --- a/sp/src/game/shared/mapbase/vscript_singletons.cpp +++ b/sp/src/game/shared/mapbase/vscript_singletons.cpp @@ -42,7 +42,6 @@ #include "tier0/memdbgon.h" extern IScriptManager *scriptmanager; -CNetMsgScriptHelper *g_ScriptNetMsg = new CNetMsgScriptHelper(); //============================================================================= // Net Prop Manager @@ -401,7 +400,7 @@ private: //int m_nEventTick; static StringHashFunctor Hash; - static inline unsigned int HashContext( const char* c ) { return (c && *c) ? Hash(c) : 0; } + static inline unsigned int HashContext( const char* c ) { return c ? Hash(c) : 0; } inline int GetIndex() { @@ -574,11 +573,10 @@ void CScriptGameEventListener::LoadEventsFromFile( const char *filename, const c void CScriptGameEventListener::DumpEventListeners() { CGMsg( 0, CON_GROUP_VSCRIPT, "--- Script game event listener dump start\n" ); - CGMsg( 0, CON_GROUP_VSCRIPT, "# ADDRESS ID CONTEXT\n" ); + CGMsg( 0, CON_GROUP_VSCRIPT, "# ID CONTEXT\n" ); FOR_EACH_VEC( s_Listeners, i ) { - CGMsg( 0, CON_GROUP_VSCRIPT, " %d (0x%p) %d : %u\n", i, - (void*)s_Listeners[i], + CGMsg( 0, CON_GROUP_VSCRIPT, " %d : %d : %u\n", i, s_Listeners[i]->GetIndex(), s_Listeners[i]->m_iContextHash ); } @@ -755,14 +753,12 @@ bool CScriptGameEventListener::StopListeningToGameEvent( int listener ) void CScriptGameEventListener::StopListeningToAllGameEvents( const char* szContext ) { unsigned int hash = HashContext( szContext ); - - // Iterate from the end so they can be safely removed as they are deleted for ( int i = s_Listeners.Count(); i--; ) { CScriptGameEventListener *pCur = s_Listeners[i]; if ( pCur->m_iContextHash == hash ) { - s_Listeners.Remove(i); // keep list order + s_Listeners.FastRemove(i); delete pCur; } } @@ -1202,10 +1198,7 @@ HSCRIPT CScriptReadWriteFile::KeyValuesRead( const char *szFile ) return hScript; } -#undef SCRIPT_MAX_FILE_READ_SIZE -#undef SCRIPT_MAX_FILE_WRITE_SIZE -#undef SCRIPT_RW_PATH_ID -#undef SCRIPT_RW_FULL_PATH_FMT + //============================================================================= // Network message helper @@ -1215,6 +1208,8 @@ HSCRIPT CScriptReadWriteFile::KeyValuesRead( const char *szFile ) // The custom message name is hashed and sent as word with the message. //============================================================================= +static CNetMsgScriptHelper scriptnetmsg; +CNetMsgScriptHelper *g_ScriptNetMsg = &scriptnetmsg; #ifdef GAME_DLL #define m_MsgIn_() m_MsgIn-> @@ -2181,23 +2176,23 @@ END_SCRIPTDESC(); //============================================================================= // ConVars //============================================================================= -class CScriptConCommand : public ICommandCallback, public ICommandCompletionCallback +class CScriptConCommand : public ConCommand, public ICommandCallback, public ICommandCompletionCallback { + typedef ConCommand BaseClass; + public: ~CScriptConCommand() { Unregister(); - delete m_pBase; } CScriptConCommand( const char *name, HSCRIPT fn, const char *helpString, int flags, ConCommand *pLinked = NULL ) + : BaseClass( name, this, helpString, flags, 0 ), + m_pLinked(pLinked), + m_hCallback(fn), + m_hCompletionCallback(NULL) { - m_pBase = new ConCommand( name, this, helpString, flags, 0 ); - m_pLinked = pLinked; - m_hCallback = fn; - m_hCompletionCallback = NULL; m_nCmdNameLen = V_strlen(name) + 1; - Assert( m_nCmdNameLen - 1 <= 128 ); } @@ -2272,17 +2267,17 @@ public: if (fn) { - if ( !m_pBase->IsRegistered() ) + if ( !BaseClass::IsRegistered() ) return; - m_pBase->m_pCommandCompletionCallback = this; - m_pBase->m_bHasCompletionCallback = true; + BaseClass::m_pCommandCompletionCallback = this; + BaseClass::m_bHasCompletionCallback = true; m_hCompletionCallback = fn; } else { - m_pBase->m_pCommandCompletionCallback = NULL; - m_pBase->m_bHasCompletionCallback = false; + BaseClass::m_pCommandCompletionCallback = NULL; + BaseClass::m_bHasCompletionCallback = false; m_hCompletionCallback = NULL; } } @@ -2291,7 +2286,7 @@ public: { if (fn) { - if ( !m_pBase->IsRegistered() ) + if ( !BaseClass::IsRegistered() ) Register(); if ( m_hCallback ) @@ -2306,8 +2301,8 @@ public: inline void Unregister() { - if ( g_pCVar && m_pBase->IsRegistered() ) - g_pCVar->UnregisterConCommand( m_pBase ); + if ( g_pCVar && BaseClass::IsRegistered() ) + g_pCVar->UnregisterConCommand( this ); if ( g_pScriptVM ) { @@ -2324,30 +2319,29 @@ public: inline void Register() { if ( g_pCVar ) - g_pCVar->RegisterConCommand( m_pBase ); + g_pCVar->RegisterConCommand( this ); } HSCRIPT m_hCallback; + ConCommand *m_pLinked; HSCRIPT m_hCompletionCallback; int m_nCmdNameLen; - ConCommand *m_pLinked; - ConCommand *m_pBase; }; -class CScriptConVar +class CScriptConVar : public ConVar { + typedef ConVar BaseClass; + public: ~CScriptConVar() { Unregister(); - delete m_pBase; } CScriptConVar( const char *pName, const char *pDefaultValue, const char *pHelpString, int flags/*, float fMin, float fMax*/ ) - { - m_pBase = new ConVar( pName, pDefaultValue, flags, pHelpString ); - m_hCallback = NULL; - } + : BaseClass( pName, pDefaultValue, flags, pHelpString ), + m_hCallback(NULL) + {} void SetChangeCallback( HSCRIPT fn ) { @@ -2359,19 +2353,19 @@ public: if (fn) { m_hCallback = fn; - m_pBase->InstallChangeCallback( (FnChangeCallback_t)ScriptConVarCallback ); + BaseClass::InstallChangeCallback( (FnChangeCallback_t)ScriptConVarCallback ); } else { m_hCallback = NULL; - m_pBase->InstallChangeCallback( NULL ); + BaseClass::InstallChangeCallback( NULL ); } } inline void Unregister() { - if ( g_pCVar && m_pBase->IsRegistered() ) - g_pCVar->UnregisterConCommand( m_pBase ); + if ( g_pCVar && BaseClass::IsRegistered() ) + g_pCVar->UnregisterConCommand( this ); if ( g_pScriptVM ) { @@ -2380,7 +2374,6 @@ public: } HSCRIPT m_hCallback; - ConVar *m_pBase; }; static CUtlMap< unsigned int, bool > g_ConVarsBlocked( DefLessFunc(unsigned int) ); @@ -2541,8 +2534,8 @@ void CScriptConvarAccessor::RegisterCommand( const char *name, HSCRIPT fn, const int idx = g_ScriptConCommands.Find(hash); if ( idx == g_ScriptConCommands.InvalidIndex() ) { - ConCommand *pLinked = NULL; - if ( g_pCVar->FindVar(name) || ( ((pLinked = g_pCVar->FindCommand(name)) != NULL) && !IsOverridable(hash) ) ) + ConCommandBase *pBase = g_pCVar->FindCommandBase(name); + if ( pBase && ( !pBase->IsCommand() || !IsOverridable(hash) ) ) { DevWarning( 1, "CScriptConvarAccessor::RegisterCommand unable to register blocked ConCommand: %s\n", name ); return; @@ -2551,7 +2544,7 @@ void CScriptConvarAccessor::RegisterCommand( const char *name, HSCRIPT fn, const if ( !fn ) return; - CScriptConCommand *p = new CScriptConCommand( name, fn, helpString, flags, pLinked ); + CScriptConCommand *p = new CScriptConCommand( name, fn, helpString, flags, static_cast< ConCommand* >(pBase) ); g_ScriptConCommands.Insert( hash, p ); } else @@ -2589,7 +2582,7 @@ void CScriptConvarAccessor::RegisterConvar( const char *name, const char *pDefau int idx = g_ScriptConVars.Find(hash); if ( idx == g_ScriptConVars.InvalidIndex() ) { - if ( g_pCVar->FindVar(name) || g_pCVar->FindCommand(name) ) + if ( g_pCVar->FindCommandBase(name) ) { DevWarning( 1, "CScriptConvarAccessor::RegisterConvar unable to register blocked ConCommand: %s\n", name ); return; diff --git a/sp/src/vscript/vscript_squirrel.cpp b/sp/src/vscript/vscript_squirrel.cpp index b1e250b1..f710b553 100644 --- a/sp/src/vscript/vscript_squirrel.cpp +++ b/sp/src/vscript/vscript_squirrel.cpp @@ -862,11 +862,10 @@ namespace SQVector float x = 0.0f, y = 0.0f, z = 0.0f; - if ( sscanf( szInput, "%f %f %f", &x, &y, &z ) < 3 ) // UTIL_StringToVector + if ( sscanf( szInput, "%f %f %f", &x, &y, &z ) < 3 ) { - // Don't throw, return null while invalidating the input vector. + // Return null while invalidating the input vector. // This allows the user to easily check for input errors without halting. - //return sq_throwerror(vm, "invalid KV string"); sq_pushnull(vm); *v1 = vec3_invalid; From c37f8eefb7546d0486472b7d042b703844f4a208 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sun, 9 May 2021 11:34:38 -0500 Subject: [PATCH 072/378] Revisited hook handler based on suggestions and new information --- sp/src/public/vscript/ivscript.h | 5 + sp/src/vscript/vscript_squirrel.cpp | 20 +++- sp/src/vscript/vscript_squirrel.nut | 150 ++++++++++++++++------------ 3 files changed, 107 insertions(+), 68 deletions(-) diff --git a/sp/src/public/vscript/ivscript.h b/sp/src/public/vscript/ivscript.h index a1f24ce6..9db7c106 100644 --- a/sp/src/public/vscript/ivscript.h +++ b/sp/src/public/vscript/ivscript.h @@ -889,6 +889,11 @@ public: // External enums //-------------------------------------------------------- virtual void RegisterEnum( ScriptEnumDesc_t *pEnumDesc ) = 0; + + //-------------------------------------------------------- + // External hooks + //-------------------------------------------------------- + virtual void RegisterHook( ScriptHook_t *pHookDesc ) = 0; #endif //-------------------------------------------------------- diff --git a/sp/src/vscript/vscript_squirrel.cpp b/sp/src/vscript/vscript_squirrel.cpp index cde074f0..a1ba928b 100644 --- a/sp/src/vscript/vscript_squirrel.cpp +++ b/sp/src/vscript/vscript_squirrel.cpp @@ -187,6 +187,11 @@ public: // External enums //-------------------------------------------------------- virtual void RegisterEnum(ScriptEnumDesc_t *pEnumDesc) override; + + //-------------------------------------------------------- + // External hooks + //-------------------------------------------------------- + virtual void RegisterHook(ScriptHook_t *pHookDesc) override; //-------------------------------------------------------- // External instances. Note class will be auto-registered. @@ -2299,7 +2304,7 @@ HSCRIPT SquirrelVM::LookupHookFunction(const char *pszEventName, HSCRIPT hScope, sq_pushroottable(vm_); sq_pushstring(vm_, "Hooks", -1); sq_get(vm_, -2); - sq_pushstring(vm_, "CallHooks", -1); + sq_pushstring(vm_, "Call", -1); sq_get(vm_, -2); HSQOBJECT obj; @@ -2328,8 +2333,8 @@ ScriptStatus_t SquirrelVM::ExecuteHookFunction(const char *pszEventName, HSCRIPT // TODO: Run in hook scope sq_pushroottable(vm_); - sq_pushstring(vm_, pszEventName, -1); sq_pushobject(vm_, *((HSQOBJECT*)hScope)); + sq_pushstring(vm_, pszEventName, -1); for (int i = 0; i < nArgs; ++i) { @@ -2602,6 +2607,17 @@ void SquirrelVM::RegisterEnum(ScriptEnumDesc_t* pEnumDesc) RegisterEnumDocumentation(vm_, pEnumDesc); } +void SquirrelVM::RegisterHook(ScriptHook_t* pHookDesc) +{ + SquirrelSafeCheck safeCheck(vm_); + Assert(pHookDesc); + + if (!pHookDesc) + return; + + RegisterHookDocumentation(vm_, pHookDesc, pHookDesc->m_desc, nullptr); +} + HSCRIPT SquirrelVM::RegisterInstance(ScriptClassDesc_t* pDesc, void* pInstance, bool bAllowDestruct) { SquirrelSafeCheck safeCheck(vm_); diff --git a/sp/src/vscript/vscript_squirrel.nut b/sp/src/vscript/vscript_squirrel.nut index 0c48bb87..8fa8fb58 100644 --- a/sp/src/vscript/vscript_squirrel.nut +++ b/sp/src/vscript/vscript_squirrel.nut @@ -125,89 +125,107 @@ class CSimpleCallChainer //--------------------------------------------------------- // Hook handler //--------------------------------------------------------- -Hooks <- { Registered = {} } +local s_List = {} -function Hooks::Add( scope, event, func, name ) +Hooks <- { - Hooks.Registered[name] <- [event, scope, func]; -} - -function Hooks::Remove( name ) -{ - Hooks.Registered.rawdelete(name); -} - -function Hooks::ScopeHookedToEvent( scope, event ) -{ - //printl("Running ScopeHookedToEvent()") - foreach (elem in Hooks.Registered) + // table, string, closure, string + function Add( scope, event, callback, context ) { - if (elem[1] == scope && elem[0] == event) - return true + if ( typeof callback != "function" ) + throw "invalid callback param" + + if ( !(scope in s_List) ) + s_List[scope] <- {} + + local t = s_List[scope] + + if ( !(event in t) ) + t[event] <- {} + + t[event][context] <- callback } - return false -} -function Hooks::CallHooks(event, scope, ...) -{ - //printl("vargv.len() = " + vargv.len()) - switch (vargv.len()) + function Remove( context, event = null ) { - case 0: - foreach (elem in Hooks.Registered) + if ( event ) + { + foreach( k,scope in s_List ) { - if (elem[0] == event && elem[1] == scope) - return elem[2]() - } - break; + if ( event in scope ) + { + local t = scope[event] + if ( context in t ) + { + delete t[context] + } - case 1: - foreach (elem in Hooks.Registered) - { - if (elem[0] == event && elem[1] == scope) - return elem[2](vargv[0]) - } - break; + // cleanup? + if ( !t.len() ) + delete scope[event] + } - case 2: - foreach (elem in Hooks.Registered) - { - if (elem[0] == event && elem[1] == scope) - return elem[2](vargv[0], vargv[1]) + // cleanup? + if ( !scope.len() ) + delete s_List[k] } - break; + } + else + { + foreach( k,scope in s_List ) + { + foreach( kk,ev in scope ) + { + if ( context in ev ) + { + delete ev[context] + } - case 3: - foreach (elem in Hooks.Registered) - { - if (elem[0] == event && elem[1] == scope) - return elem[2](vargv[0], vargv[1], vargv[2]) - } - break; + // cleanup? + if ( !ev.len() ) + delete scope[kk] + } - case 4: - foreach (elem in Hooks.Registered) - { - if (elem[0] == event && elem[1] == scope) - return elem[2](vargv[0], vargv[1], vargv[2], vargv[3]) + // cleanup? + if ( !scope.len() ) + delete s_List[k] } - break; + } + } - case 5: - foreach (elem in Hooks.Registered) - { - if (elem[0] == event && elem[1] == scope) - return elem[2](vargv[0], vargv[1], vargv[2], vargv[3], vargv[4]) - } - break; + function Call( scope, event, ... ) + { + local firstReturn = null - case 6: - foreach (elem in Hooks.Registered) + if ( scope in s_List ) + { + local t = s_List[scope] + if ( event in t ) { - if (elem[0] == event && elem[1] == scope) - return elem[2](vargv[0], vargv[1], vargv[2], vargv[3], vargv[4], vargv[5]) + foreach( context, callback in t[event] ) + { + printf( "(%.4f) Calling hook '%s' of context '%s'\n", Time(), event, context ) + vargv.insert(0,scope) + + local curReturn = callback.acall(vargv) + if (firstReturn == null) + firstReturn = curReturn + } } - break; + } + + return firstReturn + } + + function ScopeHookedToEvent( scope, event ) + { + if ( scope in s_List ) + { + if (event in s_List[scope]) + return true + } + + return false } } From c62d86e34088685fca17f6aa2cbfdfc70793bc99 Mon Sep 17 00:00:00 2001 From: samisalreadytaken <46823719+samisalreadytaken@users.noreply.github.com> Date: Mon, 10 May 2021 00:05:08 +0300 Subject: [PATCH 073/378] Added developer check on script documentation registration --- sp/src/vscript/vscript_squirrel.cpp | 32 ++++++++++++++++++++ sp/src/vscript/vscript_squirrel.nut | 45 +++++++++++++++++++++++++---- 2 files changed, 71 insertions(+), 6 deletions(-) diff --git a/sp/src/vscript/vscript_squirrel.cpp b/sp/src/vscript/vscript_squirrel.cpp index f710b553..59326ce9 100644 --- a/sp/src/vscript/vscript_squirrel.cpp +++ b/sp/src/vscript/vscript_squirrel.cpp @@ -33,11 +33,14 @@ #include "tier1/utlbuffer.h" #include "tier1/mapbase_con_groups.h" +#include "tier1/convar.h" #include "vscript_squirrel.nut" #include +extern ConVar developer; + struct WriteStateMap { CUtlMap cache; @@ -1752,6 +1755,9 @@ const char * ScriptDataTypeToName(ScriptDataType_t datatype) void RegisterDocumentation(HSQUIRRELVM vm, const ScriptFuncDescriptor_t& pFuncDesc, ScriptClassDesc_t* pClassDesc = nullptr) { + if ( !developer.GetInt() ) + return; + SquirrelSafeCheck safeCheck(vm); if (pFuncDesc.m_pszDescription && pFuncDesc.m_pszDescription[0] == SCRIPT_HIDE[0]) @@ -1791,6 +1797,9 @@ void RegisterDocumentation(HSQUIRRELVM vm, const ScriptFuncDescriptor_t& pFuncDe void RegisterClassDocumentation(HSQUIRRELVM vm, const ScriptClassDesc_t* pClassDesc) { + if ( !developer.GetInt() ) + return; + SquirrelSafeCheck safeCheck(vm); const char *name = pClassDesc->m_pszScriptName; @@ -1823,6 +1832,9 @@ void RegisterClassDocumentation(HSQUIRRELVM vm, const ScriptClassDesc_t* pClassD void RegisterEnumDocumentation(HSQUIRRELVM vm, const ScriptEnumDesc_t* pClassDesc) { + if ( !developer.GetInt() ) + return; + SquirrelSafeCheck safeCheck(vm); if (pClassDesc->m_pszDescription && pClassDesc->m_pszDescription[0] == SCRIPT_HIDE[0]) @@ -1840,6 +1852,9 @@ void RegisterEnumDocumentation(HSQUIRRELVM vm, const ScriptEnumDesc_t* pClassDes void RegisterConstantDocumentation( HSQUIRRELVM vm, const ScriptConstantBinding_t* pConstDesc, const char *pszAsString, ScriptEnumDesc_t* pEnumDesc = nullptr ) { + if ( !developer.GetInt() ) + return; + SquirrelSafeCheck safeCheck(vm); if (pConstDesc->m_pszDescription && pConstDesc->m_pszDescription[0] == SCRIPT_HIDE[0]) @@ -1868,6 +1883,9 @@ void RegisterConstantDocumentation( HSQUIRRELVM vm, const ScriptConstantBinding_ void RegisterHookDocumentation(HSQUIRRELVM vm, const ScriptHook_t* pHook, const ScriptFuncDescriptor_t& pFuncDesc, ScriptClassDesc_t* pClassDesc = nullptr) { + if ( !developer.GetInt() ) + return; + SquirrelSafeCheck safeCheck(vm); if (pFuncDesc.m_pszDescription && pFuncDesc.m_pszDescription[0] == SCRIPT_HIDE[0]) @@ -1910,6 +1928,9 @@ void RegisterHookDocumentation(HSQUIRRELVM vm, const ScriptHook_t* pHook, const void RegisterMemberDocumentation(HSQUIRRELVM vm, const ScriptMemberDesc_t& pDesc, ScriptClassDesc_t* pClassDesc = nullptr) { + if ( !developer.GetInt() ) + return; + SquirrelSafeCheck safeCheck(vm); if (pDesc.m_pszDescription && pDesc.m_pszDescription[0] == SCRIPT_HIDE[0]) @@ -1937,6 +1958,12 @@ void RegisterMemberDocumentation(HSQUIRRELVM vm, const ScriptMemberDesc_t& pDesc CallDocumentationRegisterFunction( 3 ); } +SQInteger GetDeveloperLevel(HSQUIRRELVM vm) +{ + sq_pushinteger( vm, developer.GetInt() ); + return 1; +} + bool SquirrelVM::Init() { @@ -2004,6 +2031,11 @@ bool SquirrelVM::Init() sq_pop(vm_, 1); } + sq_pushstring( vm_, "developer", -1 ); + sq_newclosure( vm_, &GetDeveloperLevel, 0 ); + //sq_setnativeclosurename( vm_, -1, "developer" ); + sq_newslot( vm_, -3, SQFalse ); + sq_pop(vm_, 1); } diff --git a/sp/src/vscript/vscript_squirrel.nut b/sp/src/vscript/vscript_squirrel.nut index f12d385b..f87aad96 100644 --- a/sp/src/vscript/vscript_squirrel.nut +++ b/sp/src/vscript/vscript_squirrel.nut @@ -122,14 +122,26 @@ class CSimpleCallChainer chain = null; } +local developer = (delete developer)() + __Documentation <- {} -local DocumentedFuncs = {} -local DocumentedClasses = {} -local DocumentedEnums = {} -local DocumentedConsts = {} -local DocumentedHooks = {} -local DocumentedMembers = {} +local DocumentedFuncs +local DocumentedClasses +local DocumentedEnums +local DocumentedConsts +local DocumentedHooks +local DocumentedMembers + +if (developer) +{ + DocumentedFuncs = {} + DocumentedClasses = {} + DocumentedEnums = {} + DocumentedConsts = {} + DocumentedHooks = {} + DocumentedMembers = {} +} local function AddAliasedToTable(name, signature, description, table) { @@ -149,6 +161,9 @@ local function AddAliasedToTable(name, signature, description, table) function __Documentation::RegisterHelp(name, signature, description) { + if ( !developer ) + return + if (description.len() && description[0] == '#') { AddAliasedToTable(name, signature, description, DocumentedFuncs) @@ -161,16 +176,25 @@ function __Documentation::RegisterHelp(name, signature, description) function __Documentation::RegisterClassHelp(name, baseclass, description) { + if ( !developer ) + return + DocumentedClasses[name] <- [baseclass, description]; } function __Documentation::RegisterEnumHelp(name, num_elements, description) { + if ( !developer ) + return + DocumentedEnums[name] <- [num_elements, description]; } function __Documentation::RegisterConstHelp(name, signature, description) { + if ( !developer ) + return + if (description.len() && description[0] == '#') { AddAliasedToTable(name, signature, description, DocumentedConsts) @@ -183,11 +207,17 @@ function __Documentation::RegisterConstHelp(name, signature, description) function __Documentation::RegisterHookHelp(name, signature, description) { + if ( !developer ) + return + DocumentedHooks[name] <- [signature, description]; } function __Documentation::RegisterMemberHelp(name, signature, description) { + if ( !developer ) + return + DocumentedMembers[name] <- [signature, description]; } @@ -317,6 +347,9 @@ local function PrintMatchesInDocList(pattern, list, printfunc) function __Documentation::PrintHelp(pattern = "*") { + if ( !developer ) + return + local patternLower = pattern.tolower(); // Have a specific order From 184be1a794f7c23ffdb9eade31a3804268732382 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Tue, 11 May 2021 10:10:44 -0500 Subject: [PATCH 074/378] Added a way to override climb node lineup linkage via target node keyvalue --- sp/src/game/server/ai_hint.h | 7 +++++++ sp/src/game/server/ai_initutils.cpp | 6 +++++- sp/src/game/server/ai_networkmanager.cpp | 10 ++++++++++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/sp/src/game/server/ai_hint.h b/sp/src/game/server/ai_hint.h index 25fd4fdb..60052ded 100644 --- a/sp/src/game/server/ai_hint.h +++ b/sp/src/game/server/ai_hint.h @@ -289,6 +289,11 @@ public: void SetHintType( int hintType, bool force = false ); string_t HintActivityName( void ) const { return m_NodeData.iszActivityName; } int GetTargetNode( void ) const { return m_nTargetNodeID; } +#ifdef MAPBASE + // HACKHACK: This is for when target nodes need to be accessed before being sorted into engine IDs + int GetTargetWCNodeID( void ) const { return m_NodeData.nTargetWCNodeID; } + int GetWCNodeID( void ) const { return m_NodeData.nWCNodeID; } +#endif bool IsDisabled( void ) const { return (m_NodeData.iDisabled != 0); } void SetDisabled( bool bDisabled ) { m_NodeData.iDisabled = bDisabled; } void DisableForSeconds( float flSeconds ); @@ -319,7 +324,9 @@ public: const char* ScriptGetHintActivity() { return STRING( HintActivityName() ); } #endif +#ifndef MAPBASE private: +#endif void Spawn( void ); virtual void Activate(); virtual void UpdateOnRemove( void ); diff --git a/sp/src/game/server/ai_initutils.cpp b/sp/src/game/server/ai_initutils.cpp index 8c476719..62d5c6ec 100644 --- a/sp/src/game/server/ai_initutils.cpp +++ b/sp/src/game/server/ai_initutils.cpp @@ -227,7 +227,11 @@ int CNodeEnt::Spawn( const char *pMapData ) // --------------------------------------------------------------------------------- CAI_Hint *pHint = NULL; - if ( ClassMatches( "info_node_hint" ) || ClassMatches( "info_node_air_hint" ) ) + if ( ClassMatches( "info_node_hint" ) || ClassMatches( "info_node_air_hint" ) +#ifdef MAPBASE + || ClassMatches( "info_node_climb" ) // Climb nodes contain hint data in the FGD +#endif + ) { if ( m_NodeData.nHintType || m_NodeData.strGroup != NULL_STRING || m_NodeData.strEntityName != NULL_STRING ) { diff --git a/sp/src/game/server/ai_networkmanager.cpp b/sp/src/game/server/ai_networkmanager.cpp index 8f470a47..0d1f71e4 100644 --- a/sp/src/game/server/ai_networkmanager.cpp +++ b/sp/src/game/server/ai_networkmanager.cpp @@ -3059,6 +3059,16 @@ int CAI_NetworkBuilder::ComputeConnection( CAI_Node *pSrcNode, CAI_Node *pDestNo } else { +#ifdef MAPBASE + // This is kind of a hack since target node IDs are designed to be used *after* the nodegraph is generated. + // However, for the purposes of forcing a climb connection outside of regular lineup bounds, it works. + if (pSrcNode->GetHint() && pDestNode->GetHint() && + (pSrcNode->GetHint()->GetTargetWCNodeID() == pDestNode->GetHint()->GetWCId() || pDestNode->GetHint()->GetTargetWCNodeID() == pSrcNode->GetHint()->GetWCId())) + { + DebugConnectMsg( srcId, destId, " Ignoring climbing lineup due to manual target ID linkage\n" ); + } + else +#endif if ( !IsInLineForClimb(srcPos, UTIL_YawToVector( pSrcNode->m_flYaw ), destPos, UTIL_YawToVector( pDestNode->m_flYaw ) ) ) { Assert( !IsInLineForClimb(destPos, UTIL_YawToVector( pDestNode->m_flYaw ), srcPos, UTIL_YawToVector( pSrcNode->m_flYaw ) ) ); From 0bd1f5fb592a2d0574a6f6850b3961d85bdfd274 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Tue, 11 May 2021 10:12:37 -0500 Subject: [PATCH 075/378] Fixed NPCs with death animations extinguishing their fires before they should be extinguished --- sp/src/game/server/EntityFlame.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sp/src/game/server/EntityFlame.cpp b/sp/src/game/server/EntityFlame.cpp index d3a1be10..80217efb 100644 --- a/sp/src/game/server/EntityFlame.cpp +++ b/sp/src/game/server/EntityFlame.cpp @@ -242,7 +242,12 @@ void CEntityFlame::FlameThink( void ) } CAI_BaseNPC *pNPC = m_hEntAttached->MyNPCPointer(); +#ifdef MAPBASE + // Don't extingish if the NPC is still dying + if ( pNPC && !pNPC->IsAlive() && pNPC->m_lifeState != LIFE_DYING ) +#else if ( pNPC && !pNPC->IsAlive() ) +#endif { UTIL_Remove( this ); // Notify the NPC that it's no longer burning! From 051a2176702a5d2be35c30fb88a986fdd864ccdd Mon Sep 17 00:00:00 2001 From: Blixibon Date: Tue, 11 May 2021 10:14:39 -0500 Subject: [PATCH 076/378] Added proper ACT_IDLE_ON_FIRE handling for Combine soldiers --- sp/src/game/server/hl2/npc_combine.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sp/src/game/server/hl2/npc_combine.cpp b/sp/src/game/server/hl2/npc_combine.cpp index d4ce19ac..15c12c76 100644 --- a/sp/src/game/server/hl2/npc_combine.cpp +++ b/sp/src/game/server/hl2/npc_combine.cpp @@ -1557,6 +1557,13 @@ Activity CNPC_Combine::NPC_BackupActivity( Activity eNewActivity ) else if (eNewActivity == ACT_RUN) return ACT_RUN_RIFLE; + // Some models might not contain ACT_COMBINE_BUGBAIT, which the soldier model uses instead of ACT_IDLE_ON_FIRE. + // Contrariwise, soldiers may be called to use ACT_IDLE_ON_FIRE in other parts of the AI and need to translate to ACT_COMBINE_BUGBAIT. + if (eNewActivity == ACT_COMBINE_BUGBAIT) + return ACT_IDLE_ON_FIRE; + else if (eNewActivity == ACT_IDLE_ON_FIRE) + return ACT_COMBINE_BUGBAIT; + return BaseClass::NPC_BackupActivity( eNewActivity ); } #endif From 6392d9ab7c011dd26db5242cf0c1e2bcf49c6bb4 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Tue, 11 May 2021 10:45:48 -0500 Subject: [PATCH 077/378] Added various misc. stubs and utility code from the Alien Swarm SDK --- sp/src/game/client/c_baseanimating.cpp | 13 ++++++++++++- sp/src/game/client/c_baseanimating.h | 4 ++++ sp/src/game/server/ai_basenpc.h | 3 ++- sp/src/game/server/baseanimating.cpp | 5 +++++ sp/src/game/server/baseanimating.h | 1 + 5 files changed, 24 insertions(+), 2 deletions(-) diff --git a/sp/src/game/client/c_baseanimating.cpp b/sp/src/game/client/c_baseanimating.cpp index 640459e5..6378e109 100644 --- a/sp/src/game/client/c_baseanimating.cpp +++ b/sp/src/game/client/c_baseanimating.cpp @@ -4808,12 +4808,18 @@ void C_BaseAnimating::GetRagdollInitBoneArrays( matrix3x4_t *pDeltaBones0, matri } } +C_ClientRagdoll *C_BaseAnimating::CreateClientRagdoll( bool bRestoring ) +{ + //DevMsg( "Creating ragdoll at tick %d\n", gpGlobals->tickcount ); + return new C_ClientRagdoll( bRestoring ); +} + C_BaseAnimating *C_BaseAnimating::CreateRagdollCopy() { //Adrian: We now create a separate entity that becomes this entity's ragdoll. //That way the server side version of this entity can go away. //Plus we can hook save/restore code to these ragdolls so they don't fall on restore anymore. - C_ClientRagdoll *pRagdoll = new C_ClientRagdoll( false ); + C_ClientRagdoll *pRagdoll = CreateClientRagdoll( false ); if ( pRagdoll == NULL ) return NULL; @@ -5366,6 +5372,11 @@ void C_BaseAnimating::StudioFrameAdvance() if ( flNewCycle < 0.0f || flNewCycle >= 1.0f ) { + if (flNewCycle >= 1.0f) + { + ReachedEndOfSequence(); + } + if ( IsSequenceLooping( hdr, GetSequence() ) ) { flNewCycle -= (int)(flNewCycle); diff --git a/sp/src/game/client/c_baseanimating.h b/sp/src/game/client/c_baseanimating.h index 50b3659b..53372e8d 100644 --- a/sp/src/game/client/c_baseanimating.h +++ b/sp/src/game/client/c_baseanimating.h @@ -38,6 +38,7 @@ class C_BaseClientShader */ class IRagdoll; +class C_ClientRagdoll; class CIKContext; class CIKState; class ConVar; @@ -301,6 +302,7 @@ public: bool IsRagdoll() const; bool IsAboutToRagdoll() const; virtual C_BaseAnimating *BecomeRagdollOnClient(); + virtual C_ClientRagdoll *CreateClientRagdoll( bool bRestoring = false ); C_BaseAnimating *CreateRagdollCopy(); bool InitAsClientRagdoll( const matrix3x4_t *pDeltaBones0, const matrix3x4_t *pDeltaBones1, const matrix3x4_t *pCurrentBonePosition, float boneDt, bool bFixedConstraints=false ); void IgniteRagdoll( C_BaseAnimating *pSource ); @@ -354,6 +356,8 @@ public: void ClientSideAnimationChanged(); virtual unsigned int ComputeClientSideAnimationFlags(); + virtual void ReachedEndOfSequence() { return; } + virtual void ResetClientsideFrame( void ) { SetCycle( 0 ); } void SetCycle( float flCycle ); diff --git a/sp/src/game/server/ai_basenpc.h b/sp/src/game/server/ai_basenpc.h index e032e990..dd326d80 100644 --- a/sp/src/game/server/ai_basenpc.h +++ b/sp/src/game/server/ai_basenpc.h @@ -667,6 +667,7 @@ public: virtual bool ShouldAlwaysThink(); void ForceGatherConditions() { m_bForceConditionsGather = true; SetEfficiency( AIE_NORMAL ); } // Force an NPC out of PVS to call GatherConditions on next think + bool IsForceGatherConditionsSet() { return m_bForceConditionsGather; } virtual float LineOfSightDist( const Vector &vecDir = vec3_invalid, float zEye = FLT_MAX ); @@ -960,7 +961,7 @@ public: void RemoveSleepFlags( int flags ) { m_SleepFlags &= ~flags; } bool HasSleepFlags( int flags ) { return (m_SleepFlags & flags) == flags; } - void UpdateSleepState( bool bInPVS ); + virtual void UpdateSleepState( bool bInPVS ); virtual void Wake( bool bFireOutput = true ); #ifdef MAPBASE // A version of Wake() that takes an activator diff --git a/sp/src/game/server/baseanimating.cpp b/sp/src/game/server/baseanimating.cpp index 788edc27..cc578df0 100644 --- a/sp/src/game/server/baseanimating.cpp +++ b/sp/src/game/server/baseanimating.cpp @@ -506,6 +506,11 @@ void CBaseAnimating::StudioFrameAdvanceInternal( CStudioHdr *pStudioHdr, float f float flNewCycle = GetCycle() + flCycleDelta; if (flNewCycle < 0.0 || flNewCycle >= 1.0) { + if (flNewCycle >= 1.0f) + { + ReachedEndOfSequence(); + } + if (m_bSequenceLoops) { flNewCycle -= (int)(flNewCycle); diff --git a/sp/src/game/server/baseanimating.h b/sp/src/game/server/baseanimating.h index 8f0e0aa8..b45f96b6 100644 --- a/sp/src/game/server/baseanimating.h +++ b/sp/src/game/server/baseanimating.h @@ -84,6 +84,7 @@ public: virtual void StudioFrameAdvance(); // advance animation frame to some time in the future void StudioFrameAdvanceManual( float flInterval ); bool IsValidSequence( int iSequence ); + virtual void ReachedEndOfSequence() { return; } inline float GetPlaybackRate(); inline void SetPlaybackRate( float rate ); From 6f515a2d34a00780524913a4301296e9a34b4981 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Tue, 11 May 2021 10:46:30 -0500 Subject: [PATCH 078/378] Added VScript functions for bone attachments and transforming bone matrices --- sp/src/game/client/c_baseanimating.cpp | 67 ++++++++++++++++++++++++-- sp/src/game/client/c_baseanimating.h | 6 +++ 2 files changed, 70 insertions(+), 3 deletions(-) diff --git a/sp/src/game/client/c_baseanimating.cpp b/sp/src/game/client/c_baseanimating.cpp index 6378e109..c8208e6a 100644 --- a/sp/src/game/client/c_baseanimating.cpp +++ b/sp/src/game/client/c_baseanimating.cpp @@ -294,6 +294,7 @@ END_SCRIPTDESC(); ScriptHook_t C_BaseAnimating::g_Hook_OnClientRagdoll; ScriptHook_t C_BaseAnimating::g_Hook_FireEvent; +ScriptHook_t C_BaseAnimating::g_Hook_BuildTransformations; #endif BEGIN_ENT_SCRIPTDESC( C_BaseAnimating, C_BaseEntity, "Animating models client-side" ) @@ -310,6 +311,14 @@ BEGIN_ENT_SCRIPTDESC( C_BaseAnimating, C_BaseEntity, "Animating models client-si DEFINE_SCRIPTFUNC( LookupBone, "Get the named bone id" ) DEFINE_SCRIPTFUNC_NAMED( ScriptGetBoneTransform, "GetBoneTransform", "Get the transform for the specified bone" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptSetBoneTransform, "SetBoneTransform", "Set the transform for the specified bone" ) + + DEFINE_SCRIPTFUNC_NAMED( ScriptAttachEntityToBone, "AttachEntityToBone", "Attaches this entity to the specified target and bone. Also allows for optional local position offset" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptRemoveBoneAttachment, "RemoveBoneAttachment", "Removes the specified bone attachment" ) + //DEFINE_SCRIPTFUNC( RemoveBoneAttachments, "Removes all bone attachments" ) + DEFINE_SCRIPTFUNC( DestroyBoneAttachments, "Destroys all bone attachments" ) + DEFINE_SCRIPTFUNC( GetNumBoneAttachments, "Gets the number of bone attachments" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptGetBoneAttachment, "GetBoneAttachment", "Gets the specified bone attachment" ) DEFINE_SCRIPTFUNC( SetBodygroup, "Sets a bodygroup") DEFINE_SCRIPTFUNC( GetBodygroup, "Gets a bodygroup" ) @@ -354,6 +363,9 @@ BEGIN_ENT_SCRIPTDESC( C_BaseAnimating, C_BaseEntity, "Animating models client-si DEFINE_SCRIPTHOOK_PARAM( "event", FIELD_INTEGER ) DEFINE_SCRIPTHOOK_PARAM( "options", FIELD_CSTRING ) END_SCRIPTHOOK() + + BEGIN_SCRIPTHOOK( C_BaseAnimating::g_Hook_BuildTransformations, "BuildTransformations", FIELD_VOID, "Called when building bone transformations. Allows VScript to read/write any bone with Get/SetBoneTransform." ) + END_SCRIPTHOOK() #endif END_SCRIPTDESC(); @@ -1538,10 +1550,43 @@ HSCRIPT C_BaseAnimating::ScriptGetAttachmentMatrix( int iAttachment ) void C_BaseAnimating::ScriptGetBoneTransform( int iBone, HSCRIPT hTransform ) { - if (hTransform == NULL) + matrix3x4_t *matTransform = HScriptToClass( hTransform ); + if (matTransform == NULL) return; - GetBoneTransform( iBone, *HScriptToClass( hTransform ) ); + GetBoneTransform( iBone, *matTransform ); +} + +void C_BaseAnimating::ScriptSetBoneTransform( int iBone, HSCRIPT hTransform ) +{ + matrix3x4_t *matTransform = HScriptToClass( hTransform ); + if (matTransform == NULL) + return; + + MatrixCopy( *matTransform, GetBoneForWrite( iBone ) ); +} + +void C_BaseAnimating::ScriptAttachEntityToBone( HSCRIPT attachTarget, int boneIndexAttached, const Vector &bonePosition, const QAngle &boneAngles ) +{ + C_BaseEntity *pTarget = ToEnt( attachTarget ); + if (pTarget == NULL) + return; + + AttachEntityToBone( pTarget->GetBaseAnimating(), boneIndexAttached, bonePosition, boneAngles ); +} + +void C_BaseAnimating::ScriptRemoveBoneAttachment( HSCRIPT boneAttachment ) +{ + C_BaseEntity *pTarget = ToEnt( boneAttachment ); + if (pTarget == NULL) + return; + + RemoveBoneAttachment( pTarget->GetBaseAnimating() ); +} + +HSCRIPT C_BaseAnimating::ScriptGetBoneAttachment( int i ) +{ + return ToHScript( GetBoneAttachment( i ) ); } HSCRIPT C_BaseAnimating::ScriptBecomeRagdollOnClient() @@ -1719,7 +1764,23 @@ void C_BaseAnimating::BuildTransformations( CStudioHdr *hdr, Vector *pos, Quater } } - +#ifdef MAPBASE_VSCRIPT + if (m_ScriptScope.IsInitialized() && g_Hook_BuildTransformations.CanRunInScope(m_ScriptScope)) + { + int oldWritableBones = m_BoneAccessor.GetWritableBones(); + int oldReadableBones = m_BoneAccessor.GetReadableBones(); + m_BoneAccessor.SetWritableBones( BONE_USED_BY_ANYTHING ); + m_BoneAccessor.SetReadableBones( BONE_USED_BY_ANYTHING ); + + // No parameters + //ScriptVariant_t args[] = {}; + //ScriptVariant_t returnValue; + g_Hook_BuildTransformations.Call( m_ScriptScope, NULL, NULL /*&returnValue, args*/ ); + + m_BoneAccessor.SetWritableBones( oldWritableBones ); + m_BoneAccessor.SetReadableBones( oldReadableBones ); + } +#endif } //----------------------------------------------------------------------------- diff --git a/sp/src/game/client/c_baseanimating.h b/sp/src/game/client/c_baseanimating.h index 53372e8d..30b69ea7 100644 --- a/sp/src/game/client/c_baseanimating.h +++ b/sp/src/game/client/c_baseanimating.h @@ -468,6 +468,11 @@ public: HSCRIPT ScriptGetAttachmentMatrix(int iAttachment); void ScriptGetBoneTransform( int iBone, HSCRIPT hTransform ); + void ScriptSetBoneTransform( int iBone, HSCRIPT hTransform ); + + void ScriptAttachEntityToBone( HSCRIPT attachTarget, int boneIndexAttached, const Vector &bonePosition, const QAngle &boneAngles ); + void ScriptRemoveBoneAttachment( HSCRIPT boneAttachment ); + HSCRIPT ScriptGetBoneAttachment( int i ); int ScriptGetSequenceActivity( int iSequence ) { return GetSequenceActivity( iSequence ); } float ScriptGetSequenceMoveDist( int iSequence ) { return GetSequenceMoveDist( GetModelPtr(), iSequence ); } @@ -486,6 +491,7 @@ public: static ScriptHook_t g_Hook_OnClientRagdoll; static ScriptHook_t g_Hook_FireEvent; + static ScriptHook_t g_Hook_BuildTransformations; float ScriptGetPoseParameter(const char* szName); #endif From 8ad19cbf0aacb75048b3a551e6b660b65639c34f Mon Sep 17 00:00:00 2001 From: Blixibon Date: Tue, 11 May 2021 11:17:06 -0500 Subject: [PATCH 079/378] Reworked the OnDeath VScript hook so it could cheat death properly --- sp/src/game/server/basecombatcharacter.cpp | 25 +++------ sp/src/game/server/baseentity.cpp | 51 +++++++++++-------- sp/src/game/server/baseentity.h | 3 ++ .../game/server/hl2/npc_combinedropship.cpp | 12 +++-- sp/src/game/server/hl2/vehicle_apc.cpp | 12 +++-- 5 files changed, 58 insertions(+), 45 deletions(-) diff --git a/sp/src/game/server/basecombatcharacter.cpp b/sp/src/game/server/basecombatcharacter.cpp index b740e3f0..6facbb2b 100644 --- a/sp/src/game/server/basecombatcharacter.cpp +++ b/sp/src/game/server/basecombatcharacter.cpp @@ -1725,25 +1725,6 @@ Killed */ void CBaseCombatCharacter::Event_Killed( const CTakeDamageInfo &info ) { -#ifdef MAPBASE_VSCRIPT - if (m_ScriptScope.IsInitialized() && g_Hook_OnDeath.CanRunInScope( m_ScriptScope )) - { - HSCRIPT hInfo = g_pScriptVM->RegisterInstance( const_cast(&info) ); - - // info - ScriptVariant_t functionReturn; - ScriptVariant_t args[] = { ScriptVariant_t( hInfo ) }; - if ( g_Hook_OnDeath.Call( m_ScriptScope, &functionReturn, args ) && (functionReturn.m_type == FIELD_BOOLEAN && functionReturn.m_bool == false) ) - { - // Make this entity cheat death - g_pScriptVM->RemoveInstance( hInfo ); - return; - } - - g_pScriptVM->RemoveInstance( hInfo ); - } -#endif - extern ConVar npc_vphysics; // Advance life state to dying @@ -2893,6 +2874,12 @@ int CBaseCombatCharacter::OnTakeDamage( const CTakeDamageInfo &info ) #endif if ( m_iHealth <= 0 ) { +#ifdef MAPBASE_VSCRIPT + // False = Cheat death + if (ScriptDeathHook( const_cast(&info) ) == false) + return retVal; +#endif + IPhysicsObject *pPhysics = VPhysicsGetObject(); if ( pPhysics ) { diff --git a/sp/src/game/server/baseentity.cpp b/sp/src/game/server/baseentity.cpp index 95adce8e..8492f299 100644 --- a/sp/src/game/server/baseentity.cpp +++ b/sp/src/game/server/baseentity.cpp @@ -1719,22 +1719,9 @@ int CBaseEntity::VPhysicsTakeDamage( const CTakeDamageInfo &info ) void CBaseEntity::Event_Killed( const CTakeDamageInfo &info ) { #ifdef MAPBASE_VSCRIPT - if (m_ScriptScope.IsInitialized() && g_Hook_OnDeath.CanRunInScope( m_ScriptScope )) - { - HSCRIPT hInfo = g_pScriptVM->RegisterInstance( const_cast(&info) ); - - // info - ScriptVariant_t functionReturn; - ScriptVariant_t args[] = { ScriptVariant_t( hInfo ) }; - if ( g_Hook_OnDeath.Call( m_ScriptScope, &functionReturn, args ) && (functionReturn.m_type == FIELD_BOOLEAN && functionReturn.m_bool == false) ) - { - // Make this entity cheat death - g_pScriptVM->RemoveInstance( hInfo ); - return; - } - - g_pScriptVM->RemoveInstance( hInfo ); - } + // False = Cheat death + if (ScriptDeathHook( const_cast(&info) ) == false) + return; #endif if( info.GetAttacker() ) @@ -4668,6 +4655,16 @@ bool CBaseEntity::AcceptInput( const char *szInputName, CBaseEntity *pActivator, return false; } +#ifdef MAPBASE_VSCRIPT +bool CBaseEntity::ScriptAcceptInput( const char *szInputName, const char *szValue, HSCRIPT hActivator, HSCRIPT hCaller ) +{ + variant_t value; + value.SetString( MAKE_STRING( szValue ) ); + + return AcceptInput( szInputName, ToEnt( hActivator ), ToEnt( hCaller ), value, 0 ); +} +#endif + //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- @@ -4700,12 +4697,26 @@ bool CBaseEntity::ScriptInputHook( const char *szInputName, CBaseEntity *pActiva } #ifdef MAPBASE_VSCRIPT -bool CBaseEntity::ScriptAcceptInput( const char *szInputName, const char *szValue, HSCRIPT hActivator, HSCRIPT hCaller ) +bool CBaseEntity::ScriptDeathHook( CTakeDamageInfo *info ) { - variant_t value; - value.SetString( MAKE_STRING(szValue) ); + if (m_ScriptScope.IsInitialized() && g_Hook_OnDeath.CanRunInScope( m_ScriptScope )) + { + HSCRIPT hInfo = g_pScriptVM->RegisterInstance( info ); - return AcceptInput( szInputName, ToEnt(hActivator), ToEnt(hCaller), value, 0 ); + // info + ScriptVariant_t functionReturn; + ScriptVariant_t args[] = { ScriptVariant_t( hInfo ) }; + if ( g_Hook_OnDeath.Call( m_ScriptScope, &functionReturn, args ) && (functionReturn.m_type == FIELD_BOOLEAN && functionReturn.m_bool == false) ) + { + // Make this entity cheat death + g_pScriptVM->RemoveInstance( hInfo ); + return false; + } + + g_pScriptVM->RemoveInstance( hInfo ); + } + + return true; } #endif diff --git a/sp/src/game/server/baseentity.h b/sp/src/game/server/baseentity.h index 4b5449d6..e3388e87 100644 --- a/sp/src/game/server/baseentity.h +++ b/sp/src/game/server/baseentity.h @@ -693,6 +693,9 @@ public: #endif bool ScriptInputHook( const char *szInputName, CBaseEntity *pActivator, CBaseEntity *pCaller, variant_t Value, ScriptVariant_t &functionReturn ); +#ifdef MAPBASE_VSCRIPT + bool ScriptDeathHook( CTakeDamageInfo *info ); +#endif // // Input handlers. diff --git a/sp/src/game/server/hl2/npc_combinedropship.cpp b/sp/src/game/server/hl2/npc_combinedropship.cpp index fa40fd76..b39dad9f 100644 --- a/sp/src/game/server/hl2/npc_combinedropship.cpp +++ b/sp/src/game/server/hl2/npc_combinedropship.cpp @@ -689,9 +689,15 @@ int CCombineDropshipContainer::OnTakeDamage( const CTakeDamageInfo &info ) if ( m_iHealth <= 0 ) { - m_iHealth = 0; - Event_Killed( dmgInfo ); - return 0; +#ifdef MAPBASE_VSCRIPT + // False = Cheat death + if (ScriptDeathHook( const_cast(&info) ) != false) +#endif + { + m_iHealth = 0; + Event_Killed( dmgInfo ); + return 0; + } } // Spawn damage effects diff --git a/sp/src/game/server/hl2/vehicle_apc.cpp b/sp/src/game/server/hl2/vehicle_apc.cpp index 80c4291f..63d5e3ed 100644 --- a/sp/src/game/server/hl2/vehicle_apc.cpp +++ b/sp/src/game/server/hl2/vehicle_apc.cpp @@ -561,9 +561,15 @@ int CPropAPC::OnTakeDamage( const CTakeDamageInfo &info ) m_iHealth -= dmgInfo.GetDamage(); if ( m_iHealth <= 0 ) { - m_iHealth = 0; - Event_Killed( dmgInfo ); - return 0; +#ifdef MAPBASE_VSCRIPT + // False = Cheat death + if (ScriptDeathHook( const_cast(&info) ) != false) +#endif + { + m_iHealth = 0; + Event_Killed( dmgInfo ); + return 0; + } } // Chain From 098486fbe4181a23c8970b943cbb3f99e5d3c0ff Mon Sep 17 00:00:00 2001 From: Alexander 'z33ky' Hirsch <1zeeky@gmail.com> Date: Sun, 23 May 2021 12:11:12 +0200 Subject: [PATCH 080/378] Fix pointer comparisons --- sp/src/game/client/clientmode_shared.cpp | 2 +- sp/src/tier1/strtools.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/sp/src/game/client/clientmode_shared.cpp b/sp/src/game/client/clientmode_shared.cpp index f68531bb..6f2aa4b8 100644 --- a/sp/src/game/client/clientmode_shared.cpp +++ b/sp/src/game/client/clientmode_shared.cpp @@ -1259,7 +1259,7 @@ void ClientModeShared::FireGameEvent( IGameEvent *event ) } } - if ( team == 0 && GetLocalTeam() > 0 ) + if ( team == 0 && GetLocalTeam() ) { bValidTeam = false; } diff --git a/sp/src/tier1/strtools.cpp b/sp/src/tier1/strtools.cpp index 9b1bfa84..62d31c15 100644 --- a/sp/src/tier1/strtools.cpp +++ b/sp/src/tier1/strtools.cpp @@ -1420,7 +1420,7 @@ int V_UCS2ToUnicode( const ucs2 *pUCS2, wchar_t *pUnicode, int cubDestSizeInByte size_t nMaxUTF8 = cubDestSizeInBytes; char *pIn = (char *)pUCS2; char *pOut = (char *)pUnicode; - if ( conv_t > 0 ) + if ( conv_t ) { cchResult = 0; cchResult = iconv( conv_t, &pIn, &nLenUnicde, &pOut, &nMaxUTF8 ); @@ -1461,7 +1461,7 @@ int V_UnicodeToUCS2( const wchar_t *pUnicode, int cubSrcInBytes, char *pUCS2, in size_t nMaxUCS2 = cubDestSizeInBytes; char *pIn = (char*)pUnicode; char *pOut = pUCS2; - if ( conv_t > 0 ) + if ( conv_t ) { cchResult = 0; cchResult = iconv( conv_t, &pIn, &nLenUnicde, &pOut, &nMaxUCS2 ); @@ -1508,7 +1508,7 @@ int V_UCS2ToUTF8( const ucs2 *pUCS2, char *pUTF8, int cubDestSizeInBytes ) size_t nMaxUTF8 = cubDestSizeInBytes - 1; char *pIn = (char *)pUCS2; char *pOut = (char *)pUTF8; - if ( conv_t > 0 ) + if ( conv_t ) { cchResult = 0; const size_t nBytesToWrite = nMaxUTF8; @@ -1554,7 +1554,7 @@ int V_UTF8ToUCS2( const char *pUTF8, int cubSrcInBytes, ucs2 *pUCS2, int cubDest size_t nMaxUTF8 = cubDestSizeInBytes; char *pIn = (char *)pUTF8; char *pOut = (char *)pUCS2; - if ( conv_t > 0 ) + if ( conv_t ) { cchResult = 0; cchResult = iconv( conv_t, &pIn, &nLenUnicde, &pOut, &nMaxUTF8 ); From 78ef9f2019983924b72fd66769712e2bf935128c Mon Sep 17 00:00:00 2001 From: Alexander 'z33ky' Hirsch <1zeeky@gmail.com> Date: Sun, 23 May 2021 12:11:26 +0200 Subject: [PATCH 081/378] Fix MapEdit memory errors deleteThis() was called on NULL pointers. Deleting individual nodes shouldn't be necessary if the whole structure (pkvFile) is deleted anyways. --- sp/src/game/shared/mapbase/MapEdit.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/sp/src/game/shared/mapbase/MapEdit.cpp b/sp/src/game/shared/mapbase/MapEdit.cpp index 9ff1db60..0891c29e 100644 --- a/sp/src/game/shared/mapbase/MapEdit.cpp +++ b/sp/src/game/shared/mapbase/MapEdit.cpp @@ -409,7 +409,6 @@ public: pkvClassname = pkvClassname->GetNextKey(); } - pkvClassname->deleteThis(); } else if (FStrEq(pNodeName, "edit")) { @@ -432,7 +431,6 @@ public: pName = pName->GetNextKey(); } - pName->deleteThis(); } else if (FStrEq(pNodeName, "delete")) { @@ -455,7 +453,6 @@ public: pName = pName->GetNextKey(); } - pName->deleteThis(); } else if (FStrEq(pNodeName, "fire")) { @@ -525,12 +522,10 @@ public: pkvNodeData = pkvNodeData->GetNextKey(); } - pkvNodeData->deleteThis(); } pkvNode = pkvNode->GetNextKey(); } - pkvNode->deleteThis(); } void SpawnMapEdit(const char *pFile = NULL) @@ -889,8 +884,8 @@ void CC_MapEdit_Print( const CCommand& args ) pkvNode = pkvNode->GetNextKey(); } - pkvNode->deleteThis(); } + pkvFile->deleteThis(); } } static ConCommand mapedit_print("mapedit_print", CC_MapEdit_Print, "Prints a mapedit file in the console."); From 7a87bfdf5ed2e4c1392a339a194458c8dae175a5 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Thu, 27 May 2021 09:52:28 -0500 Subject: [PATCH 082/378] Added ConVar material proxy --- sp/src/game/client/client_mapbase.vpc | 1 + sp/src/game/client/convarproxy.cpp | 113 ++++++++++++++++++++++++++ 2 files changed, 114 insertions(+) create mode 100644 sp/src/game/client/convarproxy.cpp diff --git a/sp/src/game/client/client_mapbase.vpc b/sp/src/game/client/client_mapbase.vpc index 2c5b606a..903822f5 100644 --- a/sp/src/game/client/client_mapbase.vpc +++ b/sp/src/game/client/client_mapbase.vpc @@ -35,6 +35,7 @@ $Project $File "c_movie_display.cpp" $File "c_movie_display.h" $File "vgui_movie_display.cpp" + $File "convarproxy.cpp" $Folder "Mapbase" { diff --git a/sp/src/game/client/convarproxy.cpp b/sp/src/game/client/convarproxy.cpp new file mode 100644 index 00000000..b3670281 --- /dev/null +++ b/sp/src/game/client/convarproxy.cpp @@ -0,0 +1,113 @@ +//========= Copyright © 1996-2008, Valve Corporation, All rights reserved. ============// +// +// Material proxy to stuff a convar into a material var. +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" +// identifier was truncated to '255' characters in the debug information +//#pragma warning(disable: 4786) + +#include "convar.h" +#include "MaterialSystem/imaterialproxy.h" +#include "materialsystem/IMaterialVar.h" +//#include "imaterialproxydict.h" + +// NOTE: This has to be the last file included! +#include "tier0/memdbgon.h" + + +class CConVarMaterialProxy: public IMaterialProxy +{ +public: + CConVarMaterialProxy() + : m_pResult( NULL ), + m_conVarRef( "", true ) + { + } + + virtual ~CConVarMaterialProxy() + { + } + + virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues ) + { + const char *pResult = pKeyValues->GetString( "resultVar" ); + if ( !pResult ) + return false; + + bool found; + m_pResult = pMaterial->FindVar( pResult, &found ); + if ( !found ) + { + m_pResult = NULL; + return false; + } + + /* + if ( !Q_stricmp( pResult, "$alpha" ) ) + { + pMaterial->SetMaterialVarFlag( MATERIAL_VAR_ALPHA_MODIFIED_BY_PROXY, true ); + } + */ + + pResult = pKeyValues->GetString( "convar" ); + if( !pResult ) + { + return false; + } + + m_conVarRef.Init( pResult, false ); + if ( !m_conVarRef.IsValid() ) + { + return false; + } + + return true; + } + + virtual void OnBind( void* ) + { + switch( m_pResult->GetType() ) + { + case MATERIAL_VAR_TYPE_VECTOR: + { + float f = m_conVarRef.GetFloat(); + Vector4D vec( f, f, f, f ); + m_pResult->SetVecValue( vec.Base(), m_pResult->VectorSize() ); + } + break; + +#ifdef MAPBASE + case MATERIAL_VAR_TYPE_STRING: + m_pResult->SetStringValue( m_conVarRef.GetString() ); + break; +#endif + + case MATERIAL_VAR_TYPE_INT: + m_pResult->SetIntValue( m_conVarRef.GetInt() ); + break; + + case MATERIAL_VAR_TYPE_FLOAT: + default: + m_pResult->SetFloatValue( m_conVarRef.GetFloat() ); + break; + } + } + + virtual IMaterial *GetMaterial() + { + return m_pResult->GetOwningMaterial(); + } + + virtual void Release() + { + } + +protected: + IMaterialVar *m_pResult; + ConVarRef m_conVarRef; +}; + +EXPOSE_INTERFACE( CConVarMaterialProxy, IMaterialProxy, "ConVar" IMATERIAL_PROXY_INTERFACE_VERSION ); From c48428b67855cd29ab72006efe9408826de7031d Mon Sep 17 00:00:00 2001 From: Blixibon Date: Thu, 27 May 2021 09:53:31 -0500 Subject: [PATCH 083/378] Added OnEntrySequence and OnActionSequence for scripted_sequence --- sp/src/game/server/ai_basenpc_schedule.cpp | 6 ++++++ sp/src/game/server/scripted.cpp | 12 ++++++++++++ sp/src/game/server/scripted.h | 4 ++++ 3 files changed, 22 insertions(+) diff --git a/sp/src/game/server/ai_basenpc_schedule.cpp b/sp/src/game/server/ai_basenpc_schedule.cpp index 10bf02e5..0d715bf4 100644 --- a/sp/src/game/server/ai_basenpc_schedule.cpp +++ b/sp/src/game/server/ai_basenpc_schedule.cpp @@ -3979,10 +3979,16 @@ void CAI_BaseNPC::RunTask( const Task_t *pTask ) // If we have an entry, we have to play it first if ( m_hCine->m_iszEntry != NULL_STRING ) { +#ifdef MAPBASE + m_hCine->OnEntrySequence( this ); +#endif m_hCine->StartSequence( (CAI_BaseNPC *)this, m_hCine->m_iszEntry, true ); } else { +#ifdef MAPBASE + m_hCine->OnActionSequence( this ); +#endif m_hCine->StartSequence( (CAI_BaseNPC *)this, m_hCine->m_iszPlay, true ); } diff --git a/sp/src/game/server/scripted.cpp b/sp/src/game/server/scripted.cpp index 19fc6784..37b45844 100644 --- a/sp/src/game/server/scripted.cpp +++ b/sp/src/game/server/scripted.cpp @@ -136,6 +136,8 @@ BEGIN_DATADESC( CAI_ScriptedSequence ) DEFINE_OUTPUT(m_OnScriptEvent[6], "OnScriptEvent07"), DEFINE_OUTPUT(m_OnScriptEvent[7], "OnScriptEvent08"), #ifdef MAPBASE + DEFINE_OUTPUT(m_OnEntrySequence, "OnEntrySequence"), + DEFINE_OUTPUT(m_OnActionSequence, "OnActionSequence"), DEFINE_OUTPUT(m_OnPreIdleSequence, "OnPreIdleSequence"), DEFINE_OUTPUT(m_OnFoundNPC, "OnFoundNPC"), #endif @@ -864,6 +866,16 @@ void CAI_ScriptedSequence::OnBeginSequence( CBaseEntity *pActor ) m_OnBeginSequence.FireOutput( pActor, this ); } +void CAI_ScriptedSequence::OnEntrySequence( CBaseEntity *pActor ) +{ + m_OnEntrySequence.FireOutput( pActor, this ); +} + +void CAI_ScriptedSequence::OnActionSequence( CBaseEntity *pActor ) +{ + m_OnActionSequence.FireOutput( pActor, this ); +} + void CAI_ScriptedSequence::OnPreIdleSequence( CBaseEntity *pActor ) { m_OnPreIdleSequence.FireOutput( pActor, this ); diff --git a/sp/src/game/server/scripted.h b/sp/src/game/server/scripted.h index 1b7398a4..7b1d8254 100644 --- a/sp/src/game/server/scripted.h +++ b/sp/src/game/server/scripted.h @@ -97,6 +97,8 @@ public: void FireScriptEvent( int nEvent ); #ifdef MAPBASE void OnBeginSequence( CBaseEntity *pActor ); + void OnEntrySequence( CBaseEntity *pActor ); + void OnActionSequence( CBaseEntity *pActor ); void OnPreIdleSequence( CBaseEntity *pActor ); #else void OnBeginSequence( void ); @@ -220,6 +222,8 @@ private: COutputEvent m_OnCancelFailedSequence; // Fired when a scene is cancelled before it's ever run COutputEvent m_OnScriptEvent[MAX_SCRIPT_EVENTS]; #ifdef MAPBASE + COutputEvent m_OnEntrySequence; + COutputEvent m_OnActionSequence; COutputEvent m_OnPreIdleSequence; COutputEvent m_OnFoundNPC; #endif From 3287643c2416188c98cad053abeaa6a0e45a21f1 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Thu, 27 May 2021 09:53:48 -0500 Subject: [PATCH 084/378] Added a few more matrix-related functions for VScript --- sp/src/vscript/vscript_bindings_math.cpp | 50 +++++++++++++++++++++++- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/sp/src/vscript/vscript_bindings_math.cpp b/sp/src/vscript/vscript_bindings_math.cpp index 2f189265..cb1567d5 100644 --- a/sp/src/vscript/vscript_bindings_math.cpp +++ b/sp/src/vscript/vscript_bindings_math.cpp @@ -102,7 +102,6 @@ void ScriptMatrixSetColumn( const Vector& vecset, int column, HSCRIPT hMat1 ) matrix3x4_t *pMat1 = ToMatrix3x4( hMat1 ); - static Vector outvec; MatrixSetColumn( vecset, column, *pMat1 ); } @@ -156,6 +155,49 @@ void ScriptSetScaleMatrix( float x, float y, float z, HSCRIPT hMat1 ) SetScaleMatrix( x, y, z, *pMat1 ); } +void ScriptMatrixScaleBy( float flScale, HSCRIPT hMat1 ) +{ + if (!hMat1) + return; + + matrix3x4_t *pMat1 = ToMatrix3x4( hMat1 ); + + MatrixScaleBy( flScale, *pMat1 ); +} + +void ScriptMatrixScaleByZero( HSCRIPT hMat1 ) +{ + if (!hMat1) + return; + + matrix3x4_t *pMat1 = ToMatrix3x4( hMat1 ); + + MatrixScaleByZero( *pMat1 ); +} + +const Vector& ScriptMatrixGetTranslation( HSCRIPT hMat1 ) +{ + static Vector outvec; + outvec.Zero(); + if (!hMat1) + return outvec; + + matrix3x4_t *pMat1 = ToMatrix3x4( hMat1 ); + + MatrixGetTranslation( *pMat1, outvec ); + return outvec; +} + +void ScriptMatrixSetTranslation( const Vector& vecset, HSCRIPT hMat1 ) +{ + if (!hMat1) + return; + + matrix3x4_t *pMat1 = ToMatrix3x4( hMat1 ); + + MatrixSetTranslation( vecset, *pMat1 ); +} + //============================================================================= // // Quaternion @@ -427,7 +469,11 @@ void RegisterMathBaseBindings( IScriptVM *pVM ) ScriptRegisterFunctionNamed( pVM, ScriptAngleMatrix, "AngleMatrix", "Sets the angles and position of a matrix." ); ScriptRegisterFunctionNamed( pVM, ScriptAngleIMatrix, "AngleIMatrix", "Sets the inverted angles and position of a matrix." ); ScriptRegisterFunctionNamed( pVM, ScriptSetIdentityMatrix, "SetIdentityMatrix", "Turns a matrix into an identity matrix." ); - ScriptRegisterFunctionNamed( pVM, ScriptSetScaleMatrix, "SetScaleMatrix", "Scales a matrix." ); + ScriptRegisterFunctionNamed( pVM, ScriptSetScaleMatrix, "SetScaleMatrix", "Builds a scale matrix." ); + ScriptRegisterFunctionNamed( pVM, ScriptMatrixScaleBy, "MatrixScaleBy", "Scales a matrix." ); + ScriptRegisterFunctionNamed( pVM, ScriptMatrixScaleByZero, "MatrixScaleByZero", "Scales a matrix by zero." ); + ScriptRegisterFunctionNamed( pVM, ScriptMatrixGetTranslation, "MatrixGetTranslation", "Gets a matrix's translation." ); + ScriptRegisterFunctionNamed( pVM, ScriptMatrixSetTranslation, "MatrixSetTranslation", "Sets a matrix's translation." ); // // Quaternion From dcd7b95b62106b58e094847c5c8ea2535a2c5e9d Mon Sep 17 00:00:00 2001 From: Blixibon Date: Thu, 27 May 2021 11:39:47 -0500 Subject: [PATCH 085/378] Added new move_rope/keyframe_rope inputs --- sp/src/game/server/rope.cpp | 49 +++++++++++++++++++++++++++++++++++++ sp/src/game/server/rope.h | 5 ++++ 2 files changed, 54 insertions(+) diff --git a/sp/src/game/server/rope.cpp b/sp/src/game/server/rope.cpp index 516015fe..23f44c39 100644 --- a/sp/src/game/server/rope.cpp +++ b/sp/src/game/server/rope.cpp @@ -90,6 +90,10 @@ BEGIN_DATADESC( CRopeKeyframe ) DEFINE_INPUTFUNC( FIELD_VOID, "Break", InputBreak ), #ifdef MAPBASE + DEFINE_INPUTFUNC( FIELD_INTEGER, "SetSlack", InputSetSlack ), + DEFINE_INPUTFUNC( FIELD_FLOAT, "SetWidth", InputSetWidth ), + DEFINE_INPUTFUNC( FIELD_INTEGER, "SetSubdivision", InputSetSubdivision ), + // Outputs DEFINE_OUTPUT( m_OnBreak, "OnBreak" ), #endif @@ -613,6 +617,51 @@ void CRopeKeyframe::InputBreak( inputdata_t &inputdata ) #endif } +#ifdef MAPBASE +//----------------------------------------------------------------------------- +// Purpose: Sets the slack +// Input : &inputdata - +//----------------------------------------------------------------------------- +void CRopeKeyframe::InputSetSlack( inputdata_t &inputdata ) +{ + m_Slack = inputdata.value.Int(); + + // Must resize in order for changes to occur + m_RopeFlags |= ROPE_RESIZE; + + if (!(m_RopeFlags & ROPE_USE_WIND)) + { + Warning( "WARNING: SetSlack on %s may need wind enabled in order to function\n", GetDebugName() ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Sets the width +// Input : &inputdata - +//----------------------------------------------------------------------------- +void CRopeKeyframe::InputSetWidth( inputdata_t &inputdata ) +{ + m_Width = inputdata.value.Float(); +} + +//----------------------------------------------------------------------------- +// Purpose: Sets the subdivision +// Input : &inputdata - +//----------------------------------------------------------------------------- +void CRopeKeyframe::InputSetSubdivision( inputdata_t &inputdata ) +{ + m_Subdiv = inputdata.value.Int(); + + // Must resize in order for changes to occur + m_RopeFlags |= ROPE_RESIZE; + + if (!(m_RopeFlags & ROPE_USE_WIND)) + { + Warning( "WARNING: SetSubdivision on %s may need wind enabled in order to function\n", GetDebugName() ); + } +} +#endif + //----------------------------------------------------------------------------- // Purpose: Breaks the rope // Output : Returns true on success, false on failure. diff --git a/sp/src/game/server/rope.h b/sp/src/game/server/rope.h index 74037800..44fc7102 100644 --- a/sp/src/game/server/rope.h +++ b/sp/src/game/server/rope.h @@ -102,6 +102,11 @@ public: void InputSetScrollSpeed( inputdata_t &inputdata ); void InputSetForce( inputdata_t &inputdata ); void InputBreak( inputdata_t &inputdata ); +#ifdef MAPBASE + void InputSetSlack( inputdata_t &inputdata ); + void InputSetWidth( inputdata_t &inputdata ); + void InputSetSubdivision( inputdata_t &inputdata ); +#endif public: From adada8f56edb4533ff4cd6502c1f12c71186d268 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Thu, 27 May 2021 11:41:52 -0500 Subject: [PATCH 086/378] Made env_global_light start using different cvars for shadow map resolution and filter size --- sp/src/game/client/c_env_global_light.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sp/src/game/client/c_env_global_light.cpp b/sp/src/game/client/c_env_global_light.cpp index 4bbb96d2..b143a79d 100644 --- a/sp/src/game/client/c_env_global_light.cpp +++ b/sp/src/game/client/c_env_global_light.cpp @@ -27,7 +27,9 @@ ConVar cl_globallight_xoffset( "cl_globallight_xoffset", "0" ); ConVar cl_globallight_yoffset( "cl_globallight_yoffset", "0" ); static ConVar cl_globallight_slopescaledepthbias_shadowmap( "cl_globallight_slopescaledepthbias_shadowmap", "16", FCVAR_CHEAT ); +static ConVar cl_globallight_shadowfiltersize( "cl_globallight_shadowfiltersize", "0.1", FCVAR_CHEAT ); static ConVar cl_globallight_depthbias_shadowmap( "cl_globallight_depthbias_shadowmap", "0.00001", FCVAR_CHEAT ); +static ConVar cl_globallight_depthres( "cl_globallight_depthres", "8192", FCVAR_CHEAT ); #else ConVar cl_globallight_xoffset( "cl_globallight_xoffset", "-800" ); ConVar cl_globallight_yoffset( "cl_globallight_yoffset", "1600" ); @@ -291,6 +293,8 @@ void C_GlobalLight::ClientThink() #ifdef MAPBASE //state.m_bDrawShadowFrustum = true; // Don't draw that huge debug thing + state.m_flShadowMapResolution = cl_globallight_depthres.GetFloat(); + state.m_flShadowFilterSize = cl_globallight_shadowfiltersize.GetFloat(); state.m_flShadowSlopeScaleDepthBias = cl_globallight_slopescaledepthbias_shadowmap.GetFloat(); state.m_flShadowDepthBias = cl_globallight_depthbias_shadowmap.GetFloat(); state.m_bEnableShadows = m_bEnableShadows; From e28813de7faf43b728cf1e901c252f9e3e2d13c4 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Thu, 27 May 2021 12:01:55 -0500 Subject: [PATCH 087/378] Added console message for when VScript documentation is requested while it's disabled --- sp/src/vscript/vscript_squirrel.nut | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sp/src/vscript/vscript_squirrel.nut b/sp/src/vscript/vscript_squirrel.nut index f87aad96..7c6a421e 100644 --- a/sp/src/vscript/vscript_squirrel.nut +++ b/sp/src/vscript/vscript_squirrel.nut @@ -348,7 +348,10 @@ local function PrintMatchesInDocList(pattern, list, printfunc) function __Documentation::PrintHelp(pattern = "*") { if ( !developer ) + { + printdocl("Documentation is not enabled. To enable documentation, restart the server with the 'developer' cvar set to 1 or higher."); return + } local patternLower = pattern.tolower(); From 1de46132d83724e6ef05829449f9b82dff67809c Mon Sep 17 00:00:00 2001 From: Blixibon Date: Thu, 27 May 2021 12:02:39 -0500 Subject: [PATCH 088/378] Slightly adjusted some prior changes --- sp/src/game/server/ai_networkmanager.cpp | 2 +- sp/src/vscript/vscript_squirrel.cpp | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/sp/src/game/server/ai_networkmanager.cpp b/sp/src/game/server/ai_networkmanager.cpp index 0d1f71e4..f366ee57 100644 --- a/sp/src/game/server/ai_networkmanager.cpp +++ b/sp/src/game/server/ai_networkmanager.cpp @@ -3061,7 +3061,7 @@ int CAI_NetworkBuilder::ComputeConnection( CAI_Node *pSrcNode, CAI_Node *pDestNo { #ifdef MAPBASE // This is kind of a hack since target node IDs are designed to be used *after* the nodegraph is generated. - // However, for the purposes of forcing a climb connection outside of regular lineup bounds, it works. + // However, for the purposes of forcing a climb connection outside of regular lineup bounds, it seems to be a reasonable solution. if (pSrcNode->GetHint() && pDestNode->GetHint() && (pSrcNode->GetHint()->GetTargetWCNodeID() == pDestNode->GetHint()->GetWCId() || pDestNode->GetHint()->GetTargetWCNodeID() == pSrcNode->GetHint()->GetWCId())) { diff --git a/sp/src/vscript/vscript_squirrel.cpp b/sp/src/vscript/vscript_squirrel.cpp index 59326ce9..af8ad7d4 100644 --- a/sp/src/vscript/vscript_squirrel.cpp +++ b/sp/src/vscript/vscript_squirrel.cpp @@ -1406,7 +1406,8 @@ SQInteger function_stub(HSQUIRRELVM vm) PushVariant(vm, retval); - retval.Free(); + if (retval.m_type == FIELD_VECTOR) + delete retval.m_pVector; return pFunc->m_desc.m_ReturnType != FIELD_VOID; } From e52835520c099a0243e5a93648674e2da9e3472d Mon Sep 17 00:00:00 2001 From: Blixibon Date: Thu, 27 May 2021 13:16:55 -0500 Subject: [PATCH 089/378] Slightly adjusted hook callback code --- sp/src/vscript/vscript_squirrel.nut | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sp/src/vscript/vscript_squirrel.nut b/sp/src/vscript/vscript_squirrel.nut index cd05139f..85c895ac 100644 --- a/sp/src/vscript/vscript_squirrel.nut +++ b/sp/src/vscript/vscript_squirrel.nut @@ -204,10 +204,10 @@ Hooks <- local t = s_List[scope] if ( event in t ) { + vargv.insert(0,scope) foreach( context, callback in t[event] ) { - printf( "(%.4f) Calling hook '%s' of context '%s'\n", Time(), event, context ) - vargv.insert(0,scope) + //printf( "(%.4f) Calling hook '%s' of context '%s'\n", Time(), event, context ) local curReturn = callback.acall(vargv) if (firstReturn == null) From 7d2970eacdf222eaa7bb1494b0916a02577ab0e1 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Thu, 27 May 2021 14:22:43 -0500 Subject: [PATCH 090/378] Updated README with latest contribution PRs --- README | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README b/README index 33cdd010..d6609449 100644 --- a/README +++ b/README @@ -111,11 +111,13 @@ Direct contributions: =-- https://github.com/mapbase-source/source-sdk-2013/pull/80 (More VScript changes, including support for extremely flexible client/server messaging) =-- https://github.com/mapbase-source/source-sdk-2013/pull/105 (VScript fixes and optimizations, Vector class extensions, custom convars/commands) =-- https://github.com/mapbase-source/source-sdk-2013/pull/114 (VScript fixes and extensions) +=-- https://github.com/mapbase-source/source-sdk-2013/pull/122 (Minor VScript-related adjustments) == Contributions from z33ky: =-- https://github.com/mapbase-source/source-sdk-2013/pull/21 (Various GCC/Linux compilation fixes) =-- https://github.com/mapbase-source/source-sdk-2013/pull/95 (Additional GCC/Linux compilation fixes) =-- https://github.com/mapbase-source/source-sdk-2013/pull/117 (Additional GCC/Linux compilation fixes) +=-- https://github.com/mapbase-source/source-sdk-2013/pull/124 (Memory error fixes) //--------------------------------------------------------------------------------------------------------------------------------------------------- From 06c7f7040d1219adea59a66eb0bf086d52a48bf5 Mon Sep 17 00:00:00 2001 From: Alexander 'z33ky' Hirsch <1zeeky@gmail.com> Date: Thu, 29 Apr 2021 18:41:50 +0200 Subject: [PATCH 091/378] Fix env_instructor_hint from disappearing after savegame load It is a bit unfortunate that the initial animation plays again after load. This is likely not fixable with SDK code without reimplementing the HUD bits, which are part of the external engine code. Also adds a destructor override, since we are dealing with a polymorphic class. --- sp/src/game/server/env_instructor_hint.cpp | 92 +++++++++++++++++++++- 1 file changed, 89 insertions(+), 3 deletions(-) diff --git a/sp/src/game/server/env_instructor_hint.cpp b/sp/src/game/server/env_instructor_hint.cpp index 32b75041..20b2379c 100644 --- a/sp/src/game/server/env_instructor_hint.cpp +++ b/sp/src/game/server/env_instructor_hint.cpp @@ -26,6 +26,15 @@ public: DECLARE_CLASS( CEnvInstructorHint, CPointEntity ); DECLARE_DATADESC(); +#ifdef MAPBASE + CEnvInstructorHint( void ); +#endif + virtual ~CEnvInstructorHint( void ) {} + +#ifdef MAPBASE + virtual void OnRestore( void ); +#endif + private: void InputShowHint( inputdata_t &inputdata ); void InputEndHint( inputdata_t &inputdata ); @@ -56,6 +65,10 @@ private: #ifdef MAPBASE string_t m_iszStartSound; int m_iHintTargetPos; + float m_flActiveUntil; + CHandle m_hActivator; + EHANDLE m_hTarget; + bool m_bFilterByActivator; #endif }; @@ -85,8 +98,13 @@ BEGIN_DATADESC( CEnvInstructorHint ) #ifdef MAPBASE DEFINE_KEYFIELD( m_iszStartSound, FIELD_STRING, "hint_start_sound" ), DEFINE_KEYFIELD( m_iHintTargetPos, FIELD_INTEGER, "hint_target_pos" ), + + DEFINE_FIELD( m_flActiveUntil, FIELD_TIME ), + DEFINE_FIELD( m_hActivator, FIELD_EHANDLE ), + DEFINE_FIELD( m_hTarget, FIELD_EHANDLE ), + DEFINE_FIELD( m_bFilterByActivator, FIELD_BOOLEAN ), #endif - + DEFINE_INPUTFUNC( FIELD_STRING, "ShowHint", InputShowHint ), DEFINE_INPUTFUNC( FIELD_VOID, "EndHint", InputEndHint ), @@ -102,6 +120,43 @@ END_DATADESC() #define LOCATOR_ICON_FX_SHAKE_NARROW 0x00000040 #define LOCATOR_ICON_FX_STATIC 0x00000100 // This icon draws at a fixed location on the HUD. +#ifdef MAPBASE +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +CEnvInstructorHint::CEnvInstructorHint( void ) +{ + m_hActivator = NULL; + m_hTarget = NULL; + m_bFilterByActivator = false; + m_flActiveUntil = -1.0f; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CEnvInstructorHint::OnRestore( void ) +{ + int iTimeLeft = 0; + if ( m_flActiveUntil < 0.0f ) + { + return; + } + if ( m_iTimeout != 0 ) + { + iTimeLeft = static_cast( m_flActiveUntil - gpGlobals->curtime ); + if ( iTimeLeft <= 0 ) + { + return; + } + } + + int iOriginalTimeout = m_iTimeout; + m_iTimeout = iTimeLeft; + inputdata_t inputdata; + InputShowHint( inputdata ); + m_iTimeout = iOriginalTimeout; +} +#endif + //----------------------------------------------------------------------------- // Purpose: Input handler for showing the message and/or playing the sound. //----------------------------------------------------------------------------- @@ -110,7 +165,15 @@ void CEnvInstructorHint::InputShowHint( inputdata_t &inputdata ) IGameEvent * event = gameeventmanager->CreateEvent( "instructor_server_hint_create", false ); if ( event ) { - CBaseEntity *pTargetEntity = gEntList.FindEntityByName( NULL, m_iszHintTargetEntity ); + CBaseEntity *pTargetEntity = NULL; + +#ifdef MAPBASE + pTargetEntity = m_hTarget; + + if ( pTargetEntity == NULL ) +#endif + pTargetEntity = gEntList.FindEntityByName( NULL, m_iszHintTargetEntity ); + if( pTargetEntity == NULL && !m_bStatic ) pTargetEntity = inputdata.pActivator; @@ -137,6 +200,15 @@ void CEnvInstructorHint::InputShowHint( inputdata_t &inputdata ) pActivator = pMarine->GetCommander(); } #else +#ifdef MAPBASE + if ( m_hActivator ) + { + pActivator = m_hActivator; + bFilterByActivator = m_bFilterByActivator; + } + else +#endif + if ( inputdata.value.StringID() != NULL_STRING ) { CBaseEntity *pTarget = gEntList.FindEntityByName( NULL, inputdata.value.String() ); @@ -150,7 +222,7 @@ void CEnvInstructorHint::InputShowHint( inputdata_t &inputdata ) { if ( GameRules()->IsMultiplayer() == false ) { - pActivator = UTIL_GetLocalPlayer(); + pActivator = UTIL_GetLocalPlayer(); } else { @@ -190,6 +262,13 @@ void CEnvInstructorHint::InputShowHint( inputdata_t &inputdata ) #endif gameeventmanager->FireEvent( event ); + +#ifdef MAPBASE + m_flActiveUntil = gpGlobals->curtime + m_iTimeout; + m_hTarget = pTargetEntity; + m_hActivator = pActivator; + m_bFilterByActivator = bFilterByActivator; +#endif } } @@ -203,6 +282,13 @@ void CEnvInstructorHint::InputEndHint( inputdata_t &inputdata ) event->SetString( "hint_name", GetEntityName().ToCStr() ); gameeventmanager->FireEvent( event ); + +#ifdef MAPBASE + m_flActiveUntil = -1.0f; + m_hActivator = NULL; + m_hTarget = NULL; + m_bFilterByActivator = false; +#endif } } From f6a750e4b326fe3069f3ca41d7eba483a4b97d9c Mon Sep 17 00:00:00 2001 From: Alexander 'z33ky' Hirsch <1zeeky@gmail.com> Date: Sun, 6 Jun 2021 15:52:35 +0200 Subject: [PATCH 092/378] Initialize all basis vectors for env_projectedtexture with target --- sp/src/game/client/c_env_projectedtexture.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sp/src/game/client/c_env_projectedtexture.cpp b/sp/src/game/client/c_env_projectedtexture.cpp index a74bb46e..7bd15a17 100644 --- a/sp/src/game/client/c_env_projectedtexture.cpp +++ b/sp/src/game/client/c_env_projectedtexture.cpp @@ -283,6 +283,8 @@ void C_EnvProjectedTexture::UpdateLight( void ) // VectorNormalize( vRight ); // VectorNormalize( vUp ); + + VectorVectors( vForward, vRight, vUp ); } } else From e989cf63c52a3dc8ee5e87e3a59dced180f47dea Mon Sep 17 00:00:00 2001 From: Alexander 'z33ky' Hirsch <1zeeky@gmail.com> Date: Sun, 6 Jun 2021 15:57:05 +0200 Subject: [PATCH 093/378] Fix ReadFileEx() arguments when loading scene files The parser expects NUL terminated data. --- sp/src/game/server/sceneentity.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sp/src/game/server/sceneentity.cpp b/sp/src/game/server/sceneentity.cpp index fc332249..67ca064a 100644 --- a/sp/src/game/server/sceneentity.cpp +++ b/sp/src/game/server/sceneentity.cpp @@ -4298,7 +4298,7 @@ const char *GetFirstSoundInScene(const char *pszScene) else { void *pBuffer = NULL; - if (filesystem->ReadFileEx( pszScene, "MOD", &pBuffer, false, true )) + if (filesystem->ReadFileEx( pszScene, "MOD", &pBuffer, true )) { g_TokenProcessor.SetBuffer((char*)pBuffer); CChoreoScene *pScene = ChoreoLoadScene( pszScene, NULL, &g_TokenProcessor, LocalScene_Printf ); @@ -5284,7 +5284,7 @@ int GetSceneSpeechCount( char const *pszScene ) else { void *pBuffer = NULL; - if (filesystem->ReadFileEx( pszScene, "MOD", &pBuffer, false, true )) + if (filesystem->ReadFileEx( pszScene, "MOD", &pBuffer, true )) { int iNumSounds = 0; @@ -5359,7 +5359,7 @@ void PrecacheInstancedScene( char const *pszScene ) // Attempt to precache manually void *pBuffer = NULL; - if (filesystem->ReadFileEx( loadfile, "MOD", &pBuffer, false, true )) + if (filesystem->ReadFileEx( loadfile, "MOD", &pBuffer, true )) { g_TokenProcessor.SetBuffer((char*)pBuffer); CChoreoScene *pScene = ChoreoLoadScene( loadfile, NULL, &g_TokenProcessor, LocalScene_Printf ); From 5f42182c45f303e182932c4ca3bb241eb29ba800 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Mon, 28 Jun 2021 20:04:23 -0500 Subject: [PATCH 094/378] Divided mapbase_version cvar into server, client, and game_shader_dx9 counterparts --- sp/src/game/shared/mapbase/mapbase_shared.cpp | 20 +++++++++---------- .../stdshaders/BaseVSShader.cpp | 3 +++ sp/src/public/tier0/platform.h | 8 ++++++++ 3 files changed, 20 insertions(+), 11 deletions(-) diff --git a/sp/src/game/shared/mapbase/mapbase_shared.cpp b/sp/src/game/shared/mapbase/mapbase_shared.cpp index 05872b4e..e9527f72 100644 --- a/sp/src/game/shared/mapbase/mapbase_shared.cpp +++ b/sp/src/game/shared/mapbase/mapbase_shared.cpp @@ -55,11 +55,9 @@ ConVar mapbase_load_soundscripts("mapbase_load_soundscripts", "1", FCVAR_ARCHIVE ConVar mapbase_load_localization("mapbase_load_localization", "1", FCVAR_ARCHIVE, "Should we load map-specific localized text files? e.g. \"maps/mapname_english.txt\""); -#ifdef CLIENT_DLL - -//ConVar mapbase_load_cc("mapbase_load_cc", "1", FCVAR_ARCHIVE, "Should we load map-specific closed captioning? e.g. \"maps/mapname_closecaption_english.txt\" and \"maps/mapname_closecaption_english.dat\""); - -#else +#ifdef GAME_DLL +// This constant should change with each Mapbase update +ConVar mapbase_version( "mapbase_version", MAPBASE_VERSION, FCVAR_NONE, "The version of Mapbase currently being used in this mod's server.dll" ); ConVar mapbase_load_sentences("mapbase_load_sentences", "1", FCVAR_ARCHIVE, "Should we load map-specific sentences? e.g. \"maps/mapname_sentences.txt\""); @@ -68,12 +66,6 @@ ConVar mapbase_flush_talker("mapbase_flush_talker", "1", FCVAR_NONE, "Normally, ConVar mapbase_load_actbusy("mapbase_load_actbusy", "1", FCVAR_ARCHIVE, "Should we load map-specific actbusy files? e.g. \"maps/mapname_actbusy.txt\""); -#endif - -#ifdef GAME_DLL -// This cvar should change with each Mapbase update -ConVar mapbase_version( "mapbase_version", "7.0", FCVAR_NONE, "The version of Mapbase currently being used in this mod." ); - extern void MapbaseGameLog_Init(); extern void ParseCustomActbusyFile(const char *file); @@ -83,6 +75,12 @@ extern void ReloadResponseSystem(); // Reloads the response system when the map changes to avoid custom talker leaking static bool g_bMapContainsCustomTalker; +#else +// This constant should change with each Mapbase update +ConVar mapbase_version_client( "mapbase_version_client", MAPBASE_VERSION, FCVAR_NONE, "The version of Mapbase currently being used in this mod's client.dll" ); + +//ConVar mapbase_load_cc("mapbase_load_cc", "1", FCVAR_ARCHIVE, "Should we load map-specific closed captioning? e.g. \"maps/mapname_closecaption_english.txt\" and \"maps/mapname_closecaption_english.dat\""); + #endif // Indicates this is a core Mapbase mod and not a mod using its code. diff --git a/sp/src/materialsystem/stdshaders/BaseVSShader.cpp b/sp/src/materialsystem/stdshaders/BaseVSShader.cpp index 49aafc10..98e6d6c2 100644 --- a/sp/src/materialsystem/stdshaders/BaseVSShader.cpp +++ b/sp/src/materialsystem/stdshaders/BaseVSShader.cpp @@ -55,6 +55,9 @@ static ConVar mat_fullbright( "mat_fullbright","0", FCVAR_CHEAT ); ConVar r_flashlightbrightness( "r_flashlightbrightness", "0.25", FCVAR_CHEAT ); #ifdef MAPBASE +// This constant should change with each Mapbase update +ConVar mapbase_version_shaders( "mapbase_version_shaders", MAPBASE_VERSION, FCVAR_NONE, "The version of Mapbase currently being used in this mod's game_shader_dx9.dll" ); + ConVar mat_specular_disable_on_missing( "mat_specular_disable_on_missing", "1", FCVAR_ARCHIVE, "Disables specular reflections on a material when the envmap cannot be found." ); #endif diff --git a/sp/src/public/tier0/platform.h b/sp/src/public/tier0/platform.h index 422a006f..f463847b 100644 --- a/sp/src/public/tier0/platform.h +++ b/sp/src/public/tier0/platform.h @@ -1234,6 +1234,14 @@ inline bool Plat_IsInDebugSession( bool bForceRecheck = false ) { return false; PLATFORM_INTERFACE bool Is64BitOS(); +#ifdef MAPBASE +//----------------------------------------------------------------------------- +// General Mapbase version constant compiled into projects for versioning purposes +//----------------------------------------------------------------------------- +#define MAPBASE_VERSION "7.0" +#endif + + //----------------------------------------------------------------------------- // XBOX Components valid in PC compilation space //----------------------------------------------------------------------------- From ea7d1afa083fb6c28b9f1ba4cd5c987150b5e82a Mon Sep 17 00:00:00 2001 From: Blixibon Date: Mon, 28 Jun 2021 21:07:30 -0500 Subject: [PATCH 095/378] Fixed a few minor mistakes and aliasing oversights --- sp/src/game/client/vgui_movie_display.cpp | 5 ++--- sp/src/game/server/basecombatcharacter.cpp | 5 ++--- sp/src/game/server/filters.cpp | 1 + sp/src/game/server/mapbase/logic_externaldata.cpp | 2 +- sp/src/game/shared/mapbase/vscript_consts_shared.cpp | 3 +-- 5 files changed, 7 insertions(+), 9 deletions(-) diff --git a/sp/src/game/client/vgui_movie_display.cpp b/sp/src/game/client/vgui_movie_display.cpp index 7b80a59c..7bc5bb62 100644 --- a/sp/src/game/client/vgui_movie_display.cpp +++ b/sp/src/game/client/vgui_movie_display.cpp @@ -368,11 +368,10 @@ bool CMovieDisplayScreen::BeginPlayback( const char *pFilename ) } else { - Q_strncpy( szMaterialName, pFilename, sizeof(szMaterialName) ); + Q_snprintf( szMaterialName, sizeof(szMaterialName), "%s_%s", pFilename, m_hScreenEntity->GetEntityName() ); } - const char *pszMaterialName = CFmtStrN<128>( "VideoMaterial_%s", m_hScreenEntity->GetEntityName() ); - m_VideoMaterial = g_pVideo->CreateVideoMaterial( pszMaterialName, pFilename, "GAME", + m_VideoMaterial = g_pVideo->CreateVideoMaterial( szMaterialName, pFilename, "GAME", VideoPlaybackFlags::DEFAULT_MATERIAL_OPTIONS, VideoSystem::DETERMINE_FROM_FILE_EXTENSION/*, m_bAllowAlternateMedia*/ ); diff --git a/sp/src/game/server/basecombatcharacter.cpp b/sp/src/game/server/basecombatcharacter.cpp index 6facbb2b..6c59d88a 100644 --- a/sp/src/game/server/basecombatcharacter.cpp +++ b/sp/src/game/server/basecombatcharacter.cpp @@ -4055,14 +4055,13 @@ void CBaseCombatCharacter::InputKilledNPC( inputdata_t &inputdata ) #ifdef MAPBASE //----------------------------------------------------------------------------- -// Purpose: Handle enemy kills. This actually measures players too. +// Purpose: Handle enemy kills. (this technically measures players too) //----------------------------------------------------------------------------- void CBaseCombatCharacter::OnKilledNPC( CBaseCombatCharacter *pKilled ) { - // I know this can sometimes pass as NULL, but that can work here...right? m_OnKilledEnemy.Set(pKilled, pKilled, this); - // Fire an additional output if this was the player + // Fire an additional output if this was a player if (pKilled && pKilled->IsPlayer()) m_OnKilledPlayer.Set(pKilled, pKilled, this); } diff --git a/sp/src/game/server/filters.cpp b/sp/src/game/server/filters.cpp index 8b7dcfc9..84021a95 100644 --- a/sp/src/game/server/filters.cpp +++ b/sp/src/game/server/filters.cpp @@ -1522,6 +1522,7 @@ public: void Activate() { + BaseClass::Activate(); ParseSurfaceIndex(); } diff --git a/sp/src/game/server/mapbase/logic_externaldata.cpp b/sp/src/game/server/mapbase/logic_externaldata.cpp index c13117f5..588bb6c7 100644 --- a/sp/src/game/server/mapbase/logic_externaldata.cpp +++ b/sp/src/game/server/mapbase/logic_externaldata.cpp @@ -96,7 +96,7 @@ BEGIN_ENT_SCRIPTDESC( CLogicExternalData, CBaseEntity, "An entity which loads ke DEFINE_SCRIPTFUNC_NAMED( ScriptGetKeyValueBlock, "GetKeyValueBlock", "Gets the current external data block expressed in CScriptKeyValues." ) DEFINE_SCRIPTFUNC_NAMED( ScriptSetKeyValues, "SetKeyValues", "Sets the external data from a CScriptKeyValues object." ) - DEFINE_SCRIPTFUNC_NAMED( ScriptSetKeyValueBlock, "SetKeyValues", "Sets the current external data block from a CScriptKeyValues object." ) + DEFINE_SCRIPTFUNC_NAMED( ScriptSetKeyValueBlock, "SetKeyValueBlock", "Sets the current external data block from a CScriptKeyValues object." ) DEFINE_SCRIPTFUNC( LoadFile, "Loads external data from the external file." ) DEFINE_SCRIPTFUNC( SaveFile, "Saves the external data to the external file." ) diff --git a/sp/src/game/shared/mapbase/vscript_consts_shared.cpp b/sp/src/game/shared/mapbase/vscript_consts_shared.cpp index 5d4675c5..dd14ddaf 100644 --- a/sp/src/game/shared/mapbase/vscript_consts_shared.cpp +++ b/sp/src/game/shared/mapbase/vscript_consts_shared.cpp @@ -500,8 +500,7 @@ void RegisterSharedScriptConstants() //ScriptRegisterConstant( g_pScriptVM, AISS_AUTO_PVS_AFTER_PVS, "" ); ScriptRegisterConstant( g_pScriptVM, AI_SLEEP_FLAGS_NONE, "No sleep flags. (NPC sleep flag used in Add/Remove/HasSleepFlags())" ); ScriptRegisterConstant( g_pScriptVM, AI_SLEEP_FLAG_AUTO_PVS, "Indicates a NPC will sleep upon exiting PVS. (NPC sleep flag used in Add/Remove/HasSleepFlags())" ); - // note: the one "?" is escaped to prevent evaluation of a trigraph - ScriptRegisterConstant( g_pScriptVM, AI_SLEEP_FLAG_AUTO_PVS_AFTER_PVS, "Indicates a NPC will sleep upon exiting PVS after entering PVS for the first time(????\?) (NPC sleep flag used in Add/Remove/HasSleepFlags())" ); + ScriptRegisterConstant( g_pScriptVM, AI_SLEEP_FLAG_AUTO_PVS_AFTER_PVS, "Indicates a NPC will sleep upon exiting PVS after entering PVS for the first time(?) (NPC sleep flag used in Add/Remove/HasSleepFlags())" ); ScriptRegisterConstantNamed( g_pScriptVM, CAI_BaseNPC::SCRIPT_PLAYING, "SCRIPT_PLAYING", "Playing the action animation." ); ScriptRegisterConstantNamed( g_pScriptVM, CAI_BaseNPC::SCRIPT_WAIT, "SCRIPT_WAIT", "Waiting on everyone in the script to be ready. Plays the pre idle animation if there is one." ); From 29075a2c90bf5c871aab64e89bef07d457faa840 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Mon, 28 Jun 2021 23:51:24 -0500 Subject: [PATCH 096/378] Added experimental static/global VScript hooks not tied to any particular class, starting with the integration of OnSave/OnRestore --- .../shared/mapbase/vscript_singletons.cpp | 11 + sp/src/public/vscript/ivscript.h | 17 + sp/src/utils/vbsp/vscript_vbsp.cpp | 3 + sp/src/vscript/vscript_squirrel.cpp | 14 +- sp/src/vscript/vscript_squirrel.nut | 434 +++++++++--------- 5 files changed, 260 insertions(+), 219 deletions(-) diff --git a/sp/src/game/shared/mapbase/vscript_singletons.cpp b/sp/src/game/shared/mapbase/vscript_singletons.cpp index 6aba49af..b2f829a5 100644 --- a/sp/src/game/shared/mapbase/vscript_singletons.cpp +++ b/sp/src/game/shared/mapbase/vscript_singletons.cpp @@ -835,6 +835,9 @@ static void FireGameEventLocal( const char* szEvent, HSCRIPT hTable ) } #endif // !CLIENT_DLL +static ScriptHook_t g_Hook_OnSave; +static ScriptHook_t g_Hook_OnRestore; + //============================================================================= // Save/Restore Utility // Based on L4D2 API @@ -852,6 +855,9 @@ public: // IGameSystem { if ( g_pScriptVM ) { + g_Hook_OnSave.Call( NULL, NULL, NULL ); + + // Legacy hook HSCRIPT hFunc = g_pScriptVM->LookupFunction( "OnSave" ); if ( hFunc ) { @@ -870,6 +876,9 @@ public: // IGameSystem { if ( g_pScriptVM ) { + g_Hook_OnRestore.Call( NULL, NULL, NULL ); + + // Legacy hook HSCRIPT hFunc = g_pScriptVM->LookupFunction( "OnRestore" ); if ( hFunc ) { @@ -3033,6 +3042,8 @@ void RegisterScriptSingletons() ScriptRegisterFunctionNamed( g_pScriptVM, CScriptSaveRestoreUtil::SaveTable, "SaveTable", "Store a table with primitive values that will persist across level transitions and save loads." ); ScriptRegisterFunctionNamed( g_pScriptVM, CScriptSaveRestoreUtil::RestoreTable, "RestoreTable", "Retrieves a table from storage. Write into input table." ); ScriptRegisterFunctionNamed( g_pScriptVM, CScriptSaveRestoreUtil::ClearSavedTable, "ClearSavedTable", "Removes the table with the given context." ); + ScriptRegisterSimpleHook( g_pScriptVM, g_Hook_OnSave, "OnSave", FIELD_VOID, "Called when the game is saved." ); + ScriptRegisterSimpleHook( g_pScriptVM, g_Hook_OnRestore, "OnRestore", FIELD_VOID, "Called when the game is restored." ); ScriptRegisterFunctionNamed( g_pScriptVM, CScriptReadWriteFile::FileWrite, "StringToFile", "Stores the string into the file" ); ScriptRegisterFunctionNamed( g_pScriptVM, CScriptReadWriteFile::FileRead, "FileToString", "Returns the string from the file, null if no file or file is too big." ); ScriptRegisterFunctionNamed( g_pScriptVM, CScriptReadWriteFile::KeyValuesWrite, "KeyValuesToFile", "Stores the CScriptKeyValues into the file" ); diff --git a/sp/src/public/vscript/ivscript.h b/sp/src/public/vscript/ivscript.h index a0c2bdcf..5fe1d570 100644 --- a/sp/src/public/vscript/ivscript.h +++ b/sp/src/public/vscript/ivscript.h @@ -755,6 +755,23 @@ static inline int ToConstantVariant(int value) pDesc->m_Hooks.AddToTail(pHook); \ } +// Static hooks (or "global" hooks) are not tied to specific classes +#define END_SCRIPTHOOK_STATIC( pVM ) \ + pVM->RegisterHook( pHook ); \ + } + +#define ScriptRegisterSimpleHook( pVM, hook, hookName, returnType, description ) \ + if (!hook.m_bDefined) \ + { \ + ScriptHook_t *pHook = &hook; \ + pHook->m_desc.m_pszScriptName = hookName; pHook->m_desc.m_pszFunction = #hook; pHook->m_desc.m_ReturnType = returnType; pHook->m_desc.m_pszDescription = description; \ + pVM->RegisterHook( pHook ); \ + } + +#define ScriptRegisterConstant( pVM, constant, description ) ScriptRegisterConstantNamed( pVM, constant, #constant, description ) +#define ScriptRegisterConstantNamed( pVM, constant, scriptName, description ) do { static ScriptConstantBinding_t binding; binding.m_pszScriptName = scriptName; binding.m_pszDescription = description; binding.m_data = ToConstantVariant(constant); pVM->RegisterConstant( &binding ); } while (0) + + #define DEFINE_MEMBERVAR( varName, returnType, description ) \ do { ScriptMemberDesc_t *pBinding = &((pDesc)->m_Members[(pDesc)->m_Members.AddToTail()]); pBinding->m_pszScriptName = varName; pBinding->m_pszDescription = description; pBinding->m_ReturnType = returnType; } while (0); #endif diff --git a/sp/src/utils/vbsp/vscript_vbsp.cpp b/sp/src/utils/vbsp/vscript_vbsp.cpp index c8295e02..abaa2d66 100644 --- a/sp/src/utils/vbsp/vscript_vbsp.cpp +++ b/sp/src/utils/vbsp/vscript_vbsp.cpp @@ -43,6 +43,9 @@ extern ScriptClassDesc_t * GetScriptDesc( CBaseEntity * ); extern int vscript_token; int vscript_token_hack = vscript_token; +// HACKHACK: VScript library relies on developer convar existing +ConVar developer( "developer", "1", 0, "Set developer message level." ); // developer mode + HSCRIPT VScriptCompileScript( const char *pszScriptName, bool bWarnMissing ) { if ( !g_pScriptVM ) diff --git a/sp/src/vscript/vscript_squirrel.cpp b/sp/src/vscript/vscript_squirrel.cpp index f14618e5..fa4c15d2 100644 --- a/sp/src/vscript/vscript_squirrel.cpp +++ b/sp/src/vscript/vscript_squirrel.cpp @@ -2350,7 +2350,11 @@ ScriptStatus_t SquirrelVM::ExecuteFunction(HSCRIPT hFunction, ScriptVariant_t* p bool SquirrelVM::ScopeIsHooked( HSCRIPT hScope, const char *pszEventName ) { - Assert( hScope && hScope != INVALID_HSCRIPT ); + // For now, assume null scope (which is used for global hooks) is always hooked + if (!hScope) + return true; + + Assert(hScope != INVALID_HSCRIPT); sq_pushroottable(vm_); sq_pushstring(vm_, "Hooks", -1); @@ -2375,7 +2379,7 @@ bool SquirrelVM::ScopeIsHooked( HSCRIPT hScope, const char *pszEventName ) HSCRIPT SquirrelVM::LookupHookFunction(const char *pszEventName, HSCRIPT hScope, bool &bLegacy) { - HSCRIPT hFunc = LookupFunction( pszEventName, hScope ); + HSCRIPT hFunc = hScope ? LookupFunction( pszEventName, hScope ) : nullptr; if (hFunc) { bLegacy = true; @@ -2421,7 +2425,11 @@ ScriptStatus_t SquirrelVM::ExecuteHookFunction(const char *pszEventName, HSCRIPT // TODO: Run in hook scope sq_pushroottable(vm_); - sq_pushobject(vm_, *((HSQOBJECT*)hScope)); + if (hScope) + sq_pushobject(vm_, *((HSQOBJECT*)hScope)); + else + sq_pushnull(vm_); // global hook + sq_pushstring(vm_, pszEventName, -1); for (int i = 0; i < nArgs; ++i) diff --git a/sp/src/vscript/vscript_squirrel.nut b/sp/src/vscript/vscript_squirrel.nut index 85c895ac..79cfb6c4 100644 --- a/sp/src/vscript/vscript_squirrel.nut +++ b/sp/src/vscript/vscript_squirrel.nut @@ -122,8 +122,6 @@ class CSimpleCallChainer chain = null; } -local developer = (delete developer)() - //--------------------------------------------------------- // Hook handler //--------------------------------------------------------- @@ -199,7 +197,26 @@ Hooks <- { local firstReturn = null - if ( scope in s_List ) + if ( scope == null ) + { + // null scope = global hook; call all scopes + vargv.insert(0,this) + foreach ( t in s_List ) + { + if ( event in t ) + { + foreach( context, callback in t[event] ) + { + //printf( "(%.4f) Calling hook '%s' of context '%s' in static iteration\n", Time(), event, context ) + + local curReturn = callback.acall(vargv) + if (firstReturn == null) + firstReturn = curReturn + } + } + } + } + else if ( scope in s_List ) { local t = s_List[scope] if ( event in t ) @@ -236,246 +253,231 @@ Hooks <- //--------------------------------------------------------- __Documentation <- {} -local DocumentedFuncs -local DocumentedClasses -local DocumentedEnums -local DocumentedConsts -local DocumentedHooks -local DocumentedMembers +local developer = (delete developer)() if (developer) { - DocumentedFuncs = {} - DocumentedClasses = {} - DocumentedEnums = {} - DocumentedConsts = {} - DocumentedHooks = {} - DocumentedMembers = {} -} + local DocumentedFuncs = {} + local DocumentedClasses = {} + local DocumentedEnums = {} + local DocumentedConsts = {} + local DocumentedHooks = {} + local DocumentedMembers = {} -local function AddAliasedToTable(name, signature, description, table) -{ - // This is an alias function, could use split() if we could guarantee - // that ':' would not occur elsewhere in the description and Squirrel had - // a convience join() function -- It has split() - local colon = description.find(":"); - if (colon == null) - colon = description.len(); - local alias = description.slice(1, colon); - description = description.slice(colon + 1); - name = alias; - signature = null; - - table[name] <- [signature, description]; -} - -function __Documentation::RegisterHelp(name, signature, description) -{ - if ( !developer ) - return - - if (description.len() && description[0] == '#') + local function AddAliasedToTable(name, signature, description, table) { - AddAliasedToTable(name, signature, description, DocumentedFuncs) + // This is an alias function, could use split() if we could guarantee + // that ':' would not occur elsewhere in the description and Squirrel had + // a convience join() function -- It has split() + local colon = description.find(":"); + if (colon == null) + colon = description.len(); + local alias = description.slice(1, colon); + description = description.slice(colon + 1); + name = alias; + signature = null; + + table[name] <- [signature, description]; } - else + + function __Documentation::RegisterHelp(name, signature, description) { - DocumentedFuncs[name] <- [signature, description]; - } -} - -function __Documentation::RegisterClassHelp(name, baseclass, description) -{ - if ( !developer ) - return - - DocumentedClasses[name] <- [baseclass, description]; -} - -function __Documentation::RegisterEnumHelp(name, num_elements, description) -{ - if ( !developer ) - return - - DocumentedEnums[name] <- [num_elements, description]; -} - -function __Documentation::RegisterConstHelp(name, signature, description) -{ - if ( !developer ) - return - - if (description.len() && description[0] == '#') - { - AddAliasedToTable(name, signature, description, DocumentedConsts) - } - else - { - DocumentedConsts[name] <- [signature, description]; - } -} - -function __Documentation::RegisterHookHelp(name, signature, description) -{ - if ( !developer ) - return - - DocumentedHooks[name] <- [signature, description]; -} - -function __Documentation::RegisterMemberHelp(name, signature, description) -{ - if ( !developer ) - return - - DocumentedMembers[name] <- [signature, description]; -} - -local function printdoc( text ) -{ - return ::printc(200,224,255,text); -} - -local function printdocl( text ) -{ - return printdoc(text + "\n"); -} - -local function PrintClass(name, doc) -{ - local text = "=====================================\n"; - text += ("Class: " + name + "\n"); - text += ("Base: " + doc[0] + "\n"); - if (doc[1].len()) - text += ("Description: " + doc[1] + "\n"); - text += "=====================================\n\n"; - - printdoc(text); -} - -local function PrintFunc(name, doc) -{ - local text = "Function: " + name + "\n" - - if (doc[0] == null) - { - // Is an aliased function - text += ("Signature: function " + name + "("); - foreach(k,v in this[name].getinfos().parameters) + if (description.len() && description[0] == '#') { - if (k == 0 && v == "this") continue; - if (k > 1) text += (", "); - text += (v); + AddAliasedToTable(name, signature, description, DocumentedFuncs) + } + else + { + DocumentedFuncs[name] <- [signature, description]; } - text += (")\n"); } - else + + function __Documentation::RegisterClassHelp(name, baseclass, description) { + DocumentedClasses[name] <- [baseclass, description]; + } + + function __Documentation::RegisterEnumHelp(name, num_elements, description) + { + DocumentedEnums[name] <- [num_elements, description]; + } + + function __Documentation::RegisterConstHelp(name, signature, description) + { + if (description.len() && description[0] == '#') + { + AddAliasedToTable(name, signature, description, DocumentedConsts) + } + else + { + DocumentedConsts[name] <- [signature, description]; + } + } + + function __Documentation::RegisterHookHelp(name, signature, description) + { + DocumentedHooks[name] <- [signature, description]; + } + + function __Documentation::RegisterMemberHelp(name, signature, description) + { + DocumentedMembers[name] <- [signature, description]; + } + + local function printdoc( text ) + { + return ::printc(200,224,255,text); + } + + local function printdocl( text ) + { + return printdoc(text + "\n"); + } + + local function PrintClass(name, doc) + { + local text = "=====================================\n"; + text += ("Class: " + name + "\n"); + text += ("Base: " + doc[0] + "\n"); + if (doc[1].len()) + text += ("Description: " + doc[1] + "\n"); + text += "=====================================\n\n"; + + printdoc(text); + } + + local function PrintFunc(name, doc) + { + local text = "Function: " + name + "\n" + + if (doc[0] == null) + { + // Is an aliased function + text += ("Signature: function " + name + "("); + foreach(k,v in this[name].getinfos().parameters) + { + if (k == 0 && v == "this") continue; + if (k > 1) text += (", "); + text += (v); + } + text += (")\n"); + } + else + { + text += ("Signature: " + doc[0] + "\n"); + } + if (doc[1].len()) + text += ("Description: " + doc[1] + "\n"); + printdocl(text); + } + + local function PrintMember(name, doc) + { + local text = ("Member: " + name + "\n"); text += ("Signature: " + doc[0] + "\n"); + if (doc[1].len()) + text += ("Description: " + doc[1] + "\n"); + printdocl(text); } - if (doc[1].len()) - text += ("Description: " + doc[1] + "\n"); - printdocl(text); -} -local function PrintMember(name, doc) -{ - local text = ("Member: " + name + "\n"); - text += ("Signature: " + doc[0] + "\n"); - if (doc[1].len()) - text += ("Description: " + doc[1] + "\n"); - printdocl(text); -} - -local function PrintEnum(name, doc) -{ - local text = "=====================================\n"; - text += ("Enum: " + name + "\n"); - text += ("Elements: " + doc[0] + "\n"); - if (doc[1].len()) - text += ("Description: " + doc[1] + "\n"); - text += "=====================================\n\n"; - - printdoc(text); -} - -local function PrintConst(name, doc) -{ - local text = ("Constant: " + name + "\n"); - if (doc[0] == null) + local function PrintEnum(name, doc) { - text += ("Value: null\n"); + local text = "=====================================\n"; + text += ("Enum: " + name + "\n"); + text += ("Elements: " + doc[0] + "\n"); + if (doc[1].len()) + text += ("Description: " + doc[1] + "\n"); + text += "=====================================\n\n"; + + printdoc(text); } - else - { - text += ("Value: " + doc[0] + "\n"); - } - if (doc[1].len()) - text += ("Description: " + doc[1] + "\n"); - printdocl(text); -} -local function PrintHook(name, doc) -{ - local text = ("Hook: " + name + "\n"); - if (doc[0] == null) + local function PrintConst(name, doc) { - // Is an aliased function - text += ("Signature: function " + name + "("); - foreach(k,v in this[name].getinfos().parameters) + local text = ("Constant: " + name + "\n"); + if (doc[0] == null) { - if (k == 0 && v == "this") continue; - if (k > 1) text += (", "); - text += (v); + text += ("Value: null\n"); } - text += (")\n"); - } - else - { - text += ("Signature: " + doc[0] + "\n"); - } - if (doc[1].len()) - text += ("Description: " + doc[1] + "\n"); - printdocl(text); -} - -local function PrintMatchesInDocList(pattern, list, printfunc) -{ - local foundMatches = 0; - - foreach(name, doc in list) - { - if (pattern == "*" || name.tolower().find(pattern) != null || (doc[1].len() && doc[1].tolower().find(pattern) != null)) + else { - foundMatches = 1; - printfunc(name, doc) + text += ("Value: " + doc[0] + "\n"); + } + if (doc[1].len()) + text += ("Description: " + doc[1] + "\n"); + printdocl(text); + } + + local function PrintHook(name, doc) + { + local text = ("Hook: " + name + "\n"); + if (doc[0] == null) + { + // Is an aliased function + text += ("Signature: function " + name + "("); + foreach(k,v in this[name].getinfos().parameters) + { + if (k == 0 && v == "this") continue; + if (k > 1) text += (", "); + text += (v); + } + text += (")\n"); + } + else + { + text += ("Signature: " + doc[0] + "\n"); + } + if (doc[1].len()) + text += ("Description: " + doc[1] + "\n"); + printdocl(text); + } + + local function PrintMatchesInDocList(pattern, list, printfunc) + { + local foundMatches = 0; + + foreach(name, doc in list) + { + if (pattern == "*" || name.tolower().find(pattern) != null || (doc[1].len() && doc[1].tolower().find(pattern) != null)) + { + foundMatches = 1; + printfunc(name, doc) + } + } + + return foundMatches; + } + + function __Documentation::PrintHelp(pattern = "*") + { + local patternLower = pattern.tolower(); + + // Have a specific order + if (!( + PrintMatchesInDocList( patternLower, DocumentedEnums, PrintEnum ) | + PrintMatchesInDocList( patternLower, DocumentedConsts, PrintConst ) | + PrintMatchesInDocList( patternLower, DocumentedClasses, PrintClass ) | + PrintMatchesInDocList( patternLower, DocumentedFuncs, PrintFunc ) | + PrintMatchesInDocList( patternLower, DocumentedMembers, PrintMember ) | + PrintMatchesInDocList( patternLower, DocumentedHooks, PrintHook ) + )) + { + printdocl("Pattern " + pattern + " not found"); } } - - return foundMatches; } - -function __Documentation::PrintHelp(pattern = "*") +else { - if ( !developer ) - { - printdocl("Documentation is not enabled. To enable documentation, restart the server with the 'developer' cvar set to 1 or higher."); - return - } + __Documentation.RegisterHelp <- + __Documentation.RegisterClassHelp <- + __Documentation.RegisterEnumHelp <- + __Documentation.RegisterConstHelp <- + __Documentation.RegisterHookHelp <- + __Documentation.RegisterMemberHelp <- dummy - local patternLower = pattern.tolower(); - - // Have a specific order - if (!( - PrintMatchesInDocList( patternLower, DocumentedEnums, PrintEnum ) | - PrintMatchesInDocList( patternLower, DocumentedConsts, PrintConst ) | - PrintMatchesInDocList( patternLower, DocumentedClasses, PrintClass ) | - PrintMatchesInDocList( patternLower, DocumentedFuncs, PrintFunc ) | - PrintMatchesInDocList( patternLower, DocumentedMembers, PrintMember ) | - PrintMatchesInDocList( patternLower, DocumentedHooks, PrintHook ) - )) + function __Documentation::PrintHelp( pattern = null ) { - printdocl("Pattern " + pattern + " not found"); + printcl(200, 224, 255, "Documentation is not enabled. To enable documentation, restart the server with the 'developer' cvar set to 1 or higher."); } } From 0fb0a3319cd7ae3d1be8ed11225bd0b0203d6686 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Mon, 28 Jun 2021 23:55:42 -0500 Subject: [PATCH 097/378] 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 // From 29635bac522255c78d58d7f72440f293a7d8ccf4 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Mon, 28 Jun 2021 23:59:36 -0500 Subject: [PATCH 098/378] Added experimental support for map-specific surfaceproperties scripts --- sp/src/game/shared/mapbase/mapbase_shared.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/sp/src/game/shared/mapbase/mapbase_shared.cpp b/sp/src/game/shared/mapbase/mapbase_shared.cpp index e9527f72..0f3db5b8 100644 --- a/sp/src/game/shared/mapbase/mapbase_shared.cpp +++ b/sp/src/game/shared/mapbase/mapbase_shared.cpp @@ -53,7 +53,9 @@ ConVar mapbase_load_soundscripts("mapbase_load_soundscripts", "1", FCVAR_ARCHIVE //ConVar mapbase_load_soundscapes("mapbase_load_soundscapes", "1", FCVAR_ARCHIVE, "Should we load map-specific soundscapes? e.g. \"maps/mapname_soundscapes.txt\""); -ConVar mapbase_load_localization("mapbase_load_localization", "1", FCVAR_ARCHIVE, "Should we load map-specific localized text files? e.g. \"maps/mapname_english.txt\""); +ConVar mapbase_load_localization( "mapbase_load_localization", "1", FCVAR_ARCHIVE, "Should we load map-specific localized text files? e.g. \"maps/mapname_english.txt\"" ); + +ConVar mapbase_load_surfaceprops( "mapbase_load_surfaceprops", "1", FCVAR_ARCHIVE, "Should we load map-specific surfaceproperties files? e.g. \"maps/mapname_surfaceproperties.txt\"" ); #ifdef GAME_DLL // This constant should change with each Mapbase update @@ -83,6 +85,8 @@ ConVar mapbase_version_client( "mapbase_version_client", MAPBASE_VERSION, FCVAR_ #endif +extern void AddSurfacepropFile( const char *pFileName, IPhysicsSurfaceProps *pProps, IFileSystem *pFileSystem ); + // Indicates this is a core Mapbase mod and not a mod using its code. static bool g_bMapbaseCore; @@ -95,6 +99,7 @@ enum //MANIFEST_PROPDATA, //MANIFEST_SOUNDSCAPES, MANIFEST_LOCALIZATION, + MANIFEST_SURFACEPROPS, #ifdef CLIENT_DLL //MANIFEST_CLOSECAPTION, MANIFEST_VGUI, @@ -121,6 +126,7 @@ static const ManifestType_t gm_szManifestFileStrings[MANIFEST_NUM_TYPES] = { //{ "propdata", &mapbase_load_propdata }, //{ "soundscapes", &mapbase_load_soundscapes }, { "localization", &mapbase_load_localization }, + { "surfaceprops", &mapbase_load_surfaceprops }, #ifdef CLIENT_DLL //{ "closecaption", &mapbase_load_cc }, { "vgui", NULL }, @@ -381,6 +387,7 @@ public: case MANIFEST_SOUNDSCRIPTS: { soundemitterbase->AddSoundOverrides(value); } break; //case MANIFEST_PROPDATA: { g_PropDataSystem.ParsePropDataFile(value); } break; case MANIFEST_LOCALIZATION: { g_pVGuiLocalize->AddFile( value, "MOD", true ); } break; + case MANIFEST_SURFACEPROPS: { AddSurfacepropFile( value, physprops, filesystem ); } break; #ifdef CLIENT_DLL //case MANIFEST_CLOSECAPTION: { todo } break; case MANIFEST_VGUI: { PanelMetaClassMgr()->LoadMetaClassDefinitionFile( value ); } break; From b41d49c639d3a1a5042a24618169c0714e167df7 Mon Sep 17 00:00:00 2001 From: Alexander 'z33ky' Hirsch <1zeeky@gmail.com> Date: Sun, 6 Jun 2021 16:08:39 +0200 Subject: [PATCH 099/378] Fix scene file loading memory errors Fixes leaks. Also safeguards against deallocated pointers by doing g_TokenProcessor.SetBuffer(NULL) after parsing is done - an access at NULL should be easier to debug than at some random address, potentially just reading in garbage data. --- sp/src/game/server/sceneentity.cpp | 31 +++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/sp/src/game/server/sceneentity.cpp b/sp/src/game/server/sceneentity.cpp index 67ca064a..5cef9cc0 100644 --- a/sp/src/game/server/sceneentity.cpp +++ b/sp/src/game/server/sceneentity.cpp @@ -3735,7 +3735,7 @@ CChoreoScene *CSceneEntity::LoadScene( const char *filename, IChoreoEventCallbac Q_FixSlashes( loadfile ); // binary compiled vcd - void *pBuffer; + void *pBuffer = NULL; #ifdef MAPBASE // // Raw scene file support @@ -3760,12 +3760,13 @@ CChoreoScene *CSceneEntity::LoadScene( const char *filename, IChoreoEventCallbac { g_TokenProcessor.SetBuffer((char*)pBuffer); pScene = ChoreoLoadScene( loadfile, NULL, &g_TokenProcessor, LocalScene_Printf ); + g_TokenProcessor.SetBuffer(NULL); } // Okay, it's definitely missing. else { MissingSceneWarning( loadfile ); - return NULL; + pScene = NULL; } if (pScene) @@ -4283,6 +4284,7 @@ CBaseEntity *CSceneEntity::FindNamedEntity( const char *name, CBaseEntity *pActo #ifdef MAPBASE const char *GetFirstSoundInScene(const char *pszScene) { + const char *soundName; SceneCachedData_t sceneData; if ( scenefilecache->GetSceneCachedData( pszScene, &sceneData ) ) { @@ -4292,7 +4294,7 @@ const char *GetFirstSoundInScene(const char *pszScene) short stringId = scenefilecache->GetSceneCachedSound( sceneData.sceneId, 0 ); // Trust that it's been precached - return scenefilecache->GetSceneString( stringId ); + soundName = scenefilecache->GetSceneString( stringId ); } } else @@ -4302,6 +4304,7 @@ const char *GetFirstSoundInScene(const char *pszScene) { g_TokenProcessor.SetBuffer((char*)pBuffer); CChoreoScene *pScene = ChoreoLoadScene( pszScene, NULL, &g_TokenProcessor, LocalScene_Printf ); + g_TokenProcessor.SetBuffer(NULL); if (pScene) { for (int i = 0; i < pScene->GetNumEvents(); i++) @@ -4309,13 +4312,17 @@ const char *GetFirstSoundInScene(const char *pszScene) CChoreoEvent *pEvent = pScene->GetEvent(i); if (pEvent->GetType() == CChoreoEvent::SPEAK) - return pEvent->GetParameters(); + { + soundName = pEvent->GetParameters(); + break; + } } } } + FreeSceneFileMemory( pBuffer ); } - return NULL; + return soundName; } const char *GetFirstSoundInScene(CChoreoScene *scene) @@ -4483,6 +4490,8 @@ bool CSceneEntity::ScriptLoadSceneFromString(const char* pszFilename, const char PrecacheScene(pScene); } + g_TokenProcessor.SetBuffer(NULL); + if (pScene != NULL) { // release prior scene if present @@ -5284,12 +5293,12 @@ int GetSceneSpeechCount( char const *pszScene ) else { void *pBuffer = NULL; + int iNumSounds = 0; if (filesystem->ReadFileEx( pszScene, "MOD", &pBuffer, true )) { - int iNumSounds = 0; - g_TokenProcessor.SetBuffer((char*)pBuffer); CChoreoScene *pScene = ChoreoLoadScene( pszScene, NULL, &g_TokenProcessor, LocalScene_Printf ); + g_TokenProcessor.SetBuffer(NULL); if (pScene) { for (int i = 0; i < pScene->GetNumEvents(); i++) @@ -5300,9 +5309,11 @@ int GetSceneSpeechCount( char const *pszScene ) iNumSounds++; } } - - return iNumSounds; } + + FreeSceneFileMemory( pBuffer ); + + return iNumSounds; } #endif return 0; @@ -5367,7 +5378,9 @@ void PrecacheInstancedScene( char const *pszScene ) { PrecacheChoreoScene(pScene); } + g_TokenProcessor.SetBuffer(NULL); } + FreeSceneFileMemory( pBuffer ); #else // Scenes are sloppy and don't always exist. // A scene that is not in the pre-built cache image, but on disk, is a true error. From 7ad12764fad373345064b755924338e3bec08dcb Mon Sep 17 00:00:00 2001 From: Alexander 'z33ky' Hirsch <1zeeky@gmail.com> Date: Sun, 6 Jun 2021 17:03:00 +0200 Subject: [PATCH 100/378] Fix console error on BreakableBrushes without spawnobject --- sp/src/game/server/func_break.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sp/src/game/server/func_break.cpp b/sp/src/game/server/func_break.cpp index bb7dff50..fd4839ae 100644 --- a/sp/src/game/server/func_break.cpp +++ b/sp/src/game/server/func_break.cpp @@ -221,6 +221,10 @@ bool CBreakable::KeyValue( const char *szKeyName, const char *szValue ) if ( object > 0 && object < ARRAYSIZE(pSpawnObjects) ) m_iszSpawnObject = MAKE_STRING( pSpawnObjects[object] ); #ifdef MAPBASE + // "0" is the default value of a "choices" field in Hammer, representing nothing selected + // atoi() returning 0 may also indicate a failed conversion, so check szValue directly + else if ( FStrEq( szValue, "0" ) ) + m_iszSpawnObject = NULL_STRING; else m_iszSpawnObject = AllocPooledString(szValue); #endif From 1b534af69dbe973b3bedab8557f6aff2f1974770 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Mon, 12 Jul 2021 14:35:43 -0500 Subject: [PATCH 101/378] Made a bunch of static movement cvars editable in-game --- sp/src/game/shared/movevars_shared.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sp/src/game/shared/movevars_shared.cpp b/sp/src/game/shared/movevars_shared.cpp index b5b94c72..563d96e3 100644 --- a/sp/src/game/shared/movevars_shared.cpp +++ b/sp/src/game/shared/movevars_shared.cpp @@ -36,7 +36,7 @@ float GetCurrentGravity( void ) ConVar sv_gravity ( "sv_gravity", DEFAULT_GRAVITY_STRING, FCVAR_NOTIFY | FCVAR_REPLICATED, "World gravity." ); -#if defined( DOD_DLL ) || defined( CSTRIKE_DLL ) || defined( HL1MP_DLL ) +#if defined( DOD_DLL ) || defined( CSTRIKE_DLL ) || defined( HL1MP_DLL ) || defined( MAPBASE ) ConVar sv_stopspeed ( "sv_stopspeed","100", FCVAR_NOTIFY | FCVAR_REPLICATED, "Minimum stopping speed when on ground." ); #else ConVar sv_stopspeed ( "sv_stopspeed","100", FCVAR_NOTIFY | FCVAR_REPLICATED | FCVAR_DEVELOPMENTONLY, "Minimum stopping speed when on ground." ); @@ -48,7 +48,7 @@ ConVar sv_specaccelerate( "sv_specaccelerate", "5", FCVAR_NOTIFY | FCVAR_ARCHIVE ConVar sv_specspeed ( "sv_specspeed", "3", FCVAR_ARCHIVE | FCVAR_NOTIFY | FCVAR_REPLICATED); ConVar sv_specnoclip ( "sv_specnoclip", "1", FCVAR_ARCHIVE | FCVAR_NOTIFY | FCVAR_REPLICATED); -#if defined( CSTRIKE_DLL ) || defined( HL1MP_DLL ) +#if defined( CSTRIKE_DLL ) || defined( HL1MP_DLL ) || defined( MAPBASE ) ConVar sv_maxspeed ( "sv_maxspeed", "320", FCVAR_NOTIFY | FCVAR_REPLICATED); #else ConVar sv_maxspeed ( "sv_maxspeed", "320", FCVAR_NOTIFY | FCVAR_REPLICATED | FCVAR_DEVELOPMENTONLY); @@ -58,7 +58,7 @@ ConVar sv_maxspeed ( "sv_maxspeed", "320", FCVAR_NOTIFY | FCVAR_REPLICATED | FC ConVar sv_accelerate ( "sv_accelerate", "7", FCVAR_NOTIFY | FCVAR_REPLICATED); #else -#if defined( CSTRIKE_DLL ) || defined( HL1MP_DLL ) +#if defined( CSTRIKE_DLL ) || defined( HL1MP_DLL ) || defined( MAPBASE ) ConVar sv_accelerate ( "sv_accelerate", "10", FCVAR_NOTIFY | FCVAR_REPLICATED); #else ConVar sv_accelerate ( "sv_accelerate", "10", FCVAR_NOTIFY | FCVAR_REPLICATED | FCVAR_DEVELOPMENTONLY); @@ -66,7 +66,7 @@ ConVar sv_maxspeed ( "sv_maxspeed", "320", FCVAR_NOTIFY | FCVAR_REPLICATED | FC #endif//_XBOX -#if defined( CSTRIKE_DLL ) || defined( HL1MP_DLL ) +#if defined( CSTRIKE_DLL ) || defined( HL1MP_DLL ) || defined( MAPBASE ) ConVar sv_airaccelerate( "sv_airaccelerate", "10", FCVAR_NOTIFY | FCVAR_REPLICATED); ConVar sv_wateraccelerate( "sv_wateraccelerate", "10", FCVAR_NOTIFY | FCVAR_REPLICATED); ConVar sv_waterfriction( "sv_waterfriction", "1", FCVAR_NOTIFY | FCVAR_REPLICATED); @@ -82,13 +82,13 @@ ConVar sv_rollspeed ( "sv_rollspeed", "200", FCVAR_NOTIFY | FCVAR_REPLICATED | F ConVar sv_rollangle ( "sv_rollangle", "0", FCVAR_NOTIFY | FCVAR_REPLICATED | FCVAR_DEVELOPMENTONLY, "Max view roll angle"); #endif // CSTRIKE_DLL -#if defined( DOD_DLL ) || defined( CSTRIKE_DLL ) || defined( HL1MP_DLL ) +#if defined( DOD_DLL ) || defined( CSTRIKE_DLL ) || defined( HL1MP_DLL ) || defined( MAPBASE ) ConVar sv_friction ( "sv_friction","4", FCVAR_NOTIFY | FCVAR_REPLICATED, "World friction." ); #else ConVar sv_friction ( "sv_friction","4", FCVAR_NOTIFY | FCVAR_REPLICATED | FCVAR_DEVELOPMENTONLY, "World friction." ); #endif // DOD_DLL || CSTRIKE_DLL -#if defined( CSTRIKE_DLL ) || defined( HL1MP_DLL ) +#if defined( CSTRIKE_DLL ) || defined( HL1MP_DLL ) || defined( MAPBASE ) ConVar sv_bounce ( "sv_bounce","0", FCVAR_NOTIFY | FCVAR_REPLICATED, "Bounce multiplier for when physically simulated objects collide with other objects." ); ConVar sv_maxvelocity ( "sv_maxvelocity","3500", FCVAR_REPLICATED, "Maximum speed any ballistically moving object is allowed to attain per axis." ); ConVar sv_stepsize ( "sv_stepsize","18", FCVAR_NOTIFY | FCVAR_REPLICATED ); From 24c03f45c2534abfaa0be98cd7f702753d1fdb8e Mon Sep 17 00:00:00 2001 From: Blixibon Date: Mon, 12 Jul 2021 14:36:39 -0500 Subject: [PATCH 102/378] Added a cvar which allows antlions to be properly ignited instead of dying immediately --- sp/src/game/server/hl2/npc_antlion.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/sp/src/game/server/hl2/npc_antlion.cpp b/sp/src/game/server/hl2/npc_antlion.cpp index 66fd8367..2d59c9a0 100644 --- a/sp/src/game/server/hl2/npc_antlion.cpp +++ b/sp/src/game/server/hl2/npc_antlion.cpp @@ -65,6 +65,9 @@ ConVar sk_antlion_worker_burst_radius( "sk_antlion_worker_burst_radius", "160", ConVar g_test_new_antlion_jump( "g_test_new_antlion_jump", "1", FCVAR_ARCHIVE ); ConVar antlion_easycrush( "antlion_easycrush", "1" ); +#ifdef MAPBASE +ConVar antlion_no_ignite_die( "antlion_no_ignite_die", "0" ); +#endif ConVar g_antlion_cascade_push( "g_antlion_cascade_push", "1", FCVAR_ARCHIVE ); ConVar g_debug_antlion_worker( "g_debug_antlion_worker", "0" ); @@ -2623,6 +2626,15 @@ int CNPC_Antlion::SelectSchedule( void ) void CNPC_Antlion::Ignite ( float flFlameLifetime, bool bNPCOnly, float flSize, bool bCalledByLevelDesigner ) { #ifdef HL2_EPISODIC + +#ifdef MAPBASE + if (antlion_no_ignite_die.GetBool()) + { + BaseClass::Ignite(flFlameLifetime, bNPCOnly, flSize, bCalledByLevelDesigner); + return; + } +#endif + float flDamage = m_iHealth + 1; CTakeDamageInfo dmgInfo( this, this, flDamage, DMG_GENERIC ); From 9b795b3c515e6ca9e999be60213e7e77f7948a48 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Mon, 12 Jul 2021 14:47:34 -0500 Subject: [PATCH 103/378] Added WIP v142 toolset support based on Source SDK 2013: Community Edition repo --- sp/src/game/client/c_baseanimating.h | 2 +- sp/src/game/client/c_baseentity.cpp | 6 + sp/src/game/client/c_baseentity.h | 2 +- sp/src/game/client/hud_lcd.cpp | 24 +-- sp/src/game/client/hud_pdump.cpp | 6 + sp/src/game/client/in_joystick.cpp | 2 + sp/src/game/client/particlemgr.h | 2 +- sp/src/game/client/physics_main_client.cpp | 2 +- sp/src/game/client/text_message.cpp | 2 +- sp/src/game/server/CommentarySystem.cpp | 2 +- sp/src/game/server/baseentity.h | 6 +- sp/src/game/server/entity_tools_server.cpp | 7 + sp/src/game/server/explode.cpp | 2 +- sp/src/game/server/hltvdirector.h | 2 +- sp/src/game/server/nav_merge.cpp | 2 +- sp/src/game/server/physics_main.cpp | 16 +- sp/src/game/shared/GameEventListener.h | 2 +- sp/src/game/shared/util_shared.cpp | 2 +- sp/src/game/shared/util_shared.h | 2 +- sp/src/mathlib/polyhedron.cpp | 22 +-- sp/src/public/ScratchPadUtils.cpp | 16 +- sp/src/public/bitmap/imageformat.h | 4 +- sp/src/public/bone_setup.cpp | 28 ++- sp/src/public/dt_utlvector_send.cpp | 2 +- sp/src/public/dt_utlvector_send.h | 2 +- sp/src/public/haptics/haptic_utils.cpp | 4 + sp/src/public/keyframe/keyframe.cpp | 16 +- sp/src/public/keyframe/keyframe.h | 4 +- .../materialsystem/MaterialSystemUtil.h | 4 + sp/src/public/networkvar.h | 4 +- sp/src/public/saverestoretypes.h | 26 +-- sp/src/public/scratchpad3d.h | 2 +- sp/src/public/sentence.cpp | 14 +- sp/src/public/studio.cpp | 26 +-- sp/src/public/studio.h | 6 +- sp/src/public/tier0/dbg.h | 6 +- sp/src/public/tier0/memalloc.h | 5 + sp/src/public/tier0/memdbgon.h | 8 +- sp/src/public/tier0/memoverride.cpp | 162 +++++++++++++++--- sp/src/public/tier0/platform.h | 68 +++++++- sp/src/public/tier1/UtlSortVector.h | 2 +- sp/src/public/tier1/byteswap.h | 2 +- sp/src/public/vgui_controls/Panel.h | 4 +- sp/src/public/vscript/ivscript.h | 2 + sp/src/raytrace/raytrace.cpp | 6 +- sp/src/raytrace/trace2.cpp | 10 +- sp/src/tier1/bitbuf.cpp | 10 +- sp/src/tier1/snappy-stubs-internal.h | 2 +- .../utils/captioncompiler/captioncompiler.vpc | 3 +- sp/src/vgui2/vgui_controls/Panel.cpp | 2 +- .../vgui2/vgui_controls/ScrollBarSlider.cpp | 2 + sp/src/vgui2/vgui_controls/Tooltip.cpp | 4 +- sp/src/vgui2/vgui_controls/TreeView.cpp | 2 +- sp/src/vpc_scripts/source_base.vpc | 14 +- sp/src/vpc_scripts/source_dll_win32_base.vpc | 11 +- .../vpc_scripts/source_exe_win_win32_base.vpc | 9 +- sp/src/vpc_scripts/source_lib_win32_base.vpc | 3 +- sp/src/vpc_scripts/source_win32_base.vpc | 13 +- 58 files changed, 427 insertions(+), 194 deletions(-) diff --git a/sp/src/game/client/c_baseanimating.h b/sp/src/game/client/c_baseanimating.h index 30b69ea7..900f5ab8 100644 --- a/sp/src/game/client/c_baseanimating.h +++ b/sp/src/game/client/c_baseanimating.h @@ -80,7 +80,7 @@ public: QAngle m_angRotation; Vector m_vOriginVelocity; int m_nLastFramecount : 31; - int m_bAnglesComputed : 1; + bool m_bAnglesComputed : 1; }; diff --git a/sp/src/game/client/c_baseentity.cpp b/sp/src/game/client/c_baseentity.cpp index a7bb37a4..4942cc65 100644 --- a/sp/src/game/client/c_baseentity.cpp +++ b/sp/src/game/client/c_baseentity.cpp @@ -4927,9 +4927,15 @@ C_BaseEntity *C_BaseEntity::Instance( int iEnt ) } #ifdef WIN32 + +#if _MSC_VER < 1900 #pragma warning( push ) #include #pragma warning( pop ) +#else +#include +#endif + #endif //----------------------------------------------------------------------------- diff --git a/sp/src/game/client/c_baseentity.h b/sp/src/game/client/c_baseentity.h index 80d89261..f5e0523d 100644 --- a/sp/src/game/client/c_baseentity.h +++ b/sp/src/game/client/c_baseentity.h @@ -1263,7 +1263,7 @@ public: #ifdef _DEBUG void FunctionCheck( void *pFunction, const char *name ); - ENTITYFUNCPTR TouchSet( ENTITYFUNCPTR func, char *name ) + ENTITYFUNCPTR TouchSet( ENTITYFUNCPTR func, const char *name ) { //COMPILE_TIME_ASSERT( sizeof(func) == 4 ); m_pfnTouch = func; diff --git a/sp/src/game/client/hud_lcd.cpp b/sp/src/game/client/hud_lcd.cpp index 0f0609d6..d0425d6b 100644 --- a/sp/src/game/client/hud_lcd.cpp +++ b/sp/src/game/client/hud_lcd.cpp @@ -528,15 +528,15 @@ void CLCD::ShowItems_R( CLCDPage *page, unsigned int dwCurTime, CUtlVector< CLCD { CLCDItem *newItem = NULL; - CLCDItem *item = ag->m_Definition[ r ]; - switch ( item->m_Type ) + CLCDItem *itemLocl = ag->m_Definition[ r ]; + switch ( itemLocl->m_Type ) { default: break; case LCDITEM_TEXT: { - CLCDItemText *text = static_cast< CLCDItemText * >( item ); + CLCDItemText *text = static_cast< CLCDItemText * >( itemLocl ); CUtlString s; s = text->m_OriginalText; Replace( s, prefix, s1 ); @@ -551,7 +551,7 @@ void CLCD::ShowItems_R( CLCDPage *page, unsigned int dwCurTime, CUtlVector< CLCD // text->m_OriginalText = s; - CLCDItemText *copy = static_cast< CLCDItemText * >( page->Alloc( item->m_Type ) ); + CLCDItemText *copy = static_cast< CLCDItemText * >( page->Alloc( itemLocl->m_Type ) ); *copy = *text; copy->m_bActive = true; copy->m_OriginalText = s; @@ -564,8 +564,8 @@ void CLCD::ShowItems_R( CLCDPage *page, unsigned int dwCurTime, CUtlVector< CLCD break; case LCDITEM_ICON: { - CLCDItemIcon *icon = static_cast< CLCDItemIcon * >( item ); - CLCDItemIcon *copy = static_cast< CLCDItemIcon * >( page->Alloc( item->m_Type ) ); + CLCDItemIcon *icon = static_cast< CLCDItemIcon * >( itemLocl ); + CLCDItemIcon *copy = static_cast< CLCDItemIcon * >( page->Alloc( itemLocl->m_Type ) ); *copy = *icon; copy->m_bActive = true; copy->Create( m_lcd ); @@ -1186,16 +1186,16 @@ void CLCD::DumpPlayer() C_Team *team = player->GetTeam(); if ( team ) { - CDescribeData helper( team ); - helper.DumpDescription( team->GetPredDescMap() ); + CDescribeData helperLocl( team ); + helperLocl.DumpDescription( team->GetPredDescMap() ); } Msg( "(playerresource)\n\n" ); if ( g_PR ) { - CDescribeData helper( g_PR ); - helper.DumpDescription( g_PR->GetPredDescMap() ); + CDescribeData helperLocl( g_PR ); + helperLocl.DumpDescription( g_PR->GetPredDescMap() ); } Msg( "(localplayerweapon)\n\n" ); @@ -1203,8 +1203,8 @@ void CLCD::DumpPlayer() C_BaseCombatWeapon *active = player->GetActiveWeapon(); if ( active ) { - CDescribeData helper( active ); - helper.DumpDescription( active->GetPredDescMap() ); + CDescribeData helperLocl( active ); + helperLocl.DumpDescription( active->GetPredDescMap() ); } Msg( "Other replacements:\n\n" ); diff --git a/sp/src/game/client/hud_pdump.cpp b/sp/src/game/client/hud_pdump.cpp index 612a18d7..56ac16f4 100644 --- a/sp/src/game/client/hud_pdump.cpp +++ b/sp/src/game/client/hud_pdump.cpp @@ -21,9 +21,15 @@ static CPDumpPanel *g_pPDumpPanel = NULL; // we pragma'd away in platform.h, so this little compiler specific hack will eliminate those warnings while // retaining our own warning setup...ywb #ifdef WIN32 + +#if _MSC_VER < 1900 #pragma warning( push ) #include #pragma warning( pop ) +#else +#include +#endif + #endif using namespace vgui; diff --git a/sp/src/game/client/in_joystick.cpp b/sp/src/game/client/in_joystick.cpp index 71d03a08..a2f73ee5 100644 --- a/sp/src/game/client/in_joystick.cpp +++ b/sp/src/game/client/in_joystick.cpp @@ -25,7 +25,9 @@ #include "tier0/icommandline.h" #include "inputsystem/iinputsystem.h" #include "inputsystem/ButtonCode.h" +#if _MSC_VER < 1900 #include "math.h" +#endif #include "tier1/convar_serverbounded.h" #include "cam_thirdperson.h" diff --git a/sp/src/game/client/particlemgr.h b/sp/src/game/client/particlemgr.h index 3214a55f..ee86e515 100644 --- a/sp/src/game/client/particlemgr.h +++ b/sp/src/game/client/particlemgr.h @@ -119,7 +119,7 @@ entities. Each one is useful under different conditions. #include "tier0/fasttimer.h" #include "utllinkedlist.h" #include "utldict.h" -#ifdef WIN32 +#if defined(WIN32) && _MSC_VER < 1900 #include #else #include diff --git a/sp/src/game/client/physics_main_client.cpp b/sp/src/game/client/physics_main_client.cpp index b1af5b23..ebc392e2 100644 --- a/sp/src/game/client/physics_main_client.cpp +++ b/sp/src/game/client/physics_main_client.cpp @@ -6,7 +6,7 @@ //=============================================================================// #include "cbase.h" #include "c_baseentity.h" -#ifdef WIN32 +#if defined(WIN32) && _MSC_VER < 1900 #include #endif #include "tier0/vprof.h" diff --git a/sp/src/game/client/text_message.cpp b/sp/src/game/client/text_message.cpp index 2251556b..33bef81f 100644 --- a/sp/src/game/client/text_message.cpp +++ b/sp/src/game/client/text_message.cpp @@ -121,7 +121,7 @@ char *CHudTextMessage::BufferedLocaliseTextString( const char *msg ) char *CHudTextMessage::LookupString( const char *msg, int *msg_dest ) { if ( !msg ) - return ""; + return (char*)""; // '#' character indicates this is a reference to a string in titles.txt, and not the string itself if ( msg[0] == '#' ) diff --git a/sp/src/game/server/CommentarySystem.cpp b/sp/src/game/server/CommentarySystem.cpp index 4d010151..39742467 100644 --- a/sp/src/game/server/CommentarySystem.cpp +++ b/sp/src/game/server/CommentarySystem.cpp @@ -892,7 +892,7 @@ bool IsListeningToCommentary( void ) void CPointCommentaryNode::Spawn( void ) { // No model specified? - char *szModel = (char *)STRING( GetModelName() ); + const char *szModel = STRING( GetModelName() ); if (!szModel || !*szModel) { szModel = "models/extras/info_speech.mdl"; diff --git a/sp/src/game/server/baseentity.h b/sp/src/game/server/baseentity.h index 8577749d..8f92ba60 100644 --- a/sp/src/game/server/baseentity.h +++ b/sp/src/game/server/baseentity.h @@ -1272,7 +1272,7 @@ public: #ifdef _DEBUG void FunctionCheck( void *pFunction, const char *name ); - ENTITYFUNCPTR TouchSet( ENTITYFUNCPTR func, char *name ) + ENTITYFUNCPTR TouchSet( ENTITYFUNCPTR func, const char *name ) { #ifdef GNUC COMPILE_TIME_ASSERT( sizeof(func) == 8 ); @@ -1283,7 +1283,7 @@ public: FunctionCheck( *(reinterpret_cast(&m_pfnTouch)), name ); return func; } - USEPTR UseSet( USEPTR func, char *name ) + USEPTR UseSet( USEPTR func, const char *name ) { #ifdef GNUC COMPILE_TIME_ASSERT( sizeof(func) == 8 ); @@ -1294,7 +1294,7 @@ public: FunctionCheck( *(reinterpret_cast(&m_pfnUse)), name ); return func; } - ENTITYFUNCPTR BlockedSet( ENTITYFUNCPTR func, char *name ) + ENTITYFUNCPTR BlockedSet( ENTITYFUNCPTR func, const char *name ) { #ifdef GNUC COMPILE_TIME_ASSERT( sizeof(func) == 8 ); diff --git a/sp/src/game/server/entity_tools_server.cpp b/sp/src/game/server/entity_tools_server.cpp index 5032ca04..8b76e888 100644 --- a/sp/src/game/server/entity_tools_server.cpp +++ b/sp/src/game/server/entity_tools_server.cpp @@ -14,6 +14,13 @@ #include "sceneentity.h" #include "particles/particles.h" +#if _MSC_VER >= 1900 +#include "icommandline.h" +#endif + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + //----------------------------------------------------------------------------- // Interface from engine to tools for manipulating entities diff --git a/sp/src/game/server/explode.cpp b/sp/src/game/server/explode.cpp index d0321356..d9031dd4 100644 --- a/sp/src/game/server/explode.cpp +++ b/sp/src/game/server/explode.cpp @@ -412,7 +412,7 @@ void ExplosionCreate( const Vector ¢er, const QAngle &angles, CEnvExplosion *pExplosion = (CEnvExplosion*)CBaseEntity::Create( "env_explosion", center, angles, pOwner ); Q_snprintf( buf,sizeof(buf), "%3d", magnitude ); - char *szKeyName = "iMagnitude"; + const char *szKeyName = "iMagnitude"; char *szValue = buf; pExplosion->KeyValue( szKeyName, szValue ); diff --git a/sp/src/game/server/hltvdirector.h b/sp/src/game/server/hltvdirector.h index 653bf1dd..1b390e83 100644 --- a/sp/src/game/server/hltvdirector.h +++ b/sp/src/game/server/hltvdirector.h @@ -67,7 +67,7 @@ public: // CBaseGameSystem overrides virtual void Shutdown(); virtual void FrameUpdatePostEntityThink(); virtual void LevelInitPostEntity(); - virtual char *GetFixedCameraEntityName( void ) { return "point_viewcontrol"; } + virtual const char *GetFixedCameraEntityName( void ) { return "point_viewcontrol"; } bool SetCameraMan( int iPlayerIndex ); int GetCameraMan() { return m_iCameraManIndex; } diff --git a/sp/src/game/server/nav_merge.cpp b/sp/src/game/server/nav_merge.cpp index d62764ab..1d5330ca 100644 --- a/sp/src/game/server/nav_merge.cpp +++ b/sp/src/game/server/nav_merge.cpp @@ -303,7 +303,7 @@ void CNavMesh::CommandNavMergeMesh( const CCommand &args ) //-------------------------------------------------------------------------------------------------------- int NavMeshMergeAutocomplete( char const *partial, char commands[ COMMAND_COMPLETION_MAXITEMS ][ COMMAND_COMPLETION_ITEM_LENGTH ] ) { - char *commandName = "nav_merge_mesh"; + const char *commandName = "nav_merge_mesh"; int numMatches = 0; partial += Q_strlen( commandName ) + 1; int partialLength = Q_strlen( partial ); diff --git a/sp/src/game/server/physics_main.cpp b/sp/src/game/server/physics_main.cpp index b0b2d867..eb6ceee6 100644 --- a/sp/src/game/server/physics_main.cpp +++ b/sp/src/game/server/physics_main.cpp @@ -7,12 +7,12 @@ #include "cbase.h" -#ifdef _WIN32 +#if POSIX || _MSC_VER >= 1900 +#include +#elif defined(_WIN32) #include "typeinfo.h" // BUGBUG: typeinfo stomps some of the warning settings (in yvals.h) #pragma warning(disable:4244) -#elif POSIX -#include #else #error "need typeinfo defined" #endif @@ -942,8 +942,8 @@ void CBaseEntity::PhysicsDispatchThink( BASEPTR thinkFunc ) if ( thinkLimit ) { // calculate running time of the AI in milliseconds - float time = ( engine->Time() - startTime ) * 1000.0f; - if ( time > thinkLimit ) + float flTime = ( engine->Time() - startTime ) * 1000.0f; + if ( flTime > thinkLimit ) { #if defined( _XBOX ) && !defined( _RETAIL ) if ( vprof_think_limit.GetBool() ) @@ -956,14 +956,14 @@ void CBaseEntity::PhysicsDispatchThink( BASEPTR thinkFunc ) CAI_BaseNPC *pNPC = MyNPCPointer(); if (pNPC && pNPC->GetCurSchedule()) { - pNPC->ReportOverThinkLimit( time ); + pNPC->ReportOverThinkLimit( flTime ); } else { #ifdef _WIN32 - Msg( "%s(%s) thinking for %.02f ms!!!\n", GetClassname(), typeid(this).raw_name(), time ); + Msg( "%s(%s) thinking for %.02f ms!!!\n", GetClassname(), typeid(this).raw_name(), flTime ); #elif POSIX - Msg( "%s(%s) thinking for %.02f ms!!!\n", GetClassname(), typeid(this).name(), time ); + Msg( "%s(%s) thinking for %.02f ms!!!\n", GetClassname(), typeid(this).name(), flTime ); #else #error "typeinfo" #endif diff --git a/sp/src/game/shared/GameEventListener.h b/sp/src/game/shared/GameEventListener.h index 42d2ebaa..9378257d 100644 --- a/sp/src/game/shared/GameEventListener.h +++ b/sp/src/game/shared/GameEventListener.h @@ -25,7 +25,7 @@ public: { } - ~CGameEventListener() + virtual ~CGameEventListener() { StopListeningForAllEvents(); } diff --git a/sp/src/game/shared/util_shared.cpp b/sp/src/game/shared/util_shared.cpp index f1dd7e00..be44201d 100644 --- a/sp/src/game/shared/util_shared.cpp +++ b/sp/src/game/shared/util_shared.cpp @@ -1126,7 +1126,7 @@ float CountdownTimer::Now( void ) const #endif -char* ReadAndAllocStringValue( KeyValues *pSub, const char *pName, const char *pFilename ) +const char* ReadAndAllocStringValue( KeyValues *pSub, const char *pName, const char *pFilename ) { const char *pValue = pSub->GetString( pName, NULL ); if ( !pValue ) diff --git a/sp/src/game/shared/util_shared.h b/sp/src/game/shared/util_shared.h index dc8523e3..98f6ba4e 100644 --- a/sp/src/game/shared/util_shared.h +++ b/sp/src/game/shared/util_shared.h @@ -606,7 +606,7 @@ private: float Now( void ) const; // work-around since client header doesn't like inlined gpGlobals->curtime }; -char* ReadAndAllocStringValue( KeyValues *pSub, const char *pName, const char *pFilename = NULL ); +const char* ReadAndAllocStringValue( KeyValues *pSub, const char *pName, const char *pFilename = NULL ); int UTIL_StringFieldToInt( const char *szValue, const char **pValueStrings, int iNumStrings ); diff --git a/sp/src/mathlib/polyhedron.cpp b/sp/src/mathlib/polyhedron.cpp index 5a858f19..5c57671a 100644 --- a/sp/src/mathlib/polyhedron.cpp +++ b/sp/src/mathlib/polyhedron.cpp @@ -1015,12 +1015,12 @@ CPolyhedron *ClipLinkedGeometry( GeneratePolyhedronFromPlanes_UnorderedPolygonLL //Scan for onplane points connected to only other onplane/dead points, these points get downgraded to dead status. { - GeneratePolyhedronFromPlanes_UnorderedPointLL *pActivePointWalk = pAllPoints; + GeneratePolyhedronFromPlanes_UnorderedPointLL *pActivePointWalkLocl = pAllPoints; do { - if( pActivePointWalk->pPoint->planarity == POINT_ONPLANE ) + if( pActivePointWalkLocl->pPoint->planarity == POINT_ONPLANE ) { - GeneratePolyhedronFromPlanes_LineLL *pOnPlaneLineWalk = pActivePointWalk->pPoint->pConnectedLines; + GeneratePolyhedronFromPlanes_LineLL *pOnPlaneLineWalk = pActivePointWalkLocl->pPoint->pConnectedLines; GeneratePolyhedronFromPlanes_LineLL *pStartLineWalk = pOnPlaneLineWalk; bool bDead = true; //assume it's dead and disprove do @@ -1047,7 +1047,7 @@ CPolyhedron *ClipLinkedGeometry( GeneratePolyhedronFromPlanes_UnorderedPolygonLL if( bDead ) { - pActivePointWalk->pPoint->planarity = POINT_DEAD; + pActivePointWalkLocl->pPoint->planarity = POINT_DEAD; pOnPlaneLineWalk = pStartLineWalk; @@ -1059,8 +1059,8 @@ CPolyhedron *ClipLinkedGeometry( GeneratePolyhedronFromPlanes_UnorderedPolygonLL } while( pOnPlaneLineWalk != pStartLineWalk ); } } - pActivePointWalk = pActivePointWalk->pNext; - } while( pActivePointWalk ); + pActivePointWalkLocl = pActivePointWalkLocl->pNext; + } while( pActivePointWalkLocl ); } #ifdef _DEBUG PlaneCutHistory.AddToTail( &pOutwardFacingPlanes[iCurrentPlane * 4] ); @@ -1337,17 +1337,17 @@ CPolyhedron *ClipLinkedGeometry( GeneratePolyhedronFromPlanes_UnorderedPolygonLL //verify that the new point isn't sitting on top of another { - GeneratePolyhedronFromPlanes_UnorderedPointLL *pActivePointWalk = pAllPoints; + GeneratePolyhedronFromPlanes_UnorderedPointLL *pActivePointWalkLocl = pAllPoints; do { - if( pActivePointWalk->pPoint != pNewPoint ) + if( pActivePointWalkLocl->pPoint != pNewPoint ) { - Vector vDiff = pActivePointWalk->pPoint->ptPosition - pNewPoint->ptPosition; + Vector vDiff = pActivePointWalkLocl->pPoint->ptPosition - pNewPoint->ptPosition; AssertMsg_DumpPolyhedron( vDiff.Length() > fOnPlaneEpsilon, "Generated a point on top of another" ); } - pActivePointWalk = pActivePointWalk->pNext; - } while( pActivePointWalk ); + pActivePointWalkLocl = pActivePointWalk->pNext; + } while( pActivePointWalkLocl ); } #endif diff --git a/sp/src/public/ScratchPadUtils.cpp b/sp/src/public/ScratchPadUtils.cpp index dfb93b0d..6e020aaf 100644 --- a/sp/src/public/ScratchPadUtils.cpp +++ b/sp/src/public/ScratchPadUtils.cpp @@ -141,11 +141,11 @@ void CScratchPadGraph::UpdateTicksAndStuff( float flTime, float flValue ) // Extend the lines attached to the time labels. for ( int i=0; i < m_nTimeLabelsDrawn; i++ ) { - float flTime = m_flTimeOrigin + m_nTimeLabelsDrawn * m_flTimeLabelEveryNSeconds; + float flTimeLocl = m_flTimeOrigin + m_nTimeLabelsDrawn * m_flTimeLabelEveryNSeconds; m_pPad->DrawLine( - CSPVert((const Vector&) GetSamplePosition( flTime, m_flHighestValue )), - CSPVert((const Vector&) GetSamplePosition( flTime, flValue ) ) + CSPVert((const Vector&) GetSamplePosition( flTimeLocl, m_flHighestValue )), + CSPVert((const Vector&) GetSamplePosition( flTimeLocl, flValue ) ) ); } @@ -158,21 +158,21 @@ void CScratchPadGraph::UpdateTicksAndStuff( float flTime, float flValue ) { CTextParams params; - float flTime = m_flTimeOrigin + m_nTimeLabelsDrawn * m_flTimeLabelEveryNSeconds; + float flTimeLocl = m_flTimeOrigin + m_nTimeLabelsDrawn * m_flTimeLabelEveryNSeconds; params.m_bSolidBackground = true; - params.m_vPos = GetSamplePosition( flTime, m_flValueOrigin-5 ); + params.m_vPos = GetSamplePosition( flTimeLocl, m_flValueOrigin-5 ); params.m_bTwoSided = true; char str[512]; - Q_snprintf( str, sizeof( str ), "time: %.2f", flTime ); + Q_snprintf( str, sizeof( str ), "time: %.2f", flTimeLocl ); m_pPad->DrawText( str, params ); // Now draw the vertical line for the value.. m_pPad->DrawLine( - CSPVert( (const Vector&)GetSamplePosition( flTime, m_flValueOrigin ) ), - CSPVert( (const Vector&)GetSamplePosition( flTime, m_flHighestValue ) ) + CSPVert( (const Vector&)GetSamplePosition( flTimeLocl, m_flValueOrigin ) ), + CSPVert( (const Vector&)GetSamplePosition( flTimeLocl, m_flHighestValue ) ) ); diff --git a/sp/src/public/bitmap/imageformat.h b/sp/src/public/bitmap/imageformat.h index 1a35cab1..4a6a8ce0 100644 --- a/sp/src/public/bitmap/imageformat.h +++ b/sp/src/public/bitmap/imageformat.h @@ -21,7 +21,7 @@ enum NormalDecodeMode_t }; // Forward declaration -#ifdef _WIN32 +#if defined(_WIN32) && _MSC_VER < 1900 typedef enum _D3DFORMAT D3DFORMAT; #endif @@ -103,7 +103,7 @@ enum ImageFormat NUM_IMAGE_FORMATS }; -#if defined( POSIX ) || defined( DX_TO_GL_ABSTRACTION ) +#if defined( POSIX ) || defined( DX_TO_GL_ABSTRACTION ) || _MSC_VER >= 1900 typedef enum _D3DFORMAT { D3DFMT_INDEX16, diff --git a/sp/src/public/bone_setup.cpp b/sp/src/public/bone_setup.cpp index 250133d5..0f1f5c47 100644 --- a/sp/src/public/bone_setup.cpp +++ b/sp/src/public/bone_setup.cpp @@ -933,8 +933,8 @@ static void CalcVirtualAnimation( virtualmodel_t *pVModel, const CStudioHdr *pSt { if (pStudioHdr->boneFlags(i) & boneMask) { - int j = pSeqGroup->boneMap[i]; - if (j >= 0 && pweight[j] > 0.0f) + int l = pSeqGroup->boneMap[i]; + if (l >= 0 && pweight[l] > 0.0f) { if (animdesc.flags & STUDIO_DELTA) { @@ -943,13 +943,13 @@ static void CalcVirtualAnimation( virtualmodel_t *pVModel, const CStudioHdr *pSt } else if (pSeqLinearBones) { - q[i] = pSeqLinearBones->quat(j); - pos[i] = pSeqLinearBones->pos(j); + q[i] = pSeqLinearBones->quat(l); + pos[i] = pSeqLinearBones->pos(l); } else { - q[i] = pSeqbone[j].quat; - pos[i] = pSeqbone[j].pos; + q[i] = pSeqbone[l].quat; + pos[i] = pSeqbone[l].pos; } #ifdef STUDIO_ENABLE_PERF_COUNTERS pStudioHdr->m_nPerfUsedBones++; @@ -997,10 +997,9 @@ static void CalcVirtualAnimation( virtualmodel_t *pVModel, const CStudioHdr *pSt matrix3x4_t *boneToWorld = g_MatrixPool.Alloc(); CBoneBitList boneComputed; - int i; - for (i = 0; i < animdesc.numlocalhierarchy; i++) + for (int l = 0; i < animdesc.numlocalhierarchy; i++) { - mstudiolocalhierarchy_t *pHierarchy = animdesc.pHierarchy( i ); + mstudiolocalhierarchy_t *pHierarchy = animdesc.pHierarchy( l ); if ( !pHierarchy ) break; @@ -1141,10 +1140,9 @@ static void CalcAnimation( const CStudioHdr *pStudioHdr, Vector *pos, Quaternion matrix3x4_t *boneToWorld = g_MatrixPool.Alloc(); CBoneBitList boneComputed; - int i; - for (i = 0; i < animdesc.numlocalhierarchy; i++) + for (int j = 0; j < animdesc.numlocalhierarchy; j++) { - mstudiolocalhierarchy_t *pHierarchy = animdesc.pHierarchy( i ); + mstudiolocalhierarchy_t *pHierarchy = animdesc.pHierarchy( j ); if ( !pHierarchy ) break; @@ -5610,9 +5608,9 @@ bool Studio_AnimPosition( mstudioanimdesc_t *panim, float flCycle, Vector &vecPo vecAngle.y = vecAngle.y * (1 - f) + pmove->angle * f; if (iLoops != 0) { - mstudiomovement_t *pmove = panim->pMovement( panim->nummovements - 1 ); - vecPos = vecPos + iLoops * pmove->position; - vecAngle.y = vecAngle.y + iLoops * pmove->angle; + mstudiomovement_t *pmoveLocl = panim->pMovement( panim->nummovements - 1 ); + vecPos = vecPos + iLoops * pmoveLocl->position; + vecAngle.y = vecAngle.y + iLoops * pmoveLocl->angle; } return true; } diff --git a/sp/src/public/dt_utlvector_send.cpp b/sp/src/public/dt_utlvector_send.cpp index b10170de..06f78c64 100644 --- a/sp/src/public/dt_utlvector_send.cpp +++ b/sp/src/public/dt_utlvector_send.cpp @@ -134,7 +134,7 @@ void* SendProxy_LengthTable( const SendProp *pProp, const void *pStructBase, con // Note: you have to be DILIGENT about calling NetworkStateChanged whenever an element in your CUtlVector changes // since CUtlVector doesn't do this automatically. SendProp SendPropUtlVector( - char *pVarName, // Use SENDINFO_UTLVECTOR to generate these 4. + const char *pVarName, // Use SENDINFO_UTLVECTOR to generate these 4. int offset, // Used to generate pData in the function specified in varProxy. int sizeofVar, // The size of each element in the utlvector. EnsureCapacityFn ensureFn, // This is the value returned for elements out of the array's current range. diff --git a/sp/src/public/dt_utlvector_send.h b/sp/src/public/dt_utlvector_send.h index f2ba68c3..3684d5b5 100644 --- a/sp/src/public/dt_utlvector_send.h +++ b/sp/src/public/dt_utlvector_send.h @@ -43,7 +43,7 @@ // ) // SendProp SendPropUtlVector( - char *pVarName, // Use SENDINFO_UTLVECTOR to generate these first 4 parameters. + const char *pVarName, // Use SENDINFO_UTLVECTOR to generate these first 4 parameters. int offset, int sizeofVar, EnsureCapacityFn ensureFn, diff --git a/sp/src/public/haptics/haptic_utils.cpp b/sp/src/public/haptics/haptic_utils.cpp index b9c72b2f..70fe86c4 100644 --- a/sp/src/public/haptics/haptic_utils.cpp +++ b/sp/src/public/haptics/haptic_utils.cpp @@ -138,6 +138,10 @@ void ConnectHaptics(CreateInterfaceFn appFactory) HookHapticMessages(); } +// deleting haptics results in a warning about deleting something with a non-virtual destructor +// big yikes but we can't do anything about it as it's accessed via interface +#pragma warning (disable: 5205) + void DisconnectHaptics() { haptics->ShutdownHaptics(); diff --git a/sp/src/public/keyframe/keyframe.cpp b/sp/src/public/keyframe/keyframe.cpp index 1e08b0a3..425a172e 100644 --- a/sp/src/public/keyframe/keyframe.cpp +++ b/sp/src/public/keyframe/keyframe.cpp @@ -154,7 +154,7 @@ class CPositionInterpolator_Linear : public IPositionInterpolator { public: virtual void Release(); - virtual void GetDetails( char **outName, int *outMinKeyReq, int *outMaxKeyReq ); + virtual void GetDetails( const char **outName, int *outMinKeyReq, int *outMaxKeyReq ); virtual void SetKeyPosition( int keyNum, Vector const &vPos ); virtual void InterpolatePosition( float time, Vector &vOut ); virtual bool ProcessKey( char const *pName, char const *pValue ) { return false; } @@ -171,7 +171,7 @@ void CPositionInterpolator_Linear::Release() { } -void CPositionInterpolator_Linear::GetDetails( char **outName, int *outMinKeyReq, int *outMaxKeyReq ) +void CPositionInterpolator_Linear::GetDetails( const char **outName, int *outMinKeyReq, int *outMaxKeyReq ) { *outName = "Linear"; *outMinKeyReq = 0; @@ -201,7 +201,7 @@ class CPositionInterpolator_CatmullRom : public IPositionInterpolator { public: virtual void Release(); - virtual void GetDetails( char **outName, int *outMinKeyReq, int *outMaxKeyReq ); + virtual void GetDetails( const char **outName, int *outMinKeyReq, int *outMaxKeyReq ); virtual void SetKeyPosition( int keyNum, Vector const &vPos ); virtual void InterpolatePosition( float time, Vector &vOut ); virtual bool ProcessKey( char const *pName, char const *pValue ) { return false; } @@ -218,7 +218,7 @@ void CPositionInterpolator_CatmullRom::Release() { } -void CPositionInterpolator_CatmullRom::GetDetails( char **outName, int *outMinKeyReq, int *outMaxKeyReq ) +void CPositionInterpolator_CatmullRom::GetDetails( const char **outName, int *outMinKeyReq, int *outMaxKeyReq ) { *outName = "Catmull-Rom Spline"; *outMinKeyReq = -1; @@ -282,7 +282,7 @@ public: CPositionInterpolator_Rope(); virtual void Release(); - virtual void GetDetails( char **outName, int *outMinKeyReq, int *outMaxKeyReq ); + virtual void GetDetails( const char **outName, int *outMinKeyReq, int *outMaxKeyReq ); virtual void SetKeyPosition( int keyNum, Vector const &vPos ); virtual void InterpolatePosition( float time, Vector &vOut ); virtual bool ProcessKey( char const *pName, char const *pValue ); @@ -319,7 +319,7 @@ void CPositionInterpolator_Rope::Release() delete this; } -void CPositionInterpolator_Rope::GetDetails( char **outName, int *outMinKeyReq, int *outMaxKeyReq ) +void CPositionInterpolator_Rope::GetDetails( const char **outName, int *outMinKeyReq, int *outMaxKeyReq ) { *outName = "Rope"; *outMinKeyReq = 0; @@ -433,7 +433,7 @@ typedef void (*RotationInterpolatorFunc_t)(float time, Quaternion &outRot); typedef struct { - char *szName; + const char *szName; RotationInterpolatorFunc_t pFunc; // defines the range of keys this interpolator needs to function @@ -458,7 +458,7 @@ int Motion_GetNumberOfRotationInterpolators( void ) return ARRAYSIZE(g_RotationInterpolators); } -bool Motion_GetRotationInterpolatorDetails( int rotInterpNum, char **outName, int *outMinKeyReq, int *outMaxKeyReq ) +bool Motion_GetRotationInterpolatorDetails( int rotInterpNum, const char **outName, int *outMinKeyReq, int *outMaxKeyReq ) { if ( rotInterpNum < 0 || rotInterpNum >= Motion_GetNumberOfRotationInterpolators() ) { diff --git a/sp/src/public/keyframe/keyframe.h b/sp/src/public/keyframe/keyframe.h index b2cfd27c..4ee04824 100644 --- a/sp/src/public/keyframe/keyframe.h +++ b/sp/src/public/keyframe/keyframe.h @@ -14,7 +14,7 @@ class IPositionInterpolator public: virtual void Release() = 0; - virtual void GetDetails( char **outName, int *outMinKeyReq, int *outMaxKeyReq ) = 0; + virtual void GetDetails( const char **outName, int *outMinKeyReq, int *outMaxKeyReq ) = 0; virtual void SetKeyPosition( int keyNum, Vector const &vPos ) = 0; virtual void InterpolatePosition( float time, Vector &vOut ) = 0; @@ -34,7 +34,7 @@ IPositionInterpolator* Motion_GetPositionInterpolator( int interpNum ); // Rotation interpolators. int Motion_GetNumberOfRotationInterpolators( void ); -bool Motion_GetRotationInterpolatorDetails( int rotInterpNum, char **outName, int *outMinKeyReq, int *outMaxKeyReq ); +bool Motion_GetRotationInterpolatorDetails( int rotInterpNum, const char **outName, int *outMinKeyReq, int *outMaxKeyReq ); bool Motion_InterpolateRotation( float time, int interpFuncNum, Quaternion &outQuatRotation ); bool Motion_SetKeyAngles( int keyNum, Quaternion &quatAngles ); diff --git a/sp/src/public/materialsystem/MaterialSystemUtil.h b/sp/src/public/materialsystem/MaterialSystemUtil.h index 3f22e918..ddabcd22 100644 --- a/sp/src/public/materialsystem/MaterialSystemUtil.h +++ b/sp/src/public/materialsystem/MaterialSystemUtil.h @@ -72,6 +72,10 @@ public: void Init( char const* pTexture, const char *pTextureGroupName, bool bComplain = true ); void InitProceduralTexture( const char *pTextureName, const char *pTextureGroupName, int w, int h, ImageFormat fmt, int nFlags ); void InitRenderTarget( int w, int h, RenderTargetSizeMode_t sizeMode, ImageFormat fmt, MaterialRenderTargetDepth_t depth, bool bHDR, char *pStrOptionalName = NULL ); + void InitRenderTarget(int w, int h, RenderTargetSizeMode_t sizeMode, ImageFormat fmt, MaterialRenderTargetDepth_t depth, bool bHDR, const char* pStrOptionalName = NULL) + { + InitRenderTarget(w, h, sizeMode, fmt, depth, bHDR, const_cast(pStrOptionalName)); + } #if defined( _X360 ) // used when RT coupling is disparate (texture is DDR based, surface is EDRAM based) void InitRenderTargetTexture( int width, int height, RenderTargetSizeMode_t sizeMode, ImageFormat fmt, MaterialRenderTargetDepth_t depth, bool bHDR, char *pStrOptionalName = NULL ); diff --git a/sp/src/public/networkvar.h b/sp/src/public/networkvar.h index 142b35e9..46a92de0 100644 --- a/sp/src/public/networkvar.h +++ b/sp/src/public/networkvar.h @@ -744,9 +744,9 @@ private: const type* Base() const { return m_Value; } \ int Count() const { return count; } \ protected: \ - inline void NetworkStateChanged( int index ) \ + inline void NetworkStateChanged( int _index ) \ { \ - CHECK_USENETWORKVARS ((ThisClass*)(((char*)this) - MyOffsetOf(ThisClass,name)))->stateChangedFn( &m_Value[index] ); \ + CHECK_USENETWORKVARS ((ThisClass*)(((char*)this) - MyOffsetOf(ThisClass,name)))->stateChangedFn( &m_Value[_index] ); \ } \ type m_Value[count]; \ }; \ diff --git a/sp/src/public/saverestoretypes.h b/sp/src/public/saverestoretypes.h index b92a77c7..96e5cf5d 100644 --- a/sp/src/public/saverestoretypes.h +++ b/sp/src/public/saverestoretypes.h @@ -181,7 +181,7 @@ class CGameSaveRestoreInfo { public: CGameSaveRestoreInfo() - : tableCount( 0 ), pTable( 0 ), m_pCurrentEntity( 0 ), m_EntityToIndex( 1024 ) + : m_iTableCount( 0 ), m_pTable( 0 ), m_pCurrentEntity( 0 ), m_EntityToIndex( 1024 ) { memset( &levelInfo, 0, sizeof( levelInfo ) ); modelSpaceOffset.Init( 0, 0, 0 ); @@ -189,8 +189,8 @@ public: void InitEntityTable( entitytable_t *pNewTable = NULL, int size = 0 ) { - pTable = pNewTable; - tableCount = size; + m_pTable = pNewTable; + m_iTableCount = size; for ( int i = 0; i < NumEntities(); i++ ) { @@ -200,17 +200,17 @@ public: entitytable_t *DetachEntityTable() { - entitytable_t *pReturn = pTable; - pTable = NULL; - tableCount = 0; + entitytable_t *pReturn = m_pTable; + m_pTable = NULL; + m_iTableCount = 0; return pReturn; } CBaseEntity *GetCurrentEntityContext() { return m_pCurrentEntity; } void SetCurrentEntityContext(CBaseEntity *pEntity) { m_pCurrentEntity = pEntity; } - int NumEntities() { return tableCount; } - entitytable_t *GetEntityInfo( int i ) { return (pTable + i); } + int NumEntities() { return m_iTableCount; } + entitytable_t *GetEntityInfo( int i ) { return (m_pTable + i); } float GetBaseTime() const { return levelInfo.time; } Vector GetLandmark() const { return ( levelInfo.fUseLandmark ) ? levelInfo.vecLandmarkOffset : vec3_origin; } @@ -218,13 +218,13 @@ public: { #ifdef GAME_DLL int i; - entitytable_t *pTable; + entitytable_t *m_pTable; int nEntities = NumEntities(); for ( i = 0; i < nEntities; i++ ) { - pTable = GetEntityInfo( i ); - m_EntityToIndex.Insert( CHashElement( pTable->hEnt.Get(), i ) ); + m_pTable = GetEntityInfo( i ); + m_EntityToIndex.Insert( CHashElement( m_pTable->hEnt.Get(), i ) ); } #endif } @@ -269,8 +269,8 @@ public: Vector modelSpaceOffset; // used only for globaly entity brushes modelled in different coordinate systems. private: - int tableCount; // Number of elements in the entity table - entitytable_t *pTable; // Array of entitytable_t elements (1 for each entity) + int m_iTableCount; // Number of elements in the entity table + entitytable_t *m_pTable; // Array of entitytable_t elements (1 for each entity) CBaseEntity *m_pCurrentEntity; // only valid during the save functions of this entity, NULL otherwise diff --git a/sp/src/public/scratchpad3d.h b/sp/src/public/scratchpad3d.h index 7e9aad66..30b2455c 100644 --- a/sp/src/public/scratchpad3d.h +++ b/sp/src/public/scratchpad3d.h @@ -51,7 +51,7 @@ public: m_pCachedRenderData = NULL; } - ~CBaseCommand() + virtual ~CBaseCommand() { ReleaseCachedRenderData(); } diff --git a/sp/src/public/sentence.cpp b/sp/src/public/sentence.cpp index 49c24c3c..1b8efd64 100644 --- a/sp/src/public/sentence.cpp +++ b/sp/src/public/sentence.cpp @@ -508,7 +508,7 @@ void CSentence::ParseWords( CUtlBuffer& buf ) // Parse phoneme int code; char phonemename[ 256 ]; - float start, end; + float startLocl, endLocl; float volume; code = atoi( token ); @@ -516,9 +516,9 @@ void CSentence::ParseWords( CUtlBuffer& buf ) buf.GetString( token ); Q_strncpy( phonemename, token, sizeof( phonemename ) ); buf.GetString( token ); - start = atof( token ); + startLocl = atof( token ); buf.GetString( token ); - end = atof( token ); + endLocl = atof( token ); buf.GetString( token ); volume = atof( token ); @@ -526,8 +526,8 @@ void CSentence::ParseWords( CUtlBuffer& buf ) assert( pt ); pt->SetPhonemeCode( code ); pt->SetTag( phonemename ); - pt->SetStartTime( start ); - pt->SetEndTime( end ); + pt->SetStartTime( startLocl ); + pt->SetEndTime( endLocl ); AddPhonemeTag( wt, pt ); } @@ -1304,9 +1304,9 @@ void CSentence::Append( float starttime, const CSentence& src ) // Offset times int c = newWord->m_Phonemes.Count(); - for ( int i = 0; i < c; ++i ) + for ( int j = 0; j < c; ++j ) { - CPhonemeTag *tag = newWord->m_Phonemes[ i ]; + CPhonemeTag *tag = newWord->m_Phonemes[ j ]; tag->AddStartTime( starttime ); tag->AddEndTime( starttime ); } diff --git a/sp/src/public/studio.cpp b/sp/src/public/studio.cpp index 9bf97018..127840dc 100644 --- a/sp/src/public/studio.cpp +++ b/sp/src/public/studio.cpp @@ -516,7 +516,7 @@ void studiohdr_t::SetAttachmentBone( int iAttachment, int iBone ) // Purpose: //----------------------------------------------------------------------------- -char *studiohdr_t::pszNodeName( int iNode ) +const char *studiohdr_t::pszNodeName( int iNode ) { if (numincludemodels == 0) { @@ -565,7 +565,7 @@ int studiohdr_t::GetActivityListVersion( void ) virtualmodel_t *pVModel = (virtualmodel_t *)GetVirtualModel(); Assert( pVModel ); - int version = activitylistversion; + int versionLocl = activitylistversion; int i; for (i = 1; i < pVModel->m_group.Count(); i++) @@ -575,15 +575,15 @@ int studiohdr_t::GetActivityListVersion( void ) Assert( pStudioHdr ); - version = min( version, pStudioHdr->activitylistversion ); + versionLocl = min( versionLocl, pStudioHdr->activitylistversion ); } - return version; + return versionLocl; } -void studiohdr_t::SetActivityListVersion( int version ) const +void studiohdr_t::SetActivityListVersion( int iVersion ) const { - activitylistversion = version; + activitylistversion = iVersion; if (numincludemodels == 0) { @@ -601,7 +601,7 @@ void studiohdr_t::SetActivityListVersion( int version ) const Assert( pStudioHdr ); - pStudioHdr->SetActivityListVersion( version ); + pStudioHdr->SetActivityListVersion( iVersion ); } } @@ -1152,7 +1152,7 @@ void CStudioHdr::SetAttachmentBone( int iAttachment, int iBone ) // Purpose: //----------------------------------------------------------------------------- -char *CStudioHdr::pszNodeName( int iNode ) +const char *CStudioHdr::pszNodeName( int iNode ) { if (m_pVModel == NULL) { @@ -1433,9 +1433,9 @@ void CStudioHdr::RunFlexRules( const float *src, float *dest ) { int m = pops->d.index; int km = k - m; - for ( int i = km + 1; i < k; ++i ) + for ( int l = km + 1; l < k; ++l ) { - stack[ km ] *= stack[ i ]; + stack[ km ] *= stack[ l ]; } k = k - m + 1; } @@ -1445,9 +1445,9 @@ void CStudioHdr::RunFlexRules( const float *src, float *dest ) int m = pops->d.index; int km = k - m; float dv = stack[ km ]; - for ( int i = km + 1; i < k; ++i ) + for ( int l = km + 1; l < k; ++l ) { - dv *= stack[ i ]; + dv *= stack[ l ]; } stack[ km - 1 ] *= 1.0f - dv; k -= m; @@ -1701,7 +1701,7 @@ void CStudioHdr::CActivityToSequenceMapping::Initialize( CStudioHdr * __restrict // This stack may potentially grow very large; so if you have problems with it, // go to a utlmap or similar structure. unsigned int allocsize = (topActivity + 1) * sizeof(int); -#define ALIGN_VALUE( val, alignment ) ( ( val + alignment - 1 ) & ~( alignment - 1 ) ) // need macro for constant expression +//#define ALIGN_VALUE( val, alignment ) ( ( val + alignment - 1 ) & ~( alignment - 1 ) ) // need macro for constant expression allocsize = ALIGN_VALUE(allocsize,16); int * __restrict seqsPerAct = static_cast(stackalloc(allocsize)); memset(seqsPerAct, 0, allocsize); diff --git a/sp/src/public/studio.h b/sp/src/public/studio.h index bcc38d5d..384f4732 100644 --- a/sp/src/public/studio.h +++ b/sp/src/public/studio.h @@ -2137,7 +2137,7 @@ struct studiohdr_t int GetSequenceActivity( int iSequence ); void SetSequenceActivity( int iSequence, int iActivity ); int GetActivityListVersion( void ); - void SetActivityListVersion( int version ) const; + void SetActivityListVersion( int iVersion ) const; int GetEventListVersion( void ); void SetEventListVersion( int version ); @@ -2185,7 +2185,7 @@ struct studiohdr_t //public: int EntryNode( int iSequence ); int ExitNode( int iSequence ); - char *pszNodeName( int iNode ); + const char *pszNodeName( int iNode ); int GetTransition( int iFrom, int iTo ) const; int numflexdesc; @@ -2395,7 +2395,7 @@ public: int EntryNode( int iSequence ); int ExitNode( int iSequence ); - char *pszNodeName( int iNode ); + const char *pszNodeName( int iNode ); // FIXME: where should this one be? int GetTransition( int iFrom, int iTo ) const; diff --git a/sp/src/public/tier0/dbg.h b/sp/src/public/tier0/dbg.h index 9fd38d0a..fab71650 100644 --- a/sp/src/public/tier0/dbg.h +++ b/sp/src/public/tier0/dbg.h @@ -15,7 +15,9 @@ #include "basetypes.h" #include "dbgflag.h" #include "platform.h" +#if _MSC_VER < 1900 #include +#endif #include #include @@ -247,10 +249,10 @@ DBG_INTERFACE struct SDL_Window * GetAssertDialogParent(); if (!(_exp)) \ { \ _SpewInfo( SPEW_ASSERT, __TFILE__, __LINE__ ); \ - SpewRetval_t ret = _SpewMessage("%s", static_cast( _msg )); \ + SpewRetval_t _ret = _SpewMessage("%s", static_cast( _msg )); \ CallAssertFailedNotifyFunc( __TFILE__, __LINE__, _msg ); \ _executeExp; \ - if ( ret == SPEW_DEBUGGER) \ + if ( _ret == SPEW_DEBUGGER) \ { \ if ( !ShouldUseNewAssertDialog() || DoNewAssertDialog( __TFILE__, __LINE__, _msg ) ) \ { \ diff --git a/sp/src/public/tier0/memalloc.h b/sp/src/public/tier0/memalloc.h index e0f9c16a..34e1ccb9 100644 --- a/sp/src/public/tier0/memalloc.h +++ b/sp/src/public/tier0/memalloc.h @@ -382,7 +382,12 @@ public: #pragma warning(disable:4290) #pragma warning(push) + +#if _MSC_VER < 1900 #include +#else + #include +#endif // MEM_DEBUG_CLASSNAME is opt-in. // Note: typeid().name() is not threadsafe, so if the project needs to access it in multiple threads diff --git a/sp/src/public/tier0/memdbgon.h b/sp/src/public/tier0/memdbgon.h index 7fd6e9ca..4e46839f 100644 --- a/sp/src/public/tier0/memdbgon.h +++ b/sp/src/public/tier0/memdbgon.h @@ -37,7 +37,7 @@ #include "commonmacros.h" #include "memalloc.h" -#if defined(USE_MEM_DEBUG) +#if USE_MEM_DEBUG #if defined( POSIX ) #define _NORMAL_BLOCK 1 @@ -91,7 +91,7 @@ inline void *MemAlloc_InlineCallocMemset( void *pMem, size_t nCount, size_t nEle } #endif -#define calloc(c, s) MemAlloc_InlineCallocMemset(malloc(c*s), c, s) +#define calloc(c, s) MemAlloc_InlineCallocMemset(malloc((c)*(s)), (c), (s)) #define free(p) g_pMemAlloc->Free( p ) #define _msize(p) g_pMemAlloc->GetSize( p ) #define _expand(p, s) _expand_NoLongerSupported(p, s) @@ -99,7 +99,7 @@ inline void *MemAlloc_InlineCallocMemset( void *pMem, size_t nCount, size_t nEle // -------------------------------------------------------- // Debug path -#if defined(USE_MEM_DEBUG) +#if USE_MEM_DEBUG #define malloc(s) g_pMemAlloc->Alloc( s, __FILE__, __LINE__) #define realloc(p, s) g_pMemAlloc->Realloc( p, s, __FILE__, __LINE__ ) @@ -231,7 +231,7 @@ inline wchar_t *MemAlloc_WcStrDup(const wchar_t *pString) #else -#if defined(USE_MEM_DEBUG) +#if USE_MEM_DEBUG #ifndef _STATIC_LINKED #pragma message ("Note: file includes crtdbg.h directly, therefore will cannot use memdbgon.h in non-debug build") #else diff --git a/sp/src/public/tier0/memoverride.cpp b/sp/src/public/tier0/memoverride.cpp index 5c679e45..269d44ec 100644 --- a/sp/src/public/tier0/memoverride.cpp +++ b/sp/src/public/tier0/memoverride.cpp @@ -40,9 +40,17 @@ #define __cdecl #endif +#undef _malloc_dbg +#undef _calloc_dbg +#undef _free_dbg +#undef _CrtSetCheckCount +#undef _CrtGetCheckCount +#undef _CrtSetDebugFillThreshold + #if defined( _WIN32 ) && !defined( _X360 ) const char *MakeModuleFileName() { +#if _MSC_VER < 1900 if ( g_pMemAlloc->IsDebugHeap() ) { char *pszModuleName = (char *)HeapAlloc( GetProcessHeap(), 0, MAX_PATH ); // small leak, debug only @@ -65,27 +73,36 @@ const char *MakeModuleFileName() return pszModuleName; } +#endif return NULL; } static void *AllocUnattributed( size_t nSize ) { +#if _MSC_VER < 1900 static const char *pszOwner = MakeModuleFileName(); if ( !pszOwner ) return g_pMemAlloc->Alloc(nSize); else return g_pMemAlloc->Alloc(nSize, pszOwner, 0); +#else + return g_pMemAlloc->Alloc(nSize); +#endif } static void *ReallocUnattributed( void *pMem, size_t nSize ) { +#if _MSC_VER < 1900 static const char *pszOwner = MakeModuleFileName(); if ( !pszOwner ) return g_pMemAlloc->Realloc(pMem, nSize); else return g_pMemAlloc->Realloc(pMem, nSize, pszOwner, 0); +#else + return g_pMemAlloc->Realloc(pMem, nSize); +#endif } #else @@ -108,6 +125,9 @@ inline void *ReallocUnattributed( void *pMem, size_t nSize ) // this magic only works under win32 // under linux this malloc() overrides the libc malloc() and so we // end up in a recursion (as g_pMemAlloc->Alloc() calls malloc) +#if _MSC_VER >= 1900 && !defined(_CRTNOALIAS) +#define _CRTNOALIAS +#endif #if _MSC_VER >= 1400 #define ALLOC_CALL _CRTNOALIAS _CRTRESTRICT #define FREE_CALL _CRTNOALIAS @@ -155,6 +175,11 @@ void* __cdecl _malloc_base( size_t nSize ) { return AllocUnattributed( nSize ); } +#elif _MSC_VER >= 1900 + __declspec(restrict) void* _malloc_base(size_t nSize) + { + return AllocUnattributed(nSize); + } #else void *_malloc_base( size_t nSize ) { @@ -162,24 +187,47 @@ void *_malloc_base( size_t nSize ) } #endif +#if _MSC_VER >= 1900 +__declspec(restrict) void* _calloc_base(size_t count, size_t nSize) +{ + void* pMem = AllocUnattributed(count * nSize); + memset(pMem, 0, count * nSize); + return pMem; +} +#else void *_calloc_base( size_t nSize ) { void *pMem = AllocUnattributed( nSize ); memset(pMem, 0, nSize); return pMem; } +#endif +#if _MSC_VER >= 1900 +__declspec(restrict) void* _realloc_base(void* pMem, size_t nSize) +{ + return ReallocUnattributed(pMem, nSize); +} +#else void *_realloc_base( void *pMem, size_t nSize ) { return ReallocUnattributed( pMem, nSize ); } +#endif +#if _MSC_VER >= 1900 +__declspec(restrict) void* _recalloc_base(void* pMem, size_t count, size_t nSize) +{ + return _recalloc(pMem, count, nSize); +} +#else void *_recalloc_base( void *pMem, size_t nSize ) { void *pMemOut = ReallocUnattributed( pMem, nSize ); memset(pMemOut, 0, nSize); return pMemOut; } +#endif void _free_base( void *pMem ) { @@ -200,7 +248,11 @@ void * __cdecl _malloc_crt(size_t size) void * __cdecl _calloc_crt(size_t count, size_t size) { +#if _MSC_VER >= 1900 + return _calloc_base(count, size); +#else return _calloc_base( count * size ); +#endif } void * __cdecl _realloc_crt(void *ptr, size_t size) @@ -210,14 +262,23 @@ void * __cdecl _realloc_crt(void *ptr, size_t size) void * __cdecl _recalloc_crt(void *ptr, size_t count, size_t size) { +#if _MSC_VER >= 1900 + return _recalloc_base(ptr, count, size); +#else return _recalloc_base( ptr, size * count ); +#endif } ALLOC_CALL void * __cdecl _recalloc ( void * memblock, size_t count, size_t size ) { - void *pMem = ReallocUnattributed( memblock, size * count ); - memset( pMem, 0, size * count ); - return pMem; + const size_t oldSize = _msize(memblock); + const size_t newSize = count * size; + void* pMemOut = ReallocUnattributed(memblock, newSize); + + if (newSize > oldSize) + memset(((char*)pMemOut) + oldSize, 0, newSize - oldSize); + + return pMemOut; } size_t _msize_base( void *pMem ) @@ -485,6 +546,7 @@ void *__cdecl _calloc_dbg_impl( size_t nNum, size_t nSize, int nBlockUse, return _calloc_dbg( nNum, nSize, nBlockUse, szFileName, nLine ); } +#ifdef DEBUG void *__cdecl _realloc_dbg( void *pMem, size_t nNewSize, int nBlockUse, const char *pFileName, int nLine ) { @@ -498,6 +560,7 @@ void *__cdecl _expand_dbg( void *pMem, size_t nNewSize, int nBlockUse, Assert( 0 ); return NULL; } +#endif void __cdecl _free_dbg( void *pMem, int nBlockUse ) { @@ -505,6 +568,7 @@ void __cdecl _free_dbg( void *pMem, int nBlockUse ) g_pMemAlloc->Free(pMem); } +#ifdef DEBUG size_t __cdecl _msize_dbg( void *pMem, int nBlockUse ) { #ifdef _WIN32 @@ -514,6 +578,7 @@ size_t __cdecl _msize_dbg( void *pMem, int nBlockUse ) return 0; #endif } +#endif #ifdef _WIN32 @@ -614,6 +679,7 @@ ALLOC_CALL void * __cdecl _aligned_offset_recalloc( void * memblock, size_t coun extern "C" { +#ifdef DEBUG int _CrtDumpMemoryLeaks(void) { return 0; @@ -628,11 +694,25 @@ int _CrtSetDbgFlag( int nNewFlag ) { return g_pMemAlloc->CrtSetDbgFlag( nNewFlag ); } +#endif // 64-bit port. #define AFNAME(var) __p_ ## var #define AFRET(var) &var +#if _MSC_VER >= 1900 +int* __cdecl __p__crtDbgFlag(void) +{ + static int dummy = _CRTDBG_ALLOC_MEM_DF | _CRTDBG_CHECK_ALWAYS_DF; + return &dummy; +} + +long* __cdecl __p__crtBreakAlloc(void) +{ + static long dummy = 0; + return &dummy; +} +#else int _crtDbgFlag = _CRTDBG_ALLOC_MEM_DF; int* AFNAME(_crtDbgFlag)(void) { @@ -644,12 +724,14 @@ long* AFNAME(_crtBreakAlloc) (void) { return AFRET(_crtBreakAlloc); } +#endif void __cdecl _CrtSetDbgBlockType( void *pMem, int nBlockUse ) { DebuggerBreak(); } +#ifdef DEBUG _CRT_ALLOC_HOOK __cdecl _CrtSetAllocHook( _CRT_ALLOC_HOOK pfnNewHook ) { DebuggerBreak(); @@ -710,13 +792,14 @@ void __cdecl _CrtDoForAllClientObjects( void (*pfn)(void *, void *), void * pCon { DebuggerBreak(); } - +#endif //----------------------------------------------------------------------------- // Methods in dbgrpt.cpp //----------------------------------------------------------------------------- long _crtAssertBusy = -1; +#ifdef DEBUG int __cdecl _CrtSetReportMode( int nReportType, int nReportMode ) { return g_pMemAlloc->CrtSetReportMode( nReportType, nReportMode ); @@ -731,6 +814,7 @@ _CRT_REPORT_HOOK __cdecl _CrtSetReportHook( _CRT_REPORT_HOOK pfnNewHook ) { return (_CRT_REPORT_HOOK)g_pMemAlloc->CrtSetReportHook( pfnNewHook ); } +#endif int __cdecl _CrtDbgReport( int nRptType, const char * szFile, int nLine, const char * szModule, const char * szFormat, ... ) @@ -863,7 +947,7 @@ ErrorHandlerRegistrar::ErrorHandlerRegistrar() _set_invalid_parameter_handler( VInvalidParameterHandler ); } -#if defined( _DEBUG ) +#if 0 // defined( _DEBUG ) // wrapper which passes no debug info; not available in debug #ifndef SUPPRESS_INVALID_PARAMETER_NO_INFO @@ -887,21 +971,41 @@ int __cdecl __crtMessageWindowW( int nRptType, const wchar_t * szFile, const wch int __cdecl _CrtDbgReportV( int nRptType, const wchar_t *szFile, int nLine, const wchar_t *szModule, const wchar_t *szFormat, va_list arglist ) { - Assert(0); + wchar_t buffer[256]; + vswprintf(buffer, 256, szFormat, arglist); + DevWarning("%ls", buffer); return 0; } int __cdecl _CrtDbgReportW( int nRptType, const wchar_t *szFile, int nLine, const wchar_t *szModule, const wchar_t *szFormat, ...) { - Assert(0); + wchar_t buffer[256]; + va_list args; + va_start(args, szFormat); + vswprintf(buffer, 256, szFormat, args); + va_end(args); + DevWarning("%ls", buffer); return 0; } +#if _MSC_VER >= 1900 +int __cdecl _VCrtDbgReportA(int nRptType, void* returnAddress, const char* szFile, int nLine, + const char* szModule, const char* szFormat, va_list arglist) +#else int __cdecl _VCrtDbgReportA( int nRptType, const wchar_t * szFile, int nLine, const wchar_t * szModule, const wchar_t * szFormat, va_list arglist ) +#endif { - Assert(0); +#if _MSC_VER >= 1900 + char buffer[256]; + vsnprintf(buffer, 256, szFormat, arglist); + DevWarning("%s", buffer); +#else + wchar_t buffer[256]; + vswprintf(buffer, 256, szFormat, arglist); + DevWarning("%ls", buffer); +#endif // _MSC_VER >= 1900 return 0; } @@ -927,13 +1031,12 @@ extern "C" int __cdecl _CrtGetCheckCount( void ) return __crtDebugCheckCount; } +#ifdef DEBUG // aligned offset debug extern "C" void * __cdecl _aligned_offset_recalloc_dbg( void * memblock, size_t count, size_t size, size_t align, size_t offset, const char * f_name, int line_n ) { Assert( IsPC() || 0 ); - void *pMem = ReallocUnattributed( memblock, size * count ); - memset( pMem, 0, size * count ); - return pMem; + return ReallocUnattributed(memblock, size * count); } extern "C" void * __cdecl _aligned_recalloc_dbg( void *memblock, size_t count, size_t size, size_t align, const char * f_name, int line_n ) @@ -950,12 +1053,16 @@ _CRT_REPORT_HOOK __cdecl _CrtGetReportHook( void ) { return NULL; } +#endif // DEBUG #endif + +#ifdef DEBUG int __cdecl _CrtReportBlockType(const void * pUserData) { return 0; } +#endif } // end extern "C" @@ -995,14 +1102,14 @@ void * __cdecl _heap_alloc_dbg( size_t nSize, int nBlockUse, const char * szFile static void * __cdecl realloc_help( void * pUserData, size_t * pnNewSize, int nBlockUse,const char * szFileName, int nLine, int fRealloc ) { - assert(0); // Shouldn't be needed + Assert(0); // Shouldn't be needed return NULL; } #else static void * __cdecl realloc_help( void * pUserData, size_t nNewSize, int nBlockUse, const char * szFileName, int nLine, int fRealloc) { - assert(0); // Shouldn't be needed + Assert(0); // Shouldn't be needed return NULL; } #endif @@ -1018,11 +1125,13 @@ void __cdecl _free_dbg_nolock( void * pUserData, int nBlockUse) _free_dbg(pUserData, 0); } +#ifdef DEBUG _CRT_ALLOC_HOOK __cdecl _CrtGetAllocHook ( void) { - assert(0); + Assert(0); return NULL; } +#endif static int __cdecl CheckBytes( unsigned char * pb, unsigned char bCheck, size_t nSize) { @@ -1030,12 +1139,13 @@ static int __cdecl CheckBytes( unsigned char * pb, unsigned char bCheck, size_t return bOkay; } - +#ifdef DEBUG _CRT_DUMP_CLIENT __cdecl _CrtGetDumpClient ( void) { - assert(0); + Assert(0); return NULL; } +#endif #if _MSC_VER >= 1400 static void __cdecl _printMemBlockData( _locale_t plocinfo, _CrtMemBlockHeader * pHead) @@ -1046,6 +1156,8 @@ static void __cdecl _CrtMemDumpAllObjectsSince_stat( const _CrtMemState * state, { } #endif + +#if defined(DEBUG) && _MSC_VER >= 1900 void * __cdecl _aligned_malloc_dbg( size_t size, size_t align, const char * f_name, int line_n) { return _aligned_malloc(size, align); @@ -1073,16 +1185,19 @@ void __cdecl _aligned_free_dbg( void * memblock) { _aligned_free(memblock); } +#endif // DEBUG +#if _MSC_VER < 1900 size_t __cdecl _CrtSetDebugFillThreshold( size_t _NewDebugFillThreshold) { assert(0); return 0; } +#endif //=========================================== // NEW!!! 64-bit - +#ifndef PROTECTED_THINGS_DISABLE char * __cdecl _strdup ( const char * string ) { int nSize = (int)strlen(string) + 1; @@ -1094,6 +1209,7 @@ char * __cdecl _strdup ( const char * string ) memcpy( pCopy, string, nSize ); return pCopy; } +#endif #if 0 _TSCHAR * __cdecl _tfullpath_dbg ( _TSCHAR *UserBuf, const _TSCHAR *path, size_t maxlen, int nBlockUse, const char * szFileName, int nLine ) @@ -1143,7 +1259,6 @@ _TSCHAR * __cdecl _ttempnam ( const _TSCHAR *dir, const _TSCHAR *pfx ) Assert(0); return 0; } -#endif wchar_t * __cdecl _wcsdup_dbg ( const wchar_t * string, int nBlockUse, const char * szFileName, int nLine ) { @@ -1156,6 +1271,7 @@ wchar_t * __cdecl _wcsdup ( const wchar_t * string ) Assert(0); return 0; } +#endif } // end extern "C" @@ -1344,6 +1460,12 @@ _CRTIMP extern uintptr_t __cdecl __threadhandle(void); /* Structure for each thread's data */ +#if _MSC_VER >= 1900 +typedef __crt_multibyte_data* pthreadmbcinfo; +typedef __crt_locale_data* pthreadlocinfo; +typedef __crt_locale_pointers _locale_tstruct; +#endif + struct _tiddata { unsigned long _tid; /* thread ID */ @@ -1387,7 +1509,7 @@ struct _tiddata { * the thread */ pthreadmbcinfo ptmbcinfo; - /* pointer to the copy of the locale informaton used by the thead */ + /* pointer to the copy of the locale information used by the thread */ pthreadlocinfo ptlocinfo; int _ownlocale; /* if 1, this thread owns its own locale */ @@ -1502,7 +1624,7 @@ struct _tiddata { * the thread */ pthreadmbcinfo ptmbcinfo; - /* pointer to the copy of the locale informaton used by the thead */ + /* pointer to the copy of the locale information used by the thread */ pthreadlocinfo ptlocinfo; int _ownlocale; /* if 1, this thread owns its own locale */ diff --git a/sp/src/public/tier0/platform.h b/sp/src/public/tier0/platform.h index f463847b..5afe5eea 100644 --- a/sp/src/public/tier0/platform.h +++ b/sp/src/public/tier0/platform.h @@ -367,7 +367,7 @@ typedef void * HINSTANCE; #define MAX_UNICODE_PATH MAX_PATH #endif -#define MAX_UNICODE_PATH_IN_UTF8 MAX_UNICODE_PATH*4 +#define MAX_UNICODE_PATH_IN_UTF8 (MAX_UNICODE_PATH*4) #ifdef GNUC #undef offsetof @@ -379,7 +379,7 @@ typedef void * HINSTANCE; #endif -#define ALIGN_VALUE( val, alignment ) ( ( val + alignment - 1 ) & ~( alignment - 1 ) ) // need macro for constant expression +#define ALIGN_VALUE( val, alignment ) ( ( (val) + (alignment) - 1 ) & ~( (alignment) - 1 ) ) // need macro for constant expression // Used to step into the debugger #if defined( _WIN32 ) && !defined( _X360 ) @@ -572,7 +572,16 @@ typedef void * HINSTANCE; #endif // GCC 3.4.1 has a bug in supporting forced inline of templated functions // this macro lets us not force inlining in that case - #define FORCEINLINE_TEMPLATE inline +#if __GNUC__ < 4 +#define FORCEINLINE_TEMPLATE inline +#else +#define FORCEINLINE_TEMPLATE inline __attribute__((always_inline)) +#endif +#if __cpp_constexpr >= 201304 +#define CONSTEXPR_FUNC constexpr +#else +#define CONSTEXPR_FUNC +#endif // #define __stdcall __attribute__ ((__stdcall__)) #endif @@ -672,6 +681,40 @@ typedef void * HINSTANCE; #pragma warning( disable : 4312 ) // conversion from 'unsigned int' to 'memhandle_t' of greater size #endif +// Detect C++11 support for "rvalue references" / "move semantics" / other C++11 (and up) stuff +#if defined(_MSC_VER) +#if _MSC_VER >= 1600 +#define VALVE_RVALUE_REFS 1 +#endif +#if _MSC_VER >= 1800 +#define VALVE_INITIALIZER_LIST_SUPPORT 1 +#define VALVE_EXPLICIT_CONVERSION_OP 1 +#endif +#elif defined(__clang__) +#if __has_extension(cxx_rvalue_references) +#define VALVE_RVALUE_REFS 1 +#endif +#if __has_feature(cxx_generalized_initializers) +#define VALVE_INITIALIZER_LIST_SUPPORT 1 +#endif +#if __has_feature(cxx_explicit_conversions) +#define VALVE_EXPLICIT_CONVERSION_OP 1 +#endif +#elif defined(__GNUC__) +#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6 ) +#if defined(__GXX_EXPERIMENTAL_CXX0X__) +#define VALVE_RVALUE_REFS 1 +#define VALVE_INITIALIZER_LIST_SUPPORT 1 +#define VALVE_EXPLICIT_CONVERSION_OP 1 +#endif +#endif +#endif + +#ifdef VALVE_RVALUE_REFS +#include "tier0/valve_minmax_off.h" +#include +#include "tier0/valve_minmax_on.h" +#endif #ifdef POSIX #define _stricmp stricmp @@ -1313,62 +1356,81 @@ inline const char *GetPlatformExt( void ) template inline T* Construct( T* pMemory ) { + HINT(pMemory != 0); return ::new( pMemory ) T; } template inline T* Construct( T* pMemory, ARG1 a1 ) { + HINT(pMemory != 0); return ::new( pMemory ) T( a1 ); } template inline T* Construct( T* pMemory, ARG1 a1, ARG2 a2 ) { + HINT(pMemory != 0); return ::new( pMemory ) T( a1, a2 ); } template inline T* Construct( T* pMemory, ARG1 a1, ARG2 a2, ARG3 a3 ) { + HINT(pMemory != 0); return ::new( pMemory ) T( a1, a2, a3 ); } template inline T* Construct( T* pMemory, ARG1 a1, ARG2 a2, ARG3 a3, ARG4 a4 ) { + HINT(pMemory != 0); return ::new( pMemory ) T( a1, a2, a3, a4 ); } template inline T* Construct( T* pMemory, ARG1 a1, ARG2 a2, ARG3 a3, ARG4 a4, ARG5 a5 ) { + HINT(pMemory != 0); return ::new( pMemory ) T( a1, a2, a3, a4, a5 ); } template inline void ConstructOneArg( T* pMemory, P const& arg) { + HINT(pMemory != 0); ::new( pMemory ) T(arg); } template inline void ConstructTwoArg( T* pMemory, P1 const& arg1, P2 const& arg2) { + HINT(pMemory != 0); ::new( pMemory ) T(arg1, arg2); } template inline void ConstructThreeArg( T* pMemory, P1 const& arg1, P2 const& arg2, P3 const& arg3) { + HINT(pMemory != 0); ::new( pMemory ) T(arg1, arg2, arg3); } template inline T* CopyConstruct( T* pMemory, T const& src ) { + HINT(pMemory != 0); return ::new( pMemory ) T(src); } + +#ifdef VALVE_RVALUE_REFS +template +inline void CopyConstruct(T* pMemory, T&& src) +{ + HINT(pMemory != 0); + ::new(pMemory)T(std::forward(src)); +} +#endif template inline void Destruct( T* pMemory ) diff --git a/sp/src/public/tier1/UtlSortVector.h b/sp/src/public/tier1/UtlSortVector.h index b5bfef53..53989db4 100644 --- a/sp/src/public/tier1/UtlSortVector.h +++ b/sp/src/public/tier1/UtlSortVector.h @@ -245,7 +245,7 @@ void CUtlSortVector::QuickSort( LessFunc& less, int nLo ctx.m_pLessContext = m_pLessContext; ctx.m_pLessFunc = &less; - qsort_s( Base(), Count(), sizeof(T), (QSortCompareFunc_t)&CUtlSortVector::CompareHelper, &ctx ); + qsort_s( this->Base(), this->Count(), sizeof(T), (QSortCompareFunc_t)&CUtlSortVector::CompareHelper, &ctx ); } #else typedef int (__cdecl *QSortCompareFunc_t)( const void *, const void *); diff --git a/sp/src/public/tier1/byteswap.h b/sp/src/public/tier1/byteswap.h index 9b082541..9c866639 100644 --- a/sp/src/public/tier1/byteswap.h +++ b/sp/src/public/tier1/byteswap.h @@ -186,7 +186,7 @@ public: if( !m_bSwapBytes || ( sizeof(T) == 1 ) ) { // If we were just going to swap in place then return. - if( !inputBuffer ) + if( inputBuffer == outputBuffer ) return; // Otherwise copy the inputBuffer to the outputBuffer: diff --git a/sp/src/public/vgui_controls/Panel.h b/sp/src/public/vgui_controls/Panel.h index 07b63d8d..99f8e223 100644 --- a/sp/src/public/vgui_controls/Panel.h +++ b/sp/src/public/vgui_controls/Panel.h @@ -139,7 +139,7 @@ class IForceVirtualInheritancePanel // This is designed as an easy-access to the vgui-functionality; for more // low-level access to vgui functions use the IPanel/IClientPanel interfaces directly //----------------------------------------------------------------------------- -class Panel : public IClientPanel, virtual IForceVirtualInheritancePanel +class Panel : public IClientPanel, public virtual IForceVirtualInheritancePanel { DECLARE_CLASS_SIMPLE_NOBASE( Panel ); @@ -1011,7 +1011,7 @@ public: void VguiPanelGetSortedChildPanelList( Panel *pParentPanel, void *pSortedPanels ); -void VguiPanelGetSortedChildButtonList( Panel *pParentPanel, void *pSortedPanels, char *pchFilter = NULL, int nFilterType = 0 ); +void VguiPanelGetSortedChildButtonList( Panel *pParentPanel, void *pSortedPanels, const char *pchFilter = NULL, int nFilterType = 0 ); int VguiPanelNavigateSortedChildButtonList( void *pSortedPanels, int nDir ); diff --git a/sp/src/public/vscript/ivscript.h b/sp/src/public/vscript/ivscript.h index 5fe1d570..001e1c24 100644 --- a/sp/src/public/vscript/ivscript.h +++ b/sp/src/public/vscript/ivscript.h @@ -828,6 +828,8 @@ enum ScriptStatus_t class IScriptVM { public: + virtual ~IScriptVM() {} + virtual bool Init() = 0; virtual void Shutdown() = 0; diff --git a/sp/src/raytrace/raytrace.cpp b/sp/src/raytrace/raytrace.cpp index 9816560d..6def3bab 100644 --- a/sp/src/raytrace/raytrace.cpp +++ b/sp/src/raytrace/raytrace.cpp @@ -425,11 +425,11 @@ void RayTracingEnvironment::Trace4Rays(const FourRays &rays, fltx4 TMin, fltx4 T MulSIMD( SubSIMD(ReplicateX4(CurNode->SplittingPlaneValue), rays.origin[split_plane_number]),OneOverRayDir[split_plane_number]); - fltx4 active=CmpLeSIMD(TMin,TMax); // mask of which rays are active + fltx4 activeLocl=CmpLeSIMD(TMin,TMax); // mask of which rays are active // now, decide how to traverse children. can either do front,back, or do front and push // back. - fltx4 hits_front=AndSIMD(active,CmpGeSIMD(dist_to_sep_plane,TMin)); + fltx4 hits_front=AndSIMD(activeLocl,CmpGeSIMD(dist_to_sep_plane,TMin)); if (! IsAnyNegative(hits_front)) { // missed the front. only traverse back @@ -440,7 +440,7 @@ void RayTracingEnvironment::Trace4Rays(const FourRays &rays, fltx4 TMin, fltx4 T } else { - fltx4 hits_back=AndSIMD(active,CmpLeSIMD(dist_to_sep_plane,TMax)); + fltx4 hits_back=AndSIMD(activeLocl,CmpLeSIMD(dist_to_sep_plane,TMax)); if (! IsAnyNegative(hits_back) ) { // missed the back - only need to traverse front node diff --git a/sp/src/raytrace/trace2.cpp b/sp/src/raytrace/trace2.cpp index 4b1d19f6..d2e50557 100644 --- a/sp/src/raytrace/trace2.cpp +++ b/sp/src/raytrace/trace2.cpp @@ -155,14 +155,14 @@ void RayTracingEnvironment::RenderScene( fltx4 MaxT=ldir.length(); ldir.VectorNormalizeFast(); // now, compute shadow flag - FourRays myrays; - myrays.origin=surface_pos; + FourRays myraysLocl; + myraysLocl.origin=surface_pos; FourVectors epsilon=ldir; epsilon*=0.01; - myrays.origin+=epsilon; - myrays.direction=ldir; + myraysLocl.origin+=epsilon; + myraysLocl.direction=ldir; RayTracingResult shadowtest; - Trace4Rays(myrays,Four_Zeros,MaxT, &shadowtest); + Trace4Rays(myraysLocl,Four_Zeros,MaxT, &shadowtest); fltx4 unshadowed=CmpGtSIMD(shadowtest.HitDistance,MaxT); if (! (IsAllZeros(unshadowed))) { diff --git a/sp/src/tier1/bitbuf.cpp b/sp/src/tier1/bitbuf.cpp index 52a25e4d..e723bae9 100644 --- a/sp/src/tier1/bitbuf.cpp +++ b/sp/src/tier1/bitbuf.cpp @@ -1357,13 +1357,13 @@ int64 bf_read::ReadLongLong() float bf_read::ReadFloat() { - float ret; - Assert( sizeof(ret) == 4 ); - ReadBits(&ret, 32); + float retLocl; + Assert( sizeof(retLocl) == 4 ); + ReadBits(&retLocl, 32); // Swap the float, since ReadBits reads raw data - LittleFloat( &ret, &ret ); - return ret; + LittleFloat( &retLocl, &retLocl ); + return retLocl; } bool bf_read::ReadBytes(void *pOut, int nBytes) diff --git a/sp/src/tier1/snappy-stubs-internal.h b/sp/src/tier1/snappy-stubs-internal.h index ec5d1018..7db8b931 100644 --- a/sp/src/tier1/snappy-stubs-internal.h +++ b/sp/src/tier1/snappy-stubs-internal.h @@ -138,7 +138,7 @@ class LogMessage { class LogMessageCrash : public LogMessage { public: LogMessageCrash() { } -#if _MSC_VER == 1700 || _MSC_VER == 1800 +#if _MSC_VER >= 1700 // Bogus warning from VS 2012 and VS 2013: // warning C4722: 'snappy::LogMessageCrash::~LogMessageCrash' : destructor never returns, potential memory leak #pragma warning(push) diff --git a/sp/src/utils/captioncompiler/captioncompiler.vpc b/sp/src/utils/captioncompiler/captioncompiler.vpc index da5a3b4e..020855fb 100644 --- a/sp/src/utils/captioncompiler/captioncompiler.vpc +++ b/sp/src/utils/captioncompiler/captioncompiler.vpc @@ -14,7 +14,8 @@ $Configuration $Compiler { $AdditionalIncludeDirectories "$BASE,..\common,$SRCDIR\game\shared,.\" - $PreprocessorDefinitions "$BASE;captioncompiler" + $PreprocessorDefinitions "$BASE;PROTECTED_THINGS_DISABLE;captioncompiler" [$VS2019] + $PreprocessorDefinitions "$BASE;captioncompiler" [!$VS2019] } } diff --git a/sp/src/vgui2/vgui_controls/Panel.cpp b/sp/src/vgui2/vgui_controls/Panel.cpp index 499296d9..6054fd29 100644 --- a/sp/src/vgui2/vgui_controls/Panel.cpp +++ b/sp/src/vgui2/vgui_controls/Panel.cpp @@ -8510,7 +8510,7 @@ void VguiPanelGetSortedChildPanelList( Panel *pParentPanel, void *pSortedPanels } } -void VguiPanelGetSortedChildButtonList( Panel *pParentPanel, void *pSortedPanels, char *pchFilter /*= NULL*/, int nFilterType /*= 0*/ ) +void VguiPanelGetSortedChildButtonList( Panel *pParentPanel, void *pSortedPanels, const char *pchFilter /*= NULL*/, int nFilterType /*= 0*/ ) { CUtlSortVector< SortedPanel_t, CSortedPanelYLess > *pList = reinterpret_cast< CUtlSortVector< SortedPanel_t, CSortedPanelYLess >* >( pSortedPanels ); diff --git a/sp/src/vgui2/vgui_controls/ScrollBarSlider.cpp b/sp/src/vgui2/vgui_controls/ScrollBarSlider.cpp index 32df2fae..6f127558 100644 --- a/sp/src/vgui2/vgui_controls/ScrollBarSlider.cpp +++ b/sp/src/vgui2/vgui_controls/ScrollBarSlider.cpp @@ -18,7 +18,9 @@ #include #include +#if _MSC_VER < 1900 #include +#endif // memdbgon must be the last include file in a .cpp file!!! #include diff --git a/sp/src/vgui2/vgui_controls/Tooltip.cpp b/sp/src/vgui2/vgui_controls/Tooltip.cpp index e18427eb..7f9738d2 100644 --- a/sp/src/vgui2/vgui_controls/Tooltip.cpp +++ b/sp/src/vgui2/vgui_controls/Tooltip.cpp @@ -6,8 +6,8 @@ // and implement another button here. //=============================================================================// -#include -#define PROTECTED_THINGS_DISABLE +//#include +//#define PROTECTED_THINGS_DISABLE #include #include diff --git a/sp/src/vgui2/vgui_controls/TreeView.cpp b/sp/src/vgui2/vgui_controls/TreeView.cpp index b7ad4d3b..c244edeb 100644 --- a/sp/src/vgui2/vgui_controls/TreeView.cpp +++ b/sp/src/vgui2/vgui_controls/TreeView.cpp @@ -418,7 +418,7 @@ class TreeNode : public Panel public: TreeNode(Panel *parent, TreeView *pTreeView); - ~TreeNode(); + virtual ~TreeNode(); void SetText(const char *pszText); void SetFont(HFont font); void SetKeyValues(KeyValues *data); diff --git a/sp/src/vpc_scripts/source_base.vpc b/sp/src/vpc_scripts/source_base.vpc index 66530a33..d3d0c73d 100644 --- a/sp/src/vpc_scripts/source_base.vpc +++ b/sp/src/vpc_scripts/source_base.vpc @@ -16,17 +16,15 @@ //$Conditional TF_BETA "1" //----------------------------------------------------------------------------- -// Mapbase conditional, equivalent to (and required for) our MAPBASE preprocessor defined below -$Conditional MAPBASE "1" -// Toggles Mapbase's RPC implementation -$Conditional MAPBASE_RPC "1" +$Conditional VS2019 "1" // Toggles Visual Studio 2019 toolset (NOTE: This makes the solution incompatible with Visual Studio 2013) -// Toggles VScript implementation (note: interfaces still exist, just the provided implementation is not present) -$Conditional MAPBASE_VSCRIPT "1" +// Mapbase functionality conditionals +$Conditional MAPBASE "1" // Equivalent to (and required for) our MAPBASE preprocessor defined below +$Conditional MAPBASE_RPC "1" // Toggles Mapbase's Rich Presence Client implementations +$Conditional MAPBASE_VSCRIPT "1" // Toggles VScript implementation (note: interfaces still exist, just the provided implementation is not present) +$Conditional NEW_RESPONSE_SYSTEM "1" // Toggles the new Response System library based on the Alien Swarm SDK -// Toggles the new Response System library based on the Alien Swarm SDK. -$Conditional NEW_RESPONSE_SYSTEM "1" //----------------------------------------------------------------------------- $Configuration "Debug" diff --git a/sp/src/vpc_scripts/source_dll_win32_base.vpc b/sp/src/vpc_scripts/source_dll_win32_base.vpc index 4b2a2852..4e738920 100644 --- a/sp/src/vpc_scripts/source_dll_win32_base.vpc +++ b/sp/src/vpc_scripts/source_dll_win32_base.vpc @@ -39,12 +39,14 @@ $Configuration $Compiler [$WIN32] { - $EnableEnhancedInstructionSet "Streaming SIMD Extensions (/arch:SSE)" + $EnableEnhancedInstructionSet "Streaming SIMD Extensions (/arch:SSE)" [!$VS2019] + $EnableEnhancedInstructionSet "Streaming SIMD Extensions 2 (/arch:SSE2)" [$VS2019] } $Linker { - $AdditionalDependencies "$BASE shell32.lib user32.lib advapi32.lib gdi32.lib comdlg32.lib ole32.lib" [$WIN32||$WIN64] + $AdditionalDependencies "$BASE shell32.lib user32.lib advapi32.lib gdi32.lib comdlg32.lib ole32.lib" [($WIN32||$WIN64) && !$VS2019] + $AdditionalDependencies "$BASE shell32.lib user32.lib advapi32.lib gdi32.lib comdlg32.lib ole32.lib legacy_stdio_definitions.lib" [($WIN32||$WIN64) && $VS2019] $TargetMachine "MachineX86 (/MACHINE:X86)" [$WIN32] $TargetMachine "MachineX64 (/MACHINE:X64)" [$WIN64] // Suppress this pointless warning using the undocumented /ignore linker switch @@ -69,7 +71,7 @@ $Configuration "if ERRORLEVEL 1 goto BuildEventFailed" "\n" \ "if exist $QUOTE$(TargetDir)$(TargetName).map$QUOTE copy $QUOTE$(TargetDir)$(TargetName).map$QUOTE $OUTBINDIR\$(TargetName).map" "\n" $CommandLine "$BASE" "call $SRCDIR\vpc_scripts\valve_p4_edit.cmd $QUOTE$OUTBINDIR\$(TargetName).pdb$QUOTE $SRCDIR" "\n" [!$SOURCESDK] - $CommandLine "$BASE" "copy $QUOTE$(TargetDir)$(TargetName).pdb$QUOTE $OUTBINDIR\$(TargetName).pdb" "\n" \ + $CommandLine "$BASE" "copy $QUOTE$(TargetDir)$(TargetName).pdb$QUOTE $QUOTE$OUTBINDIR\$(TargetName).pdb$QUOTE" "\n" \ "if ERRORLEVEL 1 goto BuildEventFailed" "\n" \ "goto BuildEventOK" "\n" \ ":BuildEventFailed" "\n" \ @@ -114,7 +116,8 @@ $Project $CustomBuildStep { // General - $CommandLine "$QUOTE$(VCInstallDir)bin\ml.exe$QUOTE /safeseh /c /Cp /Zi /Fo$QUOTE$(IntDir)\$(InputName).obj$QUOTE $QUOTE$(InputPath)$QUOTE" + $CommandLine "$QUOTE$(VCInstallDir)bin\ml.exe$QUOTE /safeseh /c /Cp /Zi /Fo$QUOTE$(IntDir)\$(InputName).obj$QUOTE $QUOTE$(InputPath)$QUOTE" [!$VS2019] + $CommandLine "$QUOTE$(VC_ExecutablePath_x64_x86)bin\ml.exe$QUOTE /safeseh /c /Cp /Zi /Fo$QUOTE$(IntDir)\$(InputName).obj$QUOTE $QUOTE$(InputPath)$QUOTE" [$VS2019] $Description "Compiling pointeroverride.asm" $Outputs "$(IntDir)\$(InputName).obj" } diff --git a/sp/src/vpc_scripts/source_exe_win_win32_base.vpc b/sp/src/vpc_scripts/source_exe_win_win32_base.vpc index 47ce40fd..e756073f 100644 --- a/sp/src/vpc_scripts/source_exe_win_win32_base.vpc +++ b/sp/src/vpc_scripts/source_exe_win_win32_base.vpc @@ -39,7 +39,8 @@ $Configuration $Compiler [$WIN32] { - $EnableEnhancedInstructionSet "Streaming SIMD Extensions (/arch:SSE)" + $EnableEnhancedInstructionSet "Streaming SIMD Extensions (/arch:SSE)" [!$VS2019] + $EnableEnhancedInstructionSet "Streaming SIMD Extensions 2 (/arch:SSE2)" [$VS2019] } $Linker @@ -66,7 +67,8 @@ $Configuration $PostBuildEvent [!$ANALYZE] { - $CommandLine "call $SRCDIR\vpc_scripts\valve_p4_edit.cmd $OUTBINDIR\$(TargetFileName) $SRCDIR" "\n" [!$SOURCESDK] + $CommandLine "call $SRCDIR\vpc_scripts\valve_p4_edit.cmd $OUTBINDIR\$(TargetFileName) $SRCDIR" "\n" [!$SOURCESDK && !$VS2019] + $CommandLine "if not exist $QUOTE$OUTBINDIR$QUOTE mkdir $QUOTE$OUTBINDIR$QUOTE" "\n" [!$SOURCESDK && $VS2019] $CommandLine "$BASE" "copy $QUOTE$(TargetDir)$QUOTE$(TargetFileName) $OUTBINDIR\$(TargetFileName) >nul" "\n" \ "if ERRORLEVEL 1 goto BuildEventFailed" "\n" \ "if exist $QUOTE$(TargetDir)$QUOTE$(TargetName).map copy $QUOTE$(TargetDir)$QUOTE$(TargetName).map $OUTBINDIR\$(TargetName).map >nul" "\n" @@ -109,7 +111,8 @@ $Project $CustomBuildStep { // General - $CommandLine "$QUOTE$(VCInstallDir)bin\ml.exe$QUOTE /c /Cp /Zi /Fo$QUOTE$(IntDir)\$(InputName).obj$QUOTE $QUOTE$(InputPath)$QUOTE" + $CommandLine "$QUOTE$(VCInstallDir)bin\ml.exe$QUOTE /c /Cp /Zi /Fo$QUOTE$(IntDir)\$(InputName).obj$QUOTE $QUOTE$(InputPath)$QUOTE" [!$VS2019] + $CommandLine "$QUOTE$(VC_ExecutablePath_x64_x86)\ml.exe$QUOTE /c /Cp /Zi /Fo$QUOTE$(IntDir)\$(InputName).obj$QUOTE $QUOTE$(InputPath)$QUOTE" [$VS2019] $Description "Compiling pointeroverride.asm" $Outputs "$(IntDir)\$(InputName).obj" } diff --git a/sp/src/vpc_scripts/source_lib_win32_base.vpc b/sp/src/vpc_scripts/source_lib_win32_base.vpc index 02caa800..ee62e539 100644 --- a/sp/src/vpc_scripts/source_lib_win32_base.vpc +++ b/sp/src/vpc_scripts/source_lib_win32_base.vpc @@ -38,7 +38,8 @@ $Configuration $Compiler [$WIN32] { - $EnableEnhancedInstructionSet "Streaming SIMD Extensions (/arch:SSE)" + $EnableEnhancedInstructionSet "Streaming SIMD Extensions (/arch:SSE)" [!$VS2019] + $EnableEnhancedInstructionSet "Streaming SIMD Extensions 2 (/arch:SSE2)" [$VS2019] } $PreBuildEvent diff --git a/sp/src/vpc_scripts/source_win32_base.vpc b/sp/src/vpc_scripts/source_win32_base.vpc index 245366f4..7dd289ed 100644 --- a/sp/src/vpc_scripts/source_win32_base.vpc +++ b/sp/src/vpc_scripts/source_win32_base.vpc @@ -8,10 +8,11 @@ $Configuration $General { // Request a specific compiler toolset. - $PlatformToolset "v110_xp" [$VS2012 && !$ANALYZE] // VS 2012 targeting Windows XP - http://msdn.microsoft.com/en-us/library/vstudio/jj851139.aspx - $PlatformToolset "v110" [$VS2012 && $ANALYZE] // VS 2012 for /analyze - $PlatformToolset "v120_xp" [$VS2013 && !$ANALYZE] // VS 2013 targeting Windows XP - http://msdn.microsoft.com/en-us/library/vstudio/jj851139.aspx - $PlatformToolset "v120" [$VS2013 && $ANALYZE] // VS 2013 for /analyze + $PlatformToolset "v110_xp" [$VS2012 && !$ANALYZE && !$VS2019] // VS 2012 targeting Windows XP - http://msdn.microsoft.com/en-us/library/vstudio/jj851139.aspx + $PlatformToolset "v110" [$VS2012 && $ANALYZE && !$VS2019] // VS 2012 for /analyze + $PlatformToolset "v120_xp" [$VS2013 && !$ANALYZE && !$VS2019] // VS 2013 targeting Windows XP - http://msdn.microsoft.com/en-us/library/vstudio/jj851139.aspx + $PlatformToolset "v120" [$VS2013 && $ANALYZE && !$VS2019] // VS 2013 for /analyze + $PlatformToolset "v142" [$VS2019] // VS 2019 } $General @@ -31,6 +32,10 @@ $Configuration // warning C4316: object allocated on the heap may not be aligned 16 $DisableSpecificWarnings "$BASE;4316" [$VS2013] + + // warning C4838: conversion requires a narrowing conversion + // warning C4456-4459: variable shadowing. TODO: fix those! + $DisableSpecificWarnings "$BASE;4316;4838;4456;4457;4458;4459" [$VS2019] // Having lots of warnings makes it harder to notice new, and possibly // important warnings, both on buildbot and in the output window. Lots From 2ffec5bbcf070201f18c6ec5038c05a7ab651de8 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Fri, 16 Jul 2021 11:56:13 -0500 Subject: [PATCH 104/378] Fixed a critical issue with Mapbase's default HL2 FGD being incompatible with VBSP instancing --- sp/src/utils/vbsp/map.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sp/src/utils/vbsp/map.cpp b/sp/src/utils/vbsp/map.cpp index f59305ba..dcb9aea5 100644 --- a/sp/src/utils/vbsp/map.cpp +++ b/sp/src/utils/vbsp/map.cpp @@ -2105,7 +2105,12 @@ void CMapFile::CheckForInstances( const char *pszFileName ) } char FDGPath[ MAX_PATH ]; +#ifdef MAPBASE + // Mapbase's FGD would be in a MOD path + if ( !g_pFullFileSystem->RelativePathToFullPath( GameDataFile, "MOD", FDGPath, sizeof( FDGPath ) ) ) +#else if ( !g_pFullFileSystem->RelativePathToFullPath( GameDataFile, "EXECUTABLE_PATH", FDGPath, sizeof( FDGPath ) ) ) +#endif { if ( !g_pFullFileSystem->RelativePathToFullPath( GameDataFile, NULL, FDGPath, sizeof( FDGPath ) ) ) { @@ -2606,7 +2611,7 @@ void CMapFile::MergeEntities( entity_t *pInstanceEntity, CMapFile *Instance, Vec Msg( "Instance Entity %d remapped to %d\n", i, num_entities + i ); Msg( " FirstBrush: from %d to %d\n", Instance->entities[ i ].firstbrush, entity->firstbrush ); Msg( " KV Pairs:\n" ); - for ( epair_t *ep = entity->epairs; ep->next != NULL; ep = ep->next ) + for ( epair_t *ep = entity->epairs; ep != NULL; ep = ep->next ) { Msg( " %s %s\n", ep->key, ep->value ); } From 20f29c555218d0748b5a32359b9e45db1e44ef55 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sat, 17 Jul 2021 00:32:56 -0500 Subject: [PATCH 105/378] Added prototype for a new type of commentary node which displays text instead of playing audio --- .../game/client/c_point_commentary_node.cpp | 305 ++++++++++++++---- sp/src/game/server/CommentarySystem.cpp | 10 + 2 files changed, 254 insertions(+), 61 deletions(-) diff --git a/sp/src/game/client/c_point_commentary_node.cpp b/sp/src/game/client/c_point_commentary_node.cpp index 47ea96ef..a24973a8 100644 --- a/sp/src/game/client/c_point_commentary_node.cpp +++ b/sp/src/game/client/c_point_commentary_node.cpp @@ -18,6 +18,9 @@ #include "convar.h" #include "hud_closecaption.h" #include "in_buttons.h" +#ifdef MAPBASE +#include "vgui_controls/Label.h" +#endif // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -37,6 +40,11 @@ bool IsInCommentaryMode( void ) static bool g_bTracingVsCommentaryNodes = false; +#ifdef MAPBASE +ConVar commentary_text_force( "commentary_text_force", "0", FCVAR_NONE, "Forces all commentary nodes to use the text type." ); +ConVar commentary_text_endtime( "commentary_text_endtime", "120" ); +#endif + //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- @@ -52,6 +60,9 @@ public: virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); void StartCommentary( C_PointCommentaryNode *pNode, char *pszSpeakers, int iNode, int iNodeMax, float flStartTime, float flEndTime ); +#ifdef MAPBASE + void StartTextCommentary( C_PointCommentaryNode *pNode, const char *pszText, char *pszSpeakers, int iNode, int iNodeMax, float flStartTime, float flEndTime ); +#endif void StopCommentary( void ); bool IsTheActiveNode( C_PointCommentaryNode *pNode ) { return (pNode == m_hActiveNode); } @@ -68,6 +79,11 @@ private: wchar_t m_szCount[MAX_COUNT_STRING]; CMaterialReference m_matIcon; bool m_bHiding; +#ifdef MAPBASE + bool m_bTextCommentary; // NOTE: If any more types are needed, use an enum + wchar_t *m_pszText; + vgui::Label *m_pLabel; +#endif // Painting CPanelAnimationVarAliasType( int, m_iBarX, "bar_xpos", "8", "proportional_int" ); @@ -84,8 +100,27 @@ private: CPanelAnimationVarAliasType( int, m_iIconTall, "icon_height", "8", "proportional_int" ); CPanelAnimationVarAliasType( int, m_nIconTextureId, "icon_texture", "vgui/hud/icon_commentary", "textureid" ); +#ifdef MAPBASE + CPanelAnimationVarAliasType( int, m_iTypeAudioX, "type_audio_xpos", "190", "proportional_int" ); + CPanelAnimationVarAliasType( int, m_iTypeAudioY, "type_audio_ypos", "350", "proportional_int" ); + CPanelAnimationVarAliasType( int, m_iTypeAudioW, "type_audio_wide", "380", "proportional_int" ); + CPanelAnimationVarAliasType( int, m_iTypeAudioT, "type_audio_tall", "40", "proportional_int" ); + CPanelAnimationVarAliasType( int, m_iTypeTextX, "type_text_xpos", "180", "proportional_int" ); + CPanelAnimationVarAliasType( int, m_iTypeTextY, "type_text_ypos", "150", "proportional_int" ); + CPanelAnimationVarAliasType( int, m_iTypeTextW, "type_text_wide", "400", "proportional_int" ); + CPanelAnimationVarAliasType( int, m_iTypeTextT, "type_text_tall", "200", "proportional_int" ); + CPanelAnimationVarAliasType( int, m_iTypeTextCountXFR, "type_text_count_xpos_from_right", "10", "proportional_int" ); + CPanelAnimationVarAliasType( int, m_iTypeTextCountY, "type_text_count_ypos", "184", "proportional_int" ); + CPanelAnimationVar( Color, m_TextBackgroundColor, "type_text_bg", "0 0 0 192" ); + CPanelAnimationVar( Color, m_TextColor, "type_text_fg", "255 230 180 255" ); +#endif + CPanelAnimationVar( bool, m_bUseScriptBGColor, "use_script_bgcolor", "0" ); +#ifdef MAPBASE + CPanelAnimationVar( Color, m_BackgroundColor, "BackgroundColor", "Panel.BgColor" ); +#else CPanelAnimationVar( Color, m_BackgroundColor, "BackgroundColor", "0 0 0 0" ); +#endif CPanelAnimationVar( Color, m_BGOverrideColor, "BackgroundOverrideColor", "Panel.BgColor" ); }; @@ -102,6 +137,11 @@ public: virtual void OnPreDataChanged( DataUpdateType_t type ); virtual void OnDataChanged( DataUpdateType_t type ); + void StartAudioCommentary( const char *pszCommentaryFile, C_BasePlayer *pPlayer ); +#ifdef MAPBASE + void StartTextCommentary( const char *pszCommentaryFile, C_BasePlayer *pPlayer ); +#endif + void OnRestore( void ) { BaseClass::OnRestore(); @@ -181,6 +221,9 @@ public: CSoundPatch *m_sndCommentary; EHANDLE m_hViewPosition; bool m_bRestartAfterRestore; +#ifdef MAPBASE + bool m_bTextCommentary; +#endif }; IMPLEMENT_CLIENTCLASS_DT(C_PointCommentaryNode, DT_PointCommentaryNode, CPointCommentaryNode) @@ -192,6 +235,9 @@ IMPLEMENT_CLIENTCLASS_DT(C_PointCommentaryNode, DT_PointCommentaryNode, CPointCo RecvPropInt( RECVINFO( m_iNodeNumber ) ), RecvPropInt( RECVINFO( m_iNodeNumberMax ) ), RecvPropEHandle( RECVINFO(m_hViewPosition) ), +#ifdef MAPBASE + RecvPropBool( RECVINFO( m_bTextCommentary ) ), +#endif END_RECV_TABLE() BEGIN_DATADESC( C_PointCommentaryNode ) @@ -245,58 +291,12 @@ void C_PointCommentaryNode::OnDataChanged( DataUpdateType_t updateType ) return; } - EmitSound_t es; - es.m_nChannel = CHAN_STATIC; - es.m_pSoundName = pszCommentaryFile; - es.m_SoundLevel = SNDLVL_GUNFIRE; - es.m_nFlags = SND_SHOULDPAUSE; - - CBaseEntity *pSoundEntity; - if ( m_hViewPosition ) - { - pSoundEntity = m_hViewPosition; - } - else if ( render->GetViewEntity() ) - { - pSoundEntity = cl_entitylist->GetEnt( render->GetViewEntity() ); - es.m_SoundLevel = SNDLVL_NONE; - } +#ifdef MAPBASE + if (m_bTextCommentary || commentary_text_force.GetBool()) + StartTextCommentary( pszCommentaryFile, pPlayer ); else - { - pSoundEntity = pPlayer; - } - CSingleUserRecipientFilter filter( pPlayer ); - m_sndCommentary = (CSoundEnvelopeController::GetController()).SoundCreate( filter, pSoundEntity->entindex(), es ); - if ( m_sndCommentary ) - { - (CSoundEnvelopeController::GetController()).SoundSetCloseCaptionDuration( m_sndCommentary, -1 ); - (CSoundEnvelopeController::GetController()).Play( m_sndCommentary, 1.0f, 100, m_flStartTime ); - } - - // Get the duration so we know when it finishes - float flDuration = enginesound->GetSoundDuration( STRING( CSoundEnvelopeController::GetController().SoundGetName( m_sndCommentary ) ) ) ; - - CHudCloseCaption *pHudCloseCaption = (CHudCloseCaption *)GET_HUDELEMENT( CHudCloseCaption ); - if ( pHudCloseCaption ) - { - // This is where we play the commentary close caption (and lock the other captions out). - // Also, if close captions are off we force a caption in non-English - if ( closecaption.GetBool() || ( !closecaption.GetBool() && !english.GetBool() ) ) - { - // Clear the close caption element in preparation - pHudCloseCaption->Reset(); - - // Process the commentary caption - pHudCloseCaption->ProcessCaptionDirect( pszCommentaryFile, flDuration ); - - // Find the close caption hud element & lock it - pHudCloseCaption->Lock(); - } - } - - // Tell the HUD element - CHudCommentary *pHudCommentary = (CHudCommentary *)GET_HUDELEMENT( CHudCommentary ); - pHudCommentary->StartCommentary( this, m_iszSpeakers, m_iNodeNumber, m_iNodeNumberMax, m_flStartTime, m_flStartTime + flDuration ); +#endif + StartAudioCommentary( pszCommentaryFile, pPlayer ); } else if ( m_bWasActive ) { @@ -312,6 +312,83 @@ void C_PointCommentaryNode::OnDataChanged( DataUpdateType_t updateType ) m_bRestartAfterRestore = false; } +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_PointCommentaryNode::StartAudioCommentary( const char *pszCommentaryFile, C_BasePlayer *pPlayer ) +{ + EmitSound_t es; + es.m_nChannel = CHAN_STATIC; + es.m_pSoundName = pszCommentaryFile; + es.m_SoundLevel = SNDLVL_GUNFIRE; + es.m_nFlags = SND_SHOULDPAUSE; + + CBaseEntity *pSoundEntity; + if ( m_hViewPosition ) + { + pSoundEntity = m_hViewPosition; + } + else if ( render->GetViewEntity() ) + { + pSoundEntity = cl_entitylist->GetEnt( render->GetViewEntity() ); + es.m_SoundLevel = SNDLVL_NONE; + } + else + { + pSoundEntity = pPlayer; + } + CSingleUserRecipientFilter filter( pPlayer ); + m_sndCommentary = (CSoundEnvelopeController::GetController()).SoundCreate( filter, pSoundEntity->entindex(), es ); + if ( m_sndCommentary ) + { + (CSoundEnvelopeController::GetController()).SoundSetCloseCaptionDuration( m_sndCommentary, -1 ); + (CSoundEnvelopeController::GetController()).Play( m_sndCommentary, 1.0f, 100, m_flStartTime ); + } + + // Get the duration so we know when it finishes + float flDuration = enginesound->GetSoundDuration( STRING( CSoundEnvelopeController::GetController().SoundGetName( m_sndCommentary ) ) ) ; + + CHudCloseCaption *pHudCloseCaption = (CHudCloseCaption *)GET_HUDELEMENT( CHudCloseCaption ); + if ( pHudCloseCaption ) + { + // This is where we play the commentary close caption (and lock the other captions out). + // Also, if close captions are off we force a caption in non-English + if ( closecaption.GetBool() || ( !closecaption.GetBool() && !english.GetBool() ) ) + { + // Clear the close caption element in preparation + pHudCloseCaption->Reset(); + + // Process the commentary caption + pHudCloseCaption->ProcessCaptionDirect( pszCommentaryFile, flDuration ); + + // Find the close caption hud element & lock it + pHudCloseCaption->Lock(); + } + } + + // Tell the HUD element + CHudCommentary *pHudCommentary = (CHudCommentary *)GET_HUDELEMENT( CHudCommentary ); + pHudCommentary->StartCommentary( this, m_iszSpeakers, m_iNodeNumber, m_iNodeNumberMax, m_flStartTime, m_flStartTime + flDuration ); +} + +#ifdef MAPBASE +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_PointCommentaryNode::StartTextCommentary( const char *pszCommentaryFile, C_BasePlayer *pPlayer ) +{ + // Get the duration so we know when it finishes + //float flDuration = enginesound->GetSoundDuration( STRING( CSoundEnvelopeController::GetController().SoundGetName( m_sndCommentary ) ) ) ; + + // TODO: Determine from text length + float flDuration = commentary_text_endtime.GetFloat(); + + // Tell the HUD element + CHudCommentary *pHudCommentary = (CHudCommentary *)GET_HUDELEMENT( CHudCommentary ); + pHudCommentary->StartTextCommentary( this, pszCommentaryFile, m_iszSpeakers, m_iNodeNumber, m_iNodeNumberMax, m_flStartTime, m_flStartTime + flDuration ); +} +#endif + //----------------------------------------------------------------------------- // Purpose: Shut down the commentary //----------------------------------------------------------------------------- @@ -374,6 +451,10 @@ CHudCommentary::CHudCommentary( const char *name ) : vgui::Panel( NULL, "HudComm m_hActiveNode = NULL; m_bShouldPaint = true; + +#ifdef MAPBASE + m_pLabel = new vgui::Label( this, "HudCommentaryTextLabel", "" ); +#endif } void CHudCommentary::ApplySchemeSettings( vgui::IScheme *pScheme ) @@ -384,6 +465,11 @@ void CHudCommentary::ApplySchemeSettings( vgui::IScheme *pScheme ) { SetBgColor( m_BGOverrideColor ); } + +#ifdef MAPBASE + m_pLabel->SetPaintBackgroundType( 2 ); + m_pLabel->SetSize( 0, GetTall() ); +#endif } //----------------------------------------------------------------------------- @@ -426,19 +512,12 @@ void CHudCommentary::Paint() int x, y, wide, tall; GetBounds( x, y, wide, tall ); - int xOffset = m_iBarX; + int xOffset = m_iBarX; int yOffset = m_iBarY; // Find our fade based on our time shown Color clr = Color( 255, 170, 0, GetAlpha() ); - // Draw the progress bar - vgui::surface()->DrawSetColor( clr ); - vgui::surface()->DrawOutlinedRect( xOffset, yOffset, xOffset+m_iBarWide, yOffset+m_iBarTall ); - vgui::surface()->DrawSetColor( clr ); - vgui::surface()->DrawFilledRect( xOffset+2, yOffset+2, xOffset+(int)(flPercentage*m_iBarWide)-2, yOffset+m_iBarTall-2 ); - - // Draw the speaker names // Get our scheme and font information vgui::HScheme scheme = vgui::scheme()->GetScheme( "ClientScheme" ); vgui::HFont hFont = vgui::scheme()->GetIScheme(scheme)->GetFont( "CommentaryDefault" ); @@ -446,6 +525,34 @@ void CHudCommentary::Paint() { hFont = vgui::scheme()->GetIScheme(scheme)->GetFont( "Default" ); } + +#ifdef MAPBASE + if (m_bTextCommentary) + { + vgui::surface()->DrawSetColor( clr ); + vgui::surface()->DrawOutlinedRect( xOffset, yOffset, xOffset + m_iBarWide, m_iTypeTextT - (yOffset + m_iBarTall) ); + + m_pLabel->SetFgColor( m_TextColor ); + m_pLabel->SetBounds( xOffset + 4, yOffset + 4, m_iBarWide - 4, m_iTypeTextT - (m_iBarTall + 4) ); + m_pLabel->SetFont( hFont ); + + // Draw the speaker names + /*vgui::surface()->DrawSetTextFont( hFont ); + vgui::surface()->DrawSetTextColor( Color( 255, 200, 100, GetAlpha() ) ); + vgui::surface()->DrawSetTextPos( xOffset+4, yOffset+4 ); + vgui::surface()->DrawPrintText( m_pszText, wcslen( m_pszText ) );*/ + } + else +#endif + { + // Draw the progress bar + vgui::surface()->DrawSetColor( clr ); + vgui::surface()->DrawOutlinedRect( xOffset, yOffset, xOffset+m_iBarWide, yOffset+m_iBarTall ); + vgui::surface()->DrawSetColor( clr ); + vgui::surface()->DrawFilledRect( xOffset+2, yOffset+2, xOffset+(int)(flPercentage*m_iBarWide)-2, yOffset+m_iBarTall-2 ); + } + + // Draw the speaker names vgui::surface()->DrawSetTextFont( hFont ); vgui::surface()->DrawSetTextColor( clr ); vgui::surface()->DrawSetTextPos( m_iSpeakersX, m_iSpeakersY ); @@ -479,8 +586,15 @@ void CHudCommentary::Paint() // Determine our text size, and move that far in from the right hand size (plus the offset) int iCountWide, iCountTall; vgui::surface()->GetTextSize( hFont, m_szCount, iCountWide, iCountTall ); + +#ifdef MAPBASE + if (m_bTextCommentary) + vgui::surface()->DrawSetTextPos( wide - m_iTypeTextCountXFR - iCountWide, m_iTypeTextCountY ); + else +#endif vgui::surface()->DrawSetTextPos( wide - m_iCountXFR - iCountWide, m_iCountY ); - vgui::surface()->DrawPrintText( m_szCount, wcslen(m_szCount) ); + + vgui::surface()->DrawPrintText( m_szCount, wcslen( m_szCount ) ); // Draw the icon vgui::surface()->DrawSetColor( Color(255,170,0,GetAlpha()) ); @@ -525,7 +639,17 @@ void CHudCommentary::StartCommentary( C_PointCommentaryNode *pNode, char *pszSpe m_flStartTime = flStartTime; m_flEndTime = flEndTime; m_bHiding = false; - g_pVGuiLocalize->ConvertANSIToUnicode( pszSpeakers, m_szSpeakers, sizeof(m_szSpeakers) ); +#ifdef MAPBASE + m_bTextCommentary = false; +#endif + g_pVGuiLocalize->ConvertANSIToUnicode( pszSpeakers, m_szSpeakers, sizeof( m_szSpeakers ) ); + +#ifdef MAPBASE + SetBounds( m_iTypeAudioX, m_iTypeAudioY, m_iTypeAudioW, m_iTypeAudioT ); + SetBgColor( m_bUseScriptBGColor ? m_BGOverrideColor : m_BackgroundColor ); + + m_pLabel->SetPaintEnabled( false ); +#endif // Don't draw the element itself if closecaptions are on (and captions are always on in non-english mode) ConVarRef pCVar( "closecaption" ); @@ -555,6 +679,65 @@ void CHudCommentary::StartCommentary( C_PointCommentaryNode *pNode, char *pszSpe } } +#ifdef MAPBASE +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudCommentary::StartTextCommentary( C_PointCommentaryNode *pNode, const char *pszText, char *pszSpeakers, int iNode, int iNodeMax, float flStartTime, float flEndTime ) +{ + if ( (flEndTime - flStartTime) <= 0 ) + return; + + m_hActiveNode = pNode; + m_flStartTime = flStartTime; + m_flEndTime = flEndTime; + m_bHiding = false; + m_bTextCommentary = true; + g_pVGuiLocalize->ConvertANSIToUnicode( pszSpeakers, m_szSpeakers, sizeof( m_szSpeakers ) ); + + SetBounds( m_iTypeTextX, m_iTypeTextY, m_iTypeTextW, m_iTypeTextT ); + SetBgColor( m_bUseScriptBGColor ? m_BGOverrideColor : m_TextBackgroundColor ); + + m_pLabel->SetText( pszText ); + m_pLabel->SetWrap( true ); + m_pLabel->SetPaintEnabled( true ); + m_pLabel->SetPaintBackgroundEnabled( false ); + m_pLabel->SetPaintBorderEnabled( false ); + //m_pLabel->SizeToContents(); + m_pLabel->SetContentAlignment( vgui::Label::a_northwest ); + + /* + // Find a localization token first. + // If one isn't found, use this static buffer. + static wchar_t szRawTextBuf[512]; + m_pszText = g_pVGuiLocalize->Find( pszText ); + if (!m_pszText) + { + g_pVGuiLocalize->ConvertANSIToUnicode( pszText, szRawTextBuf, sizeof( szRawTextBuf ) ); + m_pszText = szRawTextBuf; + } + */ + + m_bShouldPaint = true; + SetPaintBackgroundEnabled( m_bShouldPaint ); + + char sz[MAX_COUNT_STRING]; + Q_snprintf( sz, sizeof(sz), "%d \\ %d", iNode, iNodeMax ); + g_pVGuiLocalize->ConvertANSIToUnicode( sz, m_szCount, sizeof(m_szCount) ); + + // If the commentary just started, play the commentary fade in. + if ( fabs(flStartTime - gpGlobals->curtime) < 1.0 ) + { + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "ShowCommentary" ); + } + else + { + // We're reloading a savegame that has an active commentary going in it. Don't fade in. + SetAlpha( 255 ); + } +} +#endif + //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- diff --git a/sp/src/game/server/CommentarySystem.cpp b/sp/src/game/server/CommentarySystem.cpp index 4d010151..23a8a5b8 100644 --- a/sp/src/game/server/CommentarySystem.cpp +++ b/sp/src/game/server/CommentarySystem.cpp @@ -138,6 +138,10 @@ private: CNetworkVar( string_t, m_iszSpeakers ); CNetworkVar( int, m_iNodeNumber ); CNetworkVar( int, m_iNodeNumberMax ); + +#ifdef MAPBASE + CNetworkVar( bool, m_bTextCommentary ); +#endif }; BEGIN_DATADESC( CPointCommentaryNode ) @@ -166,6 +170,9 @@ BEGIN_DATADESC( CPointCommentaryNode ) DEFINE_FIELD( m_bPreventChangesWhileMoving, FIELD_BOOLEAN ), DEFINE_KEYFIELD( m_bDisabled, FIELD_BOOLEAN, "start_disabled" ), DEFINE_KEYFIELD( m_vecTeleportOrigin, FIELD_VECTOR, "teleport_origin" ), +#ifdef MAPBASE + DEFINE_KEYFIELD( m_bTextCommentary, FIELD_BOOLEAN, "type" ), // Open to additional types in the future +#endif // Outputs DEFINE_OUTPUT( m_pOnCommentaryStarted, "OnCommentaryStarted" ), @@ -192,6 +199,9 @@ IMPLEMENT_SERVERCLASS_ST( CPointCommentaryNode, DT_PointCommentaryNode ) SendPropInt( SENDINFO(m_iNodeNumber), 8, SPROP_UNSIGNED ), SendPropInt( SENDINFO(m_iNodeNumberMax), 8, SPROP_UNSIGNED ), SendPropEHandle( SENDINFO(m_hViewPosition) ), +#ifdef MAPBASE + SendPropBool( SENDINFO( m_bTextCommentary ) ), +#endif END_SEND_TABLE() LINK_ENTITY_TO_CLASS( point_commentary_node, CPointCommentaryNode ); From f67a1b95e53b84a477adeee0457d37a68ea18676 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sat, 17 Jul 2021 03:58:09 -0500 Subject: [PATCH 106/378] Updated text commentary nodes --- .../game/client/c_point_commentary_node.cpp | 44 +++++++++++-------- sp/src/game/server/CommentarySystem.cpp | 5 +++ 2 files changed, 31 insertions(+), 18 deletions(-) diff --git a/sp/src/game/client/c_point_commentary_node.cpp b/sp/src/game/client/c_point_commentary_node.cpp index a24973a8..b59cf253 100644 --- a/sp/src/game/client/c_point_commentary_node.cpp +++ b/sp/src/game/client/c_point_commentary_node.cpp @@ -110,7 +110,7 @@ private: CPanelAnimationVarAliasType( int, m_iTypeTextW, "type_text_wide", "400", "proportional_int" ); CPanelAnimationVarAliasType( int, m_iTypeTextT, "type_text_tall", "200", "proportional_int" ); CPanelAnimationVarAliasType( int, m_iTypeTextCountXFR, "type_text_count_xpos_from_right", "10", "proportional_int" ); - CPanelAnimationVarAliasType( int, m_iTypeTextCountY, "type_text_count_ypos", "184", "proportional_int" ); + CPanelAnimationVarAliasType( int, m_iTypeTextCountYFB, "type_text_count_ypos_from_bottom", "16", "proportional_int" ); CPanelAnimationVar( Color, m_TextBackgroundColor, "type_text_bg", "0 0 0 192" ); CPanelAnimationVar( Color, m_TextColor, "type_text_fg", "255 230 180 255" ); #endif @@ -380,7 +380,7 @@ void C_PointCommentaryNode::StartTextCommentary( const char *pszCommentaryFile, // Get the duration so we know when it finishes //float flDuration = enginesound->GetSoundDuration( STRING( CSoundEnvelopeController::GetController().SoundGetName( m_sndCommentary ) ) ) ; - // TODO: Determine from text length + // TODO: Determine from text length? float flDuration = commentary_text_endtime.GetFloat(); // Tell the HUD element @@ -529,11 +529,19 @@ void CHudCommentary::Paint() #ifdef MAPBASE if (m_bTextCommentary) { - vgui::surface()->DrawSetColor( clr ); - vgui::surface()->DrawOutlinedRect( xOffset, yOffset, xOffset + m_iBarWide, m_iTypeTextT - (yOffset + m_iBarTall) ); + // TODO: Make this a control? + static int iTextBorderSpace = 8; + + // Figure out the size before setting bounds + int lW, lT; + m_pLabel->GetContentSize( lW, lT ); m_pLabel->SetFgColor( m_TextColor ); - m_pLabel->SetBounds( xOffset + 4, yOffset + 4, m_iBarWide - 4, m_iTypeTextT - (m_iBarTall + 4) ); + m_pLabel->SetBounds( + xOffset + iTextBorderSpace, + yOffset + iTextBorderSpace, + m_iBarWide - iTextBorderSpace, + lT /*m_iTypeTextT - ((yOffset * 2) + iTextBorderSpace)*/ ); m_pLabel->SetFont( hFont ); // Draw the speaker names @@ -541,6 +549,14 @@ void CHudCommentary::Paint() vgui::surface()->DrawSetTextColor( Color( 255, 200, 100, GetAlpha() ) ); vgui::surface()->DrawSetTextPos( xOffset+4, yOffset+4 ); vgui::surface()->DrawPrintText( m_pszText, wcslen( m_pszText ) );*/ + + lT += (iTextBorderSpace * 2); + + vgui::surface()->DrawSetColor( clr ); + vgui::surface()->DrawOutlinedRect( xOffset, yOffset, xOffset + m_iBarWide, yOffset + lT ); //m_iTypeTextT - (yOffset /*+ m_iBarTall*/) ); + + lT += (yOffset * 2); + SetBounds( x, ( (float)m_iTypeTextT * MAX( (200.0f / (float)lT), 1.75f ) ), wide, lT ); } else #endif @@ -589,7 +605,7 @@ void CHudCommentary::Paint() #ifdef MAPBASE if (m_bTextCommentary) - vgui::surface()->DrawSetTextPos( wide - m_iTypeTextCountXFR - iCountWide, m_iTypeTextCountY ); + vgui::surface()->DrawSetTextPos( wide - m_iTypeTextCountXFR - iCountWide, tall - m_iTypeTextCountYFB - iCountTall ); else #endif vgui::surface()->DrawSetTextPos( wide - m_iCountXFR - iCountWide, m_iCountY ); @@ -616,6 +632,10 @@ bool CHudCommentary::ShouldDraw() void CHudCommentary::Init( void ) { m_matIcon.Init( "vgui/hud/icon_commentary", TEXTURE_GROUP_VGUI ); + +#ifdef MAPBASE + SetProportional( true ); +#endif } //----------------------------------------------------------------------------- @@ -706,18 +726,6 @@ void CHudCommentary::StartTextCommentary( C_PointCommentaryNode *pNode, const ch //m_pLabel->SizeToContents(); m_pLabel->SetContentAlignment( vgui::Label::a_northwest ); - /* - // Find a localization token first. - // If one isn't found, use this static buffer. - static wchar_t szRawTextBuf[512]; - m_pszText = g_pVGuiLocalize->Find( pszText ); - if (!m_pszText) - { - g_pVGuiLocalize->ConvertANSIToUnicode( pszText, szRawTextBuf, sizeof( szRawTextBuf ) ); - m_pszText = szRawTextBuf; - } - */ - m_bShouldPaint = true; SetPaintBackgroundEnabled( m_bShouldPaint ); diff --git a/sp/src/game/server/CommentarySystem.cpp b/sp/src/game/server/CommentarySystem.cpp index 23a8a5b8..6c435d3f 100644 --- a/sp/src/game/server/CommentarySystem.cpp +++ b/sp/src/game/server/CommentarySystem.cpp @@ -905,6 +905,11 @@ void CPointCommentaryNode::Spawn( void ) char *szModel = (char *)STRING( GetModelName() ); if (!szModel || !*szModel) { +#ifdef MAPBASE + if (m_bTextCommentary) + szModel = "models/extras/info_text.mdl"; + else +#endif szModel = "models/extras/info_speech.mdl"; SetModelName( AllocPooledString(szModel) ); } From 3ab83ba1c2bf98e610ea1bf77bf2fa6a7cd54144 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sun, 18 Jul 2021 01:27:33 -0500 Subject: [PATCH 107/378] Added image commentary nodes and better scaling/positioning for the text commentary panel --- .../game/client/c_point_commentary_node.cpp | 377 +++++++++++++++--- sp/src/game/server/CommentarySystem.cpp | 45 ++- sp/src/game/shared/shareddefs.h | 11 + 3 files changed, 366 insertions(+), 67 deletions(-) diff --git a/sp/src/game/client/c_point_commentary_node.cpp b/sp/src/game/client/c_point_commentary_node.cpp index b59cf253..bfef3c0a 100644 --- a/sp/src/game/client/c_point_commentary_node.cpp +++ b/sp/src/game/client/c_point_commentary_node.cpp @@ -20,6 +20,7 @@ #include "in_buttons.h" #ifdef MAPBASE #include "vgui_controls/Label.h" +#include "vgui_controls/ImagePanel.h" #endif // memdbgon must be the last include file in a .cpp file!!! @@ -41,8 +42,9 @@ bool IsInCommentaryMode( void ) static bool g_bTracingVsCommentaryNodes = false; #ifdef MAPBASE -ConVar commentary_text_force( "commentary_text_force", "0", FCVAR_NONE, "Forces all commentary nodes to use the text type." ); -ConVar commentary_text_endtime( "commentary_text_endtime", "120" ); +ConVar commentary_type_force( "commentary_type_force", "-1", FCVAR_NONE, "Forces all commentary nodes to use the specified type." ); +ConVar commentary_type_text_endtime( "commentary_type_text_endtime", "120" ); +ConVar commentary_type_image_endtime( "commentary_type_image_endtime", "120" ); #endif //----------------------------------------------------------------------------- @@ -62,6 +64,7 @@ public: void StartCommentary( C_PointCommentaryNode *pNode, char *pszSpeakers, int iNode, int iNodeMax, float flStartTime, float flEndTime ); #ifdef MAPBASE void StartTextCommentary( C_PointCommentaryNode *pNode, const char *pszText, char *pszSpeakers, int iNode, int iNodeMax, float flStartTime, float flEndTime ); + void StartImageCommentary( C_PointCommentaryNode *pNode, const char *pszImage, char *pszSpeakers, int iNode, int iNodeMax, float flStartTime, float flEndTime ); #endif void StopCommentary( void ); bool IsTheActiveNode( C_PointCommentaryNode *pNode ) { return (pNode == m_hActiveNode); } @@ -69,6 +72,10 @@ public: // vgui overrides virtual void Paint( void ); virtual bool ShouldDraw( void ); +#ifdef MAPBASE + virtual void PerformLayout(); + void ResolveBounds( int width, int height ); +#endif private: CHandle m_hActiveNode; @@ -80,9 +87,14 @@ private: CMaterialReference m_matIcon; bool m_bHiding; #ifdef MAPBASE - bool m_bTextCommentary; // NOTE: If any more types are needed, use an enum - wchar_t *m_pszText; + int m_iCommentaryType; + float m_flPanelScale; + float m_flOverrideX; + float m_flOverrideY; + vgui::Label *m_pLabel; + vgui::ImagePanel *m_pImage; + vgui::HFont m_hFont; #endif // Painting @@ -110,14 +122,16 @@ private: CPanelAnimationVarAliasType( int, m_iTypeTextW, "type_text_wide", "400", "proportional_int" ); CPanelAnimationVarAliasType( int, m_iTypeTextT, "type_text_tall", "200", "proportional_int" ); CPanelAnimationVarAliasType( int, m_iTypeTextCountXFR, "type_text_count_xpos_from_right", "10", "proportional_int" ); - CPanelAnimationVarAliasType( int, m_iTypeTextCountYFB, "type_text_count_ypos_from_bottom", "16", "proportional_int" ); - CPanelAnimationVar( Color, m_TextBackgroundColor, "type_text_bg", "0 0 0 192" ); - CPanelAnimationVar( Color, m_TextColor, "type_text_fg", "255 230 180 255" ); + CPanelAnimationVarAliasType( int, m_iTypeTextCountYFB, "type_text_count_ypos_from_bottom", "10", "proportional_int" ); + CPanelAnimationVar( Color, m_TextBackgroundColor, "BackgroundColorTextContent", "0 0 0 192" ); + CPanelAnimationVar( Color, m_TypeTextContentColor, "TextContentColor", "255 230 180 255" ); + CPanelAnimationVar( int, m_iTextBorderSpace, "type_text_border_space", "8" ); #endif CPanelAnimationVar( bool, m_bUseScriptBGColor, "use_script_bgcolor", "0" ); #ifdef MAPBASE CPanelAnimationVar( Color, m_BackgroundColor, "BackgroundColor", "Panel.BgColor" ); + CPanelAnimationVar( Color, m_ForegroundColor, "ForegroundColor", "255 170 0 255" ); #else CPanelAnimationVar( Color, m_BackgroundColor, "BackgroundColor", "0 0 0 0" ); #endif @@ -140,6 +154,7 @@ public: void StartAudioCommentary( const char *pszCommentaryFile, C_BasePlayer *pPlayer ); #ifdef MAPBASE void StartTextCommentary( const char *pszCommentaryFile, C_BasePlayer *pPlayer ); + void StartImageCommentary( const char *pszCommentaryFile, C_BasePlayer *pPlayer ); #endif void OnRestore( void ) @@ -222,7 +237,10 @@ public: EHANDLE m_hViewPosition; bool m_bRestartAfterRestore; #ifdef MAPBASE - bool m_bTextCommentary; + int m_iCommentaryType; + float m_flPanelScale; + float m_flPanelX; + float m_flPanelY; #endif }; @@ -236,7 +254,10 @@ IMPLEMENT_CLIENTCLASS_DT(C_PointCommentaryNode, DT_PointCommentaryNode, CPointCo RecvPropInt( RECVINFO( m_iNodeNumberMax ) ), RecvPropEHandle( RECVINFO(m_hViewPosition) ), #ifdef MAPBASE - RecvPropBool( RECVINFO( m_bTextCommentary ) ), + RecvPropInt( RECVINFO( m_iCommentaryType ) ), + RecvPropFloat( RECVINFO( m_flPanelScale ) ), + RecvPropFloat( RECVINFO( m_flPanelX ) ), + RecvPropFloat( RECVINFO( m_flPanelY ) ), #endif END_RECV_TABLE() @@ -292,11 +313,28 @@ void C_PointCommentaryNode::OnDataChanged( DataUpdateType_t updateType ) } #ifdef MAPBASE - if (m_bTextCommentary || commentary_text_force.GetBool()) - StartTextCommentary( pszCommentaryFile, pPlayer ); - else + int iCommentaryType = m_iCommentaryType; + if (commentary_type_force.GetInt() != -1) + iCommentaryType = commentary_type_force.GetInt(); + + switch (iCommentaryType) + { + case COMMENTARY_TYPE_TEXT: + StartTextCommentary( pszCommentaryFile, pPlayer ); + break; + + case COMMENTARY_TYPE_IMAGE: + StartImageCommentary( pszCommentaryFile, pPlayer ); + break; + + default: + case COMMENTARY_TYPE_AUDIO: + StartAudioCommentary( pszCommentaryFile, pPlayer ); + break; + } +#else + StartAudioCommentary( pszCommentaryFile, pPlayer ); #endif - StartAudioCommentary( pszCommentaryFile, pPlayer ); } else if ( m_bWasActive ) { @@ -381,12 +419,27 @@ void C_PointCommentaryNode::StartTextCommentary( const char *pszCommentaryFile, //float flDuration = enginesound->GetSoundDuration( STRING( CSoundEnvelopeController::GetController().SoundGetName( m_sndCommentary ) ) ) ; // TODO: Determine from text length? - float flDuration = commentary_text_endtime.GetFloat(); + float flDuration = commentary_type_text_endtime.GetFloat(); // Tell the HUD element CHudCommentary *pHudCommentary = (CHudCommentary *)GET_HUDELEMENT( CHudCommentary ); pHudCommentary->StartTextCommentary( this, pszCommentaryFile, m_iszSpeakers, m_iNodeNumber, m_iNodeNumberMax, m_flStartTime, m_flStartTime + flDuration ); } + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_PointCommentaryNode::StartImageCommentary( const char *pszCommentaryFile, C_BasePlayer *pPlayer ) +{ + // Get the duration so we know when it finishes + //float flDuration = enginesound->GetSoundDuration( STRING( CSoundEnvelopeController::GetController().SoundGetName( m_sndCommentary ) ) ) ; + + float flDuration = commentary_type_image_endtime.GetFloat(); + + // Tell the HUD element + CHudCommentary *pHudCommentary = (CHudCommentary *)GET_HUDELEMENT( CHudCommentary ); + pHudCommentary->StartImageCommentary( this, pszCommentaryFile, m_iszSpeakers, m_iNodeNumber, m_iNodeNumberMax, m_flStartTime, m_flStartTime + flDuration ); +} #endif //----------------------------------------------------------------------------- @@ -454,6 +507,8 @@ CHudCommentary::CHudCommentary( const char *name ) : vgui::Panel( NULL, "HudComm #ifdef MAPBASE m_pLabel = new vgui::Label( this, "HudCommentaryTextLabel", "" ); + m_pImage = new vgui::ImagePanel( this, "HudCommentaryImagePanel" ); + m_pImage->SetShouldScaleImage( true ); #endif } @@ -516,60 +571,57 @@ void CHudCommentary::Paint() int yOffset = m_iBarY; // Find our fade based on our time shown - Color clr = Color( 255, 170, 0, GetAlpha() ); - - // Get our scheme and font information - vgui::HScheme scheme = vgui::scheme()->GetScheme( "ClientScheme" ); - vgui::HFont hFont = vgui::scheme()->GetIScheme(scheme)->GetFont( "CommentaryDefault" ); - if ( !hFont ) - { - hFont = vgui::scheme()->GetIScheme(scheme)->GetFont( "Default" ); - } + Color clr = m_ForegroundColor; #ifdef MAPBASE - if (m_bTextCommentary) + switch (m_iCommentaryType) { - // TODO: Make this a control? - static int iTextBorderSpace = 8; + case COMMENTARY_TYPE_TEXT: + { + // Figure out the size before setting bounds + int lW, lT; + m_pLabel->GetContentSize( lW, lT ); - // Figure out the size before setting bounds - int lW, lT; - m_pLabel->GetContentSize( lW, lT ); + lT += (m_iTextBorderSpace * 2); - m_pLabel->SetFgColor( m_TextColor ); - m_pLabel->SetBounds( - xOffset + iTextBorderSpace, - yOffset + iTextBorderSpace, - m_iBarWide - iTextBorderSpace, - lT /*m_iTypeTextT - ((yOffset * 2) + iTextBorderSpace)*/ ); - m_pLabel->SetFont( hFont ); + vgui::surface()->DrawSetColor( clr ); + vgui::surface()->DrawOutlinedRect( xOffset, yOffset, xOffset + (m_iBarWide * m_flPanelScale), yOffset + (lT /** m_flPanelScale*/) ); //m_iTypeTextT - (yOffset /*+ m_iBarTall*/) ); + } break; - // Draw the speaker names - /*vgui::surface()->DrawSetTextFont( hFont ); - vgui::surface()->DrawSetTextColor( Color( 255, 200, 100, GetAlpha() ) ); - vgui::surface()->DrawSetTextPos( xOffset+4, yOffset+4 ); - vgui::surface()->DrawPrintText( m_pszText, wcslen( m_pszText ) );*/ + case COMMENTARY_TYPE_IMAGE: + { + // Figure out the size before setting bounds + int iW, iT; + m_pImage->GetSize( iW, iT ); + //vgui::surface()->DrawGetTextureSize( m_pImage->GetImage()->GetID(), iW, iT ); - lT += (iTextBorderSpace * 2); + iW += (m_iTextBorderSpace * 2); + iT += (m_iTextBorderSpace * 2); - vgui::surface()->DrawSetColor( clr ); - vgui::surface()->DrawOutlinedRect( xOffset, yOffset, xOffset + m_iBarWide, yOffset + lT ); //m_iTypeTextT - (yOffset /*+ m_iBarTall*/) ); + vgui::surface()->DrawSetColor( clr ); + vgui::surface()->DrawOutlinedRect( xOffset, yOffset, xOffset + iW, yOffset + iT ); //m_iTypeTextT - (yOffset /*+ m_iBarTall*/) ); + } break; - lT += (yOffset * 2); - SetBounds( x, ( (float)m_iTypeTextT * MAX( (200.0f / (float)lT), 1.75f ) ), wide, lT ); + default: + case COMMENTARY_TYPE_AUDIO: + { + // Draw the progress bar + vgui::surface()->DrawSetColor( clr ); + vgui::surface()->DrawOutlinedRect( xOffset, yOffset, xOffset+m_iBarWide, yOffset+m_iBarTall ); + vgui::surface()->DrawSetColor( clr ); + vgui::surface()->DrawFilledRect( xOffset+2, yOffset+2, xOffset+(int)(flPercentage*m_iBarWide)-2, yOffset+m_iBarTall-2 ); + } break; } - else +#else + // Draw the progress bar + vgui::surface()->DrawSetColor( clr ); + vgui::surface()->DrawOutlinedRect( xOffset, yOffset, xOffset+m_iBarWide, yOffset+m_iBarTall ); + vgui::surface()->DrawSetColor( clr ); + vgui::surface()->DrawFilledRect( xOffset+2, yOffset+2, xOffset+(int)(flPercentage*m_iBarWide)-2, yOffset+m_iBarTall-2 ); #endif - { - // Draw the progress bar - vgui::surface()->DrawSetColor( clr ); - vgui::surface()->DrawOutlinedRect( xOffset, yOffset, xOffset+m_iBarWide, yOffset+m_iBarTall ); - vgui::surface()->DrawSetColor( clr ); - vgui::surface()->DrawFilledRect( xOffset+2, yOffset+2, xOffset+(int)(flPercentage*m_iBarWide)-2, yOffset+m_iBarTall-2 ); - } // Draw the speaker names - vgui::surface()->DrawSetTextFont( hFont ); + vgui::surface()->DrawSetTextFont( m_hFont ); vgui::surface()->DrawSetTextColor( clr ); vgui::surface()->DrawSetTextPos( m_iSpeakersX, m_iSpeakersY ); vgui::surface()->DrawPrintText( m_szSpeakers, wcslen(m_szSpeakers) ); @@ -592,7 +644,7 @@ void CHudCommentary::Paint() { int w, h; UTIL_ReplaceKeyBindings( pszText, 0, wzFinal, sizeof( wzFinal ) ); - vgui::surface()->GetTextSize( hFont, wzFinal, w, h ); + vgui::surface()->GetTextSize( m_hFont, wzFinal, w, h ); vgui::surface()->DrawSetTextPos( m_iBarX + m_iBarWide - w, iY ); vgui::surface()->DrawPrintText( wzFinal, wcslen(wzFinal) ); } @@ -601,10 +653,10 @@ void CHudCommentary::Paint() // Draw the commentary count // Determine our text size, and move that far in from the right hand size (plus the offset) int iCountWide, iCountTall; - vgui::surface()->GetTextSize( hFont, m_szCount, iCountWide, iCountTall ); + vgui::surface()->GetTextSize( m_hFont, m_szCount, iCountWide, iCountTall ); #ifdef MAPBASE - if (m_bTextCommentary) + if (m_iCommentaryType != COMMENTARY_TYPE_AUDIO) vgui::surface()->DrawSetTextPos( wide - m_iTypeTextCountXFR - iCountWide, tall - m_iTypeTextCountYFB - iCountTall ); else #endif @@ -626,6 +678,128 @@ bool CHudCommentary::ShouldDraw() return ( m_hActiveNode || GetAlpha() > 0 ); } +#ifdef MAPBASE +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudCommentary::PerformLayout() +{ + BaseClass::PerformLayout(); + + switch (m_iCommentaryType) + { + case COMMENTARY_TYPE_TEXT: + { + int xOffset = m_iBarX; + int yOffset = m_iBarY; + + int x, y, wide, tall; + GetBounds( x, y, wide, tall ); + + // Figure out the size before setting bounds + int lW, lT; + m_pLabel->GetContentSize( lW, lT ); + + lW = (float)(m_iBarWide * m_flPanelScale) - m_iTextBorderSpace; + //lT = (float)lT * m_flPanelScale; // Don't affect height when scaling + + m_pLabel->SetBounds( + xOffset + m_iTextBorderSpace, + yOffset + m_iTextBorderSpace, + lW, lT ); + + lW += (float)((m_iTextBorderSpace * 2) + (xOffset * 2)); + lT += (float)((m_iTextBorderSpace * 2) + (yOffset * 2)); + + ResolveBounds( lW, lT ); + } break; + + case COMMENTARY_TYPE_IMAGE: + { + int xOffset = m_iBarX; + int yOffset = m_iBarY; + + // Figure out the size before setting bounds + int iW, iT; + //m_pImage->GetImage()->GetSize( iW, iT ); + vgui::surface()->DrawGetTextureSize( m_pImage->GetImage()->GetID(), iW, iT ); + if (iW <= 0) + iW = 1; + + int iTargetSize = (m_iBarWide - m_iTextBorderSpace); + iT *= (iTargetSize / iW); + iW = iTargetSize; + + iW = (float)iW * m_flPanelScale; + iT = (float)iT * m_flPanelScale; + + m_pImage->SetBounds( + xOffset + m_iTextBorderSpace, + yOffset + m_iTextBorderSpace, + iW, iT ); + + iW += (float)((m_iTextBorderSpace * 2) + (xOffset * 2)); + iT += (float)((m_iTextBorderSpace * 2) + (yOffset * 2)); + + ResolveBounds( iW, iT ); + } break; + + default: + case COMMENTARY_TYPE_AUDIO: + break; + } +} + +//----------------------------------------------------------------------------- +// Purpose: Resolves position on screen; Heavily borrows from CHudMessage::XPosition/YPosition +//----------------------------------------------------------------------------- +void CHudCommentary::ResolveBounds( int width, int height ) +{ + int xPos; + int yPos; + + // ====== X ====== + if ( m_flOverrideX == -1 ) + { + xPos = (ScreenWidth() - width) * 0.5f; + } + else + { + if ( m_flOverrideX < 0 ) + xPos = (1.0 + m_flOverrideX) * ScreenWidth() - width; // Align to right + else + xPos = m_flOverrideX * (ScreenWidth() - width); + } + + // Clamp to edge of screen + if ( xPos + width > ScreenWidth() ) + xPos = ScreenWidth() - width; + else if ( xPos < 0 ) + xPos = 0; + + // ====== Y ====== + if ( m_flOverrideY == -1 ) + { + yPos = (ScreenHeight() - height) * 0.5f; + } + else + { + if ( m_flOverrideY < 0 ) + yPos = (1.0 + m_flOverrideY) * ScreenHeight() - height; // Align to bottom + else + yPos = m_flOverrideY * (ScreenHeight() - height); + } + + // Clamp to edge of screen + if ( yPos + height > ScreenHeight() ) + yPos = ScreenHeight() - height; + else if ( yPos < 0 ) + yPos = 0; + + SetBounds( xPos, yPos, width, height ); +} +#endif + //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- @@ -660,7 +834,10 @@ void CHudCommentary::StartCommentary( C_PointCommentaryNode *pNode, char *pszSpe m_flEndTime = flEndTime; m_bHiding = false; #ifdef MAPBASE - m_bTextCommentary = false; + m_iCommentaryType = COMMENTARY_TYPE_AUDIO; + m_flPanelScale = pNode->m_flPanelScale; + m_flOverrideX = pNode->m_flPanelX; + m_flOverrideY = pNode->m_flPanelY; #endif g_pVGuiLocalize->ConvertANSIToUnicode( pszSpeakers, m_szSpeakers, sizeof( m_szSpeakers ) ); @@ -669,6 +846,16 @@ void CHudCommentary::StartCommentary( C_PointCommentaryNode *pNode, char *pszSpe SetBgColor( m_bUseScriptBGColor ? m_BGOverrideColor : m_BackgroundColor ); m_pLabel->SetPaintEnabled( false ); + m_pImage->SetPaintEnabled( false ); + m_pImage->EvictImage(); + + // Get our scheme and font information + vgui::HScheme scheme = vgui::scheme()->GetScheme( "ClientScheme" ); + m_hFont = vgui::scheme()->GetIScheme(scheme)->GetFont( "CommentaryDefault" ); + if ( !m_hFont ) + { + m_hFont = vgui::scheme()->GetIScheme(scheme)->GetFont( "Default" ); + } #endif // Don't draw the element itself if closecaptions are on (and captions are always on in non-english mode) @@ -712,19 +899,89 @@ void CHudCommentary::StartTextCommentary( C_PointCommentaryNode *pNode, const ch m_flStartTime = flStartTime; m_flEndTime = flEndTime; m_bHiding = false; - m_bTextCommentary = true; + m_iCommentaryType = COMMENTARY_TYPE_TEXT; + m_flPanelScale = pNode->m_flPanelScale; + m_flOverrideX = pNode->m_flPanelX; + m_flOverrideY = pNode->m_flPanelY; g_pVGuiLocalize->ConvertANSIToUnicode( pszSpeakers, m_szSpeakers, sizeof( m_szSpeakers ) ); SetBounds( m_iTypeTextX, m_iTypeTextY, m_iTypeTextW, m_iTypeTextT ); SetBgColor( m_bUseScriptBGColor ? m_BGOverrideColor : m_TextBackgroundColor ); + // Get our scheme and font information + vgui::HScheme scheme = vgui::scheme()->GetScheme( "ClientScheme" ); + m_hFont = vgui::scheme()->GetIScheme(scheme)->GetFont( "CommentaryDefault" ); + if ( !m_hFont ) + { + m_hFont = vgui::scheme()->GetIScheme(scheme)->GetFont( "Default" ); + } + m_pLabel->SetText( pszText ); + m_pLabel->SetFont( m_hFont ); m_pLabel->SetWrap( true ); m_pLabel->SetPaintEnabled( true ); m_pLabel->SetPaintBackgroundEnabled( false ); m_pLabel->SetPaintBorderEnabled( false ); //m_pLabel->SizeToContents(); m_pLabel->SetContentAlignment( vgui::Label::a_northwest ); + m_pLabel->SetFgColor( m_TypeTextContentColor ); + + m_pImage->SetPaintEnabled( false ); + m_pImage->EvictImage(); + + m_bShouldPaint = true; + SetPaintBackgroundEnabled( m_bShouldPaint ); + + char sz[MAX_COUNT_STRING]; + Q_snprintf( sz, sizeof(sz), "%d \\ %d", iNode, iNodeMax ); + g_pVGuiLocalize->ConvertANSIToUnicode( sz, m_szCount, sizeof(m_szCount) ); + + // If the commentary just started, play the commentary fade in. + if ( fabs(flStartTime - gpGlobals->curtime) < 1.0 ) + { + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "ShowCommentary" ); + } + else + { + // We're reloading a savegame that has an active commentary going in it. Don't fade in. + SetAlpha( 255 ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudCommentary::StartImageCommentary( C_PointCommentaryNode *pNode, const char *pszImage, char *pszSpeakers, int iNode, int iNodeMax, float flStartTime, float flEndTime ) +{ + if ( (flEndTime - flStartTime) <= 0 ) + return; + + m_hActiveNode = pNode; + m_flStartTime = flStartTime; + m_flEndTime = flEndTime; + m_bHiding = false; + m_iCommentaryType = COMMENTARY_TYPE_IMAGE; + m_flPanelScale = pNode->m_flPanelScale; + m_flOverrideX = pNode->m_flPanelX; + m_flOverrideY = pNode->m_flPanelY; + g_pVGuiLocalize->ConvertANSIToUnicode( pszSpeakers, m_szSpeakers, sizeof( m_szSpeakers ) ); + + SetBounds( m_iTypeTextX, m_iTypeTextY, m_iTypeTextW, m_iTypeTextT ); + SetBgColor( m_bUseScriptBGColor ? m_BGOverrideColor : m_TextBackgroundColor ); + + m_pLabel->SetPaintEnabled( false ); + + m_pImage->SetPaintEnabled( true ); + m_pImage->SetImage( pszImage ); + m_pImage->SetWide( m_iBarWide - m_iTextBorderSpace ); + + // Get our scheme and font information + vgui::HScheme scheme = vgui::scheme()->GetScheme( "ClientScheme" ); + m_hFont = vgui::scheme()->GetIScheme(scheme)->GetFont( "CommentaryDefault" ); + if ( !m_hFont ) + { + m_hFont = vgui::scheme()->GetIScheme(scheme)->GetFont( "Default" ); + } m_bShouldPaint = true; SetPaintBackgroundEnabled( m_bShouldPaint ); diff --git a/sp/src/game/server/CommentarySystem.cpp b/sp/src/game/server/CommentarySystem.cpp index 6c435d3f..906c9daf 100644 --- a/sp/src/game/server/CommentarySystem.cpp +++ b/sp/src/game/server/CommentarySystem.cpp @@ -74,6 +74,15 @@ public: DECLARE_DATADESC(); DECLARE_SERVERCLASS(); + CPointCommentaryNode() + { +#ifdef MAPBASE + m_flPanelScale = 1.0f; + m_flPanelX = -1.0f; + m_flPanelY = -1.0f; +#endif + } + void Spawn( void ); void Precache( void ); void Activate( void ); @@ -140,7 +149,10 @@ private: CNetworkVar( int, m_iNodeNumberMax ); #ifdef MAPBASE - CNetworkVar( bool, m_bTextCommentary ); + CNetworkVar( int, m_iCommentaryType ); + CNetworkVar( float, m_flPanelScale ); + CNetworkVar( float, m_flPanelX ); + CNetworkVar( float, m_flPanelY ); #endif }; @@ -171,7 +183,10 @@ BEGIN_DATADESC( CPointCommentaryNode ) DEFINE_KEYFIELD( m_bDisabled, FIELD_BOOLEAN, "start_disabled" ), DEFINE_KEYFIELD( m_vecTeleportOrigin, FIELD_VECTOR, "teleport_origin" ), #ifdef MAPBASE - DEFINE_KEYFIELD( m_bTextCommentary, FIELD_BOOLEAN, "type" ), // Open to additional types in the future + DEFINE_KEYFIELD( m_iCommentaryType, FIELD_INTEGER, "type" ), + DEFINE_KEYFIELD( m_flPanelScale, FIELD_FLOAT, "panelscale" ), + DEFINE_KEYFIELD( m_flPanelX, FIELD_FLOAT, "x" ), + DEFINE_KEYFIELD( m_flPanelY, FIELD_FLOAT, "y" ), #endif // Outputs @@ -200,7 +215,10 @@ IMPLEMENT_SERVERCLASS_ST( CPointCommentaryNode, DT_PointCommentaryNode ) SendPropInt( SENDINFO(m_iNodeNumberMax), 8, SPROP_UNSIGNED ), SendPropEHandle( SENDINFO(m_hViewPosition) ), #ifdef MAPBASE - SendPropBool( SENDINFO( m_bTextCommentary ) ), + SendPropInt( SENDINFO( m_iCommentaryType ), 2, SPROP_UNSIGNED ), + SendPropFloat( SENDINFO( m_flPanelScale ) ), + SendPropFloat( SENDINFO( m_flPanelX ) ), + SendPropFloat( SENDINFO( m_flPanelY ) ), #endif END_SEND_TABLE() @@ -906,11 +924,24 @@ void CPointCommentaryNode::Spawn( void ) if (!szModel || !*szModel) { #ifdef MAPBASE - if (m_bTextCommentary) - szModel = "models/extras/info_text.mdl"; - else -#endif + switch (m_iCommentaryType) + { + case COMMENTARY_TYPE_TEXT: + szModel = "models/extras/info_text.mdl"; + break; + + case COMMENTARY_TYPE_IMAGE: + szModel = "models/extras/info_image.mdl"; // TODO + break; + + default: + case COMMENTARY_TYPE_AUDIO: + szModel = "models/extras/info_speech.mdl"; + break; + } +#else szModel = "models/extras/info_speech.mdl"; +#endif SetModelName( AllocPooledString(szModel) ); } diff --git a/sp/src/game/shared/shareddefs.h b/sp/src/game/shared/shareddefs.h index d30843dc..0ddb6e1d 100644 --- a/sp/src/game/shared/shareddefs.h +++ b/sp/src/game/shared/shareddefs.h @@ -1048,4 +1048,15 @@ enum }; #endif // TF_DLL || TF_CLIENT_DLL +#ifdef MAPBASE +// Developer commentary types +enum +{ + COMMENTARY_TYPE_AUDIO, // Play commentary audio (default) + + COMMENTARY_TYPE_TEXT, // Display text data + COMMENTARY_TYPE_IMAGE, // Display an image +}; +#endif + #endif // SHAREDDEFS_H From 2f4ea05c8ae0cb277e948ff91a4d7906edadfde2 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sat, 24 Jul 2021 00:36:05 -0500 Subject: [PATCH 108/378] Added view target/position scales for commentary nodes --- sp/src/game/server/CommentarySystem.cpp | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/sp/src/game/server/CommentarySystem.cpp b/sp/src/game/server/CommentarySystem.cpp index 906c9daf..ba5aaba8 100644 --- a/sp/src/game/server/CommentarySystem.cpp +++ b/sp/src/game/server/CommentarySystem.cpp @@ -77,6 +77,8 @@ public: CPointCommentaryNode() { #ifdef MAPBASE + m_flViewTargetSpeedScale = 1.0f; + m_flViewPositionSpeedScale = 1.0f; m_flPanelScale = 1.0f; m_flPanelX = -1.0f; m_flPanelY = -1.0f; @@ -128,6 +130,10 @@ private: string_t m_iszViewPosition; CNetworkVar( EHANDLE, m_hViewPosition ); EHANDLE m_hViewPositionMover; // Entity used to blend the view to the viewposition entity +#ifdef MAPBASE + float m_flViewTargetSpeedScale; + float m_flViewPositionSpeedScale; +#endif bool m_bPreventMovement; bool m_bUnderCrosshair; bool m_bUnstoppable; @@ -183,6 +189,8 @@ BEGIN_DATADESC( CPointCommentaryNode ) DEFINE_KEYFIELD( m_bDisabled, FIELD_BOOLEAN, "start_disabled" ), DEFINE_KEYFIELD( m_vecTeleportOrigin, FIELD_VECTOR, "teleport_origin" ), #ifdef MAPBASE + DEFINE_KEYFIELD( m_flViewTargetSpeedScale, FIELD_FLOAT, "viewtarget_speed" ), + DEFINE_KEYFIELD( m_flViewPositionSpeedScale, FIELD_FLOAT, "viewposition_speed" ), DEFINE_KEYFIELD( m_iCommentaryType, FIELD_INTEGER, "type" ), DEFINE_KEYFIELD( m_flPanelScale, FIELD_FLOAT, "panelscale" ), DEFINE_KEYFIELD( m_flPanelX, FIELD_FLOAT, "x" ), @@ -1260,6 +1268,10 @@ void CPointCommentaryNode::UpdateViewThink( void ) float dx = AngleDiff( angGoal.x, angCurrent.x ); float dy = AngleDiff( angGoal.y, angCurrent.y ); float mod = 1.0 - ExponentialDecay( 0.5, 0.3, gpGlobals->frametime ); +#ifdef MAPBASE + if (m_flViewTargetSpeedScale != 1.0f) + mod *= m_flViewTargetSpeedScale; +#endif float dxmod = dx * mod; float dymod = dy * mod; @@ -1300,7 +1312,11 @@ void CPointCommentaryNode::UpdateViewThink( void ) } // Blend to the target position over time. - float flCurTime = (gpGlobals->curtime - m_flStartTime); + float flCurTime = (gpGlobals->curtime - m_flStartTime); +#ifdef MAPBASE + if (m_flViewPositionSpeedScale != 1.0f) + flCurTime *= m_flViewPositionSpeedScale; +#endif float flBlendPerc = clamp( flCurTime * 0.5f, 0.f, 1.f ); // Figure out the current view position @@ -1325,6 +1341,10 @@ void CPointCommentaryNode::UpdateViewPostThink( void ) { // Blend back to the player's position over time. float flCurTime = (gpGlobals->curtime - m_flFinishedTime); +#ifdef MAPBASE + if (m_flViewPositionSpeedScale != 1.0f) + flCurTime *= m_flViewPositionSpeedScale; +#endif float flTimeToBlend = MIN( 2.0, m_flFinishedTime - m_flStartTime ); float flBlendPerc = 1.0f - clamp( flCurTime / flTimeToBlend, 0.f, 1.f ); From eae3881a03e1558de64f39fcb62a60fac613c5f7 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sat, 24 Jul 2021 00:37:01 -0500 Subject: [PATCH 109/378] Made viewmodel_fov a non-cheat by default --- sp/src/game/client/view.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sp/src/game/client/view.cpp b/sp/src/game/client/view.cpp index c78c76fd..17988d18 100644 --- a/sp/src/game/client/view.cpp +++ b/sp/src/game/client/view.cpp @@ -107,7 +107,7 @@ extern ConVar cl_forwardspeed; static ConVar v_centermove( "v_centermove", "0.15"); static ConVar v_centerspeed( "v_centerspeed","500" ); -#ifdef TF_CLIENT_DLL +#if defined(TF_CLIENT_DLL) || defined(MAPBASE) // 54 degrees approximates a 35mm camera - we determined that this makes the viewmodels // and motions look the most natural. ConVar v_viewmodel_fov( "viewmodel_fov", "54", FCVAR_ARCHIVE ); From d9accd2d7aa9d3f6b6314b56452dd29dafb3643f Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sat, 24 Jul 2021 00:37:22 -0500 Subject: [PATCH 110/378] Fixed a compile error in sceneentity.cpp --- sp/src/game/server/sceneentity.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sp/src/game/server/sceneentity.cpp b/sp/src/game/server/sceneentity.cpp index 5cef9cc0..ce2a1bc6 100644 --- a/sp/src/game/server/sceneentity.cpp +++ b/sp/src/game/server/sceneentity.cpp @@ -4284,7 +4284,7 @@ CBaseEntity *CSceneEntity::FindNamedEntity( const char *name, CBaseEntity *pActo #ifdef MAPBASE const char *GetFirstSoundInScene(const char *pszScene) { - const char *soundName; + const char *soundName = NULL; SceneCachedData_t sceneData; if ( scenefilecache->GetSceneCachedData( pszScene, &sceneData ) ) { From 495731152387de3730d760bcb9e02a723a9f5348 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sat, 24 Jul 2021 00:39:36 -0500 Subject: [PATCH 111/378] Added Alyx gun readiness activities to weapon_pistol/weapon_357 and default walk/run activities to weapon_alyxgun --- sp/src/game/server/hl2/weapon_357.cpp | 48 ++++++++++++++++++++++ sp/src/game/server/hl2/weapon_alyxgun.cpp | 5 +++ sp/src/game/server/hl2/weapon_pistol.cpp | 50 +++++++++++++++++++++++ 3 files changed, 103 insertions(+) diff --git a/sp/src/game/server/hl2/weapon_357.cpp b/sp/src/game/server/hl2/weapon_357.cpp index 3fa3fab8..59237c84 100644 --- a/sp/src/game/server/hl2/weapon_357.cpp +++ b/sp/src/game/server/hl2/weapon_357.cpp @@ -105,6 +105,54 @@ acttable_t CWeapon357::m_acttable[] = { ACT_GESTURE_RELOAD, ACT_GESTURE_RELOAD_PISTOL, false }, { ACT_WALK, ACT_WALK_PISTOL, false }, { ACT_RUN, ACT_RUN_PISTOL, false }, + + // + // Activities ported from weapon_alyxgun below + // + + // Readiness activities (not aiming) + { ACT_IDLE_RELAXED, ACT_IDLE_PISTOL, false },//never aims + { ACT_IDLE_STIMULATED, ACT_IDLE_STIMULATED, false }, + { ACT_IDLE_AGITATED, ACT_IDLE_ANGRY_PISTOL, false },//always aims + { ACT_IDLE_STEALTH, ACT_IDLE_STEALTH_PISTOL, false }, + + { ACT_WALK_RELAXED, ACT_WALK, false },//never aims + { ACT_WALK_STIMULATED, ACT_WALK_STIMULATED, false }, + { ACT_WALK_AGITATED, ACT_WALK_AIM_PISTOL, false },//always aims + { ACT_WALK_STEALTH, ACT_WALK_STEALTH_PISTOL, false }, + + { ACT_RUN_RELAXED, ACT_RUN, false },//never aims + { ACT_RUN_STIMULATED, ACT_RUN_STIMULATED, false }, + { ACT_RUN_AGITATED, ACT_RUN_AIM_PISTOL, false },//always aims + { ACT_RUN_STEALTH, ACT_RUN_STEALTH_PISTOL, false }, + + // Readiness activities (aiming) + { ACT_IDLE_AIM_RELAXED, ACT_IDLE_PISTOL, false },//never aims + { ACT_IDLE_AIM_STIMULATED, ACT_IDLE_ANGRY_PISTOL, false }, + { ACT_IDLE_AIM_AGITATED, ACT_IDLE_ANGRY_PISTOL, false },//always aims + { ACT_IDLE_AIM_STEALTH, ACT_IDLE_STEALTH_PISTOL, false }, + + { ACT_WALK_AIM_RELAXED, ACT_WALK, false },//never aims + { ACT_WALK_AIM_STIMULATED, ACT_WALK_AIM_PISTOL, false }, + { ACT_WALK_AIM_AGITATED, ACT_WALK_AIM_PISTOL, false },//always aims + { ACT_WALK_AIM_STEALTH, ACT_WALK_AIM_STEALTH_PISTOL, false },//always aims + + { ACT_RUN_AIM_RELAXED, ACT_RUN, false },//never aims + { ACT_RUN_AIM_STIMULATED, ACT_RUN_AIM_PISTOL, false }, + { ACT_RUN_AIM_AGITATED, ACT_RUN_AIM_PISTOL, false },//always aims + { ACT_RUN_AIM_STEALTH, ACT_RUN_AIM_STEALTH_PISTOL, false },//always aims + //End readiness activities + + // Crouch activities + { ACT_CROUCHIDLE_STIMULATED, ACT_CROUCHIDLE_STIMULATED, false }, + { ACT_CROUCHIDLE_AIM_STIMULATED,ACT_RANGE_AIM_PISTOL_LOW, false },//always aims + { ACT_CROUCHIDLE_AGITATED, ACT_RANGE_AIM_PISTOL_LOW, false },//always aims + + // Readiness translations + { ACT_READINESS_RELAXED_TO_STIMULATED, ACT_READINESS_PISTOL_RELAXED_TO_STIMULATED, false }, + { ACT_READINESS_RELAXED_TO_STIMULATED_WALK, ACT_READINESS_PISTOL_RELAXED_TO_STIMULATED_WALK, false }, + { ACT_READINESS_AGITATED_TO_STIMULATED, ACT_READINESS_PISTOL_AGITATED_TO_STIMULATED, false }, + { ACT_READINESS_STIMULATED_TO_RELAXED, ACT_READINESS_PISTOL_STIMULATED_TO_RELAXED, false }, }; diff --git a/sp/src/game/server/hl2/weapon_alyxgun.cpp b/sp/src/game/server/hl2/weapon_alyxgun.cpp index 270a503c..9c093be6 100644 --- a/sp/src/game/server/hl2/weapon_alyxgun.cpp +++ b/sp/src/game/server/hl2/weapon_alyxgun.cpp @@ -37,6 +37,11 @@ acttable_t CWeaponAlyxGun::m_acttable[] = { ACT_RELOAD_LOW, ACT_RELOAD_PISTOL_LOW, true }, { ACT_RANGE_ATTACK1_LOW, ACT_RANGE_ATTACK_PISTOL_LOW, true }, { ACT_GESTURE_RELOAD, ACT_GESTURE_RELOAD_PISTOL, true }, +#ifdef MAPBASE + // For non-Alyx NPCs + { ACT_WALK, ACT_WALK_PISTOL, false }, + { ACT_RUN, ACT_RUN_PISTOL, false }, +#endif // Readiness activities (not aiming) { ACT_IDLE_RELAXED, ACT_IDLE_PISTOL, false },//never aims diff --git a/sp/src/game/server/hl2/weapon_pistol.cpp b/sp/src/game/server/hl2/weapon_pistol.cpp index 80bb5090..9a571bf5 100644 --- a/sp/src/game/server/hl2/weapon_pistol.cpp +++ b/sp/src/game/server/hl2/weapon_pistol.cpp @@ -149,6 +149,56 @@ acttable_t CWeaponPistol::m_acttable[] = { ACT_GESTURE_RELOAD, ACT_GESTURE_RELOAD_PISTOL, false }, { ACT_WALK, ACT_WALK_PISTOL, false }, { ACT_RUN, ACT_RUN_PISTOL, false }, + +#ifdef MAPBASE + // + // Activities ported from weapon_alyxgun below + // + + // Readiness activities (not aiming) + { ACT_IDLE_RELAXED, ACT_IDLE_PISTOL, false },//never aims + { ACT_IDLE_STIMULATED, ACT_IDLE_STIMULATED, false }, + { ACT_IDLE_AGITATED, ACT_IDLE_ANGRY_PISTOL, false },//always aims + { ACT_IDLE_STEALTH, ACT_IDLE_STEALTH_PISTOL, false }, + + { ACT_WALK_RELAXED, ACT_WALK, false },//never aims + { ACT_WALK_STIMULATED, ACT_WALK_STIMULATED, false }, + { ACT_WALK_AGITATED, ACT_WALK_AIM_PISTOL, false },//always aims + { ACT_WALK_STEALTH, ACT_WALK_STEALTH_PISTOL, false }, + + { ACT_RUN_RELAXED, ACT_RUN, false },//never aims + { ACT_RUN_STIMULATED, ACT_RUN_STIMULATED, false }, + { ACT_RUN_AGITATED, ACT_RUN_AIM_PISTOL, false },//always aims + { ACT_RUN_STEALTH, ACT_RUN_STEALTH_PISTOL, false }, + + // Readiness activities (aiming) + { ACT_IDLE_AIM_RELAXED, ACT_IDLE_PISTOL, false },//never aims + { ACT_IDLE_AIM_STIMULATED, ACT_IDLE_ANGRY_PISTOL, false }, + { ACT_IDLE_AIM_AGITATED, ACT_IDLE_ANGRY_PISTOL, false },//always aims + { ACT_IDLE_AIM_STEALTH, ACT_IDLE_STEALTH_PISTOL, false }, + + { ACT_WALK_AIM_RELAXED, ACT_WALK, false },//never aims + { ACT_WALK_AIM_STIMULATED, ACT_WALK_AIM_PISTOL, false }, + { ACT_WALK_AIM_AGITATED, ACT_WALK_AIM_PISTOL, false },//always aims + { ACT_WALK_AIM_STEALTH, ACT_WALK_AIM_STEALTH_PISTOL, false },//always aims + + { ACT_RUN_AIM_RELAXED, ACT_RUN, false },//never aims + { ACT_RUN_AIM_STIMULATED, ACT_RUN_AIM_PISTOL, false }, + { ACT_RUN_AIM_AGITATED, ACT_RUN_AIM_PISTOL, false },//always aims + { ACT_RUN_AIM_STEALTH, ACT_RUN_AIM_STEALTH_PISTOL, false },//always aims + //End readiness activities + + // Crouch activities + { ACT_CROUCHIDLE_STIMULATED, ACT_CROUCHIDLE_STIMULATED, false }, + { ACT_CROUCHIDLE_AIM_STIMULATED,ACT_RANGE_AIM_PISTOL_LOW, false },//always aims + { ACT_CROUCHIDLE_AGITATED, ACT_RANGE_AIM_PISTOL_LOW, false },//always aims + + // Readiness translations + { ACT_READINESS_RELAXED_TO_STIMULATED, ACT_READINESS_PISTOL_RELAXED_TO_STIMULATED, false }, + { ACT_READINESS_RELAXED_TO_STIMULATED_WALK, ACT_READINESS_PISTOL_RELAXED_TO_STIMULATED_WALK, false }, + { ACT_READINESS_AGITATED_TO_STIMULATED, ACT_READINESS_PISTOL_AGITATED_TO_STIMULATED, false }, + { ACT_READINESS_STIMULATED_TO_RELAXED, ACT_READINESS_PISTOL_STIMULATED_TO_RELAXED, false }, +#endif }; From 3656ea3082207930f41f38c9d489c686858d32e8 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sat, 24 Jul 2021 01:52:38 -0500 Subject: [PATCH 112/378] Added map-specific closed captioning files --- sp/src/game/client/hud_closecaption.cpp | 118 ++++++++++++++++++ sp/src/game/client/hud_closecaption.h | 5 + sp/src/game/shared/mapbase/mapbase_shared.cpp | 79 ++++++------ 3 files changed, 166 insertions(+), 36 deletions(-) diff --git a/sp/src/game/client/hud_closecaption.cpp b/sp/src/game/client/hud_closecaption.cpp index 8a5ddd55..110f8b32 100644 --- a/sp/src/game/client/hud_closecaption.cpp +++ b/sp/src/game/client/hud_closecaption.cpp @@ -2630,6 +2630,124 @@ void CHudCloseCaption::InitCaptionDictionary( const char *dbfile ) g_AsyncCaptionResourceManager.SetDbInfo( m_AsyncCaptions ); } +#ifdef MAPBASE +void CHudCloseCaption::AddAdditionalCaptionDictionary( const char *dbfile, CUtlVector &outPathSymbols ) +{ + CGMsg( 1, CON_GROUP_MAPBASE_MISC, "Adding additional caption dictionary \"%s\"\n", dbfile ); + + g_AsyncCaptionResourceManager.Clear(); + + char searchPaths[4096]; + filesystem->GetSearchPath( "MOD", true, searchPaths, sizeof( searchPaths ) ); + + for ( char *path = strtok( searchPaths, ";" ); path; path = strtok( NULL, ";" ) ) + { + if ( IsX360() && ( filesystem->GetDVDMode() == DVDMODE_STRICT ) && !V_stristr( path, ".zip" ) ) + { + // only want zip paths + continue; + } + + char fullpath[MAX_PATH]; + Q_snprintf( fullpath, sizeof( fullpath ), "%s%s", path, dbfile ); + Q_FixSlashes( fullpath ); + + if ( IsX360() ) + { + char fullpath360[MAX_PATH]; + UpdateOrCreateCaptionFile( fullpath, fullpath360, sizeof( fullpath360 ) ); + Q_strncpy( fullpath, fullpath360, sizeof( fullpath ) ); + } + + // Seach for this dictionary. If it already exists, remove it. + for (int i = 0; i < m_AsyncCaptions.Count(); ++i) + { + if (FStrEq( m_AsyncCaptions[i].m_DataBaseFile.String(), fullpath )) + { + m_AsyncCaptions.Remove( i ); + break; + } + } + + FileHandle_t fh = filesystem->Open( fullpath, "rb" ); + if ( FILESYSTEM_INVALID_HANDLE != fh ) + { + MEM_ALLOC_CREDIT(); + + CUtlBuffer dirbuffer; + + AsyncCaption_t& entry = m_AsyncCaptions[ m_AsyncCaptions.AddToTail() ]; + + // Read the header + filesystem->Read( &entry.m_Header, sizeof( entry.m_Header ), fh ); + if ( entry.m_Header.magic != COMPILED_CAPTION_FILEID ) + Error( "Invalid file id for %s\n", fullpath ); + if ( entry.m_Header.version != COMPILED_CAPTION_VERSION ) + Error( "Invalid file version for %s\n", fullpath ); + if ( entry.m_Header.directorysize < 0 || entry.m_Header.directorysize > 64 * 1024 ) + Error( "Invalid directory size %d for %s\n", entry.m_Header.directorysize, fullpath ); + //if ( entry.m_Header.blocksize != MAX_BLOCK_SIZE ) + // Error( "Invalid block size %d, expecting %d for %s\n", entry.m_Header.blocksize, MAX_BLOCK_SIZE, fullpath ); + + int directoryBytes = entry.m_Header.directorysize * sizeof( CaptionLookup_t ); + entry.m_CaptionDirectory.EnsureCapacity( entry.m_Header.directorysize ); + dirbuffer.EnsureCapacity( directoryBytes ); + + filesystem->Read( dirbuffer.Base(), directoryBytes, fh ); + filesystem->Close( fh ); + + entry.m_CaptionDirectory.CopyArray( (const CaptionLookup_t *)dirbuffer.PeekGet(), entry.m_Header.directorysize ); + entry.m_CaptionDirectory.RedoSort( true ); + + entry.m_DataBaseFile = fullpath; + outPathSymbols.AddToTail( entry.m_DataBaseFile ); + } + } + + g_AsyncCaptionResourceManager.SetDbInfo( m_AsyncCaptions ); +} + +void CHudCloseCaption::AddCustomCaptionFile( char const *file, CUtlVector &outPathSymbols ) +{ + // + // 'file' should be something like "maps/mapbase_demo01_closecaption_%language%" + // + + CGMsg( 1, CON_GROUP_MAPBASE_MISC, "Adding custom caption file \"%s\"\n", file ); + + if (!IsX360()) + { + g_pVGuiLocalize->AddFile( file, "MOD", true ); + } + + char uilanguage[64]; + engine->GetUILanguage( uilanguage, sizeof( uilanguage ) ); + + char dbfile[512]; + V_StrSubst( file, "%language%", uilanguage, dbfile, sizeof( dbfile ) ); + V_SetExtension( dbfile, ".dat", sizeof( dbfile ) ); + AddAdditionalCaptionDictionary( dbfile, outPathSymbols ); +} + +void CHudCloseCaption::RemoveCaptionDictionary( const CUtlSymbol &dbFileSymbol ) +{ + // + // 'file' should be something like "maps/mapbase_demo01_closecaption_%language%" + // + + CGMsg( 1, CON_GROUP_MAPBASE_MISC, "Removing custom caption file \"%s\"\n", dbFileSymbol.String() ); + + for (int i = 0; i < m_AsyncCaptions.Count(); ++i) + { + if ( m_AsyncCaptions[i].m_DataBaseFile == dbFileSymbol ) + { + m_AsyncCaptions.Remove( i ); + break; + } + } +} +#endif + void CHudCloseCaption::OnFinishAsyncLoad( int nFileIndex, int nBlockNum, AsyncCaptionData_t *pData ) { // Fill in data for all users of pData->m_nBlockNum diff --git a/sp/src/game/client/hud_closecaption.h b/sp/src/game/client/hud_closecaption.h index 180afe9d..f89dffb3 100644 --- a/sp/src/game/client/hud_closecaption.h +++ b/sp/src/game/client/hud_closecaption.h @@ -111,6 +111,11 @@ public: void PlayRandomCaption(); void InitCaptionDictionary( char const *dbfile ); +#ifdef MAPBASE + void AddAdditionalCaptionDictionary( char const *dbfile, CUtlVector &outPathSymbols ); + void AddCustomCaptionFile( char const *file, CUtlVector &outPathSymbols ); + void RemoveCaptionDictionary( const CUtlSymbol &dbFileSymbol ); +#endif void OnFinishAsyncLoad( int nFileIndex, int nBlockNum, AsyncCaptionData_t *pData ); void Flush(); diff --git a/sp/src/game/shared/mapbase/mapbase_shared.cpp b/sp/src/game/shared/mapbase/mapbase_shared.cpp index 0f3db5b8..49d914f7 100644 --- a/sp/src/game/shared/mapbase/mapbase_shared.cpp +++ b/sp/src/game/shared/mapbase/mapbase_shared.cpp @@ -47,27 +47,12 @@ extern ISoundEmitterSystemBase *soundemitterbase; ConVar mapbase_load_default_manifest("mapbase_load_default_manifest", "1", FCVAR_ARCHIVE, "Should we automatically load our default manifest file? (\"maps/%mapname%_manifest.txt\")"); -ConVar mapbase_load_soundscripts("mapbase_load_soundscripts", "1", FCVAR_ARCHIVE, "Should we load map-specific soundscripts? e.g. \"maps/mapname_level_sounds.txt\""); - -//ConVar mapbase_load_propdata("mapbase_load_propdata", "1", FCVAR_ARCHIVE, "Should we load map-specific propdata files? e.g. \"maps/mapname_propdata.txt\""); - -//ConVar mapbase_load_soundscapes("mapbase_load_soundscapes", "1", FCVAR_ARCHIVE, "Should we load map-specific soundscapes? e.g. \"maps/mapname_soundscapes.txt\""); - -ConVar mapbase_load_localization( "mapbase_load_localization", "1", FCVAR_ARCHIVE, "Should we load map-specific localized text files? e.g. \"maps/mapname_english.txt\"" ); - -ConVar mapbase_load_surfaceprops( "mapbase_load_surfaceprops", "1", FCVAR_ARCHIVE, "Should we load map-specific surfaceproperties files? e.g. \"maps/mapname_surfaceproperties.txt\"" ); - #ifdef GAME_DLL // This constant should change with each Mapbase update ConVar mapbase_version( "mapbase_version", MAPBASE_VERSION, FCVAR_NONE, "The version of Mapbase currently being used in this mod's server.dll" ); -ConVar mapbase_load_sentences("mapbase_load_sentences", "1", FCVAR_ARCHIVE, "Should we load map-specific sentences? e.g. \"maps/mapname_sentences.txt\""); - -ConVar mapbase_load_talker("mapbase_load_talker", "1", FCVAR_ARCHIVE, "Should we load map-specific talker files? e.g. \"maps/mapname_talker.txt\""); ConVar mapbase_flush_talker("mapbase_flush_talker", "1", FCVAR_NONE, "Normally, when a map with custom talker files is unloaded, the response system resets to rid itself of the custom file(s). Turn this convar off to prevent that from happening."); -ConVar mapbase_load_actbusy("mapbase_load_actbusy", "1", FCVAR_ARCHIVE, "Should we load map-specific actbusy files? e.g. \"maps/mapname_actbusy.txt\""); - extern void MapbaseGameLog_Init(); extern void ParseCustomActbusyFile(const char *file); @@ -81,8 +66,6 @@ static bool g_bMapContainsCustomTalker; // This constant should change with each Mapbase update ConVar mapbase_version_client( "mapbase_version_client", MAPBASE_VERSION, FCVAR_NONE, "The version of Mapbase currently being used in this mod's client.dll" ); -//ConVar mapbase_load_cc("mapbase_load_cc", "1", FCVAR_ARCHIVE, "Should we load map-specific closed captioning? e.g. \"maps/mapname_closecaption_english.txt\" and \"maps/mapname_closecaption_english.dat\""); - #endif extern void AddSurfacepropFile( const char *pFileName, IPhysicsSurfaceProps *pProps, IFileSystem *pFileSystem ); @@ -101,11 +84,11 @@ enum MANIFEST_LOCALIZATION, MANIFEST_SURFACEPROPS, #ifdef CLIENT_DLL - //MANIFEST_CLOSECAPTION, + MANIFEST_CLOSECAPTION, MANIFEST_VGUI, #else MANIFEST_TALKER, - MANIFEST_SENTENCES, + //MANIFEST_SENTENCES, MANIFEST_ACTBUSY, #endif @@ -115,25 +98,32 @@ enum struct ManifestType_t { + ManifestType_t( const char *_string, const char *cvarname, const char *cvardesc ) : cvar( cvarname, "1", FCVAR_ARCHIVE, cvardesc ) + { + string = _string; + } + //int type; const char *string; - ConVar *cvar; + ConVar cvar; }; +#define DECLARE_MANIFEST_TYPE(name, cvar, desc) { #name, ConVar(#cvar, "1", FCVAR_ARCHIVE, #desc) } + // KEEP THS IN SYNC WITH THE ENUM! static const ManifestType_t gm_szManifestFileStrings[MANIFEST_NUM_TYPES] = { - { "soundscripts", &mapbase_load_soundscripts }, - //{ "propdata", &mapbase_load_propdata }, - //{ "soundscapes", &mapbase_load_soundscapes }, - { "localization", &mapbase_load_localization }, - { "surfaceprops", &mapbase_load_surfaceprops }, + { "soundscripts", "mapbase_load_soundscripts", "Should we load map-specific soundscripts? e.g. \"maps/_level_sounds.txt\"" }, + //{ "propdata", "mapbase_load_propdata", "Should we load map-specific soundscripts? e.g. \"maps/_level_sounds.txt\"" }, + //{ "soundscapes", "mapbase_load_soundscapes", "Should we load map-specific soundscapes? e.g. \"maps/_soundscapes.txt\"" }, + { "localization", "mapbase_load_localization", "Should we load map-specific localized text files? e.g. \"maps/_english.txt\"" }, + { "surfaceprops", "mapbase_load_surfaceprops", "Should we load map-specific surfaceproperties files? e.g. \"maps/_surfaceproperties.txt\"" }, #ifdef CLIENT_DLL - //{ "closecaption", &mapbase_load_cc }, - { "vgui", NULL }, + { "closecaption", "mapbase_load_closecaption", "Should we load map-specific closed captioning? e.g. \"maps/_closecaption_english.txt\" and \"maps/_closecaption_english.dat\"" }, + { "vgui", "mapbase_load_vgui", "Should we load map-specific VGUI screens? e.g. \"maps/_screens.txt\"" }, #else - { "talker", &mapbase_load_talker }, - { "sentences", &mapbase_load_sentences }, - { "actbusy", &mapbase_load_actbusy }, + { "talker", "mapbase_load_talker", "Should we load map-specific talker files? e.g. \"maps/_talker.txt\"" }, + //{ "sentences", "mapbase_load_sentences", "Should we load map-specific sentences? e.g. \"maps/_sentences.txt\"" }, + { "actbusy", "mapbase_load_actbusy", "Should we load map-specific actbusy files? e.g. \"maps/_actbusy.txt\"" }, #endif }; @@ -262,6 +252,14 @@ public: g_MapName = NULL; RefreshCustomTalker(); + +#ifdef CLIENT_DLL + CHudCloseCaption *hudCloseCaption = GET_HUDELEMENT( CHudCloseCaption ); + FOR_EACH_VEC( m_CloseCaptionFileNames, i ) + { + hudCloseCaption->RemoveCaptionDictionary( m_CloseCaptionFileNames[i] ); + } +#endif } bool RefreshMapName() @@ -284,9 +282,6 @@ public: } #ifdef CLIENT_DLL - bool m_bInitializedRTs = false; - CUtlVector m_CameraTextures; - //----------------------------------------------------------------------------- // Initialize custom RT textures if necessary //----------------------------------------------------------------------------- @@ -389,7 +384,10 @@ public: case MANIFEST_LOCALIZATION: { g_pVGuiLocalize->AddFile( value, "MOD", true ); } break; case MANIFEST_SURFACEPROPS: { AddSurfacepropFile( value, physprops, filesystem ); } break; #ifdef CLIENT_DLL - //case MANIFEST_CLOSECAPTION: { todo } break; + case MANIFEST_CLOSECAPTION: { + if ( GET_HUDELEMENT( CHudCloseCaption ) ) + (GET_HUDELEMENT( CHudCloseCaption ))->AddCustomCaptionFile( value, m_CloseCaptionFileNames ); + } break; case MANIFEST_VGUI: { PanelMetaClassMgr()->LoadMetaClassDefinitionFile( value ); } break; //case MANIFEST_SOUNDSCAPES: { Soundscape_AddFile(value); } break; #else @@ -398,7 +396,7 @@ public: LoadResponseSystemFile(value); //PrecacheCustomResponseSystem( value ); } break; //case MANIFEST_SOUNDSCAPES: { g_SoundscapeSystem.AddSoundscapeFile(value); } break; - case MANIFEST_SENTENCES: { engine->PrecacheSentenceFile(value); } break; + //case MANIFEST_SENTENCES: { engine->PrecacheSentenceFile(value); } break; case MANIFEST_ACTBUSY: { ParseCustomActbusyFile(value); } break; #endif } @@ -457,7 +455,7 @@ public: { if (FStrEq(name, gm_szManifestFileStrings[i].string)) { - if (!gm_szManifestFileStrings[i].cvar || gm_szManifestFileStrings[i].cvar->GetBool()) + if (gm_szManifestFileStrings[i].cvar.GetBool()) { LoadFromValue(value, i, bDontWarn); } @@ -484,6 +482,15 @@ public: g_pScriptVM->RegisterInstance( this, "Mapbase" ); } #endif + +private: + +#ifdef CLIENT_DLL + bool m_bInitializedRTs = false; + CUtlVector m_CameraTextures; + + CUtlVector m_CloseCaptionFileNames; +#endif }; CMapbaseSystem g_MapbaseSystem; From 4ab87250b2a7b08d936dde2f77705b14eb014719 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sat, 24 Jul 2021 01:54:04 -0500 Subject: [PATCH 113/378] Added screen height scaling for vgui_text_display --- sp/src/game/client/c_vguiscreen.h | 9 +++++++ .../client/mapbase/c_vgui_text_display.cpp | 27 +++++++++++++++++-- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/sp/src/game/client/c_vguiscreen.h b/sp/src/game/client/c_vguiscreen.h index d304f5c9..71780093 100644 --- a/sp/src/game/client/c_vguiscreen.h +++ b/sp/src/game/client/c_vguiscreen.h @@ -112,6 +112,15 @@ public: C_BasePlayer *GetPlayerOwner( void ); bool IsInputOnlyToOwner( void ); +#ifdef MAPBASE + void GetSize( float &width, float &height ) const { width = m_flWidth; height = m_flHeight; } + void GetPixelSize( int &width, int &height ) const { width = m_nPixelWidth; height = m_nPixelHeight; } + void SetWidth( float flWidth ) { m_flWidth = flWidth; } + void SetHeight( float flHeight ) { m_flHeight = flHeight; } + void SetPixelWidth( int nWidth ) { m_nPixelWidth = nWidth; } + void SetPixelHeight( int nHeight ) { m_nPixelHeight = nHeight; } +#endif + private: // Vgui screen management void CreateVguiScreen( const char *pTypeName ); diff --git a/sp/src/game/client/mapbase/c_vgui_text_display.cpp b/sp/src/game/client/mapbase/c_vgui_text_display.cpp index c3847ac0..f0d2032d 100644 --- a/sp/src/game/client/mapbase/c_vgui_text_display.cpp +++ b/sp/src/game/client/mapbase/c_vgui_text_display.cpp @@ -157,11 +157,34 @@ void C_TextDisplayPanel::UpdateText() m_pDisplayTextLabel->SetText( m_hScreenEntity->GetDisplayText() ); //SetSize( m_hScreenEntity->GetTextSize(), m_hScreenEntity->GetTextSize() ); - SetSize( m_hScreenEntity->GetResolution(), m_hScreenEntity->GetResolution() ); - m_pDisplayTextLabel->SetSize( m_hScreenEntity->GetResolution(), m_hScreenEntity->GetResolution() ); //m_pDisplayTextLabel->SetSize( m_hScreenEntity->GetTextSize(), m_hScreenEntity->GetTextSize() ); Label::Alignment iAlignment = m_hScreenEntity->GetContentAlignment(); + + switch (iAlignment) + { + // Use a special scaling method when using a south alignment + case Label::Alignment::a_southwest: + case Label::Alignment::a_south: + case Label::Alignment::a_southeast: + int lW, lT; + m_pDisplayTextLabel->GetContentSize( lW, lT ); + SetSize( m_hScreenEntity->GetResolution(), lT ); + m_pDisplayTextLabel->SetSize( m_hScreenEntity->GetResolution(), lT ); + + float sW, sT; + m_hVGUIScreen->GetSize( sW, sT ); + //Msg( "Screen width: %f, new height: %f\n", sW, sW * (lT / m_hScreenEntity->GetResolution()) ); + m_hVGUIScreen->SetHeight( sW * ((float)lT / (float)m_hScreenEntity->GetResolution()) ); + m_hVGUIScreen->SetPixelHeight( lT ); + break; + + default: + SetSize( m_hScreenEntity->GetResolution(), m_hScreenEntity->GetResolution() ); + m_pDisplayTextLabel->SetSize( m_hScreenEntity->GetResolution(), m_hScreenEntity->GetResolution() ); + break; + } + m_pDisplayTextLabel->SetContentAlignment( iAlignment ); bool bWrap = true; From 7fde10fef60f6be7b4fcbb5494797a17d99e234a Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sat, 24 Jul 2021 18:29:14 -0500 Subject: [PATCH 114/378] Fixed issue with text commentary label bounds upon first display --- sp/src/game/client/c_point_commentary_node.cpp | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/sp/src/game/client/c_point_commentary_node.cpp b/sp/src/game/client/c_point_commentary_node.cpp index bfef3c0a..cdee8ade 100644 --- a/sp/src/game/client/c_point_commentary_node.cpp +++ b/sp/src/game/client/c_point_commentary_node.cpp @@ -123,7 +123,7 @@ private: CPanelAnimationVarAliasType( int, m_iTypeTextT, "type_text_tall", "200", "proportional_int" ); CPanelAnimationVarAliasType( int, m_iTypeTextCountXFR, "type_text_count_xpos_from_right", "10", "proportional_int" ); CPanelAnimationVarAliasType( int, m_iTypeTextCountYFB, "type_text_count_ypos_from_bottom", "10", "proportional_int" ); - CPanelAnimationVar( Color, m_TextBackgroundColor, "BackgroundColorTextContent", "0 0 0 192" ); + CPanelAnimationVar( Color, m_TextBackgroundColor, "BackgroundColorTextContent", "0 0 0 224" ); CPanelAnimationVar( Color, m_TypeTextContentColor, "TextContentColor", "255 230 180 255" ); CPanelAnimationVar( int, m_iTextBorderSpace, "type_text_border_space", "8" ); #endif @@ -506,7 +506,7 @@ CHudCommentary::CHudCommentary( const char *name ) : vgui::Panel( NULL, "HudComm m_bShouldPaint = true; #ifdef MAPBASE - m_pLabel = new vgui::Label( this, "HudCommentaryTextLabel", "" ); + m_pLabel = new vgui::Label( this, "HudCommentaryTextLabel", L"Textual commentary" ); m_pImage = new vgui::ImagePanel( this, "HudCommentaryImagePanel" ); m_pImage->SetShouldScaleImage( true ); #endif @@ -693,20 +693,17 @@ void CHudCommentary::PerformLayout() int xOffset = m_iBarX; int yOffset = m_iBarY; - int x, y, wide, tall; - GetBounds( x, y, wide, tall ); + m_pLabel->SetBounds( + xOffset + m_iTextBorderSpace, yOffset + m_iTextBorderSpace, + (float)(m_iBarWide * m_flPanelScale) - m_iTextBorderSpace, GetTall() ); // Figure out the size before setting bounds int lW, lT; m_pLabel->GetContentSize( lW, lT ); - lW = (float)(m_iBarWide * m_flPanelScale) - m_iTextBorderSpace; //lT = (float)lT * m_flPanelScale; // Don't affect height when scaling - m_pLabel->SetBounds( - xOffset + m_iTextBorderSpace, - yOffset + m_iTextBorderSpace, - lW, lT ); + m_pLabel->SetTall( lT ); lW += (float)((m_iTextBorderSpace * 2) + (xOffset * 2)); lT += (float)((m_iTextBorderSpace * 2) + (yOffset * 2)); From 632bd3d0ba19da866ef1b8ce7085559001bdc72d Mon Sep 17 00:00:00 2001 From: Blixibon Date: Mon, 26 Jul 2021 13:06:20 -0500 Subject: [PATCH 115/378] Added commentary node return speed scale --- sp/src/game/server/CommentarySystem.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/sp/src/game/server/CommentarySystem.cpp b/sp/src/game/server/CommentarySystem.cpp index ba5aaba8..959798e5 100644 --- a/sp/src/game/server/CommentarySystem.cpp +++ b/sp/src/game/server/CommentarySystem.cpp @@ -79,6 +79,7 @@ public: #ifdef MAPBASE m_flViewTargetSpeedScale = 1.0f; m_flViewPositionSpeedScale = 1.0f; + m_flReturnSpeedScale = 0.0f; m_flPanelScale = 1.0f; m_flPanelX = -1.0f; m_flPanelY = -1.0f; @@ -133,6 +134,7 @@ private: #ifdef MAPBASE float m_flViewTargetSpeedScale; float m_flViewPositionSpeedScale; + float m_flReturnSpeedScale; #endif bool m_bPreventMovement; bool m_bUnderCrosshair; @@ -191,6 +193,7 @@ BEGIN_DATADESC( CPointCommentaryNode ) #ifdef MAPBASE DEFINE_KEYFIELD( m_flViewTargetSpeedScale, FIELD_FLOAT, "viewtarget_speed" ), DEFINE_KEYFIELD( m_flViewPositionSpeedScale, FIELD_FLOAT, "viewposition_speed" ), + DEFINE_KEYFIELD( m_flReturnSpeedScale, FIELD_FLOAT, "return_speed" ), DEFINE_KEYFIELD( m_iCommentaryType, FIELD_INTEGER, "type" ), DEFINE_KEYFIELD( m_flPanelScale, FIELD_FLOAT, "panelscale" ), DEFINE_KEYFIELD( m_flPanelX, FIELD_FLOAT, "x" ), @@ -939,7 +942,7 @@ void CPointCommentaryNode::Spawn( void ) break; case COMMENTARY_TYPE_IMAGE: - szModel = "models/extras/info_image.mdl"; // TODO + szModel = "models/extras/info_image.mdl"; break; default: @@ -960,6 +963,12 @@ void CPointCommentaryNode::Spawn( void ) AddSolidFlags( FSOLID_CUSTOMRAYTEST | FSOLID_CUSTOMBOXTEST ); AddEffects( EF_NOSHADOW ); +#ifdef MAPBASE + // Default to view position speed scale (which in turn defaults to 1.0) + if (m_flReturnSpeedScale == 0.0f) + m_flReturnSpeedScale = m_flViewPositionSpeedScale; +#endif + // Setup for animation ResetSequence( LookupSequence("idle") ); SetThink( &CPointCommentaryNode::SpinThink ); @@ -1342,8 +1351,8 @@ void CPointCommentaryNode::UpdateViewPostThink( void ) // Blend back to the player's position over time. float flCurTime = (gpGlobals->curtime - m_flFinishedTime); #ifdef MAPBASE - if (m_flViewPositionSpeedScale != 1.0f) - flCurTime *= m_flViewPositionSpeedScale; + if (m_flReturnSpeedScale != 1.0f) + flCurTime *= m_flReturnSpeedScale; #endif float flTimeToBlend = MIN( 2.0, m_flFinishedTime - m_flStartTime ); float flBlendPerc = 1.0f - clamp( flCurTime / flTimeToBlend, 0.f, 1.f ); From 04687e03e97d6fc76afad8a518e40cae4c6edcc0 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Mon, 26 Jul 2021 13:07:33 -0500 Subject: [PATCH 116/378] Fixed an issue with trigger_look LOS keyvalue --- sp/src/game/server/triggers.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sp/src/game/server/triggers.cpp b/sp/src/game/server/triggers.cpp index 03e23cb7..7a5bce80 100644 --- a/sp/src/game/server/triggers.cpp +++ b/sp/src/game/server/triggers.cpp @@ -1279,7 +1279,7 @@ void CTriggerLook::Touch(CBaseEntity *pOther) VectorNormalize(vTargetDir); float fDotPr = DotProduct(vLookDir,vTargetDir); - if (fDotPr > m_flFieldOfView && (!m_bUseLOS || pOther->FVisible(pOther))) + if (fDotPr > m_flFieldOfView && (!m_bUseLOS || pOther->FVisible(m_hLookTargets[i]))) { hLookingAtEntity = m_hLookTargets[i]; break; From 2b1a8762bd726cc3b255885c0cd1ccf100455b2d Mon Sep 17 00:00:00 2001 From: Blixibon Date: Mon, 26 Jul 2021 13:08:20 -0500 Subject: [PATCH 117/378] Added I/O/KV to point_viewcontrol inspired by later games --- sp/src/game/server/triggers.cpp | 65 +++++++++++++++++++++++++++++++++ sp/src/game/server/triggers.h | 5 +++ 2 files changed, 70 insertions(+) diff --git a/sp/src/game/server/triggers.cpp b/sp/src/game/server/triggers.cpp index 7a5bce80..37f5c19b 100644 --- a/sp/src/game/server/triggers.cpp +++ b/sp/src/game/server/triggers.cpp @@ -3100,6 +3100,7 @@ BEGIN_DATADESC( CTriggerCamera ) #ifdef MAPBASE DEFINE_KEYFIELD( m_fov, FIELD_FLOAT, "fov" ), DEFINE_KEYFIELD( m_fovSpeed, FIELD_FLOAT, "fov_rate" ), + DEFINE_KEYFIELD( m_flTrackSpeed, FIELD_FLOAT, "trackspeed" ), DEFINE_KEYFIELD( m_bDontSetPlayerView, FIELD_BOOLEAN, "DontSetPlayerView" ), #endif @@ -3110,6 +3111,10 @@ BEGIN_DATADESC( CTriggerCamera ) #ifdef MAPBASE DEFINE_INPUTFUNC( FIELD_FLOAT, "SetFOV", InputSetFOV ), DEFINE_INPUTFUNC( FIELD_FLOAT, "SetFOVRate", InputSetFOVRate ), + + //DEFINE_INPUTFUNC( FIELD_STRING, "SetTarget", InputSetTarget ), // Defined by base class + DEFINE_INPUTFUNC( FIELD_STRING, "SetTargetAttachment", InputSetTargetAttachment ), + DEFINE_INPUTFUNC( FIELD_FLOAT, "SetTrackSpeed", InputSetTrackSpeed ), #endif // Function Pointers @@ -3138,6 +3143,7 @@ CTriggerCamera::CTriggerCamera() { m_fov = 90; m_fovSpeed = 1; + m_flTrackSpeed = 40.0f; } //------------------------------------------------------------------------------ @@ -3259,6 +3265,61 @@ void CTriggerCamera::InputSetFOVRate( inputdata_t &inputdata ) { m_fovSpeed = inputdata.value.Float(); } + +//------------------------------------------------------------------------------ +// Purpose: +//------------------------------------------------------------------------------ +void CTriggerCamera::InputSetTarget( inputdata_t &inputdata ) +{ + BaseClass::InputSetTarget( inputdata ); + + if ( FStrEq(STRING(m_target), "!player") ) + { + AddSpawnFlags( SF_CAMERA_PLAYER_TARGET ); + m_hTarget = m_hPlayer; + } + else + { + RemoveSpawnFlags( SF_CAMERA_PLAYER_TARGET ); + m_hTarget = GetNextTarget(); + } +} + +//------------------------------------------------------------------------------ +// Purpose: +//------------------------------------------------------------------------------ +void CTriggerCamera::InputSetTargetAttachment( inputdata_t &inputdata ) +{ + m_iszTargetAttachment = inputdata.value.StringID(); + m_iAttachmentIndex = 0; + + if (m_hTarget) + { + if ( m_iszTargetAttachment != NULL_STRING ) + { + if ( !m_hTarget->GetBaseAnimating() ) + { + Warning("%s tried to target an attachment (%s) on target %s, which has no model.\n", GetClassname(), STRING(m_iszTargetAttachment), STRING(m_hTarget->GetEntityName()) ); + } + else + { + m_iAttachmentIndex = m_hTarget->GetBaseAnimating()->LookupAttachment( STRING(m_iszTargetAttachment) ); + if ( m_iAttachmentIndex <= 0 ) + { + Warning("%s could not find attachment %s on target %s.\n", GetClassname(), STRING(m_iszTargetAttachment), STRING(m_hTarget->GetEntityName()) ); + } + } + } + } +} + +//------------------------------------------------------------------------------ +// Purpose: +//------------------------------------------------------------------------------ +void CTriggerCamera::InputSetTrackSpeed( inputdata_t &inputdata ) +{ + m_flTrackSpeed = inputdata.value.Float(); +} #endif //----------------------------------------------------------------------------- @@ -3626,7 +3687,11 @@ void CTriggerCamera::FollowTarget( ) dy = dy - 360; QAngle vecAngVel; +#ifdef MAPBASE + vecAngVel.Init( dx * m_flTrackSpeed * gpGlobals->frametime, dy * m_flTrackSpeed * gpGlobals->frametime, GetLocalAngularVelocity().z ); +#else vecAngVel.Init( dx * 40 * gpGlobals->frametime, dy * 40 * gpGlobals->frametime, GetLocalAngularVelocity().z ); +#endif SetLocalAngularVelocity(vecAngVel); } diff --git a/sp/src/game/server/triggers.h b/sp/src/game/server/triggers.h index 4aacad13..47bf82be 100644 --- a/sp/src/game/server/triggers.h +++ b/sp/src/game/server/triggers.h @@ -300,6 +300,10 @@ public: #ifdef MAPBASE void InputSetFOV( inputdata_t &inputdata ); void InputSetFOVRate( inputdata_t &inputdata ); + + void InputSetTarget( inputdata_t &inputdata ); + void InputSetTargetAttachment( inputdata_t &inputdata ); + void InputSetTrackSpeed( inputdata_t &inputdata ); #endif private: @@ -323,6 +327,7 @@ private: #ifdef MAPBASE float m_fov; float m_fovSpeed; + float m_flTrackSpeed; bool m_bDontSetPlayerView; #endif From 5a11d51db42f9b6ff892d8611301f79b131a6e72 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Mon, 26 Jul 2021 13:14:51 -0500 Subject: [PATCH 118/378] Fixed some issues with instanced response systems --- sp/src/game/shared/ai_responsesystem_new.cpp | 13 +++++++++++++ sp/src/responserules/runtime/response_system.cpp | 11 ++++++++--- sp/src/responserules/runtime/response_system.h | 3 +++ 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/sp/src/game/shared/ai_responsesystem_new.cpp b/sp/src/game/shared/ai_responsesystem_new.cpp index 6c3301bb..9b519902 100644 --- a/sp/src/game/shared/ai_responsesystem_new.cpp +++ b/sp/src/game/shared/ai_responsesystem_new.cpp @@ -531,6 +531,9 @@ public: virtual void LevelInitPostEntity() { +#ifdef MAPBASE + if (!rr_enhanced_saverestore.GetBool() || gpGlobals->eLoadType != MapLoad_Transition) +#endif ResetResponseGroups(); } @@ -567,6 +570,16 @@ public: virtual void LevelInitPostEntity() { +#ifdef MAPBASE + // CInstancedResponseSystem is not a CAutoGameSystem, so this needs to be called manually. + // The same could've been accomplished by making CInstancedResponseSystem derive from CAutoGameSystem, + // but their instanced nature would've complicated things a lot. + int c = m_InstancedSystems.Count(); + for ( int i = c - 1 ; i >= 0; i-- ) + { + m_InstancedSystems[i]->LevelInitPostEntity(); + } +#endif } virtual void Release() diff --git a/sp/src/responserules/runtime/response_system.cpp b/sp/src/responserules/runtime/response_system.cpp index 156bd45f..d294316d 100644 --- a/sp/src/responserules/runtime/response_system.cpp +++ b/sp/src/responserules/runtime/response_system.cpp @@ -192,6 +192,9 @@ CResponseSystem::CResponseSystem() : token[0] = 0; m_bUnget = false; m_bCustomManagable = false; +#ifdef MAPBASE + m_bInProspective = false; +#endif BuildDispatchTables(); } @@ -1008,11 +1011,13 @@ int CResponseSystem::SelectWeightedResponseFromResponseGroup( ResponseGroup *g, } if ( slot != -1 ) + { #ifdef MAPBASE - // Don't mark responses as used in prospective mode - if (m_bInProspective == false) + // Don't mark responses as used in prospective mode + if (m_bInProspective == false) #endif - g->MarkResponseUsed( slot ); + g->MarkResponseUsed( slot ); + } // Revert fake depletion of unavailable choices RevertFakedDepletes( g ); diff --git a/sp/src/responserules/runtime/response_system.h b/sp/src/responserules/runtime/response_system.h index b675e816..a862d761 100644 --- a/sp/src/responserules/runtime/response_system.h +++ b/sp/src/responserules/runtime/response_system.h @@ -58,6 +58,9 @@ namespace ResponseRules bool IsCustomManagable() { return m_bCustomManagable; } +#ifdef MAPBASE + virtual +#endif void Clear(); void DumpDictionary( const char *pszName ); From 22557f3751c8c377fe9070f31b760bce16ece6a2 Mon Sep 17 00:00:00 2001 From: MoofEMP <5711800-MoofEMP@users.noreply.gitlab.com> Date: Wed, 21 Jul 2021 19:56:39 -0400 Subject: [PATCH 119/378] Add logic_substring --- sp/src/game/server/logic_substring.cpp | 97 ++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 sp/src/game/server/logic_substring.cpp diff --git a/sp/src/game/server/logic_substring.cpp b/sp/src/game/server/logic_substring.cpp new file mode 100644 index 00000000..e7ed2b71 --- /dev/null +++ b/sp/src/game/server/logic_substring.cpp @@ -0,0 +1,97 @@ +//====================== By Holly Liberatore / MoofEMP ======================// +// +// Purpose: Takes a string parameter and returns a substring defined by keyvalues +// +//===========================================================================// + +#include "cbase.h" + +#define SF_SUBSTRING_START_DISABLED (1 << 0) + +class CLogicSubstring : public CLogicalEntity +{ +public: + DECLARE_CLASS( CLogicSubstring, CLogicalEntity ); + DECLARE_DATADESC(); + + CLogicSubstring( void ) { } + + void InputDisable( inputdata_t &inputData ); + void InputEnable( inputdata_t &inputData ); + void InputInValue( inputdata_t &inputData ); + void InputSetLength( inputdata_t &inputData ); + void InputSetStartPos( inputdata_t &inputData ); + + void Spawn(void); + +private: + int m_nLength; + int m_nStartPos; + + bool m_bEnabled; + + COutputString m_OutValue; +}; + +LINK_ENTITY_TO_CLASS( logic_substring, CLogicSubstring ); + +BEGIN_DATADESC( CLogicSubstring ) + + DEFINE_FIELD( m_bEnabled, FIELD_BOOLEAN ), + + DEFINE_KEYFIELD(m_nLength, FIELD_INTEGER, "length" ), + DEFINE_KEYFIELD(m_nStartPos, FIELD_INTEGER, "startPos" ), + + DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ), + DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ), + DEFINE_INPUTFUNC( FIELD_STRING, "InValue", InputInValue ), + DEFINE_INPUTFUNC( FIELD_INTEGER, "SetLength", InputSetLength ), + DEFINE_INPUTFUNC( FIELD_INTEGER, "SetStartPos", InputSetStartPos ), + + DEFINE_OUTPUT( m_OutValue, "OutValue" ), + +END_DATADESC() + +//----------------------------------------------------------------------------- +// Purpose: Disable or enable the entity (disabling prevents any input functions from running) +//----------------------------------------------------------------------------- +void CLogicSubstring::InputDisable( inputdata_t &inputData ) { m_bEnabled = false; } +void CLogicSubstring::InputEnable ( inputdata_t &inputData ) { m_bEnabled = true ; } + +//----------------------------------------------------------------------------- +// Purpose: Trim substring from input +// Output: Substring +//----------------------------------------------------------------------------- +void CLogicSubstring::InputInValue( inputdata_t &inputData ) +{ + if( !m_bEnabled ) return; + + char* strOutValue = (char*)malloc( m_nLength ); + Q_strncpy( strOutValue, inputData.value.String() + m_nStartPos, m_nLength + 1 ); // note length+1 to account for null terminator + m_OutValue.Set( MAKE_STRING(strOutValue), inputData.pActivator, this ); +} + +//----------------------------------------------------------------------------- +// Purpose: Setter methods for keyvalues +//----------------------------------------------------------------------------- +void CLogicSubstring::InputSetLength( inputdata_t &inputData ) +{ + if( !m_bEnabled ) return; + + m_nLength = inputData.value.Int(); +} + +void CLogicSubstring::InputSetStartPos( inputdata_t &inputData ) +{ + if( !m_bEnabled ) return; + + m_nStartPos = inputData.value.Int(); +} + +//----------------------------------------------------------------------------- +// Purpose: Respond to spawnflags when entity spawns +//----------------------------------------------------------------------------- +void CLogicSubstring::Spawn( void ) +{ + m_bEnabled = !HasSpawnFlags( SF_SUBSTRING_START_DISABLED ); +} From 41cde5ccf735c342f34713389b13307ba90b0497 Mon Sep 17 00:00:00 2001 From: MoofEMP <5711800-MoofEMP@users.noreply.gitlab.com> Date: Tue, 27 Jul 2021 02:29:32 -0400 Subject: [PATCH 120/378] Fix logic_substring behaviour with unexpected length/startpos values --- sp/src/game/server/logic_substring.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/sp/src/game/server/logic_substring.cpp b/sp/src/game/server/logic_substring.cpp index e7ed2b71..648cf2fe 100644 --- a/sp/src/game/server/logic_substring.cpp +++ b/sp/src/game/server/logic_substring.cpp @@ -66,8 +66,19 @@ void CLogicSubstring::InputInValue( inputdata_t &inputData ) { if( !m_bEnabled ) return; - char* strOutValue = (char*)malloc( m_nLength ); - Q_strncpy( strOutValue, inputData.value.String() + m_nStartPos, m_nLength + 1 ); // note length+1 to account for null terminator + int startPosCheck = m_nStartPos < 0 ? Q_strlen(inputData.value.String()) + m_nStartPos : m_nStartPos; + if( startPosCheck < 0 ) + { + startPosCheck = 0; + } + int lengthCheck = (m_nLength < 0 || m_nLength > Q_strlen(inputData.value.String()) - startPosCheck ? Q_strlen(inputData.value.String()) - startPosCheck : m_nLength) + 1; + if( lengthCheck < 1 || startPosCheck > Q_strlen(inputData.value.String()) ) + { + m_OutValue.Set( MAKE_STRING(""), inputData.pActivator, this ); + return; + } + char* strOutValue = (char*)malloc( lengthCheck ); + Q_strncpy( strOutValue, inputData.value.String() + startPosCheck, lengthCheck ); m_OutValue.Set( MAKE_STRING(strOutValue), inputData.pActivator, this ); } From 99a8bdcb3723e752741a3c7b905ee73a2254ed12 Mon Sep 17 00:00:00 2001 From: MoofEMP <5711800-MoofEMP@users.noreply.gitlab.com> Date: Tue, 27 Jul 2021 17:46:41 -0400 Subject: [PATCH 121/378] Use a variable for input string length in logic_substring --- sp/src/game/server/logic_substring.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sp/src/game/server/logic_substring.cpp b/sp/src/game/server/logic_substring.cpp index 648cf2fe..d1e9b96c 100644 --- a/sp/src/game/server/logic_substring.cpp +++ b/sp/src/game/server/logic_substring.cpp @@ -66,13 +66,14 @@ void CLogicSubstring::InputInValue( inputdata_t &inputData ) { if( !m_bEnabled ) return; - int startPosCheck = m_nStartPos < 0 ? Q_strlen(inputData.value.String()) + m_nStartPos : m_nStartPos; + int inputLength = Q_strlen(inputData.value.String()); + int startPosCheck = m_nStartPos < 0 ? inputLength + m_nStartPos : m_nStartPos; if( startPosCheck < 0 ) { startPosCheck = 0; } - int lengthCheck = (m_nLength < 0 || m_nLength > Q_strlen(inputData.value.String()) - startPosCheck ? Q_strlen(inputData.value.String()) - startPosCheck : m_nLength) + 1; - if( lengthCheck < 1 || startPosCheck > Q_strlen(inputData.value.String()) ) + int lengthCheck = (m_nLength < 0 || m_nLength > inputLength - startPosCheck ? inputLength - startPosCheck : m_nLength) + 1; + if( lengthCheck < 1 || startPosCheck > inputLength ) { m_OutValue.Set( MAKE_STRING(""), inputData.pActivator, this ); return; From 3e9d3deda2eb3428cade7b1b1cbc55d0cf0d4304 Mon Sep 17 00:00:00 2001 From: Moofles <62188664+moofemp@users.noreply.github.com> Date: Tue, 27 Jul 2021 17:50:32 -0400 Subject: [PATCH 122/378] Use AllocPooledString() to prevent memory leak in logic_substring Co-authored-by: Spencer Brown --- sp/src/game/server/logic_substring.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sp/src/game/server/logic_substring.cpp b/sp/src/game/server/logic_substring.cpp index d1e9b96c..7c7d153b 100644 --- a/sp/src/game/server/logic_substring.cpp +++ b/sp/src/game/server/logic_substring.cpp @@ -80,7 +80,8 @@ void CLogicSubstring::InputInValue( inputdata_t &inputData ) } char* strOutValue = (char*)malloc( lengthCheck ); Q_strncpy( strOutValue, inputData.value.String() + startPosCheck, lengthCheck ); - m_OutValue.Set( MAKE_STRING(strOutValue), inputData.pActivator, this ); + m_OutValue.Set( AllocPooledString(strOutValue), inputData.pActivator, this ); + free(strOutValue); } //----------------------------------------------------------------------------- From f1a8638a348af358508e9adfdad35173f432fec9 Mon Sep 17 00:00:00 2001 From: MoofEMP <5711800-MoofEMP@users.noreply.gitlab.com> Date: Tue, 27 Jul 2021 22:41:43 -0400 Subject: [PATCH 123/378] Move logic_substring.cpp to mapbase folder --- sp/src/game/server/{ => mapbase}/logic_substring.cpp | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename sp/src/game/server/{ => mapbase}/logic_substring.cpp (100%) diff --git a/sp/src/game/server/logic_substring.cpp b/sp/src/game/server/mapbase/logic_substring.cpp similarity index 100% rename from sp/src/game/server/logic_substring.cpp rename to sp/src/game/server/mapbase/logic_substring.cpp From 4e6f4cb2eacc08ab83cc6622caa97424b6fd32cc Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sat, 31 Jul 2021 03:00:05 -0500 Subject: [PATCH 124/378] Added scene commentary nodes, which play the audio in full VCD files --- .../game/client/c_point_commentary_node.cpp | 355 +++++++++++++++++- sp/src/game/server/CommentarySystem.cpp | 4 + sp/src/game/shared/shareddefs.h | 1 + 3 files changed, 358 insertions(+), 2 deletions(-) diff --git a/sp/src/game/client/c_point_commentary_node.cpp b/sp/src/game/client/c_point_commentary_node.cpp index cdee8ade..f9e447c6 100644 --- a/sp/src/game/client/c_point_commentary_node.cpp +++ b/sp/src/game/client/c_point_commentary_node.cpp @@ -21,6 +21,10 @@ #ifdef MAPBASE #include "vgui_controls/Label.h" #include "vgui_controls/ImagePanel.h" +#include "filesystem.h" +#include "scenefilecache/ISceneFileCache.h" +#include "choreoscene.h" +#include "c_sceneentity.h" #endif // memdbgon must be the last include file in a .cpp file!!! @@ -65,6 +69,7 @@ public: #ifdef MAPBASE void StartTextCommentary( C_PointCommentaryNode *pNode, const char *pszText, char *pszSpeakers, int iNode, int iNodeMax, float flStartTime, float flEndTime ); void StartImageCommentary( C_PointCommentaryNode *pNode, const char *pszImage, char *pszSpeakers, int iNode, int iNodeMax, float flStartTime, float flEndTime ); + void StartSceneCommentary( C_PointCommentaryNode *pNode, char *pszSpeakers, int iNode, int iNodeMax, float flStartTime, float flEndTime ); #endif void StopCommentary( void ); bool IsTheActiveNode( C_PointCommentaryNode *pNode ) { return (pNode == m_hActiveNode); } @@ -141,7 +146,7 @@ private: //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- -class C_PointCommentaryNode : public C_BaseAnimating +class C_PointCommentaryNode : public C_BaseAnimating, public IChoreoEventCallback { DECLARE_CLASS( C_PointCommentaryNode, C_BaseAnimating ); public: @@ -155,7 +160,18 @@ public: #ifdef MAPBASE void StartTextCommentary( const char *pszCommentaryFile, C_BasePlayer *pPlayer ); void StartImageCommentary( const char *pszCommentaryFile, C_BasePlayer *pPlayer ); + void StartSceneCommentary( const char *pszCommentaryFile, C_BasePlayer *pPlayer ); + + // From IChoreoEventCallback + virtual void StartEvent( float currenttime, CChoreoScene *scene, CChoreoEvent *event ); +#else + virtual void StartEvent( float currenttime, CChoreoScene *scene, CChoreoEvent *event ) {} #endif + virtual void EndEvent( float currenttime, CChoreoScene *scene, CChoreoEvent *event ) {} + virtual void ProcessEvent( float currenttime, CChoreoScene *scene, CChoreoEvent *event ) {} + virtual bool CheckEvent( float currenttime, CChoreoScene *scene, CChoreoEvent *event ) { return true; } + + void ClientThink(); void OnRestore( void ) { @@ -241,6 +257,10 @@ public: float m_flPanelScale; float m_flPanelX; float m_flPanelY; + + CChoreoScene *m_pScene; + //CHandle m_hScene; + EHANDLE m_hSceneOrigin; #endif }; @@ -327,6 +347,10 @@ void C_PointCommentaryNode::OnDataChanged( DataUpdateType_t updateType ) StartImageCommentary( pszCommentaryFile, pPlayer ); break; + case COMMENTARY_TYPE_SCENE: + StartSceneCommentary( pszCommentaryFile, pPlayer ); + break; + default: case COMMENTARY_TYPE_AUDIO: StartAudioCommentary( pszCommentaryFile, pPlayer ); @@ -440,8 +464,254 @@ void C_PointCommentaryNode::StartImageCommentary( const char *pszCommentaryFile, CHudCommentary *pHudCommentary = (CHudCommentary *)GET_HUDELEMENT( CHudCommentary ); pHudCommentary->StartImageCommentary( this, pszCommentaryFile, m_iszSpeakers, m_iNodeNumber, m_iNodeNumberMax, m_flStartTime, m_flStartTime + flDuration ); } + +extern CChoreoStringPool g_ChoreoStringPool; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_PointCommentaryNode::StartSceneCommentary( const char *pszCommentaryFile, C_BasePlayer *pPlayer ) +{ + EmitSound_t es; + es.m_nChannel = CHAN_STATIC; + es.m_pSoundName = pszCommentaryFile; + es.m_SoundLevel = SNDLVL_GUNFIRE; + es.m_nFlags = SND_SHOULDPAUSE; + + char loadfile[MAX_PATH]; + Q_strncpy( loadfile, pszCommentaryFile, sizeof( loadfile ) ); + Q_SetExtension( loadfile, ".vcd", sizeof( loadfile ) ); + Q_FixSlashes( loadfile ); + + // + // Raw scene file support + // + void *pBuffer = 0; + size_t bufsize = scenefilecache->GetSceneBufferSize( loadfile ); + if ( bufsize > 0 ) + { + // Definitely in scenes.image + pBuffer = malloc( bufsize ); + if ( !scenefilecache->GetSceneData( pszCommentaryFile, (byte *)pBuffer, bufsize ) ) + { + free( pBuffer ); + } + + + if ( IsBufferBinaryVCD( (char*)pBuffer, bufsize ) ) + { + m_pScene = new CChoreoScene( NULL ); + CUtlBuffer buf( pBuffer, bufsize, CUtlBuffer::READ_ONLY ); + if ( !m_pScene->RestoreFromBinaryBuffer( buf, loadfile, &g_ChoreoStringPool ) ) + { + Warning( "Unable to restore scene '%s'\n", loadfile ); + delete m_pScene; + m_pScene = NULL; + } + } + } + else if (filesystem->ReadFileEx( loadfile, "MOD", &pBuffer, true )) + { + // Not in scenes.image, but it's a raw file + g_TokenProcessor.SetBuffer((char*)pBuffer); + m_pScene = ChoreoLoadScene( loadfile, this, &g_TokenProcessor, Scene_Printf ); + } + + free( pBuffer ); + + if( m_pScene ) + { + m_pScene->SetPrintFunc( Scene_Printf ); + m_pScene->SetEventCallbackInterface( this ); + } + else + { + // Cancel commentary (TODO: clean up?) + return; + } + + int types[ 2 ]; + types[ 0 ] = CChoreoEvent::SPEAK; + //types[ 1 ] = CChoreoEvent::GENERIC; // TODO: Support for the game_text event? + m_pScene->RemoveEventsExceptTypes( types, 1 ); + + // Iterate events and precache necessary resources + for ( int i = 0; i < m_pScene->GetNumEvents(); i++ ) + { + CChoreoEvent *event = m_pScene->GetEvent( i ); + if ( !event ) + continue; + + // load any necessary data + switch (event->GetType() ) + { + default: + break; + case CChoreoEvent::SPEAK: + { + // Defined in SoundEmitterSystem.cpp + // NOTE: The script entries associated with .vcds are forced to preload to avoid + // loading hitches during triggering + CBaseEntity::PrecacheScriptSound( event->GetParameters() ); + + if ( event->GetCloseCaptionType() == CChoreoEvent::CC_MASTER && + event->GetNumSlaves() > 0 ) + { + char tok[ CChoreoEvent::MAX_CCTOKEN_STRING ]; + if ( event->GetPlaybackCloseCaptionToken( tok, sizeof( tok ) ) ) + { + CBaseEntity::PrecacheScriptSound( tok ); + } + } + } + break; + } + } + + PrecacheScriptSound( "AI_BaseNPC.SentenceStop" ); + + if ( m_hViewPosition ) + { + m_hSceneOrigin = m_hViewPosition; + } + else if ( render->GetViewEntity() ) + { + m_hSceneOrigin = cl_entitylist->GetEnt( render->GetViewEntity() ); + } + else + { + m_hSceneOrigin = pPlayer; + } + + // Get the duration so we know when it finishes + float flDuration = m_pScene->GetDuration(); + + CHudCloseCaption *pHudCloseCaption = (CHudCloseCaption *)GET_HUDELEMENT( CHudCloseCaption ); + if ( pHudCloseCaption ) + { + // This is where we play the commentary close caption (and lock the other captions out). + // Also, if close captions are off we force a caption in non-English + if ( closecaption.GetBool() || ( !closecaption.GetBool() && !english.GetBool() ) ) + { + // Clear the close caption element in preparation + pHudCloseCaption->Reset(); + + // Find the close caption hud element & lock it + pHudCloseCaption->Lock(); + } + } + + // Tell the HUD element + CHudCommentary *pHudCommentary = (CHudCommentary *)GET_HUDELEMENT( CHudCommentary ); + pHudCommentary->StartSceneCommentary( this, m_iszSpeakers, m_iNodeNumber, m_iNodeNumberMax, m_flStartTime, m_flStartTime + flDuration ); + + // Start thinking for the scene + SetNextClientThink( CLIENT_THINK_ALWAYS ); +} + +//----------------------------------------------------------------------------- +// Purpose: All events are leading edge triggered +// Input : currenttime - +// *event - +//----------------------------------------------------------------------------- +void C_PointCommentaryNode::StartEvent( float currenttime, CChoreoScene *scene, CChoreoEvent *event ) +{ + Assert( event ); + + if ( !Q_stricmp( event->GetName(), "NULL" ) ) + { + return; + } + + //Msg("Starting event \"%s\" (%s)\n", event->GetName(), event->GetParameters()); + + // load any necessary data + switch (event->GetType() ) + { + default: + break; + case CChoreoEvent::SPEAK: + { + CSingleUserRecipientFilter filter( C_BasePlayer::GetLocalPlayer() ); + + EmitSound_t es; + es.m_nChannel = CHAN_VOICE2; + es.m_flVolume = 1; + es.m_SoundLevel = SNDLVL_GUNFIRE; + //es.m_nFlags = SND_SHOULDPAUSE; + + es.m_bEmitCloseCaption = false; + es.m_pSoundName = event->GetParameters(); + + // Just in case + if (!m_hSceneOrigin) + m_hSceneOrigin = C_BasePlayer::GetLocalPlayer(); + + EmitSound( filter, m_hSceneOrigin->entindex(), es ); + + // Close captioning only on master token no matter what... + // Also, if close captions are off we force a caption in non-English + if ( event->GetCloseCaptionType() == CChoreoEvent::CC_MASTER && closecaption.GetBool() || ( !closecaption.GetBool() && !english.GetBool() ) ) + { + char tok[ CChoreoEvent::MAX_CCTOKEN_STRING ]; + bool validtoken = event->GetPlaybackCloseCaptionToken( tok, sizeof( tok ) ); + if ( validtoken ) + { + CRC32_t tokenCRC; + CRC32_Init( &tokenCRC ); + + char lowercase[ 256 ]; + Q_strncpy( lowercase, tok, sizeof( lowercase ) ); + Q_strlower( lowercase ); + + CRC32_ProcessBuffer( &tokenCRC, lowercase, Q_strlen( lowercase ) ); + CRC32_Final( &tokenCRC ); + + float endtime = event->GetLastSlaveEndTime(); + float durationShort = event->GetDuration(); + float durationLong = endtime - event->GetStartTime(); + float duration = MAX( durationShort, durationLong ); + + CHudCloseCaption *hudCloseCaption = GET_HUDELEMENT( CHudCloseCaption ); + if ( hudCloseCaption ) + { + hudCloseCaption->ProcessCaptionDirect( lowercase, duration ); + } + } + + } + } + break; + // TODO: Support for the game_text event? + /* + case CChoreoEvent::GENERIC: + { + + } + break; + */ + } + + event->m_flPrevTime = currenttime; +} #endif +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_PointCommentaryNode::ClientThink() +{ + BaseClass::ClientThink(); + +#ifdef MAPBASE + if (m_iCommentaryType == COMMENTARY_TYPE_SCENE && m_pScene) + { + m_pScene->Think( gpGlobals->curtime - m_flStartTime ); + SetNextClientThink( CLIENT_THINK_ALWAYS ); + } +#endif +} + //----------------------------------------------------------------------------- // Purpose: Shut down the commentary //----------------------------------------------------------------------------- @@ -452,6 +722,18 @@ void C_PointCommentaryNode::StopLoopingSounds( void ) (CSoundEnvelopeController::GetController()).SoundDestroy( m_sndCommentary ); m_sndCommentary = NULL; } + +#ifdef MAPBASE + if ( m_pScene ) + { + delete m_pScene; + m_pScene = NULL; + + // Must do this to terminate audio + if (m_hSceneOrigin) + m_hSceneOrigin->EmitSound( "AI_BaseNPC.SentenceStop" ); + } +#endif } //----------------------------------------------------------------------------- @@ -554,6 +836,12 @@ void CHudCommentary::Paint() // Detect the end of the commentary if ( flPercentage >= 1 && m_hActiveNode ) { +#ifdef MAPBASE + // Ensure that the scene is terminated + if (m_iCommentaryType == COMMENTARY_TYPE_SCENE) + m_hActiveNode->StopLoopingSounds(); +#endif + m_hActiveNode = NULL; g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "HideCommentary" ); @@ -603,6 +891,7 @@ void CHudCommentary::Paint() } break; default: + case COMMENTARY_TYPE_SCENE: case COMMENTARY_TYPE_AUDIO: { // Draw the progress bar @@ -656,7 +945,7 @@ void CHudCommentary::Paint() vgui::surface()->GetTextSize( m_hFont, m_szCount, iCountWide, iCountTall ); #ifdef MAPBASE - if (m_iCommentaryType != COMMENTARY_TYPE_AUDIO) + if (m_iCommentaryType != COMMENTARY_TYPE_AUDIO && m_iCommentaryType != COMMENTARY_TYPE_SCENE) vgui::surface()->DrawSetTextPos( wide - m_iTypeTextCountXFR - iCountWide, tall - m_iTypeTextCountYFB - iCountTall ); else #endif @@ -742,6 +1031,7 @@ void CHudCommentary::PerformLayout() } break; default: + case COMMENTARY_TYPE_SCENE: case COMMENTARY_TYPE_AUDIO: break; } @@ -998,6 +1288,67 @@ void CHudCommentary::StartImageCommentary( C_PointCommentaryNode *pNode, const c SetAlpha( 255 ); } } + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudCommentary::StartSceneCommentary( C_PointCommentaryNode *pNode, char *pszSpeakers, int iNode, int iNodeMax, float flStartTime, float flEndTime ) +{ + if ( (flEndTime - flStartTime) <= 0 ) + return; + + m_hActiveNode = pNode; + m_flStartTime = flStartTime; + m_flEndTime = flEndTime; + m_bHiding = false; + m_iCommentaryType = COMMENTARY_TYPE_SCENE; + m_flPanelScale = pNode->m_flPanelScale; + m_flOverrideX = pNode->m_flPanelX; + m_flOverrideY = pNode->m_flPanelY; + g_pVGuiLocalize->ConvertANSIToUnicode( pszSpeakers, m_szSpeakers, sizeof( m_szSpeakers ) ); + + SetBounds( m_iTypeAudioX, m_iTypeAudioY, m_iTypeAudioW, m_iTypeAudioT ); + SetBgColor( m_bUseScriptBGColor ? m_BGOverrideColor : m_BackgroundColor ); + + m_pLabel->SetPaintEnabled( false ); + m_pImage->SetPaintEnabled( false ); + m_pImage->EvictImage(); + + // Get our scheme and font information + vgui::HScheme scheme = vgui::scheme()->GetScheme( "ClientScheme" ); + m_hFont = vgui::scheme()->GetIScheme(scheme)->GetFont( "CommentaryDefault" ); + if ( !m_hFont ) + { + m_hFont = vgui::scheme()->GetIScheme(scheme)->GetFont( "Default" ); + } + + // Don't draw the element itself if closecaptions are on (and captions are always on in non-english mode) + ConVarRef pCVar( "closecaption" ); + if ( pCVar.IsValid() ) + { + m_bShouldPaint = ( !pCVar.GetBool() && english.GetBool() ); + } + else + { + m_bShouldPaint = true; + } + SetPaintBackgroundEnabled( m_bShouldPaint ); + + char sz[MAX_COUNT_STRING]; + Q_snprintf( sz, sizeof(sz), "%d \\ %d", iNode, iNodeMax ); + g_pVGuiLocalize->ConvertANSIToUnicode( sz, m_szCount, sizeof(m_szCount) ); + + // If the commentary just started, play the commentary fade in. + if ( fabs(flStartTime - gpGlobals->curtime) < 1.0 ) + { + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "ShowCommentary" ); + } + else + { + // We're reloading a savegame that has an active commentary going in it. Don't fade in. + SetAlpha( 255 ); + } +} #endif //----------------------------------------------------------------------------- diff --git a/sp/src/game/server/CommentarySystem.cpp b/sp/src/game/server/CommentarySystem.cpp index 959798e5..0ddb48b4 100644 --- a/sp/src/game/server/CommentarySystem.cpp +++ b/sp/src/game/server/CommentarySystem.cpp @@ -945,6 +945,10 @@ void CPointCommentaryNode::Spawn( void ) szModel = "models/extras/info_image.mdl"; break; + case COMMENTARY_TYPE_SCENE: + szModel = "models/extras/info_scene.mdl"; + break; + default: case COMMENTARY_TYPE_AUDIO: szModel = "models/extras/info_speech.mdl"; diff --git a/sp/src/game/shared/shareddefs.h b/sp/src/game/shared/shareddefs.h index 0ddb6e1d..11f8e8aa 100644 --- a/sp/src/game/shared/shareddefs.h +++ b/sp/src/game/shared/shareddefs.h @@ -1056,6 +1056,7 @@ enum COMMENTARY_TYPE_TEXT, // Display text data COMMENTARY_TYPE_IMAGE, // Display an image + COMMENTARY_TYPE_SCENE, // Play a VCD file }; #endif From 8e8c34f958722d6ef04740252f2a71c12cf36123 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sat, 31 Jul 2021 03:02:08 -0500 Subject: [PATCH 125/378] Added support for columns and images in outro env_credits and color overrides for both intro and outro env_credits --- sp/src/game/client/hl2/hud_credits.cpp | 331 ++++++++++++++++++++++++- 1 file changed, 323 insertions(+), 8 deletions(-) diff --git a/sp/src/game/client/hl2/hud_credits.cpp b/sp/src/game/client/hl2/hud_credits.cpp index 280e8a44..b9760712 100644 --- a/sp/src/game/client/hl2/hud_credits.cpp +++ b/sp/src/game/client/hl2/hud_credits.cpp @@ -32,6 +32,16 @@ struct creditname_t float flTimeAdd; float flTimeStart; int iSlot; + +#ifdef MAPBASE + // New credits stuff + + Color cColorOverride; + + // Images + int iImageID = -1; + float flImageScale = 1.0f; +#endif }; #define CREDITS_FILE "scripts/credits.txt" @@ -93,6 +103,10 @@ private: void DrawOutroCreditsName( void ); void DrawIntroCreditsName( void ); void DrawLogo( void ); +#ifdef MAPBASE + void DrawOutroCreditFont( const char *pCreditName, float flYPos, vgui::HFont hTFont, const Color &cColor, int iScreenWidth, int iDivisor = 2 ); + void DrawOutroCreditTexture( int iImageID, float flYPos, float flImageScale, const Color &cColor, int iScreenWidth, int iDivisor = 2 ); +#endif void PrepareLogo( float flTime ); void PrepareOutroCredits( void ); @@ -102,6 +116,10 @@ private: void PrepareLine( vgui::HFont hFont, char const *pchLine ); +#ifdef MAPBASE + int GetOrAllocateImageID( const char *szFileName ); +#endif + CPanelAnimationVar( vgui::HFont, m_hTextFont, "TextFont", "Default" ); CPanelAnimationVar( Color, m_TextColor, "TextColor", "FgColor" ); @@ -110,7 +128,10 @@ private: float m_flScrollTime; float m_flSeparation; #ifdef MAPBASE - int m_iEndLines; + int m_iEndLines; + float m_flEndLinesFadeHoldTime; + bool m_bAllowColumns; + CUtlDict m_ImageDict; #endif float m_flFadeTime; bool m_bLastOneInPlace; @@ -202,6 +223,20 @@ void CHudCredits::Clear( void ) m_bLastOneInPlace = false; m_Alpha = m_TextColor[3]; m_iLogoState = LOGO_FADEOFF; + +#ifdef MAPBASE + if ( surface() ) + { + for (int i = m_ImageDict.Count()-1; i >= 0; i--) + { + if (m_ImageDict[i] != -1) + { + surface()->DestroyTextureID( m_ImageDict[i] ); + m_ImageDict.RemoveAt( i ); + } + } + } +#endif } //----------------------------------------------------------------------------- @@ -229,7 +264,11 @@ void CHudCredits::ReadNames( KeyValues *pKeyValue ) { creditname_t Credits; V_strcpy_safe( Credits.szCreditName, pKVNames->GetName() ); +#ifdef MAPBASE + V_strcpy_safe( Credits.szFontName, pKVNames->GetString( (const char *)NULL, "Default" ) ); +#else V_strcpy_safe( Credits.szFontName, pKeyValue->GetString( Credits.szCreditName, "Default" ) ); +#endif m_CreditsList.AddToTail( Credits ); pKVNames = pKVNames->GetNextKey(); @@ -248,6 +287,8 @@ void CHudCredits::ReadParams( KeyValues *pKeyValue ) m_flSeparation = pKeyValue->GetFloat( "separation", 5 ); #ifdef MAPBASE m_iEndLines = pKeyValue->GetInt( "endlines", 1 ); + m_flEndLinesFadeHoldTime = pKeyValue->GetFloat( "endlines_fadeholdtime", ( IsConsole() ? 2.0f : 10.0f ) ); // "360 certification requires that we not hold a static image too long." + m_bAllowColumns = pKeyValue->GetBool( "allow_columns", false ); #endif m_flFadeInTime = pKeyValue->GetFloat( "fadeintime", 1 ); @@ -301,9 +342,41 @@ void CHudCredits::DrawOutroCreditsName( void ) continue; vgui::HScheme scheme = vgui::scheme()->GetScheme( "ClientScheme" ); - vgui::HFont m_hTFont = vgui::scheme()->GetIScheme(scheme)->GetFont( pCredit->szFontName, true ); + vgui::HFont m_hTFont = INVALID_FONT; - int iFontTall = surface()->GetFontTall ( m_hTFont ); + int iFontTall = 1; + +#ifdef MAPBASE + if (pCredit->iImageID != -1) + { + // Get the size of the tallest image if there's multiple + int iFontWide; + if (m_bAllowColumns && V_strstr( pCredit->szCreditName, "\t" )) + { + CUtlStringList outStrings; + V_SplitString( pCredit->szCreditName, "\t", outStrings ); + FOR_EACH_VEC( outStrings, i ) + { + int iTempTall; + surface()->DrawGetTextureSize( GetOrAllocateImageID( outStrings[i] ), iFontWide, iTempTall ); + if (iTempTall > iFontTall) + iFontTall = iTempTall; + } + outStrings.PurgeAndDeleteElements(); + } + else + { + surface()->DrawGetTextureSize( GetOrAllocateImageID( pCredit->szCreditName ), iFontWide, iFontTall ); + } + + iFontTall = ((float)iFontTall * pCredit->flImageScale); + } + else +#endif + { + m_hTFont = vgui::scheme()->GetIScheme( scheme )->GetFont( pCredit->szFontName, true ); + iFontTall = surface()->GetFontTall( m_hTFont ); + } if ( pCredit->flYPos < -iFontTall || pCredit->flYPos > iTall ) { @@ -317,6 +390,9 @@ void CHudCredits::DrawOutroCreditsName( void ) Color cColor = m_TextColor; #ifdef MAPBASE + if (pCredit->cColorOverride.a() > 0) + cColor = pCredit->cColorOverride; + // Some lines should stick around and fade out if ( i >= m_CreditsList.Count()-m_iEndLines ) #else @@ -333,8 +409,12 @@ void CHudCredits::DrawOutroCreditsName( void ) { m_bLastOneInPlace = true; +#ifdef MAPBASE + m_flFadeTime = gpGlobals->curtime + m_flEndLinesFadeHoldTime; +#else // 360 certification requires that we not hold a static image too long. m_flFadeTime = gpGlobals->curtime + ( IsConsole() ? 2.0f : 10.0f ); +#endif } } else @@ -364,6 +444,50 @@ void CHudCredits::DrawOutroCreditsName( void ) if ( pCredit->bActive == false ) continue; +#ifdef MAPBASE + // Credits separated by tabs should appear divided + if (m_bAllowColumns && V_strstr( pCredit->szCreditName, "\t" )) + { + CUtlStringList outStrings; + V_SplitString( pCredit->szCreditName, "\t", outStrings ); + int iDivisor = 1 + outStrings.Count(); + if (pCredit->iImageID != -1) + { + FOR_EACH_VEC( outStrings, i ) + { + int iImageID = GetOrAllocateImageID( outStrings[i] ); + + // Center the image if needed + int iImageWide, iImageTall = 1; + surface()->DrawGetTextureSize( iImageID, iImageWide, iImageTall ); + if (iImageTall < iFontTall) + { + DrawOutroCreditTexture( iImageID, pCredit->flYPos + ((iFontTall * 0.5f) - (iImageTall * 0.5f)), pCredit->flImageScale, cColor, iWidth*(i + 1), iDivisor ); + } + else + { + DrawOutroCreditTexture( iImageID, pCredit->flYPos, pCredit->flImageScale, cColor, iWidth*(i + 1), iDivisor ); + } + } + } + else + { + FOR_EACH_VEC( outStrings, i ) + { + DrawOutroCreditFont( outStrings[i], pCredit->flYPos, m_hTFont, cColor, iWidth*(i + 1), iDivisor ); + } + } + outStrings.PurgeAndDeleteElements(); + } + else if (pCredit->iImageID != -1) + { + DrawOutroCreditTexture( pCredit->iImageID, pCredit->flYPos, pCredit->flImageScale, cColor, iWidth, 2 ); + } + else + { + DrawOutroCreditFont( pCredit->szCreditName, pCredit->flYPos, m_hTFont, cColor, iWidth, 2 ); + } +#else surface()->DrawSetTextFont( m_hTFont ); surface()->DrawSetTextColor( cColor[0], cColor[1], cColor[2], cColor[3] ); @@ -382,9 +506,56 @@ void CHudCredits::DrawOutroCreditsName( void ) surface()->DrawSetTextPos( ( iWidth / 2 ) - ( iStringWidth / 2 ), pCredit->flYPos ); surface()->DrawUnicodeString( unicode ); +#endif } } +#ifdef MAPBASE +void CHudCredits::DrawOutroCreditFont( const char *pCreditName, float flYPos, vgui::HFont hTFont, const Color &cColor, int iScreenWidth, int iDivisor ) +{ + surface()->DrawSetTextFont( hTFont ); + surface()->DrawSetTextColor( cColor[0], cColor[1], cColor[2], cColor[3] ); + + wchar_t unicode[256]; + + if ( pCreditName[0] == '#' ) + { + g_pVGuiLocalize->ConstructString( unicode, sizeof(unicode), g_pVGuiLocalize->Find(pCreditName), 0 ); + } + else + { + g_pVGuiLocalize->ConvertANSIToUnicode( pCreditName, unicode, sizeof( unicode ) ); + } + + int iStringWidth = GetStringPixelWidth( unicode, hTFont ); + + // ((iScreenWidth*iMultiplier) / iDivisor) + // When needed, just multiply iScreenWidth before sending to the function + surface()->DrawSetTextPos( (iScreenWidth / iDivisor) - (iStringWidth / 2), flYPos ); + surface()->DrawUnicodeString( unicode ); +} + +void CHudCredits::DrawOutroCreditTexture( int iImageID, float flYPos, float flImageScale, const Color &cColor, int iScreenWidth, int iDivisor ) +{ + int iImageWide, iImageTall; + surface()->DrawGetTextureSize( iImageID, iImageWide, iImageTall ); + + // Scale for resolution + flImageScale *= ((float)GetTall() / 900.0f); + + iImageWide = ((float)(iImageWide) * flImageScale); + iImageTall = ((float)(iImageTall) * flImageScale); + + iImageWide /= 2; + //iImageTall /= 2; + iScreenWidth /= iDivisor; + + surface()->DrawSetColor( cColor ); + surface()->DrawSetTexture( iImageID ); + surface()->DrawTexturedRect( iScreenWidth - iImageWide, flYPos, iScreenWidth + iImageWide, flYPos + iImageTall ); +} +#endif + void CHudCredits::DrawLogo( void ) { if( m_iLogoState == LOGO_FADEOFF ) @@ -551,7 +722,15 @@ void CHudCredits::DrawIntroCreditsName( void ) float localTime = gpGlobals->curtime - pCredit->flTimeStart; surface()->DrawSetTextFont( m_hTFont ); +#ifdef MAPBASE + Color cColor = m_cColor; + if (pCredit->cColorOverride.a() > 0) + cColor = pCredit->cColorOverride; + + surface()->DrawSetTextColor( cColor[0], cColor[1], cColor[2], FadeBlend( m_flFadeInTime, m_flFadeOutTime, m_flFadeHoldTime + pCredit->flTimeAdd, localTime ) * cColor[3] ); +#else surface()->DrawSetTextColor( m_cColor[0], m_cColor[1], m_cColor[2], FadeBlend( m_flFadeInTime, m_flFadeOutTime, m_flFadeHoldTime + pCredit->flTimeAdd, localTime ) * m_cColor[3] ); +#endif wchar_t unicode[256]; g_pVGuiLocalize->ConvertANSIToUnicode( pCredit->szCreditName, unicode, sizeof( unicode ) ); @@ -693,16 +872,114 @@ void CHudCredits::PrepareOutroCredits( void ) continue; vgui::HScheme scheme = vgui::scheme()->GetScheme( "ClientScheme" ); - vgui::HFont m_hTFont = vgui::scheme()->GetIScheme(scheme)->GetFont( pCredit->szFontName, true ); - pCredit->flYPos = iHeight; - pCredit->bActive = false; +#ifdef MAPBASE + if (pCredit->szFontName[0] == '$') + { + if (V_strncmp( pCredit->szFontName + 1, "Image", 5 ) == 0) + { + if (pCredit->szFontName[6] == ';') + { + CUtlStringList outStrings; + V_SplitString( pCredit->szFontName, ";", outStrings ); + FOR_EACH_VEC( outStrings, i ) + { + switch (i) + { + // Get scale + case 1: + pCredit->flImageScale = atof( outStrings[i] ); + break; - iHeight += surface()->GetFontTall ( m_hTFont ) + m_flSeparation; + // Get color + case 2: + int tmp[4]; + UTIL_StringToIntArray( tmp, 4, outStrings[i] ); + pCredit->cColorOverride = Color( tmp[0], tmp[1], tmp[2], tmp[3] ); + break; + } + } + outStrings.PurgeAndDeleteElements(); + } - PrepareLine( m_hTFont, pCredit->szCreditName ); + // Get the size of the tallest image if there's multiple + int iFontWide, iFontTall = 1; + if (m_bAllowColumns && V_strstr( pCredit->szCreditName, "\t" )) + { + CUtlStringList outStrings; + V_SplitString( pCredit->szCreditName, "\t", outStrings ); + FOR_EACH_VEC( outStrings, i ) + { + pCredit->iImageID = GetOrAllocateImageID( outStrings[i] ); + + int iTempTall; + surface()->DrawGetTextureSize( pCredit->iImageID, iFontWide, iTempTall ); + if (iTempTall > iFontTall) + iFontTall = iTempTall; + } + outStrings.PurgeAndDeleteElements(); + } + else + { + pCredit->iImageID = GetOrAllocateImageID( pCredit->szCreditName ); + surface()->DrawGetTextureSize( pCredit->iImageID, iFontWide, iFontTall ); + } + + pCredit->flYPos = iHeight; + pCredit->bActive = false; + + iHeight += ((float)iFontTall * pCredit->flImageScale * ((float)GetTall() / 900.0f)) + m_flSeparation; + + Msg( "'%s' is image type (image scale is %f)\n", pCredit->szCreditName, pCredit->flImageScale ); + } + else + { + //Msg( "'%s' is not an image type\n", pCredit->szFontName + 1 ); + } + } + else +#endif + { +#ifdef MAPBASE + if (V_strstr( pCredit->szFontName, ";" )) + { + CUtlStringList outStrings; + V_SplitString( pCredit->szFontName, ";", outStrings ); + FOR_EACH_VEC( outStrings, i ) + { + switch (i) + { + // Get color + case 1: + int tmp[4]; + UTIL_StringToIntArray( tmp, 4, outStrings[i] ); + pCredit->cColorOverride = Color( tmp[0], tmp[1], tmp[2], tmp[3] ); + break; + } + } + + Q_strncpy( pCredit->szFontName, outStrings[0], sizeof( pCredit->szFontName ) ); + outStrings.PurgeAndDeleteElements(); + } +#endif + + vgui::HFont m_hTFont = vgui::scheme()->GetIScheme( scheme )->GetFont( pCredit->szFontName, true ); + + pCredit->flYPos = iHeight; + pCredit->bActive = false; + + iHeight += surface()->GetFontTall ( m_hTFont ) + m_flSeparation; + + PrepareLine( m_hTFont, pCredit->szCreditName ); + } } +#ifdef MAPBASE + // Check if the last line has a color override. If it does, use that as the alpha for the fadeout + if (m_CreditsList.Tail().cColorOverride.a() != 0) + m_Alpha = m_CreditsList.Tail().cColorOverride.a(); +#endif + SetActive( true ); g_iCreditsPixelHeight = iHeight; @@ -721,6 +998,29 @@ void CHudCredits::PrepareIntroCredits( void ) if ( pCredit == NULL ) continue; +#ifdef MAPBASE + if (V_strstr( pCredit->szFontName, ";" )) + { + CUtlStringList outStrings; + V_SplitString( pCredit->szFontName, ";", outStrings ); + FOR_EACH_VEC( outStrings, i ) + { + switch (i) + { + // Get color + case 1: + int tmp[4]; + UTIL_StringToIntArray( tmp, 4, outStrings[i] ); + pCredit->cColorOverride = Color( tmp[0], tmp[1], tmp[2], tmp[3] ); + break; + } + } + + Q_strncpy( pCredit->szFontName, outStrings[0], sizeof( pCredit->szFontName ) ); + outStrings.PurgeAndDeleteElements(); + } +#endif + vgui::HScheme scheme = vgui::scheme()->GetScheme( "ClientScheme" ); vgui::HFont m_hTFont = vgui::scheme()->GetIScheme(scheme)->GetFont( pCredit->szFontName ); @@ -749,6 +1049,21 @@ void CHudCredits::PrepareIntroCredits( void ) SetActive( true ); } +#ifdef MAPBASE +int CHudCredits::GetOrAllocateImageID( const char *szFileName ) +{ + int iIndex = m_ImageDict.Find( szFileName ); + if (iIndex == m_ImageDict.InvalidIndex()) + { + iIndex = surface()->CreateNewTextureID(); + m_ImageDict.Insert( szFileName, iIndex ); + surface()->DrawSetTextureFile( iIndex, szFileName, true, false ); + return iIndex; + } + return m_ImageDict[iIndex]; +} +#endif + void CHudCredits::MsgFunc_CreditsMsg( bf_read &msg ) { m_iCreditsType = msg.ReadByte(); From 0faa6d9b1aa690977b7d0ce57b741b5ef2ff0cc3 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sat, 31 Jul 2021 14:47:10 -0500 Subject: [PATCH 126/378] Added a way for commentary node progress bars and subtitles to appear at the same time --- .../game/client/c_point_commentary_node.cpp | 90 +++++++++++++++++++ sp/src/game/client/hud_closecaption.h | 9 ++ 2 files changed, 99 insertions(+) diff --git a/sp/src/game/client/c_point_commentary_node.cpp b/sp/src/game/client/c_point_commentary_node.cpp index f9e447c6..fa5f8eac 100644 --- a/sp/src/game/client/c_point_commentary_node.cpp +++ b/sp/src/game/client/c_point_commentary_node.cpp @@ -49,6 +49,8 @@ static bool g_bTracingVsCommentaryNodes = false; ConVar commentary_type_force( "commentary_type_force", "-1", FCVAR_NONE, "Forces all commentary nodes to use the specified type." ); ConVar commentary_type_text_endtime( "commentary_type_text_endtime", "120" ); ConVar commentary_type_image_endtime( "commentary_type_image_endtime", "120" ); +ConVar commentary_audio_element_below_cc( "commentary_audio_element_below_cc", "1", FCVAR_NONE, "Allows commentary audio elements to display even when CC is enabled (although this is done by inverting their Y axis)" ); +ConVar commentary_audio_element_below_cc_margin( "commentary_audio_element_below_cc_margin", "4" ); #endif //----------------------------------------------------------------------------- @@ -828,6 +830,18 @@ void CHudCommentary::Paint() if ( pHudCloseCaption ) { pHudCloseCaption->Reset(); + +#ifdef MAPBASE + // Reset close caption element if needed + if (pHudCloseCaption->IsUsingCommentaryDimensions()) + { + int ccX, ccY; + pHudCloseCaption->GetPos( ccX, ccY ); + pHudCloseCaption->SetPos( ccX, ccY + m_iTypeAudioT ); + + pHudCloseCaption->SetUsingCommentaryDimensions( false ); + } +#endif } } } @@ -840,6 +854,17 @@ void CHudCommentary::Paint() // Ensure that the scene is terminated if (m_iCommentaryType == COMMENTARY_TYPE_SCENE) m_hActiveNode->StopLoopingSounds(); + + // Reset close caption element if needed + CHudCloseCaption *pHudCloseCaption = (CHudCloseCaption *)GET_HUDELEMENT( CHudCloseCaption ); + if (pHudCloseCaption && pHudCloseCaption->IsUsingCommentaryDimensions()) + { + int ccX, ccY; + pHudCloseCaption->GetPos( ccX, ccY ); + pHudCloseCaption->SetPos( ccX, ccY + m_iTypeAudioT ); + + pHudCloseCaption->SetUsingCommentaryDimensions( false ); + } #endif m_hActiveNode = NULL; @@ -1155,6 +1180,33 @@ void CHudCommentary::StartCommentary( C_PointCommentaryNode *pNode, char *pszSpe { m_bShouldPaint = true; } + +#ifdef MAPBASE + if (!m_bShouldPaint && commentary_audio_element_below_cc.GetBool()) + { + m_bShouldPaint = true; + + // Invert the Y axis + //SetPos( m_iTypeAudioX, ScreenHeight() - m_iTypeAudioY ); + + // Place underneath the close caption element + CHudCloseCaption *pHudCloseCaption = (CHudCloseCaption *)GET_HUDELEMENT( CHudCloseCaption ); + if (pHudCloseCaption) + { + int ccX, ccY; + pHudCloseCaption->GetPos( ccX, ccY ); + ccY -= m_iTypeAudioT; + + pHudCloseCaption->SetPos( ccX, ccY - commentary_audio_element_below_cc_margin.GetInt() ); + + SetPos( ccX, ccY + pHudCloseCaption->GetTall() ); + SetWide( pHudCloseCaption->GetWide() ); + + pHudCloseCaption->SetUsingCommentaryDimensions( true ); + } + } +#endif + SetPaintBackgroundEnabled( m_bShouldPaint ); char sz[MAX_COUNT_STRING]; @@ -1332,6 +1384,31 @@ void CHudCommentary::StartSceneCommentary( C_PointCommentaryNode *pNode, char *p { m_bShouldPaint = true; } + + if (!m_bShouldPaint && commentary_audio_element_below_cc.GetBool()) + { + m_bShouldPaint = true; + + // Invert the Y axis + //SetPos( m_iTypeAudioX, ScreenHeight() - m_iTypeAudioY ); + + // Place underneath the close caption element + CHudCloseCaption *pHudCloseCaption = (CHudCloseCaption *)GET_HUDELEMENT( CHudCloseCaption ); + if (pHudCloseCaption) + { + int ccX, ccY; + pHudCloseCaption->GetPos( ccX, ccY ); + ccY -= m_iTypeAudioT; + + pHudCloseCaption->SetPos( ccX, ccY - commentary_audio_element_below_cc_margin.GetInt() ); + + SetPos( ccX, ccY + pHudCloseCaption->GetTall() ); + SetWide( pHudCloseCaption->GetWide() ); + + pHudCloseCaption->SetUsingCommentaryDimensions( true ); + } + } + SetPaintBackgroundEnabled( m_bShouldPaint ); char sz[MAX_COUNT_STRING]; @@ -1357,6 +1434,19 @@ void CHudCommentary::StartSceneCommentary( C_PointCommentaryNode *pNode, char *p void CHudCommentary::StopCommentary( void ) { m_hActiveNode = NULL; + +#ifdef MAPBASE + // Reset close caption element if needed + CHudCloseCaption *pHudCloseCaption = (CHudCloseCaption *)GET_HUDELEMENT( CHudCloseCaption ); + if (pHudCloseCaption && pHudCloseCaption->IsUsingCommentaryDimensions()) + { + int ccX, ccY; + pHudCloseCaption->GetPos( ccX, ccY ); + pHudCloseCaption->SetPos( ccX, ccY + m_iTypeAudioT ); + + pHudCloseCaption->SetUsingCommentaryDimensions( false ); + } +#endif } //----------------------------------------------------------------------------- diff --git a/sp/src/game/client/hud_closecaption.h b/sp/src/game/client/hud_closecaption.h index f89dffb3..b3bdae06 100644 --- a/sp/src/game/client/hud_closecaption.h +++ b/sp/src/game/client/hud_closecaption.h @@ -138,6 +138,11 @@ public: void FindSound( char const *pchANSI ); +#ifdef MAPBASE + inline bool IsUsingCommentaryDimensions() const { return m_bUsingCommentaryDimensions; } + inline void SetUsingCommentaryDimensions( bool bToggle ) { m_bUsingCommentaryDimensions = bToggle; } +#endif + public: struct CaptionRepeat @@ -217,6 +222,10 @@ private: bool m_bVisibleDueToDirect; bool m_bPaintDebugInfo; CUtlSymbol m_CurrentLanguage; + +#ifdef MAPBASE + bool m_bUsingCommentaryDimensions; +#endif }; #endif // HUD_CLOSECAPTION_H From 4787ce01f3695156b3d5df11a3f83d235f516dfa Mon Sep 17 00:00:00 2001 From: Matthew Date: Tue, 10 Aug 2021 23:23:24 -0700 Subject: [PATCH 127/378] Initial commit --- sp/src/utils/vbsp/staticprop.cpp | 41 ++++++++++++++++++++++++++++++++ sp/src/utils/vbsp/vbsp.cpp | 10 ++++++++ sp/src/utils/vbsp/vbsp.h | 4 ++++ 3 files changed, 55 insertions(+) diff --git a/sp/src/utils/vbsp/staticprop.cpp b/sp/src/utils/vbsp/staticprop.cpp index 6c643413..a08ab4e2 100644 --- a/sp/src/utils/vbsp/staticprop.cpp +++ b/sp/src/utils/vbsp/staticprop.cpp @@ -565,6 +565,10 @@ static void SetLumpData( ) void EmitStaticProps() { +#ifdef MAPBASE + Msg("Placing static props...\n"); +#endif + CreateInterfaceFn physicsFactory = GetPhysicsFactory(); if ( physicsFactory ) { @@ -588,13 +592,43 @@ void EmitStaticProps() for ( i = 0; i < num_entities; ++i) { char* pEntity = ValueForKey(&entities[i], "classname"); +#ifdef MAPBASE + const int iInsertAsStatic = IntForKey( &entities[i], "insertasstaticprop" ); // If the key is absent, IntForKey will return 0. + bool bInsertAsStatic = g_bPropperInsertAllAsStatic; + + // 1 = No, 2 = Yes; Any other number will just use what g_bPropperInsertAllAsStatic is set as. + if ( iInsertAsStatic == 1 ) { bInsertAsStatic = false; } + else if ( iInsertAsStatic == 2 ) { bInsertAsStatic = true; } + + if ( !strcmp( pEntity, "static_prop" ) || !strcmp( pEntity, "prop_static" ) || ( !strcmp( pEntity, "propper_model" ) && bInsertAsStatic ) ) +#else if (!strcmp(pEntity, "static_prop") || !strcmp(pEntity, "prop_static")) +#endif { StaticPropBuild_t build; GetVectorForKey( &entities[i], "origin", build.m_Origin ); GetAnglesForKey( &entities[i], "angles", build.m_Angles ); +#ifdef MAPBASE + if ( !strcmp( pEntity, "propper_model" ) ) + { + char* pModelName = ValueForKey( &entities[i], "modelname" ); + + // The modelname keyvalue lacks 'models/' at the start and '.mdl' at the end, so we have to add them. + char modelpath[MAX_VALUE]; + sprintf( modelpath, "models/%s.mdl", pModelName ); + + Msg( "Inserting propper_model (%.0f %.0f %.0f) as prop_static: %s\n", build.m_Origin[0], build.m_Origin[1], build.m_Origin[2], modelpath ); + + build.m_pModelName = modelpath; + } + else // Otherwise we just assume it's a normal prop_static + { + build.m_pModelName = ValueForKey( &entities[i], "model" ); + } +#else build.m_pModelName = ValueForKey( &entities[i], "model" ); +#endif build.m_Solid = IntForKey( &entities[i], "solid" ); build.m_Skin = IntForKey( &entities[i], "skin" ); build.m_FadeMaxDist = FloatForKey( &entities[i], "fademaxdist" ); @@ -651,6 +685,13 @@ void EmitStaticProps() // strip this ent from the .bsp file entities[i].epairs = 0; } +#ifdef MAPBASE + else if ( g_bPropperStripEntities && !strncmp( pEntity, "propper_", 8 ) ) // Strip out any entities with 'propper_' in their classname, as they don't actually exist in-game. + { + Warning( "Not including %s in BSP compile due to it being a propper entity that isn't used in-game.\n", pEntity ); + entities[i].epairs = 0; + } +#endif } // Strip out lighting origins; has to be done here because they are used when diff --git a/sp/src/utils/vbsp/vbsp.cpp b/sp/src/utils/vbsp/vbsp.cpp index 21b9db84..75722bfe 100644 --- a/sp/src/utils/vbsp/vbsp.cpp +++ b/sp/src/utils/vbsp/vbsp.cpp @@ -69,6 +69,8 @@ bool g_bNoHiddenManifestMaps = false; #ifdef MAPBASE bool g_bNoDefaultCubemaps = true; bool g_bSkyboxCubemaps = false; +bool g_bPropperInsertAllAsStatic = false; +bool g_bPropperStripEntities = false; int g_iDefaultCubemapSize = 32; #endif #ifdef MAPBASE_VSCRIPT @@ -1193,6 +1195,14 @@ int RunVBSP( int argc, char **argv ) Msg( "Default cubemap size = %i\n", g_iDefaultCubemapSize ); i++; } + else if ( !Q_stricmp( argv[i], "-defaultproppermodelsstatic" ) ) + { + g_bPropperInsertAllAsStatic = true; + } + else if ( !Q_stricmp( argv[i], "-strippropperentities" ) ) + { + g_bPropperStripEntities = true; + } #endif #ifdef MAPBASE_VSCRIPT else if ( !Q_stricmp( argv[i], "-scripting" ) ) diff --git a/sp/src/utils/vbsp/vbsp.h b/sp/src/utils/vbsp/vbsp.h index 3e9f44c0..27dd9553 100644 --- a/sp/src/utils/vbsp/vbsp.h +++ b/sp/src/utils/vbsp/vbsp.h @@ -401,6 +401,10 @@ extern bool g_DisableWaterLighting; extern bool g_bAllowDetailCracks; extern bool g_bNoVirtualMesh; extern bool g_bNoHiddenManifestMaps; +#ifdef MAPBASE +extern bool g_bPropperInsertAllAsStatic; +extern bool g_bPropperStripEntities; +#endif extern char outbase[32]; extern char source[1024]; From cbdc3b4de8ac15f5ef1815fa24de9d0f74561827 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sat, 18 Sep 2021 11:46:46 -0500 Subject: [PATCH 128/378] Added a way for commentary nodes to combine the speaker and print name so that the print name can be displayed to players --- .../game/client/c_point_commentary_node.cpp | 144 +++++++++++++----- sp/src/game/server/CommentarySystem.cpp | 3 + 2 files changed, 106 insertions(+), 41 deletions(-) diff --git a/sp/src/game/client/c_point_commentary_node.cpp b/sp/src/game/client/c_point_commentary_node.cpp index fa5f8eac..68516ba3 100644 --- a/sp/src/game/client/c_point_commentary_node.cpp +++ b/sp/src/game/client/c_point_commentary_node.cpp @@ -51,6 +51,7 @@ ConVar commentary_type_text_endtime( "commentary_type_text_endtime", "120" ); ConVar commentary_type_image_endtime( "commentary_type_image_endtime", "120" ); ConVar commentary_audio_element_below_cc( "commentary_audio_element_below_cc", "1", FCVAR_NONE, "Allows commentary audio elements to display even when CC is enabled (although this is done by inverting their Y axis)" ); ConVar commentary_audio_element_below_cc_margin( "commentary_audio_element_below_cc_margin", "4" ); +ConVar commentary_combine_speaker_and_printname( "commentary_combine_speaker_and_printname", "1" ); #endif //----------------------------------------------------------------------------- @@ -76,6 +77,11 @@ public: void StopCommentary( void ); bool IsTheActiveNode( C_PointCommentaryNode *pNode ) { return (pNode == m_hActiveNode); } +#ifdef MAPBASE + void CombineSpeakerAndPrintName( const char *pszPrintName ); + void RepositionCloseCaption(); +#endif + // vgui overrides virtual void Paint( void ); virtual bool ShouldDraw( void ); @@ -222,6 +228,11 @@ public: { int iRenderGroup = gHUD.LookupRenderGroupIndexByName( "commentary" ); gHUD.LockRenderGroup( iRenderGroup ); + +#ifdef MAPBASE + // Special commentary localization file (useful for things like text nodes or print names) + g_pVGuiLocalize->AddFile( "resource/commentary_%language%.txt" ); +#endif } if ( g_CommentaryNodes.Find(this) == g_CommentaryNodes.InvalidIndex() ) @@ -255,6 +266,7 @@ public: EHANDLE m_hViewPosition; bool m_bRestartAfterRestore; #ifdef MAPBASE + char m_iszPrintName[MAX_SPEAKER_NAME]; int m_iCommentaryType; float m_flPanelScale; float m_flPanelX; @@ -276,6 +288,7 @@ IMPLEMENT_CLIENTCLASS_DT(C_PointCommentaryNode, DT_PointCommentaryNode, CPointCo RecvPropInt( RECVINFO( m_iNodeNumberMax ) ), RecvPropEHandle( RECVINFO(m_hViewPosition) ), #ifdef MAPBASE + RecvPropString( RECVINFO( m_iszPrintName ) ), RecvPropInt( RECVINFO( m_iCommentaryType ) ), RecvPropFloat( RECVINFO( m_flPanelScale ) ), RecvPropFloat( RECVINFO( m_flPanelX ) ), @@ -411,6 +424,7 @@ void C_PointCommentaryNode::StartAudioCommentary( const char *pszCommentaryFile, // Get the duration so we know when it finishes float flDuration = enginesound->GetSoundDuration( STRING( CSoundEnvelopeController::GetController().SoundGetName( m_sndCommentary ) ) ) ; + bool bSubtitlesEnabled = false; CHudCloseCaption *pHudCloseCaption = (CHudCloseCaption *)GET_HUDELEMENT( CHudCloseCaption ); if ( pHudCloseCaption ) @@ -427,12 +441,16 @@ void C_PointCommentaryNode::StartAudioCommentary( const char *pszCommentaryFile, // Find the close caption hud element & lock it pHudCloseCaption->Lock(); + + bSubtitlesEnabled = true; } } + char *pszSpeakers = m_iszSpeakers; + // Tell the HUD element CHudCommentary *pHudCommentary = (CHudCommentary *)GET_HUDELEMENT( CHudCommentary ); - pHudCommentary->StartCommentary( this, m_iszSpeakers, m_iNodeNumber, m_iNodeNumberMax, m_flStartTime, m_flStartTime + flDuration ); + pHudCommentary->StartCommentary( this, pszSpeakers, m_iNodeNumber, m_iNodeNumberMax, m_flStartTime, m_flStartTime + flDuration ); } #ifdef MAPBASE @@ -921,9 +939,9 @@ void CHudCommentary::Paint() { // Draw the progress bar vgui::surface()->DrawSetColor( clr ); - vgui::surface()->DrawOutlinedRect( xOffset, yOffset, xOffset+m_iBarWide, yOffset+m_iBarTall ); + vgui::surface()->DrawOutlinedRect( xOffset, yOffset, xOffset+(m_iBarWide*m_flPanelScale), yOffset+m_iBarTall ); vgui::surface()->DrawSetColor( clr ); - vgui::surface()->DrawFilledRect( xOffset+2, yOffset+2, xOffset+(int)(flPercentage*m_iBarWide)-2, yOffset+m_iBarTall-2 ); + vgui::surface()->DrawFilledRect( xOffset+2, yOffset+2, xOffset+(int)(flPercentage*(m_iBarWide*m_flPanelScale))-2, yOffset+m_iBarTall-2 ); } break; } #else @@ -1182,28 +1200,15 @@ void CHudCommentary::StartCommentary( C_PointCommentaryNode *pNode, char *pszSpe } #ifdef MAPBASE + if (commentary_combine_speaker_and_printname.GetBool() && pNode && pNode->m_iszPrintName[0] != '\0') + { + CombineSpeakerAndPrintName( pNode->m_iszPrintName ); + } + if (!m_bShouldPaint && commentary_audio_element_below_cc.GetBool()) { m_bShouldPaint = true; - - // Invert the Y axis - //SetPos( m_iTypeAudioX, ScreenHeight() - m_iTypeAudioY ); - - // Place underneath the close caption element - CHudCloseCaption *pHudCloseCaption = (CHudCloseCaption *)GET_HUDELEMENT( CHudCloseCaption ); - if (pHudCloseCaption) - { - int ccX, ccY; - pHudCloseCaption->GetPos( ccX, ccY ); - ccY -= m_iTypeAudioT; - - pHudCloseCaption->SetPos( ccX, ccY - commentary_audio_element_below_cc_margin.GetInt() ); - - SetPos( ccX, ccY + pHudCloseCaption->GetTall() ); - SetWide( pHudCloseCaption->GetWide() ); - - pHudCloseCaption->SetUsingCommentaryDimensions( true ); - } + RepositionCloseCaption(); } #endif @@ -1269,6 +1274,12 @@ void CHudCommentary::StartTextCommentary( C_PointCommentaryNode *pNode, const ch m_pImage->EvictImage(); m_bShouldPaint = true; + + if (commentary_combine_speaker_and_printname.GetBool() && pNode && pNode->m_iszPrintName[0] != '\0') + { + CombineSpeakerAndPrintName( pNode->m_iszPrintName ); + } + SetPaintBackgroundEnabled( m_bShouldPaint ); char sz[MAX_COUNT_STRING]; @@ -1323,6 +1334,12 @@ void CHudCommentary::StartImageCommentary( C_PointCommentaryNode *pNode, const c } m_bShouldPaint = true; + + if (commentary_combine_speaker_and_printname.GetBool() && pNode && pNode->m_iszPrintName[0] != '\0') + { + CombineSpeakerAndPrintName( pNode->m_iszPrintName ); + } + SetPaintBackgroundEnabled( m_bShouldPaint ); char sz[MAX_COUNT_STRING]; @@ -1385,28 +1402,15 @@ void CHudCommentary::StartSceneCommentary( C_PointCommentaryNode *pNode, char *p m_bShouldPaint = true; } + if (commentary_combine_speaker_and_printname.GetBool() && pNode && pNode->m_iszPrintName[0] != '\0') + { + CombineSpeakerAndPrintName( pNode->m_iszPrintName ); + } + if (!m_bShouldPaint && commentary_audio_element_below_cc.GetBool()) { m_bShouldPaint = true; - - // Invert the Y axis - //SetPos( m_iTypeAudioX, ScreenHeight() - m_iTypeAudioY ); - - // Place underneath the close caption element - CHudCloseCaption *pHudCloseCaption = (CHudCloseCaption *)GET_HUDELEMENT( CHudCloseCaption ); - if (pHudCloseCaption) - { - int ccX, ccY; - pHudCloseCaption->GetPos( ccX, ccY ); - ccY -= m_iTypeAudioT; - - pHudCloseCaption->SetPos( ccX, ccY - commentary_audio_element_below_cc_margin.GetInt() ); - - SetPos( ccX, ccY + pHudCloseCaption->GetTall() ); - SetWide( pHudCloseCaption->GetWide() ); - - pHudCloseCaption->SetUsingCommentaryDimensions( true ); - } + RepositionCloseCaption(); } SetPaintBackgroundEnabled( m_bShouldPaint ); @@ -1449,6 +1453,64 @@ void CHudCommentary::StopCommentary( void ) #endif } +#ifdef MAPBASE +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudCommentary::CombineSpeakerAndPrintName( const char *pszPrintName ) +{ + wchar_t *pszLocal = g_pVGuiLocalize->Find( pszPrintName ); + if (m_szSpeakers[0] == '\0' || !m_bShouldPaint) // Use m_bShouldPaint as an indicator of whether or not we use subtitles + { + if (pszPrintName[0] == '#' && pszLocal) + wcsncpy( m_szSpeakers, pszLocal, sizeof( m_szSpeakers ) / sizeof( wchar_t ) ); + else + g_pVGuiLocalize->ConvertANSIToUnicode( pszPrintName, m_szSpeakers, sizeof( m_szSpeakers ) ); + } + else + { + static wchar_t iszPrintNameLocalized[MAX_SPEAKER_NAME]; + + if (pszPrintName[0] == '#' && pszLocal) + wcsncpy( iszPrintNameLocalized, pszLocal, sizeof( iszPrintNameLocalized ) / sizeof( wchar_t ) ); + else + g_pVGuiLocalize->ConvertANSIToUnicode( pszPrintName, iszPrintNameLocalized, sizeof( iszPrintNameLocalized ) ); + + V_snwprintf( m_szSpeakers, sizeof( m_szSpeakers ), L"%ls ~ %ls", m_szSpeakers, iszPrintNameLocalized ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudCommentary::RepositionCloseCaption() +{ + // Invert the Y axis + //SetPos( m_iTypeAudioX, ScreenHeight() - m_iTypeAudioY ); + + // Place underneath the close caption element + CHudCloseCaption *pHudCloseCaption = (CHudCloseCaption *)GET_HUDELEMENT( CHudCloseCaption ); + if (pHudCloseCaption) + { + int ccX, ccY; + pHudCloseCaption->GetPos( ccX, ccY ); + + if (!pHudCloseCaption->IsUsingCommentaryDimensions()) + { + ccY -= m_iTypeAudioT; + pHudCloseCaption->SetPos( ccX, ccY ); + } + + SetPos( ccX, ccY + pHudCloseCaption->GetTall() + commentary_audio_element_below_cc_margin.GetInt() ); + + m_flPanelScale = (float)pHudCloseCaption->GetWide() / (float)GetWide(); + SetWide( pHudCloseCaption->GetWide() ); + + pHudCloseCaption->SetUsingCommentaryDimensions( true ); + } +} +#endif + //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- diff --git a/sp/src/game/server/CommentarySystem.cpp b/sp/src/game/server/CommentarySystem.cpp index 0ddb48b4..378ccc04 100644 --- a/sp/src/game/server/CommentarySystem.cpp +++ b/sp/src/game/server/CommentarySystem.cpp @@ -135,6 +135,7 @@ private: float m_flViewTargetSpeedScale; float m_flViewPositionSpeedScale; float m_flReturnSpeedScale; + CNetworkVar( string_t, m_iszPrintName ); #endif bool m_bPreventMovement; bool m_bUnderCrosshair; @@ -194,6 +195,7 @@ BEGIN_DATADESC( CPointCommentaryNode ) DEFINE_KEYFIELD( m_flViewTargetSpeedScale, FIELD_FLOAT, "viewtarget_speed" ), DEFINE_KEYFIELD( m_flViewPositionSpeedScale, FIELD_FLOAT, "viewposition_speed" ), DEFINE_KEYFIELD( m_flReturnSpeedScale, FIELD_FLOAT, "return_speed" ), + DEFINE_KEYFIELD( m_iszPrintName, FIELD_STRING, "printname" ), DEFINE_KEYFIELD( m_iCommentaryType, FIELD_INTEGER, "type" ), DEFINE_KEYFIELD( m_flPanelScale, FIELD_FLOAT, "panelscale" ), DEFINE_KEYFIELD( m_flPanelX, FIELD_FLOAT, "x" ), @@ -226,6 +228,7 @@ IMPLEMENT_SERVERCLASS_ST( CPointCommentaryNode, DT_PointCommentaryNode ) SendPropInt( SENDINFO(m_iNodeNumberMax), 8, SPROP_UNSIGNED ), SendPropEHandle( SENDINFO(m_hViewPosition) ), #ifdef MAPBASE + SendPropStringT( SENDINFO( m_iszPrintName ) ), SendPropInt( SENDINFO( m_iCommentaryType ), 2, SPROP_UNSIGNED ), SendPropFloat( SENDINFO( m_flPanelScale ) ), SendPropFloat( SENDINFO( m_flPanelX ) ), From 0b96d525d5f9940f2bf179d8e39eb4f54678a9dd Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sat, 18 Sep 2021 11:48:24 -0500 Subject: [PATCH 129/378] New "custom font" command for closed captioning/subtitles --- sp/src/game/client/hud_closecaption.cpp | 55 +++++++++++++++++++++---- 1 file changed, 46 insertions(+), 9 deletions(-) diff --git a/sp/src/game/client/hud_closecaption.cpp b/sp/src/game/client/hud_closecaption.cpp index 110f8b32..9b9c0c11 100644 --- a/sp/src/game/client/hud_closecaption.cpp +++ b/sp/src/game/client/hud_closecaption.cpp @@ -1612,6 +1612,9 @@ struct WorkUnitParams clr = Color( 255, 255, 255, 255 ); newline = false; font = 0; +#ifdef MAPBASE + customFont = false; +#endif } ~WorkUnitParams() @@ -1657,6 +1660,9 @@ struct WorkUnitParams Color clr; bool newline; vgui::HFont font; +#ifdef MAPBASE + bool customFont; +#endif }; void CHudCloseCaption::AddWorkUnit( CCloseCaptionItem *item, @@ -1771,27 +1777,58 @@ void CHudCloseCaption::ComputeStreamWork( int available_width, CCloseCaptionItem { AddWorkUnit( item, params ); params.italic = !params.italic; +#ifdef MAPBASE + params.customFont = false; +#endif } else if ( !wcscmp( cmd, L"B" ) ) { AddWorkUnit( item, params ); params.bold = !params.bold; +#ifdef MAPBASE + params.customFont = false; +#endif } +#ifdef MAPBASE + else if ( !wcscmp( cmd, L"font" ) ) + { + AddWorkUnit( item, params ); + vgui::IScheme *pScheme = vgui::scheme()->GetIScheme( GetScheme() ); + + if ( args[0] != 0 ) + { + char font[64]; + g_pVGuiLocalize->ConvertUnicodeToANSI( args, font, sizeof( font ) ); + params.font = pScheme->GetFont( font ); + params.customFont = true; + } + else + { + params.customFont = false; + } + } +#endif continue; } - int font; - if ( IsPC() ) + vgui::HFont useF = params.font; +#ifdef MAPBASE + if (params.customFont == false) +#endif { - font = params.GetFontNumber(); + int font; + if ( IsPC() ) + { + font = params.GetFontNumber(); + } + else + { + font = streamlen >= cc_smallfontlength.GetInt() ? CCFONT_SMALL : CCFONT_NORMAL; + } + useF = m_hFonts[font]; + params.font = useF; } - else - { - font = streamlen >= cc_smallfontlength.GetInt() ? CCFONT_SMALL : CCFONT_NORMAL; - } - vgui::HFont useF = m_hFonts[font]; - params.font = useF; int w, h; From e27f4df8e58c32a1560d72e3e0e6c80303193024 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sat, 18 Sep 2021 13:06:15 -0500 Subject: [PATCH 130/378] Added support for map-specific client schemes --- .../game/client/c_point_commentary_node.cpp | 8 ++-- sp/src/game/client/hl2/hud_credits.cpp | 22 ++++++++++- sp/src/game/shared/mapbase/mapbase_shared.cpp | 39 +++++++++++++++++-- sp/src/vgui2/vgui_controls/Panel.cpp | 31 ++++++++++++--- 4 files changed, 87 insertions(+), 13 deletions(-) diff --git a/sp/src/game/client/c_point_commentary_node.cpp b/sp/src/game/client/c_point_commentary_node.cpp index 68516ba3..76e753d7 100644 --- a/sp/src/game/client/c_point_commentary_node.cpp +++ b/sp/src/game/client/c_point_commentary_node.cpp @@ -1180,7 +1180,7 @@ void CHudCommentary::StartCommentary( C_PointCommentaryNode *pNode, char *pszSpe m_pImage->EvictImage(); // Get our scheme and font information - vgui::HScheme scheme = vgui::scheme()->GetScheme( "ClientScheme" ); + vgui::HScheme scheme = GetScheme(); m_hFont = vgui::scheme()->GetIScheme(scheme)->GetFont( "CommentaryDefault" ); if ( !m_hFont ) { @@ -1253,7 +1253,7 @@ void CHudCommentary::StartTextCommentary( C_PointCommentaryNode *pNode, const ch SetBgColor( m_bUseScriptBGColor ? m_BGOverrideColor : m_TextBackgroundColor ); // Get our scheme and font information - vgui::HScheme scheme = vgui::scheme()->GetScheme( "ClientScheme" ); + vgui::HScheme scheme = GetScheme(); m_hFont = vgui::scheme()->GetIScheme(scheme)->GetFont( "CommentaryDefault" ); if ( !m_hFont ) { @@ -1326,7 +1326,7 @@ void CHudCommentary::StartImageCommentary( C_PointCommentaryNode *pNode, const c m_pImage->SetWide( m_iBarWide - m_iTextBorderSpace ); // Get our scheme and font information - vgui::HScheme scheme = vgui::scheme()->GetScheme( "ClientScheme" ); + vgui::HScheme scheme = GetScheme(); m_hFont = vgui::scheme()->GetIScheme(scheme)->GetFont( "CommentaryDefault" ); if ( !m_hFont ) { @@ -1384,7 +1384,7 @@ void CHudCommentary::StartSceneCommentary( C_PointCommentaryNode *pNode, char *p m_pImage->EvictImage(); // Get our scheme and font information - vgui::HScheme scheme = vgui::scheme()->GetScheme( "ClientScheme" ); + vgui::HScheme scheme = GetScheme(); m_hFont = vgui::scheme()->GetIScheme(scheme)->GetFont( "CommentaryDefault" ); if ( !m_hFont ) { diff --git a/sp/src/game/client/hl2/hud_credits.cpp b/sp/src/game/client/hl2/hud_credits.cpp index b9760712..6520e6b4 100644 --- a/sp/src/game/client/hl2/hud_credits.cpp +++ b/sp/src/game/client/hl2/hud_credits.cpp @@ -341,7 +341,11 @@ void CHudCredits::DrawOutroCreditsName( void ) if ( pCredit == NULL ) continue; +#ifdef MAPBASE + vgui::HScheme scheme = GetScheme(); +#else vgui::HScheme scheme = vgui::scheme()->GetScheme( "ClientScheme" ); +#endif vgui::HFont m_hTFont = INVALID_FONT; int iFontTall = 1; @@ -635,7 +639,11 @@ void CHudCredits::DrawLogo( void ) Q_snprintf( szLogoFont, sizeof( szLogoFont ), "WeaponIcons" ); } +#ifdef MAPBASE + vgui::HScheme scheme = GetScheme(); +#else vgui::HScheme scheme = vgui::scheme()->GetScheme( "ClientScheme" ); +#endif vgui::HFont m_hTFont = vgui::scheme()->GetIScheme(scheme)->GetFont( szLogoFont ); int iFontTall = surface()->GetFontTall ( m_hTFont ); @@ -715,8 +723,12 @@ void CHudCredits::DrawIntroCreditsName( void ) if ( pCredit->bActive == false ) continue; - + +#ifdef MAPBASE + vgui::HScheme scheme = GetScheme(); +#else vgui::HScheme scheme = vgui::scheme()->GetScheme( "ClientScheme" ); +#endif vgui::HFont m_hTFont = vgui::scheme()->GetIScheme(scheme)->GetFont( pCredit->szFontName ); float localTime = gpGlobals->curtime - pCredit->flTimeStart; @@ -871,7 +883,11 @@ void CHudCredits::PrepareOutroCredits( void ) if ( pCredit == NULL ) continue; +#ifdef MAPBASE + vgui::HScheme scheme = GetScheme(); +#else vgui::HScheme scheme = vgui::scheme()->GetScheme( "ClientScheme" ); +#endif #ifdef MAPBASE if (pCredit->szFontName[0] == '$') @@ -1021,7 +1037,11 @@ void CHudCredits::PrepareIntroCredits( void ) } #endif +#ifdef MAPBASE + vgui::HScheme scheme = GetScheme(); +#else vgui::HScheme scheme = vgui::scheme()->GetScheme( "ClientScheme" ); +#endif vgui::HFont m_hTFont = vgui::scheme()->GetIScheme(scheme)->GetFont( pCredit->szFontName ); pCredit->flYPos = m_flY + ( iSlot * surface()->GetFontTall ( m_hTFont ) ); diff --git a/sp/src/game/shared/mapbase/mapbase_shared.cpp b/sp/src/game/shared/mapbase/mapbase_shared.cpp index 49d914f7..3e776861 100644 --- a/sp/src/game/shared/mapbase/mapbase_shared.cpp +++ b/sp/src/game/shared/mapbase/mapbase_shared.cpp @@ -23,6 +23,7 @@ #include "panelmetaclassmgr.h" #include "c_soundscape.h" #include "hud_macros.h" +#include "clientmode_shared.h" #else #include "soundscape_system.h" #include "AI_ResponseSystem.h" @@ -66,6 +67,8 @@ static bool g_bMapContainsCustomTalker; // This constant should change with each Mapbase update ConVar mapbase_version_client( "mapbase_version_client", MAPBASE_VERSION, FCVAR_NONE, "The version of Mapbase currently being used in this mod's client.dll" ); +// This is from the vgui_controls library +extern vgui::HScheme g_iCustomClientSchemeOverride; #endif extern void AddSurfacepropFile( const char *pFileName, IPhysicsSurfaceProps *pProps, IFileSystem *pFileSystem ); @@ -86,6 +89,7 @@ enum #ifdef CLIENT_DLL MANIFEST_CLOSECAPTION, MANIFEST_VGUI, + MANIFEST_CLIENTSCHEME, #else MANIFEST_TALKER, //MANIFEST_SENTENCES, @@ -112,16 +116,17 @@ struct ManifestType_t // KEEP THS IN SYNC WITH THE ENUM! static const ManifestType_t gm_szManifestFileStrings[MANIFEST_NUM_TYPES] = { - { "soundscripts", "mapbase_load_soundscripts", "Should we load map-specific soundscripts? e.g. \"maps/_level_sounds.txt\"" }, - //{ "propdata", "mapbase_load_propdata", "Should we load map-specific soundscripts? e.g. \"maps/_level_sounds.txt\"" }, + { "soundscripts", "mapbase_load_soundscripts", "Should we load map-specific soundscripts? e.g. \"maps/_level_sounds.txt\"" }, + //{ "propdata", "mapbase_load_propdata", "Should we load map-specific soundscripts? e.g. \"maps/_level_sounds.txt\"" }, //{ "soundscapes", "mapbase_load_soundscapes", "Should we load map-specific soundscapes? e.g. \"maps/_soundscapes.txt\"" }, { "localization", "mapbase_load_localization", "Should we load map-specific localized text files? e.g. \"maps/_english.txt\"" }, { "surfaceprops", "mapbase_load_surfaceprops", "Should we load map-specific surfaceproperties files? e.g. \"maps/_surfaceproperties.txt\"" }, #ifdef CLIENT_DLL { "closecaption", "mapbase_load_closecaption", "Should we load map-specific closed captioning? e.g. \"maps/_closecaption_english.txt\" and \"maps/_closecaption_english.dat\"" }, { "vgui", "mapbase_load_vgui", "Should we load map-specific VGUI screens? e.g. \"maps/_screens.txt\"" }, + { "clientscheme", "mapbase_load_clientscheme", "Should we load map-specific ClientScheme.res overrides? e.g. \"maps/_clientscheme.res\"" }, #else - { "talker", "mapbase_load_talker", "Should we load map-specific talker files? e.g. \"maps/_talker.txt\"" }, + { "talker", "mapbase_load_talker", "Should we load map-specific talker files? e.g. \"maps/_talker.txt\"" }, //{ "sentences", "mapbase_load_sentences", "Should we load map-specific sentences? e.g. \"maps/_sentences.txt\"" }, { "actbusy", "mapbase_load_actbusy", "Should we load map-specific actbusy files? e.g. \"maps/_actbusy.txt\"" }, #endif @@ -259,6 +264,20 @@ public: { hudCloseCaption->RemoveCaptionDictionary( m_CloseCaptionFileNames[i] ); } + + if (g_iCustomClientSchemeOverride != 0) + { + // TODO: We currently have no way of actually cleaning up custom schemes upon level unload. + // That may or may not be sustainable if there's a ton of custom schemes loaded at once + g_iCustomClientSchemeOverride = 0; + + // Reload scheme + ClientModeShared *mode = ( ClientModeShared * )GetClientModeNormal(); + if ( mode ) + { + mode->ReloadScheme(); + } + } #endif } @@ -331,6 +350,19 @@ public: m_bInitializedRTs = false; } } + + // Custom scheme loading + void LoadCustomScheme( const char *pszFile ) + { + g_iCustomClientSchemeOverride = vgui::scheme()->LoadSchemeFromFile( pszFile, "CustomClientScheme" ); + + // Reload scheme + ClientModeShared *mode = ( ClientModeShared * )GetClientModeNormal(); + if ( mode ) + { + mode->ReloadScheme(); + } + } #endif // Get a generic, hardcoded manifest with hardcoded names. @@ -389,6 +421,7 @@ public: (GET_HUDELEMENT( CHudCloseCaption ))->AddCustomCaptionFile( value, m_CloseCaptionFileNames ); } break; case MANIFEST_VGUI: { PanelMetaClassMgr()->LoadMetaClassDefinitionFile( value ); } break; + case MANIFEST_CLIENTSCHEME: { LoadCustomScheme( value ); } break; //case MANIFEST_SOUNDSCAPES: { Soundscape_AddFile(value); } break; #else case MANIFEST_TALKER: { diff --git a/sp/src/vgui2/vgui_controls/Panel.cpp b/sp/src/vgui2/vgui_controls/Panel.cpp index 499296d9..18526ac7 100644 --- a/sp/src/vgui2/vgui_controls/Panel.cpp +++ b/sp/src/vgui2/vgui_controls/Panel.cpp @@ -64,6 +64,13 @@ static char *CopyString( const char *in ) return n; } +#ifdef MAPBASE +ConVar vgui_mapbase_custom_schemes( "vgui_mapbase_custom_schemes", "1" ); + +// This is used in mapbase_shared.cpp +HScheme g_iCustomClientSchemeOverride; +#endif + #if defined( VGUI_USEDRAGDROP ) //----------------------------------------------------------------------------- // Purpose: @@ -1612,17 +1619,31 @@ void Panel::DeletePanel() //----------------------------------------------------------------------------- HScheme Panel::GetScheme() { + HScheme iScheme; + if (m_iScheme) { - return m_iScheme; // return our internal scheme + iScheme = m_iScheme; // return our internal scheme } - - if (GetVParent()) // recurse down the heirarchy + else if (GetVParent()) // recurse down the heirarchy { - return ipanel()->GetScheme(GetVParent()); + iScheme = ipanel()->GetScheme(GetVParent()); + } + else + { + iScheme = scheme()->GetDefaultScheme(); } - return scheme()->GetDefaultScheme(); +#ifdef MAPBASE + // If a custom client scheme is available, use the custom scheme. + // TODO: Need a better way to detect that this panel actually uses ClientScheme.res + if (g_iCustomClientSchemeOverride != 0 && iScheme == scheme()->GetScheme( "ClientScheme" ) && vgui_mapbase_custom_schemes.GetBool()) + { + return g_iCustomClientSchemeOverride; + } +#endif + + return iScheme; } //----------------------------------------------------------------------------- From 80251f67ec6a55e45ce418dd5294bf36cbdfd366 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sat, 18 Sep 2021 18:31:29 -0500 Subject: [PATCH 131/378] Fixed metrocops not speaking standoff sentences correctly --- sp/src/game/server/ai_behavior_standoff.cpp | 18 ++++++++++++++++++ sp/src/game/server/hl2/npc_metropolice.cpp | 7 ++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/sp/src/game/server/ai_behavior_standoff.cpp b/sp/src/game/server/ai_behavior_standoff.cpp index 0792df23..bc5244ef 100644 --- a/sp/src/game/server/ai_behavior_standoff.cpp +++ b/sp/src/game/server/ai_behavior_standoff.cpp @@ -240,6 +240,23 @@ void CAI_StandoffBehavior::SetActive( bool fActive ) { if ( fActive != m_fActive ) { +#ifdef MAPBASE + // These sentences are only spoken if the standoff behavior is active, so they have to be arranged separately + if ( fActive ) + { + m_fActive = fActive; + NotifyChangeBehaviorStatus(); + + GetOuter()->SpeakSentence( STANDOFF_SENTENCE_BEGIN_STANDOFF ); + } + else + { + GetOuter()->SpeakSentence( STANDOFF_SENTENCE_END_STANDOFF ); + + m_fActive = fActive; + NotifyChangeBehaviorStatus(); + } +#else if ( fActive ) { GetOuter()->SpeakSentence( STANDOFF_SENTENCE_BEGIN_STANDOFF ); @@ -251,6 +268,7 @@ void CAI_StandoffBehavior::SetActive( bool fActive ) m_fActive = fActive; NotifyChangeBehaviorStatus(); +#endif } } diff --git a/sp/src/game/server/hl2/npc_metropolice.cpp b/sp/src/game/server/hl2/npc_metropolice.cpp index bf56dc78..8f708b6e 100644 --- a/sp/src/game/server/hl2/npc_metropolice.cpp +++ b/sp/src/game/server/hl2/npc_metropolice.cpp @@ -882,7 +882,7 @@ void CNPC_MetroPolice::SpeakStandoffSentence( int nSentenceType ) break; case STANDOFF_SENTENCE_FORCED_TAKE_COVER: - SpeakIfAllowed( TLK_COP_SO_END ); + SpeakIfAllowed( TLK_COP_SO_FORCE_COVER ); break; case STANDOFF_SENTENCE_STAND_CHECK_TARGET: @@ -1008,7 +1008,12 @@ void CNPC_MetroPolice::SpeakSentence( int nSentenceType ) return; } +#ifdef MAPBASE + // Fixed issues with standoff sentences not playing when they should + if ( m_StandoffBehavior.IsActive() ) +#else if ( GetRunningBehavior() == &m_StandoffBehavior ) +#endif { SpeakStandoffSentence( nSentenceType ); return; From ca80915b54306c9df4422d100f9157f12fa462e3 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sat, 18 Sep 2021 18:42:56 -0500 Subject: [PATCH 132/378] Fix for citizens not aiming the RPG laser dot correctly --- sp/src/game/server/hl2/npc_citizen17.cpp | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/sp/src/game/server/hl2/npc_citizen17.cpp b/sp/src/game/server/hl2/npc_citizen17.cpp index 07ba67da..e0f39577 100644 --- a/sp/src/game/server/hl2/npc_citizen17.cpp +++ b/sp/src/game/server/hl2/npc_citizen17.cpp @@ -1932,12 +1932,7 @@ void CNPC_Citizen::RunTask( const Task_t *pTask ) return; } // Add imprecision to avoid obvious robotic perfection stationary targets -#ifdef MAPBASE - // More imprecision with low-accuracy citizens - float imprecision = 18*sin(gpGlobals->curtime) + cosh(GetCurrentWeaponProficiency() - 4); -#else float imprecision = 18*sin(gpGlobals->curtime); -#endif vecLaserPos.x += imprecision; vecLaserPos.y += imprecision; vecLaserPos.z += imprecision; @@ -2278,25 +2273,21 @@ bool CNPC_Citizen::IsManhackMeleeCombatant() //----------------------------------------------------------------------------- Vector CNPC_Citizen::GetActualShootPosition( const Vector &shootOrigin ) { -#ifdef MAPBASE - // The code below is probably broken. If not, it definitely isn't very effective. - return BaseClass::GetActualShootPosition( shootOrigin ); -#else Vector vecTarget = BaseClass::GetActualShootPosition( shootOrigin ); #ifdef MAPBASE - // If we're firing an RPG at a gunship, aim off to it's side, because we'll auger towards it. + // The gunship RPG code does not appear to be funcitonal, so only set the laser position. if ( GetActiveWeapon() && EntIsClass(GetActiveWeapon(), gm_isz_class_RPG) && GetEnemy() ) { CWeaponRPG *pRPG = static_cast(GetActiveWeapon()); - if ( EntIsClass( GetEnemy(), gm_isz_class_Gunship ) ) + pRPG->SetNPCLaserPosition( vecTarget ); + } #else CWeaponRPG *pRPG = dynamic_cast(GetActiveWeapon()); // If we're firing an RPG at a gunship, aim off to it's side, because we'll auger towards it. if ( pRPG && GetEnemy() ) { if ( FClassnameIs( GetEnemy(), "npc_combinegunship" ) ) -#endif { Vector vecRight; GetVectors( NULL, &vecRight, NULL ); @@ -2331,11 +2322,10 @@ Vector CNPC_Citizen::GetActualShootPosition( const Vector &shootOrigin ) { pRPG->SetNPCLaserPosition( vecTarget ); } - } +#endif return vecTarget; -#endif } //----------------------------------------------------------------------------- From 55e75529bb8278c78d9a66f0470777177b148d81 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sun, 19 Sep 2021 01:13:43 -0500 Subject: [PATCH 133/378] Added OnEntText VScript hook inspired by later Source games --- sp/src/game/server/baseentity.cpp | 29 +++++++++++++++++++++++++++++ sp/src/game/server/baseentity.h | 2 ++ 2 files changed, 31 insertions(+) diff --git a/sp/src/game/server/baseentity.cpp b/sp/src/game/server/baseentity.cpp index 0a964058..75c1d799 100644 --- a/sp/src/game/server/baseentity.cpp +++ b/sp/src/game/server/baseentity.cpp @@ -106,6 +106,10 @@ ConVar sv_netvisdist( "sv_netvisdist", "10000", FCVAR_CHEAT | FCVAR_DEVELOPMENTO ConVar sv_script_think_interval("sv_script_think_interval", "0.1"); +#ifdef MAPBASE_VSCRIPT +ConVar ent_text_allow_script( "ent_text_allow_script", "1" ); +#endif + // This table encodes edict data. void SendProxy_AnimTime( const SendProp *pProp, const void *pStruct, const void *pVarData, DVariant *pOut, int iElement, int objectID ) @@ -1060,6 +1064,28 @@ int CBaseEntity::DrawDebugTextOverlays(void) offset++; } #endif + +#ifdef MAPBASE_VSCRIPT + // 'OnEntText' hook inspired by later source games + if (m_ScriptScope.IsInitialized() && g_Hook_OnEntText.CanRunInScope( m_ScriptScope )) + { + if (ent_text_allow_script.GetBool()) + { + ScriptVariant_t functionReturn; + if ( g_Hook_OnEntText.Call( m_ScriptScope, &functionReturn, NULL ) && functionReturn.m_type == FIELD_CSTRING ) + { + CUtlStringList outStrings; + V_SplitString( functionReturn.m_pszString, "\n", outStrings ); + + FOR_EACH_VEC( outStrings, i ) + { + EntityText( offset, outStrings[i], 0, 224, 240, 255 ); + offset++; + } + } + } + } +#endif } if (m_debugOverlays & OVERLAY_VIEWOFFSET) @@ -2209,6 +2235,8 @@ END_DATADESC() #ifdef MAPBASE_VSCRIPT ScriptHook_t CBaseEntity::g_Hook_UpdateOnRemove; +ScriptHook_t CBaseEntity::g_Hook_OnEntText; + ScriptHook_t CBaseEntity::g_Hook_VPhysicsCollision; ScriptHook_t CBaseEntity::g_Hook_FireBullets; ScriptHook_t CBaseEntity::g_Hook_OnDeath; @@ -2460,6 +2488,7 @@ BEGIN_ENT_SCRIPTDESC_ROOT( CBaseEntity, "Root class of all server-side entities" // Hooks // DEFINE_SIMPLE_SCRIPTHOOK( CBaseEntity::g_Hook_UpdateOnRemove, "UpdateOnRemove", FIELD_VOID, "Called when the entity is being removed." ) + DEFINE_SIMPLE_SCRIPTHOOK( CBaseEntity::g_Hook_OnEntText, "OnEntText", FIELD_CSTRING, "Called every frame when ent_text is enabled on the entity. Return a string to be added to the ent_text printout." ) BEGIN_SCRIPTHOOK( CBaseEntity::g_Hook_VPhysicsCollision, "VPhysicsCollision", FIELD_VOID, "Called for every single VPhysics-related collision experienced by this entity." ) DEFINE_SCRIPTHOOK_PARAM( "entity", FIELD_HSCRIPT ) diff --git a/sp/src/game/server/baseentity.h b/sp/src/game/server/baseentity.h index 8577749d..13d64503 100644 --- a/sp/src/game/server/baseentity.h +++ b/sp/src/game/server/baseentity.h @@ -2148,6 +2148,8 @@ public: void ScriptSetTakeDamage( int val ) { m_takedamage = val; } static ScriptHook_t g_Hook_UpdateOnRemove; + static ScriptHook_t g_Hook_OnEntText; + static ScriptHook_t g_Hook_VPhysicsCollision; static ScriptHook_t g_Hook_FireBullets; static ScriptHook_t g_Hook_OnDeath; From 62f4d6f87256d6eed4fd180bf7a97dd85db2f21f Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sun, 19 Sep 2021 14:52:18 -0500 Subject: [PATCH 134/378] Exposed EmitSound_t and related constants to VScript and added hooks for modifying an entity's emitted sounds on both the server and client --- sp/src/game/client/c_baseentity.cpp | 9 ++- sp/src/game/client/c_baseentity.h | 1 + sp/src/game/server/baseentity.cpp | 10 +++ sp/src/game/server/baseentity.h | 8 +++ sp/src/game/shared/SoundEmitterSystem.cpp | 7 ++ .../shared/mapbase/vscript_consts_shared.cpp | 64 ++++++++++++++++++- .../shared/mapbase/vscript_funcs_shared.cpp | 63 ++++++++++++++++++ .../shared/mapbase/vscript_funcs_shared.h | 45 +++++++++++++ 8 files changed, 204 insertions(+), 3 deletions(-) diff --git a/sp/src/game/client/c_baseentity.cpp b/sp/src/game/client/c_baseentity.cpp index a7bb37a4..2f10b2ae 100644 --- a/sp/src/game/client/c_baseentity.cpp +++ b/sp/src/game/client/c_baseentity.cpp @@ -429,7 +429,8 @@ BEGIN_RECV_TABLE_NOBASE( C_BaseEntity, DT_AnimTimeMustBeFirst ) END_RECV_TABLE() #ifdef MAPBASE_VSCRIPT -ScriptHook_t CBaseEntity::g_Hook_UpdateOnRemove; +ScriptHook_t C_BaseEntity::g_Hook_UpdateOnRemove; +ScriptHook_t C_BaseEntity::g_Hook_ModifyEmitSoundParams; #endif BEGIN_ENT_SCRIPTDESC_ROOT( C_BaseEntity, "Root class of all client-side entities" ) @@ -555,7 +556,11 @@ BEGIN_ENT_SCRIPTDESC_ROOT( C_BaseEntity, "Root class of all client-side entities DEFINE_SCRIPTFUNC_NAMED( ScriptSetContextThink, "SetContextThink", "Set a think function on this entity." ) - DEFINE_SIMPLE_SCRIPTHOOK( CBaseEntity::g_Hook_UpdateOnRemove, "UpdateOnRemove", FIELD_VOID, "Called when the entity is being removed." ) + DEFINE_SIMPLE_SCRIPTHOOK( C_BaseEntity::g_Hook_UpdateOnRemove, "UpdateOnRemove", FIELD_VOID, "Called when the entity is being removed." ) + + BEGIN_SCRIPTHOOK( C_BaseEntity::g_Hook_ModifyEmitSoundParams, "ModifyEmitSoundParams", FIELD_VOID, "Called every time a sound is emitted on this entity, allowing for its parameters to be modified." ) + DEFINE_SCRIPTHOOK_PARAM( "params", FIELD_HSCRIPT ) + END_SCRIPTHOOK() #endif // MAPBASE_VSCRIPT diff --git a/sp/src/game/client/c_baseentity.h b/sp/src/game/client/c_baseentity.h index 80d89261..29d04ea0 100644 --- a/sp/src/game/client/c_baseentity.h +++ b/sp/src/game/client/c_baseentity.h @@ -296,6 +296,7 @@ public: CScriptScope m_ScriptScope; static ScriptHook_t g_Hook_UpdateOnRemove; + static ScriptHook_t g_Hook_ModifyEmitSoundParams; #endif // IClientUnknown overrides. diff --git a/sp/src/game/server/baseentity.cpp b/sp/src/game/server/baseentity.cpp index 75c1d799..90b51999 100644 --- a/sp/src/game/server/baseentity.cpp +++ b/sp/src/game/server/baseentity.cpp @@ -2242,6 +2242,8 @@ ScriptHook_t CBaseEntity::g_Hook_FireBullets; ScriptHook_t CBaseEntity::g_Hook_OnDeath; ScriptHook_t CBaseEntity::g_Hook_OnKilledOther; ScriptHook_t CBaseEntity::g_Hook_HandleInteraction; +ScriptHook_t CBaseEntity::g_Hook_ModifyEmitSoundParams; +ScriptHook_t CBaseEntity::g_Hook_ModifySentenceParams; #endif BEGIN_ENT_SCRIPTDESC_ROOT( CBaseEntity, "Root class of all server-side entities" ) @@ -2518,6 +2520,14 @@ BEGIN_ENT_SCRIPTDESC_ROOT( CBaseEntity, "Root class of all server-side entities" //DEFINE_SCRIPTHOOK_PARAM( "data", FIELD_VARIANT ) DEFINE_SCRIPTHOOK_PARAM( "sourceEnt", FIELD_HSCRIPT ) END_SCRIPTHOOK() + + BEGIN_SCRIPTHOOK( CBaseEntity::g_Hook_ModifyEmitSoundParams, "ModifyEmitSoundParams", FIELD_VOID, "Called every time a sound is emitted on this entity, allowing for its parameters to be modified." ) + DEFINE_SCRIPTHOOK_PARAM( "params", FIELD_HSCRIPT ) + END_SCRIPTHOOK() + + BEGIN_SCRIPTHOOK( CBaseEntity::g_Hook_ModifySentenceParams, "ModifySentenceParams", FIELD_VOID, "Called every time a sentence is emitted on this entity, allowing for its parameters to be modified." ) + DEFINE_SCRIPTHOOK_PARAM( "params", FIELD_HSCRIPT ) + END_SCRIPTHOOK() #endif END_SCRIPTDESC(); diff --git a/sp/src/game/server/baseentity.h b/sp/src/game/server/baseentity.h index 13d64503..2645e476 100644 --- a/sp/src/game/server/baseentity.h +++ b/sp/src/game/server/baseentity.h @@ -1537,6 +1537,12 @@ public: void GenderExpandString( char const *in, char *out, int maxlen ); virtual void ModifyEmitSoundParams( EmitSound_t ¶ms ); +#ifdef MAPBASE + // Same as above, but for sentences + // (which don't actually have EmitSound_t params) + virtual void ModifySentenceParams( int &iSentenceIndex, int &iChannel, float &flVolume, soundlevel_t &iSoundlevel, int &iFlags, int &iPitch, + const Vector **pOrigin, const Vector **pDirection, bool &bUpdatePositions, float &soundtime, int &iSpecialDSP, int &iSpeakerIndex ); +#endif static float GetSoundDuration( const char *soundname, char const *actormodel ); @@ -2155,6 +2161,8 @@ public: static ScriptHook_t g_Hook_OnDeath; static ScriptHook_t g_Hook_OnKilledOther; static ScriptHook_t g_Hook_HandleInteraction; + static ScriptHook_t g_Hook_ModifyEmitSoundParams; + static ScriptHook_t g_Hook_ModifySentenceParams; #endif string_t m_iszVScripts; diff --git a/sp/src/game/shared/SoundEmitterSystem.cpp b/sp/src/game/shared/SoundEmitterSystem.cpp index 76a855d9..06f73b72 100644 --- a/sp/src/game/shared/SoundEmitterSystem.cpp +++ b/sp/src/game/shared/SoundEmitterSystem.cpp @@ -1450,6 +1450,13 @@ void CBaseEntity::EmitSentenceByIndex( IRecipientFilter& filter, int iEntIndex, soundOrigins ); if ( bSwallowed ) return; + + CBaseEntity *pEntity = UTIL_EntityByIndex( iEntIndex ); + if ( pEntity ) + { + pEntity->ModifySentenceParams( iSentenceIndex, iChannel, flVolume, iSoundlevel, iFlags, iPitch, + &pOrigin, &pDirection, bUpdatePositions, soundtime, iSpecialDSP, iSpeakerIndex ); + } enginesound->EmitSentenceByIndex( filter, iEntIndex, iChannel, iSentenceIndex, flVolume, iSoundlevel, iFlags, iPitch * GetSoundPitchScale(), iSpecialDSP, pOrigin, pDirection, &soundOrigins, bUpdatePositions, soundtime, iSpeakerIndex ); diff --git a/sp/src/game/shared/mapbase/vscript_consts_shared.cpp b/sp/src/game/shared/mapbase/vscript_consts_shared.cpp index db694201..e8efdee4 100644 --- a/sp/src/game/shared/mapbase/vscript_consts_shared.cpp +++ b/sp/src/game/shared/mapbase/vscript_consts_shared.cpp @@ -327,9 +327,71 @@ void RegisterSharedScriptConstants() ScriptRegisterConstantNamed( g_pScriptVM, Vector( ROPE_GRAVITY ), "ROPE_GRAVITY", "Default rope gravity vector." ); + // + // Sounds + // + ScriptRegisterConstant( g_pScriptVM, CHAN_REPLACE, "The sound channel used when playing sounds through console commands." ); + ScriptRegisterConstant( g_pScriptVM, CHAN_AUTO, "The default generic sound channel." ); + ScriptRegisterConstant( g_pScriptVM, CHAN_WEAPON, "The sound channel for player and NPC weapons." ); + ScriptRegisterConstant( g_pScriptVM, CHAN_VOICE, "The sound channel used for dialogue, voice lines, etc." ); + ScriptRegisterConstant( g_pScriptVM, CHAN_ITEM, "The sound channel used for generic physics impact sounds, health/suit chargers, +use sounds." ); + ScriptRegisterConstant( g_pScriptVM, CHAN_BODY, "The sound channel used for clothing, ragdoll impacts, footsteps, knocking/pounding/punching etc." ); + ScriptRegisterConstant( g_pScriptVM, CHAN_STREAM, "The sound channel for sounds that can be delayed by an async load, i.e. aren't responses to particular events." ); + ScriptRegisterConstant( g_pScriptVM, CHAN_STATIC, "The sound channel for constant/background sound that doesn't require any reaction." ); + ScriptRegisterConstant( g_pScriptVM, CHAN_VOICE2, "An additional sound channel for voices. Used in TF2 for the announcer." ); + ScriptRegisterConstant( g_pScriptVM, CHAN_VOICE_BASE, "The sound channel used for network voice data (online voice communications)." ); + + ScriptRegisterConstant( g_pScriptVM, VOL_NORM, "The standard volume value." ); + ScriptRegisterConstant( g_pScriptVM, PITCH_NORM, "The standard pitch value." ); + ScriptRegisterConstant( g_pScriptVM, PITCH_LOW, "The standard low pitch value." ); + ScriptRegisterConstant( g_pScriptVM, PITCH_HIGH, "The standard high pitch value." ); + + ScriptRegisterConstant( g_pScriptVM, SNDLVL_NONE, "A standard value used for a sound's sound level." ); + ScriptRegisterConstant( g_pScriptVM, SNDLVL_20dB, "A standard value used for a sound's sound level." ); + ScriptRegisterConstant( g_pScriptVM, SNDLVL_25dB, "A standard value used for a sound's sound level." ); + ScriptRegisterConstant( g_pScriptVM, SNDLVL_30dB, "A standard value used for a sound's sound level." ); + ScriptRegisterConstant( g_pScriptVM, SNDLVL_35dB, "A standard value used for a sound's sound level." ); + ScriptRegisterConstant( g_pScriptVM, SNDLVL_40dB, "A standard value used for a sound's sound level." ); + ScriptRegisterConstant( g_pScriptVM, SNDLVL_45dB, "A standard value used for a sound's sound level." ); + ScriptRegisterConstant( g_pScriptVM, SNDLVL_50dB, "A standard value used for a sound's sound level." ); + ScriptRegisterConstant( g_pScriptVM, SNDLVL_55dB, "A standard value used for a sound's sound level." ); + ScriptRegisterConstant( g_pScriptVM, SNDLVL_IDLE, "A standard value used for a sound's sound level." ); + ScriptRegisterConstant( g_pScriptVM, SNDLVL_60dB, "A standard value used for a sound's sound level." ); + ScriptRegisterConstant( g_pScriptVM, SNDLVL_65dB, "A standard value used for a sound's sound level." ); + ScriptRegisterConstant( g_pScriptVM, SNDLVL_STATIC, "A standard value used for a sound's sound level." ); + ScriptRegisterConstant( g_pScriptVM, SNDLVL_70dB, "A standard value used for a sound's sound level." ); + ScriptRegisterConstant( g_pScriptVM, SNDLVL_NORM, "A standard value used for a sound's sound level." ); + ScriptRegisterConstant( g_pScriptVM, SNDLVL_75dB, "A standard value used for a sound's sound level." ); + ScriptRegisterConstant( g_pScriptVM, SNDLVL_80dB, "A standard value used for a sound's sound level." ); + ScriptRegisterConstant( g_pScriptVM, SNDLVL_TALKING, "A standard value used for a sound's sound level." ); + ScriptRegisterConstant( g_pScriptVM, SNDLVL_85dB, "A standard value used for a sound's sound level." ); + ScriptRegisterConstant( g_pScriptVM, SNDLVL_90dB, "A standard value used for a sound's sound level." ); + ScriptRegisterConstant( g_pScriptVM, SNDLVL_95dB, "A standard value used for a sound's sound level." ); + ScriptRegisterConstant( g_pScriptVM, SNDLVL_100dB, "A standard value used for a sound's sound level." ); + ScriptRegisterConstant( g_pScriptVM, SNDLVL_105dB, "A standard value used for a sound's sound level." ); + ScriptRegisterConstant( g_pScriptVM, SNDLVL_110dB, "A standard value used for a sound's sound level." ); + ScriptRegisterConstant( g_pScriptVM, SNDLVL_120dB, "A standard value used for a sound's sound level." ); + ScriptRegisterConstant( g_pScriptVM, SNDLVL_130dB, "A standard value used for a sound's sound level." ); + ScriptRegisterConstant( g_pScriptVM, SNDLVL_GUNFIRE, "A standard value used for a sound's sound level." ); + ScriptRegisterConstant( g_pScriptVM, SNDLVL_140dB, "A standard value used for a sound's sound level." ); + ScriptRegisterConstant( g_pScriptVM, SNDLVL_150dB, "A standard value used for a sound's sound level." ); + ScriptRegisterConstant( g_pScriptVM, SNDLVL_180dB, "A standard value used for a sound's sound level." ); + + ScriptRegisterConstant( g_pScriptVM, SND_CHANGE_VOL, "Indicates a sound is a volume change to an already-playing sound." ); + ScriptRegisterConstant( g_pScriptVM, SND_CHANGE_PITCH, "Indicates a sound is a pitch change to an already-playing sound." ); + ScriptRegisterConstant( g_pScriptVM, SND_STOP, "Indicates a sound is stopping an already-playing sound." ); + ScriptRegisterConstant( g_pScriptVM, SND_SPAWNING, "Indicates a sound is spawning, used in some cases for ambients. Not networked." ); + ScriptRegisterConstant( g_pScriptVM, SND_DELAY, "Indicates a sound has an initial delay." ); + ScriptRegisterConstant( g_pScriptVM, SND_STOP_LOOPING, "Stops all looping sounds on an entity." ); + ScriptRegisterConstant( g_pScriptVM, SND_SPEAKER, "Indicates a sound is being played again by a microphone through a speaker." ); + ScriptRegisterConstant( g_pScriptVM, SND_SHOULDPAUSE, "Forces a sound to pause if the game is paused." ); + ScriptRegisterConstant( g_pScriptVM, SND_IGNORE_PHONEMES, "Prevents the entity emitting this sound from using its phonemes (no lip-syncing)." ); + ScriptRegisterConstant( g_pScriptVM, SND_IGNORE_NAME, "Used to change all sounds emitted by an entity, regardless of name." ); + ScriptRegisterConstant( g_pScriptVM, SND_DO_NOT_OVERWRITE_EXISTING_ON_CHANNEL, "Prevents a sound from interrupting other sounds on a channel (if the channel supports interruption)." ); + #ifdef GAME_DLL // - // Sound Types, Contexts, and Channels + // AI Sounds // (QueryHearSound hook can use these) // ScriptRegisterConstant( g_pScriptVM, SOUND_NONE, "Sound type used in QueryHearSound hooks, etc." ); diff --git a/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp b/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp index e564d2b4..a2af7d71 100644 --- a/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp +++ b/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp @@ -560,6 +560,52 @@ bool CAnimEventTInstanceHelper::Set( void *p, const char *pszKey, ScriptVariant_ return true; } +//----------------------------------------------------------------------------- +// EmitSound_t +//----------------------------------------------------------------------------- +BEGIN_SCRIPTDESC_ROOT_NAMED( ScriptEmitSound_t, "EmitSound_t", "Handle for accessing EmitSound_t info." ) + DEFINE_SCRIPT_CONSTRUCTOR() + + DEFINE_SCRIPTFUNC( GetChannel, "Gets the sound's channel." ) + DEFINE_SCRIPTFUNC( SetChannel, "Gets the sound's channel." ) + + DEFINE_SCRIPTFUNC( GetSoundName, "Gets the sound's file path or soundscript name." ) + DEFINE_SCRIPTFUNC( SetSoundName, "Sets the sound's file path or soundscript name." ) + + DEFINE_SCRIPTFUNC( GetVolume, "Gets the sound's volume. (Note that this may not apply to soundscripts)" ) + DEFINE_SCRIPTFUNC( SetVolume, "Sets the sound's volume. (Note that this may not apply to soundscripts)" ) + + DEFINE_SCRIPTFUNC( GetSoundLevel, "Gets the sound's level in decibels. (Note that this may not apply to soundscripts)" ) + DEFINE_SCRIPTFUNC( SetSoundLevel, "Sets the sound's level in decibels. (Note that this may not apply to soundscripts)" ) + + DEFINE_SCRIPTFUNC( GetFlags, "Gets the sound's flags. See the 'SND_' set of constants for more information." ) + DEFINE_SCRIPTFUNC( SetFlags, "Sets the sound's flags. See the 'SND_' set of constants for more information." ) + + DEFINE_SCRIPTFUNC( GetSpecialDSP, "Gets the sound's special DSP setting." ) + DEFINE_SCRIPTFUNC( SetSpecialDSP, "Sets the sound's special DSP setting." ) + + DEFINE_SCRIPTFUNC( GetOrigin, "Gets the sound's origin override." ) + DEFINE_SCRIPTFUNC( SetOrigin, "Sets the sound's origin override." ) + + DEFINE_SCRIPTFUNC( GetSoundTime, "Gets the time the sound will begin, relative to Time()." ) + DEFINE_SCRIPTFUNC( SetSoundTime, "Sets the time the sound will begin, relative to Time()." ) + + DEFINE_SCRIPTFUNC( GetEmitCloseCaption, "Gets whether or not the sound will emit closed captioning/subtitles." ) + DEFINE_SCRIPTFUNC( SetEmitCloseCaption, "Sets whether or not the sound will emit closed captioning/subtitles." ) + + DEFINE_SCRIPTFUNC( GetWarnOnMissingCloseCaption, "Gets whether or not the sound will send a message to the console if there is no corresponding closed captioning token." ) + DEFINE_SCRIPTFUNC( SetWarnOnMissingCloseCaption, "Sets whether or not the sound will send a message to the console if there is no corresponding closed captioning token." ) + + DEFINE_SCRIPTFUNC( GetWarnOnDirectWaveReference, "Gets whether or not the sound will send a message to the console if it references a direct sound file instead of a soundscript." ) + DEFINE_SCRIPTFUNC( SetWarnOnDirectWaveReference, "Sets whether or not the sound will send a message to the console if it references a direct sound file instead of a soundscript." ) + + DEFINE_SCRIPTFUNC( GetSpeakerEntity, "Gets the sound's original source if it is being transmitted by a microphone." ) + DEFINE_SCRIPTFUNC( SetSpeakerEntity, "Sets the sound's original source if it is being transmitted by a microphone." ) + + DEFINE_SCRIPTFUNC( GetSoundScriptHandle, "Gets the sound's script handle." ) + DEFINE_SCRIPTFUNC( SetSoundScriptHandle, "Sets the sound's script handle." ) +END_SCRIPTDESC(); + //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- @@ -744,6 +790,21 @@ static HSCRIPT ScriptCreateRope( HSCRIPT hStart, HSCRIPT hEnd, int iStartAttachm return ToHScript( pRope ); } +static void EmitSoundParamsOn( HSCRIPT hParams, HSCRIPT hEnt ) +{ + CBaseEntity *pEnt = ToEnt( hEnt ); + if (!pEnt) + return; + + ScriptEmitSound_t *pParams = (ScriptEmitSound_t*)g_pScriptVM->GetInstanceValue( hParams, GetScriptDescForClass( ScriptEmitSound_t ) ); + if (!pParams) + return; + + CPASAttenuationFilter filter( pEnt, pParams->m_pSoundName ); + + CBaseEntity::EmitSound( filter, pEnt->entindex(), *pParams ); +} + //----------------------------------------------------------------------------- // Simple particle effect dispatch //----------------------------------------------------------------------------- @@ -909,6 +970,8 @@ void RegisterSharedScriptFunctions() ScriptRegisterFunctionNamed( g_pScriptVM, ScriptCreateRope, "CreateRope", "Creates a single rope between two entities. Can optionally follow specific attachments." ); + ScriptRegisterFunction( g_pScriptVM, EmitSoundParamsOn, "Play EmitSound_t params on an entity." ); + 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." ); diff --git a/sp/src/game/shared/mapbase/vscript_funcs_shared.h b/sp/src/game/shared/mapbase/vscript_funcs_shared.h index 0a38e5a1..ae3def47 100644 --- a/sp/src/game/shared/mapbase/vscript_funcs_shared.h +++ b/sp/src/game/shared/mapbase/vscript_funcs_shared.h @@ -130,4 +130,49 @@ class CAnimEventTInstanceHelper : public IScriptInstanceHelper bool Set( void *p, const char *pszKey, ScriptVariant_t &variant ); }; +//----------------------------------------------------------------------------- +// Exposes EmitSound_t to VScript +//----------------------------------------------------------------------------- +struct ScriptEmitSound_t : public EmitSound_t +{ + int GetChannel() { return m_nChannel; } + void SetChannel( int nChannel ) { m_nChannel = nChannel; } + + const char *GetSoundName() { return m_pSoundName; } + void SetSoundName( const char *pSoundName ) { m_pSoundName = pSoundName; } + + float GetVolume() { return m_flVolume; } + void SetVolume( float flVolume ) { m_flVolume = flVolume; } + + int GetSoundLevel() { return m_SoundLevel; } + void SetSoundLevel( int iSoundLevel ) { m_SoundLevel = (soundlevel_t)iSoundLevel; } + + int GetFlags() { return m_nFlags; } + void SetFlags( int nFlags ) { m_nFlags = nFlags; } + + int GetSpecialDSP() { return m_nSpecialDSP; } + void SetSpecialDSP( int nSpecialDSP ) { m_nSpecialDSP = nSpecialDSP; } + + ScriptVariant_t GetOrigin() { return m_pOrigin ? *m_pOrigin : ScriptVariant_t(); } + void SetOrigin( ScriptVariant_t origin ) { m_pOrigin = origin.m_pVector; } + + float GetSoundTime() { return m_flSoundTime; } + void SetSoundTime( float flSoundTime ) { m_flSoundTime = flSoundTime; } + + float GetEmitCloseCaption() { return m_bEmitCloseCaption; } + void SetEmitCloseCaption( bool bEmitCloseCaption ) { m_bEmitCloseCaption = bEmitCloseCaption; } + + float GetWarnOnMissingCloseCaption() { return m_bWarnOnMissingCloseCaption; } + void SetWarnOnMissingCloseCaption( bool bWarnOnMissingCloseCaption ) { m_bWarnOnMissingCloseCaption = bWarnOnMissingCloseCaption; } + + float GetWarnOnDirectWaveReference() { return m_bWarnOnDirectWaveReference; } + void SetWarnOnDirectWaveReference( bool bWarnOnDirectWaveReference ) { m_bWarnOnDirectWaveReference = bWarnOnDirectWaveReference; } + + int GetSpeakerEntity() { return m_nSpeakerEntity; } + void SetSpeakerEntity( int nSpeakerEntity ) { m_nSpeakerEntity = nSpeakerEntity; } + + int GetSoundScriptHandle() { return m_hSoundScriptHandle; } + void SetSoundScriptHandle( int hSoundScriptHandle ) { m_hSoundScriptHandle = hSoundScriptHandle; } +}; + #endif From 5896fb73c8f0214f81a9749a9ee841aaa26dac80 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sun, 19 Sep 2021 21:03:36 -0500 Subject: [PATCH 135/378] Fixed issue with EmitSound_t origin in VScript --- sp/src/game/shared/mapbase/vscript_funcs_shared.cpp | 2 ++ sp/src/game/shared/mapbase/vscript_funcs_shared.h | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp b/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp index a2af7d71..26c0c1b8 100644 --- a/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp +++ b/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp @@ -584,8 +584,10 @@ BEGIN_SCRIPTDESC_ROOT_NAMED( ScriptEmitSound_t, "EmitSound_t", "Handle for acces DEFINE_SCRIPTFUNC( GetSpecialDSP, "Gets the sound's special DSP setting." ) DEFINE_SCRIPTFUNC( SetSpecialDSP, "Sets the sound's special DSP setting." ) + DEFINE_SCRIPTFUNC( HasOrigin, "Returns true if the sound has an origin override." ) DEFINE_SCRIPTFUNC( GetOrigin, "Gets the sound's origin override." ) DEFINE_SCRIPTFUNC( SetOrigin, "Sets the sound's origin override." ) + DEFINE_SCRIPTFUNC( ClearOrigin, "Clears the sound's origin override if it has one." ) DEFINE_SCRIPTFUNC( GetSoundTime, "Gets the time the sound will begin, relative to Time()." ) DEFINE_SCRIPTFUNC( SetSoundTime, "Sets the time the sound will begin, relative to Time()." ) diff --git a/sp/src/game/shared/mapbase/vscript_funcs_shared.h b/sp/src/game/shared/mapbase/vscript_funcs_shared.h index ae3def47..40055a88 100644 --- a/sp/src/game/shared/mapbase/vscript_funcs_shared.h +++ b/sp/src/game/shared/mapbase/vscript_funcs_shared.h @@ -153,8 +153,10 @@ struct ScriptEmitSound_t : public EmitSound_t int GetSpecialDSP() { return m_nSpecialDSP; } void SetSpecialDSP( int nSpecialDSP ) { m_nSpecialDSP = nSpecialDSP; } - ScriptVariant_t GetOrigin() { return m_pOrigin ? *m_pOrigin : ScriptVariant_t(); } - void SetOrigin( ScriptVariant_t origin ) { m_pOrigin = origin.m_pVector; } + bool HasOrigin() { return m_pOrigin ? true : false; } + const Vector &GetOrigin() { return m_pOrigin ? *m_pOrigin : vec3_origin; } + void SetOrigin( Vector origin ) { m_pOrigin = &origin; } + void ClearOrigin() { m_pOrigin = NULL; } float GetSoundTime() { return m_flSoundTime; } void SetSoundTime( float flSoundTime ) { m_flSoundTime = flSoundTime; } From 97928611aadcb95abf3817a74b5859faf8253c41 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sun, 19 Sep 2021 21:04:31 -0500 Subject: [PATCH 136/378] Removed CancelEventsByInput at the suggestion of its contributor --- sp/src/game/server/baseentity.cpp | 10 +++++----- sp/src/game/server/baseentity.h | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/sp/src/game/server/baseentity.cpp b/sp/src/game/server/baseentity.cpp index 90b51999..5598ba69 100644 --- a/sp/src/game/server/baseentity.cpp +++ b/sp/src/game/server/baseentity.cpp @@ -1375,10 +1375,10 @@ float CBaseEntity::GetMaxOutputDelay( const char *pszOutput ) return 0; } -void CBaseEntity::CancelEventsByInput( const char *szInput ) -{ - g_EventQueue.CancelEventsByInput( this, szInput ); -} +//void CBaseEntity::CancelEventsByInput( const char *szInput ) +//{ +// g_EventQueue.CancelEventsByInput( this, szInput ); +//} #endif // MAPBASE_VSCRIPT CBaseEntityOutput *CBaseEntity::FindNamedOutput( const char *pszOutput ) @@ -2378,7 +2378,7 @@ BEGIN_ENT_SCRIPTDESC_ROOT( CBaseEntity, "Root class of all server-side entities" DEFINE_SCRIPTFUNC_NAMED( ScriptAcceptInput, "AcceptInput", "" ) DEFINE_SCRIPTFUNC_NAMED( ScriptFireOutput, "FireOutput", "Fire an entity output" ) DEFINE_SCRIPTFUNC( GetMaxOutputDelay, "Get the longest delay for all events attached to an output" ) - DEFINE_SCRIPTFUNC( CancelEventsByInput, "Cancel all I/O events for this entity, match input" ) + //DEFINE_SCRIPTFUNC( CancelEventsByInput, "Cancel all I/O events for this entity, match input" ) // Commented out due to unpredictability and unknown risks DEFINE_SCRIPTFUNC_NAMED( ScriptAddOutput, "AddOutput", "Add an output" ) DEFINE_SCRIPTFUNC_NAMED( ScriptGetKeyValue, "GetKeyValue", "Get a keyvalue" ) diff --git a/sp/src/game/server/baseentity.h b/sp/src/game/server/baseentity.h index 2645e476..c55c8c2b 100644 --- a/sp/src/game/server/baseentity.h +++ b/sp/src/game/server/baseentity.h @@ -610,7 +610,7 @@ public: #ifdef MAPBASE_VSCRIPT void ScriptFireOutput( const char *pszOutput, HSCRIPT hActivator, HSCRIPT hCaller, const char *szValue, float flDelay ); float GetMaxOutputDelay( const char *pszOutput ); - void CancelEventsByInput( const char *szInput ); + //void CancelEventsByInput( const char *szInput ); #endif From d629fac2b5d50503fa8663a486552762908bc845 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sun, 19 Sep 2021 21:08:02 -0500 Subject: [PATCH 137/378] Fixed a VScript think function crash --- sp/src/game/server/baseentity.cpp | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/sp/src/game/server/baseentity.cpp b/sp/src/game/server/baseentity.cpp index 5598ba69..fd31f792 100644 --- a/sp/src/game/server/baseentity.cpp +++ b/sp/src/game/server/baseentity.cpp @@ -458,6 +458,17 @@ extern bool g_bDisableEhandleAccess; //----------------------------------------------------------------------------- CBaseEntity::~CBaseEntity( ) { +#ifdef MAPBASE_VSCRIPT + // HACKHACK: This is needed to fix a crash when an entity removes itself with Destroy() during its own think function. + // (see https://github.com/mapbase-source/source-sdk-2013/issues/138) + FOR_EACH_VEC( m_ScriptThinkFuncs, i ) + { + HSCRIPT h = m_ScriptThinkFuncs[i]->m_hfnThink; + if ( h ) g_pScriptVM->ReleaseScript( h ); + } + m_ScriptThinkFuncs.PurgeAndDeleteElements(); +#endif // MAPBASE_VSCRIPT + // FIXME: This can't be called from UpdateOnRemove! There's at least one // case where friction sounds are added between the call to UpdateOnRemove + ~CBaseEntity PhysCleanupFrictionSounds( this ); @@ -2643,15 +2654,6 @@ void CBaseEntity::UpdateOnRemove( void ) g_pScriptVM->RemoveInstance( m_hScriptInstance ); m_hScriptInstance = NULL; - -#ifdef MAPBASE_VSCRIPT - FOR_EACH_VEC( m_ScriptThinkFuncs, i ) - { - HSCRIPT h = m_ScriptThinkFuncs[i]->m_hfnThink; - if ( h ) g_pScriptVM->ReleaseScript( h ); - } - m_ScriptThinkFuncs.PurgeAndDeleteElements(); -#endif // MAPBASE_VSCRIPT } } From 0368abaf29f3668b98706b061ade48ea8d872940 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sun, 19 Sep 2021 21:09:25 -0500 Subject: [PATCH 138/378] Made VScript's enum registration use direct API functions to create constant tables instead of declaring them in string literal code --- sp/src/vscript/vscript_squirrel.cpp | 36 ++++++++--------------------- 1 file changed, 10 insertions(+), 26 deletions(-) diff --git a/sp/src/vscript/vscript_squirrel.cpp b/sp/src/vscript/vscript_squirrel.cpp index fa4c15d2..cd5fe6f6 100644 --- a/sp/src/vscript/vscript_squirrel.cpp +++ b/sp/src/vscript/vscript_squirrel.cpp @@ -2669,44 +2669,28 @@ void SquirrelVM::RegisterEnum(ScriptEnumDesc_t* pEnumDesc) if (!pEnumDesc) return; + sq_newtableex(vm_, pEnumDesc->m_ConstantBindings.Count()); + sq_pushconsttable(vm_); + sq_pushstring(vm_, pEnumDesc->m_pszScriptName, -1); - - // Check if class name is already taken - if (sq_get(vm_, -2) == SQ_OK) - { - HSQOBJECT obj; - sq_resetobject(&obj); - sq_getstackobj(vm_, -1, &obj); - if (!sq_isnull(obj)) - { - sq_pop(vm_, 2); - return; - } - } - - sq_pop(vm_, 1); - - // HACKHACK: I have no idea how to declare enums with the current API. - // For now, we'll just cram everything into a script buffer and compile it. (Blixibon) - char szScript[2048]; - V_snprintf( szScript, sizeof(szScript), "enum %s {\n", pEnumDesc->m_pszScriptName ); + sq_push(vm_, -3); + sq_rawset(vm_, -3); for (int i = 0; i < pEnumDesc->m_ConstantBindings.Count(); ++i) { auto& scriptConstant = pEnumDesc->m_ConstantBindings[i]; + sq_pushstring(vm_, scriptConstant.m_pszScriptName, -1); + PushVariant(vm_, scriptConstant.m_data); + sq_rawset(vm_, -4); + char szValue[64]; GetVariantScriptString( scriptConstant.m_data, szValue, sizeof(szValue) ); - - V_snprintf( szScript, sizeof(szScript), "%s%s = %s\n", szScript, scriptConstant.m_pszScriptName, szValue ); - RegisterConstantDocumentation(vm_, &scriptConstant, szValue, pEnumDesc); } - V_strcat_safe( szScript, "}" ); - - Run( szScript ); + sq_pop(vm_, 2); RegisterEnumDocumentation(vm_, pEnumDesc); } From 08dcf3ffff4988fbc430d2bc0f563fc15ac22e1f Mon Sep 17 00:00:00 2001 From: Blixibon Date: Mon, 20 Sep 2021 15:30:16 -0500 Subject: [PATCH 139/378] Fixed an accidental omission from the EmitSound_t hooks (particularly the code which actually runs them) --- sp/src/game/shared/baseentity_shared.cpp | 59 ++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/sp/src/game/shared/baseentity_shared.cpp b/sp/src/game/shared/baseentity_shared.cpp index 6b802a25..cd3854dd 100644 --- a/sp/src/game/shared/baseentity_shared.cpp +++ b/sp/src/game/shared/baseentity_shared.cpp @@ -2393,8 +2393,67 @@ void CBaseEntity::ModifyEmitSoundParams( EmitSound_t ¶ms ) params.m_pSoundName = GameRules()->TranslateEffectForVisionFilter( "sounds", params.m_pSoundName ); } #endif + +#ifdef MAPBASE_VSCRIPT + if (m_ScriptScope.IsInitialized() && g_Hook_ModifyEmitSoundParams.CanRunInScope( m_ScriptScope )) + { + HSCRIPT hParams = g_pScriptVM->RegisterInstance( reinterpret_cast(¶ms) ); + + // params + ScriptVariant_t functionReturn; + ScriptVariant_t args[] = { ScriptVariant_t( hParams ) }; + g_Hook_ModifyEmitSoundParams.Call( m_ScriptScope, &functionReturn, args ); + + g_pScriptVM->RemoveInstance( hParams ); + } +#endif } +#if defined(MAPBASE) && defined(GAME_DLL) +void CBaseEntity::ModifySentenceParams( int &iSentenceIndex, int &iChannel, float &flVolume, soundlevel_t &iSoundlevel, int &iFlags, int &iPitch, + const Vector **pOrigin, const Vector **pDirection, bool &bUpdatePositions, float &soundtime, int &iSpecialDSP, int &iSpeakerIndex ) +{ +#ifdef MAPBASE_VSCRIPT + if (m_ScriptScope.IsInitialized() && g_Hook_ModifySentenceParams.CanRunInScope( m_ScriptScope )) + { + // This is a bit of a hack, but for consistency with ModifyEmitSoundParams, put them into an EmitSound_t params + ScriptEmitSound_t params; + params.m_pSoundName = engine->SentenceNameFromIndex( iSentenceIndex ); + params.m_nChannel = iChannel; + params.m_flVolume = flVolume; + params.m_SoundLevel = iSoundlevel; + params.m_nFlags = iFlags; + params.m_nPitch = iPitch; + params.m_pOrigin = *pOrigin; + params.m_flSoundTime = soundtime; + params.m_nSpecialDSP = iSpecialDSP; + params.m_nSpeakerEntity = iSpeakerIndex; + + HSCRIPT hParams = g_pScriptVM->RegisterInstance( ¶ms ); + + // params + ScriptVariant_t functionReturn; + ScriptVariant_t args[] = { ScriptVariant_t( hParams ) }; + if (g_Hook_ModifySentenceParams.Call( m_ScriptScope, &functionReturn, args )) + { + iSentenceIndex = engine->SentenceIndexFromName( params.m_pSoundName ); + iChannel = params.m_nChannel; + flVolume = params.m_flVolume; + iSoundlevel = params.m_SoundLevel; + iFlags = params.m_nFlags; + iPitch = params.m_nPitch; + *pOrigin = params.m_pOrigin; + soundtime = params.m_flSoundTime; + iSpecialDSP = params.m_nSpecialDSP; + iSpeakerIndex = params.m_nSpeakerEntity; + } + + g_pScriptVM->RemoveInstance( hParams ); + } +#endif +} +#endif + //----------------------------------------------------------------------------- // These methods encapsulate MOVETYPE_FOLLOW, which became obsolete //----------------------------------------------------------------------------- From 4d4296dac2d3c850edfefc0ed0f1336b435e1f7a Mon Sep 17 00:00:00 2001 From: Blixibon Date: Mon, 20 Sep 2021 22:07:16 -0500 Subject: [PATCH 140/378] Added keyvalue to ai_goal_follow to enable normal memory discard duration --- sp/src/game/server/ai_behavior_follow.cpp | 6 +++++- sp/src/game/server/ai_behavior_follow.h | 4 ++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/sp/src/game/server/ai_behavior_follow.cpp b/sp/src/game/server/ai_behavior_follow.cpp index bcd254a5..a2ab0cae 100644 --- a/sp/src/game/server/ai_behavior_follow.cpp +++ b/sp/src/game/server/ai_behavior_follow.cpp @@ -408,10 +408,11 @@ bool CAI_FollowBehavior::SetFollowGoal( CAI_FollowGoal *pGoal, bool fFinishCurSc SetFollowTarget( pGoal->GetGoalEntity() ); #ifdef MAPBASE Assert( pGoal->m_iFormation < AIF_NUM_FORMATIONS ); + SetParameters( AI_FollowParams_t( (AI_Formations_t)pGoal->m_iFormation, pGoal->m_bNormalMemoryDiscard ) ); #else Assert( pGoal->m_iFormation == AIF_SIMPLE || pGoal->m_iFormation == AIF_WIDE || pGoal->m_iFormation == AIF_MEDIUM || pGoal->m_iFormation == AIF_SIDEKICK || pGoal->m_iFormation == AIF_VORTIGAUNT ); -#endif SetParameters( AI_FollowParams_t( (AI_Formations_t)pGoal->m_iFormation ) ); +#endif m_hFollowGoalEnt = pGoal; m_flTimeUpdatedFollowPosition = 0; return true; @@ -2138,6 +2139,9 @@ bool CAI_FollowBehavior::ShouldAlwaysThink() BEGIN_DATADESC( CAI_FollowGoal ) DEFINE_KEYFIELD( m_iFormation, FIELD_INTEGER, "Formation" ), +#ifdef MAPBASE + DEFINE_KEYFIELD( m_bNormalMemoryDiscard, FIELD_BOOLEAN, "NormalMemoryDiscard" ), +#endif #ifdef HL2_EPISODIC DEFINE_INPUTFUNC( FIELD_VOID, "OutsideTransition", InputOutsideTransition ), diff --git a/sp/src/game/server/ai_behavior_follow.h b/sp/src/game/server/ai_behavior_follow.h index 84cb0109..097588c6 100644 --- a/sp/src/game/server/ai_behavior_follow.h +++ b/sp/src/game/server/ai_behavior_follow.h @@ -71,6 +71,10 @@ public: int m_iFormation; +#ifdef MAPBASE + bool m_bNormalMemoryDiscard = false; +#endif + DECLARE_DATADESC(); }; From f278491d86cabcc311a8047778693d4f39e7e6eb Mon Sep 17 00:00:00 2001 From: Blixibon Date: Mon, 20 Sep 2021 22:10:34 -0500 Subject: [PATCH 141/378] Fixed point_viewcontrol "Don't set player view" keyvalue not working properly --- sp/src/game/server/triggers.cpp | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/sp/src/game/server/triggers.cpp b/sp/src/game/server/triggers.cpp index 37f5c19b..2361f8fa 100644 --- a/sp/src/game/server/triggers.cpp +++ b/sp/src/game/server/triggers.cpp @@ -3497,12 +3497,14 @@ void CTriggerCamera::Enable( void ) #ifdef MAPBASE if (!m_bDontSetPlayerView) #endif - pPlayer->SetViewEntity( this ); - - // Hide the player's viewmodel - if ( pPlayer->GetActiveWeapon() ) { - pPlayer->GetActiveWeapon()->AddEffects( EF_NODRAW ); + pPlayer->SetViewEntity( this ); + + // Hide the player's viewmodel + if ( pPlayer->GetActiveWeapon() ) + { + pPlayer->GetActiveWeapon()->AddEffects( EF_NODRAW ); + } } // Only track if we have a target @@ -3548,11 +3550,16 @@ void CTriggerCamera::Disable( void ) pBasePlayer->RemoveSolidFlags( FSOLID_NOT_SOLID ); } - if (!m_bDontSetPlayerView) - pBasePlayer->SetViewEntity( NULL ); + if ( HasSpawnFlags( SF_CAMERA_PLAYER_TAKECONTROL ) ) + { + pBasePlayer->EnableControl( TRUE ); + } - pBasePlayer->EnableControl(TRUE); - pBasePlayer->m_Local.m_bDrawViewmodel = true; + if (!m_bDontSetPlayerView) + { + pBasePlayer->SetViewEntity( NULL ); + pBasePlayer->m_Local.m_bDrawViewmodel = true; + } } if ( HasSpawnFlags( SF_CAMERA_PLAYER_SETFOV ) ) From fc93d736eee1a6bf00ac39b2a8a2e9c7aa48fed6 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Mon, 20 Sep 2021 22:38:49 -0500 Subject: [PATCH 142/378] Added support for displaying multiple screen overlays at the same time --- sp/src/game/client/c_env_screenoverlay.cpp | 32 ++++++- sp/src/game/client/iviewrender.h | 7 ++ sp/src/game/client/viewdebug.cpp | 51 ++++++++++ sp/src/game/client/viewrender.cpp | 105 +++++++++++++++++++++ sp/src/game/client/viewrender.h | 11 +++ sp/src/game/server/env_screenoverlay.cpp | 12 +++ 6 files changed, 216 insertions(+), 2 deletions(-) diff --git a/sp/src/game/client/c_env_screenoverlay.cpp b/sp/src/game/client/c_env_screenoverlay.cpp index 5496d453..a3125882 100644 --- a/sp/src/game/client/c_env_screenoverlay.cpp +++ b/sp/src/game/client/c_env_screenoverlay.cpp @@ -48,6 +48,9 @@ protected: int m_iCachedDesiredOverlay; int m_iCurrentOverlay; float m_flCurrentOverlayTime; +#ifdef MAPBASE + int m_iOverlayIndex; +#endif }; IMPLEMENT_CLIENTCLASS_DT( C_EnvScreenOverlay, DT_EnvScreenOverlay, CEnvScreenOverlay ) @@ -56,6 +59,9 @@ IMPLEMENT_CLIENTCLASS_DT( C_EnvScreenOverlay, DT_EnvScreenOverlay, CEnvScreenOve RecvPropFloat( RECVINFO( m_flStartTime ) ), RecvPropInt( RECVINFO( m_iDesiredOverlay ) ), RecvPropBool( RECVINFO( m_bIsActive ) ), +#ifdef MAPBASE + RecvPropInt( RECVINFO( m_iOverlayIndex ) ), +#endif END_RECV_TABLE() //----------------------------------------------------------------------------- @@ -77,7 +83,11 @@ void C_EnvScreenOverlay::PostDataUpdate( DataUpdateType_t updateType ) BaseClass::PostDataUpdate( updateType ); // If we have a start time now, start the overlays going +#ifdef MAPBASE + if ( m_bIsActive && m_flStartTime > 0 && (view->GetScreenOverlayMaterial() == NULL || (m_iOverlayIndex != -1 && view->GetIndexedScreenOverlayMaterial(m_iOverlayIndex) == NULL)) ) +#else if ( m_bIsActive && m_flStartTime > 0 && view->GetScreenOverlayMaterial() == NULL ) +#endif { StartOverlays(); } @@ -111,7 +121,16 @@ void C_EnvScreenOverlay::StopOverlays( void ) if ( m_bWasActive && !m_bIsActive ) { - view->SetScreenOverlayMaterial( NULL ); +#ifdef MAPBASE + if (m_iOverlayIndex != -1) + { + view->SetIndexedScreenOverlayMaterial( m_iOverlayIndex, NULL ); + } + else +#endif + { + view->SetScreenOverlayMaterial( NULL ); + } } } @@ -163,7 +182,16 @@ void C_EnvScreenOverlay::StartCurrentOverlay( void ) IMaterial *pMaterial = materials->FindMaterial( m_iszOverlayNames[m_iCurrentOverlay], TEXTURE_GROUP_CLIENT_EFFECTS, false ); if ( !IsErrorMaterial( pMaterial ) ) { - view->SetScreenOverlayMaterial( pMaterial ); +#ifdef MAPBASE + if (m_iOverlayIndex != -1) + { + view->SetIndexedScreenOverlayMaterial( m_iOverlayIndex, pMaterial ); + } + else +#endif + { + view->SetScreenOverlayMaterial( pMaterial ); + } } else { diff --git a/sp/src/game/client/iviewrender.h b/sp/src/game/client/iviewrender.h index c66061ae..8d797dea 100644 --- a/sp/src/game/client/iviewrender.h +++ b/sp/src/game/client/iviewrender.h @@ -115,6 +115,13 @@ public: virtual void SetScreenOverlayMaterial( IMaterial *pMaterial ) = 0; virtual IMaterial *GetScreenOverlayMaterial( ) = 0; +#ifdef MAPBASE + virtual void SetIndexedScreenOverlayMaterial( int i, IMaterial *pMaterial ) = 0; + virtual IMaterial *GetIndexedScreenOverlayMaterial( int i ) = 0; + virtual void ResetIndexedScreenOverlays() = 0; + virtual int GetMaxIndexedScreenOverlays() const = 0; +#endif + virtual void WriteSaveGameScreenshot( const char *pFilename ) = 0; virtual void WriteSaveGameScreenshotOfSize( const char *pFilename, int width, int height, bool bCreatePowerOf2Padded = false, bool bWriteVTF = false ) = 0; diff --git a/sp/src/game/client/viewdebug.cpp b/sp/src/game/client/viewdebug.cpp index 619993fa..a6537349 100644 --- a/sp/src/game/client/viewdebug.cpp +++ b/sp/src/game/client/viewdebug.cpp @@ -655,6 +655,57 @@ CON_COMMAND_F( r_screenoverlay, "Draw specified material as an overlay", FCVAR_C } } +#ifdef MAPBASE +//----------------------------------------------------------------------------- +// The same as above, but using the new indexed overlays +//----------------------------------------------------------------------------- +CON_COMMAND_F( r_screenoverlay_indexed, "Draw specified material as an overlay in the specified index", FCVAR_CHEAT|FCVAR_SERVER_CAN_EXECUTE ) +{ + if( args.ArgC() == 3 ) + { + int index = atoi( args[1] ); + if (index < 0 || index >= MAX_SCREEN_OVERLAYS) + { + Warning( "r_screenoverlay_indexed: '%i' is out of range (should be 0-9)\n", index ); + return; + } + + if ( !Q_stricmp( "off", args[2] ) ) + { + view->SetIndexedScreenOverlayMaterial( index, NULL ); + } + else + { + IMaterial *pMaterial = materials->FindMaterial( args[2], TEXTURE_GROUP_OTHER, false ); + if ( !IsErrorMaterial( pMaterial ) ) + { + view->SetIndexedScreenOverlayMaterial( index, pMaterial ); + } + else + { + view->SetIndexedScreenOverlayMaterial( index, NULL ); + } + } + } + else if ( args.ArgC() == 2 ) + { + int index = atoi( args[1] ); + if (index < 0 || index >= MAX_SCREEN_OVERLAYS) + { + Warning( "r_screenoverlay_indexed: '%i' is out of range (should be 0-9)\n", index ); + return; + } + + IMaterial *pMaterial = view->GetIndexedScreenOverlayMaterial( index ); + Warning( "r_screenoverlay_indexed %i: %s\n", index, pMaterial ? pMaterial->GetName() : "off" ); + } + else + { + Warning( "Format: r_screenoverlay_indexed %s\n" ); + } +} +#endif + // Used to verify frame syncing. void CDebugViewRender::GenerateOverdrawForTesting() { diff --git a/sp/src/game/client/viewrender.cpp b/sp/src/game/client/viewrender.cpp index 29f9c651..9ebc261a 100644 --- a/sp/src/game/client/viewrender.cpp +++ b/sp/src/game/client/viewrender.cpp @@ -1218,6 +1218,73 @@ IMaterial *CViewRender::GetScreenOverlayMaterial( ) } +#ifdef MAPBASE +//----------------------------------------------------------------------------- +// Purpose: Sets the screen space effect material (can't be done during rendering) +//----------------------------------------------------------------------------- +void CViewRender::SetIndexedScreenOverlayMaterial( int i, IMaterial *pMaterial ) +{ + if (i < 0 || i >= MAX_SCREEN_OVERLAYS) + return; + + m_IndexedScreenOverlayMaterials[i].Init( pMaterial ); + + if (pMaterial == NULL) + { + // Check if we should set to false + int i; + for (i = 0; i < MAX_SCREEN_OVERLAYS; i++) + { + if (m_IndexedScreenOverlayMaterials[i] != NULL) + break; + } + + if (i == MAX_SCREEN_OVERLAYS) + m_bUsingIndexedScreenOverlays = false; + } + else + { + m_bUsingIndexedScreenOverlays = true; + } +} + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +IMaterial *CViewRender::GetIndexedScreenOverlayMaterial( int i ) +{ + if (i < 0 || i >= MAX_SCREEN_OVERLAYS) + return NULL; + + return m_IndexedScreenOverlayMaterials[i]; +} + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CViewRender::ResetIndexedScreenOverlays() +{ + for (int i = 0; i < MAX_SCREEN_OVERLAYS; i++) + { + m_IndexedScreenOverlayMaterials[i].Init( NULL ); + } + + m_bUsingIndexedScreenOverlays = false; +} + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +int CViewRender::GetMaxIndexedScreenOverlays( ) const +{ + return MAX_SCREEN_OVERLAYS; +} +#endif + + //----------------------------------------------------------------------------- // Purpose: Performs screen space effects, if any //----------------------------------------------------------------------------- @@ -1254,6 +1321,44 @@ void CViewRender::PerformScreenOverlay( int x, int y, int w, int h ) render->ViewDrawFade( color, m_ScreenOverlayMaterial ); } } + +#ifdef MAPBASE + if (m_bUsingIndexedScreenOverlays) + { + for (int i = 0; i < MAX_SCREEN_OVERLAYS; i++) + { + if (!m_IndexedScreenOverlayMaterials[i]) + continue; + + tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ ); + + if ( m_IndexedScreenOverlayMaterials[i]->NeedsFullFrameBufferTexture() ) + { + // FIXME: check with multi/sub-rect renders. Should this be 0,0,w,h instead? + DrawScreenEffectMaterial( m_IndexedScreenOverlayMaterials[i], x, y, w, h ); + } + else if ( m_IndexedScreenOverlayMaterials[i]->NeedsPowerOfTwoFrameBufferTexture() ) + { + // First copy the FB off to the offscreen texture + UpdateRefractTexture( x, y, w, h, true ); + + // Now draw the entire screen using the material... + CMatRenderContextPtr pRenderContext( materials ); + ITexture *pTexture = GetPowerOfTwoFrameBufferTexture( ); + int sw = pTexture->GetActualWidth(); + int sh = pTexture->GetActualHeight(); + // Note - don't offset by x,y - already done by the viewport. + pRenderContext->DrawScreenSpaceRectangle( m_IndexedScreenOverlayMaterials[i], 0, 0, w, h, + 0, 0, sw-1, sh-1, sw, sh ); + } + else + { + byte color[4] = { 255, 255, 255, 255 }; + render->ViewDrawFade( color, m_IndexedScreenOverlayMaterials[i] ); + } + } + } +#endif } void CViewRender::DrawUnderwaterOverlay( void ) diff --git a/sp/src/game/client/viewrender.h b/sp/src/game/client/viewrender.h index 2312c4d5..5e99096a 100644 --- a/sp/src/game/client/viewrender.h +++ b/sp/src/game/client/viewrender.h @@ -468,6 +468,13 @@ private: IMaterial *GetScreenOverlayMaterial( ); void PerformScreenOverlay( int x, int y, int w, int h ); +#ifdef MAPBASE + void SetIndexedScreenOverlayMaterial( int i, IMaterial *pMaterial ); + IMaterial *GetIndexedScreenOverlayMaterial( int i ); + void ResetIndexedScreenOverlays(); + int GetMaxIndexedScreenOverlays() const; +#endif + void DrawUnderwaterOverlay( void ); // Water-related methods @@ -511,6 +518,10 @@ private: CMaterialReference m_TranslucentSingleColor; CMaterialReference m_ModulateSingleColor; CMaterialReference m_ScreenOverlayMaterial; +#ifdef MAPBASE + CMaterialReference m_IndexedScreenOverlayMaterials[MAX_SCREEN_OVERLAYS]; + bool m_bUsingIndexedScreenOverlays; +#endif CMaterialReference m_UnderWaterOverlayMaterial; Vector m_vecLastFacing; diff --git a/sp/src/game/server/env_screenoverlay.cpp b/sp/src/game/server/env_screenoverlay.cpp index 07bbf08d..259a6fdc 100644 --- a/sp/src/game/server/env_screenoverlay.cpp +++ b/sp/src/game/server/env_screenoverlay.cpp @@ -39,6 +39,9 @@ protected: CNetworkVar( float, m_flStartTime ); CNetworkVar( int, m_iDesiredOverlay ); CNetworkVar( bool, m_bIsActive ); +#ifdef MAPBASE + CNetworkVar( int, m_iOverlayIndex ); +#endif }; LINK_ENTITY_TO_CLASS( env_screenoverlay, CEnvScreenOverlay ); @@ -74,6 +77,9 @@ BEGIN_DATADESC( CEnvScreenOverlay ) DEFINE_FIELD( m_iDesiredOverlay, FIELD_INTEGER ), DEFINE_FIELD( m_flStartTime, FIELD_TIME ), DEFINE_FIELD( m_bIsActive, FIELD_BOOLEAN ), +#ifdef MAPBASE + DEFINE_KEYFIELD( m_iOverlayIndex, FIELD_INTEGER, "OverlayIndex" ), +#endif DEFINE_INPUTFUNC( FIELD_VOID, "StartOverlays", InputStartOverlay ), DEFINE_INPUTFUNC( FIELD_VOID, "StopOverlays", InputStopOverlay ), @@ -93,6 +99,9 @@ IMPLEMENT_SERVERCLASS_ST( CEnvScreenOverlay, DT_EnvScreenOverlay ) SendPropFloat( SENDINFO( m_flStartTime ), 32, SPROP_NOSCALE ), SendPropInt( SENDINFO( m_iDesiredOverlay ), 5 ), SendPropBool( SENDINFO( m_bIsActive ) ), +#ifdef MAPBASE + SendPropInt( SENDINFO( m_iOverlayIndex ), 5 ), +#endif END_SEND_TABLE() //----------------------------------------------------------------------------- @@ -103,6 +112,9 @@ CEnvScreenOverlay::CEnvScreenOverlay( void ) m_flStartTime = 0; m_iDesiredOverlay = 0; m_bIsActive = false; +#ifdef MAPBASE + m_iOverlayIndex = -1; +#endif } //----------------------------------------------------------------------------- From e39e1e0cca35975e4c9257e97b8bb3daea4046af Mon Sep 17 00:00:00 2001 From: Blixibon Date: Mon, 20 Sep 2021 23:46:39 -0500 Subject: [PATCH 143/378] Added a separate "host_pitchscale" cvar which can override host_timescale's sound pitch scaling --- sp/src/game/shared/SoundEmitterSystem.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sp/src/game/shared/SoundEmitterSystem.cpp b/sp/src/game/shared/SoundEmitterSystem.cpp index 06f73b72..6b10c6fe 100644 --- a/sp/src/game/shared/SoundEmitterSystem.cpp +++ b/sp/src/game/shared/SoundEmitterSystem.cpp @@ -132,12 +132,18 @@ void Hack_FixEscapeChars( char *str ) #ifdef MAPBASE static const ConVar *pHostTimescale; +static ConVar host_pitchscale( "host_pitchscale", "-1", FCVAR_REPLICATED, "If greater than 0, controls the pitch scale of sounds instead of host_timescale." ); static float GetSoundPitchScale() { static ConVarRef sv_cheats( "sv_cheats" ); if (sv_cheats.GetBool()) - return pHostTimescale->GetFloat(); + { + if (host_pitchscale.GetFloat() > 0.0f) + return host_pitchscale.GetFloat(); + else + return pHostTimescale->GetFloat(); + } return 1.0f; } From 8985ad2fe406a53c8ebd416289161c833e076daa Mon Sep 17 00:00:00 2001 From: Blixibon Date: Fri, 24 Sep 2021 00:11:18 -0500 Subject: [PATCH 144/378] Support for map-specific HUD animations and HUD layout scripts --- .../client/game_controls/baseviewport.cpp | 26 ++++++++ .../game/client/game_controls/baseviewport.h | 4 ++ sp/src/game/shared/mapbase/mapbase_shared.cpp | 65 ++++++++++++++++++- 3 files changed, 94 insertions(+), 1 deletion(-) diff --git a/sp/src/game/client/game_controls/baseviewport.cpp b/sp/src/game/client/game_controls/baseviewport.cpp index 0b99ef63..a0986620 100644 --- a/sp/src/game/client/game_controls/baseviewport.cpp +++ b/sp/src/game/client/game_controls/baseviewport.cpp @@ -146,6 +146,32 @@ bool CBaseViewport::LoadHudAnimations( void ) return true; } +#ifdef MAPBASE +//----------------------------------------------------------------------------- +// Purpose: Reloads HUD animations after loading a map-specific HUD animations file. +//----------------------------------------------------------------------------- +void CBaseViewport::ReloadHudAnimations( void ) +{ + // Force a reload + if ( LoadHudAnimations() == false ) + { + // Fall back to just the main + if ( m_pAnimController->SetScriptFile( GetVPanel(), "scripts/HudAnimations.txt", true ) == false ) + { + Assert(0); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: Loads a map-specific HUD animations file. +//----------------------------------------------------------------------------- +bool CBaseViewport::LoadCustomHudAnimations( const char *pszFile ) +{ + return m_pAnimController->SetScriptFile( GetVPanel(), pszFile, true ); +} +#endif + //================================================================ CBaseViewport::CBaseViewport() : vgui::EditablePanel( NULL, "CBaseViewport") { diff --git a/sp/src/game/client/game_controls/baseviewport.h b/sp/src/game/client/game_controls/baseviewport.h index 4e4c64e8..cbc602a0 100644 --- a/sp/src/game/client/game_controls/baseviewport.h +++ b/sp/src/game/client/game_controls/baseviewport.h @@ -73,6 +73,10 @@ public: public: // IGameEventListener: virtual void FireGameEvent( IGameEvent * event); +#ifdef MAPBASE + bool LoadCustomHudAnimations( const char *pszFile ); + void ReloadHudAnimations( void ); +#endif protected: diff --git a/sp/src/game/shared/mapbase/mapbase_shared.cpp b/sp/src/game/shared/mapbase/mapbase_shared.cpp index 3e776861..6701e0be 100644 --- a/sp/src/game/shared/mapbase/mapbase_shared.cpp +++ b/sp/src/game/shared/mapbase/mapbase_shared.cpp @@ -69,6 +69,9 @@ ConVar mapbase_version_client( "mapbase_version_client", MAPBASE_VERSION, FCVAR_ // This is from the vgui_controls library extern vgui::HScheme g_iCustomClientSchemeOverride; + +bool g_bUsingCustomHudAnimations = false; +bool g_bUsingCustomHudLayout = false; #endif extern void AddSurfacepropFile( const char *pFileName, IPhysicsSurfaceProps *pProps, IFileSystem *pFileSystem ); @@ -90,6 +93,8 @@ enum MANIFEST_CLOSECAPTION, MANIFEST_VGUI, MANIFEST_CLIENTSCHEME, + MANIFEST_HUDANIMATIONS, + MANIFEST_HUDLAYOUT, #else MANIFEST_TALKER, //MANIFEST_SENTENCES, @@ -125,6 +130,8 @@ static const ManifestType_t gm_szManifestFileStrings[MANIFEST_NUM_TYPES] = { { "closecaption", "mapbase_load_closecaption", "Should we load map-specific closed captioning? e.g. \"maps/_closecaption_english.txt\" and \"maps/_closecaption_english.dat\"" }, { "vgui", "mapbase_load_vgui", "Should we load map-specific VGUI screens? e.g. \"maps/_screens.txt\"" }, { "clientscheme", "mapbase_load_clientscheme", "Should we load map-specific ClientScheme.res overrides? e.g. \"maps/_clientscheme.res\"" }, + { "hudanimations", "mapbase_load_hudanimations", "Should we load map-specific HUD animation overrides? e.g. \"maps/_hudanimations.txt\"" }, + { "hudlayout", "mapbase_load_hudlayout", "Should we load map-specific HUD layout overrides? e.g. \"maps/_hudlayout.res\"" }, #else { "talker", "mapbase_load_talker", "Should we load map-specific talker files? e.g. \"maps/_talker.txt\"" }, //{ "sentences", "mapbase_load_sentences", "Should we load map-specific sentences? e.g. \"maps/_sentences.txt\"" }, @@ -264,18 +271,36 @@ public: { hudCloseCaption->RemoveCaptionDictionary( m_CloseCaptionFileNames[i] ); } + m_CloseCaptionFileNames.RemoveAll(); - if (g_iCustomClientSchemeOverride != 0) + if (g_iCustomClientSchemeOverride != 0 || g_bUsingCustomHudAnimations || g_bUsingCustomHudLayout) { + CGMsg( 1, CON_GROUP_MAPBASE_MISC, "Mapbase: Reloading client mode and viewport scheme\n" ); + // TODO: We currently have no way of actually cleaning up custom schemes upon level unload. // That may or may not be sustainable if there's a ton of custom schemes loaded at once g_iCustomClientSchemeOverride = 0; + g_bUsingCustomHudAnimations = false; + g_bUsingCustomHudLayout = false; + // Reload scheme ClientModeShared *mode = ( ClientModeShared * )GetClientModeNormal(); if ( mode ) { mode->ReloadScheme(); + + // We need to reload default values, so load a special "hudlayout_mapbase.res" file that only contains + // default Mapbase definitions identical to the defaults in the code + CBaseViewport *pViewport = dynamic_cast(g_pClientMode->GetViewport()); + if (pViewport) + { + KeyValuesAD pConditions( "conditions" ); + g_pClientMode->ComputeVguiResConditions( pConditions ); + + // reload the .res file from disk + pViewport->LoadControlSettings( "scripts/hudlayout_mapbase.res", NULL, NULL, pConditions ); + } } } #endif @@ -363,6 +388,42 @@ public: mode->ReloadScheme(); } } + + void LoadCustomHudAnimations( const char *pszFile ) + { + CBaseViewport *pViewport = dynamic_cast(g_pClientMode->GetViewport()); + if (pViewport) + { + g_bUsingCustomHudAnimations = true; + if (!pViewport->LoadCustomHudAnimations( pszFile )) + { + g_bUsingCustomHudAnimations = false; + CGWarning( 0, CON_GROUP_MAPBASE_MISC, "Custom HUD animations file \"%s\" failed to load\n", pszFile ); + pViewport->ReloadHudAnimations(); + } + else + { + CGMsg( 1, CON_GROUP_MAPBASE_MISC, "Loaded custom HUD animations file \"%s\"\n", pszFile );; + } + } + } + + void LoadCustomHudLayout( const char *pszFile ) + { + CBaseViewport *pViewport = dynamic_cast(g_pClientMode->GetViewport()); + if (pViewport) + { + g_bUsingCustomHudLayout = true; + + KeyValuesAD pConditions( "conditions" ); + g_pClientMode->ComputeVguiResConditions( pConditions ); + + // reload the .res file from disk + pViewport->LoadControlSettings( pszFile, NULL, NULL, pConditions ); + + CGMsg( 1, CON_GROUP_MAPBASE_MISC, "Loaded custom HUD layout file \"%s\"\n", pszFile );; + } + } #endif // Get a generic, hardcoded manifest with hardcoded names. @@ -422,6 +483,8 @@ public: } break; case MANIFEST_VGUI: { PanelMetaClassMgr()->LoadMetaClassDefinitionFile( value ); } break; case MANIFEST_CLIENTSCHEME: { LoadCustomScheme( value ); } break; + case MANIFEST_HUDANIMATIONS: { LoadCustomHudAnimations( value ); } break; + case MANIFEST_HUDLAYOUT: { LoadCustomHudLayout( value ); } break; //case MANIFEST_SOUNDSCAPES: { Soundscape_AddFile(value); } break; #else case MANIFEST_TALKER: { From f1bd6fcf810882480ceaf2727583f9c3de91bb2e Mon Sep 17 00:00:00 2001 From: Blixibon Date: Fri, 24 Sep 2021 00:12:45 -0500 Subject: [PATCH 145/378] Support for overriding HUD animations via map-specific scripts --- .../vgui_controls/AnimationController.cpp | 35 +++++++++++++++++-- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/sp/src/vgui2/vgui_controls/AnimationController.cpp b/sp/src/vgui2/vgui_controls/AnimationController.cpp index 6da33a38..886b4291 100644 --- a/sp/src/vgui2/vgui_controls/AnimationController.cpp +++ b/sp/src/vgui2/vgui_controls/AnimationController.cpp @@ -31,6 +31,11 @@ using namespace vgui; static CUtlSymbolTable g_ScriptSymbols(0, 128, true); +#ifdef MAPBASE +// Allows animation sequences to be overridden by map-specific files +extern bool g_bUsingCustomHudAnimations; +#endif + // singleton accessor for animation controller for use by the vgui controls namespace vgui { @@ -317,11 +322,35 @@ bool AnimationController::ParseScriptFile(char *pMem, int length) return false; } - int seqIndex; + int seqIndex = -1; UtlSymId_t nameIndex = g_ScriptSymbols.AddString(token); - // Create a new sequence - seqIndex = m_Sequences.AddToTail(); +#ifdef MAPBASE + if (g_bUsingCustomHudAnimations) + { + // look through for the sequence + for (seqIndex = 0; seqIndex < m_Sequences.Count(); seqIndex++) + { + if (m_Sequences[seqIndex].name == nameIndex) + break; + } + + if (seqIndex >= m_Sequences.Count()) + seqIndex = -1; + else + { + // Clear some stuff + m_Sequences[seqIndex].cmdList.RemoveAll(); + } + } + + if (seqIndex == -1) +#endif + { + // Create a new sequence + seqIndex = m_Sequences.AddToTail(); + } + AnimSequence_t &seq = m_Sequences[seqIndex]; seq.name = nameIndex; seq.duration = 0.0f; From 14a22858626988ce295c317d1ac245c6048d1492 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Fri, 24 Sep 2021 00:19:45 -0500 Subject: [PATCH 146/378] Overhauled fake world portals to be more stable and much cleaner internally --- .../mapbase/c_func_fake_worldportal.cpp | 7 +- .../client/mapbase/c_func_fake_worldportal.h | 4 +- sp/src/game/client/viewrender.cpp | 149 +++++++++--------- sp/src/game/client/viewrender.h | 2 +- .../server/mapbase/func_fake_worldportal.cpp | 2 +- 5 files changed, 81 insertions(+), 83 deletions(-) diff --git a/sp/src/game/client/mapbase/c_func_fake_worldportal.cpp b/sp/src/game/client/mapbase/c_func_fake_worldportal.cpp index 9d92675e..1cae8ebe 100644 --- a/sp/src/game/client/mapbase/c_func_fake_worldportal.cpp +++ b/sp/src/game/client/mapbase/c_func_fake_worldportal.cpp @@ -1,6 +1,6 @@ //========= Mapbase - https://github.com/mapbase-source/source-sdk-2013 ============// // -// Purpose: Recreates Portal 2 linked_portal_door functionality using SDK code only. +// Purpose: Recreates Portal 2 linked_portal_door visual functionality using SDK code only. // (basically a combination of point_camera and func_reflective_glass) // // $NoKeywords: $ @@ -120,8 +120,8 @@ C_FuncFakeWorldPortal *IsFakeWorldPortalInView( const CViewSetup& view, cplane_t //----------------------------------------------------------------------------- // Iterates through fake world portals instead of just picking one //----------------------------------------------------------------------------- -C_FuncFakeWorldPortal *NextFakeWorldPortal( C_FuncFakeWorldPortal *pStart, const CViewSetup& view, cplane_t &plane, - const Frustum_t &frustum ) +C_FuncFakeWorldPortal *NextFakeWorldPortal( C_FuncFakeWorldPortal *pStart, const CViewSetup& view, + cplane_t &plane, Vector &vecPlaneOrigin, const Frustum_t &frustum ) { // Early out if no cameras C_FuncFakeWorldPortal *pReflectiveGlass = NULL; @@ -167,6 +167,7 @@ C_FuncFakeWorldPortal *NextFakeWorldPortal( C_FuncFakeWorldPortal *pStart, const if ( !pReflectiveGlass->m_hTargetPlane ) continue; + vecPlaneOrigin = vecOrigin; return pReflectiveGlass; } } diff --git a/sp/src/game/client/mapbase/c_func_fake_worldportal.h b/sp/src/game/client/mapbase/c_func_fake_worldportal.h index 3fc4418b..1bae2de0 100644 --- a/sp/src/game/client/mapbase/c_func_fake_worldportal.h +++ b/sp/src/game/client/mapbase/c_func_fake_worldportal.h @@ -55,8 +55,8 @@ public: //----------------------------------------------------------------------------- C_FuncFakeWorldPortal *IsFakeWorldPortalInView( const CViewSetup& view, cplane_t &plane ); -C_FuncFakeWorldPortal *NextFakeWorldPortal( C_FuncFakeWorldPortal *pStart, const CViewSetup& view, cplane_t &plane, - const Frustum_t &frustum ); +C_FuncFakeWorldPortal *NextFakeWorldPortal( C_FuncFakeWorldPortal *pStart, const CViewSetup& view, + cplane_t &plane, Vector &vecPlaneOrigin, const Frustum_t &frustum ); #endif // C_FUNC_FAKE_WORLDPORTAL diff --git a/sp/src/game/client/viewrender.cpp b/sp/src/game/client/viewrender.cpp index 9ebc261a..e3889d74 100644 --- a/sp/src/game/client/viewrender.cpp +++ b/sp/src/game/client/viewrender.cpp @@ -2110,18 +2110,19 @@ void CViewRender::RenderView( const CViewSetup &view, int nClearFlags, int whatT GeneratePerspectiveFrustum( view.origin, view.angles, view.zNear, view.zFar, view.fov, view.m_flAspectRatio, frustum ); cplane_t portalPlane; + Vector vecPlaneOrigin; //C_FuncFakeWorldPortal *pPortalEnt = IsFakeWorldPortalInView( view, portalPlane ); //if ( pPortalEnt ) - C_FuncFakeWorldPortal *pPortalEnt = NextFakeWorldPortal( NULL, view, portalPlane, frustum ); + C_FuncFakeWorldPortal *pPortalEnt = NextFakeWorldPortal( NULL, view, portalPlane, vecPlaneOrigin, frustum ); while ( pPortalEnt != NULL ) { ITexture *pCameraTarget = pPortalEnt->RenderTarget(); int width = pCameraTarget->GetActualWidth(); int height = pCameraTarget->GetActualHeight(); - DrawFakeWorldPortal( pCameraTarget, pPortalEnt, viewMiddle, C_BasePlayer::GetLocalPlayer(), 0, 0, width, height, view, portalPlane ); + DrawFakeWorldPortal( pCameraTarget, pPortalEnt, viewMiddle, C_BasePlayer::GetLocalPlayer(), 0, 0, width, height, view, portalPlane, vecPlaneOrigin ); - pPortalEnt = NextFakeWorldPortal( pPortalEnt, view, portalPlane, frustum ); + pPortalEnt = NextFakeWorldPortal( pPortalEnt, view, portalPlane, vecPlaneOrigin, frustum ); } #endif } @@ -3539,8 +3540,7 @@ ConVar r_fakeworldportal_debug("r_fakeworldportal_debug", "0"); //----------------------------------------------------------------------------- // Purpose: Sets up scene and renders WIP fake world portal view. -// Based on code from monitors, mirrors, and 3D skyboxes. -// It's also terrible right now. +// Based on code from monitors, mirrors, and logic_measure_movement. // // Input : cameraNum - // &cameraView @@ -3554,7 +3554,7 @@ ConVar r_fakeworldportal_debug("r_fakeworldportal_debug", "0"); //----------------------------------------------------------------------------- bool CViewRender::DrawFakeWorldPortal( ITexture *pRenderTarget, C_FuncFakeWorldPortal *pCameraEnt, const CViewSetup &cameraView, C_BasePlayer *localPlayer, int x, int y, int width, int height, - const CViewSetup &mainView, cplane_t &ourPlane ) + const CViewSetup &mainView, cplane_t &ourPlane, const Vector &vecPlaneOrigin ) { #ifdef USE_MONITORS VPROF_INCREMENT_COUNTER( "cameras rendered", 1 ); @@ -3593,97 +3593,89 @@ bool CViewRender::DrawFakeWorldPortal( ITexture *pRenderTarget, C_FuncFakeWorldP monitorView.origin = mainView.origin; monitorView.angles = mainView.angles; - // Temporary debug stuff + // Debug stuff static float flLastDebugTime = 0.0f; bool bDebug = r_fakeworldportal_debug.GetBool() && gpGlobals->curtime > flLastDebugTime; - QAngle angTargetAngles = pCameraEnt->m_hTargetPlane->GetAbsAngles() + pCameraEnt->m_PlaneAngles; - - // RED - First origin - if (bDebug) - debugoverlay->AddBoxOverlay( monitorView.origin, Vector(-32,-32,-32), Vector(32,32,32), monitorView.angles, 255, 0, 0, 128, 10.0f ); - - // Make sure the origin and angles are relative to the target plane - monitorView.origin -= pCameraEnt->GetAbsOrigin(); - - // scale origin by sky scale - if ( pCameraEnt->m_flScale > 0 ) - { - float scale = 1.0f / pCameraEnt->m_flScale; - VectorScale( monitorView.origin, scale, monitorView.origin ); - } - - // YELLOW - Main origin - if (bDebug) - debugoverlay->AddBoxOverlay( pCameraEnt->GetAbsOrigin(), Vector(-32,-32,-32), Vector(32,32,32), monitorView.angles, 255, 224, 0, 128, 10.0f ); - - // Make sure our angles are relative to the main plane, just like the origin - QAngle angOurAngles; - VectorAngles( ourPlane.normal * -1, angOurAngles ); - //angles -= angOurAngles; - - // First, create a matrix for the sky's angles. - matrix3x4_t matSkyAngles; - AngleMatrix( angTargetAngles - angOurAngles, matSkyAngles ); - - Vector vecSkyForward, vecSkyRight, vecSkyUp; + // + // Calculate the angles for the fake portal plane + // + QAngle angTargetAngles = pCameraEnt->m_hTargetPlane->GetAbsAngles() - pCameraEnt->m_PlaneAngles; + QAngle angFakePortalAngles; // Get vectors from our original angles. - Vector vPlayerForward, vPlayerRight, vPlayerUp; - AngleVectors( monitorView.angles, &vPlayerForward, &vPlayerRight, &vPlayerUp ); - - VectorTransform( vPlayerForward, matSkyAngles, vecSkyForward ); - VectorTransform( vPlayerRight, matSkyAngles, vecSkyRight ); - VectorTransform( vPlayerUp, matSkyAngles, vecSkyUp ); - - // Normalize them. - VectorNormalize( vecSkyForward ); - VectorNormalize( vecSkyRight ); - VectorNormalize( vecSkyUp ); + Vector vOurForward, vOurRight, vOurUp; + AngleVectors( pCameraEnt->GetAbsAngles(), &vOurForward, &vOurRight, &vOurUp ); Quaternion quat; - BasisToQuaternion( vecSkyForward, vecSkyRight, vecSkyUp, quat ); - QuaternionAngles( quat, monitorView.angles ); + BasisToQuaternion( ourPlane.normal, vOurRight, vOurUp, quat ); + QuaternionAngles( quat, angFakePortalAngles ); - // End of code mostly lifted from projected texture screenspace stuff - // ---------------------------------------------------------------------- - - // Now just rotate our origin with that matrix. - // We create a copy of the origin since VectorRotate doesn't want in1 to be the same variable as the destination. - VectorRotate(Vector(monitorView.origin), matSkyAngles, monitorView.origin); - - // BLUE - Target origin - if (bDebug) - debugoverlay->AddBoxOverlay( pCameraEnt->m_hTargetPlane->GetAbsOrigin(), Vector(-32,-32,-32), Vector(32,32,32), monitorView.angles, 0, 0, 255, 128, 10.0f ); - - monitorView.origin += pCameraEnt->m_hTargetPlane->GetAbsOrigin(); - - // GREEN - Final origin if (bDebug) { + // RED - Initial player origin + debugoverlay->AddBoxOverlay( monitorView.origin, Vector(-32,-32,-32), Vector(32,32,32), monitorView.angles, 255, 0, 0, 128, 10.0f ); + + // YELLOW - Portal origin + debugoverlay->AddBoxOverlay( pCameraEnt->GetAbsOrigin(), Vector(-32,-32,-32), Vector(32,32,32), angFakePortalAngles, 255, 224, 0, 128, 10.0f ); + } + + // + // Translate the actual portal view position to be relative to the target + // + matrix3x4_t matPlayer, matPortal, matPlayerToPortal; + AngleIMatrix( monitorView.angles, monitorView.origin, matPlayer ); + AngleMatrix( angFakePortalAngles, pCameraEnt->GetAbsOrigin(), matPortal ); + ConcatTransforms( matPlayer, matPortal, matPlayerToPortal ); + + // Apply the scale factor + if ( pCameraEnt->m_flScale > 0 ) + { + Vector vecTranslation; + MatrixGetColumn( matPlayerToPortal, 3, vecTranslation ); + vecTranslation /= pCameraEnt->m_flScale; + MatrixSetColumn( vecTranslation, 3, matPlayerToPortal ); + } + + matrix3x4_t matTarget; + AngleMatrix( angTargetAngles, pCameraEnt->m_hTargetPlane->GetAbsOrigin(), matTarget ); + + // Now apply the new matrix to the new reference point + matrix3x4_t matPortalToPlayer, matNewPlayerPosition; + MatrixInvert( matPlayerToPortal, matPortalToPlayer ); + + ConcatTransforms( matTarget, matPortalToPlayer, matNewPlayerPosition ); + + MatrixAngles( matNewPlayerPosition, monitorView.angles, monitorView.origin ); + + if (bDebug) + { + // BLUE - Target origin + debugoverlay->AddBoxOverlay( pCameraEnt->m_hTargetPlane->GetAbsOrigin(), Vector(-32,-32,-32), Vector(32,32,32), angTargetAngles, 0, 0, 255, 128, 10.0f ); + + // GREEN - Final origin debugoverlay->AddBoxOverlay( monitorView.origin, Vector(-32,-32,-32), Vector(32,32,32), monitorView.angles, 0, 255, 0, 128, 10.0f ); flLastDebugTime = gpGlobals->curtime + 5.0f; } - monitorView.fov = mainView.fov; - monitorView.m_bOrtho = false; - monitorView.m_flAspectRatio = 0.0f; + monitorView.m_bOrtho = mainView.m_bOrtho; + monitorView.m_flAspectRatio = mainView.m_flAspectRatio; monitorView.m_bViewToProjectionOverride = false; // @MULTICORE (toml 8/11/2006): this should be a renderer.... int nClearFlags = (VIEW_CLEAR_DEPTH | VIEW_CLEAR_COLOR | VIEW_CLEAR_OBEY_STENCIL); bool bDrew3dSkybox = false; - SkyboxVisibility_t nSkyMode = pCameraEnt->SkyMode(); Frustum frustum; render->Push3DView( monitorView, nClearFlags, pRenderTarget, (VPlane *)frustum ); // - // Monitor sky handling + // Sky handling // - if ( pCameraEnt->SkyMode() == SKYBOX_3DSKYBOX_VISIBLE ) + SkyboxVisibility_t nSkyMode = pCameraEnt->SkyMode(); + if ( nSkyMode == SKYBOX_3DSKYBOX_VISIBLE ) { // if the 3d skybox world is drawn, then don't draw the normal skybox CSkyboxView *pSkyView = new CSkyboxView( this ); @@ -3694,16 +3686,21 @@ bool CViewRender::DrawFakeWorldPortal( ITexture *pRenderTarget, C_FuncFakeWorldP SafeRelease( pSkyView ); } + // + // Make a clipping plane for the target view + // Vector4D plane; - // Combine the target angles and the plane angles - Vector vecAnglesNormal( angTargetAngles.x, angTargetAngles.y, angTargetAngles.z ); + Vector vecAnglesNormal; + AngleVectors( angTargetAngles, &vecAnglesNormal ); VectorNormalize( vecAnglesNormal ); - VectorCopy( vecAnglesNormal, plane.AsVector3D() ); + VectorCopy( -vecAnglesNormal, plane.AsVector3D() ); - // TODO: How do we get a good value for this!?!? - //plane.w = m_OurPlane.dist + 0.1f; - plane.w = -32.0f + 0.1f; + // The portal plane's distance from the actual brush's origin + float flPlaneDist = vecPlaneOrigin.Length(); + + // The target's distance from world origin + plane.w = -((pCameraEnt->m_hTargetPlane->GetAbsOrigin() * vecAnglesNormal).Length() + flPlaneDist) + 0.1f; CMatRenderContextPtr pRenderContext( materials ); pRenderContext->PushCustomClipPlane( plane.Base() ); diff --git a/sp/src/game/client/viewrender.h b/sp/src/game/client/viewrender.h index 5e99096a..936a282b 100644 --- a/sp/src/game/client/viewrender.h +++ b/sp/src/game/client/viewrender.h @@ -454,7 +454,7 @@ private: #ifdef MAPBASE bool DrawFakeWorldPortal( ITexture *pRenderTarget, C_FuncFakeWorldPortal *pCameraEnt, const CViewSetup &cameraView, C_BasePlayer *localPlayer, int x, int y, int width, int height, - const CViewSetup &mainView, cplane_t &ourPlane ); + const CViewSetup &mainView, cplane_t &ourPlane, const Vector &vecPlaneOrigin ); #endif // Drawing primitives diff --git a/sp/src/game/server/mapbase/func_fake_worldportal.cpp b/sp/src/game/server/mapbase/func_fake_worldportal.cpp index 3184d2fa..de951b6a 100644 --- a/sp/src/game/server/mapbase/func_fake_worldportal.cpp +++ b/sp/src/game/server/mapbase/func_fake_worldportal.cpp @@ -1,6 +1,6 @@ //========= Mapbase - https://github.com/mapbase-source/source-sdk-2013 ============// // -// Purpose: Recreates Portal 2 linked_portal_door functionality using SDK code only. +// Purpose: Recreates Portal 2 linked_portal_door visual functionality using SDK code only. // (basically a combination of point_camera and func_reflective_glass) // //===========================================================================// From 8341a65a893ff51c88beee4a1f4db291d95ec6f1 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Fri, 24 Sep 2021 00:24:40 -0500 Subject: [PATCH 147/378] C_BaseAnimating tracks both server and client ragdolls --- sp/src/game/client/c_baseanimating.cpp | 12 ++++++++---- sp/src/game/client/c_baseanimating.h | 4 ++++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/sp/src/game/client/c_baseanimating.cpp b/sp/src/game/client/c_baseanimating.cpp index c8208e6a..c5b54eef 100644 --- a/sp/src/game/client/c_baseanimating.cpp +++ b/sp/src/game/client/c_baseanimating.cpp @@ -784,6 +784,10 @@ C_BaseAnimating::C_BaseAnimating() : m_nPrevSequence = -1; m_nRestoreSequence = -1; m_pRagdoll = NULL; + m_pClientsideRagdoll = NULL; +#ifdef MAPBASE + m_pServerRagdoll = NULL; +#endif m_builtRagdoll = false; m_hitboxBoneCacheHandle = 0; int i; @@ -4948,26 +4952,26 @@ C_BaseAnimating *C_BaseAnimating::BecomeRagdollOnClient() { MoveToLastReceivedPosition( true ); GetAbsOrigin(); - C_BaseAnimating *pRagdoll = CreateRagdollCopy(); + m_pClientsideRagdoll = CreateRagdollCopy(); matrix3x4_t boneDelta0[MAXSTUDIOBONES]; matrix3x4_t boneDelta1[MAXSTUDIOBONES]; matrix3x4_t currentBones[MAXSTUDIOBONES]; const float boneDt = 0.1f; GetRagdollInitBoneArrays( boneDelta0, boneDelta1, currentBones, boneDt ); - pRagdoll->InitAsClientRagdoll( boneDelta0, boneDelta1, currentBones, boneDt ); + m_pClientsideRagdoll->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() ) }; + ScriptVariant_t args[] = { ScriptVariant_t( m_pClientsideRagdoll->GetScriptInstance() ) }; g_Hook_OnClientRagdoll.Call( m_ScriptScope, NULL, args ); } #endif - return pRagdoll; + return m_pClientsideRagdoll; } bool C_BaseAnimating::InitAsClientRagdoll( const matrix3x4_t *pDeltaBones0, const matrix3x4_t *pDeltaBones1, const matrix3x4_t *pCurrentBonePosition, float boneDt, bool bFixedConstraints ) diff --git a/sp/src/game/client/c_baseanimating.h b/sp/src/game/client/c_baseanimating.h index 30b69ea7..342579dd 100644 --- a/sp/src/game/client/c_baseanimating.h +++ b/sp/src/game/client/c_baseanimating.h @@ -531,6 +531,10 @@ private: public: CRagdoll *m_pRagdoll; + C_BaseAnimating *m_pClientsideRagdoll; // From Alien Swarm SDK +#ifdef MAPBASE + C_BaseAnimating *m_pServerRagdoll; // Not from Alien Swarm SDK (note that this can exist without the entity having died) +#endif // Texture group to use int m_nSkin; From f11d7e0be871dfab2d22ca36701aa8e0f3392a8d Mon Sep 17 00:00:00 2001 From: Blixibon Date: Fri, 24 Sep 2021 00:26:51 -0500 Subject: [PATCH 148/378] Added model instance snatching for serverside ragdolls (retains decals) --- sp/src/game/client/ragdoll.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/sp/src/game/client/ragdoll.cpp b/sp/src/game/client/ragdoll.cpp index 0fc3d0e0..1e044a1d 100644 --- a/sp/src/game/client/ragdoll.cpp +++ b/sp/src/game/client/ragdoll.cpp @@ -487,6 +487,9 @@ int C_ServerRagdoll::InternalDrawModel( int flags ) return ret; } +#ifdef MAPBASE +static ConVar g_ragdoll_server_snatch_instance( "g_ragdoll_server_snatch_instance", "1", FCVAR_NONE, "Allows serverside ragdolls to snatch their source entities' model instances in the same way clientside ragdolls do, thereby retaining decals." ); +#endif CStudioHdr *C_ServerRagdoll::OnNewModel( void ) { @@ -509,6 +512,26 @@ CStudioHdr *C_ServerRagdoll::OnNewModel( void ) m_iv_ragAngles.SetMaxCount( m_elementCount ); } +#ifdef MAPBASE + if ( GetOwnerEntity() ) + { + if (GetOwnerEntity()->GetModelName() == GetModelName()) + { + // TODO: Is there a better place for this? + if (GetOwnerEntity()->GetBaseAnimating()) + GetOwnerEntity()->GetBaseAnimating()->m_pServerRagdoll = this; + + if (g_ragdoll_server_snatch_instance.GetBool()) + { + GetOwnerEntity()->SnatchModelInstance( this ); + } + } + } + + // Add server ragdolls to the creation tick list + NoteRagdollCreationTick( this ); +#endif + return hdr; } From 5d484bfa5fa7fe8aaeff5e7c132f450181f66f28 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Fri, 24 Sep 2021 00:30:49 -0500 Subject: [PATCH 149/378] Death ragdolls "steal" impact decals from final damage + clientside ragdolls already on the ground receive impact decals --- sp/src/game/client/fx_impact.cpp | 90 +++++++++++++++++++++++++++++++- sp/src/game/client/fx_impact.h | 9 ++++ 2 files changed, 97 insertions(+), 2 deletions(-) diff --git a/sp/src/game/client/fx_impact.cpp b/sp/src/game/client/fx_impact.cpp index 682d5435..41893f7b 100644 --- a/sp/src/game/client/fx_impact.cpp +++ b/sp/src/game/client/fx_impact.cpp @@ -25,6 +25,13 @@ extern ConVar r_drawmodeldecals; ImpactSoundRouteFn g_pImpactSoundRouteFn = NULL; +#ifdef MAPBASE +ConVar g_ragdoll_steal_impacts_client( "g_ragdoll_steal_impacts_client", "1", FCVAR_NONE, "Allows clientside death ragdolls to \"steal\" impacts from their source entities. This fixes issues with NPCs dying before decals are applied." ); +ConVar g_ragdoll_steal_impacts_server( "g_ragdoll_steal_impacts_server", "1", FCVAR_NONE, "Allows serverside death ragdolls to \"steal\" impacts from their source entities. This fixes issues with NPCs dying before decals are applied." ); + +ConVar g_ragdoll_client_impact_decals( "g_ragdoll_client_impact_decals", "1", FCVAR_NONE, "Applies decals to clientside ragdolls when they are hit." ); +#endif + //========================================================================================================================== // RAGDOLL ENUMERATOR //========================================================================================================================== @@ -32,7 +39,11 @@ CRagdollEnumerator::CRagdollEnumerator( Ray_t& shot, int iDamageType ) { m_rayShot = shot; m_iDamageType = iDamageType; +#ifdef MAPBASE + m_pHitEnt = NULL; +#else m_bHit = false; +#endif } IterationRetval_t CRagdollEnumerator::EnumElement( IHandleEntity *pHandleEntity ) @@ -57,7 +68,11 @@ IterationRetval_t CRagdollEnumerator::EnumElement( IHandleEntity *pHandleEntity if ( tr.fraction < 1.0 ) { pModel->ImpactTrace( &tr, m_iDamageType, NULL ); +#ifdef MAPBASE + m_pHitEnt = pModel; +#else m_bHit = true; +#endif //FIXME: Yes? No? return ITERATION_STOP; @@ -84,6 +99,22 @@ bool FX_AffectRagdolls( Vector vecOrigin, Vector vecStart, int iDamageType ) return ragdollEnum.Hit(); } +#ifdef MAPBASE +C_BaseAnimating *FX_AffectRagdolls_GetHit( Vector vecOrigin, Vector vecStart, int iDamageType ) +{ + // don't do this when lots of ragdolls are simulating + if ( s_RagdollLRU.CountRagdolls(true) > 1 ) + return false; + Ray_t shotRay; + shotRay.Init( vecStart, vecOrigin ); + + CRagdollEnumerator ragdollEnum( shotRay, iDamageType ); + partition->EnumerateElementsAlongRay( PARTITION_CLIENT_RESPONSIVE_EDICTS, shotRay, false, &ragdollEnum ); + + return ragdollEnum.GetHit(); +} +#endif + //----------------------------------------------------------------------------- // Purpose: // Input : &data - @@ -104,6 +135,22 @@ bool Impact( Vector &vecOrigin, Vector &vecStart, int iMaterial, int iDamageType Assert ( pEntity ); +#ifdef MAPBASE + // If the entity already has a ragdoll that was created on the current tick, use that ragdoll instead. + // This allows the killing damage's decals to show up on the ragdoll. + if (C_BaseAnimating *pAnimating = pEntity->GetBaseAnimating()) + { + if (pAnimating->m_pClientsideRagdoll && WasRagdollCreatedOnCurrentTick( pAnimating->m_pClientsideRagdoll ) && g_ragdoll_steal_impacts_client.GetBool()) + { + pEntity = pAnimating->m_pClientsideRagdoll; + } + else if (pAnimating->m_pServerRagdoll && WasRagdollCreatedOnCurrentTick( pAnimating->m_pServerRagdoll ) && g_ragdoll_steal_impacts_server.GetBool()) + { + pEntity = pAnimating->m_pServerRagdoll; + } + } +#endif + // Clear out the trace memset( &tr, 0, sizeof(trace_t)); tr.fraction = 1.0f; @@ -115,13 +162,52 @@ bool Impact( Vector &vecOrigin, Vector &vecStart, int iMaterial, int iDamageType VectorMA( vecStart, flLength + 8.0f, shotDir, traceExt ); // Attempt to hit ragdolls - + bool bHitRagdoll = false; - + +#ifdef MAPBASE + if ( !pEntity->IsClientCreated() ) + { + C_BaseAnimating *pRagdoll = FX_AffectRagdolls_GetHit( vecOrigin, vecStart, iDamageType ); + if (pRagdoll) + { + bHitRagdoll = true; + + if (g_ragdoll_client_impact_decals.GetBool()) + { + pEntity = pRagdoll; + + // HACKHACK: Get the ragdoll's nearest bone for its material + int iNearestMaterial = 0; + float flNearestDistSqr = FLT_MAX; + + IPhysicsObject *pList[VPHYSICS_MAX_OBJECT_LIST_COUNT]; + int count = pEntity->VPhysicsGetObjectList( pList, ARRAYSIZE(pList) ); + for ( int i = 0; i < count; i++ ) + { + Vector vecPosition; + QAngle angAngles; + pList[i]->GetPosition( &vecPosition, &angAngles ); + float flDistSqr = (vecStart - vecPosition).LengthSqr(); + if (flDistSqr < flNearestDistSqr) + { + iNearestMaterial = pList[i]->GetMaterialIndex(); + flNearestDistSqr = flDistSqr; + } + } + + // Get the material from the surfaceprop + surfacedata_t *psurfaceData = physprops->GetSurfaceData( iNearestMaterial ); + iMaterial = psurfaceData->game.material; + } + } + } +#else if ( !pEntity->IsClientCreated() ) { bHitRagdoll = FX_AffectRagdolls( vecOrigin, vecStart, iDamageType ); } +#endif if ( (nFlags & IMPACT_NODECAL) == 0 ) { diff --git a/sp/src/game/client/fx_impact.h b/sp/src/game/client/fx_impact.h index ad57f7e7..9c6cb875 100644 --- a/sp/src/game/client/fx_impact.h +++ b/sp/src/game/client/fx_impact.h @@ -58,12 +58,21 @@ public: // Actual work code virtual IterationRetval_t EnumElement( IHandleEntity *pHandleEntity ); +#ifdef MAPBASE + bool Hit( void ) const { return m_pHitEnt != NULL; } + C_BaseAnimating *GetHit( void ) { return m_pHitEnt; } +#else bool Hit( void ) const { return m_bHit; } +#endif private: Ray_t m_rayShot; int m_iDamageType; +#ifdef MAPBASE + C_BaseAnimating *m_pHitEnt; +#else bool m_bHit; +#endif }; #endif // FX_IMPACT_H From 256cdfb7af1c192e483d37f837c3e9eb1a98df7c Mon Sep 17 00:00:00 2001 From: Blixibon Date: Fri, 24 Sep 2021 13:10:37 -0500 Subject: [PATCH 150/378] Refactored the way certain classes and structs are exposed to VScript to make the code less reliant on metamethods and reduce awkward code placement --- sp/src/game/server/ai_basenpc.cpp | 6 +- sp/src/game/server/ai_memory.cpp | 23 ---- sp/src/game/server/ai_memory.h | 23 ---- sp/src/game/server/baseanimating.cpp | 5 +- .../shared/mapbase/vscript_consts_shared.cpp | 12 ++ .../shared/mapbase/vscript_funcs_shared.cpp | 76 +++++++++-- .../shared/mapbase/vscript_funcs_shared.h | 124 +++++++++++++++++- sp/src/game/shared/usercmd.h | 33 ----- sp/src/public/vphysics_interface.h | 24 ---- 9 files changed, 205 insertions(+), 121 deletions(-) diff --git a/sp/src/game/server/ai_basenpc.cpp b/sp/src/game/server/ai_basenpc.cpp index e62f7f66..09257b0d 100644 --- a/sp/src/game/server/ai_basenpc.cpp +++ b/sp/src/game/server/ai_basenpc.cpp @@ -100,6 +100,10 @@ #include "items.h" #endif +#ifdef MAPBASE_VSCRIPT +#include "mapbase/vscript_funcs_shared.h" +#endif + #include "env_debughistory.h" #include "collisionutils.h" @@ -729,7 +733,7 @@ HSCRIPT CAI_BaseNPC::VScriptFindEnemyMemory( HSCRIPT pEnemy ) AI_EnemyInfo_t *info = GetEnemies()->Find( ToEnt(pEnemy) ); if (info) { - hScript = g_pScriptVM->RegisterInstance( info ); + hScript = g_pScriptVM->RegisterInstance( reinterpret_cast(info) ); } return hScript; diff --git a/sp/src/game/server/ai_memory.cpp b/sp/src/game/server/ai_memory.cpp index 0af73a89..7ac69311 100644 --- a/sp/src/game/server/ai_memory.cpp +++ b/sp/src/game/server/ai_memory.cpp @@ -146,29 +146,6 @@ BEGIN_SIMPLE_DATADESC( AI_EnemyInfo_t ) // NOT SAVED nextEMemory END_DATADESC() -#ifdef MAPBASE_VSCRIPT -#define DEFINE_ENEMY_INFO_SCRIPTFUNCS(name, desc) \ - DEFINE_SCRIPTFUNC_NAMED( Get##name, #name, "Get " desc ) \ - DEFINE_SCRIPTFUNC( Set##name, "Set " desc ) - -BEGIN_SCRIPTDESC_ROOT( AI_EnemyInfo_t, "Accessor for information about an enemy." ) - DEFINE_SCRIPTFUNC( Enemy, "Get the enemy." ) - DEFINE_SCRIPTFUNC( SetEnemy, "Set the enemy." ) - DEFINE_ENEMY_INFO_SCRIPTFUNCS( LastKnownLocation, "the enemy's last known location." ) - DEFINE_ENEMY_INFO_SCRIPTFUNCS( LastSeenLocation, "the enemy's last seen location." ) - DEFINE_ENEMY_INFO_SCRIPTFUNCS( TimeLastSeen, "the last time the enemy was seen." ) - DEFINE_ENEMY_INFO_SCRIPTFUNCS( TimeFirstSeen, "the first time the enemy was seen." ) - DEFINE_ENEMY_INFO_SCRIPTFUNCS( TimeLastReacquired, "the last time the enemy was reaquired." ) - DEFINE_ENEMY_INFO_SCRIPTFUNCS( TimeValidEnemy, "the time at which the enemy can be selected (reaction delay)." ) - DEFINE_ENEMY_INFO_SCRIPTFUNCS( TimeLastReceivedDamageFrom, "the last time damage was received from this enemy." ) - DEFINE_ENEMY_INFO_SCRIPTFUNCS( TimeAtFirstHand, "the time at which the enemy was seen firsthand." ) - DEFINE_ENEMY_INFO_SCRIPTFUNCS( DangerMemory, "the memory of danger position w/o enemy pointer." ) - DEFINE_ENEMY_INFO_SCRIPTFUNCS( EludedMe, "whether the enemy is not at the last known location." ) - DEFINE_ENEMY_INFO_SCRIPTFUNCS( Unforgettable, "whether the enemy is unforgettable." ) - DEFINE_ENEMY_INFO_SCRIPTFUNCS( MobbedMe, "whether the enemy was part of a mob at some point." ) -END_SCRIPTDESC(); -#endif - //----------------------------------------------------------------------------- CAI_Enemies::CAI_Enemies(void) diff --git a/sp/src/game/server/ai_memory.h b/sp/src/game/server/ai_memory.h index faa482a2..d348c53e 100644 --- a/sp/src/game/server/ai_memory.h +++ b/sp/src/game/server/ai_memory.h @@ -45,29 +45,6 @@ struct AI_EnemyInfo_t bool bUnforgettable; bool bMobbedMe; // True if enemy was part of a mob at some point -#ifdef MAPBASE_VSCRIPT - // Script functions. - #define ENEMY_INFO_SCRIPT_FUNCS(type, name, var) \ - type Get##name() { return var; } \ - void Set##name( type v ) { var = v; } - - HSCRIPT Enemy() { return ToHScript(hEnemy); } - void SetEnemy( HSCRIPT ent ) { hEnemy = ToEnt(ent); } - - ENEMY_INFO_SCRIPT_FUNCS( Vector, LastKnownLocation, vLastKnownLocation ); - ENEMY_INFO_SCRIPT_FUNCS( Vector, LastSeenLocation, vLastSeenLocation ); - ENEMY_INFO_SCRIPT_FUNCS( float, TimeLastSeen, timeLastSeen ); - ENEMY_INFO_SCRIPT_FUNCS( float, TimeFirstSeen, timeFirstSeen ); - ENEMY_INFO_SCRIPT_FUNCS( float, TimeLastReacquired, timeLastReacquired ); - ENEMY_INFO_SCRIPT_FUNCS( float, TimeValidEnemy, timeValidEnemy ); - ENEMY_INFO_SCRIPT_FUNCS( float, TimeLastReceivedDamageFrom, timeLastReceivedDamageFrom ); - ENEMY_INFO_SCRIPT_FUNCS( float, TimeAtFirstHand, timeAtFirstHand ); - ENEMY_INFO_SCRIPT_FUNCS( bool, DangerMemory, bDangerMemory ); - ENEMY_INFO_SCRIPT_FUNCS( bool, EludedMe, bEludedMe ); - ENEMY_INFO_SCRIPT_FUNCS( bool, Unforgettable, bUnforgettable ); - ENEMY_INFO_SCRIPT_FUNCS( bool, MobbedMe, bMobbedMe ); -#endif - DECLARE_SIMPLE_DATADESC(); }; diff --git a/sp/src/game/server/baseanimating.cpp b/sp/src/game/server/baseanimating.cpp index cc578df0..5d27044a 100644 --- a/sp/src/game/server/baseanimating.cpp +++ b/sp/src/game/server/baseanimating.cpp @@ -32,6 +32,9 @@ #include "gib.h" #include "CRagdollMagnet.h" #endif +#ifdef MAPBASE_VSCRIPT +#include "mapbase/vscript_funcs_shared.h" +#endif // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -1296,7 +1299,7 @@ bool CBaseAnimating::ScriptHookHandleAnimEvent( animevent_t *pEvent ) { if (m_ScriptScope.IsInitialized() && g_Hook_HandleAnimEvent.CanRunInScope(m_ScriptScope)) { - HSCRIPT hEvent = g_pScriptVM->RegisterInstance( pEvent ); + HSCRIPT hEvent = g_pScriptVM->RegisterInstance( reinterpret_cast(pEvent) ); // event ScriptVariant_t args[] = { hEvent }; diff --git a/sp/src/game/shared/mapbase/vscript_consts_shared.cpp b/sp/src/game/shared/mapbase/vscript_consts_shared.cpp index e8efdee4..54273d6a 100644 --- a/sp/src/game/shared/mapbase/vscript_consts_shared.cpp +++ b/sp/src/game/shared/mapbase/vscript_consts_shared.cpp @@ -9,6 +9,7 @@ #include "activitylist.h" #include "in_buttons.h" #include "rope_shared.h" +#include "eventlist.h" #ifdef CLIENT_DLL #include "c_ai_basenpc.h" #else @@ -311,6 +312,17 @@ void RegisterSharedScriptConstants() ScriptRegisterConstant( g_pScriptVM, MOVETYPE_OBSERVER, "Move type used in GetMoveType(), etc." ); ScriptRegisterConstant( g_pScriptVM, MOVETYPE_CUSTOM, "Move type used in GetMoveType(), etc." ); + // + // Animation Stuff + // + ScriptRegisterConstant( g_pScriptVM, AE_TYPE_SERVER, "Animation event flag which indicates an event is supposed to be serverside only." ); + ScriptRegisterConstant( g_pScriptVM, AE_TYPE_SCRIPTED, "Animation event flag with an unknown purpose." ); + ScriptRegisterConstant( g_pScriptVM, AE_TYPE_SHARED, "Animation event flag which indicates an event is supposed to be shared between the server and client." ); + ScriptRegisterConstant( g_pScriptVM, AE_TYPE_WEAPON, "Animation event flag which indicates an event is part of a weapon." ); + ScriptRegisterConstant( g_pScriptVM, AE_TYPE_CLIENT, "Animation event flag which indicates an event is supposed to be clientside only." ); + ScriptRegisterConstant( g_pScriptVM, AE_TYPE_FACEPOSER, "Animation event flag with an unknown purpose. Presumably related to Faceposer." ); + ScriptRegisterConstant( g_pScriptVM, AE_TYPE_NEWEVENTSYSTEM, "Animation event flag which indicates an event is using the new system. This is often used by class-specific events from NPCs." ); + // // Ropes // diff --git a/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp b/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp index 26c0c1b8..aab303d8 100644 --- a/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp +++ b/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp @@ -323,7 +323,7 @@ BEGIN_SCRIPTDESC_ROOT_NAMED( CTraceInfoAccessor, "CGameTrace", "Handle for acces DEFINE_SCRIPTFUNC( Destroy, "Deletes this instance. Important for preventing memory leaks." ) END_SCRIPTDESC(); -BEGIN_SCRIPTDESC_ROOT_NAMED( surfacedata_t, "surfacedata_t", "Handle for accessing surface data." ) +BEGIN_SCRIPTDESC_ROOT_NAMED( scriptsurfacedata_t, "surfacedata_t", "Handle for accessing surface data." ) DEFINE_SCRIPTFUNC( GetFriction, "The surface's friction." ) DEFINE_SCRIPTFUNC( GetThickness, "The surface's thickness." ) @@ -342,16 +342,16 @@ BEGIN_SCRIPTDESC_ROOT_NAMED( surfacedata_t, "surfacedata_t", "Handle for accessi DEFINE_SCRIPTFUNC( GetSoundStrain, "The surface's strain sound." ) END_SCRIPTDESC(); -const char* surfacedata_t::GetSoundStepLeft() { return physprops->GetString( sounds.stepleft ); } -const char* surfacedata_t::GetSoundStepRight() { return physprops->GetString( sounds.stepright ); } -const char* surfacedata_t::GetSoundImpactSoft() { return physprops->GetString( sounds.impactSoft ); } -const char* surfacedata_t::GetSoundImpactHard() { return physprops->GetString( sounds.impactHard ); } -const char* surfacedata_t::GetSoundScrapeSmooth() { return physprops->GetString( sounds.scrapeSmooth ); } -const char* surfacedata_t::GetSoundScrapeRough() { return physprops->GetString( sounds.scrapeRough ); } -const char* surfacedata_t::GetSoundBulletImpact() { return physprops->GetString( sounds.bulletImpact ); } -const char* surfacedata_t::GetSoundRolling() { return physprops->GetString( sounds.rolling ); } -const char* surfacedata_t::GetSoundBreak() { return physprops->GetString( sounds.breakSound ); } -const char* surfacedata_t::GetSoundStrain() { return physprops->GetString( sounds.strainSound ); } +const char* scriptsurfacedata_t::GetSoundStepLeft() { return physprops->GetString( sounds.stepleft ); } +const char* scriptsurfacedata_t::GetSoundStepRight() { return physprops->GetString( sounds.stepright ); } +const char* scriptsurfacedata_t::GetSoundImpactSoft() { return physprops->GetString( sounds.impactSoft ); } +const char* scriptsurfacedata_t::GetSoundImpactHard() { return physprops->GetString( sounds.impactHard ); } +const char* scriptsurfacedata_t::GetSoundScrapeSmooth() { return physprops->GetString( sounds.scrapeSmooth ); } +const char* scriptsurfacedata_t::GetSoundScrapeRough() { return physprops->GetString( sounds.scrapeRough ); } +const char* scriptsurfacedata_t::GetSoundBulletImpact() { return physprops->GetString( sounds.bulletImpact ); } +const char* scriptsurfacedata_t::GetSoundRolling() { return physprops->GetString( sounds.rolling ); } +const char* scriptsurfacedata_t::GetSoundBreak() { return physprops->GetString( sounds.breakSound ); } +const char* scriptsurfacedata_t::GetSoundStrain() { return physprops->GetString( sounds.strainSound ); } BEGIN_SCRIPTDESC_ROOT_NAMED( CSurfaceScriptAccessor, "csurface_t", "Handle for accessing csurface_t info." ) DEFINE_SCRIPTFUNC( Name, "The surface's name." ) @@ -506,16 +506,36 @@ FireBulletsInfo_t *GetFireBulletsInfoFromInfo( HSCRIPT hBulletsInfo ) } //----------------------------------------------------------------------------- -// +// animevent_t //----------------------------------------------------------------------------- CAnimEventTInstanceHelper g_AnimEventTInstanceHelper; -BEGIN_SCRIPTDESC_ROOT( animevent_t, "Handle for accessing animevent_t info." ) +BEGIN_SCRIPTDESC_ROOT( scriptanimevent_t, "Handle for accessing animevent_t info." ) DEFINE_SCRIPT_INSTANCE_HELPER( &g_AnimEventTInstanceHelper ) + + DEFINE_SCRIPTFUNC( GetEvent, "Gets the event number." ) + DEFINE_SCRIPTFUNC( SetEvent, "Sets the event number." ) + + DEFINE_SCRIPTFUNC( GetOptions, "Gets the event's options/parameters." ) + DEFINE_SCRIPTFUNC( SetOptions, "Sets the event's options/parameters." ) + + DEFINE_SCRIPTFUNC( GetCycle, "Gets the cycle at which the event happens." ) + DEFINE_SCRIPTFUNC( SetCycle, "Sets the cycle at which the event happens." ) + + DEFINE_SCRIPTFUNC( GetEventTime, "Gets the time the event plays." ) + DEFINE_SCRIPTFUNC( SetEventTime, "Sets the time the event plays." ) + + DEFINE_SCRIPTFUNC( GetType, "Gets the event's type flags. See the 'AE_TYPE_' set of constants for valid flags." ) + DEFINE_SCRIPTFUNC( SetType, "Sets the event's type flags. See the 'AE_TYPE_' set of constants for valid flags." ) + + DEFINE_SCRIPTFUNC( GetSource, "Gets the event's source entity." ) + DEFINE_SCRIPTFUNC( SetSource, "Sets the event's source entity." ) END_SCRIPTDESC(); bool CAnimEventTInstanceHelper::Get( void *p, const char *pszKey, ScriptVariant_t &variant ) { + DevWarning( "VScript animevent_t.%s: animevent_t metamethod members are deprecated! Use 'script_help animevent_t' to see the correct functions.\n", pszKey ); + animevent_t *ani = ((animevent_t *)p); if (FStrEq( pszKey, "event" )) variant = ani->event; @@ -537,6 +557,8 @@ bool CAnimEventTInstanceHelper::Get( void *p, const char *pszKey, ScriptVariant_ bool CAnimEventTInstanceHelper::Set( void *p, const char *pszKey, ScriptVariant_t &variant ) { + DevWarning( "VScript animevent_t.%s: animevent_t metamethod members are deprecated! Use 'script_help animevent_t' to see the correct functions.\n", pszKey ); + animevent_t *ani = ((animevent_t *)p); if (FStrEq( pszKey, "event" )) ani->event = variant; @@ -611,7 +633,7 @@ END_SCRIPTDESC(); //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- -BEGIN_SCRIPTDESC_ROOT( CUserCmd, "Handle for accessing CUserCmd info." ) +BEGIN_SCRIPTDESC_ROOT_NAMED( CScriptUserCmd, "CUserCmd", "Handle for accessing CUserCmd info." ) DEFINE_SCRIPTFUNC( GetCommandNumber, "For matching server and client commands for debugging." ) DEFINE_SCRIPTFUNC_NAMED( ScriptGetTickCount, "GetTickCount", "The tick the client created this command." ) @@ -644,6 +666,32 @@ BEGIN_SCRIPTDESC_ROOT( CUserCmd, "Handle for accessing CUserCmd info." ) DEFINE_SCRIPTFUNC( SetMouseY, "Sets mouse accum in y from create move." ) END_SCRIPTDESC(); +#ifdef GAME_DLL +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +#define DEFINE_ENEMY_INFO_SCRIPTFUNCS(name, desc) \ + DEFINE_SCRIPTFUNC_NAMED( Get##name, #name, "Get " desc ) \ + DEFINE_SCRIPTFUNC( Set##name, "Set " desc ) + +BEGIN_SCRIPTDESC_ROOT_NAMED( Script_AI_EnemyInfo_t, "AI_EnemyInfo_t", "Accessor for information about an enemy." ) + DEFINE_SCRIPTFUNC( Enemy, "Get the enemy." ) + DEFINE_SCRIPTFUNC( SetEnemy, "Set the enemy." ) + DEFINE_ENEMY_INFO_SCRIPTFUNCS( LastKnownLocation, "the enemy's last known location." ) + DEFINE_ENEMY_INFO_SCRIPTFUNCS( LastSeenLocation, "the enemy's last seen location." ) + DEFINE_ENEMY_INFO_SCRIPTFUNCS( TimeLastSeen, "the last time the enemy was seen." ) + DEFINE_ENEMY_INFO_SCRIPTFUNCS( TimeFirstSeen, "the first time the enemy was seen." ) + DEFINE_ENEMY_INFO_SCRIPTFUNCS( TimeLastReacquired, "the last time the enemy was reaquired." ) + DEFINE_ENEMY_INFO_SCRIPTFUNCS( TimeValidEnemy, "the time at which the enemy can be selected (reaction delay)." ) + DEFINE_ENEMY_INFO_SCRIPTFUNCS( TimeLastReceivedDamageFrom, "the last time damage was received from this enemy." ) + DEFINE_ENEMY_INFO_SCRIPTFUNCS( TimeAtFirstHand, "the time at which the enemy was seen firsthand." ) + DEFINE_ENEMY_INFO_SCRIPTFUNCS( DangerMemory, "the memory of danger position w/o enemy pointer." ) + DEFINE_ENEMY_INFO_SCRIPTFUNCS( EludedMe, "whether the enemy is not at the last known location." ) + DEFINE_ENEMY_INFO_SCRIPTFUNCS( Unforgettable, "whether the enemy is unforgettable." ) + DEFINE_ENEMY_INFO_SCRIPTFUNCS( MobbedMe, "whether the enemy was part of a mob at some point." ) +END_SCRIPTDESC(); +#endif + //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- diff --git a/sp/src/game/shared/mapbase/vscript_funcs_shared.h b/sp/src/game/shared/mapbase/vscript_funcs_shared.h index 40055a88..c7ad9ca7 100644 --- a/sp/src/game/shared/mapbase/vscript_funcs_shared.h +++ b/sp/src/game/shared/mapbase/vscript_funcs_shared.h @@ -11,13 +11,41 @@ #pragma once #endif +#include "npcevent.h" +#ifdef GAME_DLL +#include "ai_memory.h" +#endif + +//----------------------------------------------------------------------------- +// Exposes surfacedata_t to VScript +//----------------------------------------------------------------------------- +struct scriptsurfacedata_t : public surfacedata_t +{ + float GetFriction() { return physics.friction; } + float GetThickness() { return physics.thickness; } + + float GetJumpFactor() { return game.jumpFactor; } + char GetMaterialChar() { return game.material; } + + const char* GetSoundStepLeft(); + const char* GetSoundStepRight(); + const char* GetSoundImpactSoft(); + const char* GetSoundImpactHard(); + const char* GetSoundScrapeSmooth(); + const char* GetSoundScrapeRough(); + const char* GetSoundBulletImpact(); + const char* GetSoundRolling(); + const char* GetSoundBreak(); + const char* GetSoundStrain(); +}; + //----------------------------------------------------------------------------- // Exposes csurface_t to VScript //----------------------------------------------------------------------------- class CSurfaceScriptAccessor { public: - CSurfaceScriptAccessor( csurface_t &surf ) { m_surf = &surf; m_surfaceData = g_pScriptVM->RegisterInstance( physprops->GetSurfaceData( m_surf->surfaceProps ) ); } + CSurfaceScriptAccessor( csurface_t &surf ) { m_surf = &surf; m_surfaceData = g_pScriptVM->RegisterInstance( reinterpret_cast(physprops->GetSurfaceData( m_surf->surfaceProps )) ); } ~CSurfaceScriptAccessor() { delete m_surfaceData; } // cplane_t stuff @@ -124,6 +152,32 @@ private: //----------------------------------------------------------------------------- // Exposes animevent_t to VScript //----------------------------------------------------------------------------- +struct scriptanimevent_t : public animevent_t +{ + int GetEvent() { return event; } + void SetEvent( int nEvent ) { event = nEvent; } + + const char *GetOptions() { return options; } + void SetOptions( const char *pOptions ) { options = pOptions; } + + float GetCycle() { return cycle; } + void SetCycle( float flCycle ) { cycle = flCycle; } + + float GetEventTime() { return eventtime; } + void SetEventTime( float flEventTime ) { eventtime = flEventTime; } + + int GetType() { return type; } + void SetType( int nType ) { eventtime = type; } + + HSCRIPT GetSource() { return ToHScript( pSource ); } + void SetSource( HSCRIPT hSource ) + { + CBaseEntity *pEnt = ToEnt( hSource ); + if (pEnt) + pSource = pEnt->GetBaseAnimating(); + } +}; + class CAnimEventTInstanceHelper : public IScriptInstanceHelper { bool Get( void *p, const char *pszKey, ScriptVariant_t &variant ); @@ -155,7 +209,7 @@ struct ScriptEmitSound_t : public EmitSound_t bool HasOrigin() { return m_pOrigin ? true : false; } const Vector &GetOrigin() { return m_pOrigin ? *m_pOrigin : vec3_origin; } - void SetOrigin( Vector origin ) { m_pOrigin = &origin; } + void SetOrigin( const Vector &origin ) { static Vector tempOrigin; tempOrigin = origin; m_pOrigin = &tempOrigin; } void ClearOrigin() { m_pOrigin = NULL; } float GetSoundTime() { return m_flSoundTime; } @@ -177,4 +231,70 @@ struct ScriptEmitSound_t : public EmitSound_t void SetSoundScriptHandle( int hSoundScriptHandle ) { m_hSoundScriptHandle = hSoundScriptHandle; } }; +//----------------------------------------------------------------------------- +// Exposes CUserCmd to VScript +//----------------------------------------------------------------------------- +class CScriptUserCmd : public CUserCmd +{ +public: + int GetCommandNumber() { return command_number; } + + int ScriptGetTickCount() { return tick_count; } + + const QAngle& GetViewAngles() { return viewangles; } + void SetViewAngles( const QAngle& val ) { viewangles = val; } + + float GetForwardMove() { return forwardmove; } + void SetForwardMove( float val ) { forwardmove = val; } + float GetSideMove() { return sidemove; } + void SetSideMove( float val ) { sidemove = val; } + float GetUpMove() { return upmove; } + void SetUpMove( float val ) { upmove = val; } + + int GetButtons() { return buttons; } + void SetButtons( int val ) { buttons = val; } + int GetImpulse() { return impulse; } + void SetImpulse( int val ) { impulse = val; } + + int GetWeaponSelect() { return weaponselect; } + void SetWeaponSelect( int val ) { weaponselect = val; } + int GetWeaponSubtype() { return weaponsubtype; } + void SetWeaponSubtype( int val ) { weaponsubtype = val; } + + int GetRandomSeed() { return random_seed; } + + int GetMouseX() { return mousedx; } + void SetMouseX( int val ) { mousedx = val; } + int GetMouseY() { return mousedy; } + void SetMouseY( int val ) { mousedy = val; } +}; + +#ifdef GAME_DLL +//----------------------------------------------------------------------------- +// Exposes AI_EnemyInfo_t to VScript +//----------------------------------------------------------------------------- +struct Script_AI_EnemyInfo_t : public AI_EnemyInfo_t +{ + #define ENEMY_INFO_SCRIPT_FUNCS(type, name, var) \ + type Get##name() { return var; } \ + void Set##name( type v ) { var = v; } + + HSCRIPT Enemy() { return ToHScript(hEnemy); } + void SetEnemy( HSCRIPT ent ) { hEnemy = ToEnt(ent); } + + ENEMY_INFO_SCRIPT_FUNCS( Vector, LastKnownLocation, vLastKnownLocation ); + ENEMY_INFO_SCRIPT_FUNCS( Vector, LastSeenLocation, vLastSeenLocation ); + ENEMY_INFO_SCRIPT_FUNCS( float, TimeLastSeen, timeLastSeen ); + ENEMY_INFO_SCRIPT_FUNCS( float, TimeFirstSeen, timeFirstSeen ); + ENEMY_INFO_SCRIPT_FUNCS( float, TimeLastReacquired, timeLastReacquired ); + ENEMY_INFO_SCRIPT_FUNCS( float, TimeValidEnemy, timeValidEnemy ); + ENEMY_INFO_SCRIPT_FUNCS( float, TimeLastReceivedDamageFrom, timeLastReceivedDamageFrom ); + ENEMY_INFO_SCRIPT_FUNCS( float, TimeAtFirstHand, timeAtFirstHand ); + ENEMY_INFO_SCRIPT_FUNCS( bool, DangerMemory, bDangerMemory ); + ENEMY_INFO_SCRIPT_FUNCS( bool, EludedMe, bEludedMe ); + ENEMY_INFO_SCRIPT_FUNCS( bool, Unforgettable, bUnforgettable ); + ENEMY_INFO_SCRIPT_FUNCS( bool, MobbedMe, bMobbedMe ); +}; +#endif + #endif diff --git a/sp/src/game/shared/usercmd.h b/sp/src/game/shared/usercmd.h index 6b87f888..04ff44ed 100644 --- a/sp/src/game/shared/usercmd.h +++ b/sp/src/game/shared/usercmd.h @@ -127,39 +127,6 @@ public: impulse = 0; } -#ifdef MAPBASE_VSCRIPT // These functions are needed for exposing CUserCmd to VScript. - int GetCommandNumber() { return command_number; } - - int ScriptGetTickCount() { return tick_count; } - - const QAngle& GetViewAngles() { return viewangles; } - void SetViewAngles( const QAngle& val ) { viewangles = val; } - - float GetForwardMove() { return forwardmove; } - void SetForwardMove( float val ) { forwardmove = val; } - float GetSideMove() { return sidemove; } - void SetSideMove( float val ) { sidemove = val; } - float GetUpMove() { return upmove; } - void SetUpMove( float val ) { upmove = val; } - - int GetButtons() { return buttons; } - void SetButtons( int val ) { buttons = val; } - int GetImpulse() { return impulse; } - void SetImpulse( int val ) { impulse = val; } - - int GetWeaponSelect() { return weaponselect; } - void SetWeaponSelect( int val ) { weaponselect = val; } - int GetWeaponSubtype() { return weaponsubtype; } - void SetWeaponSubtype( int val ) { weaponsubtype = val; } - - int GetRandomSeed() { return random_seed; } - - int GetMouseX() { return mousedx; } - void SetMouseX( int val ) { mousedx = val; } - int GetMouseY() { return mousedy; } - void SetMouseY( int val ) { mousedy = val; } -#endif - // For matching server and client commands for debugging int command_number; diff --git a/sp/src/public/vphysics_interface.h b/sp/src/public/vphysics_interface.h index d6e61935..1852ab8c 100644 --- a/sp/src/public/vphysics_interface.h +++ b/sp/src/public/vphysics_interface.h @@ -961,30 +961,6 @@ struct surfacedata_t surfacegameprops_t game; // Game data / properties surfacesoundhandles_t soundhandles; - -#ifdef MAPBASE_VSCRIPT - // These functions are for the VScript class description. - - float GetFriction() { return physics.friction; } - float GetThickness() { return physics.thickness; } - - float GetJumpFactor() { return game.jumpFactor; } - char GetMaterialChar() { return game.material; } - -#if defined(CLIENT_DLL) || defined(GAME_DLL) - const char* GetSoundStepLeft(); - const char* GetSoundStepRight(); - const char* GetSoundImpactSoft(); - const char* GetSoundImpactHard(); - const char* GetSoundScrapeSmooth(); - const char* GetSoundScrapeRough(); - const char* GetSoundBulletImpact(); - const char* GetSoundRolling(); - const char* GetSoundBreak(); - const char* GetSoundStrain(); -#endif - -#endif }; #define VPHYSICS_SURFACEPROPS_INTERFACE_VERSION "VPhysicsSurfaceProps001" From 5998158ac28b9d96e5c54cb3b59fbbc9032952bc Mon Sep 17 00:00:00 2001 From: Blixibon Date: Fri, 24 Sep 2021 13:18:04 -0500 Subject: [PATCH 151/378] OnItemDrop output for NPCs --- sp/src/game/server/ai_basenpc.cpp | 5 +++++ sp/src/game/server/ai_basenpc.h | 1 + sp/src/game/server/basecombatcharacter.cpp | 9 ++++++++- 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/sp/src/game/server/ai_basenpc.cpp b/sp/src/game/server/ai_basenpc.cpp index 09257b0d..f1ee3dbe 100644 --- a/sp/src/game/server/ai_basenpc.cpp +++ b/sp/src/game/server/ai_basenpc.cpp @@ -11576,6 +11576,10 @@ CBaseEntity *CAI_BaseNPC::DropItem ( const char *pszItemName, Vector vecPos, QAn pItem->ApplyLocalAngularVelocityImpulse( AngularImpulse( 0, random->RandomFloat( 0, 100 ), 0 ) ); } +#ifdef MAPBASE + m_OnItemDrop.Set( pItem, pItem, this ); +#endif + return pItem; } else @@ -11943,6 +11947,7 @@ BEGIN_DATADESC( CAI_BaseNPC ) DEFINE_OUTPUT( m_OnForcedInteractionFinished, "OnForcedInteractionFinished" ), #ifdef MAPBASE DEFINE_OUTPUT( m_OnItemPickup, "OnItemPickup" ), + DEFINE_OUTPUT( m_OnItemDrop, "OnItemDrop" ), #endif // Inputs diff --git a/sp/src/game/server/ai_basenpc.h b/sp/src/game/server/ai_basenpc.h index dd326d80..1a00cb87 100644 --- a/sp/src/game/server/ai_basenpc.h +++ b/sp/src/game/server/ai_basenpc.h @@ -2119,6 +2119,7 @@ public: COutputEHANDLE m_OnUnholsterWeapon; COutputEHANDLE m_OnItemPickup; + COutputEHANDLE m_OnItemDrop; COutputInt m_OnStateChange; #endif diff --git a/sp/src/game/server/basecombatcharacter.cpp b/sp/src/game/server/basecombatcharacter.cpp index 08d119dc..5f61ae37 100644 --- a/sp/src/game/server/basecombatcharacter.cpp +++ b/sp/src/game/server/basecombatcharacter.cpp @@ -1788,7 +1788,14 @@ void CBaseCombatCharacter::Event_Killed( const CTakeDamageInfo &info ) // if flagged to drop a health kit if (HasSpawnFlags(SF_NPC_DROP_HEALTHKIT)) { - CBaseEntity::Create( "item_healthvial", GetAbsOrigin(), GetAbsAngles() ); + CBaseEntity *pItem = CBaseEntity::Create( "item_healthvial", GetAbsOrigin(), GetAbsAngles() ); + if (pItem) + { +#ifdef MAPBASE + if (MyNPCPointer()) + MyNPCPointer()->m_OnItemDrop.Set( pItem, pItem, this ); +#endif + } } // clear the deceased's sound channels.(may have been firing or reloading when killed) EmitSound( "BaseCombatCharacter.StopWeaponSounds" ); From 394501826c7a8306ee8e28985e7964e6b8b5a74d Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sat, 25 Sep 2021 10:31:20 -0500 Subject: [PATCH 152/378] Forgot to reflect CUserCmd VScript change in player.cpp --- sp/src/game/server/player.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sp/src/game/server/player.cpp b/sp/src/game/server/player.cpp index 7efac526..e2465cc7 100644 --- a/sp/src/game/server/player.cpp +++ b/sp/src/game/server/player.cpp @@ -3831,7 +3831,7 @@ void CBasePlayer::PlayerRunCommand(CUserCmd *ucmd, IMoveHelper *moveHelper) // Movement hook for VScript if (m_ScriptScope.IsInitialized() && g_Hook_PlayerRunCommand.CanRunInScope(m_ScriptScope)) { - HSCRIPT hCmd = g_pScriptVM->RegisterInstance( ucmd ); + HSCRIPT hCmd = g_pScriptVM->RegisterInstance( reinterpret_cast(ucmd) ); // command ScriptVariant_t args[] = { hCmd }; From 4eae5f4e162d19cf3125519ee15ba143b555fd13 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sat, 25 Sep 2021 10:33:19 -0500 Subject: [PATCH 153/378] Fix flipped viewmodels not swinging, etc. correctly --- sp/src/game/shared/baseviewmodel_shared.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/sp/src/game/shared/baseviewmodel_shared.cpp b/sp/src/game/shared/baseviewmodel_shared.cpp index b7fef9b7..708c17bb 100644 --- a/sp/src/game/shared/baseviewmodel_shared.cpp +++ b/sp/src/game/shared/baseviewmodel_shared.cpp @@ -424,6 +424,21 @@ void CBaseViewModel::CalcViewModelView( CBasePlayer *owner, const Vector& eyePos g_ClientVirtualReality.OverrideViewModelTransform( vmorigin, vmangles, pWeapon && pWeapon->ShouldUseLargeViewModelVROverride() ); } +#ifdef MAPBASE + // Flip the view if we should be flipping + if (ShouldFlipViewModel()) + { + Vector vecOriginDiff = (eyePosition - vmorigin); + QAngle angAnglesDiff = (eyeAngles - vmangles); + + vmorigin.x = (eyePosition.x + vecOriginDiff.x); + vmorigin.y = (eyePosition.y + vecOriginDiff.y); + + vmangles.y = (eyeAngles.y + angAnglesDiff.y); + vmangles.z = (eyeAngles.z + angAnglesDiff.z); + } +#endif + SetLocalOrigin( vmorigin ); SetLocalAngles( vmangles ); From 24e6ab37670296c43eeec15d30ad366ca912891f Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sat, 25 Sep 2021 11:28:29 -0500 Subject: [PATCH 154/378] Added logic_substring to VPC --- sp/src/game/server/server_mapbase.vpc | 1 + 1 file changed, 1 insertion(+) diff --git a/sp/src/game/server/server_mapbase.vpc b/sp/src/game/server/server_mapbase.vpc index 9c943105..523ba827 100644 --- a/sp/src/game/server/server_mapbase.vpc +++ b/sp/src/game/server/server_mapbase.vpc @@ -69,6 +69,7 @@ $Project $File "mapbase\GlobalStrings.h" $File "mapbase\logic_externaldata.cpp" $File "mapbase\logic_skill.cpp" + $File "mapbase\logic_substring.cpp" $File "mapbase\point_advanced_finder.cpp" $File "mapbase\point_copy_size.cpp" $File "mapbase\point_damageinfo.cpp" From 85097e119e92dab1a1dbda55015046c4e303f13e Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sat, 25 Sep 2021 14:26:31 -0500 Subject: [PATCH 155/378] Grenade/alt-fire item dropping for metrocops and player companions --- sp/src/game/server/hl2/npc_combine.cpp | 4 + sp/src/game/server/hl2/npc_combine.h | 18 ++- sp/src/game/server/hl2/npc_metropolice.cpp | 11 ++ sp/src/game/server/hl2/npc_metropolice.h | 7 +- .../game/server/hl2/npc_playercompanion.cpp | 47 ++++++ sp/src/game/server/hl2/npc_playercompanion.h | 12 +- sp/src/game/server/mapbase/ai_grenade.cpp | 2 + sp/src/game/server/mapbase/ai_grenade.h | 143 +++++++++++++++++- 8 files changed, 232 insertions(+), 12 deletions(-) diff --git a/sp/src/game/server/hl2/npc_combine.cpp b/sp/src/game/server/hl2/npc_combine.cpp index 15c12c76..3076347d 100644 --- a/sp/src/game/server/hl2/npc_combine.cpp +++ b/sp/src/game/server/hl2/npc_combine.cpp @@ -230,7 +230,9 @@ DEFINE_INPUTFUNC( FIELD_STRING, "SetPoliceGoal", InputSetPoliceGoal ), DEFINE_AIGRENADE_DATADESC() #endif +#ifndef MAPBASE DEFINE_FIELD( m_iLastAnimEventHandled, FIELD_INTEGER ), +#endif DEFINE_FIELD( m_fIsElite, FIELD_BOOLEAN ), #ifndef MAPBASE DEFINE_FIELD( m_vecAltFireTarget, FIELD_VECTOR ), @@ -3687,7 +3689,9 @@ void CNPC_Combine::SetActivity( Activity NewActivity ) { BaseClass::SetActivity( NewActivity ); +#ifndef MAPBASE // CAI_GrenadeUser m_iLastAnimEventHandled = -1; +#endif } //----------------------------------------------------------------------------- diff --git a/sp/src/game/server/hl2/npc_combine.h b/sp/src/game/server/hl2/npc_combine.h index ec541cca..c9af8010 100644 --- a/sp/src/game/server/hl2/npc_combine.h +++ b/sp/src/game/server/hl2/npc_combine.h @@ -59,7 +59,7 @@ public: // Create components virtual bool CreateComponents(); -#ifndef MAPBASE +#ifndef MAPBASE // CAI_GrenadeUser bool CanThrowGrenade( const Vector &vecTarget ); bool CheckCanThrowGrenade( const Vector &vecTarget ); #endif @@ -118,7 +118,7 @@ public: const char* GetGrenadeAttachment() { return "lefthand"; } #else #endif -#ifndef MAPBASE +#ifndef MAPBASE // CAI_GrenadeUser void DelayAltFireAttack( float flDelay ); void DelaySquadAltFireAttack( float flDelay ); #endif @@ -131,7 +131,7 @@ public: Vector EyeOffset( Activity nActivity ); Vector EyePosition( void ); Vector BodyTarget( const Vector &posSrc, bool bNoisy = true ); -#ifndef MAPBASE +#ifndef MAPBASE // CAI_GrenadeUser Vector GetAltFireTarget(); #endif @@ -320,7 +320,7 @@ private: private: int m_nKickDamage; -#ifndef MAPBASE +#ifndef MAPBASE // CAI_GrenadeUser Vector m_vecTossVelocity; EHANDLE m_hForcedGrenadeTarget; #else @@ -334,12 +334,12 @@ private: // Time Variables float m_flNextPainSoundTime; float m_flNextAlertSoundTime; -#ifndef MAPBASE +#ifndef MAPBASE // CAI_GrenadeUser float m_flNextGrenadeCheck; #endif float m_flNextLostSoundTime; float m_flAlertPatrolTime; // When to stop doing alert patrol -#ifndef MAPBASE +#ifndef MAPBASE // CAI_GrenadeUser float m_flNextAltFireTime; // Elites only. Next time to begin considering alt-fire attack. #endif @@ -351,7 +351,7 @@ private: CAI_Sentence< CNPC_Combine > m_Sentences; #endif -#ifndef MAPBASE +#ifndef MAPBASE // CAI_GrenadeUser int m_iNumGrenades; #endif CAI_AssaultBehavior m_AssaultBehavior; @@ -365,9 +365,11 @@ private: #endif public: +#ifndef MAPBASE // CAI_GrenadeUser int m_iLastAnimEventHandled; +#endif bool m_fIsElite; -#ifndef MAPBASE +#ifndef MAPBASE // CAI_GrenadeUser Vector m_vecAltFireTarget; #endif diff --git a/sp/src/game/server/hl2/npc_metropolice.cpp b/sp/src/game/server/hl2/npc_metropolice.cpp index 8f708b6e..cf94fdbf 100644 --- a/sp/src/game/server/hl2/npc_metropolice.cpp +++ b/sp/src/game/server/hl2/npc_metropolice.cpp @@ -261,6 +261,7 @@ BEGIN_DATADESC( CNPC_MetroPolice ) #ifdef MAPBASE DEFINE_AIGRENADE_DATADESC() DEFINE_INPUT( m_iGrenadeCapabilities, FIELD_INTEGER, "SetGrenadeCapabilities" ), + DEFINE_INPUT( m_iGrenadeDropCapabilities, FIELD_INTEGER, "SetGrenadeDropCapabilities" ), #endif END_DATADESC() @@ -517,6 +518,11 @@ CNPC_MetroPolice::CNPC_MetroPolice() { #ifdef MAPBASE m_iGrenadeCapabilities = GRENCAP_GRENADE; + + if (ai_grenade_always_drop.GetBool()) + { + m_iGrenadeDropCapabilities = (eGrenadeDropCapabilities)(GRENDROPCAP_GRENADE | GRENDROPCAP_ALTFIRE | GRENDROPCAP_INTERRUPTED); + } #endif } @@ -3681,6 +3687,11 @@ void CNPC_MetroPolice::Event_Killed( const CTakeDamageInfo &info ) DropItem( "item_healthvial", WorldSpaceCenter()+RandomVector(-4,4), RandomAngle(0,360) ); pHL2GameRules->NPC_DroppedHealth(); } + +#ifdef MAPBASE + // Drop grenades if we should + DropGrenadeItemsOnDeath( info, pPlayer ); +#endif } BaseClass::Event_Killed( info ); diff --git a/sp/src/game/server/hl2/npc_metropolice.h b/sp/src/game/server/hl2/npc_metropolice.h index 1f3f9517..742de7e3 100644 --- a/sp/src/game/server/hl2/npc_metropolice.h +++ b/sp/src/game/server/hl2/npc_metropolice.h @@ -67,8 +67,12 @@ public: const char* GetGrenadeAttachment() { return "LHand"; } - virtual bool IsAltFireCapable() { return (m_iGrenadeCapabilities & GRENCAP_ALTFIRE) != 0; } + virtual bool IsAltFireCapable() { return (m_iGrenadeCapabilities & GRENCAP_ALTFIRE) != 0 && BaseClass::IsAltFireCapable(); } virtual bool IsGrenadeCapable() { return (m_iGrenadeCapabilities & GRENCAP_GRENADE) != 0; } + + virtual bool ShouldDropGrenades() { return (m_iGrenadeDropCapabilities & GRENDROPCAP_GRENADE) != 0 && BaseClass::ShouldDropGrenades(); } + virtual bool ShouldDropInterruptedGrenades() { return (m_iGrenadeDropCapabilities & GRENDROPCAP_INTERRUPTED) != 0 && BaseClass::ShouldDropInterruptedGrenades(); } + virtual bool ShouldDropAltFire() { return (m_iGrenadeDropCapabilities & GRENDROPCAP_ALTFIRE) != 0 && BaseClass::ShouldDropAltFire(); } #endif Vector EyeDirection3D( void ) { return CAI_BaseHumanoid::EyeDirection3D(); } // cops don't have eyes @@ -520,6 +524,7 @@ private: // Determines whether this NPC is allowed to use grenades or alt-fire stuff. eGrenadeCapabilities m_iGrenadeCapabilities; + eGrenadeDropCapabilities m_iGrenadeDropCapabilities; #endif AIHANDLE m_hManhack; diff --git a/sp/src/game/server/hl2/npc_playercompanion.cpp b/sp/src/game/server/hl2/npc_playercompanion.cpp index 8eec2e6d..6ee991e1 100644 --- a/sp/src/game/server/hl2/npc_playercompanion.cpp +++ b/sp/src/game/server/hl2/npc_playercompanion.cpp @@ -34,6 +34,7 @@ #ifdef MAPBASE #include "mapbase/GlobalStrings.h" #include "world.h" +#include "vehicle_base.h" #endif ConVar ai_debug_readiness("ai_debug_readiness", "0" ); @@ -148,6 +149,7 @@ BEGIN_DATADESC( CNPC_PlayerCompanion ) #ifdef MAPBASE DEFINE_AIGRENADE_DATADESC() DEFINE_INPUT( m_iGrenadeCapabilities, FIELD_INTEGER, "SetGrenadeCapabilities" ), + DEFINE_INPUT( m_iGrenadeDropCapabilities, FIELD_INTEGER, "SetGrenadeDropCapabilities" ), #endif END_DATADESC() @@ -175,6 +177,19 @@ string_t CNPC_PlayerCompanion::gm_iszAR2Classname; //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- +CNPC_PlayerCompanion::CNPC_PlayerCompanion() +{ +#ifdef MAPBASE + if (ai_grenade_always_drop.GetBool()) + { + m_iGrenadeDropCapabilities = (eGrenadeDropCapabilities)(GRENDROPCAP_GRENADE | GRENDROPCAP_ALTFIRE | GRENDROPCAP_INTERRUPTED); + } +#endif +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- + bool CNPC_PlayerCompanion::CreateBehaviors() { #ifdef HL2_EPISODIC @@ -4179,6 +4194,38 @@ void CNPC_PlayerCompanion::OnPlayerKilledOther( CBaseEntity *pVictim, const CTak } #ifdef MAPBASE +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CNPC_PlayerCompanion::Event_Killed( const CTakeDamageInfo &info ) +{ + // For now, allied player companions are set to always drop grenades and other items + // even if the player did not kill them + CBasePlayer *pPlayer = UTIL_GetLocalPlayer(); + if (!IsPlayerAlly( pPlayer )) + { + pPlayer = ToBasePlayer( info.GetAttacker() ); + + // See if there's a player in a vehicle instead (from CNPC_CombineS) + if ( !pPlayer ) + { + CPropVehicleDriveable *pVehicle = dynamic_cast( info.GetAttacker() ) ; + if ( pVehicle && pVehicle->GetDriver() && pVehicle->GetDriver()->IsPlayer() ) + { + pPlayer = assert_cast( pVehicle->GetDriver() ); + } + } + } + + if ( pPlayer != NULL ) + { + // Drop grenades if we should + DropGrenadeItemsOnDeath( info, pPlayer ); + } + + BaseClass::Event_Killed( info ); +} + //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void CNPC_PlayerCompanion::Event_KilledOther( CBaseEntity *pVictim, const CTakeDamageInfo &info ) diff --git a/sp/src/game/server/hl2/npc_playercompanion.h b/sp/src/game/server/hl2/npc_playercompanion.h index 81ba080c..2fe0b843 100644 --- a/sp/src/game/server/hl2/npc_playercompanion.h +++ b/sp/src/game/server/hl2/npc_playercompanion.h @@ -108,8 +108,10 @@ class CNPC_PlayerCompanion : public CAI_PlayerAlly { DECLARE_CLASS( CNPC_PlayerCompanion, CAI_PlayerAlly ); #endif - public: + + CNPC_PlayerCompanion(); + //--------------------------------- bool CreateBehaviors(); void Precache(); @@ -237,6 +239,7 @@ public: // This is just here to overwrite ai_playerally's TLK_ENEMY_DEAD virtual void OnKilledNPC(CBaseCombatCharacter *pKilled) {} + virtual void Event_Killed( const CTakeDamageInfo &info ); virtual void Event_KilledOther( CBaseEntity *pVictim, const CTakeDamageInfo &info ); virtual void DoCustomCombatAI( void ); #endif @@ -337,13 +340,18 @@ public: bool AllowReadinessValueChange( void ); #ifdef MAPBASE - virtual bool IsAltFireCapable() { return (m_iGrenadeCapabilities & GRENCAP_ALTFIRE) != 0; } + virtual bool IsAltFireCapable() { return (m_iGrenadeCapabilities & GRENCAP_ALTFIRE) != 0 && BaseClass::IsAltFireCapable(); } virtual bool IsGrenadeCapable() { return (m_iGrenadeCapabilities & GRENCAP_GRENADE) != 0; } + virtual bool ShouldDropGrenades() { return (m_iGrenadeDropCapabilities & GRENDROPCAP_GRENADE) != 0 && BaseClass::ShouldDropGrenades(); } + virtual bool ShouldDropInterruptedGrenades() { return (m_iGrenadeDropCapabilities & GRENDROPCAP_INTERRUPTED) != 0 && BaseClass::ShouldDropInterruptedGrenades(); } + virtual bool ShouldDropAltFire() { return (m_iGrenadeDropCapabilities & GRENDROPCAP_ALTFIRE) != 0 && BaseClass::ShouldDropAltFire(); } + private: // Determines whether this NPC is allowed to use grenades or alt-fire stuff. eGrenadeCapabilities m_iGrenadeCapabilities; + eGrenadeDropCapabilities m_iGrenadeDropCapabilities; #endif protected: diff --git a/sp/src/game/server/mapbase/ai_grenade.cpp b/sp/src/game/server/mapbase/ai_grenade.cpp index e14b47a3..a9ff5302 100644 --- a/sp/src/game/server/mapbase/ai_grenade.cpp +++ b/sp/src/game/server/mapbase/ai_grenade.cpp @@ -11,3 +11,5 @@ int COMBINE_AE_BEGIN_ALTFIRE; int COMBINE_AE_ALTFIRE; + +ConVar ai_grenade_always_drop( "ai_grenade_always_drop", "0", FCVAR_NONE, "Causes non-Combine grenade user NPCs to be allowed to drop grenades, alt-fire items, etc. *IF* the keyvalue has not already been set in Hammer. This is useful for debugging purposes or if a mod which was developed before this feature was introduced wants its NPCs to drop grenades and beyond without recompiling all of the maps." ); diff --git a/sp/src/game/server/mapbase/ai_grenade.h b/sp/src/game/server/mapbase/ai_grenade.h index 7f1ea8c1..69031d74 100644 --- a/sp/src/game/server/mapbase/ai_grenade.h +++ b/sp/src/game/server/mapbase/ai_grenade.h @@ -19,6 +19,9 @@ #include "basegrenade_shared.h" #include "ai_squad.h" #include "GlobalStrings.h" +#include "gameweaponmanager.h" +#include "hl2_gamerules.h" +#include "weapon_physcannon.h" #define COMBINE_AE_GREN_TOSS ( 7 ) @@ -36,6 +39,7 @@ DEFINE_FIELD( m_flNextAltFireTime, FIELD_TIME ), \ DEFINE_FIELD( m_vecAltFireTarget, FIELD_VECTOR ), \ DEFINE_FIELD( m_vecTossVelocity, FIELD_VECTOR ), \ + DEFINE_FIELD( m_iLastAnimEventHandled, FIELD_INTEGER ), \ DEFINE_INPUTFUNC( FIELD_STRING, "ThrowGrenadeAtTarget", InputThrowGrenadeAtTarget ), \ DEFINE_INPUTFUNC( FIELD_INTEGER, "SetGrenades", InputSetGrenades ), \ DEFINE_INPUTFUNC( FIELD_INTEGER, "AddGrenades", InputAddGrenades ), \ @@ -61,12 +65,22 @@ extern int COMBINE_AE_BEGIN_ALTFIRE; extern int COMBINE_AE_ALTFIRE; +extern ConVar ai_grenade_always_drop; + enum eGrenadeCapabilities { GRENCAP_GRENADE = (1 << 0), GRENCAP_ALTFIRE = (1 << 1), }; +// What grenade/item types NPCs are capable of dropping +enum eGrenadeDropCapabilities +{ + GRENDROPCAP_GRENADE = (1 << 0), + GRENDROPCAP_ALTFIRE = (1 << 1), + GRENDROPCAP_INTERRUPTED = (1 << 2), // Drops grenades when interrupted mid-animation +}; + //----------------------------------------------------------------------------- // Other classes can use this and access some CAI_GrenadeUser functions. //----------------------------------------------------------------------------- @@ -102,7 +116,8 @@ public: m_OnOutOfGrenades.Set( pLastGrenade, pLastGrenade, this ); } - virtual bool IsAltFireCapable() { return false; } + // Use secondary ammo as a way of checking if this is a weapon which can be alt-fired (e.g. AR2 or SMG) + virtual bool IsAltFireCapable() { return (GetActiveWeapon() && GetActiveWeapon()->UsesSecondaryAmmo()); } virtual bool IsGrenadeCapable() { return true; } inline bool HasGrenades() { return m_iNumGrenades > 0; } @@ -113,6 +128,7 @@ public: virtual void DelayGrenadeCheck( float delay ) { m_flNextGrenadeCheck = gpGlobals->curtime + delay; } void HandleAnimEvent( animevent_t *pEvent ); + void SetActivity( Activity NewActivity ); // Soldiers use "lefthand", cops use "LHand", and citizens use "anim_attachment_LH" virtual const char* GetGrenadeAttachment() { return "anim_attachment_LH"; } @@ -131,6 +147,12 @@ public: // For OnThrowGrenade + point_entity_replace, see grenade_frag.cpp bool UsingOnThrowGrenade() { return m_OnThrowGrenade.NumberOfElements() > 0; } + // For dropping grenades and beyond + void DropGrenadeItemsOnDeath( const CTakeDamageInfo &info, CBasePlayer *pPlayer ); + virtual bool ShouldDropGrenades() { return HasGrenades(); } + virtual bool ShouldDropInterruptedGrenades() { return true; } + virtual bool ShouldDropAltFire() { return HasGrenades(); } + protected: void StartTask_FaceAltFireTarget( const Task_t *pTask ); @@ -151,6 +173,9 @@ protected: // We can't have any private saved variables because only derived cla Vector m_vecAltFireTarget; Vector m_vecTossVelocity; + // CNPC_Combine port for determining if we tossed a grenade + int m_iLastAnimEventHandled; + COutputEHANDLE m_OnThrowGrenade; COutputEHANDLE m_OnOutOfGrenades; }; @@ -166,6 +191,8 @@ void CAI_GrenadeUser::HandleAnimEvent( animevent_t *pEvent ) if (this->GetActiveWeapon()) this->GetActiveWeapon()->WeaponSound( SPECIAL1 ); + m_iLastAnimEventHandled = pEvent->event; + //SpeakIfAllowed( TLK_CMB_THROWGRENADE, "altfire:1" ); return; } @@ -185,6 +212,8 @@ void CAI_GrenadeUser::HandleAnimEvent( animevent_t *pEvent ) AddGrenades(-1); + m_iLastAnimEventHandled = pEvent->event; + return; } @@ -221,12 +250,25 @@ void CAI_GrenadeUser::HandleAnimEvent( animevent_t *pEvent ) // wait six seconds before even looking again to see if a grenade can be thrown. m_flNextGrenadeCheck = gpGlobals->curtime + 6; + + m_iLastAnimEventHandled = pEvent->event; + return; } BaseClass::HandleAnimEvent( pEvent ); } +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +template +void CAI_GrenadeUser::SetActivity( Activity NewActivity ) +{ + BaseClass::SetActivity( NewActivity ); + + m_iLastAnimEventHandled = -1; +} + //----------------------------------------------------------------------------- // Purpose: Force the combine soldier to throw a grenade at the target // If I'm a combine elite, fire my combine ball at the target instead. @@ -534,6 +576,105 @@ void CAI_GrenadeUser::ClearAttackConditions() } } +//----------------------------------------------------------------------------- +// Purpose: Drops grenades and alt-fire items on death. Based on code from npc_combines.cpp and npc_combine.cpp +//----------------------------------------------------------------------------- +template +void CAI_GrenadeUser::DropGrenadeItemsOnDeath( const CTakeDamageInfo &info, CBasePlayer *pPlayer ) +{ + // Elites drop alt-fire ammo, so long as they weren't killed by dissolving. + if( IsAltFireCapable() && ShouldDropAltFire() ) + { + CBaseEntity *pItem; + if (this->GetActiveWeapon() && FClassnameIs( this->GetActiveWeapon(), "weapon_smg1" )) + pItem = this->DropItem( "item_ammo_smg1_grenade", WorldSpaceCenter()+RandomVector(-4,4), RandomAngle(0,360) ); + else + pItem = this->DropItem( "item_ammo_ar2_altfire", WorldSpaceCenter() + RandomVector( -4, 4 ), RandomAngle( 0, 360 ) ); + + if ( pItem ) + { + IPhysicsObject *pObj = pItem->VPhysicsGetObject(); + + if ( pObj ) + { + Vector vel = RandomVector( -64.0f, 64.0f ); + AngularImpulse angImp = RandomAngularImpulse( -300.0f, 300.0f ); + + vel[2] = 0.0f; + pObj->AddVelocity( &vel, &angImp ); + } + + if( info.GetDamageType() & DMG_DISSOLVE ) + { + CBaseAnimating *pAnimating = dynamic_cast(pItem); + + if( pAnimating ) + { + pAnimating->Dissolve( NULL, gpGlobals->curtime, false, ENTITY_DISSOLVE_NORMAL ); + } + } + else + { + WeaponManager_AddManaged( pItem ); + } + } + } + + if ( IsGrenadeCapable() ) + { + if ( ShouldDropGrenades() ) + { + CHalfLife2 *pHL2GameRules = static_cast(g_pGameRules); + + // Attempt to drop a grenade + if ( pHL2GameRules->NPC_ShouldDropGrenade( pPlayer ) ) + { + this->DropItem( "weapon_frag", WorldSpaceCenter()+RandomVector(-4,4), RandomAngle(0,360) ); + pHL2GameRules->NPC_DroppedGrenade(); + } + } + + // if I was killed before I could finish throwing my grenade, drop + // a grenade item that the player can retrieve. + if (GetActivity() == ACT_RANGE_ATTACK2 && ShouldDropInterruptedGrenades()) + { + if( m_iLastAnimEventHandled != COMBINE_AE_GREN_TOSS ) + { + // Drop the grenade as an item. + Vector vecStart; + this->GetAttachment( GetGrenadeAttachment(), vecStart ); + + CBaseEntity *pItem = DropItem( "weapon_frag", vecStart, RandomAngle(0,360) ); + + if ( pItem ) + { + IPhysicsObject *pObj = pItem->VPhysicsGetObject(); + + if ( pObj ) + { + Vector vel; + vel.x = random->RandomFloat( -100.0f, 100.0f ); + vel.y = random->RandomFloat( -100.0f, 100.0f ); + vel.z = random->RandomFloat( 800.0f, 1200.0f ); + AngularImpulse angImp = RandomAngularImpulse( -300.0f, 300.0f ); + + vel[2] = 0.0f; + pObj->AddVelocity( &vel, &angImp ); + } + + // In the Citadel we need to dissolve this + if ( PlayerHasMegaPhysCannon() && GlobalEntity_GetCounter("super_phys_gun") != 1 ) + { + CBaseCombatWeapon *pWeapon = static_cast(pItem); + + pWeapon->Dissolve( NULL, gpGlobals->curtime, false, ENTITY_DISSOLVE_NORMAL ); + } + } + } + } + } +} + //----------------------------------------------------------------------------- // Purpose: Task helpers //----------------------------------------------------------------------------- From f61b933ed3d40c6f561a0cf94800788c9449f4e7 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sat, 25 Sep 2021 14:27:11 -0500 Subject: [PATCH 156/378] Fix for a crash which occurs when NPCs pick up a weapon the player is already holding --- sp/src/game/server/ai_basenpc.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sp/src/game/server/ai_basenpc.cpp b/sp/src/game/server/ai_basenpc.cpp index f1ee3dbe..1aa07ac7 100644 --- a/sp/src/game/server/ai_basenpc.cpp +++ b/sp/src/game/server/ai_basenpc.cpp @@ -11495,6 +11495,14 @@ bool CAI_BaseNPC::ChooseEnemy( void ) //========================================================= void CAI_BaseNPC::PickupWeapon( CBaseCombatWeapon *pWeapon ) { +#ifdef MAPBASE + if ( pWeapon->VPhysicsGetObject() && pWeapon->VPhysicsGetObject()->GetGameFlags() & FVPHYSICS_PLAYER_HELD ) + { + CBasePlayer *pPlayer = UTIL_GetLocalPlayer(); + pPlayer->ForceDropOfCarriedPhysObjects( pWeapon ); + } +#endif + pWeapon->OnPickedUp( this ); Weapon_Equip( pWeapon ); m_iszPendingWeapon = NULL_STRING; From 59825cb6c1e3262c6d299557de7adc490b72ffeb Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sat, 25 Sep 2021 14:28:44 -0500 Subject: [PATCH 157/378] Added Mapbase RT cameras to mat_showcamerarendertarget and fixed the command's materials not being referenced --- sp/src/game/client/viewdebug.cpp | 57 ++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/sp/src/game/client/viewdebug.cpp b/sp/src/game/client/viewdebug.cpp index a6537349..0204a0ab 100644 --- a/sp/src/game/client/viewdebug.cpp +++ b/sp/src/game/client/viewdebug.cpp @@ -29,6 +29,9 @@ static ConVar mat_wateroverlaysize( "mat_wateroverlaysize", "256" ); static ConVar mat_showframebuffertexture( "mat_showframebuffertexture", "0", FCVAR_CHEAT ); static ConVar mat_framebuffercopyoverlaysize( "mat_framebuffercopyoverlaysize", "256" ); static ConVar mat_showcamerarendertarget( "mat_showcamerarendertarget", "0", FCVAR_CHEAT ); +#ifdef MAPBASE +static ConVar mat_showcamerarendertarget_all( "mat_showcamerarendertarget_all", "0", FCVAR_CHEAT ); +#endif static ConVar mat_camerarendertargetoverlaysize( "mat_camerarendertargetoverlaysize", "256", FCVAR_CHEAT ); static ConVar mat_hsv( "mat_hsv", "0", FCVAR_CHEAT ); static ConVar mat_yuv( "mat_yuv", "0", FCVAR_CHEAT ); @@ -178,6 +181,11 @@ void OverlayCameraRenderTarget( const char *pszMaterialName, float flX, float fl pMaterial = materials->FindMaterial( pszMaterialName, TEXTURE_GROUP_OTHER, true ); if( !IsErrorMaterial( pMaterial ) ) { +#ifdef MAPBASE + // HACKHACK + pMaterial->IncrementReferenceCount(); +#endif + CMatRenderContextPtr pRenderContext( materials ); pRenderContext->Bind( pMaterial ); IMesh* pMesh = pRenderContext->GetDynamicMesh( true ); @@ -203,6 +211,11 @@ void OverlayCameraRenderTarget( const char *pszMaterialName, float flX, float fl meshBuilder.End(); pMesh->Draw(); + +#ifdef MAPBASE + // HACKHACK + pMaterial->DecrementReferenceCount(); +#endif } } @@ -214,7 +227,11 @@ static void OverlayFrameBufferTexture( int nFrameBufferIndex ) IMaterial *pMaterial; char buf[MAX_PATH]; Q_snprintf( buf, MAX_PATH, "debug/debugfbtexture%d", nFrameBufferIndex ); +#ifdef MAPBASE + pMaterial = materials->FindMaterial( buf, NULL, true ); +#else pMaterial = materials->FindMaterial( buf, TEXTURE_GROUP_OTHER, true ); +#endif if( !IsErrorMaterial( pMaterial ) ) { CMatRenderContextPtr pRenderContext( materials ); @@ -586,12 +603,52 @@ void CDebugViewRender::Draw2DDebuggingInfo( const CViewSetup &view ) if ( mat_showcamerarendertarget.GetBool() ) { +#ifdef MAPBASE + float w = mat_camerarendertargetoverlaysize.GetFloat(); + float h = mat_camerarendertargetoverlaysize.GetFloat(); +#else float w = mat_wateroverlaysize.GetFloat(); float h = mat_wateroverlaysize.GetFloat(); +#endif #ifdef PORTAL g_pPortalRender->OverlayPortalRenderTargets( w, h ); #else + +#ifdef MAPBASE + int iCameraNum = mat_showcamerarendertarget.GetInt(); + + if (iCameraNum == 1) // Display the default camera + { + OverlayCameraRenderTarget( "debug/debugcamerarendertarget", 0, 0, w, h ); + } + else if (mat_showcamerarendertarget_all.GetBool()) // Display all cameras + { + OverlayCameraRenderTarget( "debug/debugcamerarendertarget", 0, 0, w, h ); + + // Already showed one camera + iCameraNum--; + + // Show Mapbase's cameras + char szTextureName[48]; + for (int i = 0; i < iCameraNum; i++) + { + V_snprintf( szTextureName, sizeof( szTextureName ), "debug/debugcamerarendertarget_camera%i", i ); + + // Show them vertically if the cvar is set to 2 + if (mat_showcamerarendertarget_all.GetInt() == 2) + OverlayCameraRenderTarget( szTextureName, 0, h * (i + 1), w, h ); + else + OverlayCameraRenderTarget( szTextureName, w * (i + 1), 0, w, h ); + } + } + else // Display one of the new cameras + { + OverlayCameraRenderTarget( VarArgs( "debug/debugcamerarendertarget_camera%i", iCameraNum-2 ), 0, 0, w, h ); + } +#else OverlayCameraRenderTarget( "debug/debugcamerarendertarget", 0, 0, w, h ); +#endif + #endif } From da686350139bb11da5477f4cd4f63bed45be6b9c Mon Sep 17 00:00:00 2001 From: Blixibon Date: Tue, 28 Sep 2021 10:59:30 -0500 Subject: [PATCH 158/378] Fixed an issue with IsCombatItem() not being overridden in CItem --- sp/src/game/server/items.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sp/src/game/server/items.h b/sp/src/game/server/items.h index 53f440e8..6209c15e 100644 --- a/sp/src/game/server/items.h +++ b/sp/src/game/server/items.h @@ -89,9 +89,9 @@ public: #endif #ifdef MAPBASE - // This is in CBaseEntity, but I can't find a use for it anywhere. - // It may have been originally intended for TF2 or some other game-specific item class. Please remove this if it turns out to be something important. - virtual bool IsCombatItem() { return true; } + // This appeared to have no prior use in Source SDK 2013. + // It may have been originally intended for TF2 or some other game-specific item class. + virtual bool IsCombatItem() const { return true; } // Used to access item_healthkit values, etc. from outside of the class virtual float GetItemAmount() { return 1.0f; } From 4f140abd19ffe78ac30d170cf5c6edb63881a07e Mon Sep 17 00:00:00 2001 From: Blixibon Date: Tue, 28 Sep 2021 11:02:14 -0500 Subject: [PATCH 159/378] Misc. commentary node stability changes, including the usage of HUD animation commands --- .../game/client/c_point_commentary_node.cpp | 78 +++++++++++++------ 1 file changed, 55 insertions(+), 23 deletions(-) diff --git a/sp/src/game/client/c_point_commentary_node.cpp b/sp/src/game/client/c_point_commentary_node.cpp index 76e753d7..006451e4 100644 --- a/sp/src/game/client/c_point_commentary_node.cpp +++ b/sp/src/game/client/c_point_commentary_node.cpp @@ -21,6 +21,7 @@ #ifdef MAPBASE #include "vgui_controls/Label.h" #include "vgui_controls/ImagePanel.h" +#include "vgui_controls/AnimationController.h" #include "filesystem.h" #include "scenefilecache/ISceneFileCache.h" #include "choreoscene.h" @@ -108,6 +109,9 @@ private: vgui::Label *m_pLabel; vgui::ImagePanel *m_pImage; vgui::HFont m_hFont; + + // HACKHACK: Needed as a failsafe to prevent desync + int m_iCCDefaultY; #endif // Painting @@ -492,12 +496,6 @@ extern CChoreoStringPool g_ChoreoStringPool; //----------------------------------------------------------------------------- void C_PointCommentaryNode::StartSceneCommentary( const char *pszCommentaryFile, C_BasePlayer *pPlayer ) { - EmitSound_t es; - es.m_nChannel = CHAN_STATIC; - es.m_pSoundName = pszCommentaryFile; - es.m_SoundLevel = SNDLVL_GUNFIRE; - es.m_nFlags = SND_SHOULDPAUSE; - char loadfile[MAX_PATH]; Q_strncpy( loadfile, pszCommentaryFile, sizeof( loadfile ) ); Q_SetExtension( loadfile, ".vcd", sizeof( loadfile ) ); @@ -606,6 +604,9 @@ void C_PointCommentaryNode::StartSceneCommentary( const char *pszCommentaryFile, // Get the duration so we know when it finishes float flDuration = m_pScene->GetDuration(); + // Add a tiny amount of time at the end to ensure audio doesn't get cut off + flDuration += 0.5f; + CHudCloseCaption *pHudCloseCaption = (CHudCloseCaption *)GET_HUDELEMENT( CHudCloseCaption ); if ( pHudCloseCaption ) { @@ -750,6 +751,7 @@ void C_PointCommentaryNode::StopLoopingSounds( void ) m_pScene = NULL; // Must do this to terminate audio + // (TODO: This causes problems when players switch from a scene node immediately to a regular audio node) if (m_hSceneOrigin) m_hSceneOrigin->EmitSound( "AI_BaseNPC.SentenceStop" ); } @@ -811,6 +813,8 @@ CHudCommentary::CHudCommentary( const char *name ) : vgui::Panel( NULL, "HudComm m_pLabel = new vgui::Label( this, "HudCommentaryTextLabel", L"Textual commentary" ); m_pImage = new vgui::ImagePanel( this, "HudCommentaryImagePanel" ); m_pImage->SetShouldScaleImage( true ); + + m_iCCDefaultY = 0; #endif } @@ -855,7 +859,10 @@ void CHudCommentary::Paint() { int ccX, ccY; pHudCloseCaption->GetPos( ccX, ccY ); - pHudCloseCaption->SetPos( ccX, ccY + m_iTypeAudioT ); + //pHudCloseCaption->SetPos( ccX, ccY + m_iTypeAudioT ); + + // Run this animation command instead of setting the position directly + g_pClientMode->GetViewportAnimationController()->RunAnimationCommand( pHudCloseCaption, "YPos", ccY + m_iTypeAudioT, 0.0f, 0.4f, vgui::AnimationController::INTERPOLATOR_ACCEL ); pHudCloseCaption->SetUsingCommentaryDimensions( false ); } @@ -879,7 +886,10 @@ void CHudCommentary::Paint() { int ccX, ccY; pHudCloseCaption->GetPos( ccX, ccY ); - pHudCloseCaption->SetPos( ccX, ccY + m_iTypeAudioT ); + //pHudCloseCaption->SetPos( ccX, ccY + m_iTypeAudioT ); + + // Run this animation command instead of setting the position directly + g_pClientMode->GetViewportAnimationController()->RunAnimationCommand( pHudCloseCaption, "YPos", ccY + m_iTypeAudioT, 0.0f, 0.4f, vgui::AnimationController::INTERPOLATOR_ACCEL ); pHudCloseCaption->SetUsingCommentaryDimensions( false ); } @@ -1149,6 +1159,9 @@ void CHudCommentary::VidInit( void ) { SetAlpha(0); StopCommentary(); +#ifdef MAPBASE + m_iCCDefaultY = 0; +#endif } //----------------------------------------------------------------------------- @@ -1200,16 +1213,16 @@ void CHudCommentary::StartCommentary( C_PointCommentaryNode *pNode, char *pszSpe } #ifdef MAPBASE - if (commentary_combine_speaker_and_printname.GetBool() && pNode && pNode->m_iszPrintName[0] != '\0') - { - CombineSpeakerAndPrintName( pNode->m_iszPrintName ); - } - if (!m_bShouldPaint && commentary_audio_element_below_cc.GetBool()) { m_bShouldPaint = true; RepositionCloseCaption(); } + + if (commentary_combine_speaker_and_printname.GetBool() && pNode && pNode->m_iszPrintName[0] != '\0') + { + CombineSpeakerAndPrintName( pNode->m_iszPrintName ); + } #endif SetPaintBackgroundEnabled( m_bShouldPaint ); @@ -1402,17 +1415,17 @@ void CHudCommentary::StartSceneCommentary( C_PointCommentaryNode *pNode, char *p m_bShouldPaint = true; } - if (commentary_combine_speaker_and_printname.GetBool() && pNode && pNode->m_iszPrintName[0] != '\0') - { - CombineSpeakerAndPrintName( pNode->m_iszPrintName ); - } - if (!m_bShouldPaint && commentary_audio_element_below_cc.GetBool()) { m_bShouldPaint = true; RepositionCloseCaption(); } + if (commentary_combine_speaker_and_printname.GetBool() && pNode && pNode->m_iszPrintName[0] != '\0') + { + CombineSpeakerAndPrintName( pNode->m_iszPrintName ); + } + SetPaintBackgroundEnabled( m_bShouldPaint ); char sz[MAX_COUNT_STRING]; @@ -1446,7 +1459,10 @@ void CHudCommentary::StopCommentary( void ) { int ccX, ccY; pHudCloseCaption->GetPos( ccX, ccY ); - pHudCloseCaption->SetPos( ccX, ccY + m_iTypeAudioT ); + //pHudCloseCaption->SetPos( ccX, ccY + m_iTypeAudioT ); + + // Run this animation command instead of setting the position directly + g_pClientMode->GetViewportAnimationController()->RunAnimationCommand( pHudCloseCaption, "YPos", ccY + m_iTypeAudioT, 0.0f, 0.4f, vgui::AnimationController::INTERPOLATOR_ACCEL ); pHudCloseCaption->SetUsingCommentaryDimensions( false ); } @@ -1490,23 +1506,39 @@ void CHudCommentary::RepositionCloseCaption() // Place underneath the close caption element CHudCloseCaption *pHudCloseCaption = (CHudCloseCaption *)GET_HUDELEMENT( CHudCloseCaption ); - if (pHudCloseCaption) + if (pHudCloseCaption /*&& !pHudCloseCaption->IsUsingCommentaryDimensions()*/) { int ccX, ccY; pHudCloseCaption->GetPos( ccX, ccY ); + // Save the default position in case we need to do a hard reset + // (this usually happens when players begin commentary before the CC element's return animation command is finished) + if (m_iCCDefaultY == 0) + { + m_iCCDefaultY = ccY; + } + if (!pHudCloseCaption->IsUsingCommentaryDimensions()) { + if (m_iCCDefaultY != ccY && !pHudCloseCaption->IsUsingCommentaryDimensions()) + { + DevMsg( "CHudCommentary had to reset misaligned CC element Y (%i) to default Y (%i)\n", ccY, m_iCCDefaultY ); + ccY = m_iCCDefaultY; + } + ccY -= m_iTypeAudioT; - pHudCloseCaption->SetPos( ccX, ccY ); + + // Run this animation command instead of setting the position directly + g_pClientMode->GetViewportAnimationController()->RunAnimationCommand( pHudCloseCaption, "YPos", ccY, 0.0f, 0.2f, vgui::AnimationController::INTERPOLATOR_DEACCEL ); + //pHudCloseCaption->SetPos( ccX, ccY ); + + pHudCloseCaption->SetUsingCommentaryDimensions( true ); } SetPos( ccX, ccY + pHudCloseCaption->GetTall() + commentary_audio_element_below_cc_margin.GetInt() ); m_flPanelScale = (float)pHudCloseCaption->GetWide() / (float)GetWide(); SetWide( pHudCloseCaption->GetWide() ); - - pHudCloseCaption->SetUsingCommentaryDimensions( true ); } } #endif From 78f7ae6b8d081591e65386c6e5c3d9e1e168249e Mon Sep 17 00:00:00 2001 From: Blixibon Date: Tue, 28 Sep 2021 11:04:27 -0500 Subject: [PATCH 160/378] Added I/O to allow commentary nodes to change view control parameters mid-commentary --- sp/src/game/server/CommentarySystem.cpp | 168 +++++++++++++++++++++++- 1 file changed, 167 insertions(+), 1 deletion(-) diff --git a/sp/src/game/server/CommentarySystem.cpp b/sp/src/game/server/CommentarySystem.cpp index 378ccc04..8269c612 100644 --- a/sp/src/game/server/CommentarySystem.cpp +++ b/sp/src/game/server/CommentarySystem.cpp @@ -136,6 +136,7 @@ private: float m_flViewPositionSpeedScale; float m_flReturnSpeedScale; CNetworkVar( string_t, m_iszPrintName ); + float m_flViewPositionChangedTime; // View position now blends relative to this value. Mainly needed for when SetViewPosition is used #endif bool m_bPreventMovement; bool m_bUnderCrosshair; @@ -196,6 +197,7 @@ BEGIN_DATADESC( CPointCommentaryNode ) DEFINE_KEYFIELD( m_flViewPositionSpeedScale, FIELD_FLOAT, "viewposition_speed" ), DEFINE_KEYFIELD( m_flReturnSpeedScale, FIELD_FLOAT, "return_speed" ), DEFINE_KEYFIELD( m_iszPrintName, FIELD_STRING, "printname" ), + DEFINE_FIELD( m_flViewPositionChangedTime, FIELD_TIME ), DEFINE_KEYFIELD( m_iCommentaryType, FIELD_INTEGER, "type" ), DEFINE_KEYFIELD( m_flPanelScale, FIELD_FLOAT, "panelscale" ), DEFINE_KEYFIELD( m_flPanelX, FIELD_FLOAT, "x" ), @@ -211,6 +213,13 @@ BEGIN_DATADESC( CPointCommentaryNode ) DEFINE_INPUTFUNC( FIELD_VOID, "StartUnstoppableCommentary", InputStartUnstoppableCommentary ), DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ), DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ), +#ifdef MAPBASE + DEFINE_INPUTFUNC( FIELD_EHANDLE, "SetViewTarget", InputSetViewTarget ), + DEFINE_INPUTFUNC( FIELD_EHANDLE, "SetViewPosition", InputSetViewPosition ), + DEFINE_INPUTFUNC( FIELD_FLOAT, "SetViewTargetSpeed", InputSetViewTargetSpeed ), + DEFINE_INPUTFUNC( FIELD_FLOAT, "SetViewPositionSpeed", InputSetViewPositionSpeed ), + DEFINE_INPUTFUNC( FIELD_FLOAT, "SetReturnSpeed", InputSetReturnSpeed ), +#endif // Functions DEFINE_THINKFUNC( SpinThink ), @@ -1210,6 +1219,21 @@ void CPointCommentaryNode::StartCommentary( void ) // Start the commentary m_flStartTime = gpGlobals->curtime; +#ifdef MAPBASE + if (m_hViewPosition.Get()) + { + m_flViewPositionChangedTime = gpGlobals->curtime; + } + else + { + m_flViewPositionChangedTime = -1.0f; + } + + // This is now used in certain places to denote the "last blend to" origin + m_vecFinishOrigin = pPlayer->EyePosition(); + m_vecFinishAngles = pPlayer->EyeAngles(); +#endif + // If we have a view target, start blending towards it if ( m_hViewTarget || m_hViewPosition.Get() ) { @@ -1328,20 +1352,85 @@ void CPointCommentaryNode::UpdateViewThink( void ) } // Blend to the target position over time. - float flCurTime = (gpGlobals->curtime - m_flStartTime); #ifdef MAPBASE + float flCurTime = (gpGlobals->curtime - m_flViewPositionChangedTime); if (m_flViewPositionSpeedScale != 1.0f) flCurTime *= m_flViewPositionSpeedScale; +#else + float flCurTime = (gpGlobals->curtime - m_flStartTime); #endif float flBlendPerc = clamp( flCurTime * 0.5f, 0.f, 1.f ); // Figure out the current view position Vector vecCurEye; +#ifdef MAPBASE + VectorLerp( m_vecFinishOrigin, m_hViewPosition.Get()->GetAbsOrigin(), flBlendPerc, vecCurEye ); +#else VectorLerp( pPlayer->EyePosition(), m_hViewPosition.Get()->GetAbsOrigin(), flBlendPerc, vecCurEye ); +#endif m_hViewPositionMover->SetAbsOrigin( vecCurEye ); SetNextThink( gpGlobals->curtime, s_pCommentaryUpdateViewThink ); } +#ifdef MAPBASE + else if ( m_flViewPositionChangedTime != -1.0f && m_hViewPositionMover ) + { + // Blend back to the player's position over time. + float flCurTime = (gpGlobals->curtime - m_flViewPositionChangedTime); + if (m_flViewPositionSpeedScale != 1.0f) + flCurTime *= m_flViewPositionSpeedScale; + + //float flTimeToBlend = MIN( 2.0, m_flViewPositionChangedTime - m_flStartTime ); + //float flBlendPerc = 1.0f - clamp( flCurTime / flTimeToBlend, 0.f, 1.f ); + float flBlendPerc = 1.0f - clamp( flCurTime * 0.5f, 0.f, 1.f ); + + //Msg("OUT: CurTime %.2f, BlendTime: %.2f, Blend: %.3f\n", flCurTime, flTimeToBlend, flBlendPerc ); + + // Only do this while we're still moving + if ( flBlendPerc > 0 ) + { + // Figure out the current view position + Vector vecPlayerPos = pPlayer->EyePosition(); + Vector vecToPosition = (m_vecFinishOrigin - vecPlayerPos); + Vector vecCurEye = pPlayer->EyePosition() + (vecToPosition * flBlendPerc); + m_hViewPositionMover->SetAbsOrigin( vecCurEye ); + + if ( m_hViewTarget ) + { + Quaternion quatFinish; + Quaternion quatOriginal; + Quaternion quatCurrent; + AngleQuaternion( m_vecOriginalAngles, quatOriginal ); + AngleQuaternion( m_vecFinishAngles, quatFinish ); + QuaternionSlerp( quatFinish, quatOriginal, 1.0 - flBlendPerc, quatCurrent ); + QAngle angCurrent; + QuaternionAngles( quatCurrent, angCurrent ); + m_hViewPositionMover->SetAbsAngles( angCurrent ); + } + + SetNextThink( gpGlobals->curtime, s_pCommentaryUpdateViewThink ); + return; + } + else + { + pPlayer->SnapEyeAngles( m_hViewPositionMover->GetAbsAngles() ); + + // Try to clean up the view position stuff without ending the commentary + if ( !m_hViewTargetAngles && pPlayer->GetActiveWeapon() ) + { + pPlayer->GetActiveWeapon()->Deploy(); + } + + if (pPlayer->GetViewEntity() == m_hViewPositionMover) + { + pPlayer->SetViewEntity( NULL ); + } + UTIL_Remove( m_hViewPositionMover ); + + m_flViewPositionChangedTime = -1.0f; + } + } +#endif } //----------------------------------------------------------------------------- @@ -1522,6 +1611,79 @@ void CPointCommentaryNode::InputDisable( inputdata_t &inputdata ) SetDisabled( true ); } +#ifdef MAPBASE +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CPointCommentaryNode::InputSetViewTarget( inputdata_t &inputdata ) +{ + m_hViewTarget = inputdata.value.Entity(); + + // Do not let Activate() reassign this + m_iszViewTarget = NULL_STRING; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CPointCommentaryNode::InputSetViewPosition( inputdata_t &inputdata ) +{ + if (m_hViewPosition.Get() && m_hViewPositionMover) + { + // In case the view position is being cleared, assign the "finish" vectors + m_vecFinishOrigin = m_hViewPositionMover->GetAbsOrigin(); + m_vecFinishAngles = m_hViewPositionMover->GetAbsAngles(); + } + else + { + CBasePlayer *pPlayer = GetCommentaryPlayer(); + if (pPlayer) + { + // And in case it's a new view position coming from the player, assign the "finish" vectors to the player + m_vecFinishOrigin = pPlayer->EyePosition(); + m_vecFinishAngles = m_vecOriginalAngles = pPlayer->EyeAngles(); + } + } + + m_hViewPosition = inputdata.value.Entity(); + + // Do not let Activate() reassign this + m_iszViewPosition = NULL_STRING; + + m_flViewPositionChangedTime = gpGlobals->curtime; + + // If we have a view target, start blending towards it + if ( m_hViewPosition.Get() ) + { + SetContextThink( &CPointCommentaryNode::UpdateViewThink, gpGlobals->curtime, s_pCommentaryUpdateViewThink ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CPointCommentaryNode::InputSetViewTargetSpeed( inputdata_t &inputdata ) +{ + m_flViewTargetSpeedScale = inputdata.value.Float(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CPointCommentaryNode::InputSetViewPositionSpeed( inputdata_t &inputdata ) +{ + m_flViewPositionSpeedScale = inputdata.value.Float(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CPointCommentaryNode::InputSetReturnSpeed( inputdata_t &inputdata ) +{ + m_flReturnSpeedScale = inputdata.value.Float(); +} +#endif + //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- @@ -1583,7 +1745,11 @@ void CPointCommentaryNode::SetTransmit( CCheckTransmitInfo *pInfo, bool bAlways bool CPointCommentaryNode::PreventsMovement( void ) { // If we're moving the player's view at all, prevent movement +#ifdef MAPBASE + if ( m_hViewPosition.Get() || m_flViewPositionChangedTime != -1.0f ) +#else if ( m_hViewPosition.Get() ) +#endif return true; return m_bPreventMovement; From f6380097972239e62810005faa90f970407f04f6 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Tue, 28 Sep 2021 11:06:14 -0500 Subject: [PATCH 161/378] Exposed developer commentary nodes to VScript --- .../game/client/c_point_commentary_node.cpp | 57 +++++++++++++++ sp/src/game/server/CommentarySystem.cpp | 71 +++++++++++++++++++ 2 files changed, 128 insertions(+) diff --git a/sp/src/game/client/c_point_commentary_node.cpp b/sp/src/game/client/c_point_commentary_node.cpp index 006451e4..3314330b 100644 --- a/sp/src/game/client/c_point_commentary_node.cpp +++ b/sp/src/game/client/c_point_commentary_node.cpp @@ -164,6 +164,9 @@ class C_PointCommentaryNode : public C_BaseAnimating, public IChoreoEventCallbac public: DECLARE_CLIENTCLASS(); DECLARE_DATADESC(); +#ifdef MAPBASE_VSCRIPT + DECLARE_ENT_SCRIPTDESC(); +#endif virtual void OnPreDataChanged( DataUpdateType_t type ); virtual void OnDataChanged( DataUpdateType_t type ); @@ -256,6 +259,20 @@ public: } } +#ifdef MAPBASE_VSCRIPT // VScript funcs + bool IsActive() { return m_bActive; } + + int GetCommentaryType() { return m_iCommentaryType; } + void SetCommentaryType( int iType ) { m_iCommentaryType = iType; } + + const char *GetCommentaryFile() { return m_iszCommentaryFile; } + void SetCommentaryFile( const char *pszNewFile ) { Q_strncpy( m_iszCommentaryFile, pszNewFile, sizeof( m_iszCommentaryFile ) ); } + const char *GetSpeakers() { return m_iszSpeakers; } + void SetSpeakers( const char *pszSpeakers ) { Q_strncpy( m_iszSpeakers, pszSpeakers, sizeof( m_iszSpeakers ) ); } + const char *GetPrintName() { return m_iszPrintName; } + void SetPrintName( const char *pszPrintName ) { Q_strncpy( m_iszPrintName, pszPrintName, sizeof( m_iszPrintName ) ); } +#endif + public: // Data received from the server bool m_bActive; @@ -280,6 +297,10 @@ public: //CHandle m_hScene; EHANDLE m_hSceneOrigin; #endif + +#ifdef MAPBASE_VSCRIPT + static ScriptHook_t g_Hook_PreStartCommentaryClient; +#endif }; IMPLEMENT_CLIENTCLASS_DT(C_PointCommentaryNode, DT_PointCommentaryNode, CPointCommentaryNode) @@ -306,6 +327,26 @@ BEGIN_DATADESC( C_PointCommentaryNode ) DEFINE_SOUNDPATCH( m_sndCommentary ), END_DATADESC() +#ifdef MAPBASE_VSCRIPT +ScriptHook_t C_PointCommentaryNode::g_Hook_PreStartCommentaryClient; + +BEGIN_ENT_SCRIPTDESC( C_PointCommentaryNode, C_BaseAnimating, "Commentary nodes which play commentary in commentary mode." ) + + DEFINE_SCRIPTFUNC( IsActive, "" ) + DEFINE_SCRIPTFUNC( GetCommentaryFile, "" ) + DEFINE_SCRIPTFUNC( SetCommentaryFile, "" ) + DEFINE_SCRIPTFUNC( GetSpeakers, "" ) + DEFINE_SCRIPTFUNC( SetSpeakers, "" ) + DEFINE_SCRIPTFUNC( GetPrintName, "" ) + DEFINE_SCRIPTFUNC( SetPrintName, "" ) + DEFINE_SCRIPTFUNC( GetCommentaryType, "" ) + DEFINE_SCRIPTFUNC( SetCommentaryType, "" ) + + DEFINE_SIMPLE_SCRIPTHOOK( C_PointCommentaryNode::g_Hook_PreStartCommentaryClient, "PreStartCommentaryClient", FIELD_BOOLEAN, "Called just before commentary begins on the client. Use this to modify variables or commentary behavior before it begins. Returning false will prevent the commentary from starting." ) + +END_SCRIPTDESC(); +#endif + //----------------------------------------------------------------------------- // Purpose: @@ -335,6 +376,22 @@ void C_PointCommentaryNode::OnDataChanged( DataUpdateType_t updateType ) C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); if ( m_bActive && pPlayer ) { +#ifdef MAPBASE_VSCRIPT + if (m_ScriptScope.IsInitialized() && g_Hook_PreStartCommentaryClient.CanRunInScope( m_ScriptScope )) + { + ScriptVariant_t functionReturn; + if (g_Hook_PreStartCommentaryClient.Call( m_ScriptScope, &functionReturn, NULL ) && functionReturn.m_type == FIELD_BOOLEAN) + { + // Don't play the commentary if it returned false + if (functionReturn.m_bool == false) + { + engine->ServerCmd( "commentary_finishnode\n" ); + return; + } + } + } +#endif + // Use the HDR / Non-HDR version based on whether we're running HDR or not char *pszCommentaryFile; if ( g_pMaterialSystemHardwareConfig->GetHDRType() == HDR_TYPE_NONE && m_iszCommentaryFileNoHDR && m_iszCommentaryFileNoHDR[0] ) diff --git a/sp/src/game/server/CommentarySystem.cpp b/sp/src/game/server/CommentarySystem.cpp index 8269c612..437ed086 100644 --- a/sp/src/game/server/CommentarySystem.cpp +++ b/sp/src/game/server/CommentarySystem.cpp @@ -72,6 +72,9 @@ class CPointCommentaryNode : public CBaseAnimating DECLARE_CLASS( CPointCommentaryNode, CBaseAnimating ); public: DECLARE_DATADESC(); +#ifdef MAPBASE_VSCRIPT + DECLARE_ENT_SCRIPTDESC(); +#endif DECLARE_SERVERCLASS(); CPointCommentaryNode() @@ -114,11 +117,37 @@ public: void TeleportTo( CBasePlayer *pPlayer ); bool CanTeleportTo( void ); +#ifdef MAPBASE + bool IsActive() { return m_bActive; } + bool IsDisabled() { return m_bDisabled; } + + int GetCommentaryType() { return m_iCommentaryType; } + void SetCommentaryType( int iType ) { m_iCommentaryType = iType; } + + const char *GetCommentaryFile() { return STRING( m_iszCommentaryFile.Get() ); } + void SetCommentaryFile( const char *pszNewFile ) { m_iszCommentaryFile.Set( AllocPooledString( pszNewFile ) ); } + const char *GetSpeakers() { return STRING( m_iszSpeakers.Get() ); } + void SetSpeakers( const char *pszSpeakers ) { m_iszSpeakers.Set( AllocPooledString( pszSpeakers ) ); } + const char *GetPrintName() { return STRING( m_iszPrintName.Get() ); } + void SetPrintName( const char *pszPrintName ) { m_iszPrintName.Set( AllocPooledString( pszPrintName ) ); } +#endif + // Inputs void InputStartCommentary( inputdata_t &inputdata ); void InputStartUnstoppableCommentary( inputdata_t &inputdata ); void InputEnable( inputdata_t &inputdata ); void InputDisable( inputdata_t &inputdata ); +#ifdef MAPBASE + void InputSetViewTarget( inputdata_t &inputdata ); + void InputSetViewPosition( inputdata_t &inputdata ); + void InputSetViewTargetSpeed( inputdata_t &inputdata ); + void InputSetViewPositionSpeed( inputdata_t &inputdata ); + void InputSetReturnSpeed( inputdata_t &inputdata ); +#endif + +#ifdef MAPBASE_VSCRIPT + static ScriptHook_t g_Hook_PreStartCommentary; +#endif private: string_t m_iszPreCommands; @@ -227,6 +256,35 @@ BEGIN_DATADESC( CPointCommentaryNode ) DEFINE_THINKFUNC( UpdateViewPostThink ), END_DATADESC() +#ifdef MAPBASE_VSCRIPT + +ScriptHook_t CPointCommentaryNode::g_Hook_PreStartCommentary; + +BEGIN_ENT_SCRIPTDESC( CPointCommentaryNode, CBaseAnimating, "Commentary nodes which play commentary in commentary mode." ) + DEFINE_SCRIPTFUNC( IsDisabled, "" ) + DEFINE_SCRIPTFUNC( SetDisabled, "" ) + + DEFINE_SCRIPTFUNC( IsActive, "" ) + DEFINE_SCRIPTFUNC( GetCommentaryFile, "" ) + DEFINE_SCRIPTFUNC( SetCommentaryFile, "" ) + DEFINE_SCRIPTFUNC( GetSpeakers, "" ) + DEFINE_SCRIPTFUNC( SetSpeakers, "" ) + DEFINE_SCRIPTFUNC( GetPrintName, "" ) + DEFINE_SCRIPTFUNC( SetPrintName, "" ) + DEFINE_SCRIPTFUNC( GetCommentaryType, "" ) + DEFINE_SCRIPTFUNC( SetCommentaryType, "" ) + + DEFINE_SCRIPTFUNC( HasViewTarget, "" ) + DEFINE_SCRIPTFUNC( PreventsMovement, "" ) + DEFINE_SCRIPTFUNC( CannotBeStopped, "" ) + + DEFINE_SCRIPTFUNC( AbortPlaying, "Stops playing the node and snaps out of its camera control immediately. The game uses this function to shut down commentary while in the middle of playing a node, as it can't smoothly blend out (since the commentary entities need to be removed)." ) + + DEFINE_SIMPLE_SCRIPTHOOK( CPointCommentaryNode::g_Hook_PreStartCommentary, "PreStartCommentary", FIELD_BOOLEAN, "Called just before commentary begins. Use this to modify variables or commentary behavior before it begins. Returning false will prevent the commentary from starting." ) +END_SCRIPTDESC(); + +#endif // MAPBASE_VSCRIPT + IMPLEMENT_SERVERCLASS_ST( CPointCommentaryNode, DT_PointCommentaryNode ) SendPropBool( SENDINFO(m_bActive) ), SendPropStringT( SENDINFO(m_iszCommentaryFile) ), @@ -1198,6 +1256,19 @@ void CPointCommentaryNode::StartCommentary( void ) if ( !pPlayer ) return; +#ifdef MAPBASE_VSCRIPT + if (m_ScriptScope.IsInitialized() && g_Hook_PreStartCommentary.CanRunInScope( m_ScriptScope )) + { + ScriptVariant_t functionReturn; + if ( g_Hook_PreStartCommentary.Call( m_ScriptScope, &functionReturn, NULL ) && functionReturn.m_type == FIELD_BOOLEAN ) + { + // Don't play the commentary if it returned false + if (functionReturn.m_bool == false) + return; + } + } +#endif + m_bActive = true; m_flAnimTime = gpGlobals->curtime; From 15f4d582f26ece5f2447e9167763b46d1b7a41e6 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Tue, 28 Sep 2021 11:06:34 -0500 Subject: [PATCH 162/378] Added SetScale input to func_fake_worldportal --- sp/src/game/server/mapbase/func_fake_worldportal.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sp/src/game/server/mapbase/func_fake_worldportal.cpp b/sp/src/game/server/mapbase/func_fake_worldportal.cpp index de951b6a..6430d5df 100644 --- a/sp/src/game/server/mapbase/func_fake_worldportal.cpp +++ b/sp/src/game/server/mapbase/func_fake_worldportal.cpp @@ -54,6 +54,7 @@ public: void InputSetSkyMode( inputdata_t &inputdata ) { m_iSkyMode = inputdata.value.Int(); } void InputSetRenderTarget( inputdata_t &inputdata ) { m_iszRenderTarget = inputdata.value.StringID(); } void InputSetFogController( inputdata_t &inputdata ) { m_hFogController = inputdata.value.Entity(); if (m_hFogController) { m_iszFogController = m_hFogController->GetEntityName(); } } + void InputSetScale( inputdata_t &inputdata ) { m_flScale = inputdata.value.Float(); } private: @@ -83,6 +84,7 @@ BEGIN_DATADESC( CFuncFakeWorldPortal ) DEFINE_INPUTFUNC( FIELD_INTEGER, "SetSkyMode", InputSetSkyMode ), DEFINE_INPUTFUNC( FIELD_STRING, "SetRenderTarget", InputSetRenderTarget ), DEFINE_INPUTFUNC( FIELD_EHANDLE, "SetFogController", InputSetFogController ), + DEFINE_INPUTFUNC( FIELD_FLOAT, "SetScale", InputSetScale ), END_DATADESC() From 5fa76486935c3c940ac2bf781ef2d4dbbe8a9ce2 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Tue, 28 Sep 2021 11:12:07 -0500 Subject: [PATCH 163/378] Added more VScript functions for CMapbaseSystem --- sp/src/game/shared/mapbase/mapbase_shared.cpp | 169 +++++++++++------- 1 file changed, 102 insertions(+), 67 deletions(-) diff --git a/sp/src/game/shared/mapbase/mapbase_shared.cpp b/sp/src/game/shared/mapbase/mapbase_shared.cpp index 6701e0be..877cf9ff 100644 --- a/sp/src/game/shared/mapbase/mapbase_shared.cpp +++ b/sp/src/game/shared/mapbase/mapbase_shared.cpp @@ -375,55 +375,6 @@ public: m_bInitializedRTs = false; } } - - // Custom scheme loading - void LoadCustomScheme( const char *pszFile ) - { - g_iCustomClientSchemeOverride = vgui::scheme()->LoadSchemeFromFile( pszFile, "CustomClientScheme" ); - - // Reload scheme - ClientModeShared *mode = ( ClientModeShared * )GetClientModeNormal(); - if ( mode ) - { - mode->ReloadScheme(); - } - } - - void LoadCustomHudAnimations( const char *pszFile ) - { - CBaseViewport *pViewport = dynamic_cast(g_pClientMode->GetViewport()); - if (pViewport) - { - g_bUsingCustomHudAnimations = true; - if (!pViewport->LoadCustomHudAnimations( pszFile )) - { - g_bUsingCustomHudAnimations = false; - CGWarning( 0, CON_GROUP_MAPBASE_MISC, "Custom HUD animations file \"%s\" failed to load\n", pszFile ); - pViewport->ReloadHudAnimations(); - } - else - { - CGMsg( 1, CON_GROUP_MAPBASE_MISC, "Loaded custom HUD animations file \"%s\"\n", pszFile );; - } - } - } - - void LoadCustomHudLayout( const char *pszFile ) - { - CBaseViewport *pViewport = dynamic_cast(g_pClientMode->GetViewport()); - if (pViewport) - { - g_bUsingCustomHudLayout = true; - - KeyValuesAD pConditions( "conditions" ); - g_pClientMode->ComputeVguiResConditions( pConditions ); - - // reload the .res file from disk - pViewport->LoadControlSettings( pszFile, NULL, NULL, pConditions ); - - CGMsg( 1, CON_GROUP_MAPBASE_MISC, "Loaded custom HUD layout file \"%s\"\n", pszFile );; - } - } #endif // Get a generic, hardcoded manifest with hardcoded names. @@ -477,14 +428,11 @@ public: case MANIFEST_LOCALIZATION: { g_pVGuiLocalize->AddFile( value, "MOD", true ); } break; case MANIFEST_SURFACEPROPS: { AddSurfacepropFile( value, physprops, filesystem ); } break; #ifdef CLIENT_DLL - case MANIFEST_CLOSECAPTION: { - if ( GET_HUDELEMENT( CHudCloseCaption ) ) - (GET_HUDELEMENT( CHudCloseCaption ))->AddCustomCaptionFile( value, m_CloseCaptionFileNames ); - } break; - case MANIFEST_VGUI: { PanelMetaClassMgr()->LoadMetaClassDefinitionFile( value ); } break; - case MANIFEST_CLIENTSCHEME: { LoadCustomScheme( value ); } break; - case MANIFEST_HUDANIMATIONS: { LoadCustomHudAnimations( value ); } break; - case MANIFEST_HUDLAYOUT: { LoadCustomHudLayout( value ); } break; + case MANIFEST_CLOSECAPTION: { ManifestLoadCustomCloseCaption( value ); } break; + case MANIFEST_VGUI: { PanelMetaClassMgr()->LoadMetaClassDefinitionFile( value ); } break; + case MANIFEST_CLIENTSCHEME: { ManifestLoadCustomScheme( value ); } break; + case MANIFEST_HUDANIMATIONS: { ManifestLoadCustomHudAnimations( value ); } break; + case MANIFEST_HUDLAYOUT: { ManifestLoadCustomHudLayout( value ); } break; //case MANIFEST_SOUNDSCAPES: { Soundscape_AddFile(value); } break; #else case MANIFEST_TALKER: { @@ -561,18 +509,87 @@ public: } } -#ifdef MAPBASE_VSCRIPT - void ScriptAddManifestFile( const char *szScript ) { AddManifestFile( szScript ); } +private: - void LoadSoundscriptFile( const char *szScript ) { LoadFromValue(szScript, MANIFEST_SOUNDSCRIPTS, false); } -#ifndef CLIENT_DLL - void LoadTalkerFile( const char *szScript ) { LoadFromValue( szScript, MANIFEST_TALKER, false ); } - void LoadActbusyFile( const char *szScript ) { LoadFromValue( szScript, MANIFEST_ACTBUSY, false ); } +#ifdef CLIENT_DLL + void ManifestLoadCustomCloseCaption( const char *pszFile ) + { + if (GET_HUDELEMENT( CHudCloseCaption )) + (GET_HUDELEMENT( CHudCloseCaption ))->AddCustomCaptionFile( pszFile, m_CloseCaptionFileNames ); + } + + // Custom scheme loading + void ManifestLoadCustomScheme( const char *pszFile ) + { + g_iCustomClientSchemeOverride = vgui::scheme()->LoadSchemeFromFile( pszFile, "CustomClientScheme" ); + + // Reload scheme + ClientModeShared *mode = ( ClientModeShared * )GetClientModeNormal(); + if ( mode ) + { + mode->ReloadScheme(); + } + } + + void ManifestLoadCustomHudAnimations( const char *pszFile ) + { + CBaseViewport *pViewport = dynamic_cast(g_pClientMode->GetViewport()); + if (pViewport) + { + g_bUsingCustomHudAnimations = true; + if (!pViewport->LoadCustomHudAnimations( pszFile )) + { + g_bUsingCustomHudAnimations = false; + CGWarning( 0, CON_GROUP_MAPBASE_MISC, "Custom HUD animations file \"%s\" failed to load\n", pszFile ); + pViewport->ReloadHudAnimations(); + } + else + { + CGMsg( 1, CON_GROUP_MAPBASE_MISC, "Loaded custom HUD animations file \"%s\"\n", pszFile );; + } + } + } + + void ManifestLoadCustomHudLayout( const char *pszFile ) + { + CBaseViewport *pViewport = dynamic_cast(g_pClientMode->GetViewport()); + if (pViewport) + { + g_bUsingCustomHudLayout = true; + + KeyValuesAD pConditions( "conditions" ); + g_pClientMode->ComputeVguiResConditions( pConditions ); + + // reload the .res file from disk + pViewport->LoadControlSettings( pszFile, NULL, NULL, pConditions ); + + CGMsg( 1, CON_GROUP_MAPBASE_MISC, "Loaded custom HUD layout file \"%s\"\n", pszFile );; + } + } +#endif + +public: + + void LoadCustomSoundscriptFile( const char *szScript ) { LoadFromValue( szScript, MANIFEST_SOUNDSCRIPTS, false ); } + void LoadCustomLocalizationFile( const char *szScript ) { LoadFromValue( szScript, MANIFEST_LOCALIZATION, false ); } + void LoadCustomSurfacePropsFile( const char *szScript ) { LoadFromValue( szScript, MANIFEST_SURFACEPROPS, false ); } +#ifdef CLIENT_DLL + void LoadCustomCloseCaptionFile( const char *szScript ) { LoadFromValue( szScript, MANIFEST_CLOSECAPTION, false ); } + void LoadCustomVGUIFile( const char *szScript ) { LoadFromValue( szScript, MANIFEST_VGUI, false ); } + void LoadCustomClientSchemeFile( const char *szScript ) { LoadFromValue( szScript, MANIFEST_CLIENTSCHEME, false ); } + void LoadCustomHUDAnimationsFile( const char *szScript ) { LoadFromValue( szScript, MANIFEST_HUDANIMATIONS, false ); } + void LoadCustomHUDLayoutFile( const char *szScript ) { LoadFromValue( szScript, MANIFEST_HUDLAYOUT, false ); } +#else + void LoadCustomTalkerFile( const char *szScript ) { LoadFromValue( szScript, MANIFEST_TALKER, false ); } + void LoadCustomActbusyFile( const char *szScript ) { LoadFromValue( szScript, MANIFEST_ACTBUSY, false ); } #endif const char *GetModName() { return g_iszGameName; } bool IsCoreMapbase() { return g_bMapbaseCore; } +#ifdef MAPBASE_VSCRIPT + void ScriptAddManifestFile( const char *szScript ) { AddManifestFile( szScript ); } + virtual void RegisterVScript() { g_pScriptVM->RegisterInstance( this, "Mapbase" ); @@ -599,14 +616,32 @@ END_DATADESC() #ifdef MAPBASE_VSCRIPT BEGIN_SCRIPTDESC_ROOT( CMapbaseSystem, SCRIPT_SINGLETON "All-purpose Mapbase system primarily used for map-specific files." ) + DEFINE_SCRIPTFUNC_NAMED( ScriptAddManifestFile, "AddManifestFile", "Loads a manifest file." ) - DEFINE_SCRIPTFUNC( LoadSoundscriptFile, "Loads a custom soundscript file." ) -#ifndef CLIENT_DLL - DEFINE_SCRIPTFUNC( LoadTalkerFile, "Loads a custom talker file." ) - DEFINE_SCRIPTFUNC( LoadActbusyFile, "Loads a custom actbusy file." ) + DEFINE_SCRIPTFUNC( LoadCustomSoundscriptFile, "Loads a custom soundscript file." ) + DEFINE_SCRIPTFUNC( LoadCustomLocalizationFile, "Loads a custom localization file." ) + DEFINE_SCRIPTFUNC( LoadCustomSurfacePropsFile, "Loads a custom surface properties file." ) +#ifdef CLIENT_DLL + DEFINE_SCRIPTFUNC( LoadCustomCloseCaptionFile, "Loads a custom closed captions file." ) + DEFINE_SCRIPTFUNC( LoadCustomVGUIFile, "Loads a custom VGUI definitions file." ) + DEFINE_SCRIPTFUNC( LoadCustomClientSchemeFile, "Loads a custom ClientScheme.res override file." ) + DEFINE_SCRIPTFUNC( LoadCustomHUDAnimationsFile, "Loads a custom HUD animations override file." ) + DEFINE_SCRIPTFUNC( LoadCustomHUDLayoutFile, "Loads a custom HUD layout override file." ) +#else + DEFINE_SCRIPTFUNC( LoadCustomTalkerFile, "Loads a custom talker file." ) + DEFINE_SCRIPTFUNC( LoadCustomActbusyFile, "Loads a custom actbusy file." ) #endif + DEFINE_SCRIPTFUNC( GetModName, "Gets the name of the mod. This is the name which shows up on Steam, RPC, etc." ) DEFINE_SCRIPTFUNC( IsCoreMapbase, "Indicates whether this is one of the original Mapbase mods or just a separate mod using its code." ) + + // Legacy + DEFINE_SCRIPTFUNC_NAMED( LoadCustomSoundscriptFile, "LoadSoundscriptFile", SCRIPT_HIDE ) +#ifndef CLIENT_DLL + DEFINE_SCRIPTFUNC_NAMED( LoadCustomTalkerFile, "LoadTalkerFile", SCRIPT_HIDE ) + DEFINE_SCRIPTFUNC_NAMED( LoadCustomActbusyFile, "LoadActbusyFile", SCRIPT_HIDE ) +#endif + END_SCRIPTDESC(); #endif From a1bc5196f24eba120ae90845e4294d6e4fdc790d Mon Sep 17 00:00:00 2001 From: Blixibon Date: Tue, 28 Sep 2021 11:16:14 -0500 Subject: [PATCH 164/378] Standalone FileExists() function for VScript --- .../shared/mapbase/vscript_singletons.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/sp/src/game/shared/mapbase/vscript_singletons.cpp b/sp/src/game/shared/mapbase/vscript_singletons.cpp index b2f829a5..009aa48c 100644 --- a/sp/src/game/shared/mapbase/vscript_singletons.cpp +++ b/sp/src/game/shared/mapbase/vscript_singletons.cpp @@ -1006,6 +1006,7 @@ class CScriptReadWriteFile : public CAutoGameSystem public: static bool FileWrite( const char *szFile, const char *szInput ); static const char *FileRead( const char *szFile ); + static bool FileExists( const char *szFile ); // NOTE: These two functions are new with Mapbase and have no Valve equivalent static bool KeyValuesWrite( const char *szFile, HSCRIPT hInput ); @@ -1111,6 +1112,23 @@ const char *CScriptReadWriteFile::FileRead( const char *szFile ) } } +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +bool CScriptReadWriteFile::FileExists( const char *szFile ) +{ + char pszFullName[MAX_PATH]; + V_snprintf( pszFullName, sizeof(pszFullName), SCRIPT_RW_FULL_PATH_FMT, szFile ); + + if ( !V_RemoveDotSlashes( pszFullName, CORRECT_PATH_SEPARATOR, true ) ) + { + DevWarning( 2, "Invalid file location : %s\n", szFile ); + return NULL; + } + + return g_pFullFileSystem->FileExists( pszFullName, SCRIPT_RW_PATH_ID ); +} + //----------------------------------------------------------------------------- // Get the checksum of any file. Can be used to check the existence or validity of a file. // Returns unsigned int as hex string. @@ -3046,6 +3064,7 @@ void RegisterScriptSingletons() ScriptRegisterSimpleHook( g_pScriptVM, g_Hook_OnRestore, "OnRestore", FIELD_VOID, "Called when the game is restored." ); ScriptRegisterFunctionNamed( g_pScriptVM, CScriptReadWriteFile::FileWrite, "StringToFile", "Stores the string into the file" ); ScriptRegisterFunctionNamed( g_pScriptVM, CScriptReadWriteFile::FileRead, "FileToString", "Returns the string from the file, null if no file or file is too big." ); + ScriptRegisterFunctionNamed( g_pScriptVM, CScriptReadWriteFile::FileExists, "FileExists", "Returns true if the file exists." ); ScriptRegisterFunctionNamed( g_pScriptVM, CScriptReadWriteFile::KeyValuesWrite, "KeyValuesToFile", "Stores the CScriptKeyValues into the file" ); ScriptRegisterFunctionNamed( g_pScriptVM, CScriptReadWriteFile::KeyValuesRead, "FileToKeyValues", "Returns the CScriptKeyValues from the file, null if no file or file is too big." ); From 6d04c46dc0b8079e94dbc1977b0834732ecad39e Mon Sep 17 00:00:00 2001 From: Blixibon Date: Tue, 28 Sep 2021 12:09:29 -0500 Subject: [PATCH 165/378] Added speed modifier to scanners and rollermines --- sp/src/game/server/hl2/npc_basescanner.cpp | 8 +++++ sp/src/game/server/hl2/npc_rollermine.cpp | 38 +++++++++++++++++----- sp/src/game/server/hl2/npc_scanner.cpp | 8 +++++ 3 files changed, 46 insertions(+), 8 deletions(-) diff --git a/sp/src/game/server/hl2/npc_basescanner.cpp b/sp/src/game/server/hl2/npc_basescanner.cpp index a94c77b6..fdae50da 100644 --- a/sp/src/game/server/hl2/npc_basescanner.cpp +++ b/sp/src/game/server/hl2/npc_basescanner.cpp @@ -1278,6 +1278,14 @@ void CNPC_BaseScanner::MoveToTarget( float flInterval, const Vector &vecMoveTarg myZAccel = flDist / flInterval; } +#ifdef MAPBASE + if (m_flSpeedModifier != 1.0f) + { + myAccel *= m_flSpeedModifier; + //myZAccel *= m_flSpeedModifier; + } +#endif + MoveInDirection( flInterval, targetDir, myAccel, myZAccel, myDecay ); // calc relative banking targets diff --git a/sp/src/game/server/hl2/npc_rollermine.cpp b/sp/src/game/server/hl2/npc_rollermine.cpp index ec9be919..fc803f1f 100644 --- a/sp/src/game/server/hl2/npc_rollermine.cpp +++ b/sp/src/game/server/hl2/npc_rollermine.cpp @@ -310,6 +310,16 @@ protected: bool IsActive() { return m_flActiveTime > gpGlobals->curtime ? false : true; } + inline float GetForwardSpeed() const + { +#ifdef MAPBASE + if (m_flSpeedModifier != 1.0f) + return m_flForwardSpeed * m_flSpeedModifier; + else +#endif + return m_flForwardSpeed; + } + // INPCInteractive Functions virtual bool CanInteractWith( CAI_BaseNPC *pUser ) { return true; } virtual bool HasBeenInteractedWith() { return m_bHackedByAlyx; } @@ -1313,7 +1323,7 @@ void CNPC_RollerMine::RunTask( const Task_t *pTask ) Vector vecRight; AngleVectors( QAngle( 0, yaw, 0 ), NULL, &vecRight, NULL ); - m_RollerController.m_vecAngular += WorldToLocalRotation( SetupMatrixAngles(GetLocalAngles()), vecRight, -m_flForwardSpeed * 5 ); + m_RollerController.m_vecAngular += WorldToLocalRotation( SetupMatrixAngles(GetLocalAngles()), vecRight, -GetForwardSpeed() * 5 ); TaskComplete(); return; @@ -1323,6 +1333,8 @@ void CNPC_RollerMine::RunTask( const Task_t *pTask ) } { + float flForwardSpeed = GetForwardSpeed(); + float yaw = UTIL_VecToYaw( GetNavigator()->GetCurWaypointPos() - GetLocalOrigin() ); Vector vecRight; @@ -1362,17 +1374,17 @@ void CNPC_RollerMine::RunTask( const Task_t *pTask ) vecCompensate.y = -vecVelocity.x; vecCompensate.z = 0; - m_RollerController.m_vecAngular = WorldToLocalRotation( SetupMatrixAngles(GetLocalAngles()), vecCompensate, m_flForwardSpeed * -0.75 ); + m_RollerController.m_vecAngular = WorldToLocalRotation( SetupMatrixAngles(GetLocalAngles()), vecCompensate, flForwardSpeed * -0.75 ); } if( m_bHackedByAlyx ) { // Move faster. - m_RollerController.m_vecAngular += WorldToLocalRotation( SetupMatrixAngles(GetLocalAngles()), vecRight, m_flForwardSpeed * 2.0f ); + m_RollerController.m_vecAngular += WorldToLocalRotation( SetupMatrixAngles(GetLocalAngles()), vecRight, flForwardSpeed * 2.0f ); } else { - m_RollerController.m_vecAngular += WorldToLocalRotation( SetupMatrixAngles(GetLocalAngles()), vecRight, m_flForwardSpeed ); + m_RollerController.m_vecAngular += WorldToLocalRotation( SetupMatrixAngles(GetLocalAngles()), vecRight, flForwardSpeed ); } } break; @@ -1496,8 +1508,10 @@ void CNPC_RollerMine::RunTask( const Task_t *pTask ) vecCompensate.z = 0; VectorNormalize( vecCompensate ); - m_RollerController.m_vecAngular = WorldToLocalRotation( SetupMatrixAngles(GetLocalAngles()), vecCompensate, m_flForwardSpeed * -0.75 ); - m_RollerController.m_vecAngular += WorldToLocalRotation( SetupMatrixAngles(GetLocalAngles()), vecRight, m_flForwardSpeed * flTorqueFactor ); + float flForwardSpeed = GetForwardSpeed(); + + m_RollerController.m_vecAngular = WorldToLocalRotation( SetupMatrixAngles(GetLocalAngles()), vecCompensate, flForwardSpeed * -0.75 ); + m_RollerController.m_vecAngular += WorldToLocalRotation( SetupMatrixAngles(GetLocalAngles()), vecRight, flForwardSpeed * flTorqueFactor ); // Taunt when I get closer if( !(m_iSoundEventFlags & ROLLERMINE_SE_TAUNT) && UTIL_DistApprox( GetLocalOrigin(), vecTargetPosition ) <= 400 ) @@ -1615,8 +1629,10 @@ void CNPC_RollerMine::RunTask( const Task_t *pTask ) vecCompensate.z = 0; VectorNormalize( vecCompensate ); - m_RollerController.m_vecAngular = WorldToLocalRotation( SetupMatrixAngles(GetLocalAngles()), vecCompensate, m_flForwardSpeed * -0.75 ); - m_RollerController.m_vecAngular += WorldToLocalRotation( SetupMatrixAngles(GetLocalAngles()), vecRight, m_flForwardSpeed * flTorqueFactor ); + float flForwardSpeed = GetForwardSpeed(); + + m_RollerController.m_vecAngular = WorldToLocalRotation( SetupMatrixAngles(GetLocalAngles()), vecCompensate, flForwardSpeed * -0.75 ); + m_RollerController.m_vecAngular += WorldToLocalRotation( SetupMatrixAngles(GetLocalAngles()), vecRight, flForwardSpeed * flTorqueFactor ); // Once we're near the player, slow & stop if ( GetAbsOrigin().DistToSqr( vecTargetPosition ) < (ROLLERMINE_RETURN_TO_PLAYER_DIST*2.0) ) @@ -2572,6 +2588,12 @@ float CNPC_RollerMine::RollingSpeed() float rollingSpeed = angVel.Length() - 90; rollingSpeed = clamp( rollingSpeed, 1, MAX_ROLLING_SPEED ); rollingSpeed *= (1/MAX_ROLLING_SPEED); +#ifdef MAPBASE + if (m_flSpeedModifier != 1.0f) + { + rollingSpeed *= m_flSpeedModifier; + } +#endif return rollingSpeed; } return 0; diff --git a/sp/src/game/server/hl2/npc_scanner.cpp b/sp/src/game/server/hl2/npc_scanner.cpp index aac717c5..0323afcc 100644 --- a/sp/src/game/server/hl2/npc_scanner.cpp +++ b/sp/src/game/server/hl2/npc_scanner.cpp @@ -2567,6 +2567,14 @@ void CNPC_CScanner::MoveToTarget( float flInterval, const Vector &vecMoveTarget myZAccel = flDist / flInterval; } +#ifdef MAPBASE + if (m_flSpeedModifier != 1.0f) + { + myAccel *= m_flSpeedModifier; + //myZAccel *= m_flSpeedModifier; + } +#endif + MoveInDirection( flInterval, targetDir, myAccel, myZAccel, myDecay ); // calc relative banking targets From 7702ce96d40b195e8a6e57bd916cbb632f423c9b Mon Sep 17 00:00:00 2001 From: Blixibon Date: Tue, 28 Sep 2021 12:10:25 -0500 Subject: [PATCH 166/378] Fixed reloading for certain weapons on certain NPCs --- .../game/shared/basecombatweapon_shared.cpp | 21 +++++++++++++++++++ sp/src/game/shared/basecombatweapon_shared.h | 2 +- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/sp/src/game/shared/basecombatweapon_shared.cpp b/sp/src/game/shared/basecombatweapon_shared.cpp index 9f3b9be4..a48aa413 100644 --- a/sp/src/game/shared/basecombatweapon_shared.cpp +++ b/sp/src/game/shared/basecombatweapon_shared.cpp @@ -2339,6 +2339,27 @@ bool CBaseCombatWeapon::Reload( void ) return DefaultReload( GetMaxClip1(), GetMaxClip2(), ACT_VM_RELOAD ); } +#ifdef MAPBASE +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CBaseCombatWeapon::Reload_NPC( void ) +{ + WeaponSound( RELOAD_NPC ); + + if (UsesClipsForAmmo1()) + { + m_iClip1 = GetMaxClip1(); + } + else + { + // For weapons which don't use clips, give the owner ammo. + if (GetOwner()) + GetOwner()->SetAmmoCount( GetDefaultClip1(), m_iPrimaryAmmoType ); + } +} +#endif + //========================================================= void CBaseCombatWeapon::WeaponIdle( void ) { diff --git a/sp/src/game/shared/basecombatweapon_shared.h b/sp/src/game/shared/basecombatweapon_shared.h index 2d19727d..b0a3e330 100644 --- a/sp/src/game/shared/basecombatweapon_shared.h +++ b/sp/src/game/shared/basecombatweapon_shared.h @@ -319,7 +319,7 @@ public: bool ReloadsSingly( void ) const; #ifdef MAPBASE // Originally created for the crossbow, can be used to add special NPC reloading behavior - virtual void Reload_NPC( void ) { WeaponSound(RELOAD_NPC); m_iClip1 = GetMaxClip1(); } + virtual void Reload_NPC( void ); #endif virtual bool AutoFiresFullClip( void ) { return false; } From 2fa658cd5769ab0f5d62342e03acf37d1b7f4eab Mon Sep 17 00:00:00 2001 From: samisalreadytaken <46823719+samisalreadytaken@users.noreply.github.com> Date: Fri, 1 Oct 2021 16:20:04 +0300 Subject: [PATCH 167/378] Re-add mistakenly removed wrappers --- .../game/shared/mapbase/vscript_funcs_shared.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp b/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp index aab303d8..e57a714d 100644 --- a/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp +++ b/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp @@ -775,6 +775,16 @@ static void AddPhysVelocity( HSCRIPT hPhys, const Vector& vecVelocity, const Vec //============================================================================= //============================================================================= +static int ScriptPrecacheModel( const char *modelname ) +{ + return CBaseEntity::PrecacheModel( modelname ); +} + +static void ScriptPrecacheOther( const char *classname ) +{ + UTIL_PrecacheOther( classname ); +} + #ifndef CLIENT_DLL // TODO: Move this? static void ScriptInsertSound( int iType, const Vector &vecOrigin, int iVolume, float flDuration, HSCRIPT hOwner, int soundChannelIndex, HSCRIPT hSoundTarget ) @@ -996,10 +1006,10 @@ void RegisterSharedScriptFunctions() // // Precaching // - ScriptRegisterFunctionNamed( g_pScriptVM, CBaseEntity::PrecacheModel, "PrecacheModel", "Precaches a model for later usage." ); + ScriptRegisterFunctionNamed( g_pScriptVM, ScriptPrecacheModel, "PrecacheModel", "Precaches a model for later usage." ); ScriptRegisterFunction( g_pScriptVM, PrecacheMaterial, "Precaches a material for later usage." ); ScriptRegisterFunction( g_pScriptVM, PrecacheParticleSystem, "Precaches a particle system for later usage." ); - ScriptRegisterFunctionNamed( g_pScriptVM, UTIL_PrecacheOther, "PrecacheOther", "Precaches an entity class for later usage." ); + ScriptRegisterFunctionNamed( g_pScriptVM, ScriptPrecacheOther, "PrecacheOther", "Precaches an entity class for later usage." ); // // NPCs From bf24798ee86d90029f323eb88d49499688ddfec1 Mon Sep 17 00:00:00 2001 From: samisalreadytaken <46823719+samisalreadytaken@users.noreply.github.com> Date: Fri, 1 Oct 2021 16:20:14 +0300 Subject: [PATCH 168/378] Uncomment debug code --- .../shared/mapbase/vscript_singletons.cpp | 39 ++++++++++++------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/sp/src/game/shared/mapbase/vscript_singletons.cpp b/sp/src/game/shared/mapbase/vscript_singletons.cpp index b2f829a5..2f492f88 100644 --- a/sp/src/game/shared/mapbase/vscript_singletons.cpp +++ b/sp/src/game/shared/mapbase/vscript_singletons.cpp @@ -366,6 +366,11 @@ END_SCRIPTDESC(); //============================================================================= // Game Event Listener // Based on Source 2 API +// +// NOTE: In Source 2 vscript (Lua) event listener contexts are tables that are +// passed to the callback function as the call environment. +// In mapbase implementation these are string identifiers because unlike Lua, +// Squirrel has closure methods such as 'bindenv' which can bind functions to specified environments. //============================================================================= // Define to use the older code that loads all events manually independent from the game event manager. @@ -375,7 +380,13 @@ END_SCRIPTDESC(); class CScriptGameEventListener : public IGameEventListener2, public CAutoGameSystem { public: - CScriptGameEventListener() : m_bActive(false) /*, m_nEventTick(0)*/ {} + CScriptGameEventListener() : m_bActive(false) + { +#ifdef _DEBUG + m_nEventTick = 0; +#endif + } + ~CScriptGameEventListener() { StopListeningForEvent(); @@ -397,7 +408,9 @@ private: HSCRIPT m_hCallback; unsigned int m_iContextHash; bool m_bActive; - //int m_nEventTick; +#ifdef _DEBUG + int m_nEventTick; +#endif static StringHashFunctor Hash; static inline unsigned int HashContext( const char* c ) { return c ? Hash(c) : 0; } @@ -592,7 +605,9 @@ void CScriptGameEventListener::LevelShutdownPreEntity() void CScriptGameEventListener::FireGameEvent( IGameEvent *event ) { - //m_nEventTick = gpGlobals->tickcount; +#ifdef _DEBUG + m_nEventTick = gpGlobals->tickcount; +#endif ScriptVariant_t hTable; g_pScriptVM->CreateTable( hTable ); WriteEventData( event, hTable ); @@ -722,13 +737,15 @@ void CScriptGameEventListener::StopListeningForEvent() if ( gameeventmanager ) gameeventmanager->RemoveListener( this ); +#ifdef _DEBUG // Event listeners are iterated forwards in the game event manager, // removing while iterating will cause it to skip one listener. // This could be prevented by writing a custom game event manager. - //if ( m_nEventTick == gpGlobals->tickcount ) - //{ - // Warning("CScriptGameEventListener stopped in the same frame it was fired. This will break other event listeners!\n"); - //} + if ( m_nEventTick == gpGlobals->tickcount ) + { + Warning("CScriptGameEventListener stopped in the same frame it was fired. This will break other event listeners!\n"); + } +#endif } //----------------------------------------------------------------------------- @@ -2405,9 +2422,7 @@ public: inline bool IsOverridable( unsigned int hash ) { int idx = g_ConCommandsOverridable.Find( hash ); - if ( idx == g_ConCommandsOverridable.InvalidIndex() ) - return false; - return true; + return ( idx != g_ConCommandsOverridable.InvalidIndex() ); } inline void AddBlockedConVar( const char *name ) @@ -2418,9 +2433,7 @@ public: inline bool IsBlockedConvar( const char *name ) { int idx = g_ConVarsBlocked.Find( Hash(name) ); - if ( idx == g_ConVarsBlocked.InvalidIndex() ) - return false; - return true; + return ( idx != g_ConVarsBlocked.InvalidIndex() ); } public: From 690299b39c0ec6bd87a1121f3560a179090e401c Mon Sep 17 00:00:00 2001 From: samisalreadytaken <46823719+samisalreadytaken@users.noreply.github.com> Date: Fri, 1 Oct 2021 16:20:24 +0300 Subject: [PATCH 169/378] Add missing documentation in vscript --- sp/src/vscript/vscript_squirrel.nut | 119 ++++++++++++++++++---------- 1 file changed, 76 insertions(+), 43 deletions(-) diff --git a/sp/src/vscript/vscript_squirrel.nut b/sp/src/vscript/vscript_squirrel.nut index 79cfb6c4..b1700118 100644 --- a/sp/src/vscript/vscript_squirrel.nut +++ b/sp/src/vscript/vscript_squirrel.nut @@ -7,62 +7,82 @@ static char g_Script_vscript_squirrel[] = R"vscript( Warning <- error; -function clamp(val,min,max) +function clamp( val, min, max ) { if ( max < min ) return max; - else if( val < min ) + if ( val < min ) return min; - else if( val > max ) + if ( val > max ) return max; - else - return val; + return val; } -function max(a,b) return a > b ? a : b +function max( a, b ) +{ + if ( a > b ) + return a; + return b; +} -function min(a,b) return a < b ? a : b +function min( a, b ) +{ + if ( a < b ) + return a; + return b; +} -function RemapVal(val, A, B, C, D) +function RemapVal( val, A, B, C, D ) { if ( A == B ) - return val >= B ? D : C; + { + if ( val >= B ) + return D; + return C; + }; return C + (D - C) * (val - A) / (B - A); } -function RemapValClamped(val, A, B, C, D) +function RemapValClamped( val, A, B, C, D ) { if ( A == B ) - return val >= B ? D : C; + { + if ( val >= B ) + return D; + return C; + }; + local cVal = (val - A) / (B - A); - cVal = (cVal < 0.0) ? 0.0 : (1.0 < cVal) ? 1.0 : cVal; + + if ( cVal <= 0.0 ) + return C; + + if ( cVal >= 1.0 ) + return D; + return C + (D - C) * cVal; } function Approach( target, value, speed ) { - local delta = target - value + local delta = target - value; - if( delta > speed ) - value += speed - else if( delta < (-speed) ) - value -= speed - else - value = target - - return value + if ( delta > speed ) + return value + speed; + if ( -speed > delta ) + return value - speed; + return target; } function AngleDistance( next, cur ) { local delta = next - cur - if ( delta < (-180.0) ) - delta += 360.0 - else if ( delta > 180.0 ) - delta -= 360.0 - - return delta + if ( delta > 180.0 ) + return delta - 360.0; + if ( -180.0 > delta ) + return delta + 360.0; + return delta; } function FLerp( f1, f2, i1, i2, x ) @@ -83,7 +103,7 @@ function SimpleSpline( f ) function printl( text ) { - return ::print(text + "\n"); + return print(text + "\n"); } class CSimpleCallChainer @@ -481,23 +501,36 @@ else } } -// Vector documentation -__Documentation.RegisterClassHelp( "Vector", "", "Basic 3-float Vector class." ); -__Documentation.RegisterHelp( "Vector::Length", "float Vector::Length()", "Return the vector's length." ); -__Documentation.RegisterHelp( "Vector::LengthSqr", "float Vector::LengthSqr()", "Return the vector's squared length." ); -__Documentation.RegisterHelp( "Vector::Length2D", "float Vector::Length2D()", "Return the vector's 2D length." ); -__Documentation.RegisterHelp( "Vector::Length2DSqr", "float Vector::Length2DSqr()", "Return the vector's squared 2D length." ); +if (developer) +{ + // Vector documentation + __Documentation.RegisterClassHelp( "Vector", "", "Basic 3-float Vector class." ); + __Documentation.RegisterHelp( "Vector::Length", "float Vector::Length()", "Return the vector's length." ); + __Documentation.RegisterHelp( "Vector::LengthSqr", "float Vector::LengthSqr()", "Return the vector's squared length." ); + __Documentation.RegisterHelp( "Vector::Length2D", "float Vector::Length2D()", "Return the vector's 2D length." ); + __Documentation.RegisterHelp( "Vector::Length2DSqr", "float Vector::Length2DSqr()", "Return the vector's squared 2D length." ); -__Documentation.RegisterHelp( "Vector::Normalized", "float Vector::Normalized()", "Return a normalized version of the vector." ); -__Documentation.RegisterHelp( "Vector::Norm", "void Vector::Norm()", "Normalize the vector in place." ); -__Documentation.RegisterHelp( "Vector::Scale", "vector Vector::Scale(float)", "Scale the vector's magnitude and return the result." ); -__Documentation.RegisterHelp( "Vector::Dot", "float Vector::Dot(vector)", "Return the dot/scalar product of two vectors." ); -__Documentation.RegisterHelp( "Vector::Cross", "float Vector::Cross(vector)", "Return the vector product of two vectors." ); + __Documentation.RegisterHelp( "Vector::Normalized", "float Vector::Normalized()", "Return a normalized version of the vector." ); + __Documentation.RegisterHelp( "Vector::Norm", "void Vector::Norm()", "Normalize the vector in place." ); + __Documentation.RegisterHelp( "Vector::Scale", "vector Vector::Scale(float)", "Scale the vector's magnitude and return the result." ); + __Documentation.RegisterHelp( "Vector::Dot", "float Vector::Dot(vector)", "Return the dot/scalar product of two vectors." ); + __Documentation.RegisterHelp( "Vector::Cross", "float Vector::Cross(vector)", "Return the vector product of two vectors." ); -__Documentation.RegisterHelp( "Vector::ToKVString", "string Vector::ToKVString()", "Return a vector as a string in KeyValue form, without separation commas." ); + __Documentation.RegisterHelp( "Vector::ToKVString", "string Vector::ToKVString()", "Return a vector as a string in KeyValue form, without separation commas." ); -__Documentation.RegisterMemberHelp( "Vector.x", "float Vector.x", "The vector's X coordinate on the cartesian X axis." ); -__Documentation.RegisterMemberHelp( "Vector.y", "float Vector.y", "The vector's Y coordinate on the cartesian Y axis." ); -__Documentation.RegisterMemberHelp( "Vector.z", "float Vector.z", "The vector's Z coordinate on the cartesian Z axis." ); + __Documentation.RegisterMemberHelp( "Vector.x", "float Vector.x", "The vector's X coordinate on the cartesian X axis." ); + __Documentation.RegisterMemberHelp( "Vector.y", "float Vector.y", "The vector's Y coordinate on the cartesian Y axis." ); + __Documentation.RegisterMemberHelp( "Vector.z", "float Vector.z", "The vector's Z coordinate on the cartesian Z axis." ); + __Documentation.RegisterHelp( "clamp", "float clamp(float, float, float)", "" ); + __Documentation.RegisterHelp( "max", "float max(float, float)", "" ); + __Documentation.RegisterHelp( "min", "float min(float, float)", "" ); + __Documentation.RegisterHelp( "RemapVal", "float RemapVal(float, float, float, float, float)", "" ); + __Documentation.RegisterHelp( "RemapValClamped", "float RemapValClamped(float, float, float, float, float)", "" ); + __Documentation.RegisterHelp( "Approach", "float Approach(float, float, float)", "" ); + __Documentation.RegisterHelp( "AngleDistance", "float AngleDistance(float, float)", "" ); + __Documentation.RegisterHelp( "FLerp", "float FLerp(float, float, float, float, float)", "" ); + __Documentation.RegisterHelp( "Lerp", "float Lerp(float, float, float)", "" ); + __Documentation.RegisterHelp( "SimpleSpline", "float SimpleSpline(float)", "" ); +} )vscript"; \ No newline at end of file From 7894c8ad8768399c85f30a031226d3c4771701a5 Mon Sep 17 00:00:00 2001 From: samisalreadytaken <46823719+samisalreadytaken@users.noreply.github.com> Date: Mon, 4 Oct 2021 20:26:46 +0300 Subject: [PATCH 170/378] Eliminate redundant code --- sp/src/game/server/hl2/hl2_player.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sp/src/game/server/hl2/hl2_player.cpp b/sp/src/game/server/hl2/hl2_player.cpp index a43cfe32..6f4a8ef2 100644 --- a/sp/src/game/server/hl2/hl2_player.cpp +++ b/sp/src/game/server/hl2/hl2_player.cpp @@ -4036,7 +4036,10 @@ Vector CHL2_Player::EyeDirection2D( void ) Vector CHL2_Player::EyeDirection3D( void ) { Vector vecForward; - +#ifdef MAPBASE + EyeVectors( &vecForward ); + return vecForward; +#else // Return the vehicle angles if we request them if ( GetVehicle() != NULL ) { @@ -4047,6 +4050,7 @@ Vector CHL2_Player::EyeDirection3D( void ) AngleVectors( EyeAngles(), &vecForward ); return vecForward; +#endif } From 495d534307b85fd1865ee1ee0edcbfc7c506a5b1 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sat, 9 Oct 2021 15:04:10 -0500 Subject: [PATCH 171/378] Fixed trigger_fall not doing anything when landing in water --- sp/src/game/client/c_baseplayer.cpp | 1 + sp/src/game/client/c_baseplayer.h | 2 ++ sp/src/game/server/player.cpp | 1 + sp/src/game/server/player.h | 2 +- sp/src/game/shared/gamemovement.cpp | 8 +++++--- 5 files changed, 10 insertions(+), 4 deletions(-) diff --git a/sp/src/game/client/c_baseplayer.cpp b/sp/src/game/client/c_baseplayer.cpp index ced6ced9..0b2422fa 100644 --- a/sp/src/game/client/c_baseplayer.cpp +++ b/sp/src/game/client/c_baseplayer.cpp @@ -281,6 +281,7 @@ END_RECV_TABLE() RecvPropInt ( RECVINFO( m_spawnflags ), 0, RecvProxy_ShiftPlayerSpawnflags ), RecvPropBool ( RECVINFO( m_bDrawPlayerModelExternally ) ), + RecvPropBool ( RECVINFO( m_bInTriggerFall ) ), #endif END_RECV_TABLE() diff --git a/sp/src/game/client/c_baseplayer.h b/sp/src/game/client/c_baseplayer.h index fac6c0dd..84ccffb5 100644 --- a/sp/src/game/client/c_baseplayer.h +++ b/sp/src/game/client/c_baseplayer.h @@ -458,6 +458,8 @@ public: // Allows the player's model to draw on non-main views, like monitors or mirrors. bool m_bDrawPlayerModelExternally; + + bool m_bInTriggerFall; #endif protected: diff --git a/sp/src/game/server/player.cpp b/sp/src/game/server/player.cpp index e2465cc7..5280b60a 100644 --- a/sp/src/game/server/player.cpp +++ b/sp/src/game/server/player.cpp @@ -8676,6 +8676,7 @@ void SendProxy_ShiftPlayerSpawnflags( const SendProp *pProp, const void *pStruct SendPropInt ( SENDINFO( m_spawnflags ), 3, SPROP_UNSIGNED, SendProxy_ShiftPlayerSpawnflags ), SendPropBool ( SENDINFO( m_bDrawPlayerModelExternally ) ), + SendPropBool ( SENDINFO( m_bInTriggerFall ) ), #endif END_SEND_TABLE() diff --git a/sp/src/game/server/player.h b/sp/src/game/server/player.h index 03709ade..85c92c67 100644 --- a/sp/src/game/server/player.h +++ b/sp/src/game/server/player.h @@ -943,7 +943,7 @@ public: #endif #ifdef MAPBASE - bool m_bInTriggerFall; + CNetworkVar( bool, m_bInTriggerFall ); #endif private: diff --git a/sp/src/game/shared/gamemovement.cpp b/sp/src/game/shared/gamemovement.cpp index d77d0c89..46afe4f2 100644 --- a/sp/src/game/shared/gamemovement.cpp +++ b/sp/src/game/shared/gamemovement.cpp @@ -3907,13 +3907,11 @@ void CGameMovement::CheckFalling( void ) return; #ifdef MAPBASE -#ifdef GAME_DLL // Let's hope we could work without transmitting to the client... if ( player->m_bInTriggerFall ) { - // This lets the fall damage functions do their magic without having to change them. + // This value lets the existing fall damage functions ensure a fatal fall. player->m_Local.m_flFallVelocity += (PLAYER_FATAL_FALL_SPEED + PLAYER_LAND_ON_FLOATING_OBJECT); } -#endif #endif if ( !IsDead() && player->m_Local.m_flFallVelocity >= PLAYER_FALL_PUNCH_THRESHOLD ) @@ -3921,7 +3919,11 @@ void CGameMovement::CheckFalling( void ) bool bAlive = true; float fvol = 0.5; +#ifdef MAPBASE + if ( player->GetWaterLevel() > 0 && !player->m_bInTriggerFall ) +#else if ( player->GetWaterLevel() > 0 ) +#endif { // They landed in water. } From cc32c629643727fe3f1706050b6670f758337f49 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sat, 9 Oct 2021 15:05:28 -0500 Subject: [PATCH 172/378] Fixed issues with particle precipitation clamping not working on spawn or being inconsistent for non-rain types --- sp/src/game/client/c_effects.cpp | 115 ++++++++++++++++++++----------- sp/src/game/client/c_effects.h | 4 ++ 2 files changed, 80 insertions(+), 39 deletions(-) diff --git a/sp/src/game/client/c_effects.cpp b/sp/src/game/client/c_effects.cpp index afd5bcf9..135b5645 100644 --- a/sp/src/game/client/c_effects.cpp +++ b/sp/src/game/client/c_effects.cpp @@ -40,7 +40,10 @@ ConVar r_RainSplashPercentage( "r_RainSplashPercentage", "20", FCVAR_CHEAT ); // ConVar r_RainParticleDensity( "r_RainParticleDensity", "1", FCVAR_NONE, "Density of Particle Rain 0-1" ); #ifdef MAPBASE -ConVar r_RainParticleClampOffset( "r_RainParticleClampOffset", "112", FCVAR_NONE, "How far inward or outward to extrude clamped precipitation particle systems" ); +ConVar r_RainParticleClampOffset_Rain( "r_RainParticleClampOffset_Rain", "112", FCVAR_NONE, "How far inward or outward to extrude clamped precipitation particle systems using the 'Particle Rain' type." ); +ConVar r_RainParticleClampOffset_Ash( "r_RainParticleClampOffset_Ash", "300", FCVAR_NONE, "How far inward or outward to extrude clamped precipitation particle systems using the 'Particle Ash' type." ); +ConVar r_RainParticleClampOffset_RainStorm( "r_RainParticleClampOffset_RainStorm", "112", FCVAR_NONE, "How far inward or outward to extrude clamped precipitation particle systems using the 'Particle Rain Storm' type." ); +ConVar r_RainParticleClampOffset_Snow( "r_RainParticleClampOffset_Snow", "300", FCVAR_NONE, "How far inward or outward to extrude clamped precipitation particle systems using the 'Particle Snow' type." ); ConVar r_RainParticleClampDebug( "r_RainParticleClampDebug", "0", FCVAR_NONE, "Enables debug code for precipitation particle system clamping" ); #endif @@ -951,6 +954,70 @@ void CClient_Precipitation::CreateParticlePrecip( void ) UpdateParticlePrecip( pPlayer ); } +#ifdef MAPBASE +void CClient_Precipitation::ClampParticlePosition( Vector &vPlayerPos, Vector &vOffsetPos, Vector &vOffsetPosNear, Vector &vOffsetPosFar ) +{ + Vector mins, maxs; + modelinfo->GetModelBounds( GetModel(), mins, maxs ); + + // Account for precipitation height + maxs.z += 180; + + Vector vecOrigin; //= WorldSpaceCenter(); + VectorLerp( mins, maxs, 0.5f, vecOrigin ); + + maxs -= vecOrigin; + mins -= vecOrigin; + + //float flMax = r_RainParticleClampOffset.GetFloat(); + float flMax = 0; + switch (m_nPrecipType) + { + case PRECIPITATION_TYPE_PARTICLERAIN: + flMax = r_RainParticleClampOffset_Rain.GetFloat(); + break; + + case PRECIPITATION_TYPE_PARTICLEASH: + flMax = r_RainParticleClampOffset_Ash.GetFloat(); + break; + + case PRECIPITATION_TYPE_PARTICLERAINSTORM: + flMax = r_RainParticleClampOffset_RainStorm.GetFloat(); + break; + + case PRECIPITATION_TYPE_PARTICLESNOW: + flMax = r_RainParticleClampOffset_Snow.GetFloat(); + break; + } + + Vector addend( flMax, flMax, 0 ); + mins += addend; + maxs -= addend; + + if (flMax > 0) + { + // Unless this is extruding outwards, make sure the offset isn't inverting the bounds. + // This means precipitation triggers with bounds less than offset*2 will turn into a thin line + // and the involved precipitation will pretty much be spatial at all times, which is okay. + mins.x = clamp( mins.x, -FLT_MAX, -1 ); + mins.y = clamp( mins.y, -FLT_MAX, -1 ); + maxs.x = clamp( maxs.x, 1, FLT_MAX ); + maxs.y = clamp( maxs.y, 1, FLT_MAX ); + } + + if (r_RainParticleClampDebug.GetBool()) + debugoverlay->AddBoxOverlay( vecOrigin, mins, maxs, vec3_angle, 255, 0, 0, 128, 0.15f ); + + maxs += vecOrigin; + mins += vecOrigin; + + CalcClosestPointOnAABB( mins, maxs, vPlayerPos, vPlayerPos ); + CalcClosestPointOnAABB( mins, maxs, vOffsetPos, vOffsetPos ); + CalcClosestPointOnAABB( mins, maxs, vOffsetPosNear, vOffsetPosNear ); + CalcClosestPointOnAABB( mins, maxs, vOffsetPosFar, vOffsetPosFar ); +} +#endif + void CClient_Precipitation::UpdateParticlePrecip( C_BasePlayer *pPlayer ) { if ( !pPlayer ) @@ -980,44 +1047,7 @@ void CClient_Precipitation::UpdateParticlePrecip( C_BasePlayer *pPlayer ) #ifdef MAPBASE if (m_spawnflags & SF_PRECIP_PARTICLE_CLAMP) { - Vector mins, maxs; - modelinfo->GetModelBounds( GetModel(), mins, maxs ); - - // Account for precipitation height - maxs.z += 180; - - Vector vecOrigin; //= WorldSpaceCenter(); - VectorLerp( mins, maxs, 0.5f, vecOrigin ); - - maxs -= vecOrigin; - mins -= vecOrigin; - - float flMax = r_RainParticleClampOffset.GetFloat(); - Vector addend( flMax, flMax, 0 ); - mins += addend; - maxs -= addend; - - if (flMax > 0) - { - // Unless this is extruding outwards, make sure the offset isn't inverting the bounds. - // This means precipitation triggers with bounds less than offset*2 will turn into a thin line - // and the involved precipitation will pretty much be spatial at all times, which is okay. - mins.x = clamp( mins.x, -FLT_MAX, -1 ); - mins.y = clamp( mins.y, -FLT_MAX, -1 ); - maxs.x = clamp( maxs.x, 1, FLT_MAX ); - maxs.y = clamp( maxs.y, 1, FLT_MAX ); - } - - if (r_RainParticleClampDebug.GetBool()) - debugoverlay->AddBoxOverlay( vecOrigin, mins, maxs, vec3_angle, 255, 0, 0, 128, 0.15f ); - - maxs += vecOrigin; - mins += vecOrigin; - - CalcClosestPointOnAABB( mins, maxs, vPlayerPos, vPlayerPos ); - CalcClosestPointOnAABB( mins, maxs, vOffsetPos, vOffsetPos ); - CalcClosestPointOnAABB( mins, maxs, vOffsetPosNear, vOffsetPosNear ); - CalcClosestPointOnAABB( mins, maxs, vOffsetPosFar, vOffsetPosFar ); + ClampParticlePosition( vPlayerPos, vOffsetPos, vOffsetPosNear, vOffsetPosFar ); } #endif @@ -1236,6 +1266,13 @@ void CClient_Precipitation::DispatchInnerParticlePrecip( C_BasePlayer *pPlayer, Vector vOffsetPosFar = vPlayerPos + Vector ( 0, 0, 180 ) + ( vForward * m_flParticleInnerDist ); // 100.0 Vector vDensity = Vector( r_RainParticleDensity.GetFloat(), 0, 0 ) * m_flDensity; +#ifdef MAPBASE + if (m_spawnflags & SF_PRECIP_PARTICLE_CLAMP) + { + ClampParticlePosition( vPlayerPos, vOffsetPos, vOffsetPosNear, vOffsetPosFar ); + } +#endif + #ifdef MAPBASE if (!(m_spawnflags & SF_PRECIP_PARTICLE_NO_OUTER)) #endif diff --git a/sp/src/game/client/c_effects.h b/sp/src/game/client/c_effects.h index 6012dff7..5f7e02a5 100644 --- a/sp/src/game/client/c_effects.h +++ b/sp/src/game/client/c_effects.h @@ -130,6 +130,10 @@ private: void CreateAshParticle( void ); void CreateRainOrSnowParticle( Vector vSpawnPosition, Vector vVelocity ); +#ifdef MAPBASE + void ClampParticlePosition( Vector &vPlayerPos, Vector &vOffsetPos, Vector &vOffsetPosNear, Vector &vOffsetPosFar ); +#endif + // Information helpful in creating and rendering particles IMaterial *m_MatHandle; // material used From f880e95e47fa42426124feecac50034d432e659e Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sat, 9 Oct 2021 15:06:36 -0500 Subject: [PATCH 173/378] Encapsulated m_bDrawPlayerModelExternally --- sp/src/game/server/hl2/hl2_player.cpp | 2 +- sp/src/game/server/player.h | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/sp/src/game/server/hl2/hl2_player.cpp b/sp/src/game/server/hl2/hl2_player.cpp index a43cfe32..e52ffcb0 100644 --- a/sp/src/game/server/hl2/hl2_player.cpp +++ b/sp/src/game/server/hl2/hl2_player.cpp @@ -5089,6 +5089,6 @@ void CLogicPlayerProxy::InputSetPlayerDrawExternally( inputdata_t &inputdata ) return; CBasePlayer *pPlayer = static_cast(m_hPlayer.Get()); - pPlayer->m_bDrawPlayerModelExternally = inputdata.value.Bool(); + pPlayer->SetDrawPlayerModelExternally( inputdata.value.Bool() ); } #endif diff --git a/sp/src/game/server/player.h b/sp/src/game/server/player.h index 85c92c67..bda4a5fe 100644 --- a/sp/src/game/server/player.h +++ b/sp/src/game/server/player.h @@ -1147,7 +1147,8 @@ public: int m_nNumCrateHudHints; #ifdef MAPBASE - CNetworkVar( bool, m_bDrawPlayerModelExternally ); + bool GetDrawPlayerModelExternally( void ) { return m_bDrawPlayerModelExternally; } + void SetDrawPlayerModelExternally( bool bToggle ) { m_bDrawPlayerModelExternally.Set( bToggle ); } #endif private: @@ -1188,6 +1189,10 @@ private: // Player name char m_szNetname[MAX_PLAYER_NAME_LENGTH]; +#ifdef MAPBASE + CNetworkVar( bool, m_bDrawPlayerModelExternally ); +#endif + protected: // HACK FOR TF2 Prediction friend class CTFGameMovementRecon; From 35f941d6d0a06aceb6f935b8566215494331e721 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sat, 9 Oct 2021 15:09:48 -0500 Subject: [PATCH 174/378] Fixed issues with hand viewmodels not working upon weapon holster + Added a way to set the hand viewmodel bodygroup --- sp/src/game/server/hl2/hl2_client.cpp | 2 +- sp/src/game/server/hl2/hl2_player.cpp | 15 +++++++++++++++ sp/src/game/shared/baseviewmodel_shared.cpp | 20 ++++++++++++++++++++ 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/sp/src/game/server/hl2/hl2_client.cpp b/sp/src/game/server/hl2/hl2_client.cpp index 4cd9dd7b..12dc248f 100644 --- a/sp/src/game/server/hl2/hl2_client.cpp +++ b/sp/src/game/server/hl2/hl2_client.cpp @@ -142,7 +142,7 @@ void respawn( CBaseEntity *pEdict, bool fCopyCorpse ) { // In SP respawns, only create corpse if drawing externally CBasePlayer *pPlayer = (CBasePlayer*)pEdict; - if ( fCopyCorpse && pPlayer->m_bDrawPlayerModelExternally ) + if ( fCopyCorpse && pPlayer->GetDrawPlayerModelExternally() ) { // make a copy of the dead body for appearances sake pPlayer->CreateCorpse(); diff --git a/sp/src/game/server/hl2/hl2_player.cpp b/sp/src/game/server/hl2/hl2_player.cpp index e52ffcb0..3e70f4fa 100644 --- a/sp/src/game/server/hl2/hl2_player.cpp +++ b/sp/src/game/server/hl2/hl2_player.cpp @@ -259,6 +259,7 @@ public: void InputSetHandModel( inputdata_t &inputdata ); void InputSetHandModelSkin( inputdata_t &inputdata ); + void InputSetHandModelBodyGroup( inputdata_t &inputdata ); void InputSetPlayerModel( inputdata_t &inputdata ); void InputSetPlayerDrawExternally( inputdata_t &inputdata ); @@ -4617,6 +4618,7 @@ BEGIN_DATADESC( CLogicPlayerProxy ) DEFINE_INPUTFUNC( FIELD_STRING, "GetAmmoOnWeapon", InputGetAmmoOnWeapon ), DEFINE_INPUTFUNC( FIELD_STRING, "SetHandModel", InputSetHandModel ), DEFINE_INPUTFUNC( FIELD_INTEGER, "SetHandModelSkin", InputSetHandModelSkin ), + DEFINE_INPUTFUNC( FIELD_INTEGER, "SetHandModelBodyGroup", InputSetHandModelBodyGroup ), DEFINE_INPUTFUNC( FIELD_STRING, "SetPlayerModel", InputSetPlayerModel ), DEFINE_INPUTFUNC( FIELD_BOOLEAN, "SetPlayerDrawExternally", InputSetPlayerDrawExternally ), DEFINE_INPUT( m_MaxArmor, FIELD_INTEGER, "SetMaxInputArmor" ), @@ -4659,6 +4661,8 @@ bool CLogicPlayerProxy::KeyValue( const char *szKeyName, const char *szValue ) vm->SetModel(szValue); else if (FStrEq(szKeyName, "Skin")) // HandsVMSkin vm->m_nSkin = atoi(szValue); + else if (FStrEq(szKeyName, "Body")) // HandsVMBody + vm->m_nBody = atoi(szValue); } return true; } @@ -5062,6 +5066,17 @@ void CLogicPlayerProxy::InputSetHandModelSkin( inputdata_t &inputdata ) vm->m_nSkin = inputdata.value.Int(); } +void CLogicPlayerProxy::InputSetHandModelBodyGroup( inputdata_t &inputdata ) +{ + if (!m_hPlayer) + return; + + CBasePlayer *pPlayer = static_cast( m_hPlayer.Get() ); + CBaseViewModel *vm = pPlayer->GetViewModel(1); + if (vm) + vm->m_nBody = inputdata.value.Int(); +} + void CLogicPlayerProxy::InputSetPlayerModel( inputdata_t &inputdata ) { if (!m_hPlayer) diff --git a/sp/src/game/shared/baseviewmodel_shared.cpp b/sp/src/game/shared/baseviewmodel_shared.cpp index 708c17bb..47acecd6 100644 --- a/sp/src/game/shared/baseviewmodel_shared.cpp +++ b/sp/src/game/shared/baseviewmodel_shared.cpp @@ -289,6 +289,16 @@ void CBaseViewModel::AddEffects( int nEffects ) SetControlPanelsActive( false ); } +#ifdef MAPBASE + // Apply effect changes to any viewmodel children as well + // (fixes hand models) + for (CBaseEntity *pChild = FirstMoveChild(); pChild != NULL; pChild = pChild->NextMovePeer()) + { + if (pChild->GetClassname()[0] == 'h') + pChild->AddEffects( nEffects ); + } +#endif + BaseClass::AddEffects( nEffects ); } @@ -302,6 +312,16 @@ void CBaseViewModel::RemoveEffects( int nEffects ) SetControlPanelsActive( true ); } +#ifdef MAPBASE + // Apply effect changes to any viewmodel children as well + // (fixes hand models) + for (CBaseEntity *pChild = FirstMoveChild(); pChild != NULL; pChild = pChild->NextMovePeer()) + { + if (pChild->GetClassname()[0] == 'h') + pChild->RemoveEffects( nEffects ); + } +#endif + BaseClass::RemoveEffects( nEffects ); } From 525e3214f2e61f98aa11d113933cc0a846e02d4e Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sun, 10 Oct 2021 19:35:04 -0500 Subject: [PATCH 175/378] Added global VScript hooks for entity creation/deletion --- sp/src/game/client/vscript_client.cpp | 48 +++++++++++++++++++- sp/src/game/server/vscript_server.cpp | 65 ++++++++++++++++++++++++++- 2 files changed, 111 insertions(+), 2 deletions(-) diff --git a/sp/src/game/client/vscript_client.cpp b/sp/src/game/client/vscript_client.cpp index dccaf2a5..405b2083 100644 --- a/sp/src/game/client/vscript_client.cpp +++ b/sp/src/game/client/vscript_client.cpp @@ -41,10 +41,13 @@ extern ScriptClassDesc_t * GetScriptDesc( CBaseEntity * ); #endif // VMPROFILE #ifdef MAPBASE_VSCRIPT +static ScriptHook_t g_Hook_OnEntityCreated; +static ScriptHook_t g_Hook_OnEntityDeleted; + //----------------------------------------------------------------------------- // Purpose: A clientside variant of CScriptEntityIterator. //----------------------------------------------------------------------------- -class CScriptClientEntityIterator +class CScriptClientEntityIterator : public IClientEntityListener { public: HSCRIPT GetLocalPlayer() @@ -96,6 +99,38 @@ public: return NULL; } + void EnableEntityListening() + { + // Start getting entity updates! + ClientEntityList().AddListenerEntity( this ); + } + + void DisableEntityListening() + { + // Stop getting entity updates! + ClientEntityList().RemoveListenerEntity( this ); + } + + void OnEntityCreated( CBaseEntity *pEntity ) + { + if ( g_pScriptVM ) + { + // entity + ScriptVariant_t args[] = { ScriptVariant_t( pEntity->GetScriptInstance() ) }; + g_Hook_OnEntityCreated.Call( NULL, NULL, args ); + } + }; + + void OnEntityDeleted( CBaseEntity *pEntity ) + { + if ( g_pScriptVM ) + { + // entity + ScriptVariant_t args[] = { ScriptVariant_t( pEntity->GetScriptInstance() ) }; + g_Hook_OnEntityDeleted.Call( NULL, NULL, args ); + } + }; + private: } g_ScriptEntityIterator; @@ -106,6 +141,17 @@ BEGIN_SCRIPTDESC_ROOT_NAMED( CScriptClientEntityIterator, "CEntities", SCRIPT_SI DEFINE_SCRIPTFUNC( CreateByClassname, "Creates an entity by classname" ) DEFINE_SCRIPTFUNC( FindByClassname, "Find entities by class name. Pass 'null' to start an iteration, or reference to a previously found entity to continue a search" ) DEFINE_SCRIPTFUNC( FindByName, "Find entities by name. Pass 'null' to start an iteration, or reference to a previously found entity to continue a search" ) + + DEFINE_SCRIPTFUNC( EnableEntityListening, "Enables the 'OnEntity' hooks. This function must be called before using them." ) + DEFINE_SCRIPTFUNC( DisableEntityListening, "Disables the 'OnEntity' hooks." ) + + BEGIN_SCRIPTHOOK( g_Hook_OnEntityCreated, "OnEntityCreated", FIELD_VOID, "Called when an entity is created. Requires EnableEntityListening() to be fired beforehand." ) + DEFINE_SCRIPTHOOK_PARAM( "entity", FIELD_HSCRIPT ) + END_SCRIPTHOOK() + + BEGIN_SCRIPTHOOK( g_Hook_OnEntityDeleted, "OnEntityDeleted", FIELD_VOID, "Called when an entity is deleted. Requires EnableEntityListening() to be fired beforehand." ) + DEFINE_SCRIPTHOOK_PARAM( "entity", FIELD_HSCRIPT ) + END_SCRIPTHOOK() END_SCRIPTDESC(); //----------------------------------------------------------------------------- diff --git a/sp/src/game/server/vscript_server.cpp b/sp/src/game/server/vscript_server.cpp index 6927b0f1..76d66a83 100644 --- a/sp/src/game/server/vscript_server.cpp +++ b/sp/src/game/server/vscript_server.cpp @@ -37,10 +37,16 @@ extern ScriptClassDesc_t * GetScriptDesc( CBaseEntity * ); #endif // VMPROFILE +#ifdef MAPBASE_VSCRIPT +static ScriptHook_t g_Hook_OnEntityCreated; +static ScriptHook_t g_Hook_OnEntitySpawned; +static ScriptHook_t g_Hook_OnEntityDeleted; +#endif + //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- -class CScriptEntityIterator +class CScriptEntityIterator : public IEntityListener { public: #ifdef MAPBASE_VSCRIPT @@ -115,6 +121,48 @@ public: { return ToHScript( gEntList.FindEntityClassNearestFacing( origin, facing, threshold, const_cast(classname) ) ); } + + void EnableEntityListening() + { + // Start getting entity updates! + gEntList.AddListenerEntity( this ); + } + + void DisableEntityListening() + { + // Stop getting entity updates! + gEntList.RemoveListenerEntity( this ); + } + + void OnEntityCreated( CBaseEntity *pEntity ) + { + if ( g_pScriptVM ) + { + // entity + ScriptVariant_t args[] = { ScriptVariant_t( pEntity->GetScriptInstance() ) }; + g_Hook_OnEntityCreated.Call( NULL, NULL, args ); + } + }; + + void OnEntitySpawned( CBaseEntity *pEntity ) + { + if ( g_pScriptVM ) + { + // entity + ScriptVariant_t args[] = { ScriptVariant_t( pEntity->GetScriptInstance() ) }; + g_Hook_OnEntitySpawned.Call( NULL, NULL, args ); + } + }; + + void OnEntityDeleted( CBaseEntity *pEntity ) + { + if ( g_pScriptVM ) + { + // entity + ScriptVariant_t args[] = { ScriptVariant_t( pEntity->GetScriptInstance() ) }; + g_Hook_OnEntityDeleted.Call( NULL, NULL, args ); + } + }; #endif private: } g_ScriptEntityIterator; @@ -138,6 +186,21 @@ BEGIN_SCRIPTDESC_ROOT_NAMED( CScriptEntityIterator, "CEntities", SCRIPT_SINGLETO #ifdef MAPBASE_VSCRIPT DEFINE_SCRIPTFUNC( FindByClassnameWithinBox, "Find entities by class name within an AABB. Pass 'null' to start an iteration, or reference to a previously found entity to continue a search" ) DEFINE_SCRIPTFUNC( FindByClassNearestFacing, "Find the nearest entity along the facing direction from the given origin within the angular threshold with the given classname." ) + + DEFINE_SCRIPTFUNC( EnableEntityListening, "Enables the 'OnEntity' hooks. This function must be called before using them." ) + DEFINE_SCRIPTFUNC( DisableEntityListening, "Disables the 'OnEntity' hooks." ) + + BEGIN_SCRIPTHOOK( g_Hook_OnEntityCreated, "OnEntityCreated", FIELD_VOID, "Called when an entity is created. Requires EnableEntityListening() to be fired beforehand." ) + DEFINE_SCRIPTHOOK_PARAM( "entity", FIELD_HSCRIPT ) + END_SCRIPTHOOK() + + BEGIN_SCRIPTHOOK( g_Hook_OnEntitySpawned, "OnEntitySpawned", FIELD_VOID, "Called when an entity spawns. Requires EnableEntityListening() to be fired beforehand." ) + DEFINE_SCRIPTHOOK_PARAM( "entity", FIELD_HSCRIPT ) + END_SCRIPTHOOK() + + BEGIN_SCRIPTHOOK( g_Hook_OnEntityDeleted, "OnEntityDeleted", FIELD_VOID, "Called when an entity is deleted. Requires EnableEntityListening() to be fired beforehand." ) + DEFINE_SCRIPTHOOK_PARAM( "entity", FIELD_HSCRIPT ) + END_SCRIPTHOOK() #endif END_SCRIPTDESC(); From 138d6c52aae2a22df0273bc5115a75a07a0be523 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sun, 10 Oct 2021 19:41:42 -0500 Subject: [PATCH 176/378] Ported some minor fixes from the Alien Swarm SDK --- sp/src/game/server/ai_baseactor.cpp | 8 +++++ sp/src/game/server/ai_basenpc.cpp | 48 ++++++++++++++++------------- 2 files changed, 35 insertions(+), 21 deletions(-) diff --git a/sp/src/game/server/ai_baseactor.cpp b/sp/src/game/server/ai_baseactor.cpp index 09940829..99f6b244 100644 --- a/sp/src/game/server/ai_baseactor.cpp +++ b/sp/src/game/server/ai_baseactor.cpp @@ -835,7 +835,11 @@ void CAI_BaseActor::UpdateLatchedValues( ) // set head latch m_fLatchedPositions |= HUMANOID_LATCHED_HEAD; +#ifdef MAPBASE // From Alien Swarm SDK + if ( CanSkipAnimation() || !GetAttachment( "eyes", m_latchedEyeOrigin, &m_latchedHeadDirection )) +#else if (!HasCondition( COND_IN_PVS ) || !GetAttachment( "eyes", m_latchedEyeOrigin, &m_latchedHeadDirection )) +#endif { m_latchedEyeOrigin = BaseClass::EyePosition( ); AngleVectors( GetLocalAngles(), &m_latchedHeadDirection ); @@ -1626,7 +1630,11 @@ void CAI_BaseActor::MaintainLookTargets( float flInterval ) } // don't bother with any of the rest if the player can't see you +#ifdef MAPBASE // From Alien Swarm SDK + if ( CanSkipAnimation() ) +#else if (!HasCondition( COND_IN_PVS )) +#endif { return; } diff --git a/sp/src/game/server/ai_basenpc.cpp b/sp/src/game/server/ai_basenpc.cpp index 1aa07ac7..513f6dc2 100644 --- a/sp/src/game/server/ai_basenpc.cpp +++ b/sp/src/game/server/ai_basenpc.cpp @@ -668,7 +668,7 @@ void CAI_BaseNPC::Ignite( float flFlameLifetime, bool bNPCOnly, float flSize, bo #ifdef HL2_EPISODIC CBasePlayer *pPlayer = AI_GetSinglePlayer(); - if ( pPlayer->IRelationType( this ) != D_LI ) + if ( pPlayer && pPlayer->IRelationType( this ) != D_LI ) { CNPC_Alyx *alyx = CNPC_Alyx::GetAlyx(); @@ -993,29 +993,27 @@ int CAI_BaseNPC::OnTakeDamage_Alive( const CTakeDamageInfo &info ) // only fire once per frame m_OnDamaged.FireOutput( info.GetAttacker(), this); - if( info.GetAttacker()->IsPlayer() ) + if ( info.GetAttacker() ) { - m_OnDamagedByPlayer.FireOutput( info.GetAttacker(), this ); - - // This also counts as being harmed by player's squad. - m_OnDamagedByPlayerSquad.FireOutput( info.GetAttacker(), this ); - } - else - { - // See if the person that injured me is an NPC. -#ifdef MAPBASE - // Sometimes I find these things and I can't just sit idly by. - CAI_BaseNPC *pAttacker = info.GetAttacker()->MyNPCPointer(); -#else - CAI_BaseNPC *pAttacker = dynamic_cast( info.GetAttacker() ); -#endif - CBasePlayer *pPlayer = AI_GetSinglePlayer(); - - if( pAttacker && pAttacker->IsAlive() && pPlayer ) + if( info.GetAttacker()->IsPlayer() ) { - if( pAttacker->GetSquad() != NULL && pAttacker->IsInPlayerSquad() ) + m_OnDamagedByPlayer.FireOutput( info.GetAttacker(), this ); + + // This also counts as being harmed by player's squad. + m_OnDamagedByPlayerSquad.FireOutput( info.GetAttacker(), this ); + } + else + { + // See if the person that injured me is an NPC. + CAI_BaseNPC *pAttacker = info.GetAttacker()->MyNPCPointer(); + CBasePlayer *pPlayer = AI_GetSinglePlayer(); + + if( pAttacker && pAttacker->IsAlive() && pPlayer ) { - m_OnDamagedByPlayerSquad.FireOutput( info.GetAttacker(), this ); + if( pAttacker->GetSquad() != NULL && pAttacker->IsInPlayerSquad() ) + { + m_OnDamagedByPlayerSquad.FireOutput( info.GetAttacker(), this ); + } } } } @@ -7466,7 +7464,11 @@ void CAI_BaseNPC::SetHullSizeNormal( bool force ) if ( m_fIsUsingSmallHull || force ) { // Find out what the height difference will be between the versions and adjust our bbox accordingly to keep us level +#ifdef MAPBASE // From Alien Swarm SDK + const float flScale = MIN( 1.0f, GetModelScale() ); // NOTE: Cannot scale NPC bounding box up, as pathfinding will fail (hull needs to match the traces used for the node network) +#else const float flScale = GetModelScale(); +#endif Vector vecMins = ( GetHullMins() * flScale ); Vector vecMaxs = ( GetHullMaxs() * flScale ); @@ -13423,6 +13425,10 @@ void CAI_BaseNPC::Teleport( const Vector *newPosition, const QAngle *newAngles, CleanupScriptsOnTeleport( false ); BaseClass::Teleport( newPosition, newAngles, newVelocity ); + +#ifdef MAPBASE // From Alien Swarm SDK + CheckPVSCondition(); +#endif } //----------------------------------------------------------------------------- From 046296569d6240f0b3d417c5a43dbd018cac1ae8 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sun, 10 Oct 2021 19:47:10 -0500 Subject: [PATCH 177/378] Exposed CBaseAnimatingOverlay to VScript --- sp/src/game/server/BaseAnimatingOverlay.cpp | 96 +++++++++++++++++++++ sp/src/game/server/BaseAnimatingOverlay.h | 26 ++++++ sp/src/game/server/ai_baseactor.cpp | 4 +- sp/src/game/server/baseflex.cpp | 4 + 4 files changed, 128 insertions(+), 2 deletions(-) diff --git a/sp/src/game/server/BaseAnimatingOverlay.cpp b/sp/src/game/server/BaseAnimatingOverlay.cpp index c1d7b883..d04ff89d 100644 --- a/sp/src/game/server/BaseAnimatingOverlay.cpp +++ b/sp/src/game/server/BaseAnimatingOverlay.cpp @@ -57,6 +57,45 @@ BEGIN_DATADESC( CBaseAnimatingOverlay ) END_DATADESC() +#ifdef MAPBASE_VSCRIPT +BEGIN_ENT_SCRIPTDESC( CBaseAnimatingOverlay, CBaseAnimating, "Animating models which support dynamic animation layers/overlays." ) + + DEFINE_SCRIPTFUNC( GetNumAnimOverlays, "Gets the current number of animation layers." ) + DEFINE_SCRIPTFUNC( RemoveAllGestures, "Removes all animation layers." ) + + DEFINE_SCRIPTFUNC( IsValidLayer, "Returns true if the specified layer index is valid." ) + DEFINE_SCRIPTFUNC( HasActiveLayer, "Returns true if there is currently an active layer." ) + DEFINE_SCRIPTFUNC( RemoveLayer, "Removes the specified layer index with the specified kill rate and delay." ) + DEFINE_SCRIPTFUNC( FastRemoveLayer, "Removes the specified layer index immediately." ) + + DEFINE_SCRIPTFUNC_NAMED( ScriptAddGesture, "AddGesture", "Adds a new animation layer using the specified activity name." ) + DEFINE_SCRIPTFUNC_NAMED( ScriptAddGestureID, "AddGestureID", "Adds a new animation layer using the specified activity index." ) + DEFINE_SCRIPTFUNC_NAMED( ScriptAddGestureSequence, "AddGestureSequence", "Adds a new animation layer using the specified activity name." ) + DEFINE_SCRIPTFUNC_NAMED( ScriptAddGestureSequenceID, "AddGestureSequenceID", "Adds a new animation layer using the specified sequence index." ) + + DEFINE_SCRIPTFUNC_NAMED( ScriptFindGestureLayer, "FindGestureLayer", "Finds and returns the first active animation layer which uses the specified activity name." ) + DEFINE_SCRIPTFUNC_NAMED( ScriptFindGestureLayerByID, "FindGestureLayerByID", "Finds and returns the first active animation layer which uses the specified activity index." ) + + DEFINE_SCRIPTFUNC_NAMED( ScriptGetLayerActivity, "GetLayerActivity", "Gets the activity name of the specified layer index." ) + DEFINE_SCRIPTFUNC_NAMED( ScriptGetLayerActivityID, "GetLayerActivityID", "Gets the activity index of the specified layer index." ) + DEFINE_SCRIPTFUNC( GetLayerSequence, "Gets the sequence index of the specified layer index." ) + DEFINE_SCRIPTFUNC( SetLayerDuration, "Sets the duration of the specified layer index." ) + DEFINE_SCRIPTFUNC( GetLayerDuration, "Gets the duration of the specified layer index." ) + DEFINE_SCRIPTFUNC_NAMED( ScriptSetLayerCycle, "SetLayerCycle", "Sets the cycle of the specified layer index." ) + DEFINE_SCRIPTFUNC( GetLayerCycle, "Gets the cycle of the specified layer index." ) + DEFINE_SCRIPTFUNC( SetLayerPlaybackRate, "Sets the playback rate of the specified layer index." ) + DEFINE_SCRIPTFUNC( SetLayerWeight, "Sets the weight of the specified layer index." ) + DEFINE_SCRIPTFUNC( GetLayerWeight, "Gets the weight of the specified layer index." ) + DEFINE_SCRIPTFUNC( SetLayerBlendIn, "Sets the fade-in of the specified layer index, with the fade being a 0-1 fraction of the cycle." ) + DEFINE_SCRIPTFUNC( SetLayerBlendOut, "Sets the fade-out of the specified layer index, with the fade being a 0-1 fraction of the cycle." ) + DEFINE_SCRIPTFUNC( SetLayerAutokill, "Sets whether or not the specified layer index should remove itself when it's finished playing." ) + DEFINE_SCRIPTFUNC( SetLayerLooping, "Sets whether or not the specified layer index should loop." ) + DEFINE_SCRIPTFUNC( SetLayerNoRestore, "Sets whether or not the specified layer index should restore after a save is loaded." ) + DEFINE_SCRIPTFUNC( SetLayerNoEvents, "Sets whether or not the specified layer index should fire animation events." ) + +END_SCRIPTDESC(); +#endif + #define ORDER_BITS 4 #define WEIGHT_BITS 8 @@ -354,7 +393,11 @@ void CBaseAnimatingOverlay::DispatchAnimEvents ( CBaseAnimating *eventHandler ) for ( int i = 0; i < m_AnimOverlay.Count(); i++ ) { +#ifdef MAPBASE // From Alien Swarm SDK + if (m_AnimOverlay[ i ].IsActive() && !m_AnimOverlay[ i ].NoEvents()) +#else if (m_AnimOverlay[ i ].IsActive()) +#endif { m_AnimOverlay[ i ].DispatchAnimEvents( eventHandler, this ); } @@ -1052,6 +1095,27 @@ void CBaseAnimatingOverlay::SetLayerNoRestore( int iLayer, bool bNoRestore ) } +#ifdef MAPBASE // From Alien Swarm SDK +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CBaseAnimatingOverlay::SetLayerNoEvents( int iLayer, bool bNoEvents ) +{ + if (!IsValidLayer( iLayer )) + return; + + if (bNoEvents) + { + m_AnimOverlay[iLayer].m_fFlags |= ANIM_LAYER_NOEVENTS; + } + else + { + m_AnimOverlay[iLayer].m_fFlags &= ~ANIM_LAYER_NOEVENTS; + } +} +#endif + + //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- @@ -1149,4 +1213,36 @@ bool CBaseAnimatingOverlay::HasActiveLayer( void ) return false; } +#ifdef MAPBASE_VSCRIPT +int CBaseAnimatingOverlay::ScriptAddGesture( const char *pszActivity, bool autokill ) +{ + return AddGesture( (Activity)CAI_BaseNPC::GetActivityID( pszActivity ), autokill ); +} + +int CBaseAnimatingOverlay::ScriptAddGestureID( int iActivity, bool autokill ) +{ + return AddGesture( (Activity)iActivity, autokill ); +} + +int CBaseAnimatingOverlay::ScriptFindGestureLayer( const char *pszActivity ) +{ + return FindGestureLayer( (Activity)CAI_BaseNPC::GetActivityID( pszActivity ) ); +} + +int CBaseAnimatingOverlay::ScriptFindGestureLayerByID( int iActivity ) +{ + return FindGestureLayer( (Activity)iActivity ); +} + +const char *CBaseAnimatingOverlay::ScriptGetLayerActivity( int iLayer ) +{ + return CAI_BaseNPC::GetActivityName( GetLayerActivity( iLayer ) ); +} + +int CBaseAnimatingOverlay::ScriptGetLayerActivityID( int iLayer ) +{ + return GetLayerActivity( iLayer ); +} +#endif + //----------------------------------------------------------------------------- diff --git a/sp/src/game/server/BaseAnimatingOverlay.h b/sp/src/game/server/BaseAnimatingOverlay.h index ac112cbd..d7b882f8 100644 --- a/sp/src/game/server/BaseAnimatingOverlay.h +++ b/sp/src/game/server/BaseAnimatingOverlay.h @@ -43,6 +43,9 @@ public: #define ANIM_LAYER_DONTRESTORE 0x0008 #define ANIM_LAYER_CHECKACCESS 0x0010 #define ANIM_LAYER_DYING 0x0020 +#ifdef MAPBASE // From Alien Swarm SDK +#define ANIM_LAYER_NOEVENTS 0x0040 +#endif int m_fFlags; @@ -80,6 +83,9 @@ public: void Dying( void ) { m_fFlags |= ANIM_LAYER_DYING; } bool IsDying( void ) { return ((m_fFlags & ANIM_LAYER_DYING) != 0); } void Dead( void ) { m_fFlags &= ~ANIM_LAYER_DYING; } +#ifdef MAPBASE // From Alien Swarm SDK + bool NoEvents( void ) { return ((m_fFlags & ANIM_LAYER_NOEVENTS) != 0); } +#endif bool IsAbandoned( void ); void MarkActive( void ); @@ -175,6 +181,9 @@ public: void SetLayerAutokill( int iLayer, bool bAutokill ); void SetLayerLooping( int iLayer, bool bLooping ); void SetLayerNoRestore( int iLayer, bool bNoRestore ); +#ifdef MAPBASE // From Alien Swarm SDK + void SetLayerNoEvents( int iLayer, bool bNoEvents ); +#endif Activity GetLayerActivity( int iLayer ); int GetLayerSequence( int iLayer ); @@ -195,9 +204,26 @@ public: private: int AllocateLayer( int iPriority = 0 ); // lower priorities are processed first +#ifdef MAPBASE_VSCRIPT + int ScriptAddGesture( const char *pszActivity, bool autokill ); + int ScriptAddGestureID( int iActivity, bool autokill ); + int ScriptAddGestureSequence( const char *pszSequence, bool autokill ) { return AddGestureSequence( LookupSequence( pszSequence ), autokill ); } + int ScriptAddGestureSequenceID( int iSequence, bool autokill ) { return AddGestureSequence( iSequence, autokill ); } + + int ScriptFindGestureLayer( const char *pszActivity ); + int ScriptFindGestureLayerByID( int iActivity ); + const char *ScriptGetLayerActivity( int iLayer ); + int ScriptGetLayerActivityID( int iLayer ); + + void ScriptSetLayerCycle( int iLayer, float flCycle ) { SetLayerCycle( iLayer, flCycle ); } +#endif + DECLARE_SERVERCLASS(); DECLARE_DATADESC(); DECLARE_PREDICTABLE(); +#ifdef MAPBASE_VSCRIPT + DECLARE_ENT_SCRIPTDESC(); +#endif }; EXTERN_SEND_TABLE(DT_BaseAnimatingOverlay); diff --git a/sp/src/game/server/ai_baseactor.cpp b/sp/src/game/server/ai_baseactor.cpp index 99f6b244..248c0841 100644 --- a/sp/src/game/server/ai_baseactor.cpp +++ b/sp/src/game/server/ai_baseactor.cpp @@ -101,8 +101,8 @@ END_DATADESC() #ifdef MAPBASE_VSCRIPT BEGIN_ENT_SCRIPTDESC( CAI_BaseActor, CAI_BaseNPC, "The base class for NPCs which act in complex choreo scenes." ) - DEFINE_SCRIPTFUNC_NAMED( ScriptAddLookTarget, "AddLookTarget", "Add a potential look target for this actor." ) - DEFINE_SCRIPTFUNC_NAMED( ScriptAddLookTargetPos, "AddLookTargetPos", "Add a potential look target position for this actor." ) + DEFINE_SCRIPTFUNC_NAMED( ScriptAddLookTarget, "AddLookTarget", "Add a potential look target for this actor with the specified importance, duration, and ramp." ) + DEFINE_SCRIPTFUNC_NAMED( ScriptAddLookTargetPos, "AddLookTargetPos", "Add a potential look target position for this actor with the specified importance, duration, and ramp." ) END_SCRIPTDESC(); #endif diff --git a/sp/src/game/server/baseflex.cpp b/sp/src/game/server/baseflex.cpp index 8da332cd..3c660a88 100644 --- a/sp/src/game/server/baseflex.cpp +++ b/sp/src/game/server/baseflex.cpp @@ -95,7 +95,11 @@ BEGIN_DATADESC( CBaseFlex ) END_DATADESC() +#ifdef MAPBASE_VSCRIPT +BEGIN_ENT_SCRIPTDESC( CBaseFlex, CBaseAnimatingOverlay, "Animated characters who have vertex flex capability." ) +#else BEGIN_ENT_SCRIPTDESC( CBaseFlex, CBaseAnimating, "Animated characters who have vertex flex capability." ) +#endif DEFINE_SCRIPTFUNC_NAMED( ScriptGetOldestScene, "GetCurrentScene", "Returns the instance of the oldest active scene entity (if any)." ) DEFINE_SCRIPTFUNC_NAMED( ScriptGetSceneByIndex, "GetSceneByIndex", "Returns the instance of the scene entity at the specified index." ) END_SCRIPTDESC(); From f63213afc31671492e57c80fc226184e86794381 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sun, 10 Oct 2021 19:49:47 -0500 Subject: [PATCH 178/378] Exposed npc_citizen to VScript and fixed SelectModel() arrangement oversights --- sp/src/game/server/hl2/npc_barney.cpp | 2 + sp/src/game/server/hl2/npc_citizen17.cpp | 76 +++++++++++++++++++ sp/src/game/server/hl2/npc_citizen17.h | 9 +++ sp/src/game/server/hl2/npc_fisherman.cpp | 4 +- .../game/server/hl2/npc_playercompanion.cpp | 7 ++ .../shared/mapbase/vscript_consts_shared.cpp | 4 + 6 files changed, 101 insertions(+), 1 deletion(-) diff --git a/sp/src/game/server/hl2/npc_barney.cpp b/sp/src/game/server/hl2/npc_barney.cpp index 93ca92f0..cfb80afc 100644 --- a/sp/src/game/server/hl2/npc_barney.cpp +++ b/sp/src/game/server/hl2/npc_barney.cpp @@ -51,8 +51,10 @@ public: virtual void Precache() { +#ifndef MAPBASE // This is now done in CNPC_PlayerCompanion::Precache() // Prevents a warning SelectModel( ); +#endif BaseClass::Precache(); PrecacheScriptSound( "NPC_Barney.FootstepLeft" ); diff --git a/sp/src/game/server/hl2/npc_citizen17.cpp b/sp/src/game/server/hl2/npc_citizen17.cpp index e0f39577..d14fc702 100644 --- a/sp/src/game/server/hl2/npc_citizen17.cpp +++ b/sp/src/game/server/hl2/npc_citizen17.cpp @@ -407,6 +407,27 @@ BEGIN_DATADESC( CNPC_Citizen ) END_DATADESC() +#ifdef MAPBASE_VSCRIPT +ScriptHook_t CNPC_Citizen::g_Hook_SelectModel; + +BEGIN_ENT_SCRIPTDESC( CNPC_Citizen, CAI_BaseActor, "npc_citizen from Half-Life 2" ) + + DEFINE_SCRIPTFUNC( IsMedic, "Returns true if this citizen is a medic." ) + DEFINE_SCRIPTFUNC( IsAmmoResupplier, "Returns true if this citizen is an ammo resupplier." ) + DEFINE_SCRIPTFUNC( CanHeal, "Returns true if this citizen is a medic or ammo resupplier currently able to heal/give ammo." ) + + DEFINE_SCRIPTFUNC( GetCitizenType, "Gets the citizen's type. 1 = Downtrodden, 2 = Refugee, 3 = Rebel, 4 = Unique" ) + DEFINE_SCRIPTFUNC( SetCitizenType, "Sets the citizen's type. 1 = Downtrodden, 2 = Refugee, 3 = Rebel, 4 = Unique" ) + + BEGIN_SCRIPTHOOK( CNPC_Citizen::g_Hook_SelectModel, "SelectModel", FIELD_CSTRING, "Called when a citizen is selecting a random model. 'model_path' is the directory of the selected model and 'model_head' is the name. The 'gender' parameter uses the 'GENDER_' constants and is based only on the citizen's random head spawnflags. If a full model path string is returned, it will be used as the model instead." ) + DEFINE_SCRIPTHOOK_PARAM( "model_path", FIELD_CSTRING ) + DEFINE_SCRIPTHOOK_PARAM( "model_head", FIELD_CSTRING ) + DEFINE_SCRIPTHOOK_PARAM( "gender", FIELD_INTEGER ) + END_SCRIPTHOOK() + +END_SCRIPTDESC(); +#endif + //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- @@ -431,7 +452,12 @@ bool CNPC_Citizen::CreateBehaviors() //----------------------------------------------------------------------------- void CNPC_Citizen::Precache() { +#ifdef MAPBASE + // CNPC_PlayerCompanion::Precache() is responsible for calling this now + BaseClass::Precache(); +#else SelectModel(); +#endif SelectExpressionType(); if ( !npc_citizen_dont_precache_all.GetBool() ) @@ -468,7 +494,9 @@ void CNPC_Citizen::Precache() } } +#ifndef MAPBASE // See above BaseClass::Precache(); +#endif } //----------------------------------------------------------------------------- @@ -769,6 +797,54 @@ void CNPC_Citizen::SelectModel() pszModelName = g_ppszRandomHeads[m_iHead]; SetModelName(NULL_STRING); } + +#ifdef MAPBASE_VSCRIPT + if (m_ScriptScope.IsInitialized() && g_Hook_SelectModel.CanRunInScope( m_ScriptScope )) + { + gender_t scriptGender; + switch (gender) + { + case 'm': + scriptGender = GENDER_MALE; + break; + case 'f': + scriptGender = GENDER_FEMALE; + break; + default: + scriptGender = GENDER_NONE; + break; + } + + const char *pszModelPath = CFmtStr( "models/Humans/%s/", (const char *)(CFmtStr( g_ppszModelLocs[m_Type], (IsMedic()) ? "m" : "" )) ); + + // model_path, model_head, gender + ScriptVariant_t args[] = { pszModelPath, pszModelName, (int)scriptGender }; + ScriptVariant_t returnValue = NULL; + g_Hook_SelectModel.Call( m_ScriptScope, &returnValue, args ); + + if (returnValue.m_type == FIELD_CSTRING && returnValue.m_pszString[0] != '\0') + { + // Refresh the head if it's different + const char *pszNewHead = strrchr( returnValue.m_pszString, '/' ); + if ( pszNewHead && Q_stricmp(pszNewHead+1, pszModelName) != 0 ) + { + pszNewHead++; + for ( int i = 0; i < ARRAYSIZE(g_ppszRandomHeads); i++ ) + { + if ( Q_stricmp( g_ppszRandomHeads[i], pszModelName ) == 0 ) + { + m_iHead = i; + break; + } + } + } + + // Just set the model right here + SetModelName( AllocPooledString( returnValue.m_pszString ) ); + return; + } + } +#endif } Assert( pszModelName || GetModelName() != NULL_STRING ); diff --git a/sp/src/game/server/hl2/npc_citizen17.h b/sp/src/game/server/hl2/npc_citizen17.h index 35f39a05..6828a664 100644 --- a/sp/src/game/server/hl2/npc_citizen17.h +++ b/sp/src/game/server/hl2/npc_citizen17.h @@ -277,6 +277,11 @@ public: virtual void OnChangeRunningBehavior( CAI_BehaviorBase *pOldBehavior, CAI_BehaviorBase *pNewBehavior ); +#ifdef MAPBASE + int GetCitizenType() { return (int)m_Type; } + void SetCitizenType( int iType ) { m_Type = (CitizenType_t)iType; } +#endif + private: //----------------------------------------------------- // Conditions, Schedules, Tasks @@ -382,6 +387,10 @@ private: //----------------------------------------------------- +#ifdef MAPBASE_VSCRIPT + static ScriptHook_t g_Hook_SelectModel; + DECLARE_ENT_SCRIPTDESC(); +#endif DECLARE_DATADESC(); #ifdef _XBOX protected: diff --git a/sp/src/game/server/hl2/npc_fisherman.cpp b/sp/src/game/server/hl2/npc_fisherman.cpp index 4530f261..967c5795 100644 --- a/sp/src/game/server/hl2/npc_fisherman.cpp +++ b/sp/src/game/server/hl2/npc_fisherman.cpp @@ -64,8 +64,10 @@ public: virtual void Precache() { +#ifndef MAPBASE // This is now done in CNPC_PlayerCompanion::Precache() // Prevents a warning - SelectModel( ); + SelectModel(); +#endif BaseClass::Precache(); PrecacheScriptSound( "NPC_Fisherman.FootstepLeft" ); diff --git a/sp/src/game/server/hl2/npc_playercompanion.cpp b/sp/src/game/server/hl2/npc_playercompanion.cpp index 6ee991e1..597f4c7f 100644 --- a/sp/src/game/server/hl2/npc_playercompanion.cpp +++ b/sp/src/game/server/hl2/npc_playercompanion.cpp @@ -234,6 +234,11 @@ void CNPC_PlayerCompanion::Precache() #endif #endif +#ifdef MAPBASE + // Moved from Spawn() + SelectModel(); +#endif + PrecacheModel( STRING( GetModelName() ) ); #ifdef HL2_EPISODIC @@ -252,7 +257,9 @@ void CNPC_PlayerCompanion::Precache() //----------------------------------------------------------------------------- void CNPC_PlayerCompanion::Spawn() { +#ifndef MAPBASE // Moved to Precache() SelectModel(); +#endif Precache(); diff --git a/sp/src/game/shared/mapbase/vscript_consts_shared.cpp b/sp/src/game/shared/mapbase/vscript_consts_shared.cpp index 54273d6a..0bcdd8ae 100644 --- a/sp/src/game/shared/mapbase/vscript_consts_shared.cpp +++ b/sp/src/game/shared/mapbase/vscript_consts_shared.cpp @@ -401,6 +401,10 @@ void RegisterSharedScriptConstants() ScriptRegisterConstant( g_pScriptVM, SND_IGNORE_NAME, "Used to change all sounds emitted by an entity, regardless of name." ); ScriptRegisterConstant( g_pScriptVM, SND_DO_NOT_OVERWRITE_EXISTING_ON_CHANNEL, "Prevents a sound from interrupting other sounds on a channel (if the channel supports interruption)." ); + ScriptRegisterConstant( g_pScriptVM, GENDER_NONE, "A standard value used to represent no specific gender. Usually used for sounds." ); + ScriptRegisterConstant( g_pScriptVM, GENDER_MALE, "A standard value used to represent male gender. Usually used for sounds." ); + ScriptRegisterConstant( g_pScriptVM, GENDER_FEMALE, "A standard value used to represent female gender. Usually used for sounds." ); + #ifdef GAME_DLL // // AI Sounds From 3431f21f4d6cb1bd73ecc95375273c9e2a27fad8 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sun, 10 Oct 2021 19:51:49 -0500 Subject: [PATCH 179/378] Misc. NPC fixes --- sp/src/game/server/ai_basenpc.cpp | 10 +--------- sp/src/game/server/ai_basenpc_schedule.cpp | 11 ++++++++++- sp/src/game/server/baseanimating.h | 2 ++ sp/src/game/server/basecombatweapon.cpp | 5 +++++ sp/src/game/server/hl2/npc_barnacle.cpp | 6 ++++++ sp/src/game/server/hl2/npc_metropolice.cpp | 5 +++++ sp/src/game/server/hl2/npc_vortigaunt_episodic.cpp | 7 +++++-- 7 files changed, 34 insertions(+), 12 deletions(-) diff --git a/sp/src/game/server/ai_basenpc.cpp b/sp/src/game/server/ai_basenpc.cpp index 513f6dc2..d2ec72bf 100644 --- a/sp/src/game/server/ai_basenpc.cpp +++ b/sp/src/game/server/ai_basenpc.cpp @@ -6618,15 +6618,7 @@ Activity CAI_BaseNPC::NPC_TranslateActivity( Activity eNewActivity ) { case ACT_RANGE_ATTACK1: eNewActivity = ACT_RANGE_ATTACK1_LOW; break; case ACT_RELOAD: eNewActivity = ACT_RELOAD_LOW; break; - case ACT_IDLE: eNewActivity = ACT_CROUCHIDLE; break; - - // ==== - // HACK : LEIPZIG 06 - The underlying problem is that the AR2 and SMG1 cannot map IDLE_ANGRY to a crouched equivalent automatically - // which causes the character to pop up and down in their idle state of firing while crouched. -- jdw - case ACT_IDLE_ANGRY_SMG1: - case ACT_IDLE_ANGRY_AR2: - eNewActivity = ACT_RANGE_AIM_LOW; - break; + case ACT_IDLE: eNewActivity = ACT_RANGE_AIM_LOW; break; // ACT_CROUCHIDLE is more-or-less deprecated and not friendly to weapon translation } } diff --git a/sp/src/game/server/ai_basenpc_schedule.cpp b/sp/src/game/server/ai_basenpc_schedule.cpp index 0d715bf4..cf425fd0 100644 --- a/sp/src/game/server/ai_basenpc_schedule.cpp +++ b/sp/src/game/server/ai_basenpc_schedule.cpp @@ -3015,7 +3015,16 @@ void CAI_BaseNPC::StartTask( const Task_t *pTask ) case TASK_ITEM_PICKUP: { - SetIdealActivity( ACT_PICKUP_GROUND ); +#ifdef MAPBASE + if (GetTarget() && fabs( GetTarget()->WorldSpaceCenter().z - GetAbsOrigin().z ) >= 12.0f) + { + SetIdealActivity( ACT_PICKUP_RACK ); + } + else +#endif + { + SetIdealActivity( ACT_PICKUP_GROUND ); + } } break; diff --git a/sp/src/game/server/baseanimating.h b/sp/src/game/server/baseanimating.h index b45f96b6..4fb3c47c 100644 --- a/sp/src/game/server/baseanimating.h +++ b/sp/src/game/server/baseanimating.h @@ -388,6 +388,8 @@ private: void InputSetCycle( inputdata_t &inputdata ); void InputSetPlaybackRate( inputdata_t &inputdata ); + +public: // From Alien Swarm SDK #endif bool CanSkipAnimation( void ); diff --git a/sp/src/game/server/basecombatweapon.cpp b/sp/src/game/server/basecombatweapon.cpp index 1135aa82..e49c1c1f 100644 --- a/sp/src/game/server/basecombatweapon.cpp +++ b/sp/src/game/server/basecombatweapon.cpp @@ -373,7 +373,12 @@ bool CBaseCombatWeapon::WeaponLOSCondition( const Vector &ownerPos, const Vector //----------------------------------------------------------------------------- int CBaseCombatWeapon::WeaponRangeAttack1Condition( float flDot, float flDist ) { +#ifdef MAPBASE + // HACKHACK: HasPrimaryAmmo() checks the NPC's reserve ammo counts, which should not be evaluated here if we use clips + if ( UsesPrimaryAmmo() && (UsesClipsForAmmo1() ? !m_iClip1 : !HasPrimaryAmmo()) ) +#else if ( UsesPrimaryAmmo() && !HasPrimaryAmmo() ) +#endif { return COND_NO_PRIMARY_AMMO; } diff --git a/sp/src/game/server/hl2/npc_barnacle.cpp b/sp/src/game/server/hl2/npc_barnacle.cpp index 2ffca3bc..d26f702a 100644 --- a/sp/src/game/server/hl2/npc_barnacle.cpp +++ b/sp/src/game/server/hl2/npc_barnacle.cpp @@ -689,6 +689,12 @@ bool CNPC_Barnacle::CanPickup( CBaseCombatCharacter *pBCC ) if( FClassnameIs( pBCC, "npc_turret_floor" ) ) return false; +#ifdef MAPBASE + // Don't pickup rollermines + if( FClassnameIs( pBCC, "npc_rollermine" ) ) + return false; +#endif + // Don't pick up a dead player or NPC if( !pBCC->IsAlive() ) return false; diff --git a/sp/src/game/server/hl2/npc_metropolice.cpp b/sp/src/game/server/hl2/npc_metropolice.cpp index cf94fdbf..b3b0e5d1 100644 --- a/sp/src/game/server/hl2/npc_metropolice.cpp +++ b/sp/src/game/server/hl2/npc_metropolice.cpp @@ -4945,7 +4945,12 @@ int CNPC_MetroPolice::SelectSchedule( void ) // This will cause the cops to run backwards + shoot at the same time if ( !bHighHealth && !HasBaton() ) { +#ifdef MAPBASE + // Don't do this with the 357 or any weapons which don't use clips + if ( GetActiveWeapon() && GetActiveWeapon()->UsesClipsForAmmo1() && GetActiveWeapon()->m_iClassname != gm_isz_class_357 && (GetActiveWeapon()->m_iClip1 <= 5) ) +#else if ( GetActiveWeapon() && (GetActiveWeapon()->m_iClip1 <= 5) ) +#endif { #ifdef METROPOLICE_USES_RESPONSE_SYSTEM SpeakIfAllowed( TLK_COP_LOWAMMO ); diff --git a/sp/src/game/server/hl2/npc_vortigaunt_episodic.cpp b/sp/src/game/server/hl2/npc_vortigaunt_episodic.cpp index 8dffd6db..7fdd89f2 100644 --- a/sp/src/game/server/hl2/npc_vortigaunt_episodic.cpp +++ b/sp/src/game/server/hl2/npc_vortigaunt_episodic.cpp @@ -582,8 +582,11 @@ bool CNPC_Vortigaunt::InnateWeaponLOSCondition( const Vector &ownerPos, const Ve UTIL_PredictedPosition( GetEnemy(), flTimeDelta, &vecNewTargetPos ); #ifdef MAPBASE - // This fix was created by DKY. - // His original comment is below. + // There's apparently a null pointer crash here + if (!GetEnemy()) + return false; + + // The fix below and its accompanying comment were created by DKY. /* From b9f3ac03fa7d2ef0bf30be0e00e4823b35b66d56 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sun, 10 Oct 2021 19:56:40 -0500 Subject: [PATCH 180/378] Redid the backup activity system so that individual weapons can choose which activity tables to fall back to --- sp/src/game/server/basecombatcharacter.cpp | 26 ++++++++--------- sp/src/game/server/hl2/weapon_357.cpp | 8 +++++ sp/src/game/server/hl2/weapon_alyxgun.h | 10 +++++++ sp/src/game/server/hl2/weapon_ar2.cpp | 4 --- sp/src/game/server/hl2/weapon_crowbar.h | 6 ++++ sp/src/game/server/hl2/weapon_pistol.cpp | 6 ++++ .../game/shared/basecombatweapon_shared.cpp | 29 +++++++++++++++++-- sp/src/game/shared/basecombatweapon_shared.h | 2 ++ sp/src/game/shared/hl2mp/weapon_stunstick.h | 6 ++++ 9 files changed, 77 insertions(+), 20 deletions(-) diff --git a/sp/src/game/server/basecombatcharacter.cpp b/sp/src/game/server/basecombatcharacter.cpp index 5f61ae37..c3927156 100644 --- a/sp/src/game/server/basecombatcharacter.cpp +++ b/sp/src/game/server/basecombatcharacter.cpp @@ -61,11 +61,6 @@ extern int g_interactionBarnacleVictimReleased; #endif //HL2_DLL -#ifdef MAPBASE -extern acttable_t *GetSMG1Acttable(); -extern int GetSMG1ActtableCount(); -#endif - extern ConVar weapon_showproficiency; ConVar ai_show_hull_attacks( "ai_show_hull_attacks", "0" ); @@ -2751,19 +2746,22 @@ Activity CBaseCombatCharacter::Weapon_BackupActivity( Activity activity, bool we return activity; } - acttable_t *pTable = GetSMG1Acttable(); - int actCount = GetSMG1ActtableCount(); - for ( int i = 0; i < actCount; i++, pTable++ ) + acttable_t *pTable = pWeapon->GetBackupActivityList(); + if (pTable) { - if ( activity == pTable->baseAct ) + int actCount = pWeapon->GetBackupActivityListCount(); + for ( int i = 0; i < actCount; i++, pTable++ ) { - // Don't pick SMG animations we don't actually have an animation for. - if (GetModelPtr() ? !GetModelPtr()->HaveSequenceForActivity(pTable->weaponAct) : false) + if ( activity == pTable->baseAct ) { - return activity; - } + // Don't pick SMG animations we don't actually have an animation for. + if (GetModelPtr() ? !GetModelPtr()->HaveSequenceForActivity(pTable->weaponAct) : false) + { + return activity; + } - return (Activity)pTable->weaponAct; + return (Activity)pTable->weaponAct; + } } } diff --git a/sp/src/game/server/hl2/weapon_357.cpp b/sp/src/game/server/hl2/weapon_357.cpp index 59237c84..b012811f 100644 --- a/sp/src/game/server/hl2/weapon_357.cpp +++ b/sp/src/game/server/hl2/weapon_357.cpp @@ -27,6 +27,11 @@ // CWeapon357 //----------------------------------------------------------------------------- +#ifdef MAPBASE +extern acttable_t *GetPistolActtable(); +extern int GetPistolActtableCount(); +#endif + class CWeapon357 : public CBaseHLCombatWeapon { DECLARE_CLASS( CWeapon357, CBaseHLCombatWeapon ); @@ -69,6 +74,9 @@ public: void FireNPCPrimaryAttack( CBaseCombatCharacter *pOperator, Vector &vecShootOrigin, Vector &vecShootDir ); void Operator_ForceNPCFire( CBaseCombatCharacter *pOperator, bool bSecondary ); + + virtual acttable_t *GetBackupActivityList() { return GetPistolActtable(); } + virtual int GetBackupActivityListCount() { return GetPistolActtableCount(); } #endif DECLARE_SERVERCLASS(); diff --git a/sp/src/game/server/hl2/weapon_alyxgun.h b/sp/src/game/server/hl2/weapon_alyxgun.h index cc3e862c..4dd95532 100644 --- a/sp/src/game/server/hl2/weapon_alyxgun.h +++ b/sp/src/game/server/hl2/weapon_alyxgun.h @@ -13,6 +13,11 @@ #pragma once #endif +#ifdef MAPBASE +extern acttable_t *GetPistolActtable(); +extern int GetPistolActtableCount(); +#endif + class CWeaponAlyxGun : public CHLSelectFireMachineGun { DECLARE_DATADESC(); @@ -51,6 +56,11 @@ public: SetTouch(NULL); } +#ifdef MAPBASE + virtual acttable_t *GetBackupActivityList() { return GetPistolActtable(); } + virtual int GetBackupActivityListCount() { return GetPistolActtableCount(); } +#endif + float m_flTooCloseTimer; DECLARE_ACTTABLE(); diff --git a/sp/src/game/server/hl2/weapon_ar2.cpp b/sp/src/game/server/hl2/weapon_ar2.cpp index 89a16700..dcd0009c 100644 --- a/sp/src/game/server/hl2/weapon_ar2.cpp +++ b/sp/src/game/server/hl2/weapon_ar2.cpp @@ -38,10 +38,6 @@ ConVar sk_weapon_ar2_alt_fire_radius( "sk_weapon_ar2_alt_fire_radius", "10" ); ConVar sk_weapon_ar2_alt_fire_duration( "sk_weapon_ar2_alt_fire_duration", "2" ); ConVar sk_weapon_ar2_alt_fire_mass( "sk_weapon_ar2_alt_fire_mass", "150" ); -#ifdef MAPBASE -extern acttable_t *GetSMG1Acttable(); -#endif - //========================================================= //========================================================= diff --git a/sp/src/game/server/hl2/weapon_crowbar.h b/sp/src/game/server/hl2/weapon_crowbar.h index 1890ef6e..26bb961f 100644 --- a/sp/src/game/server/hl2/weapon_crowbar.h +++ b/sp/src/game/server/hl2/weapon_crowbar.h @@ -46,6 +46,12 @@ public: // Animation event virtual void Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatCharacter *pOperator ); +#ifdef MAPBASE + // Don't use backup activities + acttable_t *GetBackupActivityList() { return NULL; } + int GetBackupActivityListCount() { return 0; } +#endif + private: // Animation event handlers void HandleAnimEventMeleeHit( animevent_t *pEvent, CBaseCombatCharacter *pOperator ); diff --git a/sp/src/game/server/hl2/weapon_pistol.cpp b/sp/src/game/server/hl2/weapon_pistol.cpp index 9a571bf5..da78654b 100644 --- a/sp/src/game/server/hl2/weapon_pistol.cpp +++ b/sp/src/game/server/hl2/weapon_pistol.cpp @@ -108,6 +108,12 @@ public: return 0.5f; } +#ifdef MAPBASE + // Pistols are their own backup activities + virtual acttable_t *GetBackupActivityList() { return NULL; } + virtual int GetBackupActivityListCount() { return 0; } +#endif + DECLARE_ACTTABLE(); private: diff --git a/sp/src/game/shared/basecombatweapon_shared.cpp b/sp/src/game/shared/basecombatweapon_shared.cpp index a48aa413..d807e559 100644 --- a/sp/src/game/shared/basecombatweapon_shared.cpp +++ b/sp/src/game/shared/basecombatweapon_shared.cpp @@ -1077,6 +1077,11 @@ WeaponClass_t CBaseCombatWeapon::WeaponClassFromString(const char *str) return WEPCLASS_INVALID; } +#ifdef HL2_DLL +extern acttable_t *GetSMG1Acttable(); +extern int GetSMG1ActtableCount(); +#endif + //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- @@ -1084,12 +1089,32 @@ bool CBaseCombatWeapon::SupportsBackupActivity(Activity activity) { // Derived classes should override this. - // Pistol and melee users should not use SMG animations for missing pistol activities. - if (WeaponClassify() == WEPCLASS_HANDGUN || IsMeleeWeapon()) +#ifdef HL2_DLL + // Melee users should not use SMG animations for missing activities. + if (IsMeleeWeapon() && GetBackupActivityList() == GetSMG1Acttable()) return false; +#endif return true; } + +acttable_t *CBaseCombatWeapon::GetBackupActivityList() +{ +#ifdef HL2_DLL + return GetSMG1Acttable(); +#else + return NULL; +#endif +} + +int CBaseCombatWeapon::GetBackupActivityListCount() +{ +#ifdef HL2_DLL + return GetSMG1ActtableCount(); +#else + return 0; +#endif +} #endif diff --git a/sp/src/game/shared/basecombatweapon_shared.h b/sp/src/game/shared/basecombatweapon_shared.h index b0a3e330..0f2fe433 100644 --- a/sp/src/game/shared/basecombatweapon_shared.h +++ b/sp/src/game/shared/basecombatweapon_shared.h @@ -230,6 +230,8 @@ public: static WeaponClass_t WeaponClassFromString(const char *str); virtual bool SupportsBackupActivity(Activity activity); + virtual acttable_t *GetBackupActivityList(); + virtual int GetBackupActivityListCount(); #endif virtual void Equip( CBaseCombatCharacter *pOwner ); diff --git a/sp/src/game/shared/hl2mp/weapon_stunstick.h b/sp/src/game/shared/hl2mp/weapon_stunstick.h index da25999c..93688915 100644 --- a/sp/src/game/shared/hl2mp/weapon_stunstick.h +++ b/sp/src/game/shared/hl2mp/weapon_stunstick.h @@ -83,6 +83,12 @@ public: float GetDamageForActivity( Activity hitActivity ); +#ifdef MAPBASE + // Don't use backup activities + acttable_t *GetBackupActivityList() { return NULL; } + int GetBackupActivityListCount() { return 0; } +#endif + CWeaponStunStick( const CWeaponStunStick & ); private: From 4cfa6dd22cea8ca07d82c927163d63b2a45e40d8 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sun, 10 Oct 2021 20:02:50 -0500 Subject: [PATCH 181/378] Revisited Mapbase's custom shared activities and expanded HL2 weapon activities --- sp/src/game/server/ai_activity.cpp | 56 ++++++++++++++- sp/src/game/shared/activitylist.cpp | 56 ++++++++++++++- sp/src/game/shared/ai_activity.h | 108 ++++++++++++++++++++-------- 3 files changed, 187 insertions(+), 33 deletions(-) diff --git a/sp/src/game/server/ai_activity.cpp b/sp/src/game/server/ai_activity.cpp index b88c1142..7e5f13f9 100644 --- a/sp/src/game/server/ai_activity.cpp +++ b/sp/src/game/server/ai_activity.cpp @@ -2180,7 +2180,7 @@ void CAI_BaseNPC::InitDefaultActivitySR(void) ADD_ACTIVITY_TO_SR( ACT_RUN_AIM_AR2 ); ADD_ACTIVITY_TO_SR( ACT_RELOAD_AR2 ); - //ADD_ACTIVITY_TO_SR( ACT_RELOAD_AR2_LOW ); + ADD_ACTIVITY_TO_SR( ACT_RELOAD_AR2_LOW ); ADD_ACTIVITY_TO_SR( ACT_GESTURE_RELOAD_AR2 ); #endif @@ -2189,6 +2189,11 @@ void CAI_BaseNPC::InitDefaultActivitySR(void) ADD_ACTIVITY_TO_SR( ACT_COMBINE_THROW_GRENADE ); ADD_ACTIVITY_TO_SR( ACT_COMBINE_AR2_ALTFIRE ); + ADD_ACTIVITY_TO_SR( ACT_GESTURE_COMBINE_THROW_GRENADE ); + ADD_ACTIVITY_TO_SR( ACT_GESTURE_COMBINE_AR2_ALTFIRE ); + ADD_ACTIVITY_TO_SR( ACT_GESTURE_SPECIAL_ATTACK1 ); + ADD_ACTIVITY_TO_SR( ACT_GESTURE_SPECIAL_ATTACK2 ); + ADD_ACTIVITY_TO_SR( ACT_GESTURE_SIGNAL_ADVANCE ); ADD_ACTIVITY_TO_SR( ACT_GESTURE_SIGNAL_FORWARD ); ADD_ACTIVITY_TO_SR( ACT_GESTURE_SIGNAL_GROUP ); @@ -2198,7 +2203,54 @@ void CAI_BaseNPC::InitDefaultActivitySR(void) ADD_ACTIVITY_TO_SR( ACT_GESTURE_SIGNAL_TAKECOVER ); #endif -#ifdef COMPANION_HOLSTER_WORKAROUND +#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES + ADD_ACTIVITY_TO_SR( ACT_IDLE_REVOLVER ); + ADD_ACTIVITY_TO_SR( ACT_IDLE_ANGRY_REVOLVER ); + ADD_ACTIVITY_TO_SR( ACT_WALK_REVOLVER ); + ADD_ACTIVITY_TO_SR( ACT_RUN_REVOLVER ); + ADD_ACTIVITY_TO_SR( ACT_WALK_AIM_REVOLVER ); + ADD_ACTIVITY_TO_SR( ACT_RUN_AIM_REVOLVER ); + ADD_ACTIVITY_TO_SR( ACT_RANGE_ATTACK_REVOLVER ); + ADD_ACTIVITY_TO_SR( ACT_RELOAD_REVOLVER ); + ADD_ACTIVITY_TO_SR( ACT_RANGE_ATTACK_REVOLVER_LOW ); + ADD_ACTIVITY_TO_SR( ACT_RELOAD_REVOLVER_LOW ); + ADD_ACTIVITY_TO_SR( ACT_COVER_REVOLVER_LOW ); + ADD_ACTIVITY_TO_SR( ACT_RANGE_AIM_REVOLVER_LOW ); + ADD_ACTIVITY_TO_SR( ACT_GESTURE_RANGE_ATTACK_REVOLVER ); + ADD_ACTIVITY_TO_SR( ACT_GESTURE_RELOAD_REVOLVER ); + + ADD_ACTIVITY_TO_SR( ACT_IDLE_CROSSBOW ); + ADD_ACTIVITY_TO_SR( ACT_IDLE_ANGRY_CROSSBOW ); + ADD_ACTIVITY_TO_SR( ACT_WALK_CROSSBOW ); + ADD_ACTIVITY_TO_SR( ACT_RUN_CROSSBOW ); + ADD_ACTIVITY_TO_SR( ACT_WALK_AIM_CROSSBOW ); + ADD_ACTIVITY_TO_SR( ACT_RUN_AIM_CROSSBOW ); + ADD_ACTIVITY_TO_SR( ACT_RANGE_ATTACK_CROSSBOW ); + ADD_ACTIVITY_TO_SR( ACT_RELOAD_CROSSBOW ); + ADD_ACTIVITY_TO_SR( ACT_RANGE_ATTACK_CROSSBOW_LOW ); + ADD_ACTIVITY_TO_SR( ACT_RELOAD_CROSSBOW_LOW ); + ADD_ACTIVITY_TO_SR( ACT_COVER_CROSSBOW_LOW ); + ADD_ACTIVITY_TO_SR( ACT_RANGE_AIM_CROSSBOW_LOW ); + ADD_ACTIVITY_TO_SR( ACT_GESTURE_RANGE_ATTACK_CROSSBOW ); + ADD_ACTIVITY_TO_SR( ACT_GESTURE_RELOAD_CROSSBOW ); + + ADD_ACTIVITY_TO_SR( ACT_IDLE_PISTOL_RELAXED ); + ADD_ACTIVITY_TO_SR( ACT_IDLE_PISTOL_STIMULATED ); + ADD_ACTIVITY_TO_SR( ACT_WALK_PISTOL_RELAXED ); + ADD_ACTIVITY_TO_SR( ACT_WALK_PISTOL_STIMULATED ); + ADD_ACTIVITY_TO_SR( ACT_RUN_PISTOL_RELAXED ); + ADD_ACTIVITY_TO_SR( ACT_RUN_PISTOL_STIMULATED ); + + ADD_ACTIVITY_TO_SR( ACT_IDLE_AIM_PISTOL_STIMULATED ); + ADD_ACTIVITY_TO_SR( ACT_WALK_AIM_PISTOL_STIMULATED ); + ADD_ACTIVITY_TO_SR( ACT_RUN_AIM_PISTOL_STIMULATED ); + + ADD_ACTIVITY_TO_SR( ACT_RANGE_AIM_RPG_LOW ); + ADD_ACTIVITY_TO_SR( ACT_RANGE_ATTACK_RPG_LOW ); + + ADD_ACTIVITY_TO_SR( ACT_RUN_PACKAGE ); + ADD_ACTIVITY_TO_SR( ACT_RUN_SUITCASE ); + ADD_ACTIVITY_TO_SR( ACT_ARM_RIFLE ); ADD_ACTIVITY_TO_SR( ACT_DISARM_RIFLE ); #endif diff --git a/sp/src/game/shared/activitylist.cpp b/sp/src/game/shared/activitylist.cpp index 9e986cb7..ede1485b 100644 --- a/sp/src/game/shared/activitylist.cpp +++ b/sp/src/game/shared/activitylist.cpp @@ -2296,7 +2296,7 @@ void ActivityList_RegisterSharedActivities( void ) REGISTER_SHARED_ACTIVITY( ACT_RUN_AIM_AR2 ); REGISTER_SHARED_ACTIVITY( ACT_RELOAD_AR2 ); - //REGISTER_SHARED_ACTIVITY( ACT_RELOAD_AR2_LOW ); + REGISTER_SHARED_ACTIVITY( ACT_RELOAD_AR2_LOW ); REGISTER_SHARED_ACTIVITY( ACT_GESTURE_RELOAD_AR2 ); #endif @@ -2305,6 +2305,11 @@ void ActivityList_RegisterSharedActivities( void ) REGISTER_SHARED_ACTIVITY( ACT_COMBINE_THROW_GRENADE ); REGISTER_SHARED_ACTIVITY( ACT_COMBINE_AR2_ALTFIRE ); + REGISTER_SHARED_ACTIVITY( ACT_GESTURE_COMBINE_THROW_GRENADE ); + REGISTER_SHARED_ACTIVITY( ACT_GESTURE_COMBINE_AR2_ALTFIRE ); + REGISTER_SHARED_ACTIVITY( ACT_GESTURE_SPECIAL_ATTACK1 ); + REGISTER_SHARED_ACTIVITY( ACT_GESTURE_SPECIAL_ATTACK2 ); + REGISTER_SHARED_ACTIVITY( ACT_GESTURE_SIGNAL_ADVANCE ); REGISTER_SHARED_ACTIVITY( ACT_GESTURE_SIGNAL_FORWARD ); REGISTER_SHARED_ACTIVITY( ACT_GESTURE_SIGNAL_GROUP ); @@ -2314,7 +2319,54 @@ void ActivityList_RegisterSharedActivities( void ) REGISTER_SHARED_ACTIVITY( ACT_GESTURE_SIGNAL_TAKECOVER ); #endif -#ifdef COMPANION_HOLSTER_WORKAROUND +#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES + REGISTER_SHARED_ACTIVITY( ACT_IDLE_REVOLVER ); + REGISTER_SHARED_ACTIVITY( ACT_IDLE_ANGRY_REVOLVER ); + REGISTER_SHARED_ACTIVITY( ACT_WALK_REVOLVER ); + REGISTER_SHARED_ACTIVITY( ACT_RUN_REVOLVER ); + REGISTER_SHARED_ACTIVITY( ACT_WALK_AIM_REVOLVER ); + REGISTER_SHARED_ACTIVITY( ACT_RUN_AIM_REVOLVER ); + REGISTER_SHARED_ACTIVITY( ACT_RANGE_ATTACK_REVOLVER ); + REGISTER_SHARED_ACTIVITY( ACT_RELOAD_REVOLVER ); + REGISTER_SHARED_ACTIVITY( ACT_RANGE_ATTACK_REVOLVER_LOW ); + REGISTER_SHARED_ACTIVITY( ACT_RELOAD_REVOLVER_LOW ); + REGISTER_SHARED_ACTIVITY( ACT_COVER_REVOLVER_LOW ); + REGISTER_SHARED_ACTIVITY( ACT_RANGE_AIM_REVOLVER_LOW ); + REGISTER_SHARED_ACTIVITY( ACT_GESTURE_RANGE_ATTACK_REVOLVER ); + REGISTER_SHARED_ACTIVITY( ACT_GESTURE_RELOAD_REVOLVER ); + + REGISTER_SHARED_ACTIVITY( ACT_IDLE_CROSSBOW ); + REGISTER_SHARED_ACTIVITY( ACT_IDLE_ANGRY_CROSSBOW ); + REGISTER_SHARED_ACTIVITY( ACT_WALK_CROSSBOW ); + REGISTER_SHARED_ACTIVITY( ACT_RUN_CROSSBOW ); + REGISTER_SHARED_ACTIVITY( ACT_WALK_AIM_CROSSBOW ); + REGISTER_SHARED_ACTIVITY( ACT_RUN_AIM_CROSSBOW ); + REGISTER_SHARED_ACTIVITY( ACT_RANGE_ATTACK_CROSSBOW ); + REGISTER_SHARED_ACTIVITY( ACT_RELOAD_CROSSBOW ); + REGISTER_SHARED_ACTIVITY( ACT_RANGE_ATTACK_CROSSBOW_LOW ); + REGISTER_SHARED_ACTIVITY( ACT_RELOAD_CROSSBOW_LOW ); + REGISTER_SHARED_ACTIVITY( ACT_COVER_CROSSBOW_LOW ); + REGISTER_SHARED_ACTIVITY( ACT_RANGE_AIM_CROSSBOW_LOW ); + REGISTER_SHARED_ACTIVITY( ACT_GESTURE_RANGE_ATTACK_CROSSBOW ); + REGISTER_SHARED_ACTIVITY( ACT_GESTURE_RELOAD_CROSSBOW ); + + REGISTER_SHARED_ACTIVITY( ACT_IDLE_PISTOL_RELAXED ); + REGISTER_SHARED_ACTIVITY( ACT_IDLE_PISTOL_STIMULATED ); + REGISTER_SHARED_ACTIVITY( ACT_WALK_PISTOL_RELAXED ); + REGISTER_SHARED_ACTIVITY( ACT_WALK_PISTOL_STIMULATED ); + REGISTER_SHARED_ACTIVITY( ACT_RUN_PISTOL_RELAXED ); + REGISTER_SHARED_ACTIVITY( ACT_RUN_PISTOL_STIMULATED ); + + REGISTER_SHARED_ACTIVITY( ACT_IDLE_AIM_PISTOL_STIMULATED ); + REGISTER_SHARED_ACTIVITY( ACT_WALK_AIM_PISTOL_STIMULATED ); + REGISTER_SHARED_ACTIVITY( ACT_RUN_AIM_PISTOL_STIMULATED ); + + REGISTER_SHARED_ACTIVITY( ACT_RANGE_AIM_RPG_LOW ); + REGISTER_SHARED_ACTIVITY( ACT_RANGE_ATTACK_RPG_LOW ); + + REGISTER_SHARED_ACTIVITY( ACT_RUN_PACKAGE ); + REGISTER_SHARED_ACTIVITY( ACT_RUN_SUITCASE ); + REGISTER_SHARED_ACTIVITY( ACT_ARM_RIFLE ); REGISTER_SHARED_ACTIVITY( ACT_DISARM_RIFLE ); #endif diff --git a/sp/src/game/shared/ai_activity.h b/sp/src/game/shared/ai_activity.h index 44b8f62d..bfe3eb05 100644 --- a/sp/src/game/shared/ai_activity.h +++ b/sp/src/game/shared/ai_activity.h @@ -13,42 +13,34 @@ #ifdef MAPBASE -// Mapbase adds a few shared activities. // -// These used to be placed in between existing activities, as outside of the code activities are based off of strings. -// This seemed like a bad idea, but no problems arose at the time. -// I later discovered that apparently some things in MP use the direct integers instead of the enum names. -// I retroactively put all custom activities at the bottom of the enum instead. -// Their placements in activitylist.cpp and ai_activity.cpp have not been changed. +// Mapbase adds many new shared activities, primarily for NPCs. +// +// These are at the bottom of the enum to prevent disruptions in the order of existing activities. +// // AR2 ACTIVITY FIX -// You know all of those AR2 activities that citizens and combine soldiers have? -// Yeah, those are unused. It appears Valve forgot to implement them. +// Citizens and Combine soldiers have several activities for the SMG1 and AR2 which differ from each other. +// Across both NPCs, there are around 20-40 different AR2 animations. Most of these animations are similar to the +// SMG1 animations, except their hand positions are adjusted to use the AR2 instead. // -// What could be 20-40 different animations on two different characters are not even defined in code. -// I didn't even realize they were unused until I saw ACT_RELOAD_AR2, so I don't blame them for never realizing this. -// They work surprisingly well for probably never being tested in-game. +// Unfortunately, the vast majority of the AR2 animations in those models are not declared as real activities in +// code. The AR2 instead falls back to its SMG1 animation counterparts. +// This is thought to be an oversight which dates back to late in Half-Life 2's development. // -// 1 = Add activities directly -// 2 = Add activities as custom activities (todo) -// -// 2 should only be preferable if adding them like this breaks something. +// This preprocessor declares those activities and implements them on the AR2. In-game, they work surprisingly well +// despite presumably never being tested in-game during HL2's development. #define AR2_ACTIVITY_FIX 1 -// COMPANION HOLSTER WORKAROUND -// I introduced a separate holster/unholster animation to male_shared -// and female_shared and I realized it might conflict with Alyx's animation. -// -// I came up with a solution--ACT_ARM_RIFLE and its disarm counterpart--to solve it. -// I didn't think about the fact I could've named them the same as Alyx's so her animations would overwrite it... -// ...so this has been deactivated. -//#define COMPANION_HOLSTER_WORKAROUND 1 - // SHARED COMBINE ACTIVITIES -// This turns ACT_COMBINE_AR2_ALTFIRE and ACT_COMBINE_THROW_GRENADE into shared activities. -// This is necessary so other NPCs to use them without having to rely on a bunch of custom activities. +// This turns ACT_COMBINE_AR2_ALTFIRE, ACT_COMBINE_THROW_GRENADE, and their new gesture counterparts into shared activities. +// This is necessary for other NPCs to use them without having to rely on private custom activities declared through the AI definition system. #define SHARED_COMBINE_ACTIVITIES 1 +// EXPANDED HL2 WEAPON ACTIVITIES +// This enables a bunch of new activities for Half-Life 2 weapons, including new 357 animations and readiness activities for pistols. +#define EXPANDED_HL2_WEAPON_ACTIVITIES 1 + #endif #define ACTIVITY_NOT_AVAILABLE -1 @@ -2169,7 +2161,7 @@ typedef enum ACT_RUN_AIM_AR2, ACT_RELOAD_AR2, - //ACT_RELOAD_AR2_LOW, + ACT_RELOAD_AR2_LOW, ACT_GESTURE_RELOAD_AR2, #endif @@ -2178,7 +2170,12 @@ typedef enum ACT_COMBINE_THROW_GRENADE, ACT_COMBINE_AR2_ALTFIRE, - // New gesture-based signals as activities for people who want to use them + // Gesture versions for existing Combine signal and grenade activities + ACT_GESTURE_COMBINE_THROW_GRENADE, + ACT_GESTURE_COMBINE_AR2_ALTFIRE, + ACT_GESTURE_SPECIAL_ATTACK1, + ACT_GESTURE_SPECIAL_ATTACK2, + ACT_GESTURE_SIGNAL_ADVANCE, ACT_GESTURE_SIGNAL_FORWARD, ACT_GESTURE_SIGNAL_GROUP, @@ -2188,7 +2185,60 @@ typedef enum ACT_GESTURE_SIGNAL_TAKECOVER, #endif -#ifdef COMPANION_HOLSTER_WORKAROUND +#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES + // Revolver (357) + ACT_IDLE_REVOLVER, + ACT_IDLE_ANGRY_REVOLVER, + ACT_WALK_REVOLVER, + ACT_RUN_REVOLVER, + ACT_WALK_AIM_REVOLVER, + ACT_RUN_AIM_REVOLVER, + ACT_RANGE_ATTACK_REVOLVER, + ACT_RELOAD_REVOLVER, + ACT_RANGE_ATTACK_REVOLVER_LOW, + ACT_RELOAD_REVOLVER_LOW, + ACT_COVER_REVOLVER_LOW, + ACT_RANGE_AIM_REVOLVER_LOW, + ACT_GESTURE_RANGE_ATTACK_REVOLVER, + ACT_GESTURE_RELOAD_REVOLVER, + + // Crossbow + ACT_IDLE_CROSSBOW, + ACT_IDLE_ANGRY_CROSSBOW, + ACT_WALK_CROSSBOW, + ACT_RUN_CROSSBOW, + ACT_WALK_AIM_CROSSBOW, + ACT_RUN_AIM_CROSSBOW, + ACT_RANGE_ATTACK_CROSSBOW, + ACT_RELOAD_CROSSBOW, + ACT_RANGE_ATTACK_CROSSBOW_LOW, + ACT_RELOAD_CROSSBOW_LOW, + ACT_COVER_CROSSBOW_LOW, + ACT_RANGE_AIM_CROSSBOW_LOW, + ACT_GESTURE_RANGE_ATTACK_CROSSBOW, + ACT_GESTURE_RELOAD_CROSSBOW, + + // Pistol + ACT_IDLE_PISTOL_RELAXED, + ACT_IDLE_PISTOL_STIMULATED, + ACT_WALK_PISTOL_RELAXED, + ACT_WALK_PISTOL_STIMULATED, + ACT_RUN_PISTOL_RELAXED, + ACT_RUN_PISTOL_STIMULATED, + + ACT_IDLE_AIM_PISTOL_STIMULATED, + ACT_WALK_AIM_PISTOL_STIMULATED, + ACT_RUN_AIM_PISTOL_STIMULATED, + + // RPG + ACT_RANGE_AIM_RPG_LOW, + ACT_RANGE_ATTACK_RPG_LOW, + + // Citizen accessories + ACT_RUN_PACKAGE, + ACT_RUN_SUITCASE, + + // Holster/Unholster ACT_ARM_RIFLE, ACT_DISARM_RIFLE, #endif From 6490e8925635ceddc568d624c569330cd38b403e Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sun, 10 Oct 2021 20:06:30 -0500 Subject: [PATCH 182/378] Implemented new pistol, 357, and crossbow activities --- sp/src/game/server/hl2/npc_alyx_episodic.cpp | 79 +++++++++++++++++++ sp/src/game/server/hl2/npc_alyx_episodic.h | 4 + sp/src/game/server/hl2/npc_citizen17.cpp | 7 ++ sp/src/game/server/hl2/npc_combine.cpp | 7 ++ sp/src/game/server/hl2/weapon_357.cpp | 34 +++++++- sp/src/game/server/hl2/weapon_alyxgun.cpp | 17 +++- sp/src/game/server/hl2/weapon_crossbow.cpp | 26 ++++++ sp/src/game/server/hl2/weapon_pistol.cpp | 48 +++++++++++ .../game/shared/basecombatweapon_shared.cpp | 6 ++ 9 files changed, 226 insertions(+), 2 deletions(-) diff --git a/sp/src/game/server/hl2/npc_alyx_episodic.cpp b/sp/src/game/server/hl2/npc_alyx_episodic.cpp index 42c2eb3f..cdeb8f6b 100644 --- a/sp/src/game/server/hl2/npc_alyx_episodic.cpp +++ b/sp/src/game/server/hl2/npc_alyx_episodic.cpp @@ -1687,9 +1687,88 @@ Activity CNPC_Alyx::NPC_TranslateActivity( Activity activity ) case ACT_DROP_WEAPON: if ( HasShotgun() ) return (Activity)ACT_DROP_WEAPON_SHOTGUN; } +#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES + // Alyx has her own pistol readiness animations which use the default activities + switch (activity) + { + case ACT_IDLE_PISTOL_RELAXED: + return ACT_IDLE_RELAXED; + case ACT_IDLE_PISTOL_STIMULATED: + return ACT_IDLE_STIMULATED; + case ACT_WALK_PISTOL_RELAXED: + return ACT_WALK; + case ACT_WALK_PISTOL_STIMULATED: + return ACT_WALK_PISTOL; + case ACT_RUN_PISTOL_RELAXED: + return ACT_RUN; + case ACT_RUN_PISTOL_STIMULATED: + return ACT_RUN_PISTOL; + } +#endif + return activity; } +#ifdef MAPBASE +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +Activity CNPC_Alyx::Weapon_TranslateActivity( Activity activity, bool *pRequired ) +{ + activity = BaseClass::Weapon_TranslateActivity( activity, pRequired ); + +#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES + // Alyx has her own pistol readiness animations which use the default activities + switch (activity) + { + case ACT_IDLE_PISTOL_RELAXED: + return ACT_IDLE_RELAXED; + case ACT_IDLE_PISTOL_STIMULATED: + return ACT_IDLE_STIMULATED; + case ACT_WALK_PISTOL_RELAXED: + return ACT_WALK; + case ACT_WALK_PISTOL_STIMULATED: + return ACT_WALK_PISTOL; + case ACT_RUN_PISTOL_RELAXED: + return ACT_RUN; + case ACT_RUN_PISTOL_STIMULATED: + return ACT_RUN_PISTOL; + } +#endif + + return activity; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +Activity CNPC_Alyx::Weapon_BackupActivity( Activity activity, bool weaponTranslationWasRequired, CBaseCombatWeapon *pSpecificWeapon ) +{ + activity = BaseClass::Weapon_BackupActivity( activity, weaponTranslationWasRequired, pSpecificWeapon ); + +#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES + // Alyx has her own pistol readiness animations which use the default activities + switch (activity) + { + case ACT_IDLE_PISTOL_RELAXED: + return ACT_IDLE_RELAXED; + case ACT_IDLE_PISTOL_STIMULATED: + return ACT_IDLE_STIMULATED; + case ACT_WALK_PISTOL_RELAXED: + return ACT_WALK; + case ACT_WALK_PISTOL_STIMULATED: + return ACT_WALK_PISTOL; + case ACT_RUN_PISTOL_RELAXED: + return ACT_RUN; + case ACT_RUN_PISTOL_STIMULATED: + return ACT_RUN_PISTOL; + } +#endif + + return activity; +} +#endif + bool CNPC_Alyx::ShouldDeferToFollowBehavior() { return BaseClass::ShouldDeferToFollowBehavior(); diff --git a/sp/src/game/server/hl2/npc_alyx_episodic.h b/sp/src/game/server/hl2/npc_alyx_episodic.h index 6d4eb67b..2f95099b 100644 --- a/sp/src/game/server/hl2/npc_alyx_episodic.h +++ b/sp/src/game/server/hl2/npc_alyx_episodic.h @@ -91,6 +91,10 @@ public: bool CanSeeEntityInDarkness( CBaseEntity *pEntity ); bool IsCoverPosition( const Vector &vecThreat, const Vector &vecPosition ); Activity NPC_TranslateActivity ( Activity activity ); +#ifdef MAPBASE + Activity Weapon_TranslateActivity( Activity baseAct, bool *pRequired = NULL ); + Activity Weapon_BackupActivity( Activity activity, bool weaponTranslationWasRequired = false, CBaseCombatWeapon *pSpecificWeapon = NULL ); +#endif bool ShouldDeferToFollowBehavior(); void BuildScheduleTestBits(); bool ShouldBehaviorSelectSchedule( CAI_BehaviorBase *pBehavior ); diff --git a/sp/src/game/server/hl2/npc_citizen17.cpp b/sp/src/game/server/hl2/npc_citizen17.cpp index d14fc702..62cd9ab2 100644 --- a/sp/src/game/server/hl2/npc_citizen17.cpp +++ b/sp/src/game/server/hl2/npc_citizen17.cpp @@ -2085,6 +2085,13 @@ Activity CNPC_Citizen::NPC_TranslateActivity( Activity activity ) return ACT_RUN_AIM_AR2_STIMULATED; if (activity == ACT_WALK_AIM_AR2) return ACT_WALK_AIM_AR2_STIMULATED; + +#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES + if (activity == ACT_RUN_AIM_PISTOL) + return ACT_RUN_AIM_PISTOL_STIMULATED; + if (activity == ACT_WALK_AIM_PISTOL) + return ACT_WALK_AIM_PISTOL_STIMULATED; +#endif } #endif diff --git a/sp/src/game/server/hl2/npc_combine.cpp b/sp/src/game/server/hl2/npc_combine.cpp index 3076347d..3a643ff7 100644 --- a/sp/src/game/server/hl2/npc_combine.cpp +++ b/sp/src/game/server/hl2/npc_combine.cpp @@ -3791,6 +3791,13 @@ WeaponProficiency_t CNPC_Combine::CalcWeaponProficiency( CBaseCombatWeapon *pWea { return WEAPON_PROFICIENCY_GOOD; } +#ifdef MAPBASE + else if ( pWeapon->ClassMatches( gm_isz_class_Pistol ) ) + { + // Mods which need a lower soldier pistol accuracy can either change this value or use proficiency override in Hammer. + return WEAPON_PROFICIENCY_VERY_GOOD; + } +#endif return BaseClass::CalcWeaponProficiency( pWeapon ); } diff --git a/sp/src/game/server/hl2/weapon_357.cpp b/sp/src/game/server/hl2/weapon_357.cpp index b012811f..dc8e4483 100644 --- a/sp/src/game/server/hl2/weapon_357.cpp +++ b/sp/src/game/server/hl2/weapon_357.cpp @@ -99,6 +99,22 @@ END_DATADESC() #ifdef MAPBASE acttable_t CWeapon357::m_acttable[] = { +#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES + { ACT_IDLE, ACT_IDLE_REVOLVER, true }, + { ACT_IDLE_ANGRY, ACT_IDLE_ANGRY_REVOLVER, true }, + { ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_REVOLVER, true }, + { ACT_RELOAD, ACT_RELOAD_REVOLVER, true }, + { ACT_WALK_AIM, ACT_WALK_AIM_REVOLVER, true }, + { ACT_RUN_AIM, ACT_RUN_AIM_REVOLVER, true }, + { ACT_GESTURE_RANGE_ATTACK1, ACT_GESTURE_RANGE_ATTACK_REVOLVER, true }, + { ACT_RELOAD_LOW, ACT_RELOAD_REVOLVER_LOW, false }, + { ACT_RANGE_ATTACK1_LOW, ACT_RANGE_ATTACK_REVOLVER_LOW, false }, + { ACT_COVER_LOW, ACT_COVER_REVOLVER_LOW, false }, + { ACT_RANGE_AIM_LOW, ACT_RANGE_AIM_REVOLVER_LOW, false }, + { ACT_GESTURE_RELOAD, ACT_GESTURE_RELOAD_REVOLVER, false }, + { ACT_WALK, ACT_WALK_REVOLVER, true }, + { ACT_RUN, ACT_RUN_REVOLVER, true }, +#else { ACT_IDLE, ACT_IDLE_PISTOL, true }, { ACT_IDLE_ANGRY, ACT_IDLE_ANGRY_PISTOL, true }, { ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_PISTOL, true }, @@ -113,24 +129,40 @@ acttable_t CWeapon357::m_acttable[] = { ACT_GESTURE_RELOAD, ACT_GESTURE_RELOAD_PISTOL, false }, { ACT_WALK, ACT_WALK_PISTOL, false }, { ACT_RUN, ACT_RUN_PISTOL, false }, +#endif // // Activities ported from weapon_alyxgun below // // Readiness activities (not aiming) +#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES + { ACT_IDLE_RELAXED, ACT_IDLE_PISTOL_RELAXED, false },//never aims + { ACT_IDLE_STIMULATED, ACT_IDLE_PISTOL_STIMULATED, false }, +#else { ACT_IDLE_RELAXED, ACT_IDLE_PISTOL, false },//never aims { ACT_IDLE_STIMULATED, ACT_IDLE_STIMULATED, false }, +#endif { ACT_IDLE_AGITATED, ACT_IDLE_ANGRY_PISTOL, false },//always aims { ACT_IDLE_STEALTH, ACT_IDLE_STEALTH_PISTOL, false }, +#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES + { ACT_WALK_RELAXED, ACT_WALK_PISTOL_RELAXED, false },//never aims + { ACT_WALK_STIMULATED, ACT_WALK_PISTOL_STIMULATED, false }, +#else { ACT_WALK_RELAXED, ACT_WALK, false },//never aims { ACT_WALK_STIMULATED, ACT_WALK_STIMULATED, false }, +#endif { ACT_WALK_AGITATED, ACT_WALK_AIM_PISTOL, false },//always aims { ACT_WALK_STEALTH, ACT_WALK_STEALTH_PISTOL, false }, - + +#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES + { ACT_RUN_RELAXED, ACT_RUN_PISTOL_RELAXED, false },//never aims + { ACT_RUN_STIMULATED, ACT_RUN_PISTOL_STIMULATED, false }, +#else { ACT_RUN_RELAXED, ACT_RUN, false },//never aims { ACT_RUN_STIMULATED, ACT_RUN_STIMULATED, false }, +#endif { ACT_RUN_AGITATED, ACT_RUN_AIM_PISTOL, false },//always aims { ACT_RUN_STEALTH, ACT_RUN_STEALTH_PISTOL, false }, diff --git a/sp/src/game/server/hl2/weapon_alyxgun.cpp b/sp/src/game/server/hl2/weapon_alyxgun.cpp index 9c093be6..538f6312 100644 --- a/sp/src/game/server/hl2/weapon_alyxgun.cpp +++ b/sp/src/game/server/hl2/weapon_alyxgun.cpp @@ -44,18 +44,33 @@ acttable_t CWeaponAlyxGun::m_acttable[] = #endif // Readiness activities (not aiming) +#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES + { ACT_IDLE_RELAXED, ACT_IDLE_PISTOL_RELAXED, false },//never aims + { ACT_IDLE_STIMULATED, ACT_IDLE_PISTOL_STIMULATED, false }, +#else { ACT_IDLE_RELAXED, ACT_IDLE_PISTOL, false },//never aims { ACT_IDLE_STIMULATED, ACT_IDLE_STIMULATED, false }, +#endif { ACT_IDLE_AGITATED, ACT_IDLE_ANGRY_PISTOL, false },//always aims { ACT_IDLE_STEALTH, ACT_IDLE_STEALTH_PISTOL, false }, +#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES + { ACT_WALK_RELAXED, ACT_WALK_PISTOL_RELAXED, false },//never aims + { ACT_WALK_STIMULATED, ACT_WALK_PISTOL_STIMULATED, false }, +#else { ACT_WALK_RELAXED, ACT_WALK, false },//never aims { ACT_WALK_STIMULATED, ACT_WALK_STIMULATED, false }, +#endif { ACT_WALK_AGITATED, ACT_WALK_AIM_PISTOL, false },//always aims { ACT_WALK_STEALTH, ACT_WALK_STEALTH_PISTOL, false }, - + +#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES + { ACT_RUN_RELAXED, ACT_RUN_PISTOL_RELAXED, false },//never aims + { ACT_RUN_STIMULATED, ACT_RUN_PISTOL_STIMULATED, false }, +#else { ACT_RUN_RELAXED, ACT_RUN, false },//never aims { ACT_RUN_STIMULATED, ACT_RUN_STIMULATED, false }, +#endif { ACT_RUN_AGITATED, ACT_RUN_AIM_PISTOL, false },//always aims { ACT_RUN_STEALTH, ACT_RUN_STEALTH_PISTOL, false }, diff --git a/sp/src/game/server/hl2/weapon_crossbow.cpp b/sp/src/game/server/hl2/weapon_crossbow.cpp index b86b4c05..eb492e97 100644 --- a/sp/src/game/server/hl2/weapon_crossbow.cpp +++ b/sp/src/game/server/hl2/weapon_crossbow.cpp @@ -638,6 +638,15 @@ END_DATADESC() #ifdef MAPBASE acttable_t CWeaponCrossbow::m_acttable[] = { +#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES + { ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_CROSSBOW, true }, + { ACT_RELOAD, ACT_RELOAD_CROSSBOW, true }, + { ACT_IDLE, ACT_IDLE_CROSSBOW, true }, + { ACT_IDLE_ANGRY, ACT_IDLE_ANGRY_CROSSBOW, true }, + + { ACT_WALK, ACT_WALK_CROSSBOW, true }, + { ACT_WALK_AIM, ACT_WALK_AIM_CROSSBOW, true }, +#else { ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_SMG1, true }, { ACT_RELOAD, ACT_RELOAD_SMG1, true }, { ACT_IDLE, ACT_IDLE_SMG1, true }, @@ -645,6 +654,7 @@ acttable_t CWeaponCrossbow::m_acttable[] = { ACT_WALK, ACT_WALK_RIFLE, true }, { ACT_WALK_AIM, ACT_WALK_AIM_RIFLE, true }, +#endif // Readiness activities (not aiming) { ACT_IDLE_RELAXED, ACT_IDLE_SMG1_RELAXED, false },//never aims @@ -673,6 +683,21 @@ acttable_t CWeaponCrossbow::m_acttable[] = { ACT_RUN_AIM_AGITATED, ACT_RUN_AIM_RIFLE, false },//always aims //End readiness activities +#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES + { ACT_WALK_AIM, ACT_WALK_AIM_CROSSBOW, true }, + { ACT_WALK_CROUCH, ACT_WALK_CROUCH_RIFLE, true }, + { ACT_WALK_CROUCH_AIM, ACT_WALK_CROUCH_AIM_RIFLE, true }, + { ACT_RUN, ACT_RUN_CROSSBOW, true }, + { ACT_RUN_AIM, ACT_RUN_AIM_CROSSBOW, true }, + { ACT_RUN_CROUCH, ACT_RUN_CROUCH_RIFLE, true }, + { ACT_RUN_CROUCH_AIM, ACT_RUN_CROUCH_AIM_RIFLE, true }, + { ACT_GESTURE_RANGE_ATTACK1, ACT_GESTURE_RANGE_ATTACK_CROSSBOW, true }, + { ACT_RANGE_ATTACK1_LOW, ACT_RANGE_ATTACK_CROSSBOW_LOW, true }, + { ACT_COVER_LOW, ACT_COVER_CROSSBOW_LOW, false }, + { ACT_RANGE_AIM_LOW, ACT_RANGE_AIM_CROSSBOW_LOW, false }, + { ACT_RELOAD_LOW, ACT_RELOAD_CROSSBOW_LOW, false }, + { ACT_GESTURE_RELOAD, ACT_GESTURE_RELOAD_CROSSBOW, true }, +#else { ACT_WALK_AIM, ACT_WALK_AIM_RIFLE, true }, { ACT_WALK_CROUCH, ACT_WALK_CROUCH_RIFLE, true }, { ACT_WALK_CROUCH_AIM, ACT_WALK_CROUCH_AIM_RIFLE, true }, @@ -686,6 +711,7 @@ acttable_t CWeaponCrossbow::m_acttable[] = { ACT_RANGE_AIM_LOW, ACT_RANGE_AIM_SMG1_LOW, false }, { ACT_RELOAD_LOW, ACT_RELOAD_SMG1_LOW, false }, { ACT_GESTURE_RELOAD, ACT_GESTURE_RELOAD_SMG1, true }, +#endif }; IMPLEMENT_ACTTABLE(CWeaponCrossbow); diff --git a/sp/src/game/server/hl2/weapon_pistol.cpp b/sp/src/game/server/hl2/weapon_pistol.cpp index da78654b..417d1ee5 100644 --- a/sp/src/game/server/hl2/weapon_pistol.cpp +++ b/sp/src/game/server/hl2/weapon_pistol.cpp @@ -161,6 +161,40 @@ acttable_t CWeaponPistol::m_acttable[] = // Activities ported from weapon_alyxgun below // +#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES + // Readiness activities (not aiming) + { ACT_IDLE_RELAXED, ACT_IDLE_PISTOL_RELAXED, false },//never aims + { ACT_IDLE_STIMULATED, ACT_IDLE_PISTOL_STIMULATED, false }, + { ACT_IDLE_AGITATED, ACT_IDLE_ANGRY_PISTOL, false },//always aims + { ACT_IDLE_STEALTH, ACT_IDLE_STEALTH_PISTOL, false }, + + { ACT_WALK_RELAXED, ACT_WALK_PISTOL_RELAXED, false },//never aims + { ACT_WALK_STIMULATED, ACT_WALK_PISTOL_STIMULATED, false }, + { ACT_WALK_AGITATED, ACT_WALK_AIM_PISTOL, false },//always aims + { ACT_WALK_STEALTH, ACT_WALK_STEALTH_PISTOL, false }, + + { ACT_RUN_RELAXED, ACT_RUN_PISTOL_RELAXED, false },//never aims + { ACT_RUN_STIMULATED, ACT_RUN_PISTOL_STIMULATED, false }, + { ACT_RUN_AGITATED, ACT_RUN_AIM_PISTOL, false },//always aims + { ACT_RUN_STEALTH, ACT_RUN_STEALTH_PISTOL, false }, + + // Readiness activities (aiming) + { ACT_IDLE_AIM_RELAXED, ACT_IDLE_PISTOL_RELAXED, false },//never aims + { ACT_IDLE_AIM_STIMULATED, ACT_IDLE_AIM_PISTOL_STIMULATED, false }, + { ACT_IDLE_AIM_AGITATED, ACT_IDLE_ANGRY_PISTOL, false },//always aims + { ACT_IDLE_AIM_STEALTH, ACT_IDLE_STEALTH_PISTOL, false }, + + { ACT_WALK_AIM_RELAXED, ACT_WALK_PISTOL_RELAXED, false },//never aims + { ACT_WALK_AIM_STIMULATED, ACT_WALK_AIM_PISTOL, false }, + { ACT_WALK_AIM_AGITATED, ACT_WALK_AIM_PISTOL, false },//always aims + { ACT_WALK_AIM_STEALTH, ACT_WALK_AIM_STEALTH_PISTOL, false },//always aims + + { ACT_RUN_AIM_RELAXED, ACT_RUN_PISTOL_RELAXED, false },//never aims + { ACT_RUN_AIM_STIMULATED, ACT_RUN_AIM_PISTOL, false }, + { ACT_RUN_AIM_AGITATED, ACT_RUN_AIM_PISTOL, false },//always aims + { ACT_RUN_AIM_STEALTH, ACT_RUN_AIM_STEALTH_PISTOL, false },//always aims + //End readiness activities +#else // Readiness activities (not aiming) { ACT_IDLE_RELAXED, ACT_IDLE_PISTOL, false },//never aims { ACT_IDLE_STIMULATED, ACT_IDLE_STIMULATED, false }, @@ -193,6 +227,7 @@ acttable_t CWeaponPistol::m_acttable[] = { ACT_RUN_AIM_AGITATED, ACT_RUN_AIM_PISTOL, false },//always aims { ACT_RUN_AIM_STEALTH, ACT_RUN_AIM_STEALTH_PISTOL, false },//always aims //End readiness activities +#endif // Crouch activities { ACT_CROUCHIDLE_STIMULATED, ACT_CROUCHIDLE_STIMULATED, false }, @@ -210,6 +245,19 @@ acttable_t CWeaponPistol::m_acttable[] = IMPLEMENT_ACTTABLE( CWeaponPistol ); +#ifdef MAPBASE +// Allows Weapon_BackupActivity() to access the pistol's activity table. +acttable_t *GetPistolActtable() +{ + return CWeaponPistol::m_acttable; +} + +int GetPistolActtableCount() +{ + return ARRAYSIZE(CWeaponPistol::m_acttable); +} +#endif + //----------------------------------------------------------------------------- // Purpose: Constructor //----------------------------------------------------------------------------- diff --git a/sp/src/game/shared/basecombatweapon_shared.cpp b/sp/src/game/shared/basecombatweapon_shared.cpp index d807e559..1036259e 100644 --- a/sp/src/game/shared/basecombatweapon_shared.cpp +++ b/sp/src/game/shared/basecombatweapon_shared.cpp @@ -1046,7 +1046,13 @@ WeaponClass_t CBaseCombatWeapon::WeaponClassify() Activity idleact = ActivityOverride(ACT_IDLE_ANGRY, NULL); switch (idleact) { +#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES + case ACT_IDLE_ANGRY_REVOLVER: +#endif case ACT_IDLE_ANGRY_PISTOL: return WEPCLASS_HANDGUN; +#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES + case ACT_IDLE_ANGRY_CROSSBOW: // For now, crossbows are rifles +#endif case ACT_IDLE_ANGRY_SMG1: case ACT_IDLE_ANGRY_AR2: return WEPCLASS_RIFLE; case ACT_IDLE_ANGRY_SHOTGUN: return WEPCLASS_SHOTGUN; From fcc815512fb101309ead9479f9f51d5283a873e7 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sun, 10 Oct 2021 20:07:55 -0500 Subject: [PATCH 183/378] Implemented new activities on RPG, crowbar, stunstick, and citizen accessories --- sp/src/game/server/hl2/weapon_citizenpackage.cpp | 14 ++++++++++++++ sp/src/game/server/hl2/weapon_crowbar.cpp | 5 +++++ sp/src/game/server/hl2/weapon_rpg.cpp | 4 ++++ sp/src/game/shared/hl2mp/weapon_stunstick.cpp | 6 ++++++ 4 files changed, 29 insertions(+) diff --git a/sp/src/game/server/hl2/weapon_citizenpackage.cpp b/sp/src/game/server/hl2/weapon_citizenpackage.cpp index cdb9378a..3d82e46c 100644 --- a/sp/src/game/server/hl2/weapon_citizenpackage.cpp +++ b/sp/src/game/server/hl2/weapon_citizenpackage.cpp @@ -23,6 +23,13 @@ acttable_t CWeaponCitizenPackage::m_acttable[] = { { ACT_IDLE, ACT_IDLE_PACKAGE, false }, { ACT_WALK, ACT_WALK_PACKAGE, false }, +#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES + { ACT_RUN, ACT_RUN_PACKAGE, false }, + + { ACT_IDLE_ANGRY, ACT_IDLE_PACKAGE, false }, + { ACT_WALK_AIM, ACT_WALK_PACKAGE, false }, + { ACT_RUN_AIM, ACT_RUN_PACKAGE, false }, +#endif }; IMPLEMENT_ACTTABLE(CWeaponCitizenPackage); @@ -70,5 +77,12 @@ acttable_t CWeaponCitizenSuitcase::m_acttable[] = { { ACT_IDLE, ACT_IDLE_SUITCASE, false }, { ACT_WALK, ACT_WALK_SUITCASE, false }, +#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES + { ACT_RUN, ACT_RUN_SUITCASE, false }, + + { ACT_IDLE_ANGRY, ACT_IDLE_SUITCASE, false }, + { ACT_WALK_AIM, ACT_WALK_SUITCASE, false }, + { ACT_RUN_AIM, ACT_RUN_SUITCASE, false }, +#endif }; IMPLEMENT_ACTTABLE(CWeaponCitizenSuitcase); diff --git a/sp/src/game/server/hl2/weapon_crowbar.cpp b/sp/src/game/server/hl2/weapon_crowbar.cpp index fdbc7943..e95c2dbb 100644 --- a/sp/src/game/server/hl2/weapon_crowbar.cpp +++ b/sp/src/game/server/hl2/weapon_crowbar.cpp @@ -42,6 +42,11 @@ acttable_t CWeaponCrowbar::m_acttable[] = { ACT_MELEE_ATTACK1, ACT_MELEE_ATTACK_SWING, true }, { ACT_IDLE, ACT_IDLE_ANGRY_MELEE, false }, { ACT_IDLE_ANGRY, ACT_IDLE_ANGRY_MELEE, false }, +#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES + // Just so we don't have to implement more activities, re-use the MP acts + { ACT_RUN, ACT_MP_RUN_MELEE, false }, + { ACT_WALK, ACT_MP_WALK_MELEE, false }, +#endif }; IMPLEMENT_ACTTABLE(CWeaponCrowbar); diff --git a/sp/src/game/server/hl2/weapon_rpg.cpp b/sp/src/game/server/hl2/weapon_rpg.cpp index 3ae41e28..808b6e90 100644 --- a/sp/src/game/server/hl2/weapon_rpg.cpp +++ b/sp/src/game/server/hl2/weapon_rpg.cpp @@ -1399,6 +1399,10 @@ PRECACHE_WEAPON_REGISTER(weapon_rpg); acttable_t CWeaponRPG::m_acttable[] = { { ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_RPG, true }, +#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES + { ACT_RANGE_AIM_LOW, ACT_RANGE_AIM_RPG_LOW, false }, + { ACT_RANGE_ATTACK1_LOW, ACT_RANGE_ATTACK_RPG_LOW, false }, +#endif { ACT_IDLE_RELAXED, ACT_IDLE_RPG_RELAXED, true }, { ACT_IDLE_STIMULATED, ACT_IDLE_ANGRY_RPG, true }, diff --git a/sp/src/game/shared/hl2mp/weapon_stunstick.cpp b/sp/src/game/shared/hl2mp/weapon_stunstick.cpp index 1d68b529..0884153e 100644 --- a/sp/src/game/shared/hl2mp/weapon_stunstick.cpp +++ b/sp/src/game/shared/hl2mp/weapon_stunstick.cpp @@ -81,6 +81,12 @@ acttable_t CWeaponStunStick::m_acttable[] = #endif { ACT_MELEE_ATTACK1, ACT_MELEE_ATTACK_SWING, true }, { ACT_IDLE_ANGRY, ACT_IDLE_ANGRY_MELEE, true }, +#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES + // Just so we don't have to implement more activities, re-use the MP acts + { ACT_IDLE, ACT_MP_STAND_MELEE, false }, + { ACT_RUN, ACT_MP_RUN_MELEE, false }, + { ACT_WALK, ACT_MP_WALK_MELEE, false }, +#endif }; IMPLEMENT_ACTTABLE(CWeaponStunStick); From a8f0af792594a8a13037f3160977a0bd9e5561d6 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sun, 10 Oct 2021 20:09:32 -0500 Subject: [PATCH 184/378] Implemented misc. new activities --- sp/src/game/server/hl2/npc_combine.cpp | 37 +++++++++++++++---- .../game/server/hl2/npc_playercompanion.cpp | 15 -------- sp/src/game/server/hl2/weapon_ar2.cpp | 2 +- sp/src/game/server/hl2/weapon_smg1.cpp | 5 +++ 4 files changed, 36 insertions(+), 23 deletions(-) diff --git a/sp/src/game/server/hl2/npc_combine.cpp b/sp/src/game/server/hl2/npc_combine.cpp index 3a643ff7..73f58af5 100644 --- a/sp/src/game/server/hl2/npc_combine.cpp +++ b/sp/src/game/server/hl2/npc_combine.cpp @@ -43,9 +43,13 @@ int g_fCombineQuestion; // true if an idle grunt asked a question. Cleared wh #ifdef MAPBASE ConVar npc_combine_idle_walk_easy( "npc_combine_idle_walk_easy", "1", FCVAR_NONE, "Mapbase: Allows Combine soldiers to use ACT_WALK_EASY as a walking animation when idle." ); ConVar npc_combine_unarmed_anims( "npc_combine_unarmed_anims", "1", FCVAR_NONE, "Mapbase: Allows Combine soldiers to use unarmed idle/walk animations when they have no weapon." ); +ConVar npc_combine_protected_run( "npc_combine_protected_run", "0", FCVAR_NONE, "Mapbase: Allows Combine soldiers to use \"protected run\" animations." ); ConVar npc_combine_altfire_not_allies_only( "npc_combine_altfire_not_allies_only", "1", FCVAR_NONE, "Mapbase: Elites are normally only allowed to fire their alt-fire attack at the player and the player's allies; This allows elites to alt-fire at other enemies too." ); ConVar npc_combine_new_cover_behavior( "npc_combine_new_cover_behavior", "1", FCVAR_NONE, "Mapbase: Toggles small patches for parts of npc_combine AI related to soldiers failing to take cover. These patches are minimal and only change cases where npc_combine would otherwise look at an enemy without shooting or run up to the player to melee attack when they don't have to. Consult the Mapbase wiki for more information." ); + +extern acttable_t *GetSMG1Acttable(); +extern acttable_t *GetPistolActtable(); #endif #define COMBINE_SKIN_DEFAULT 0 @@ -129,6 +133,11 @@ Activity ACT_WALK_MARCH; #ifdef MAPBASE Activity ACT_IDLE_UNARMED; Activity ACT_WALK_UNARMED; +Activity ACT_RUN_UNARMED; +Activity ACT_WALK_EASY_PISTOL; +Activity ACT_TURRET_CARRY_IDLE; +Activity ACT_TURRET_CARRY_WALK; +Activity ACT_TURRET_CARRY_RUN; #endif // ----------------------------------------------- @@ -1540,11 +1549,6 @@ void CNPC_Combine::BuildScheduleTestBits( void ) //----------------------------------------------------------------------------- Activity CNPC_Combine::Weapon_TranslateActivity( Activity eNewActivity, bool *pRequired ) { - // We have differing low animations and ACT_CROUCHIDLE is not friendly to weapon translation. - // ACT_CROUCHIDLE is pretty much deprecated at this point anyway. - if (eNewActivity == ACT_CROUCHIDLE) - eNewActivity = ACT_RANGE_AIM_LOW; - return BaseClass::Weapon_TranslateActivity(eNewActivity, pRequired); } @@ -1636,10 +1640,24 @@ Activity CNPC_Combine::NPC_TranslateActivity( Activity eNewActivity ) eNewActivity = ACT_IDLE_UNARMED; else if (eNewActivity == ACT_WALK) eNewActivity = ACT_WALK_UNARMED; + else if (eNewActivity == ACT_RUN) + eNewActivity = ACT_RUN_UNARMED; } - else if (eNewActivity == ACT_WALK && m_NPCState == NPC_STATE_IDLE && npc_combine_idle_walk_easy.GetBool() && HaveSequenceForActivity(ACT_WALK_EASY)) + else if (m_NPCState == NPC_STATE_IDLE && npc_combine_idle_walk_easy.GetBool() && HaveSequenceForActivity(ACT_WALK_EASY)) { - eNewActivity = ACT_WALK_EASY; + if (eNewActivity == ACT_WALK && GetActiveWeapon()) + { + if (GetActiveWeapon()->GetBackupActivityList() == GetSMG1Acttable()) + eNewActivity = ACT_WALK_EASY; + else if (GetActiveWeapon()->GetBackupActivityList() == GetPistolActtable()) + eNewActivity = ACT_WALK_EASY_PISTOL; + } + } + + if ( eNewActivity == ACT_RUN && ( IsCurSchedule( SCHED_TAKE_COVER_FROM_BEST_SOUND ) || IsCurSchedule( SCHED_FLEE_FROM_BEST_SOUND ) ) ) + { + if ( random->RandomInt( 0, 1 ) && npc_combine_protected_run.GetBool() && HaveSequenceForActivity( ACT_RUN_PROTECTED ) ) + eNewActivity = ACT_RUN_PROTECTED; } #endif @@ -3949,6 +3967,11 @@ DECLARE_ACTIVITY( ACT_WALK_MARCH ) #ifdef MAPBASE DECLARE_ACTIVITY( ACT_IDLE_UNARMED ) DECLARE_ACTIVITY( ACT_WALK_UNARMED ) +DECLARE_ACTIVITY( ACT_RUN_UNARMED ) +DECLARE_ACTIVITY( ACT_WALK_EASY_PISTOL ) +DECLARE_ACTIVITY( ACT_TURRET_CARRY_IDLE ) +DECLARE_ACTIVITY( ACT_TURRET_CARRY_WALK ) +DECLARE_ACTIVITY( ACT_TURRET_CARRY_RUN ) #endif DECLARE_ANIMEVENT( COMBINE_AE_BEGIN_ALTFIRE ) diff --git a/sp/src/game/server/hl2/npc_playercompanion.cpp b/sp/src/game/server/hl2/npc_playercompanion.cpp index 597f4c7f..7ed8553e 100644 --- a/sp/src/game/server/hl2/npc_playercompanion.cpp +++ b/sp/src/game/server/hl2/npc_playercompanion.cpp @@ -1665,21 +1665,6 @@ Activity CNPC_PlayerCompanion::NPC_TranslateActivity( Activity activity ) activity = ACT_RUN_PROTECTED; } -#ifdef COMPANION_HOLSTER_WORKAROUND - if (activity == ACT_DISARM || activity == ACT_ARM) - { - CBaseCombatWeapon *pWeapon = GetActiveWeapon() ? GetActiveWeapon() : m_hWeapons[m_iLastHolsteredWeapon]; - if (pWeapon && pWeapon->WeaponClassify() != WEPCLASS_HANDGUN) - { - switch (activity) - { - case ACT_DISARM: return ACT_DISARM_RIFLE; - case ACT_ARM: return ACT_ARM_RIFLE; - } - } - } -#endif - activity = BaseClass::NPC_TranslateActivity( activity ); if ( activity == ACT_IDLE ) diff --git a/sp/src/game/server/hl2/weapon_ar2.cpp b/sp/src/game/server/hl2/weapon_ar2.cpp index dcd0009c..6279c34d 100644 --- a/sp/src/game/server/hl2/weapon_ar2.cpp +++ b/sp/src/game/server/hl2/weapon_ar2.cpp @@ -103,7 +103,7 @@ acttable_t CWeaponAR2::m_acttable[] = { ACT_COVER_LOW, ACT_COVER_SMG1_LOW, false }, { ACT_RANGE_AIM_LOW, ACT_RANGE_AIM_AR2_LOW, false }, { ACT_RANGE_ATTACK1_LOW, ACT_RANGE_ATTACK_AR2_LOW, false }, - { ACT_RELOAD_LOW, ACT_RELOAD_SMG1_LOW, false }, + { ACT_RELOAD_LOW, ACT_RELOAD_AR2_LOW, false }, { ACT_GESTURE_RELOAD, ACT_GESTURE_RELOAD_AR2, true }, // { ACT_RANGE_ATTACK2, ACT_RANGE_ATTACK_AR2_GRENADE, true }, #else diff --git a/sp/src/game/server/hl2/weapon_smg1.cpp b/sp/src/game/server/hl2/weapon_smg1.cpp index 97b0e89e..8e889851 100644 --- a/sp/src/game/server/hl2/weapon_smg1.cpp +++ b/sp/src/game/server/hl2/weapon_smg1.cpp @@ -93,6 +93,11 @@ acttable_t CWeaponSMG1::m_acttable[] = { ACT_WALK, ACT_WALK_RIFLE, true }, { ACT_WALK_AIM, ACT_WALK_AIM_RIFLE, true }, + +#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES + { ACT_ARM, ACT_ARM_RIFLE, false }, + { ACT_DISARM, ACT_DISARM_RIFLE, false }, +#endif // Readiness activities (not aiming) { ACT_IDLE_RELAXED, ACT_IDLE_SMG1_RELAXED, false },//never aims From 2638dd1d1cd8b6cc07c15a705aeee5efb8227b2f Mon Sep 17 00:00:00 2001 From: Blixibon Date: Mon, 11 Oct 2021 13:23:37 -0500 Subject: [PATCH 185/378] Added ThrowGrenadeGestureAtTarget input --- sp/src/game/server/mapbase/ai_grenade.h | 59 +++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/sp/src/game/server/mapbase/ai_grenade.h b/sp/src/game/server/mapbase/ai_grenade.h index 69031d74..bfcbd4de 100644 --- a/sp/src/game/server/mapbase/ai_grenade.h +++ b/sp/src/game/server/mapbase/ai_grenade.h @@ -41,6 +41,7 @@ DEFINE_FIELD( m_vecTossVelocity, FIELD_VECTOR ), \ DEFINE_FIELD( m_iLastAnimEventHandled, FIELD_INTEGER ), \ DEFINE_INPUTFUNC( FIELD_STRING, "ThrowGrenadeAtTarget", InputThrowGrenadeAtTarget ), \ + DEFINE_INPUTFUNC( FIELD_STRING, "ThrowGrenadeGestureAtTarget", InputThrowGrenadeGestureAtTarget ), \ DEFINE_INPUTFUNC( FIELD_INTEGER, "SetGrenades", InputSetGrenades ), \ DEFINE_INPUTFUNC( FIELD_INTEGER, "AddGrenades", InputAddGrenades ), \ DEFINE_OUTPUT(m_OnThrowGrenade, "OnThrowGrenade"), \ @@ -124,6 +125,7 @@ public: void InputSetGrenades( inputdata_t &inputdata ) { AddGrenades( inputdata.value.Int() - m_iNumGrenades ); } void InputAddGrenades( inputdata_t &inputdata ) { AddGrenades( inputdata.value.Int() ); } void InputThrowGrenadeAtTarget( inputdata_t &inputdata ); + void InputThrowGrenadeGestureAtTarget( inputdata_t &inputdata ); virtual void DelayGrenadeCheck( float delay ) { m_flNextGrenadeCheck = gpGlobals->curtime + delay; } @@ -294,6 +296,63 @@ void CAI_GrenadeUser::InputThrowGrenadeAtTarget( inputdata_t &inputdat this->ClearSchedule( "Told to throw grenade via input" ); } +//----------------------------------------------------------------------------- +// Purpose: Force the combine soldier to throw a grenade at the target using the gesture animation. +// If I'm a combine elite, fire my combine ball at the target instead. +// Input : &inputdata - +//----------------------------------------------------------------------------- +template +void CAI_GrenadeUser::InputThrowGrenadeGestureAtTarget( inputdata_t &inputdata ) +{ + // Ignore if we're inside a scripted sequence + //if ( this->GetState() == NPC_STATE_SCRIPT && this->m_hCine ) + // return; + + CBaseEntity *pEntity = gEntList.FindEntityByName( NULL, inputdata.value.String(), this, inputdata.pActivator, inputdata.pCaller ); + if ( !pEntity ) + { + DevMsg("%s (%s) received ThrowGrenadeGestureAtTarget input, but couldn't find target entity '%s'\n", this->GetClassname(), this->GetDebugName(), inputdata.value.String() ); + return; + } + + m_hForcedGrenadeTarget = pEntity; + m_flNextGrenadeCheck = 0; + + Vector vecTarget = m_hForcedGrenadeTarget->WorldSpaceCenter(); + +#ifdef SHARED_COMBINE_ACTIVITIES + if (IsAltFireCapable()) + { + if (FVisible( m_hForcedGrenadeTarget )) + { + m_vecAltFireTarget = vecTarget; + m_hForcedGrenadeTarget = NULL; + + int iLayer = AddGesture( ACT_GESTURE_COMBINE_AR2_ALTFIRE ); + if (iLayer != -1) + { + this->GetShotRegulator()->FireNoEarlierThan( gpGlobals->curtime + this->GetLayerDuration( iLayer ) ); + } + } + } + else + { + // If we can, throw a grenade at the target. + // Ignore grenade count / distance / etc + if (CheckCanThrowGrenade( vecTarget )) + { + int iLayer = AddGesture( ACT_GESTURE_COMBINE_THROW_GRENADE ); + if (iLayer != -1) + { + this->GetShotRegulator()->FireNoEarlierThan( gpGlobals->curtime + this->GetLayerDuration( iLayer ) ); + } + } + } +#else + Warning("Gesture grenades/alt-fire not supported\n"); +#endif +} + //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- template From 3d5f73b8be96922c60691e46a5ba5bf63af910a0 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Wed, 13 Oct 2021 16:17:46 -0500 Subject: [PATCH 186/378] Added new NPC climbing activities and improved climbing navigation AI --- sp/src/game/server/ai_activity.cpp | 9 ++ sp/src/game/server/ai_basenpc.cpp | 14 ++ sp/src/game/server/ai_basenpc_schedule.cpp | 37 +++++ sp/src/game/server/ai_motor.cpp | 176 ++++++++++++++++++++- sp/src/game/server/ai_motor.h | 4 + sp/src/game/server/ai_navigator.cpp | 18 +++ sp/src/game/server/hl2/npc_fastzombie.cpp | 14 +- sp/src/game/shared/activitylist.cpp | 9 ++ sp/src/game/shared/ai_activity.h | 13 ++ 9 files changed, 290 insertions(+), 4 deletions(-) diff --git a/sp/src/game/server/ai_activity.cpp b/sp/src/game/server/ai_activity.cpp index 7e5f13f9..c467ddc4 100644 --- a/sp/src/game/server/ai_activity.cpp +++ b/sp/src/game/server/ai_activity.cpp @@ -2254,4 +2254,13 @@ void CAI_BaseNPC::InitDefaultActivitySR(void) ADD_ACTIVITY_TO_SR( ACT_ARM_RIFLE ); ADD_ACTIVITY_TO_SR( ACT_DISARM_RIFLE ); #endif + +#ifdef EXPANDED_NAVIGATION_ACTIVITIES + ADD_ACTIVITY_TO_SR( ACT_CLIMB_ALL ); + ADD_ACTIVITY_TO_SR( ACT_CLIMB_IDLE ); + + ADD_ACTIVITY_TO_SR( ACT_CLIMB_MOUNT_TOP ); + ADD_ACTIVITY_TO_SR( ACT_CLIMB_MOUNT_BOTTOM ); + ADD_ACTIVITY_TO_SR( ACT_CLIMB_DISMOUNT_BOTTOM ); +#endif } diff --git a/sp/src/game/server/ai_basenpc.cpp b/sp/src/game/server/ai_basenpc.cpp index d2ec72bf..170b5454 100644 --- a/sp/src/game/server/ai_basenpc.cpp +++ b/sp/src/game/server/ai_basenpc.cpp @@ -6593,6 +6593,12 @@ Activity CAI_BaseNPC::NPC_BackupActivity( Activity eNewActivity ) if (eNewActivity == ACT_WALK_ANGRY) return TranslateActivity(ACT_WALK); + // If one climbing animation isn't available, use the other + if (eNewActivity == ACT_CLIMB_DOWN) + return ACT_CLIMB_UP; + else if (eNewActivity == ACT_CLIMB_UP) + return ACT_CLIMB_DOWN; + // GetCoverActivity() should have this covered. // --------------------------------------------- //if (eNewActivity == ACT_COVER) @@ -6609,6 +6615,14 @@ Activity CAI_BaseNPC::NPC_BackupActivity( Activity eNewActivity ) //----------------------------------------------------------------------------- Activity CAI_BaseNPC::NPC_TranslateActivity( Activity eNewActivity ) { +#ifdef EXPANDED_NAVIGATION_ACTIVITIES + if ( GetNavType() == NAV_CLIMB && eNewActivity == ACT_IDLE ) + { + // Schedules which break into idle activities should try to maintain the climbing animation. + return ACT_CLIMB_IDLE; + } +#endif + #ifdef MAPBASE Assert( eNewActivity != ACT_INVALID ); diff --git a/sp/src/game/server/ai_basenpc_schedule.cpp b/sp/src/game/server/ai_basenpc_schedule.cpp index cf425fd0..7fc1c13b 100644 --- a/sp/src/game/server/ai_basenpc_schedule.cpp +++ b/sp/src/game/server/ai_basenpc_schedule.cpp @@ -1363,6 +1363,14 @@ void CAI_BaseNPC::StartTask( const Task_t *pTask ) break; case TASK_STOP_MOVING: +#ifdef MAPBASE + if ( GetNavType() == NAV_CLIMB ) + { + // Don't clear the goal so that the climb can finish + DbgNavMsg( this, "Start TASK_STOP_MOVING with climb workaround\n" ); + } + else +#endif if ( ( GetNavigator()->IsGoalSet() && GetNavigator()->IsGoalActive() ) || GetNavType() == NAV_JUMP ) { DbgNavMsg( this, "Start TASK_STOP_MOVING\n" ); @@ -3348,8 +3356,37 @@ void CAI_BaseNPC::RunTask( const Task_t *pTask ) // a navigation while in the middle of a climb if (GetNavType() == NAV_CLIMB) { +#ifdef MAPBASE + if (GetActivity() != ACT_CLIMB_DISMOUNT) + { + // Try to just pause the climb, but dismount if we're in SCHED_FAIL + if (IsCurSchedule( SCHED_FAIL, false )) + { + GetMotor()->MoveClimbStop(); + } + else + { + GetMotor()->MoveClimbPause(); + } + + TaskComplete(); + } + else if (IsActivityFinished()) + { + // Dismount complete. Fix up our position if we have to + Vector vecTeleportOrigin; + if (GetMotor()->MoveClimbShouldTeleportToSequenceEnd( vecTeleportOrigin )) + { + GetMotor()->MoveClimbStop(); + SetLocalOrigin( vecTeleportOrigin ); + TaskComplete(); + } + } + break; +#else // wait until you reach the end break; +#endif } DbgNavMsg( this, "TASK_STOP_MOVING Complete\n" ); diff --git a/sp/src/game/server/ai_motor.cpp b/sp/src/game/server/ai_motor.cpp index 49f3d5f4..0db2c6c5 100644 --- a/sp/src/game/server/ai_motor.cpp +++ b/sp/src/game/server/ai_motor.cpp @@ -235,18 +235,47 @@ void CAI_Motor::MoveClimbStart( const Vector &climbDest, const Vector &climbDir // > code are not reciprocal for all state, and furthermore, stomp // > other state? + bool bGoingUp = (climbDir.z > 0.01); +#ifdef EXPANDED_NAVIGATION_ACTIVITIES + if ( bGoingUp && GetOuter()->HaveSequenceForActivity( ACT_CLIMB_MOUNT_BOTTOM ) ) + { + SetActivity( ACT_CLIMB_MOUNT_BOTTOM ); + + // Steal m_vecDismount for this + GetOuter()->GetSequenceLinearMotion( GetSequence(), &m_vecDismount ); + GetOuter()->SetCycle( GetOuter()->GetMovementFrame( m_vecDismount.z - climbDist ) ); + } + else if ( !bGoingUp && GetOuter()->HaveSequenceForActivity( ACT_CLIMB_MOUNT_TOP ) ) + { + SetActivity( ACT_CLIMB_MOUNT_TOP ); + + // Steal m_vecDismount for this + GetOuter()->GetSequenceLinearMotion( GetSequence(), &m_vecDismount ); + GetOuter()->SetCycle( GetOuter()->GetMovementFrame( m_vecDismount.z - climbDist ) ); + } + else +#endif if ( fabsf( climbDir.z ) < .1 ) { SetActivity( GetNavigator()->GetMovementActivity() ); } else { - SetActivity( (climbDir.z > -0.01 ) ? ACT_CLIMB_UP : ACT_CLIMB_DOWN ); + SetActivity( bGoingUp ? ACT_CLIMB_UP : ACT_CLIMB_DOWN ); } m_nDismountSequence = SelectWeightedSequence( ACT_CLIMB_DISMOUNT ); if (m_nDismountSequence != ACT_INVALID) { +#ifdef EXPANDED_NAVIGATION_ACTIVITIES + if ( !bGoingUp ) + { + int nBottomDismount = SelectWeightedSequence( ACT_CLIMB_DISMOUNT_BOTTOM ); + if (nBottomDismount != ACTIVITY_NOT_AVAILABLE) + m_nDismountSequence = nBottomDismount; + } +#endif + GetOuter()->GetSequenceLinearMotion( m_nDismountSequence, &m_vecDismount ); } else @@ -262,6 +291,76 @@ void CAI_Motor::MoveClimbStart( const Vector &climbDest, const Vector &climbDir AIMoveResult_t CAI_Motor::MoveClimbExecute( const Vector &climbDest, const Vector &climbDir, float climbDist, float yaw, int climbNodesLeft ) { +#ifdef EXPANDED_NAVIGATION_ACTIVITIES + if ( (GetActivity() == ACT_CLIMB_MOUNT_TOP || GetActivity() == ACT_CLIMB_MOUNT_BOTTOM) ) + { + if (!GetOuter()->IsActivityFinished()) + { + // Wait for the mounting to finish + SetGroundEntity( NULL ); + } + else + { + // Fix up our position if we have to + Vector vecTeleportOrigin; + if (MoveClimbShouldTeleportToSequenceEnd( vecTeleportOrigin )) + { + SetLocalOrigin( vecTeleportOrigin ); + } + + // Reset activity and start from the beginning + GetOuter()->ResetActivity(); + return MoveClimbExecute( climbDest, climbDir, climbDist, yaw, climbNodesLeft ); + } + } + else if ( fabsf( climbDir.z ) > .1 && (GetActivity() != ACT_CLIMB_DISMOUNT && GetActivity() != ACT_CLIMB_DISMOUNT_BOTTOM) ) + { + bool bGoingUp = (climbDir.z > -0.01); + if ( GetOuter()->HaveSequenceForActivity( ACT_CLIMB_ALL ) ) + { + SetActivity( ACT_CLIMB_ALL ); + + // TODO: Use UTIL_VecToPitch() instead if move_yaw becomes a true climb yaw and not just an up-down scalar + SetPoseParameter( GetOuter()->LookupPoseMoveYaw(), climbDir.z < 0 ? 180.0 : -180.0 ); + } + else + { + Activity desiredActivity = bGoingUp ? ACT_CLIMB_UP : ACT_CLIMB_DOWN; + if ( GetActivity() != desiredActivity ) + { + SetActivity( desiredActivity ); + } + } + + if (m_nDismountSequence != ACT_INVALID) + { + if (climbNodesLeft <= 2 && climbDist < fabs( m_vecDismount.z )) + { + if (bGoingUp) + { + // fixme: No other way to force m_nIdealSequence? + GetOuter()->SetActivity( ACT_CLIMB_DISMOUNT ); + GetOuter()->SetCycle( GetOuter()->GetMovementFrame( m_vecDismount.z - climbDist ) ); + } + else + { + if (GetSequence() != m_nDismountSequence && GetOuter()->GetSequenceActivity( m_nDismountSequence ) == ACT_CLIMB_DISMOUNT_BOTTOM) + { + SetActivity( ACT_CLIMB_DISMOUNT_BOTTOM ); + } + } + } + } + } + else if ( climbDir.Length() == 0 && GetOuter()->GetInstantaneousVelocity() <= 0.01 ) + { + // The NPC is somehow stuck climbing with no direction or movement. + // This can be caused by NPCs getting stuck in each other and/or being moved away from the ladder. + // In these cases, the NPC has to be made unstuck, or else they may remain in an immobile climbing state forever. + Warning( "%s had to abort climbing due to no direction or movement\n", GetOuter()->GetDebugName() ); + return AIMR_ILLEGAL; + } +#else if ( fabsf( climbDir.z ) > .1 ) { if ( GetActivity() != ACT_CLIMB_DISMOUNT ) @@ -292,13 +391,34 @@ AIMoveResult_t CAI_Motor::MoveClimbExecute( const Vector &climbDest, const Vecto } } } +#endif float climbSpeed = GetOuter()->GetInstantaneousVelocity(); if (m_nDismountSequence != ACT_INVALID) { // catch situations where the climb mount/dismount finished before reaching goal +#ifdef EXPANDED_NAVIGATION_ACTIVITIES + if ((GetActivity() == ACT_CLIMB_DISMOUNT || GetActivity() == ACT_CLIMB_DISMOUNT_BOTTOM)) + { + SetGroundEntity( NULL ); + + if (GetOuter()->IsActivityFinished()) + { + // Fix up our position if we have to + Vector vecTeleportOrigin; + if (MoveClimbShouldTeleportToSequenceEnd( vecTeleportOrigin )) + { + // Just force it to complete + climbDist = 0.0f; + } + + climbSpeed = 200.0f; + } + } +#else climbSpeed = MAX( climbSpeed, 30.0 ); +#endif } else { @@ -314,7 +434,7 @@ AIMoveResult_t CAI_Motor::MoveClimbExecute( const Vector &climbDest, const Vecto climbDist = 0; const float climbTime = climbDist / climbSpeed; - + SetMoveInterval( GetMoveInterval() - climbTime ); SetLocalOrigin( climbDest ); @@ -340,11 +460,63 @@ void CAI_Motor::MoveClimbStop() else SetActivity( ACT_IDLE ); +#ifdef MAPBASE + // Unlock desired weapon state so NPCs can unholster their weapons again. + GetOuter()->SetDesiredWeaponState( DESIREDWEAPONSTATE_IGNORE ); + + // Unlock yaw + // TODO: Add yaw locking for when climbing is paused + //SetYawLocked( false ); +#endif + GetOuter()->RemoveFlag( FL_FLY ); SetSmoothedVelocity( vec3_origin ); SetGravity( 1.0 ); } +#ifdef MAPBASE +void CAI_Motor::MoveClimbPause() +{ + if (GetActivity() != ACT_CLIMB_DISMOUNT +#ifdef EXPANDED_NAVIGATION_ACTIVITIES + && GetActivity() != ACT_CLIMB_MOUNT_TOP && GetActivity() != ACT_CLIMB_MOUNT_BOTTOM +#endif + ) + { + if ( GetActivity() == ACT_CLIMB_ALL ) + { + SetPoseParameter( GetOuter()->LookupPoseMoveYaw(), 0.0f ); + } + + SetSmoothedVelocity( vec3_origin ); + } + else + { + // If already dismounting, do nothing + } +} + +//----------------------------------------------------------------------------- +// Purpose: This is part of a hack needed in cases where ladder mount/dismount animations collide with the world and don't move properly. +// It's based off of the same code as scripted_sequence's teleportation fixup, although this function only resolves the bone origin and +// returns whether or not teleportation is necessary, as the teleportation is achieved in different ways for different uses of this code. +//----------------------------------------------------------------------------- +bool CAI_Motor::MoveClimbShouldTeleportToSequenceEnd( Vector &teleportOrigin ) +{ + QAngle new_angle; + GetOuter()->GetBonePosition( 0, teleportOrigin, new_angle ); + + // Ensure that there is actually a distance needed to teleport there + if ((GetLocalOrigin() - teleportOrigin).Length2DSqr() > Square( 8.0 )) + { + teleportOrigin.z = GetLocalOrigin().z; + return true; + } + + return false; +} +#endif + //----------------------------------------------------------------------------- // Purpose: Motion for jumping // Input : diff --git a/sp/src/game/server/ai_motor.h b/sp/src/game/server/ai_motor.h index d7f14293..b5f5d297 100644 --- a/sp/src/game/server/ai_motor.h +++ b/sp/src/game/server/ai_motor.h @@ -62,6 +62,10 @@ public: virtual void MoveClimbStart( const Vector &climbDest, const Vector &climbDir, float climbDist, float yaw ); virtual AIMoveResult_t MoveClimbExecute( const Vector &climbDest, const Vector &climbDir, float climbDist, float yaw, int climbNodesLeft ); virtual void MoveClimbStop(); +#ifdef MAPBASE + virtual void MoveClimbPause(); + virtual bool MoveClimbShouldTeleportToSequenceEnd( Vector &teleportOrigin ); +#endif //--------------------------------- diff --git a/sp/src/game/server/ai_navigator.cpp b/sp/src/game/server/ai_navigator.cpp index d136c923..9d6ae06a 100644 --- a/sp/src/game/server/ai_navigator.cpp +++ b/sp/src/game/server/ai_navigator.cpp @@ -1642,6 +1642,15 @@ void CAI_Navigator::MoveCalcBaseGoal( AILocalMoveGoal_t *pMoveGoal ) AI_Waypoint_t *pCurWaypoint = GetPath()->GetCurWaypoint(); if ( pCurWaypoint->GetNext() && pCurWaypoint->GetNext()->NavType() != pCurWaypoint->NavType() ) pMoveGoal->flags |= AILMG_TARGET_IS_TRANSITION; + +#ifdef MAPBASE + // TODO: Better place for this code? + if (pMoveGoal->flags & AILMG_TARGET_IS_TRANSITION && pCurWaypoint->GetNext()->NavType() == NAV_CLIMB) + { + // NPCs need to holster their weapons before climbing. + GetOuter()->SetDesiredWeaponState( DESIREDWEAPONSTATE_HOLSTERED ); + } +#endif } const Task_t *pCurTask = GetOuter()->GetTask(); @@ -2591,8 +2600,12 @@ bool CAI_Navigator::Move( float flInterval ) if ( GetNavType() == NAV_CLIMB ) { +#ifdef MAPBASE + GetMotor()->MoveClimbPause(); +#else GetMotor()->MoveClimbStop(); SetNavType( NAV_GROUND ); +#endif } GetMotor()->MoveStop(); AssertMsg( TaskIsRunning() || TaskIsComplete(), ("Schedule stalled!!\n") ); @@ -3880,7 +3893,12 @@ bool CAI_Navigator::GetStoppingPath( CAI_WaypointList * pClippedWaypoints ) AI_Waypoint_t *pCurWaypoint = GetPath()->GetCurWaypoint(); if ( pCurWaypoint ) { +#ifdef EXPANDED_NAVIGATION_ACTIVITIES + // Since regular climb nav can interrupt itself now, only do this when dismounting + bool bMustCompleteCurrent = ( (pCurWaypoint->NavType() == NAV_CLIMB && (GetActivity() == ACT_CLIMB_DISMOUNT || GetActivity() == ACT_CLIMB_MOUNT_TOP)) || pCurWaypoint->NavType() == NAV_JUMP ); +#else bool bMustCompleteCurrent = ( pCurWaypoint->NavType() == NAV_CLIMB || pCurWaypoint->NavType() == NAV_JUMP ); +#endif float distRemaining = GetMotor()->MinStoppingDist( 0 ); if ( bMustCompleteCurrent ) diff --git a/sp/src/game/server/hl2/npc_fastzombie.cpp b/sp/src/game/server/hl2/npc_fastzombie.cpp index 0e15e2a8..be53f344 100644 --- a/sp/src/game/server/hl2/npc_fastzombie.cpp +++ b/sp/src/game/server/hl2/npc_fastzombie.cpp @@ -1296,7 +1296,11 @@ void CFastZombie::StartTask( const Task_t *pTask ) CBaseEntity *pEnemy = GetEnemy(); Vector vecJumpDir; - if ( GetActivity() == ACT_CLIMB_UP || GetActivity() == ACT_CLIMB_DOWN ) + if ( GetActivity() == ACT_CLIMB_UP || GetActivity() == ACT_CLIMB_DOWN +#ifdef EXPANDED_NAVIGATION_ACTIVITIES + || GetActivity() == ACT_CLIMB_ALL +#endif + ) { // Jump off the pipe backwards! Vector forward; @@ -1449,7 +1453,11 @@ int CFastZombie::TranslateSchedule( int scheduleType ) break; case SCHED_FASTZOMBIE_UNSTICK_JUMP: - if ( GetActivity() == ACT_CLIMB_UP || GetActivity() == ACT_CLIMB_DOWN || GetActivity() == ACT_CLIMB_DISMOUNT ) + if ( GetActivity() == ACT_CLIMB_UP || GetActivity() == ACT_CLIMB_DOWN || GetActivity() == ACT_CLIMB_DISMOUNT +#ifdef EXPANDED_NAVIGATION_ACTIVITIES + || (GetActivity() >= ACT_CLIMB_ALL && GetActivity() <= ACT_CLIMB_DISMOUNT_BOTTOM) +#endif + ) { return SCHED_FASTZOMBIE_CLIMBING_UNSTICK_JUMP; } @@ -1477,8 +1485,10 @@ int CFastZombie::TranslateSchedule( int scheduleType ) //--------------------------------------------------------- Activity CFastZombie::NPC_TranslateActivity( Activity baseAct ) { +#ifndef MAPBASE // Now covered by CAI_BaseNPC::NPC_BackupActivity if ( baseAct == ACT_CLIMB_DOWN ) return ACT_CLIMB_UP; +#endif return BaseClass::NPC_TranslateActivity( baseAct ); } diff --git a/sp/src/game/shared/activitylist.cpp b/sp/src/game/shared/activitylist.cpp index ede1485b..6d3f3cf6 100644 --- a/sp/src/game/shared/activitylist.cpp +++ b/sp/src/game/shared/activitylist.cpp @@ -2371,6 +2371,15 @@ void ActivityList_RegisterSharedActivities( void ) REGISTER_SHARED_ACTIVITY( ACT_DISARM_RIFLE ); #endif +#ifdef EXPANDED_NAVIGATION_ACTIVITIES + REGISTER_SHARED_ACTIVITY( ACT_CLIMB_ALL ); + REGISTER_SHARED_ACTIVITY( ACT_CLIMB_IDLE ); + + REGISTER_SHARED_ACTIVITY( ACT_CLIMB_MOUNT_TOP ); + REGISTER_SHARED_ACTIVITY( ACT_CLIMB_MOUNT_BOTTOM ); + REGISTER_SHARED_ACTIVITY( ACT_CLIMB_DISMOUNT_BOTTOM ); +#endif + AssertMsg( g_HighestActivity == LAST_SHARED_ACTIVITY - 1, "Not all activities from ai_activity.h registered in activitylist.cpp" ); } diff --git a/sp/src/game/shared/ai_activity.h b/sp/src/game/shared/ai_activity.h index bfe3eb05..36d07ed3 100644 --- a/sp/src/game/shared/ai_activity.h +++ b/sp/src/game/shared/ai_activity.h @@ -41,6 +41,10 @@ // This enables a bunch of new activities for Half-Life 2 weapons, including new 357 animations and readiness activities for pistols. #define EXPANDED_HL2_WEAPON_ACTIVITIES 1 +// EXPANDED NAVIGATION ACTIVITIES +// This enables some new navigation-related activities. +#define EXPANDED_NAVIGATION_ACTIVITIES 1 + #endif #define ACTIVITY_NOT_AVAILABLE -1 @@ -2243,6 +2247,15 @@ typedef enum ACT_DISARM_RIFLE, #endif +#ifdef EXPANDED_NAVIGATION_ACTIVITIES + ACT_CLIMB_ALL, // An actual blend animation which uses pose parameters for direction + ACT_CLIMB_IDLE, + + ACT_CLIMB_MOUNT_TOP, + ACT_CLIMB_MOUNT_BOTTOM, + ACT_CLIMB_DISMOUNT_BOTTOM, +#endif + // this is the end of the global activities, private per-monster activities start here. LAST_SHARED_ACTIVITY, } Activity; From 1c6b0679f81482817692ebea92f85f5cc6092b14 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Thu, 14 Oct 2021 02:16:38 -0500 Subject: [PATCH 187/378] Fixed various NPC holster-related issues --- sp/src/game/server/ai_basenpc.cpp | 31 +++++++++++++++++----- sp/src/game/server/ai_basenpc.h | 4 +-- sp/src/game/server/hl2/npc_metropolice.cpp | 9 +++++++ sp/src/game/server/hl2/weapon_ar2.cpp | 5 ++++ sp/src/game/server/hl2/weapon_crossbow.cpp | 3 +++ sp/src/game/server/hl2/weapon_rpg.cpp | 5 ++++ sp/src/game/server/hl2/weapon_shotgun.cpp | 5 ++++ sp/src/game/server/hl2/weapon_smg1.cpp | 10 +++---- 8 files changed, 59 insertions(+), 13 deletions(-) diff --git a/sp/src/game/server/ai_basenpc.cpp b/sp/src/game/server/ai_basenpc.cpp index 170b5454..e11d6452 100644 --- a/sp/src/game/server/ai_basenpc.cpp +++ b/sp/src/game/server/ai_basenpc.cpp @@ -7782,7 +7782,7 @@ int CAI_BaseNPC::HolsterWeapon( void ) if ( IsWeaponHolstered() ) return -1; -#ifdef COMPANION_HOLSTER_WORKAROUND +#ifdef MAPBASE Activity activity = TranslateActivity( ACT_DISARM ); int iHolsterGesture = FindGestureLayer( activity ); if ( iHolsterGesture != -1 ) @@ -7838,7 +7838,7 @@ int CAI_BaseNPC::UnholsterWeapon( void ) if ( !IsWeaponHolstered() ) return -1; -#ifdef COMPANION_HOLSTER_WORKAROUND +#ifdef MAPBASE Activity activity = TranslateActivity( ACT_ARM ); int iHolsterGesture = FindGestureLayer( activity ); #else @@ -7867,13 +7867,12 @@ int CAI_BaseNPC::UnholsterWeapon( void ) { SetActiveWeapon( GetWeapon(i) ); -#ifdef COMPANION_HOLSTER_WORKAROUND - int iLayer = AddGesture( activity, true ); - //iLayer = AddGesture( ACT_GESTURE_ARM, true ); +#ifdef MAPBASE + int iLayer = AddGesture( TranslateActivity( ACT_ARM ), true ); #else int iLayer = AddGesture( ACT_ARM, true ); - //iLayer = AddGesture( ACT_GESTURE_ARM, true ); #endif + //iLayer = AddGesture( ACT_GESTURE_ARM, true ); if (iLayer != -1) { @@ -8052,6 +8051,26 @@ bool CAI_BaseNPC::DoUnholster( void ) return false; } +//----------------------------------------------------------------------------- +// Purpose: Returns true if the NPC should be unholstering their weapon +//----------------------------------------------------------------------------- +bool CAI_BaseNPC::ShouldUnholsterWeapon( void ) +{ + return GetState() == NPC_STATE_COMBAT; +} + +//----------------------------------------------------------------------------- +// Purpose: Returns true if the NPC can unholster their weapon +//----------------------------------------------------------------------------- +bool CAI_BaseNPC::CanUnholsterWeapon( void ) +{ + // Don't unholster during special navigation + if ( GetNavType() == NAV_JUMP || GetNavType() == NAV_CLIMB ) + return false; + + return IsWeaponHolstered(); +} + //------------------------------------------------------------------------------ // Purpose: Give the NPC in question the weapon specified //------------------------------------------------------------------------------ diff --git a/sp/src/game/server/ai_basenpc.h b/sp/src/game/server/ai_basenpc.h index 1a00cb87..675412af 100644 --- a/sp/src/game/server/ai_basenpc.h +++ b/sp/src/game/server/ai_basenpc.h @@ -1731,8 +1731,8 @@ public: virtual bool DoHolster(void); virtual bool DoUnholster(void); - virtual bool ShouldUnholsterWeapon() { return GetState() == NPC_STATE_COMBAT; } - virtual bool CanUnholsterWeapon() { return IsWeaponHolstered(); } + virtual bool ShouldUnholsterWeapon(); + virtual bool CanUnholsterWeapon(); void InputGiveWeaponHolstered( inputdata_t &inputdata ); void InputChangeWeapon( inputdata_t &inputdata ); diff --git a/sp/src/game/server/hl2/npc_metropolice.cpp b/sp/src/game/server/hl2/npc_metropolice.cpp index b3b0e5d1..31e86f37 100644 --- a/sp/src/game/server/hl2/npc_metropolice.cpp +++ b/sp/src/game/server/hl2/npc_metropolice.cpp @@ -3899,6 +3899,15 @@ int CNPC_MetroPolice::SelectScheduleNoDirectEnemy() return SCHED_METROPOLICE_SMASH_PROP; } +#ifdef MAPBASE + // If you see your enemy and your weapon is holstered, you're probably about to arm yourself. + // Wait and don't just charge in + if ( IsWeaponHolstered() && HasCondition(COND_SEE_ENEMY) ) + { + return SCHED_COMBAT_FACE; + } +#endif + return SCHED_METROPOLICE_CHASE_ENEMY; } diff --git a/sp/src/game/server/hl2/weapon_ar2.cpp b/sp/src/game/server/hl2/weapon_ar2.cpp index 6279c34d..5e12856c 100644 --- a/sp/src/game/server/hl2/weapon_ar2.cpp +++ b/sp/src/game/server/hl2/weapon_ar2.cpp @@ -156,6 +156,11 @@ acttable_t CWeaponAR2::m_acttable[] = { ACT_GESTURE_RELOAD, ACT_GESTURE_RELOAD_SMG1, true }, // { ACT_RANGE_ATTACK2, ACT_RANGE_ATTACK_AR2_GRENADE, true }, #endif + +#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES + { ACT_ARM, ACT_ARM_RIFLE, false }, + { ACT_DISARM, ACT_DISARM_RIFLE, false }, +#endif }; IMPLEMENT_ACTTABLE(CWeaponAR2); diff --git a/sp/src/game/server/hl2/weapon_crossbow.cpp b/sp/src/game/server/hl2/weapon_crossbow.cpp index eb492e97..87f45fce 100644 --- a/sp/src/game/server/hl2/weapon_crossbow.cpp +++ b/sp/src/game/server/hl2/weapon_crossbow.cpp @@ -697,6 +697,9 @@ acttable_t CWeaponCrossbow::m_acttable[] = { ACT_RANGE_AIM_LOW, ACT_RANGE_AIM_CROSSBOW_LOW, false }, { ACT_RELOAD_LOW, ACT_RELOAD_CROSSBOW_LOW, false }, { ACT_GESTURE_RELOAD, ACT_GESTURE_RELOAD_CROSSBOW, true }, + + { ACT_ARM, ACT_ARM_RIFLE, false }, + { ACT_DISARM, ACT_DISARM_RIFLE, false }, #else { ACT_WALK_AIM, ACT_WALK_AIM_RIFLE, true }, { ACT_WALK_CROUCH, ACT_WALK_CROUCH_RIFLE, true }, diff --git a/sp/src/game/server/hl2/weapon_rpg.cpp b/sp/src/game/server/hl2/weapon_rpg.cpp index 808b6e90..2efbd409 100644 --- a/sp/src/game/server/hl2/weapon_rpg.cpp +++ b/sp/src/game/server/hl2/weapon_rpg.cpp @@ -1415,6 +1415,11 @@ acttable_t CWeaponRPG::m_acttable[] = { ACT_RUN, ACT_RUN_RPG, true }, { ACT_RUN_CROUCH, ACT_RUN_CROUCH_RPG, true }, { ACT_COVER_LOW, ACT_COVER_LOW_RPG, true }, + +#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES + { ACT_ARM, ACT_ARM_RIFLE, false }, + { ACT_DISARM, ACT_DISARM_RIFLE, false }, +#endif }; IMPLEMENT_ACTTABLE(CWeaponRPG); diff --git a/sp/src/game/server/hl2/weapon_shotgun.cpp b/sp/src/game/server/hl2/weapon_shotgun.cpp index fb9ec215..44406dee 100644 --- a/sp/src/game/server/hl2/weapon_shotgun.cpp +++ b/sp/src/game/server/hl2/weapon_shotgun.cpp @@ -153,6 +153,11 @@ acttable_t CWeaponShotgun::m_acttable[] = { ACT_RANGE_ATTACK1_LOW, ACT_RANGE_ATTACK_SHOTGUN_LOW, true }, { ACT_RELOAD_LOW, ACT_RELOAD_SHOTGUN_LOW, false }, { ACT_GESTURE_RELOAD, ACT_GESTURE_RELOAD_SHOTGUN, false }, + +#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES + { ACT_ARM, ACT_ARM_RIFLE, false }, + { ACT_DISARM, ACT_DISARM_RIFLE, false }, +#endif }; IMPLEMENT_ACTTABLE(CWeaponShotgun); diff --git a/sp/src/game/server/hl2/weapon_smg1.cpp b/sp/src/game/server/hl2/weapon_smg1.cpp index 8e889851..b0c75a14 100644 --- a/sp/src/game/server/hl2/weapon_smg1.cpp +++ b/sp/src/game/server/hl2/weapon_smg1.cpp @@ -93,11 +93,6 @@ acttable_t CWeaponSMG1::m_acttable[] = { ACT_WALK, ACT_WALK_RIFLE, true }, { ACT_WALK_AIM, ACT_WALK_AIM_RIFLE, true }, - -#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES - { ACT_ARM, ACT_ARM_RIFLE, false }, - { ACT_DISARM, ACT_DISARM_RIFLE, false }, -#endif // Readiness activities (not aiming) { ACT_IDLE_RELAXED, ACT_IDLE_SMG1_RELAXED, false },//never aims @@ -139,6 +134,11 @@ acttable_t CWeaponSMG1::m_acttable[] = { ACT_RANGE_AIM_LOW, ACT_RANGE_AIM_SMG1_LOW, false }, { ACT_RELOAD_LOW, ACT_RELOAD_SMG1_LOW, false }, { ACT_GESTURE_RELOAD, ACT_GESTURE_RELOAD_SMG1, true }, + +#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES + { ACT_ARM, ACT_ARM_RIFLE, false }, + { ACT_DISARM, ACT_DISARM_RIFLE, false }, +#endif }; IMPLEMENT_ACTTABLE(CWeaponSMG1); From c53070b3224dc32b501cd636688aad843b1fd93b Mon Sep 17 00:00:00 2001 From: Alexander 'z33ky' Hirsch <1zeeky@gmail.com> Date: Mon, 18 Oct 2021 00:13:06 +0200 Subject: [PATCH 188/378] Fix gcc build errors & warnings --- sp/src/game/client/c_baseviewmodel.cpp | 2 +- sp/src/game/client/fx_impact.cpp | 2 +- sp/src/game/client/viewdebug.cpp | 2 +- sp/src/game/server/baseanimating.cpp | 2 +- sp/src/game/server/mapbase/ai_grenade.h | 13 +++++++------ 5 files changed, 11 insertions(+), 10 deletions(-) diff --git a/sp/src/game/client/c_baseviewmodel.cpp b/sp/src/game/client/c_baseviewmodel.cpp index b053ac1b..6e73e155 100644 --- a/sp/src/game/client/c_baseviewmodel.cpp +++ b/sp/src/game/client/c_baseviewmodel.cpp @@ -192,7 +192,7 @@ bool C_BaseViewModel::Interpolate( float currentTime ) } -inline bool C_BaseViewModel::ShouldFlipViewModel() +bool C_BaseViewModel::ShouldFlipViewModel() { #if defined(CSTRIKE_DLL) || defined (MAPBASE) // If cl_righthand is set, then we want them all right-handed. diff --git a/sp/src/game/client/fx_impact.cpp b/sp/src/game/client/fx_impact.cpp index 41893f7b..0ef81cc5 100644 --- a/sp/src/game/client/fx_impact.cpp +++ b/sp/src/game/client/fx_impact.cpp @@ -104,7 +104,7 @@ C_BaseAnimating *FX_AffectRagdolls_GetHit( Vector vecOrigin, Vector vecStart, in { // don't do this when lots of ragdolls are simulating if ( s_RagdollLRU.CountRagdolls(true) > 1 ) - return false; + return NULL; Ray_t shotRay; shotRay.Init( vecStart, vecOrigin ); diff --git a/sp/src/game/client/viewdebug.cpp b/sp/src/game/client/viewdebug.cpp index 0204a0ab..94988d9f 100644 --- a/sp/src/game/client/viewdebug.cpp +++ b/sp/src/game/client/viewdebug.cpp @@ -758,7 +758,7 @@ CON_COMMAND_F( r_screenoverlay_indexed, "Draw specified material as an overlay i } else { - Warning( "Format: r_screenoverlay_indexed %s\n" ); + Warning( "Format: r_screenoverlay_indexed []\n" ); } } #endif diff --git a/sp/src/game/server/baseanimating.cpp b/sp/src/game/server/baseanimating.cpp index 5d27044a..1db0693a 100644 --- a/sp/src/game/server/baseanimating.cpp +++ b/sp/src/game/server/baseanimating.cpp @@ -1948,7 +1948,7 @@ ConVar ai_setupbones_debug( "ai_setupbones_debug", "0", 0, "Shows that bones tha -inline bool CBaseAnimating::CanSkipAnimation( void ) +bool CBaseAnimating::CanSkipAnimation( void ) { if ( !sv_pvsskipanimation.GetBool() ) return false; diff --git a/sp/src/game/server/mapbase/ai_grenade.h b/sp/src/game/server/mapbase/ai_grenade.h index 69031d74..5f014fec 100644 --- a/sp/src/game/server/mapbase/ai_grenade.h +++ b/sp/src/game/server/mapbase/ai_grenade.h @@ -22,6 +22,7 @@ #include "gameweaponmanager.h" #include "hl2_gamerules.h" #include "weapon_physcannon.h" +#include "globalstate.h" #define COMBINE_AE_GREN_TOSS ( 7 ) @@ -117,7 +118,7 @@ public: } // Use secondary ammo as a way of checking if this is a weapon which can be alt-fired (e.g. AR2 or SMG) - virtual bool IsAltFireCapable() { return (GetActiveWeapon() && GetActiveWeapon()->UsesSecondaryAmmo()); } + virtual bool IsAltFireCapable() { return (this->GetActiveWeapon() && this->GetActiveWeapon()->UsesSecondaryAmmo()); } virtual bool IsGrenadeCapable() { return true; } inline bool HasGrenades() { return m_iNumGrenades > 0; } @@ -587,9 +588,9 @@ void CAI_GrenadeUser::DropGrenadeItemsOnDeath( const CTakeDamageInfo & { CBaseEntity *pItem; if (this->GetActiveWeapon() && FClassnameIs( this->GetActiveWeapon(), "weapon_smg1" )) - pItem = this->DropItem( "item_ammo_smg1_grenade", WorldSpaceCenter()+RandomVector(-4,4), RandomAngle(0,360) ); + pItem = this->DropItem( "item_ammo_smg1_grenade", this->WorldSpaceCenter()+RandomVector(-4,4), RandomAngle(0,360) ); else - pItem = this->DropItem( "item_ammo_ar2_altfire", WorldSpaceCenter() + RandomVector( -4, 4 ), RandomAngle( 0, 360 ) ); + pItem = this->DropItem( "item_ammo_ar2_altfire", this->WorldSpaceCenter() + RandomVector( -4, 4 ), RandomAngle( 0, 360 ) ); if ( pItem ) { @@ -629,14 +630,14 @@ void CAI_GrenadeUser::DropGrenadeItemsOnDeath( const CTakeDamageInfo & // Attempt to drop a grenade if ( pHL2GameRules->NPC_ShouldDropGrenade( pPlayer ) ) { - this->DropItem( "weapon_frag", WorldSpaceCenter()+RandomVector(-4,4), RandomAngle(0,360) ); + this->DropItem( "weapon_frag", this->WorldSpaceCenter()+RandomVector(-4,4), RandomAngle(0,360) ); pHL2GameRules->NPC_DroppedGrenade(); } } // if I was killed before I could finish throwing my grenade, drop // a grenade item that the player can retrieve. - if (GetActivity() == ACT_RANGE_ATTACK2 && ShouldDropInterruptedGrenades()) + if (this->GetActivity() == ACT_RANGE_ATTACK2 && ShouldDropInterruptedGrenades()) { if( m_iLastAnimEventHandled != COMBINE_AE_GREN_TOSS ) { @@ -644,7 +645,7 @@ void CAI_GrenadeUser::DropGrenadeItemsOnDeath( const CTakeDamageInfo & Vector vecStart; this->GetAttachment( GetGrenadeAttachment(), vecStart ); - CBaseEntity *pItem = DropItem( "weapon_frag", vecStart, RandomAngle(0,360) ); + CBaseEntity *pItem = this->DropItem( "weapon_frag", vecStart, RandomAngle(0,360) ); if ( pItem ) { From ade8fe0d02a1333d0ec73a3b664f87e60f2af8af Mon Sep 17 00:00:00 2001 From: Blixibon Date: Mon, 18 Oct 2021 11:27:20 -0500 Subject: [PATCH 189/378] Added yaw locking to climbing navigation --- sp/src/game/server/ai_motor.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/sp/src/game/server/ai_motor.cpp b/sp/src/game/server/ai_motor.cpp index 0db2c6c5..c9c6fb8e 100644 --- a/sp/src/game/server/ai_motor.cpp +++ b/sp/src/game/server/ai_motor.cpp @@ -450,6 +450,20 @@ AIMoveResult_t CAI_Motor::MoveClimbExecute( const Vector &climbDest, const Vecto // -------------------------------------------- SetIdealYawAndUpdate( yaw ); +#ifdef MAPBASE + // Lock the yaw if we're in position + if ( UTIL_AngleMod( yaw ) == UTIL_AngleMod( GetLocalAngles().y ) ) + { + SetYawLocked( true ); + } + else if ( IsYawLocked() ) + { + // We're in a different position now. Unlock the yaw and update it + SetYawLocked( false ); + UpdateYaw( -1 ); + } +#endif + return AIMR_OK; } @@ -465,8 +479,7 @@ void CAI_Motor::MoveClimbStop() GetOuter()->SetDesiredWeaponState( DESIREDWEAPONSTATE_IGNORE ); // Unlock yaw - // TODO: Add yaw locking for when climbing is paused - //SetYawLocked( false ); + SetYawLocked( false ); #endif GetOuter()->RemoveFlag( FL_FLY ); From 3cd6f2e5816bc43ae6dcc2a740bfca13023bbb65 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Mon, 18 Oct 2021 11:33:01 -0500 Subject: [PATCH 190/378] Allowed Alyx to fly properly --- sp/src/game/server/hl2/npc_alyx_episodic.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sp/src/game/server/hl2/npc_alyx_episodic.cpp b/sp/src/game/server/hl2/npc_alyx_episodic.cpp index cdeb8f6b..01a64dea 100644 --- a/sp/src/game/server/hl2/npc_alyx_episodic.cpp +++ b/sp/src/game/server/hl2/npc_alyx_episodic.cpp @@ -156,6 +156,8 @@ ConVar npc_alyx_crouch( "npc_alyx_crouch", "1" ); #ifdef MAPBASE ConVar npc_alyx_interact_manhacks( "npc_alyx_interact_manhacks", "1" ); ConVar npc_alyx_interact_turrets( "npc_alyx_interact_turrets", "0" ); + +ConVar npc_alyx_allow_fly( "npc_alyx_allow_fly", "0", FCVAR_NONE, "Allows Alyx to use FL_FLY outside of scripted sequences, actbusy, or navigation." ); #endif // global pointer to Alyx for fast lookups @@ -885,7 +887,11 @@ void CNPC_Alyx::GatherConditions() // ROBIN: This was here to solve a problem in a playtest. We've since found what we think was the cause. // It's a useful piece of debug to have lying there, so I've left it in. - if ( (GetFlags() & FL_FLY) && m_NPCState != NPC_STATE_SCRIPT && !m_ActBusyBehavior.IsActive() && !m_PassengerBehavior.IsEnabled() ) + if ( (GetFlags() & FL_FLY) && m_NPCState != NPC_STATE_SCRIPT && !m_ActBusyBehavior.IsActive() && !m_PassengerBehavior.IsEnabled() +#ifdef MAPBASE + && GetNavType() != NAV_CLIMB && !npc_alyx_allow_fly.GetBool() +#endif + ) { Warning( "Removed FL_FLY from Alyx, who wasn't running a script or actbusy. Time %.2f, map %s.\n", gpGlobals->curtime, STRING(gpGlobals->mapname) ); RemoveFlag( FL_FLY ); From a5c0091588211c8307d0449110b3dfb0f6587ba9 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Mon, 18 Oct 2021 11:37:06 -0500 Subject: [PATCH 191/378] Fixed metrocop unholster behavior --- sp/src/game/server/hl2/npc_metropolice.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/sp/src/game/server/hl2/npc_metropolice.cpp b/sp/src/game/server/hl2/npc_metropolice.cpp index 31e86f37..9d8e0b96 100644 --- a/sp/src/game/server/hl2/npc_metropolice.cpp +++ b/sp/src/game/server/hl2/npc_metropolice.cpp @@ -1537,7 +1537,12 @@ void CNPC_MetroPolice::OnUpdateShotRegulator( ) BaseClass::OnUpdateShotRegulator(); // FIXME: This code (except the burst interval) could be used for all weapon types +#ifdef MAPBASE + // Only if we actually have the pistol out + if ( EntIsClass( GetActiveWeapon(), gm_isz_class_Pistol ) ) +#else if( Weapon_OwnsThisType( "weapon_pistol" ) ) +#endif { if ( m_nBurstMode == BURST_NOT_ACTIVE ) { @@ -3900,9 +3905,9 @@ int CNPC_MetroPolice::SelectScheduleNoDirectEnemy() } #ifdef MAPBASE - // If you see your enemy and your weapon is holstered, you're probably about to arm yourself. - // Wait and don't just charge in - if ( IsWeaponHolstered() && HasCondition(COND_SEE_ENEMY) ) + // If you see your enemy and you're still arming yourself, wait and don't just charge in + // (if your weapon is holstered, you're probably about to arm yourself) + if ( HasCondition( COND_SEE_ENEMY ) && (IsWeaponHolstered() || FindGestureLayer( TranslateActivity( ACT_ARM ) )) ) { return SCHED_COMBAT_FACE; } From b2c0ab41c085e2ebd42e2023d1d56959375fe08c Mon Sep 17 00:00:00 2001 From: samisalreadytaken <46823719+samisalreadytaken@users.noreply.github.com> Date: Sat, 23 Oct 2021 18:45:05 +0300 Subject: [PATCH 192/378] Fix format string vulnerabilities --- sp/src/game/client/vgui_debugoverlaypanel.cpp | 4 ++-- sp/src/game/shared/mapbase/vscript_funcs_shared.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sp/src/game/client/vgui_debugoverlaypanel.cpp b/sp/src/game/client/vgui_debugoverlaypanel.cpp index c3734147..2460ffa0 100644 --- a/sp/src/game/client/vgui_debugoverlaypanel.cpp +++ b/sp/src/game/client/vgui_debugoverlaypanel.cpp @@ -129,7 +129,7 @@ void CDebugOverlay::Paint() { float xPos = screenPos[0]; float yPos = screenPos[1]+ (pCurrText->lineOffset*13); // Line spacing; - g_pMatSystemSurface->DrawColoredText( m_hFont, xPos, yPos, r, g, b, a, pCurrText->text ); + g_pMatSystemSurface->DrawColoredText( m_hFont, xPos, yPos, r, g, b, a, "%s", pCurrText->text ); } } else @@ -138,7 +138,7 @@ void CDebugOverlay::Paint() { float xPos = screenPos[0]; float yPos = screenPos[1]+ (pCurrText->lineOffset*13); // Line spacing; - g_pMatSystemSurface->DrawColoredText( m_hFont, xPos, yPos, r, g, b, a, pCurrText->text ); + g_pMatSystemSurface->DrawColoredText( m_hFont, xPos, yPos, r, g, b, a, "%s", pCurrText->text ); } } } diff --git a/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp b/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp index aab303d8..34729186 100644 --- a/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp +++ b/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp @@ -908,7 +908,7 @@ bool ScriptIsClient() // Notification printing on the right edge of the screen void NPrint( int pos, const char* fmt ) { - engine->Con_NPrintf(pos, fmt); + engine->Con_NPrintf( pos, "%s", fmt ); } void NXPrint( int pos, int r, int g, int b, bool fixed, float ftime, const char* fmt ) @@ -922,7 +922,7 @@ void NXPrint( int pos, int r, int g, int b, bool fixed, float ftime, const char* info.color[2] = b / 255.f; info.fixed_width_font = fixed; - engine->Con_NXPrintf( &info, fmt ); + engine->Con_NXPrintf( &info, "%s", fmt ); } static float IntervalPerTick() From 74d219add46bfc5bf803bcd8f19682dd3d3bb40c Mon Sep 17 00:00:00 2001 From: samisalreadytaken <46823719+samisalreadytaken@users.noreply.github.com> Date: Sat, 23 Oct 2021 18:45:15 +0300 Subject: [PATCH 193/378] Fix buffer overflow exploit --- sp/src/game/client/hud_closecaption.cpp | 22 ++++++++++++++-------- sp/src/game/client/hud_closecaption.h | 2 +- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/sp/src/game/client/hud_closecaption.cpp b/sp/src/game/client/hud_closecaption.cpp index 9b9c0c11..e2d718c9 100644 --- a/sp/src/game/client/hud_closecaption.cpp +++ b/sp/src/game/client/hud_closecaption.cpp @@ -1302,7 +1302,7 @@ void CHudCloseCaption::Reset( void ) Unlock(); } -bool CHudCloseCaption::SplitCommand( wchar_t const **ppIn, wchar_t *cmd, wchar_t *args ) const +bool CHudCloseCaption::SplitCommand( wchar_t const **ppIn, wchar_t *cmd, wchar_t *args, int size ) const { const wchar_t *in = *ppIn; const wchar_t *oldin = in; @@ -1317,8 +1317,11 @@ bool CHudCloseCaption::SplitCommand( wchar_t const **ppIn, wchar_t *cmd, wchar_t cmd[ 0 ]= 0; wchar_t *out = cmd; in++; - while ( *in != L'\0' && *in != L':' && *in != L'>' && !isspace( *in ) ) + while ( *in != L'\0' && *in != L':' && *in != L'>' && !V_isspace( *in ) ) { + if ( (int)( out - cmd ) + (int)sizeof( wchar_t ) >= size ) + break; + *out++ = *in++; } *out = L'\0'; @@ -1333,6 +1336,9 @@ bool CHudCloseCaption::SplitCommand( wchar_t const **ppIn, wchar_t *cmd, wchar_t out = args; while ( *in != L'\0' && *in != L'>' ) { + if ( (int)( out - args ) + (int)sizeof( wchar_t ) >= size ) + break; + *out++ = *in++; } *out = L'\0'; @@ -1360,7 +1366,7 @@ bool CHudCloseCaption::GetFloatCommandValue( const wchar_t *stream, const wchar_ wchar_t cmd[ 256 ]; wchar_t args[ 256 ]; - if ( SplitCommand( &curpos, cmd, args ) ) + if ( SplitCommand( &curpos, cmd, args, sizeof( cmd ) ) ) { if ( !wcscmp( cmd, findcmd ) ) { @@ -1384,7 +1390,7 @@ bool CHudCloseCaption::StreamHasCommand( const wchar_t *stream, const wchar_t *f wchar_t cmd[ 256 ]; wchar_t args[ 256 ]; - if ( SplitCommand( &curpos, cmd, args ) ) + if ( SplitCommand( &curpos, cmd, args, sizeof( cmd ) ) ) { if ( !wcscmp( cmd, findcmd ) ) { @@ -1423,7 +1429,7 @@ bool CHudCloseCaption::StreamHasCommand( const wchar_t *stream, const wchar_t *s wchar_t cmd[ 256 ]; wchar_t args[ 256 ]; - if ( SplitCommand( &curpos, cmd, args ) ) + if ( SplitCommand( &curpos, cmd, args, sizeof( cmd ) ) ) { if ( !wcscmp( cmd, search ) ) { @@ -1515,7 +1521,7 @@ void CHudCloseCaption::Process( const wchar_t *stream, float duration, const cha const wchar_t *prevpos = curpos; - if ( SplitCommand( &curpos, cmd, args ) ) + if ( SplitCommand( &curpos, cmd, args, sizeof( cmd ) ) ) { if ( !wcscmp( cmd, L"delay" ) ) { @@ -1722,7 +1728,7 @@ void CHudCloseCaption::ComputeStreamWork( int available_width, CCloseCaptionItem wchar_t cmd[ 256 ]; wchar_t args[ 256 ]; - if ( SplitCommand( &curpos, cmd, args ) ) + if ( SplitCommand( &curpos, cmd, args, sizeof( cmd ) ) ) { if ( !wcscmp( cmd, L"cr" ) ) { @@ -1976,7 +1982,7 @@ bool CHudCloseCaption::GetNoRepeatValue( const wchar_t *caption, float &retval ) wchar_t cmd[ 256 ]; wchar_t args[ 256 ]; - if ( SplitCommand( &curpos, cmd, args ) ) + if ( SplitCommand( &curpos, cmd, args, sizeof( cmd ) ) ) { if ( !wcscmp( cmd, L"norepeat" ) ) { diff --git a/sp/src/game/client/hud_closecaption.h b/sp/src/game/client/hud_closecaption.h index b3bdae06..8688e60e 100644 --- a/sp/src/game/client/hud_closecaption.h +++ b/sp/src/game/client/hud_closecaption.h @@ -179,7 +179,7 @@ private: void DrawStream( wrect_t& rect, wrect_t &rcWindow, CCloseCaptionItem *item, int iFadeLine, float flFadeLineAlpha ); void ComputeStreamWork( int available_width, CCloseCaptionItem *item ); - bool SplitCommand( wchar_t const **ppIn, wchar_t *cmd, wchar_t *args ) const; + bool SplitCommand( wchar_t const **ppIn, wchar_t *cmd, wchar_t *args, int size ) const; bool StreamHasCommand( const wchar_t *stream, const wchar_t *findcmd ) const; bool GetFloatCommandValue( const wchar_t *stream, const wchar_t *findcmd, float& value ) const; From 65478e754d8e6111d840258a1dbe1c14e42311ad Mon Sep 17 00:00:00 2001 From: Blixibon Date: Wed, 27 Oct 2021 17:02:49 -0500 Subject: [PATCH 194/378] Added func_tank behavior to vortigaunts and Barney --- .../game/server/hl2/ai_behavior_functank.cpp | 22 +++++++++++++++++++ sp/src/game/server/hl2/ai_behavior_functank.h | 2 ++ sp/src/game/server/hl2/func_tank.cpp | 12 ++++++++-- sp/src/game/server/hl2/npc_alyx_episodic.cpp | 2 ++ sp/src/game/server/hl2/npc_alyx_episodic.h | 2 ++ sp/src/game/server/hl2/npc_citizen17.cpp | 3 ++- sp/src/game/server/hl2/npc_citizen17.h | 3 ++- .../game/server/hl2/npc_playercompanion.cpp | 4 ++++ sp/src/game/server/hl2/npc_playercompanion.h | 4 ++++ .../server/hl2/npc_vortigaunt_episodic.cpp | 9 ++++++++ 10 files changed, 59 insertions(+), 4 deletions(-) diff --git a/sp/src/game/server/hl2/ai_behavior_functank.cpp b/sp/src/game/server/hl2/ai_behavior_functank.cpp index f0a32601..89f79228 100644 --- a/sp/src/game/server/hl2/ai_behavior_functank.cpp +++ b/sp/src/game/server/hl2/ai_behavior_functank.cpp @@ -110,6 +110,28 @@ bool CAI_FuncTankBehavior::IsInterruptable( void ) return BaseClass::IsInterruptable(); } + +ConVar ai_tank_allow_expanded_npcs( "ai_tank_allow_expanded_npcs", "1", FCVAR_NONE, "Allows Father Grigori, Barney, and vortigaunts to automatically man func_tanks." ); + +//----------------------------------------------------------------------------- +// Purpose: +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CAI_FuncTankBehavior::CanManTank( CFuncTank *pTank, bool bForced ) +{ + if (!bForced) + { + // In order to prevent potential problems in existing maps, Father Grigori, Barney, and vortigaunts can be set to not automatically man func_tanks by default. + if (ai_tank_allow_expanded_npcs.GetBool() == false) + { + const char *pszClass = GetOuter()->GetClassname(); + if ( FStrEq( pszClass, "npc_monk" ) || FStrEq( pszClass, "npc_barney" ) || FStrEq( pszClass, "npc_vortigaunt" ) ) + return false; + } + } + + return true; +} #endif //----------------------------------------------------------------------------- diff --git a/sp/src/game/server/hl2/ai_behavior_functank.h b/sp/src/game/server/hl2/ai_behavior_functank.h index a9f19496..75d5b8df 100644 --- a/sp/src/game/server/hl2/ai_behavior_functank.h +++ b/sp/src/game/server/hl2/ai_behavior_functank.h @@ -51,6 +51,8 @@ public: void PrescheduleThink(); #ifdef MAPBASE bool IsInterruptable( void ); + + bool CanManTank( CFuncTank *pTank, bool bForced ); #endif Activity NPC_TranslateActivity( Activity activity ); diff --git a/sp/src/game/server/hl2/func_tank.cpp b/sp/src/game/server/hl2/func_tank.cpp index 963a0e54..c4462575 100644 --- a/sp/src/game/server/hl2/func_tank.cpp +++ b/sp/src/game/server/hl2/func_tank.cpp @@ -402,7 +402,11 @@ void CFuncTank::InputFindNPCToManTank( inputdata_t &inputdata ) { // Verify the npc has the func_tank controller behavior. CAI_FuncTankBehavior *pBehavior; +#ifdef MAPBASE + if ( pNPC->GetBehavior( &pBehavior ) && pBehavior->CanManTank( this, true ) ) +#else if ( pNPC->GetBehavior( &pBehavior ) ) +#endif { m_hController = pNPC; pBehavior->SetFuncTank( this ); @@ -439,7 +443,7 @@ void CFuncTank::InputTeleportNPCToManTank( inputdata_t &inputdata ) { // Verify the npc has the func_tank controller behavior. CAI_FuncTankBehavior *pBehavior; - if ( pNPC->GetBehavior( &pBehavior ) ) + if ( pNPC->GetBehavior( &pBehavior ) && pBehavior->CanManTank( this, true ) ) { Vector vecVec; QAngle angAng; @@ -512,7 +516,7 @@ void CFuncTank::InputForceNPCToManTank( inputdata_t &inputdata ) { // Verify the npc has the func_tank controller behavior. CAI_FuncTankBehavior *pBehavior; - if ( pNPC->GetBehavior( &pBehavior ) ) + if ( pNPC->GetBehavior( &pBehavior ) && pBehavior->CanManTank( this, true ) ) { // Set the forced condition pBehavior->SetCondition( CAI_FuncTankBehavior::COND_FUNCTANK_FORCED ); @@ -627,7 +631,11 @@ void CFuncTank::NPC_FindController( void ) continue; CAI_FuncTankBehavior *pBehavior; +#ifdef MAPBASE + if ( pNPC->GetBehavior( &pBehavior ) && pBehavior->CanManTank( this, false ) ) +#else if ( pNPC->GetBehavior( &pBehavior ) ) +#endif { // Don't mount the func_tank if your "enemy" is within X feet or it or the npc. CBaseEntity *pEnemy = pNPC->GetEnemy(); diff --git a/sp/src/game/server/hl2/npc_alyx_episodic.cpp b/sp/src/game/server/hl2/npc_alyx_episodic.cpp index 01a64dea..9df7a3ee 100644 --- a/sp/src/game/server/hl2/npc_alyx_episodic.cpp +++ b/sp/src/game/server/hl2/npc_alyx_episodic.cpp @@ -321,7 +321,9 @@ CNPC_Alyx *CNPC_Alyx::GetAlyx( void ) //========================================================= bool CNPC_Alyx::CreateBehaviors() { +#ifndef MAPBASE // Moved to CNPC_PlayerCompanion AddBehavior( &m_FuncTankBehavior ); +#endif bool result = BaseClass::CreateBehaviors(); return result; diff --git a/sp/src/game/server/hl2/npc_alyx_episodic.h b/sp/src/game/server/hl2/npc_alyx_episodic.h index 2f95099b..f24ddf67 100644 --- a/sp/src/game/server/hl2/npc_alyx_episodic.h +++ b/sp/src/game/server/hl2/npc_alyx_episodic.h @@ -235,7 +235,9 @@ private: bool m_bShouldHaveEMP; +#ifndef MAPBASE // Moved to CNPC_PlayerCompanion CAI_FuncTankBehavior m_FuncTankBehavior; +#endif COutputEvent m_OnFinishInteractWithObject; COutputEvent m_OnPlayerUse; diff --git a/sp/src/game/server/hl2/npc_citizen17.cpp b/sp/src/game/server/hl2/npc_citizen17.cpp index 62cd9ab2..ab7647c6 100644 --- a/sp/src/game/server/hl2/npc_citizen17.cpp +++ b/sp/src/game/server/hl2/npc_citizen17.cpp @@ -439,10 +439,11 @@ CSimpleSimTimer CNPC_Citizen::gm_PlayerSquadEvaluateTimer; bool CNPC_Citizen::CreateBehaviors() { BaseClass::CreateBehaviors(); - AddBehavior( &m_FuncTankBehavior ); #ifdef MAPBASE AddBehavior( &m_RappelBehavior ); AddBehavior( &m_PolicingBehavior ); +#else // Moved to CNPC_PlayerCompanion + AddBehavior( &m_FuncTankBehavior ); #endif return true; diff --git a/sp/src/game/server/hl2/npc_citizen17.h b/sp/src/game/server/hl2/npc_citizen17.h index 6828a664..5d23429d 100644 --- a/sp/src/game/server/hl2/npc_citizen17.h +++ b/sp/src/game/server/hl2/npc_citizen17.h @@ -370,7 +370,6 @@ private: #endif //----------------------------------------------------- - CAI_FuncTankBehavior m_FuncTankBehavior; #ifdef MAPBASE CAI_RappelBehavior m_RappelBehavior; CAI_PolicingBehavior m_PolicingBehavior; @@ -378,6 +377,8 @@ private: // Rappel virtual bool IsWaitingToRappel( void ) { return m_RappelBehavior.IsWaitingToRappel(); } void BeginRappel() { m_RappelBehavior.BeginRappel(); } +#else // Moved to CNPC_PlayerCompanion + CAI_FuncTankBehavior m_FuncTankBehavior; #endif CHandle m_hSavedFollowGoalEnt; diff --git a/sp/src/game/server/hl2/npc_playercompanion.cpp b/sp/src/game/server/hl2/npc_playercompanion.cpp index 7ed8553e..ed782f1b 100644 --- a/sp/src/game/server/hl2/npc_playercompanion.cpp +++ b/sp/src/game/server/hl2/npc_playercompanion.cpp @@ -211,6 +211,10 @@ bool CNPC_PlayerCompanion::CreateBehaviors() AddBehavior( &m_FollowBehavior ); AddBehavior( &m_LeadBehavior ); #endif//HL2_EPISODIC + +#ifdef MAPBASE + AddBehavior( &m_FuncTankBehavior ); +#endif return BaseClass::CreateBehaviors(); } diff --git a/sp/src/game/server/hl2/npc_playercompanion.h b/sp/src/game/server/hl2/npc_playercompanion.h index 2fe0b843..ce23058b 100644 --- a/sp/src/game/server/hl2/npc_playercompanion.h +++ b/sp/src/game/server/hl2/npc_playercompanion.h @@ -23,6 +23,7 @@ #endif #ifdef MAPBASE +#include "ai_behavior_functank.h" #include "mapbase/ai_grenade.h" #endif @@ -432,6 +433,9 @@ protected: CAI_OperatorBehavior m_OperatorBehavior; CAI_PassengerBehaviorCompanion m_PassengerBehavior; CAI_FearBehavior m_FearBehavior; +#endif +#ifdef MAPBASE + CAI_FuncTankBehavior m_FuncTankBehavior; #endif //----------------------------------------------------- diff --git a/sp/src/game/server/hl2/npc_vortigaunt_episodic.cpp b/sp/src/game/server/hl2/npc_vortigaunt_episodic.cpp index 7fdd89f2..839c18d9 100644 --- a/sp/src/game/server/hl2/npc_vortigaunt_episodic.cpp +++ b/sp/src/game/server/hl2/npc_vortigaunt_episodic.cpp @@ -2718,6 +2718,15 @@ void CNPC_Vortigaunt::OnSquishedGrub( const CBaseEntity *pGrub ) //----------------------------------------------------------------------------- void CNPC_Vortigaunt::AimGun( void ) { +#ifdef MAPBASE + // Use base for func_tank + if (m_FuncTankBehavior.IsRunning()) + { + BaseClass::AimGun(); + return; + } +#endif + // If our aim lock is on, don't bother if ( m_flAimDelay >= gpGlobals->curtime ) return; From 2eb12bcd5def11217ab41b9c774f928b72414538 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Wed, 27 Oct 2021 17:03:47 -0500 Subject: [PATCH 195/378] Fixed NPC death poses --- sp/src/game/client/c_baseanimating.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/sp/src/game/client/c_baseanimating.cpp b/sp/src/game/client/c_baseanimating.cpp index c5b54eef..13abe166 100644 --- a/sp/src/game/client/c_baseanimating.cpp +++ b/sp/src/game/client/c_baseanimating.cpp @@ -1990,6 +1990,10 @@ CollideType_t C_BaseAnimating::GetCollideType( void ) return BaseClass::GetCollideType(); } +#ifdef MAPBASE +ConVar ai_death_pose_enabled( "ai_death_pose_enabled", "1", FCVAR_NONE, "Toggles the death pose fix code, which cancels sequence transitions while a NPC is ragdolling." ); +#endif + //----------------------------------------------------------------------------- // Purpose: if the active sequence changes, keep track of the previous ones and decay them based on their decay rate //----------------------------------------------------------------------------- @@ -2006,6 +2010,14 @@ void C_BaseAnimating::MaintainSequenceTransitions( IBoneSetup &boneSetup, float return; } +#ifdef MAPBASE + if ( IsAboutToRagdoll() && ai_death_pose_enabled.GetBool() ) + { + m_nPrevNewSequenceParity = m_nNewSequenceParity; + return; + } +#endif + m_SequenceTransitioner.CheckForSequenceChange( boneSetup.GetStudioHdr(), GetSequence(), From 0e8b870e7d0deb9f51483ed72d2116ef0f6af700 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Wed, 27 Oct 2021 17:05:19 -0500 Subject: [PATCH 196/378] Re-enabled NPC gesture turning with a cvar to toggle it --- sp/src/game/server/ai_basenpc_schedule.cpp | 10 ++++++++++ sp/src/game/server/ai_blended_movement.cpp | 7 +++++++ 2 files changed, 17 insertions(+) diff --git a/sp/src/game/server/ai_basenpc_schedule.cpp b/sp/src/game/server/ai_basenpc_schedule.cpp index 7fc1c13b..bcb54c81 100644 --- a/sp/src/game/server/ai_basenpc_schedule.cpp +++ b/sp/src/game/server/ai_basenpc_schedule.cpp @@ -4317,6 +4317,15 @@ void CAI_BaseNPC::SetTurnActivity ( void ) float flYD; flYD = GetMotor()->DeltaIdealYaw(); +#ifdef MAPBASE + // Allow AddTurnGesture() to decide this + if (GetMotor()->AddTurnGesture( flYD )) + { + SetIdealActivity( ACT_IDLE ); + Remember( bits_MEMORY_TURNING ); + return; + } +#else // FIXME: unknown case, update yaw should catch these /* if (GetMotor()->AddTurnGesture( flYD )) @@ -4326,6 +4335,7 @@ void CAI_BaseNPC::SetTurnActivity ( void ) return; } */ +#endif if( flYD <= -80 && flYD >= -100 && SelectWeightedSequence( ACT_90_RIGHT ) != ACTIVITY_NOT_AVAILABLE ) { diff --git a/sp/src/game/server/ai_blended_movement.cpp b/sp/src/game/server/ai_blended_movement.cpp index d1b32d14..0a11c915 100644 --- a/sp/src/game/server/ai_blended_movement.cpp +++ b/sp/src/game/server/ai_blended_movement.cpp @@ -1640,10 +1640,17 @@ void CAI_BlendedMotor::MaintainTurnActivity( void ) ConVar scene_flatturn( "scene_flatturn", "1" ); +#ifdef MAPBASE +ConVar ai_turning_enabled( "ai_turning_enabled", "1", FCVAR_NONE, "Enables NPC turning, which was previously disabled by Valve at some point after 2004 due to a now-unknown major issue." ); +#endif + bool CAI_BlendedMotor::AddTurnGesture( float flYD ) { // some funky bug with human turn gestures, disable for now +#ifdef MAPBASE + if (!ai_turning_enabled.GetBool()) +#endif return false; // try using a turn gesture From 833f0b0823419d6343edd943d89804a533f49f56 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Wed, 27 Oct 2021 17:10:31 -0500 Subject: [PATCH 197/378] Added a bajillion new activities --- sp/src/game/server/ai_activity.cpp | 184 +++++++++++++++++++++ sp/src/game/server/hl2/weapon_357.cpp | 5 + sp/src/game/server/hl2/weapon_ar2.cpp | 14 +- sp/src/game/server/hl2/weapon_crossbow.cpp | 5 + sp/src/game/server/hl2/weapon_crowbar.cpp | 3 + sp/src/game/server/hl2/weapon_pistol.cpp | 17 ++ sp/src/game/server/hl2/weapon_rpg.cpp | 10 +- sp/src/game/server/hl2/weapon_shotgun.cpp | 61 ++++++- sp/src/game/server/hl2/weapon_smg1.cpp | 10 ++ sp/src/game/shared/activitylist.cpp | 67 ++++++++ sp/src/game/shared/ai_activity.h | 74 +++++++++ 11 files changed, 444 insertions(+), 6 deletions(-) diff --git a/sp/src/game/server/ai_activity.cpp b/sp/src/game/server/ai_activity.cpp index c467ddc4..f62e38db 100644 --- a/sp/src/game/server/ai_activity.cpp +++ b/sp/src/game/server/ai_activity.cpp @@ -2183,6 +2183,8 @@ void CAI_BaseNPC::InitDefaultActivitySR(void) ADD_ACTIVITY_TO_SR( ACT_RELOAD_AR2_LOW ); ADD_ACTIVITY_TO_SR( ACT_GESTURE_RELOAD_AR2 ); + + ADD_ACTIVITY_TO_SR( ACT_COVER_AR2_LOW ); #endif #ifdef SHARED_COMBINE_ACTIVITIES @@ -2245,14 +2247,42 @@ void CAI_BaseNPC::InitDefaultActivitySR(void) ADD_ACTIVITY_TO_SR( ACT_WALK_AIM_PISTOL_STIMULATED ); ADD_ACTIVITY_TO_SR( ACT_RUN_AIM_PISTOL_STIMULATED ); + ADD_ACTIVITY_TO_SR( ACT_WALK_CROUCH_PISTOL ); + ADD_ACTIVITY_TO_SR( ACT_WALK_CROUCH_AIM_PISTOL ); + ADD_ACTIVITY_TO_SR( ACT_RUN_CROUCH_PISTOL ); + ADD_ACTIVITY_TO_SR( ACT_RUN_CROUCH_AIM_PISTOL ); + + ADD_ACTIVITY_TO_SR( ACT_IDLE_SHOTGUN ); + ADD_ACTIVITY_TO_SR( ACT_WALK_SHOTGUN ); + ADD_ACTIVITY_TO_SR( ACT_RUN_SHOTGUN ); + + ADD_ACTIVITY_TO_SR( ACT_COVER_SHOTGUN_LOW ); + ADD_ACTIVITY_TO_SR( ACT_RANGE_AIM_SHOTGUN_LOW ); + + ADD_ACTIVITY_TO_SR( ACT_WALK_SHOTGUN_RELAXED ); + ADD_ACTIVITY_TO_SR( ACT_WALK_SHOTGUN_STIMULATED ); + ADD_ACTIVITY_TO_SR( ACT_RUN_SHOTGUN_RELAXED ); + ADD_ACTIVITY_TO_SR( ACT_RUN_SHOTGUN_STIMULATED ); + + ADD_ACTIVITY_TO_SR( ACT_IDLE_AIM_SHOTGUN_STIMULATED ); + ADD_ACTIVITY_TO_SR( ACT_WALK_AIM_SHOTGUN_STIMULATED ); + ADD_ACTIVITY_TO_SR( ACT_RUN_AIM_SHOTGUN_STIMULATED ); + ADD_ACTIVITY_TO_SR( ACT_RANGE_AIM_RPG_LOW ); ADD_ACTIVITY_TO_SR( ACT_RANGE_ATTACK_RPG_LOW ); + ADD_ACTIVITY_TO_SR( ACT_GESTURE_RANGE_ATTACK_RPG ); ADD_ACTIVITY_TO_SR( ACT_RUN_PACKAGE ); ADD_ACTIVITY_TO_SR( ACT_RUN_SUITCASE ); ADD_ACTIVITY_TO_SR( ACT_ARM_RIFLE ); + ADD_ACTIVITY_TO_SR( ACT_ARM_SHOTGUN ); + ADD_ACTIVITY_TO_SR( ACT_ARM_RPG ); + ADD_ACTIVITY_TO_SR( ACT_ARM_MELEE ); ADD_ACTIVITY_TO_SR( ACT_DISARM_RIFLE ); + ADD_ACTIVITY_TO_SR( ACT_DISARM_SHOTGUN ); + ADD_ACTIVITY_TO_SR( ACT_DISARM_RPG ); + ADD_ACTIVITY_TO_SR( ACT_DISARM_MELEE ); #endif #ifdef EXPANDED_NAVIGATION_ACTIVITIES @@ -2263,4 +2293,158 @@ void CAI_BaseNPC::InitDefaultActivitySR(void) ADD_ACTIVITY_TO_SR( ACT_CLIMB_MOUNT_BOTTOM ); ADD_ACTIVITY_TO_SR( ACT_CLIMB_DISMOUNT_BOTTOM ); #endif + +#ifdef EXPANDED_HL2_COVER_ACTIVITIES + ADD_ACTIVITY_TO_SR( ACT_RANGE_ATTACK1_MED ); + ADD_ACTIVITY_TO_SR( ACT_RANGE_ATTACK2_MED ); + ADD_ACTIVITY_TO_SR( ACT_RANGE_AIM_MED ); + + ADD_ACTIVITY_TO_SR( ACT_RANGE_ATTACK_AR2_MED ); + ADD_ACTIVITY_TO_SR( ACT_RANGE_ATTACK_SMG1_MED ); + ADD_ACTIVITY_TO_SR( ACT_RANGE_ATTACK_SHOTGUN_MED ); + ADD_ACTIVITY_TO_SR( ACT_RANGE_ATTACK_PISTOL_MED ); + ADD_ACTIVITY_TO_SR( ACT_RANGE_ATTACK_RPG_MED ); + ADD_ACTIVITY_TO_SR( ACT_RANGE_ATTACK_REVOLVER_MED ); + ADD_ACTIVITY_TO_SR( ACT_RANGE_ATTACK_CROSSBOW_MED ); + + ADD_ACTIVITY_TO_SR( ACT_RANGE_AIM_AR2_MED ); + ADD_ACTIVITY_TO_SR( ACT_RANGE_AIM_SMG1_MED ); + ADD_ACTIVITY_TO_SR( ACT_RANGE_AIM_SHOTGUN_MED ); + ADD_ACTIVITY_TO_SR( ACT_RANGE_AIM_PISTOL_MED ); + ADD_ACTIVITY_TO_SR( ACT_RANGE_AIM_RPG_MED ); + ADD_ACTIVITY_TO_SR( ACT_RANGE_AIM_REVOLVER_MED ); + ADD_ACTIVITY_TO_SR( ACT_RANGE_AIM_CROSSBOW_MED ); + + ADD_ACTIVITY_TO_SR( ACT_COVER_WALL_R ); + ADD_ACTIVITY_TO_SR( ACT_COVER_WALL_L ); + ADD_ACTIVITY_TO_SR( ACT_COVER_WALL_LOW_R ); + ADD_ACTIVITY_TO_SR( ACT_COVER_WALL_LOW_L ); + + ADD_ACTIVITY_TO_SR( ACT_COVER_WALL_R_RIFLE ); + ADD_ACTIVITY_TO_SR( ACT_COVER_WALL_L_RIFLE ); + ADD_ACTIVITY_TO_SR( ACT_COVER_WALL_LOW_R_RIFLE ); + ADD_ACTIVITY_TO_SR( ACT_COVER_WALL_LOW_L_RIFLE ); + + ADD_ACTIVITY_TO_SR( ACT_COVER_WALL_R_PISTOL ); + ADD_ACTIVITY_TO_SR( ACT_COVER_WALL_L_PISTOL ); + ADD_ACTIVITY_TO_SR( ACT_COVER_WALL_LOW_R_PISTOL ); + ADD_ACTIVITY_TO_SR( ACT_COVER_WALL_LOW_L_PISTOL ); +#endif } + +#ifdef MAPBASE +//----------------------------------------------------------------------------- +// Purpose: This is a multi-purpose table which links NPC activities to their gesture variants. +//----------------------------------------------------------------------------- +CAI_BaseNPC::actlink_t CAI_BaseNPC::gm_ActivityGestureLinks[] = +{ + { ACT_RANGE_ATTACK1, ACT_GESTURE_RANGE_ATTACK1 }, + { ACT_RANGE_ATTACK2, ACT_GESTURE_RANGE_ATTACK2 }, + { ACT_MELEE_ATTACK1, ACT_GESTURE_MELEE_ATTACK1 }, + { ACT_MELEE_ATTACK2, ACT_GESTURE_MELEE_ATTACK2 }, + { ACT_RELOAD, ACT_GESTURE_RELOAD }, + + { ACT_RANGE_ATTACK1_LOW, ACT_GESTURE_RANGE_ATTACK1 }, // NOTE: ACT_GESTURE_RANGE_ATTACK1_LOW exists, but isn't used + { ACT_RANGE_ATTACK2_LOW, ACT_GESTURE_RANGE_ATTACK2 }, // NOTE: ACT_GESTURE_RANGE_ATTACK2_LOW exists, but isn't used + { ACT_RELOAD_LOW, ACT_GESTURE_RELOAD }, + + { ACT_MELEE_ATTACK_SWING, ACT_GESTURE_MELEE_ATTACK_SWING }, + + // ----------------------------------------------------------- + + { ACT_RANGE_ATTACK_AR2, ACT_GESTURE_RANGE_ATTACK_AR2 }, + { ACT_RANGE_ATTACK_AR2_LOW, ACT_GESTURE_RANGE_ATTACK_AR2 }, + { ACT_RANGE_ATTACK_SMG1, ACT_GESTURE_RANGE_ATTACK_SMG1 }, + { ACT_RANGE_ATTACK_SMG1_LOW, ACT_GESTURE_RANGE_ATTACK_SMG1 }, + { ACT_RANGE_ATTACK_SHOTGUN, ACT_GESTURE_RANGE_ATTACK_SHOTGUN }, + { ACT_RANGE_ATTACK_SHOTGUN_LOW, ACT_GESTURE_RANGE_ATTACK_SHOTGUN }, + { ACT_RANGE_ATTACK_PISTOL, ACT_GESTURE_RANGE_ATTACK_PISTOL }, + { ACT_RANGE_ATTACK_PISTOL_LOW, ACT_GESTURE_RANGE_ATTACK_PISTOL }, + + // ----------------------------------------------------------- + + { ACT_SMALL_FLINCH, ACT_GESTURE_SMALL_FLINCH }, + { ACT_BIG_FLINCH, ACT_GESTURE_BIG_FLINCH }, + { ACT_FLINCH_HEAD, ACT_GESTURE_FLINCH_HEAD }, + { ACT_FLINCH_CHEST, ACT_GESTURE_FLINCH_CHEST }, + { ACT_FLINCH_STOMACH, ACT_GESTURE_FLINCH_STOMACH }, + { ACT_FLINCH_LEFTARM, ACT_GESTURE_FLINCH_LEFTARM }, + { ACT_FLINCH_RIGHTARM, ACT_GESTURE_FLINCH_RIGHTARM }, + { ACT_FLINCH_LEFTLEG, ACT_GESTURE_FLINCH_LEFTLEG }, + { ACT_FLINCH_RIGHTLEG, ACT_GESTURE_FLINCH_RIGHTLEG }, + + // ----------------------------------------------------------- + +#if AR2_ACTIVITY_FIX == 1 + { ACT_RELOAD_AR2, ACT_GESTURE_RELOAD_AR2 }, + { ACT_RELOAD_AR2_LOW, ACT_GESTURE_RELOAD_AR2 }, +#endif + { ACT_RELOAD_SMG1, ACT_GESTURE_RELOAD_SMG1 }, + { ACT_RELOAD_SMG1_LOW, ACT_GESTURE_RELOAD_SMG1 }, + { ACT_RELOAD_SHOTGUN, ACT_GESTURE_RELOAD_SHOTGUN }, + { ACT_RELOAD_SHOTGUN_LOW, ACT_GESTURE_RELOAD_SHOTGUN }, + { ACT_RELOAD_PISTOL, ACT_GESTURE_RELOAD_PISTOL }, + { ACT_RELOAD_PISTOL_LOW, ACT_GESTURE_RELOAD_PISTOL }, + +#ifdef SHARED_COMBINE_ACTIVITIES + { ACT_SPECIAL_ATTACK1, ACT_GESTURE_SPECIAL_ATTACK1 }, + { ACT_SPECIAL_ATTACK2, ACT_GESTURE_SPECIAL_ATTACK2 }, + { ACT_COMBINE_THROW_GRENADE, ACT_GESTURE_COMBINE_THROW_GRENADE }, + { ACT_COMBINE_AR2_ALTFIRE, ACT_GESTURE_COMBINE_AR2_ALTFIRE }, + + { ACT_SIGNAL_ADVANCE, ACT_GESTURE_SIGNAL_ADVANCE }, + { ACT_SIGNAL_FORWARD, ACT_GESTURE_SIGNAL_FORWARD }, + { ACT_SIGNAL_GROUP, ACT_GESTURE_SIGNAL_GROUP }, + { ACT_SIGNAL_HALT, ACT_GESTURE_SIGNAL_HALT }, + { ACT_SIGNAL_LEFT, ACT_GESTURE_SIGNAL_LEFT }, + { ACT_SIGNAL_RIGHT, ACT_GESTURE_SIGNAL_RIGHT }, + { ACT_SIGNAL_TAKECOVER, ACT_GESTURE_SIGNAL_TAKECOVER }, +#endif + +#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES + { ACT_RANGE_ATTACK_REVOLVER, ACT_GESTURE_RANGE_ATTACK_REVOLVER }, + { ACT_RANGE_ATTACK_REVOLVER_LOW, ACT_GESTURE_RANGE_ATTACK_REVOLVER }, + { ACT_RANGE_ATTACK_CROSSBOW, ACT_GESTURE_RANGE_ATTACK_CROSSBOW }, + { ACT_RANGE_ATTACK_CROSSBOW_LOW, ACT_GESTURE_RANGE_ATTACK_CROSSBOW }, + { ACT_RANGE_ATTACK_RPG, ACT_GESTURE_RANGE_ATTACK_RPG }, + { ACT_RANGE_ATTACK_RPG_LOW, ACT_GESTURE_RANGE_ATTACK_RPG }, + + { ACT_RELOAD_REVOLVER, ACT_GESTURE_RELOAD_REVOLVER }, + { ACT_RELOAD_REVOLVER_LOW, ACT_GESTURE_RELOAD_REVOLVER }, + { ACT_RELOAD_CROSSBOW, ACT_GESTURE_RELOAD_CROSSBOW }, + { ACT_RELOAD_CROSSBOW_LOW, ACT_GESTURE_RELOAD_CROSSBOW }, +#endif +}; + +Activity CAI_BaseNPC::GetGestureVersionOfActivity( Activity inActivity ) +{ + actlink_t *pTable = gm_ActivityGestureLinks; + int actCount = ARRAYSIZE( gm_ActivityGestureLinks ); + + for ( int i = 0; i < actCount; i++, pTable++ ) + { + if ( inActivity == pTable->sequence ) + { + return pTable->gesture; + } + } + + return ACT_INVALID; +} + +Activity CAI_BaseNPC::GetSequenceVersionOfGesture( Activity inActivity ) +{ + actlink_t *pTable = gm_ActivityGestureLinks; + int actCount = ARRAYSIZE( gm_ActivityGestureLinks ); + + for (int i = 0; i < actCount; i++, pTable++) + { + if (inActivity == pTable->gesture) + { + return pTable->sequence; + } + } + + return ACT_INVALID; +} +#endif diff --git a/sp/src/game/server/hl2/weapon_357.cpp b/sp/src/game/server/hl2/weapon_357.cpp index dc8e4483..16c57991 100644 --- a/sp/src/game/server/hl2/weapon_357.cpp +++ b/sp/src/game/server/hl2/weapon_357.cpp @@ -193,6 +193,11 @@ acttable_t CWeapon357::m_acttable[] = { ACT_READINESS_RELAXED_TO_STIMULATED_WALK, ACT_READINESS_PISTOL_RELAXED_TO_STIMULATED_WALK, false }, { ACT_READINESS_AGITATED_TO_STIMULATED, ACT_READINESS_PISTOL_AGITATED_TO_STIMULATED, false }, { ACT_READINESS_STIMULATED_TO_RELAXED, ACT_READINESS_PISTOL_STIMULATED_TO_RELAXED, false }, + +#ifdef EXPANDED_HL2_COVER_ACTIVITIES + { ACT_RANGE_AIM_MED, ACT_RANGE_AIM_REVOLVER_MED, false }, + { ACT_RANGE_ATTACK1_MED, ACT_RANGE_ATTACK_REVOLVER_MED, true }, +#endif }; diff --git a/sp/src/game/server/hl2/weapon_ar2.cpp b/sp/src/game/server/hl2/weapon_ar2.cpp index 5e12856c..35305f59 100644 --- a/sp/src/game/server/hl2/weapon_ar2.cpp +++ b/sp/src/game/server/hl2/weapon_ar2.cpp @@ -96,11 +96,11 @@ acttable_t CWeaponAR2::m_acttable[] = { ACT_WALK_CROUCH, ACT_WALK_CROUCH_RIFLE, true }, { ACT_WALK_CROUCH_AIM, ACT_WALK_CROUCH_AIM_RIFLE, true }, { ACT_RUN, ACT_RUN_AR2, true }, - { ACT_RUN_AIM, ACT_RUN_AIM_RIFLE, true }, + { ACT_RUN_AIM, ACT_RUN_AIM_AR2, true }, { ACT_RUN_CROUCH, ACT_RUN_CROUCH_RIFLE, true }, { ACT_RUN_CROUCH_AIM, ACT_RUN_CROUCH_AIM_RIFLE, true }, { ACT_GESTURE_RANGE_ATTACK1, ACT_GESTURE_RANGE_ATTACK_AR2, false }, - { ACT_COVER_LOW, ACT_COVER_SMG1_LOW, false }, + { ACT_COVER_LOW, ACT_COVER_AR2_LOW, true }, { ACT_RANGE_AIM_LOW, ACT_RANGE_AIM_AR2_LOW, false }, { ACT_RANGE_ATTACK1_LOW, ACT_RANGE_ATTACK_AR2_LOW, false }, { ACT_RELOAD_LOW, ACT_RELOAD_AR2_LOW, false }, @@ -161,6 +161,16 @@ acttable_t CWeaponAR2::m_acttable[] = { ACT_ARM, ACT_ARM_RIFLE, false }, { ACT_DISARM, ACT_DISARM_RIFLE, false }, #endif + +#ifdef EXPANDED_HL2_COVER_ACTIVITIES + { ACT_RANGE_AIM_MED, ACT_RANGE_AIM_AR2_MED, false }, + { ACT_RANGE_ATTACK1_MED, ACT_RANGE_ATTACK_AR2_MED, true }, + + { ACT_COVER_WALL_R, ACT_COVER_WALL_R_RIFLE, true }, + { ACT_COVER_WALL_L, ACT_COVER_WALL_L_RIFLE, true }, + { ACT_COVER_WALL_LOW_R, ACT_COVER_WALL_LOW_R_RIFLE, true }, + { ACT_COVER_WALL_LOW_L, ACT_COVER_WALL_LOW_L_RIFLE, true }, +#endif }; IMPLEMENT_ACTTABLE(CWeaponAR2); diff --git a/sp/src/game/server/hl2/weapon_crossbow.cpp b/sp/src/game/server/hl2/weapon_crossbow.cpp index 87f45fce..f1b5009a 100644 --- a/sp/src/game/server/hl2/weapon_crossbow.cpp +++ b/sp/src/game/server/hl2/weapon_crossbow.cpp @@ -715,6 +715,11 @@ acttable_t CWeaponCrossbow::m_acttable[] = { ACT_RELOAD_LOW, ACT_RELOAD_SMG1_LOW, false }, { ACT_GESTURE_RELOAD, ACT_GESTURE_RELOAD_SMG1, true }, #endif + +#ifdef EXPANDED_HL2_COVER_ACTIVITIES + { ACT_RANGE_AIM_MED, ACT_RANGE_AIM_CROSSBOW_MED, false }, + { ACT_RANGE_ATTACK1_MED, ACT_RANGE_ATTACK_CROSSBOW_MED, true }, +#endif }; IMPLEMENT_ACTTABLE(CWeaponCrossbow); diff --git a/sp/src/game/server/hl2/weapon_crowbar.cpp b/sp/src/game/server/hl2/weapon_crowbar.cpp index e95c2dbb..1a6488c2 100644 --- a/sp/src/game/server/hl2/weapon_crowbar.cpp +++ b/sp/src/game/server/hl2/weapon_crowbar.cpp @@ -46,6 +46,9 @@ acttable_t CWeaponCrowbar::m_acttable[] = // Just so we don't have to implement more activities, re-use the MP acts { ACT_RUN, ACT_MP_RUN_MELEE, false }, { ACT_WALK, ACT_MP_WALK_MELEE, false }, + + { ACT_ARM, ACT_ARM_MELEE, false }, + { ACT_DISARM, ACT_DISARM_MELEE, false }, #endif }; diff --git a/sp/src/game/server/hl2/weapon_pistol.cpp b/sp/src/game/server/hl2/weapon_pistol.cpp index 417d1ee5..eff09cfe 100644 --- a/sp/src/game/server/hl2/weapon_pistol.cpp +++ b/sp/src/game/server/hl2/weapon_pistol.cpp @@ -240,6 +240,23 @@ acttable_t CWeaponPistol::m_acttable[] = { ACT_READINESS_AGITATED_TO_STIMULATED, ACT_READINESS_PISTOL_AGITATED_TO_STIMULATED, false }, { ACT_READINESS_STIMULATED_TO_RELAXED, ACT_READINESS_PISTOL_STIMULATED_TO_RELAXED, false }, #endif + +#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES + { ACT_WALK_CROUCH, ACT_WALK_CROUCH_PISTOL, true }, + { ACT_WALK_CROUCH_AIM, ACT_WALK_CROUCH_AIM_PISTOL, true }, + { ACT_RUN_CROUCH, ACT_RUN_CROUCH_PISTOL, true }, + { ACT_RUN_CROUCH_AIM, ACT_RUN_CROUCH_AIM_PISTOL, true }, +#endif + +#ifdef EXPANDED_HL2_COVER_ACTIVITIES + { ACT_RANGE_AIM_MED, ACT_RANGE_AIM_PISTOL_MED, false }, + { ACT_RANGE_ATTACK1_MED, ACT_RANGE_ATTACK_PISTOL_MED, true }, + + { ACT_COVER_WALL_R, ACT_COVER_WALL_R_PISTOL, true }, + { ACT_COVER_WALL_L, ACT_COVER_WALL_L_PISTOL, true }, + { ACT_COVER_WALL_LOW_R, ACT_COVER_WALL_LOW_R_PISTOL, true }, + { ACT_COVER_WALL_LOW_L, ACT_COVER_WALL_LOW_L_PISTOL, true }, +#endif }; diff --git a/sp/src/game/server/hl2/weapon_rpg.cpp b/sp/src/game/server/hl2/weapon_rpg.cpp index 2efbd409..72ee96f9 100644 --- a/sp/src/game/server/hl2/weapon_rpg.cpp +++ b/sp/src/game/server/hl2/weapon_rpg.cpp @@ -1402,6 +1402,7 @@ acttable_t CWeaponRPG::m_acttable[] = #ifdef EXPANDED_HL2_WEAPON_ACTIVITIES { ACT_RANGE_AIM_LOW, ACT_RANGE_AIM_RPG_LOW, false }, { ACT_RANGE_ATTACK1_LOW, ACT_RANGE_ATTACK_RPG_LOW, false }, + { ACT_GESTURE_RANGE_ATTACK1, ACT_GESTURE_RANGE_ATTACK_RPG, false }, #endif { ACT_IDLE_RELAXED, ACT_IDLE_RPG_RELAXED, true }, @@ -1417,8 +1418,13 @@ acttable_t CWeaponRPG::m_acttable[] = { ACT_COVER_LOW, ACT_COVER_LOW_RPG, true }, #ifdef EXPANDED_HL2_WEAPON_ACTIVITIES - { ACT_ARM, ACT_ARM_RIFLE, false }, - { ACT_DISARM, ACT_DISARM_RIFLE, false }, + { ACT_ARM, ACT_ARM_RPG, false }, + { ACT_DISARM, ACT_DISARM_RPG, false }, +#endif + +#ifdef EXPANDED_HL2_COVER_ACTIVITIES + { ACT_RANGE_AIM_MED, ACT_RANGE_AIM_RPG_MED, false }, + { ACT_RANGE_ATTACK1_MED, ACT_RANGE_ATTACK_RPG_MED, true }, #endif }; diff --git a/sp/src/game/server/hl2/weapon_shotgun.cpp b/sp/src/game/server/hl2/weapon_shotgun.cpp index 44406dee..a1a228c8 100644 --- a/sp/src/game/server/hl2/weapon_shotgun.cpp +++ b/sp/src/game/server/hl2/weapon_shotgun.cpp @@ -108,6 +108,57 @@ END_DATADESC() acttable_t CWeaponShotgun::m_acttable[] = { +#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES + // Note that ACT_IDLE_SHOTGUN_AGITATED seems to be a stand-in for ACT_IDLE_SHOTGUN on citizens, + // but that isn't acceptable for NPCs which don't use readiness activities. + { ACT_IDLE, ACT_IDLE_SHOTGUN, true }, + + { ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_SHOTGUN, true }, + { ACT_RELOAD, ACT_RELOAD_SHOTGUN, false }, + { ACT_WALK, ACT_WALK_SHOTGUN, true }, + { ACT_IDLE_ANGRY, ACT_IDLE_ANGRY_SHOTGUN, true }, + +// Readiness activities (not aiming) + { ACT_IDLE_RELAXED, ACT_IDLE_SHOTGUN_RELAXED, false },//never aims + { ACT_IDLE_STIMULATED, ACT_IDLE_SHOTGUN_STIMULATED, false }, + { ACT_IDLE_AGITATED, ACT_IDLE_ANGRY_SHOTGUN, false },//always aims + + { ACT_WALK_RELAXED, ACT_WALK_SHOTGUN_RELAXED, false },//never aims + { ACT_WALK_STIMULATED, ACT_WALK_SHOTGUN_STIMULATED, false }, + { ACT_WALK_AGITATED, ACT_WALK_AIM_SHOTGUN, false },//always aims + + { ACT_RUN_RELAXED, ACT_RUN_SHOTGUN_RELAXED, false },//never aims + { ACT_RUN_STIMULATED, ACT_RUN_SHOTGUN_STIMULATED, false }, + { ACT_RUN_AGITATED, ACT_RUN_AIM_SHOTGUN, false },//always aims + +// Readiness activities (aiming) + { ACT_IDLE_AIM_RELAXED, ACT_IDLE_SHOTGUN_RELAXED, false },//never aims + { ACT_IDLE_AIM_STIMULATED, ACT_IDLE_AIM_SHOTGUN_STIMULATED, false }, + { ACT_IDLE_AIM_AGITATED, ACT_IDLE_ANGRY_SHOTGUN, false },//always aims + + { ACT_WALK_AIM_RELAXED, ACT_WALK_SHOTGUN_RELAXED, false },//never aims + { ACT_WALK_AIM_STIMULATED, ACT_WALK_AIM_SHOTGUN_STIMULATED, false }, + { ACT_WALK_AIM_AGITATED, ACT_WALK_AIM_SHOTGUN, false },//always aims + + { ACT_RUN_AIM_RELAXED, ACT_RUN_SHOTGUN_RELAXED, false },//never aims + { ACT_RUN_AIM_STIMULATED, ACT_RUN_AIM_SHOTGUN_STIMULATED, false }, + { ACT_RUN_AIM_AGITATED, ACT_RUN_AIM_SHOTGUN, false },//always aims +//End readiness activities + + { ACT_WALK_AIM, ACT_WALK_AIM_SHOTGUN, true }, + { ACT_WALK_CROUCH, ACT_WALK_CROUCH_RIFLE, true }, + { ACT_WALK_CROUCH_AIM, ACT_WALK_CROUCH_AIM_RIFLE, true }, + { ACT_RUN, ACT_RUN_SHOTGUN, true }, + { ACT_RUN_AIM, ACT_RUN_AIM_SHOTGUN, true }, + { ACT_RUN_CROUCH, ACT_RUN_CROUCH_RIFLE, true }, + { ACT_RUN_CROUCH_AIM, ACT_RUN_CROUCH_AIM_RIFLE, true }, + { ACT_GESTURE_RANGE_ATTACK1, ACT_GESTURE_RANGE_ATTACK_SHOTGUN, true }, + { ACT_RANGE_ATTACK1_LOW, ACT_RANGE_ATTACK_SHOTGUN_LOW, true }, + { ACT_RELOAD_LOW, ACT_RELOAD_SHOTGUN_LOW, false }, + { ACT_GESTURE_RELOAD, ACT_GESTURE_RELOAD_SHOTGUN, false }, + { ACT_COVER_LOW, ACT_COVER_SHOTGUN_LOW, false }, + { ACT_RANGE_AIM_LOW, ACT_RANGE_AIM_SHOTGUN_LOW, false }, +#else { ACT_IDLE, ACT_IDLE_SMG1, true }, // FIXME: hook to shotgun unique { ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_SHOTGUN, true }, @@ -153,10 +204,16 @@ acttable_t CWeaponShotgun::m_acttable[] = { ACT_RANGE_ATTACK1_LOW, ACT_RANGE_ATTACK_SHOTGUN_LOW, true }, { ACT_RELOAD_LOW, ACT_RELOAD_SHOTGUN_LOW, false }, { ACT_GESTURE_RELOAD, ACT_GESTURE_RELOAD_SHOTGUN, false }, +#endif #ifdef EXPANDED_HL2_WEAPON_ACTIVITIES - { ACT_ARM, ACT_ARM_RIFLE, false }, - { ACT_DISARM, ACT_DISARM_RIFLE, false }, + { ACT_ARM, ACT_ARM_SHOTGUN, true }, + { ACT_DISARM, ACT_DISARM_SHOTGUN, true }, +#endif + +#ifdef EXPANDED_HL2_COVER_ACTIVITIES + { ACT_RANGE_AIM_MED, ACT_RANGE_AIM_SHOTGUN_MED, false }, + { ACT_RANGE_ATTACK1_MED, ACT_RANGE_ATTACK_SHOTGUN_MED, true }, #endif }; diff --git a/sp/src/game/server/hl2/weapon_smg1.cpp b/sp/src/game/server/hl2/weapon_smg1.cpp index b0c75a14..3589358e 100644 --- a/sp/src/game/server/hl2/weapon_smg1.cpp +++ b/sp/src/game/server/hl2/weapon_smg1.cpp @@ -139,6 +139,16 @@ acttable_t CWeaponSMG1::m_acttable[] = { ACT_ARM, ACT_ARM_RIFLE, false }, { ACT_DISARM, ACT_DISARM_RIFLE, false }, #endif + +#ifdef EXPANDED_HL2_COVER_ACTIVITIES + { ACT_RANGE_AIM_MED, ACT_RANGE_AIM_SMG1_MED, false }, + { ACT_RANGE_ATTACK1_MED, ACT_RANGE_ATTACK_SMG1_MED, true }, + + { ACT_COVER_WALL_R, ACT_COVER_WALL_R_RIFLE, true }, + { ACT_COVER_WALL_L, ACT_COVER_WALL_L_RIFLE, true }, + { ACT_COVER_WALL_LOW_R, ACT_COVER_WALL_LOW_R_RIFLE, true }, + { ACT_COVER_WALL_LOW_L, ACT_COVER_WALL_LOW_L_RIFLE, true }, +#endif }; IMPLEMENT_ACTTABLE(CWeaponSMG1); diff --git a/sp/src/game/shared/activitylist.cpp b/sp/src/game/shared/activitylist.cpp index 6d3f3cf6..95ff2144 100644 --- a/sp/src/game/shared/activitylist.cpp +++ b/sp/src/game/shared/activitylist.cpp @@ -2299,6 +2299,8 @@ void ActivityList_RegisterSharedActivities( void ) REGISTER_SHARED_ACTIVITY( ACT_RELOAD_AR2_LOW ); REGISTER_SHARED_ACTIVITY( ACT_GESTURE_RELOAD_AR2 ); + + REGISTER_SHARED_ACTIVITY( ACT_COVER_AR2_LOW ); #endif #ifdef SHARED_COMBINE_ACTIVITIES @@ -2361,14 +2363,42 @@ void ActivityList_RegisterSharedActivities( void ) REGISTER_SHARED_ACTIVITY( ACT_WALK_AIM_PISTOL_STIMULATED ); REGISTER_SHARED_ACTIVITY( ACT_RUN_AIM_PISTOL_STIMULATED ); + REGISTER_SHARED_ACTIVITY( ACT_WALK_CROUCH_PISTOL ); + REGISTER_SHARED_ACTIVITY( ACT_WALK_CROUCH_AIM_PISTOL ); + REGISTER_SHARED_ACTIVITY( ACT_RUN_CROUCH_PISTOL ); + REGISTER_SHARED_ACTIVITY( ACT_RUN_CROUCH_AIM_PISTOL ); + + REGISTER_SHARED_ACTIVITY( ACT_IDLE_SHOTGUN ); + REGISTER_SHARED_ACTIVITY( ACT_WALK_SHOTGUN ); + REGISTER_SHARED_ACTIVITY( ACT_RUN_SHOTGUN ); + + REGISTER_SHARED_ACTIVITY( ACT_COVER_SHOTGUN_LOW ); + REGISTER_SHARED_ACTIVITY( ACT_RANGE_AIM_SHOTGUN_LOW ); + + REGISTER_SHARED_ACTIVITY( ACT_WALK_SHOTGUN_RELAXED ); + REGISTER_SHARED_ACTIVITY( ACT_WALK_SHOTGUN_STIMULATED ); + REGISTER_SHARED_ACTIVITY( ACT_RUN_SHOTGUN_RELAXED ); + REGISTER_SHARED_ACTIVITY( ACT_RUN_SHOTGUN_STIMULATED ); + + REGISTER_SHARED_ACTIVITY( ACT_IDLE_AIM_SHOTGUN_STIMULATED ); + REGISTER_SHARED_ACTIVITY( ACT_WALK_AIM_SHOTGUN_STIMULATED ); + REGISTER_SHARED_ACTIVITY( ACT_RUN_AIM_SHOTGUN_STIMULATED ); + REGISTER_SHARED_ACTIVITY( ACT_RANGE_AIM_RPG_LOW ); REGISTER_SHARED_ACTIVITY( ACT_RANGE_ATTACK_RPG_LOW ); + REGISTER_SHARED_ACTIVITY( ACT_GESTURE_RANGE_ATTACK_RPG ); REGISTER_SHARED_ACTIVITY( ACT_RUN_PACKAGE ); REGISTER_SHARED_ACTIVITY( ACT_RUN_SUITCASE ); REGISTER_SHARED_ACTIVITY( ACT_ARM_RIFLE ); + REGISTER_SHARED_ACTIVITY( ACT_ARM_SHOTGUN ); + REGISTER_SHARED_ACTIVITY( ACT_ARM_RPG ); + REGISTER_SHARED_ACTIVITY( ACT_ARM_MELEE ); REGISTER_SHARED_ACTIVITY( ACT_DISARM_RIFLE ); + REGISTER_SHARED_ACTIVITY( ACT_DISARM_SHOTGUN ); + REGISTER_SHARED_ACTIVITY( ACT_DISARM_RPG ); + REGISTER_SHARED_ACTIVITY( ACT_DISARM_MELEE ); #endif #ifdef EXPANDED_NAVIGATION_ACTIVITIES @@ -2380,6 +2410,43 @@ void ActivityList_RegisterSharedActivities( void ) REGISTER_SHARED_ACTIVITY( ACT_CLIMB_DISMOUNT_BOTTOM ); #endif +#ifdef EXPANDED_HL2_COVER_ACTIVITIES + REGISTER_SHARED_ACTIVITY( ACT_RANGE_ATTACK1_MED ); + REGISTER_SHARED_ACTIVITY( ACT_RANGE_ATTACK2_MED ); + REGISTER_SHARED_ACTIVITY( ACT_RANGE_AIM_MED ); + + REGISTER_SHARED_ACTIVITY( ACT_RANGE_ATTACK_AR2_MED ); + REGISTER_SHARED_ACTIVITY( ACT_RANGE_ATTACK_SMG1_MED ); + REGISTER_SHARED_ACTIVITY( ACT_RANGE_ATTACK_SHOTGUN_MED ); + REGISTER_SHARED_ACTIVITY( ACT_RANGE_ATTACK_PISTOL_MED ); + REGISTER_SHARED_ACTIVITY( ACT_RANGE_ATTACK_RPG_MED ); + REGISTER_SHARED_ACTIVITY( ACT_RANGE_ATTACK_REVOLVER_MED ); + REGISTER_SHARED_ACTIVITY( ACT_RANGE_ATTACK_CROSSBOW_MED ); + + REGISTER_SHARED_ACTIVITY( ACT_RANGE_AIM_AR2_MED ); + REGISTER_SHARED_ACTIVITY( ACT_RANGE_AIM_SMG1_MED ); + REGISTER_SHARED_ACTIVITY( ACT_RANGE_AIM_SHOTGUN_MED ); + REGISTER_SHARED_ACTIVITY( ACT_RANGE_AIM_PISTOL_MED ); + REGISTER_SHARED_ACTIVITY( ACT_RANGE_AIM_RPG_MED ); + REGISTER_SHARED_ACTIVITY( ACT_RANGE_AIM_REVOLVER_MED ); + REGISTER_SHARED_ACTIVITY( ACT_RANGE_AIM_CROSSBOW_MED ); + + REGISTER_SHARED_ACTIVITY( ACT_COVER_WALL_R ); + REGISTER_SHARED_ACTIVITY( ACT_COVER_WALL_L ); + REGISTER_SHARED_ACTIVITY( ACT_COVER_WALL_LOW_R ); + REGISTER_SHARED_ACTIVITY( ACT_COVER_WALL_LOW_L ); + + REGISTER_SHARED_ACTIVITY( ACT_COVER_WALL_R_RIFLE ); + REGISTER_SHARED_ACTIVITY( ACT_COVER_WALL_L_RIFLE ); + REGISTER_SHARED_ACTIVITY( ACT_COVER_WALL_LOW_R_RIFLE ); + REGISTER_SHARED_ACTIVITY( ACT_COVER_WALL_LOW_L_RIFLE ); + + REGISTER_SHARED_ACTIVITY( ACT_COVER_WALL_R_PISTOL ); + REGISTER_SHARED_ACTIVITY( ACT_COVER_WALL_L_PISTOL ); + REGISTER_SHARED_ACTIVITY( ACT_COVER_WALL_LOW_R_PISTOL ); + REGISTER_SHARED_ACTIVITY( ACT_COVER_WALL_LOW_L_PISTOL ); +#endif + AssertMsg( g_HighestActivity == LAST_SHARED_ACTIVITY - 1, "Not all activities from ai_activity.h registered in activitylist.cpp" ); } diff --git a/sp/src/game/shared/ai_activity.h b/sp/src/game/shared/ai_activity.h index 36d07ed3..11845787 100644 --- a/sp/src/game/shared/ai_activity.h +++ b/sp/src/game/shared/ai_activity.h @@ -45,6 +45,10 @@ // This enables some new navigation-related activities. #define EXPANDED_NAVIGATION_ACTIVITIES 1 +// EXPANDED HL2 COVER ACTIVITIES +// This enables some new cover-related activities. +#define EXPANDED_HL2_COVER_ACTIVITIES 1 + #endif #define ACTIVITY_NOT_AVAILABLE -1 @@ -2168,6 +2172,8 @@ typedef enum ACT_RELOAD_AR2_LOW, ACT_GESTURE_RELOAD_AR2, + + ACT_COVER_AR2_LOW, #endif #ifdef SHARED_COMBINE_ACTIVITIES @@ -2234,9 +2240,32 @@ typedef enum ACT_WALK_AIM_PISTOL_STIMULATED, ACT_RUN_AIM_PISTOL_STIMULATED, + ACT_WALK_CROUCH_PISTOL, + ACT_WALK_CROUCH_AIM_PISTOL, + ACT_RUN_CROUCH_PISTOL, + ACT_RUN_CROUCH_AIM_PISTOL, + + // Shotgun + ACT_IDLE_SHOTGUN, + ACT_WALK_SHOTGUN, + ACT_RUN_SHOTGUN, + + ACT_COVER_SHOTGUN_LOW, + ACT_RANGE_AIM_SHOTGUN_LOW, + + ACT_WALK_SHOTGUN_RELAXED, + ACT_WALK_SHOTGUN_STIMULATED, + ACT_RUN_SHOTGUN_RELAXED, + ACT_RUN_SHOTGUN_STIMULATED, + + ACT_IDLE_AIM_SHOTGUN_STIMULATED, + ACT_WALK_AIM_SHOTGUN_STIMULATED, + ACT_RUN_AIM_SHOTGUN_STIMULATED, + // RPG ACT_RANGE_AIM_RPG_LOW, ACT_RANGE_ATTACK_RPG_LOW, + ACT_GESTURE_RANGE_ATTACK_RPG, // Citizen accessories ACT_RUN_PACKAGE, @@ -2244,7 +2273,13 @@ typedef enum // Holster/Unholster ACT_ARM_RIFLE, + ACT_ARM_SHOTGUN, + ACT_ARM_RPG, + ACT_ARM_MELEE, ACT_DISARM_RIFLE, + ACT_DISARM_SHOTGUN, + ACT_DISARM_RPG, + ACT_DISARM_MELEE, #endif #ifdef EXPANDED_NAVIGATION_ACTIVITIES @@ -2255,6 +2290,45 @@ typedef enum ACT_CLIMB_MOUNT_BOTTOM, ACT_CLIMB_DISMOUNT_BOTTOM, #endif + +#ifdef EXPANDED_HL2_COVER_ACTIVITIES + // Crouch Cover Medium + ACT_RANGE_ATTACK1_MED, + ACT_RANGE_ATTACK2_MED, + ACT_RANGE_AIM_MED, + + ACT_RANGE_ATTACK_AR2_MED, + ACT_RANGE_ATTACK_SMG1_MED, + ACT_RANGE_ATTACK_SHOTGUN_MED, + ACT_RANGE_ATTACK_PISTOL_MED, + ACT_RANGE_ATTACK_RPG_MED, + ACT_RANGE_ATTACK_REVOLVER_MED, + ACT_RANGE_ATTACK_CROSSBOW_MED, + + ACT_RANGE_AIM_AR2_MED, + ACT_RANGE_AIM_SMG1_MED, + ACT_RANGE_AIM_SHOTGUN_MED, + ACT_RANGE_AIM_PISTOL_MED, + ACT_RANGE_AIM_RPG_MED, + ACT_RANGE_AIM_REVOLVER_MED, + ACT_RANGE_AIM_CROSSBOW_MED, + + // Wall Cover (for use in custom cover hints) + ACT_COVER_WALL_R, + ACT_COVER_WALL_L, + ACT_COVER_WALL_LOW_R, + ACT_COVER_WALL_LOW_L, + + ACT_COVER_WALL_R_RIFLE, + ACT_COVER_WALL_L_RIFLE, + ACT_COVER_WALL_LOW_R_RIFLE, + ACT_COVER_WALL_LOW_L_RIFLE, + + ACT_COVER_WALL_R_PISTOL, + ACT_COVER_WALL_L_PISTOL, + ACT_COVER_WALL_LOW_R_PISTOL, + ACT_COVER_WALL_LOW_L_PISTOL, +#endif // this is the end of the global activities, private per-monster activities start here. LAST_SHARED_ACTIVITY, From 26c05ee685ba34d985fdc3192be1e622395fff5d Mon Sep 17 00:00:00 2001 From: Blixibon Date: Wed, 27 Oct 2021 23:49:22 -0500 Subject: [PATCH 198/378] Integrated medium cover activities into standoffs and beyond --- sp/src/game/server/ai_basenpc.cpp | 83 ++++++++++--- sp/src/game/server/ai_basenpc.h | 5 + sp/src/game/server/ai_behavior.cpp | 18 +++ sp/src/game/server/ai_behavior.h | 64 ++++++++++ sp/src/game/server/ai_behavior_standoff.cpp | 126 ++++++++++++++++++-- sp/src/game/server/ai_behavior_standoff.h | 11 ++ sp/src/game/server/hl2/npc_metropolice.cpp | 29 +---- 7 files changed, 284 insertions(+), 52 deletions(-) diff --git a/sp/src/game/server/ai_basenpc.cpp b/sp/src/game/server/ai_basenpc.cpp index e11d6452..61cba40a 100644 --- a/sp/src/game/server/ai_basenpc.cpp +++ b/sp/src/game/server/ai_basenpc.cpp @@ -6509,7 +6509,7 @@ CAI_BaseNPC *CAI_BaseNPC::CreateCustomTarget( const Vector &vecOrigin, float dur //----------------------------------------------------------------------------- Activity CAI_BaseNPC::TranslateCrouchActivity( Activity eNewActivity ) { - if (CapabilitiesGet() & bits_CAP_DUCK) + if (CapabilitiesGet() & bits_CAP_DUCK && CanTranslateCrouchActivity()) { // ======================================================================== // The main issue with cover hint nodes is that crouch activities are not translated at the right time @@ -6541,10 +6541,18 @@ Activity CAI_BaseNPC::TranslateCrouchActivity( Activity eNewActivity ) CAI_Hint *pHint = GetHintNode(); if (pHint) { - if (pHint->HintType() == HINT_TACTICAL_COVER_LOW || pHint->HintType() == HINT_TACTICAL_COVER_MED) + if (pHint->HintType() == HINT_TACTICAL_COVER_LOW) { nCoverActivity = ACT_RANGE_ATTACK1_LOW; } + else if (pHint->HintType() == HINT_TACTICAL_COVER_MED) + { +#ifdef EXPANDED_HL2_COVER_ACTIVITIES + nCoverActivity = ACT_RANGE_ATTACK1_MED; +#else + nCoverActivity = ACT_RANGE_ATTACK1_LOW; +#endif + } } } } @@ -6586,21 +6594,30 @@ Activity CAI_BaseNPC::NPC_BackupActivity( Activity eNewActivity ) //if (eNewActivity == ACT_DROP_WEAPON) // return TranslateActivity(ACT_IDLE); + // --------------------------------------------- + // Accounts for certain act busy activities that aren't on all NPCs. if (eNewActivity == ACT_BUSY_QUEUE || eNewActivity == ACT_BUSY_STAND) return TranslateActivity(ACT_IDLE); + // --------------------------------------------- + if (eNewActivity == ACT_WALK_ANGRY) return TranslateActivity(ACT_WALK); + // --------------------------------------------- + // If one climbing animation isn't available, use the other if (eNewActivity == ACT_CLIMB_DOWN) return ACT_CLIMB_UP; else if (eNewActivity == ACT_CLIMB_UP) return ACT_CLIMB_DOWN; - // GetCoverActivity() should have this covered. // --------------------------------------------- + + if (eNewActivity == ACT_COVER_MED) + eNewActivity = ACT_COVER_LOW; + //if (eNewActivity == ACT_COVER) // return TranslateActivity(ACT_IDLE); @@ -9137,27 +9154,45 @@ Activity CAI_BaseNPC::GetCoverActivity( CAI_Hint *pHint ) switch (pHint->HintType()) { case HINT_TACTICAL_COVER_MED: -#ifndef MAPBASE // I know what you're thinking, but ACT_COVER_MED is pretty much deprecated at this point anyway. { - nCoverActivity = ACT_COVER_MED; #ifdef MAPBASE - // Some NPCs lack ACT_COVER_MED, but could easily use ACT_COVER_LOW. - if (SelectWeightedSequence(nCoverActivity) == ACTIVITY_NOT_AVAILABLE) - nCoverActivity = ACT_COVER_LOW; -#endif + // NPCs which lack ACT_COVER_MED should fall through to HINT_TACTICAL_COVER_LOW + if (SelectWeightedSequence( ACT_COVER_MED ) != ACTIVITY_NOT_AVAILABLE) + { + nCoverActivity = ACT_COVER_MED; + } +#else + nCoverActivity = ACT_COVER_MED; break; - } #endif + } case HINT_TACTICAL_COVER_LOW: { #ifdef MAPBASE - if (pHint->HintActivityName() != NULL_STRING) - nCoverActivity = (Activity)CAI_BaseNPC::GetActivityID( STRING(pHint->HintActivityName()) ); - else -#endif + // Make sure nCoverActivity wasn't already assigned above, then fall through to HINT_TACTICAL_COVER_CUSTOM + if (nCoverActivity == ACT_INVALID) + nCoverActivity = ACT_COVER_LOW; +#else nCoverActivity = ACT_COVER_LOW; break; +#endif } + +#ifdef MAPBASE + case HINT_TACTICAL_COVER_CUSTOM: + { + if (pHint->HintActivityName() != NULL_STRING) + { + nCoverActivity = (Activity)CAI_BaseNPC::GetActivityID( STRING(pHint->HintActivityName()) ); + if (nCoverActivity == ACT_INVALID) + { + m_iszSceneCustomMoveSeq = pHint->HintActivityName(); + nCoverActivity = ACT_SCRIPT_CUSTOM_MOVE; + } + } + break; + } +#endif } } @@ -15985,6 +16020,26 @@ bool CAI_BaseNPC::CouldShootIfCrouching( CBaseEntity *pTarget ) return bResult; } +#ifdef MAPBASE +//----------------------------------------------------------------------------- +// Purpose: Check if this position will block our line of sight if aiming low. +//----------------------------------------------------------------------------- +bool CAI_BaseNPC::CouldShootIfCrouchingAt( const Vector &vecPosition, const Vector &vecForward, const Vector &vecRight, float flDist ) +{ + Vector vGunPos = vecPosition; + vGunPos += (GetCrouchGunOffset() + vecRight * 8); + + trace_t tr; + AI_TraceLOS( vGunPos, vGunPos + (vecForward * flDist), this, &tr ); + if (tr.fraction != 1.0) + { + return false; + } + + return true; +} +#endif + //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- diff --git a/sp/src/game/server/ai_basenpc.h b/sp/src/game/server/ai_basenpc.h index 675412af..d666a33d 100644 --- a/sp/src/game/server/ai_basenpc.h +++ b/sp/src/game/server/ai_basenpc.h @@ -998,6 +998,7 @@ public: Activity NPC_TranslateActivity( Activity eNewActivity ); #ifdef MAPBASE Activity TranslateCrouchActivity( Activity baseAct ); + virtual bool CanTranslateCrouchActivity( void ) { return true; } virtual Activity NPC_BackupActivity( Activity eNewActivity ); #endif Activity GetActivity( void ) { return m_Activity; } @@ -2207,6 +2208,10 @@ public: inline void ForceCrouch( void ); inline void ClearForceCrouch( void ); +#ifdef MAPBASE + bool CouldShootIfCrouchingAt( const Vector &vecPosition, const Vector &vecForward, const Vector &vecRight, float flDist = 48.0f ); +#endif + protected: virtual bool Crouch( void ); virtual bool Stand( void ); diff --git a/sp/src/game/server/ai_behavior.cpp b/sp/src/game/server/ai_behavior.cpp index 8822f750..4730e122 100644 --- a/sp/src/game/server/ai_behavior.cpp +++ b/sp/src/game/server/ai_behavior.cpp @@ -420,6 +420,24 @@ bool CAI_BehaviorBase::CanUnholsterWeapon( void ) return m_pBackBridge->BackBridge_CanUnholsterWeapon(); } + +//------------------------------------- + +bool CAI_BehaviorBase::ShouldPickADeathPose( void ) +{ + Assert( m_pBackBridge != NULL ); + + return m_pBackBridge->BackBridge_ShouldPickADeathPose(); +} + +//------------------------------------- + +bool CAI_BehaviorBase::CanTranslateCrouchActivity( void ) +{ + Assert( m_pBackBridge != NULL ); + + return m_pBackBridge->BackBridge_CanTranslateCrouchActivity(); +} #endif //------------------------------------- diff --git a/sp/src/game/server/ai_behavior.h b/sp/src/game/server/ai_behavior.h index ce26ca61..f4df0640 100644 --- a/sp/src/game/server/ai_behavior.h +++ b/sp/src/game/server/ai_behavior.h @@ -132,6 +132,8 @@ public: void BridgeHandleAnimEvent( animevent_t *pEvent ); #ifdef MAPBASE bool BridgeCanUnholsterWeapon( void ); + bool BridgeShouldPickADeathPose( void ); + bool BridgeCanTranslateCrouchActivity( void ); #endif virtual void GatherConditions(); @@ -220,6 +222,8 @@ protected: virtual void HandleAnimEvent( animevent_t *pEvent ); #ifdef MAPBASE virtual bool CanUnholsterWeapon( void ); + virtual bool ShouldPickADeathPose( void ); + virtual bool CanTranslateCrouchActivity( void ); #endif virtual bool ShouldAlwaysThink(); @@ -370,6 +374,9 @@ public: #ifdef MAPBASE // For func_tank behavior virtual bool BackBridge_CanUnholsterWeapon( void ) = 0; + + virtual bool BackBridge_ShouldPickADeathPose( void ) = 0; + virtual bool BackBridge_CanTranslateCrouchActivity( void ) = 0; #endif //------------------------------------- @@ -470,6 +477,8 @@ public: void HandleAnimEvent( animevent_t *pEvent ); #ifdef MAPBASE bool CanUnholsterWeapon( void ); + bool ShouldPickADeathPose( void ); + bool CanTranslateCrouchActivity( void ); #endif bool ShouldAlwaysThink(); @@ -534,6 +543,9 @@ private: #ifdef MAPBASE // For func_tank behavior bool BackBridge_CanUnholsterWeapon( void ); + + bool BackBridge_ShouldPickADeathPose( void ); + bool BackBridge_CanTranslateCrouchActivity( void ); #endif CAI_BehaviorBase **AccessBehaviors(); @@ -913,6 +925,20 @@ inline bool CAI_BehaviorBase::BridgeCanUnholsterWeapon( void ) { return CanUnholsterWeapon(); } + +//----------------------------------------------------------------------------- + +inline bool CAI_BehaviorBase::BridgeShouldPickADeathPose( void ) +{ + return ShouldPickADeathPose(); +} + +//----------------------------------------------------------------------------- + +inline bool CAI_BehaviorBase::BridgeCanTranslateCrouchActivity( void ) +{ + return CanTranslateCrouchActivity(); +} #endif //----------------------------------------------------------------------------- @@ -1498,6 +1524,22 @@ inline bool CAI_BehaviorHost::BackBridge_CanUnholsterWeapon( void ) { return BaseClass::CanUnholsterWeapon(); } + +//------------------------------------- + +template +inline bool CAI_BehaviorHost::BackBridge_ShouldPickADeathPose( void ) +{ + return BaseClass::ShouldPickADeathPose(); +} + +//------------------------------------- + +template +inline bool CAI_BehaviorHost::BackBridge_CanTranslateCrouchActivity( void ) +{ + return BaseClass::CanTranslateCrouchActivity(); +} #endif //------------------------------------- @@ -1914,6 +1956,28 @@ inline bool CAI_BehaviorHost::CanUnholsterWeapon( void ) return BaseClass::CanUnholsterWeapon(); } + +//------------------------------------- + +template +inline bool CAI_BehaviorHost::ShouldPickADeathPose( void ) +{ + if (m_pCurBehavior) + return m_pCurBehavior->BridgeShouldPickADeathPose(); + + return BaseClass::ShouldPickADeathPose(); +} + +//------------------------------------- + +template +inline bool CAI_BehaviorHost::CanTranslateCrouchActivity( void ) +{ + if (m_pCurBehavior) + return m_pCurBehavior->BridgeCanTranslateCrouchActivity(); + + return BaseClass::CanTranslateCrouchActivity(); +} #endif //------------------------------------- diff --git a/sp/src/game/server/ai_behavior_standoff.cpp b/sp/src/game/server/ai_behavior_standoff.cpp index bc5244ef..85740876 100644 --- a/sp/src/game/server/ai_behavior_standoff.cpp +++ b/sp/src/game/server/ai_behavior_standoff.cpp @@ -535,10 +535,11 @@ int CAI_StandoffBehavior::SelectScheduleCheckCover( void ) { StandoffMsg( "Regulated to not shoot\n" ); #ifdef MAPBASE - if ( GetHintType() == HINT_TACTICAL_COVER_LOW || GetHintType() == HINT_TACTICAL_COVER_MED ) -#else - if ( GetHintType() == HINT_TACTICAL_COVER_LOW ) + if ( GetHintType() == HINT_TACTICAL_COVER_MED || GetCoverActivity() == ACT_COVER_MED ) + SetPosture( AIP_CROUCHING_MED ); + else #endif + if ( GetHintType() == HINT_TACTICAL_COVER_LOW ) SetPosture( AIP_CROUCHING ); else SetPosture( AIP_STANDING ); @@ -557,7 +558,11 @@ int CAI_StandoffBehavior::SelectScheduleEstablishAim( void ) { if ( HasCondition( COND_ENEMY_OCCLUDED ) ) { +#ifdef EXPANDED_HL2_COVER_ACTIVITIES + if ( GetPosture() == AIP_CROUCHING || GetPosture() == AIP_CROUCHING_MED ) +#else if ( GetPosture() == AIP_CROUCHING ) +#endif { // force a stand up, just in case GetOuter()->SpeakSentence( STANDOFF_SENTENCE_STAND_CHECK_TARGET ); @@ -668,6 +673,15 @@ Activity CAI_MappedActivityBehavior_Temporary::GetMappedActivity( AI_Posture_t p { if ( posture != AIP_STANDING ) { +#ifdef EXPANDED_HL2_COVER_ACTIVITIES + // See UpdateTranslateActivityMap() for more information on what this is for + if ( posture == AIP_CROUCHING_MED ) + { + if (activity != ACT_RANGE_ATTACK1) + posture = AIP_CROUCHING; + } +#endif + unsigned short iActivityTranslation = m_ActivityMap.Find( MAKE_ACTMAP_KEY( posture, activity ) ); if ( iActivityTranslation != m_ActivityMap.InvalidIndex() ) { @@ -685,10 +699,28 @@ Activity CAI_StandoffBehavior::NPC_TranslateActivity( Activity activity ) Activity coverActivity = GetCoverActivity(); if ( coverActivity != ACT_INVALID ) { +#ifdef MAPBASE + if ( GetPosture() == AIP_STANDING ) + { + if ( coverActivity == ACT_COVER_LOW ) + SetPosture( AIP_CROUCHING ); + else if ( coverActivity == ACT_COVER_MED ) + { + SetPosture( AIP_CROUCHING_MED ); + coverActivity = ACT_COVER_LOW; + } + } + else if (coverActivity == ACT_COVER_MED) + coverActivity = ACT_COVER_LOW; + if ( activity == ACT_IDLE ) activity = coverActivity; +#else + if (activity == ACT_IDLE) + activity = coverActivity; if ( GetPosture() == AIP_STANDING && coverActivity == ACT_COVER_LOW ) SetPosture( AIP_CROUCHING ); +#endif } Activity result = GetMappedActivity( GetPosture(), activity ); @@ -1089,12 +1121,25 @@ void CAI_StandoffBehavior::UnlockHintNode() Activity CAI_StandoffBehavior::GetCoverActivity() { -#ifdef MAPBASE - // This does two things: - // A. Allows medium cover nodes to be used, kind of. - // B. GetCoverActivity() already checks everything we checked here. - Activity coveract = GetOuter()->GetCoverActivity( GetHintNode() ); - return coveract == ACT_IDLE ? ACT_INVALID : coveract; +#ifdef EXPANDED_HL2_COVER_ACTIVITIES + // GetCoverActivity() already checks everything we checked here. + Activity coverActivity = GetOuter()->GetCoverActivity( GetHintNode() ); + + if (coverActivity == ACT_COVER_LOW) + { + // Check if this node will block our line of sight if aiming low. + Vector vHintPos, vHintForward, vHintRight; + GetHintNode()->GetPosition( GetHullType(), &vHintPos ); + vHintForward = GetHintNode()->GetDirection(); + + GetHintNode()->GetVectors( NULL, &vHintRight, NULL ); + if (GetOuter()->CouldShootIfCrouchingAt( vHintPos, vHintForward, vHintRight )) + { + coverActivity = ACT_COVER_MED; + } + } + + return coverActivity == ACT_IDLE ? ACT_INVALID : coverActivity; #else CAI_Hint *pHintNode = GetHintNode(); if ( pHintNode && pHintNode->HintType() == HINT_TACTICAL_COVER_LOW ) @@ -1112,6 +1157,14 @@ struct AI_ActivityMapping_t Activity activity; const char * pszWeapon; Activity translation; +#ifdef MAPBASE + Activity backup; + + AI_ActivityMapping_t( AI_Posture_t _p, Activity _a, const char *_w, Activity _t, Activity _b = ACT_INVALID ) + { + posture = _p; activity = _a; pszWeapon = _w; translation = _t; backup = _b; + } +#endif }; void CAI_MappedActivityBehavior_Temporary::UpdateTranslateActivityMap() @@ -1125,15 +1178,60 @@ void CAI_MappedActivityBehavior_Temporary::UpdateTranslateActivityMap() { AIP_CROUCHING, ACT_WALK_AIM, NULL, ACT_WALK_CROUCH_AIM, }, { AIP_CROUCHING, ACT_RUN_AIM, NULL, ACT_RUN_CROUCH_AIM, }, { AIP_CROUCHING, ACT_RELOAD, NULL, ACT_RELOAD_LOW, }, +#ifdef MAPBASE + { AIP_CROUCHING, ACT_RANGE_ATTACK1, NULL, ACT_RANGE_ATTACK1_LOW, }, + { AIP_CROUCHING, ACT_COVER_MED, NULL, ACT_COVER_LOW, }, +#else { AIP_CROUCHING, ACT_RANGE_ATTACK_SMG1, NULL, ACT_RANGE_ATTACK_SMG1_LOW, }, { AIP_CROUCHING, ACT_RANGE_ATTACK_AR2, NULL, ACT_RANGE_ATTACK_AR2_LOW, }, +#endif +#ifdef EXPANDED_HL2_COVER_ACTIVITIES + // + // ============ Really long explanation that should be in a wiki/documentation article somewhere ~ Blixibon, 10/27/2021 ============ + // + // Standoff behavior assumes low attack animations allow NPCs to see over barricades, with ACT_COVER_LOW being their "safely in cover" animation. + // This is why AIP_CROUCHING translates ACT_RANGE_ATTACK1 to its low animation, but translates ACT_IDLE_ANGRY to ACT_COVER_LOW instead of ACT_RANGE_AIM_LOW, + // as this would ideally allow NPCs to pop in and out of cover to shoot. + // This is also why AIP_PEEKING translates ACT_COVER_LOW to ACT_RANGE_AIM_LOW, as it's supposed to force the NPC to peek over their cover. + // + // However, this assumption mainly just applies to metrocops. Citizens' low attacking animations crouch low to the ground (which isn't effective for + // shooting over most barricades) and, while they do have a distinct ACT_COVER_LOW animation with transitions, they are close enough together that popping + // in and out of cover is redundant in most cases. Meanwhile, Combine soldiers have identical ACT_COVER_LOW and ACT_RANGE_AIM_LOW animations, which means + // they do not pop in and out of cover and AIP_PEEKING does nothing. This may be the reason why Combine soldiers occasionally get stuck in cover after a fight. + // + // ------------------------------------------------------------- + // + // As part of Mapbase v7.0's NPC activity overhaul, a new "medium cover" activity set has been added. Metrocops' previous "low cover" animation set (which, as + // mentioned before, is different from that of other NPCs) has been retroactively changed to use "medium cover". This was done for a few reasons unrelated to + // standoff behavior, but the important point is that these activities indicate a new cover height. This means we can use them to give standoff behavior more leeway + // for judging which animations to use in various levels of cover. + // + // Standoff behavior can use "medium cover" animations in cover which is too high for the "low" animations, and when the medium cover animations are not available, + // it simply falls back to the "standing" animations, thus resolving the issue with other NPCs not peeking in and out of cover without requiring new medium cover + // animations. + // + // In Mapbase, this is done by changing AIP_PEEKING to use the medium cover animations and adding a new alternate crouching posture posture called "AIP_CROUCHING_MED", + // which only uses the medium cover attack activity and otherwise automatically falls back to AIP_CROUCHING. AIP_CROUCHING_MED is automatically set if the NPC cannot + // get LOS from a regular crouching position. + // + { AIP_CROUCHING_MED, ACT_RANGE_ATTACK1, NULL, ACT_RANGE_ATTACK1_MED, }, + + //---- + { AIP_PEEKING, ACT_IDLE, NULL, ACT_RANGE_AIM_MED, }, + { AIP_PEEKING, ACT_IDLE_ANGRY, NULL, ACT_RANGE_AIM_MED, }, + { AIP_PEEKING, ACT_COVER_LOW, NULL, ACT_RANGE_AIM_MED, ACT_IDLE_ANGRY }, + { AIP_PEEKING, ACT_COVER_MED, NULL, ACT_RANGE_AIM_MED, ACT_IDLE_ANGRY }, + { AIP_PEEKING, ACT_RANGE_ATTACK1, NULL, ACT_RANGE_ATTACK1_MED, }, + { AIP_PEEKING, ACT_RELOAD, NULL, ACT_RELOAD_LOW, }, +#else //---- { AIP_PEEKING, ACT_IDLE, NULL, ACT_RANGE_AIM_LOW, }, { AIP_PEEKING, ACT_IDLE_ANGRY, NULL, ACT_RANGE_AIM_LOW, }, { AIP_PEEKING, ACT_COVER_LOW, NULL, ACT_RANGE_AIM_LOW, }, { AIP_PEEKING, ACT_RANGE_ATTACK1, NULL, ACT_RANGE_ATTACK1_LOW, }, { AIP_PEEKING, ACT_RELOAD, NULL, ACT_RELOAD_LOW, }, +#endif }; m_ActivityMap.RemoveAll(); @@ -1145,7 +1243,7 @@ void CAI_MappedActivityBehavior_Temporary::UpdateTranslateActivityMap() if ( !mappings[i].pszWeapon || stricmp( mappings[i].pszWeapon, pszWeaponClass ) == 0 ) { #ifdef MAPBASE - // Check backup activity + // Check NPC backup activity if ( HaveSequenceForActivity( mappings[i].translation ) || HaveSequenceForActivity( GetOuter()->Weapon_TranslateActivity( mappings[i].translation ) ) || HaveSequenceForActivity( GetOuter()->Weapon_BackupActivity( mappings[i].translation ) ) ) #else if ( HaveSequenceForActivity( mappings[i].translation ) || HaveSequenceForActivity( GetOuter()->Weapon_TranslateActivity( mappings[i].translation ) ) ) @@ -1154,6 +1252,14 @@ void CAI_MappedActivityBehavior_Temporary::UpdateTranslateActivityMap() Assert( m_ActivityMap.Find( MAKE_ACTMAP_KEY( mappings[i].posture, mappings[i].activity ) ) == m_ActivityMap.InvalidIndex() ); m_ActivityMap.Insert( MAKE_ACTMAP_KEY( mappings[i].posture, mappings[i].activity ), mappings[i].translation ); } +#ifdef MAPBASE + // Check activity map backup activity + else if ( mappings[i].backup != ACT_INVALID && HaveSequenceForActivity( mappings[i].backup ) ) + { + Assert( m_ActivityMap.Find( MAKE_ACTMAP_KEY( mappings[i].posture, mappings[i].activity ) ) == m_ActivityMap.InvalidIndex() ); + m_ActivityMap.Insert( MAKE_ACTMAP_KEY( mappings[i].posture, mappings[i].activity ), mappings[i].backup ); + } +#endif } } } diff --git a/sp/src/game/server/ai_behavior_standoff.h b/sp/src/game/server/ai_behavior_standoff.h index c08059e8..2de2a072 100644 --- a/sp/src/game/server/ai_behavior_standoff.h +++ b/sp/src/game/server/ai_behavior_standoff.h @@ -51,6 +51,9 @@ enum AI_Posture_t AIP_INDIFFERENT, AIP_STANDING, AIP_CROUCHING, +#ifdef EXPANDED_HL2_COVER_ACTIVITIES + AIP_CROUCHING_MED, // See UpdateTranslateActivityMap() for more information on what this is for +#endif AIP_PEEKING, }; @@ -149,6 +152,14 @@ protected: // Standoff overrides base AI crouch handling bool IsCrouching( void ) { return false; } + +#ifdef MAPBASE + // Standoff overrides base cover activity translation + bool CanTranslateCrouchActivity( void ) { return false; } + + // Don't do death poses while crouching + bool ShouldPickADeathPose( void ) { return (GetPosture() != AIP_CROUCHING && GetPosture() != AIP_PEEKING) && BaseClass::ShouldPickADeathPose(); } +#endif private: diff --git a/sp/src/game/server/hl2/npc_metropolice.cpp b/sp/src/game/server/hl2/npc_metropolice.cpp index 9d8e0b96..b107b971 100644 --- a/sp/src/game/server/hl2/npc_metropolice.cpp +++ b/sp/src/game/server/hl2/npc_metropolice.cpp @@ -4536,34 +4536,7 @@ int CNPC_MetroPolice::SelectBehaviorOverrideSchedule() //----------------------------------------------------------------------------- bool CNPC_MetroPolice::IsCrouchedActivity( Activity activity ) { - Activity realActivity = TranslateActivity(activity); - - switch ( realActivity ) - { - case ACT_RELOAD_LOW: - case ACT_COVER_LOW: - case ACT_COVER_PISTOL_LOW: - case ACT_COVER_SMG1_LOW: - case ACT_RELOAD_SMG1_LOW: - //case ACT_RELOAD_AR2_LOW: - case ACT_RELOAD_PISTOL_LOW: - case ACT_RELOAD_SHOTGUN_LOW: - - // These animations aren't actually "low" on metrocops - //case ACT_RANGE_AIM_LOW: - //case ACT_RANGE_AIM_AR2_LOW: - //case ACT_RANGE_AIM_SMG1_LOW: - //case ACT_RANGE_AIM_PISTOL_LOW: - - //case ACT_RANGE_ATTACK1_LOW: - //case ACT_RANGE_ATTACK_AR2_LOW: - //case ACT_RANGE_ATTACK_SMG1_LOW: - //case ACT_RANGE_ATTACK_PISTOL_LOW: - //case ACT_RANGE_ATTACK2_LOW: - return true; - } - - return false; + return BaseClass::IsCrouchedActivity( activity ); } //----------------------------------------------------------------------------- From dfa7e6c0c284aa96f7acc662eb145e4f737d9bc3 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Wed, 27 Oct 2021 23:55:55 -0500 Subject: [PATCH 199/378] Added "fake sequence gestures" for NPCs, which play certain activities as gestures instead when the current animation needs to be preserved --- sp/src/game/server/ai_basenpc.cpp | 145 +++++++++++++++++++++++++++++- sp/src/game/server/ai_basenpc.h | 41 +++++++++ 2 files changed, 185 insertions(+), 1 deletion(-) diff --git a/sp/src/game/server/ai_basenpc.cpp b/sp/src/game/server/ai_basenpc.cpp index 61cba40a..16faea3a 100644 --- a/sp/src/game/server/ai_basenpc.cpp +++ b/sp/src/game/server/ai_basenpc.cpp @@ -169,6 +169,8 @@ extern ConVar ai_vehicle_avoidance; extern ISoundEmitterSystemBase *soundemitterbase; ConVar ai_dynint_always_enabled( "ai_dynint_always_enabled", "0", FCVAR_NONE, "Makes the \"Don't Care\" setting equivalent to \"Yes\"." ); + +ConVar ai_debug_fake_sequence_gestures_always_play( "ai_debug_fake_sequence_gestures_always_play", "0", FCVAR_NONE, "Always plays fake sequence gestures." ); #endif #ifndef _RETAIL @@ -313,6 +315,8 @@ ScriptHook_t CAI_BaseNPC::g_Hook_QuerySeeEntity; ScriptHook_t CAI_BaseNPC::g_Hook_TranslateActivity; ScriptHook_t CAI_BaseNPC::g_Hook_TranslateSchedule; ScriptHook_t CAI_BaseNPC::g_Hook_GetActualShootPosition; +ScriptHook_t CAI_BaseNPC::g_Hook_OverrideMove; +ScriptHook_t CAI_BaseNPC::g_Hook_ShouldPlayFakeSequenceGesture; #endif // @@ -7048,6 +7052,23 @@ void CAI_BaseNPC::SetIdealActivity( Activity NewActivity ) // Perform translation in case we need to change sequences within a single activity, // such as between a standing idle and a crouching idle. ResolveActivityToSequence(m_IdealActivity, m_nIdealSequence, m_IdealTranslatedActivity, m_IdealWeaponActivity); + +#ifdef MAPBASE + // Check if we need a gesture to imitate this sequence + if ( ShouldPlayFakeSequenceGesture( m_IdealActivity, m_IdealTranslatedActivity ) ) + { + Activity nGesture = SelectFakeSequenceGesture( m_IdealActivity, m_IdealTranslatedActivity ); + if (nGesture != -1) + { + PlayFakeSequenceGesture( nGesture, m_IdealActivity, m_IdealTranslatedActivity ); + } + } + else if (GetFakeSequenceGesture() != -1) + { + // Reset the current gesture sequence if there is one + ResetFakeSequenceGesture(); + } +#endif } @@ -7096,6 +7117,14 @@ void CAI_BaseNPC::AdvanceToIdealActivity(void) //DevMsg("%s: Unable to get from sequence %s to %s!\n", GetClassname(), GetSequenceName(GetSequence()), GetSequenceName(m_nIdealSequence)); SetActivity(m_IdealActivity); } + +#ifdef MAPBASE + // If there was a gesture imitating a sequence, get rid of it + if ( GetFakeSequenceGesture() != -1 ) + { + ResetFakeSequenceGesture(); + } +#endif } @@ -7153,6 +7182,12 @@ void CAI_BaseNPC::MaintainActivity(void) } // Else a transition sequence is in progress, do nothing. } +#ifdef MAPBASE + else if (GetFakeSequenceGesture() != -1) + { + // Don't advance even if the sequence gesture is finished, as advancing would just play the original activity afterwards + } +#endif // Else get a specific sequence for the activity and try to transition to that. else { @@ -7171,11 +7206,104 @@ void CAI_BaseNPC::MaintainActivity(void) } +#ifdef MAPBASE +bool CAI_BaseNPC::ShouldPlayFakeSequenceGesture( Activity nActivity, Activity nTranslatedActivity ) +{ + // Don't do anything if we're resetting our activity + if (GetActivity() == ACT_RESET) + return false; + + // No need to do this while we're moving + if (IsCurTaskContinuousMove()) + return false; + + if (ai_debug_fake_sequence_gestures_always_play.GetBool()) + return true; + +#ifdef MAPBASE_VSCRIPT + if (m_ScriptScope.IsInitialized() && g_Hook_ShouldPlayFakeSequenceGesture.CanRunInScope(m_ScriptScope)) + { + // activity, translatedActivity + ScriptVariant_t functionReturn; + ScriptVariant_t args[] = { GetActivityName( nActivity ), GetActivityName( nTranslatedActivity ) }; + if (g_Hook_ShouldPlayFakeSequenceGesture.Call( m_ScriptScope, &functionReturn, args )) + { + if (functionReturn.m_type == FIELD_BOOLEAN) + return functionReturn.m_bool; + } + } +#endif + + if (GetHintNode() && GetHintNode()->HintActivityName() != NULL_STRING) + { + switch (GetHintNode()->HintType()) + { + // Cover nodes with custom activities should allow NPCs to do things like reload while in cover. + case HINT_TACTICAL_COVER_LOW: + case HINT_TACTICAL_COVER_MED: + case HINT_TACTICAL_COVER_CUSTOM: + if (HasMemory( bits_MEMORY_INCOVER )) + { + // Don't attack while using a custom animation in cover + if (nActivity != ACT_RANGE_ATTACK1 && nActivity != ACT_RANGE_ATTACK1_LOW) + return true; + } + break; + } + } + + return false; +} + +Activity CAI_BaseNPC::SelectFakeSequenceGesture( Activity nActivity, Activity nTranslatedActivity ) +{ + return GetGestureVersionOfActivity( nTranslatedActivity ); +} + +inline void CAI_BaseNPC::PlayFakeSequenceGesture( Activity nActivity, Activity nSequence, Activity nTranslatedSequence ) +{ + RestartGesture( nActivity, true, true ); + m_FakeSequenceGestureLayer = FindGestureLayer( nActivity ); + + switch ( nSequence ) + { + case ACT_RANGE_ATTACK1: + //case ACT_RANGE_ATTACK2: + { + OnRangeAttack1(); + + // FIXME: this seems a bit wacked + Weapon_SetActivity( Weapon_TranslateActivity( nSequence ), 0 ); + } break; + } +} + +inline int CAI_BaseNPC::GetFakeSequenceGesture() +{ + return m_FakeSequenceGestureLayer; +} + +void CAI_BaseNPC::ResetFakeSequenceGesture() +{ + SetLayerCycle( m_FakeSequenceGestureLayer, 1.0f ); + m_FakeSequenceGestureLayer = -1; +} +#endif + + //----------------------------------------------------------------------------- // Purpose: Returns true if our ideal activity has finished playing. //----------------------------------------------------------------------------- bool CAI_BaseNPC::IsActivityFinished( void ) { +#ifdef MAPBASE + if (GetFakeSequenceGesture() != -1) + { + Msg( "Checking if fake sequence gesture is finished\n" ); + return IsLayerFinished( GetFakeSequenceGesture() ); + } +#endif + return (IsSequenceFinished() && (GetSequence() == m_nIdealSequence)); } @@ -11972,6 +12100,7 @@ BEGIN_DATADESC( CAI_BaseNPC ) DEFINE_KEYFIELD( m_FriendlyFireOverride, FIELD_INTEGER, "FriendlyFireOverride" ), DEFINE_KEYFIELD( m_flSpeedModifier, FIELD_FLOAT, "BaseSpeedModifier" ), + DEFINE_FIELD( m_FakeSequenceGestureLayer, FIELD_INTEGER ), #endif // Satisfy classcheck @@ -12129,6 +12258,11 @@ BEGIN_ENT_SCRIPTDESC( CAI_BaseNPC, CBaseCombatCharacter, "The base class all NPC DEFINE_SCRIPTFUNC_NAMED( ScriptSetActivityID, "SetActivityID", "Set the NPC's current activity ID." ) DEFINE_SCRIPTFUNC( ResetActivity, "Reset the NPC's current activity." ) + DEFINE_SCRIPTFUNC_NAMED( VScriptGetGestureVersionOfActivity, "GetGestureVersionOfActivity", "Get the gesture activity counterpart of the specified sequence activity, if one exists." ) + DEFINE_SCRIPTFUNC_NAMED( VScriptGetGestureVersionOfActivityID, "GetGestureVersionOfActivityID", "Get the gesture activity ID counterpart of the specified sequence activity ID, if one exists." ) + DEFINE_SCRIPTFUNC_NAMED( VScriptGetSequenceVersionOfGesture, "GetSequenceVersionOfGesture", "Get the sequence activity counterpart of the specified gesture activity, if one exists." ) + DEFINE_SCRIPTFUNC_NAMED( VScriptGetSequenceVersionOfGestureID, "GetSequenceVersionOfGestureID", "Get the sequence activity ID counterpart of the specified gesture activity ID, if one exists." ) + DEFINE_SCRIPTFUNC_NAMED( VScriptGetSchedule, "GetSchedule", "Get the NPC's current schedule." ) DEFINE_SCRIPTFUNC_NAMED( VScriptGetScheduleID, "GetScheduleID", "Get the NPC's current schedule ID." ) DEFINE_SCRIPTFUNC_NAMED( VScriptSetSchedule, "SetSchedule", "Set the NPC's current schedule." ) @@ -12175,10 +12309,17 @@ BEGIN_ENT_SCRIPTDESC( CAI_BaseNPC, CBaseCombatCharacter, "The base class all NPC DEFINE_SCRIPTHOOK_PARAM( "schedule", FIELD_CSTRING ) DEFINE_SCRIPTHOOK_PARAM( "schedule_id", FIELD_INTEGER ) END_SCRIPTHOOK() - BEGIN_SCRIPTHOOK( CAI_BaseNPC::g_Hook_GetActualShootPosition, "GetActualShootPosition", FIELD_VOID, "Called when the NPC is getting their actual shoot position, using the default shoot position as the parameter. (NOTE: NPCs which override this themselves might not always use this hook!)" ) + BEGIN_SCRIPTHOOK( CAI_BaseNPC::g_Hook_GetActualShootPosition, "GetActualShootPosition", FIELD_VECTOR, "Called when the NPC is getting their actual shoot position, using the default shoot position as the parameter. (NOTE: NPCs which override this themselves might not always use this hook!)" ) DEFINE_SCRIPTHOOK_PARAM( "shootOrigin", FIELD_VECTOR ) DEFINE_SCRIPTHOOK_PARAM( "target", FIELD_HSCRIPT ) END_SCRIPTHOOK() + BEGIN_SCRIPTHOOK( CAI_BaseNPC::g_Hook_OverrideMove, "OverrideMove", FIELD_VOID, "Called when the NPC runs movement code, allowing the NPC's movement to be overridden by some other method. (NOTE: NPCs which override this themselves might not always use this hook!)" ) + DEFINE_SCRIPTHOOK_PARAM( "interval", FIELD_FLOAT ) + END_SCRIPTHOOK() + BEGIN_SCRIPTHOOK( CAI_BaseNPC::g_Hook_ShouldPlayFakeSequenceGesture, "ShouldPlayFakeSequenceGesture", FIELD_BOOLEAN, "Called when an activity is set on a NPC. Returning true will make the NPC convert the activity into a gesture (if a gesture is available) and continue their current activity instead." ) + DEFINE_SCRIPTHOOK_PARAM( "activity", FIELD_CSTRING ) + DEFINE_SCRIPTHOOK_PARAM( "translatedActivity", FIELD_CSTRING ) + END_SCRIPTHOOK() END_SCRIPTDESC(); #endif @@ -12829,6 +12970,8 @@ CAI_BaseNPC::CAI_BaseNPC(void) #ifdef MAPBASE m_iDynamicInteractionsAllowed = TRS_NONE; m_flSpeedModifier = 1.0f; + + m_FakeSequenceGestureLayer = -1; #endif } diff --git a/sp/src/game/server/ai_basenpc.h b/sp/src/game/server/ai_basenpc.h index d666a33d..fe63f36e 100644 --- a/sp/src/game/server/ai_basenpc.h +++ b/sp/src/game/server/ai_basenpc.h @@ -1021,6 +1021,25 @@ public: void SetActivityAndSequence(Activity NewActivity, int iSequence, Activity translatedActivity, Activity weaponActivity); +#ifdef MAPBASE + //----------------------------------------------------- + + // Returns the gesture variant of an activity (i.e. "ACT_GESTURE_RANGE_ATTACK1") + static Activity GetGestureVersionOfActivity( Activity inActivity ); + + // Returns the sequence variant of a gesture activity + static Activity GetSequenceVersionOfGesture( Activity inActivity ); + + //----------------------------------------------------- + + virtual bool ShouldPlayFakeSequenceGesture( Activity nActivity, Activity nTranslatedActivity ); + virtual Activity SelectFakeSequenceGesture( Activity nActivity, Activity nTranslatedActivity ); + void PlayFakeSequenceGesture( Activity nActivity, Activity nSequence, Activity nTranslatedSequence ); + + int GetFakeSequenceGesture(); + void ResetFakeSequenceGesture(); +#endif + private: void AdvanceToIdealActivity(void); @@ -1034,6 +1053,10 @@ private: Activity m_IdealTranslatedActivity; // Desired actual translated animation state Activity m_IdealWeaponActivity; // Desired weapon animation state +#ifdef MAPBASE + int m_FakeSequenceGestureLayer; // The gesture layer impersonating a sequence (-1 if invalid) +#endif + CNetworkVar(int, m_iDeathPose ); CNetworkVar(int, m_iDeathFrame ); @@ -1218,6 +1241,8 @@ public: #endif #ifdef MAPBASE_VSCRIPT +private: + // VScript stuff uses "VScript" instead of just "Script" to avoid // confusion with NPC_STATE_SCRIPT or StartScripting HSCRIPT VScriptGetEnemy(); @@ -1244,6 +1269,11 @@ public: int ScriptTranslateActivity( const char *szActivity ) { return TranslateActivity( (Activity)GetActivityID( szActivity ) ); } int ScriptTranslateActivityID( int iActivity ) { return TranslateActivity( (Activity)iActivity ); } + const char* VScriptGetGestureVersionOfActivity( const char *pszActivity ) { return GetActivityName( GetGestureVersionOfActivity( (Activity)GetActivityID( pszActivity ) ) ); } + int VScriptGetGestureVersionOfActivityID( int iActivity ) { return GetGestureVersionOfActivity( (Activity)iActivity ); } + const char* VScriptGetSequenceVersionOfGesture( const char *pszActivity ) { return GetActivityName( GetSequenceVersionOfGesture( (Activity)GetActivityID( pszActivity ) ) ); } + int VScriptGetSequenceVersionOfGestureID( int iActivity ) { return GetSequenceVersionOfGesture( (Activity)iActivity ); } + const char* VScriptGetSchedule(); int VScriptGetScheduleID(); void VScriptSetSchedule( const char *szSchedule ); @@ -2271,6 +2301,16 @@ private: static CAI_GlobalScheduleNamespace gm_SchedulingSymbols; static CAI_ClassScheduleIdSpace gm_ClassScheduleIdSpace; +#ifdef MAPBASE + typedef struct + { + Activity sequence; + Activity gesture; + } actlink_t; + + static actlink_t gm_ActivityGestureLinks[]; +#endif + public: //---------------------------------------------------- // Debugging tools @@ -2322,6 +2362,7 @@ public: static ScriptHook_t g_Hook_TranslateSchedule; static ScriptHook_t g_Hook_GetActualShootPosition; static ScriptHook_t g_Hook_OverrideMove; + static ScriptHook_t g_Hook_ShouldPlayFakeSequenceGesture; #endif private: From ece1a612ced93d068b8f4743789052921ef5e521 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Wed, 27 Oct 2021 23:59:27 -0500 Subject: [PATCH 200/378] Integrated custom cover hints into base AI movement code --- sp/src/game/server/BaseAnimatingOverlay.cpp | 15 +++++++++++-- sp/src/game/server/BaseAnimatingOverlay.h | 6 +++-- sp/src/game/server/ai_basenpc.cpp | 25 +++++++++++++++++++++ sp/src/game/server/ai_basenpc_schedule.cpp | 18 ++++++++++++--- sp/src/game/server/ai_motor.cpp | 20 ++++++++++++++--- sp/src/game/server/ai_motor.h | 3 +++ sp/src/game/server/ai_navigator.cpp | 17 +++++++++++--- sp/src/game/server/ai_tacticalservices.cpp | 5 +++++ 8 files changed, 96 insertions(+), 13 deletions(-) diff --git a/sp/src/game/server/BaseAnimatingOverlay.cpp b/sp/src/game/server/BaseAnimatingOverlay.cpp index d04ff89d..06bf690e 100644 --- a/sp/src/game/server/BaseAnimatingOverlay.cpp +++ b/sp/src/game/server/BaseAnimatingOverlay.cpp @@ -1095,9 +1095,9 @@ void CBaseAnimatingOverlay::SetLayerNoRestore( int iLayer, bool bNoRestore ) } -#ifdef MAPBASE // From Alien Swarm SDK +#ifdef MAPBASE //----------------------------------------------------------------------------- -// Purpose: +// From Alien Swarm SDK //----------------------------------------------------------------------------- void CBaseAnimatingOverlay::SetLayerNoEvents( int iLayer, bool bNoEvents ) { @@ -1113,6 +1113,17 @@ void CBaseAnimatingOverlay::SetLayerNoEvents( int iLayer, bool bNoEvents ) m_AnimOverlay[iLayer].m_fFlags &= ~ANIM_LAYER_NOEVENTS; } } + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CBaseAnimatingOverlay::IsLayerFinished( int iLayer ) +{ + if (!IsValidLayer( iLayer )) + return true; + + return m_AnimOverlay[iLayer].m_bSequenceFinished; +} #endif diff --git a/sp/src/game/server/BaseAnimatingOverlay.h b/sp/src/game/server/BaseAnimatingOverlay.h index d7b882f8..38ee7ed1 100644 --- a/sp/src/game/server/BaseAnimatingOverlay.h +++ b/sp/src/game/server/BaseAnimatingOverlay.h @@ -181,8 +181,10 @@ public: void SetLayerAutokill( int iLayer, bool bAutokill ); void SetLayerLooping( int iLayer, bool bLooping ); void SetLayerNoRestore( int iLayer, bool bNoRestore ); -#ifdef MAPBASE // From Alien Swarm SDK - void SetLayerNoEvents( int iLayer, bool bNoEvents ); +#ifdef MAPBASE + void SetLayerNoEvents( int iLayer, bool bNoEvents ); // From Alien Swarm SDK + + bool IsLayerFinished( int iLayer ); #endif Activity GetLayerActivity( int iLayer ); diff --git a/sp/src/game/server/ai_basenpc.cpp b/sp/src/game/server/ai_basenpc.cpp index 16faea3a..02a8b725 100644 --- a/sp/src/game/server/ai_basenpc.cpp +++ b/sp/src/game/server/ai_basenpc.cpp @@ -2598,7 +2598,11 @@ bool CAI_BaseNPC::FValidateHintType ( CAI_Hint *pHint ) Activity CAI_BaseNPC::GetHintActivity( short sHintType, Activity HintsActivity ) { if ( HintsActivity != ACT_INVALID ) +#ifdef MAPBASE + return TranslateActivity( HintsActivity ); // Always translate the activity +#else return HintsActivity; +#endif return ACT_IDLE; } @@ -6866,7 +6870,12 @@ void CAI_BaseNPC::ResolveActivityToSequence(Activity NewActivity, int &iSequence translatedActivity = TranslateActivity( NewActivity, &weaponActivity ); +#ifdef MAPBASE + // Cover cases where TranslateActivity() returns a sequence by using ACT_SCRIPT_CUSTOM_MOVE + if ( NewActivity == ACT_SCRIPT_CUSTOM_MOVE || translatedActivity == ACT_SCRIPT_CUSTOM_MOVE ) +#else if ( NewActivity == ACT_SCRIPT_CUSTOM_MOVE ) +#endif { iSequence = GetScriptCustomMoveSequence(); } @@ -7339,6 +7348,15 @@ void CAI_BaseNPC::OnChangeActivity( Activity eNewActivity ) eNewActivity == ACT_WALK ) { Stand(); + +#ifdef MAPBASE + // Unlock custom cover nodes + if (GetHintNode() && GetHintNode()->HintType() == HINT_TACTICAL_COVER_CUSTOM && HasMemory(bits_MEMORY_INCOVER)) + { + GetHintNode()->Unlock( GetHintDelay( GetHintNode()->HintType() ) ); + SetHintNode( NULL ); + } +#endif } } @@ -9358,6 +9376,13 @@ float CAI_BaseNPC::CalcIdealYaw( const Vector &vecTarget ) return UTIL_VecToYaw( vecProjection - GetLocalOrigin() ); } +#ifdef MAPBASE + // Allow hint nodes to override the yaw without needing to control AI + else if (GetHintNode() && GetHintNode()->OverridesNPCYaw( this )) + { + return GetHintNode()->Yaw(); + } +#endif else { return UTIL_VecToYaw ( vecTarget - GetLocalOrigin() ); diff --git a/sp/src/game/server/ai_basenpc_schedule.cpp b/sp/src/game/server/ai_basenpc_schedule.cpp index bcb54c81..e0c9feef 100644 --- a/sp/src/game/server/ai_basenpc_schedule.cpp +++ b/sp/src/game/server/ai_basenpc_schedule.cpp @@ -980,11 +980,12 @@ bool CAI_BaseNPC::FindCoverFromEnemy( bool bNodesOnly, float flMinDistance, floa // FIXME: add to goal if (GetHintNode()) { - GetNavigator()->SetArrivalActivity( GetCoverActivity( GetHintNode() ) ); #ifdef MAPBASE - if (GetHintNode()->GetIgnoreFacing() != HIF_NO) -#endif + GetHintNode()->NPCHandleStartNav( this, true ); +#else + GetNavigator()->SetArrivalActivity( GetCoverActivity( GetHintNode() ) ); GetNavigator()->SetArrivalDirection( GetHintNode()->GetDirection() ); +#endif } return true; @@ -3431,6 +3432,17 @@ void CAI_BaseNPC::RunTask( const Task_t *pTask ) // If the yaw is locked, this function will not act correctly Assert( GetMotor()->IsYawLocked() == false ); +#ifdef MAPBASE + if ( GetHintNode() && GetHintNode()->OverridesNPCYaw( this ) ) + { + // If the yaw is supposed to use that of a hint node, chain to TASK_FACE_HINTNODE + GetMotor()->SetIdealYaw( GetHintNode()->Yaw() ); + GetMotor()->SetIdealYaw( CalcReasonableFacing( true ) ); // CalcReasonableFacing() is based on previously set ideal yaw + ChainRunTask( TASK_FACE_HINTNODE, pTask->flTaskData ); + break; + } +#endif + Vector vecEnemyLKP = GetEnemyLKP(); if (!FInAimCone( vecEnemyLKP )) { diff --git a/sp/src/game/server/ai_motor.cpp b/sp/src/game/server/ai_motor.cpp index c9c6fb8e..f54432ff 100644 --- a/sp/src/game/server/ai_motor.cpp +++ b/sp/src/game/server/ai_motor.cpp @@ -14,6 +14,9 @@ #include "ai_basenpc.h" #include "ai_localnavigator.h" #include "ai_moveprobe.h" +#ifdef MAPBASE +#include "ai_hint.h" +#endif #include "saverestore_utlvector.h" // memdbgon must be the last include file in a .cpp file!!! @@ -836,9 +839,20 @@ void CAI_Motor::MoveFacing( const AILocalMoveGoal_t &move ) { // FIXME: move this up to navigator so that path goals can ignore these overrides. Vector dir; - float flInfluence = GetFacingDirection( dir ); - dir = move.facing * (1 - flInfluence) + dir * flInfluence; - VectorNormalize( dir ); + +#ifdef MAPBASE + if (IsDeceleratingToGoal() && (GetOuter()->GetHintNode() /*|| GetOuter()->m_hOpeningDoor*/)) + { + // Don't let the facing queue interfere with arrival direction in important cases + dir = move.facing; + } + else +#endif + { + float flInfluence = GetFacingDirection( dir ); + dir = move.facing * (1 - flInfluence) + dir * flInfluence; + VectorNormalize( dir ); + } // ideal facing direction float idealYaw = UTIL_AngleMod( UTIL_VecToYaw( dir ) ); diff --git a/sp/src/game/server/ai_motor.h b/sp/src/game/server/ai_motor.h index b5f5d297..29c05f84 100644 --- a/sp/src/game/server/ai_motor.h +++ b/sp/src/game/server/ai_motor.h @@ -87,6 +87,9 @@ public: const Vector & GetCurVel() const { return m_vecVelocity; } virtual float OverrideMaxYawSpeed( Activity activity ) { return -1; } +#ifdef MAPBASE + virtual +#endif bool IsDeceleratingToGoal() const { return false; } //--------------------------------- diff --git a/sp/src/game/server/ai_navigator.cpp b/sp/src/game/server/ai_navigator.cpp index 9d6ae06a..59c06822 100644 --- a/sp/src/game/server/ai_navigator.cpp +++ b/sp/src/game/server/ai_navigator.cpp @@ -999,12 +999,23 @@ int CAI_Navigator::GetArrivalSequence( int curSequence ) activity = ACT_IDLE; } - sequence = GetOuter()->SelectWeightedSequence( GetOuter()->TranslateActivity( activity ), curSequence ); + Activity translatedActivity = GetOuter()->TranslateActivity( activity ); + sequence = GetOuter()->SelectWeightedSequence( translatedActivity, curSequence ); if ( sequence == ACT_INVALID ) { - DevMsg( GetOuter(), "No appropriate sequence for arrival activity %s (%d)\n", GetOuter()->GetActivityName( GetPath()->GetArrivalActivity() ), GetPath()->GetArrivalActivity() ); - sequence = GetOuter()->SelectWeightedSequence( GetOuter()->TranslateActivity( ACT_IDLE ), curSequence ); +#ifdef MAPBASE + if ( translatedActivity == ACT_SCRIPT_CUSTOM_MOVE ) + { + // ACT_SCRIPT_CUSTOM_MOVE allows activity translation to resolve into specific sequences + sequence = GetOuter()->GetScriptCustomMoveSequence(); + } + else +#endif + { + DevMsg( GetOuter(), "No appropriate sequence for arrival activity %s (%d)\n", GetOuter()->GetActivityName( GetPath()->GetArrivalActivity() ), GetPath()->GetArrivalActivity() ); + sequence = GetOuter()->SelectWeightedSequence( GetOuter()->TranslateActivity( ACT_IDLE ), curSequence ); + } } Assert( sequence != ACT_INVALID ); GetPath()->SetArrivalSequence( sequence ); diff --git a/sp/src/game/server/ai_tacticalservices.cpp b/sp/src/game/server/ai_tacticalservices.cpp index 87399c4f..8bcdcc08 100644 --- a/sp/src/game/server/ai_tacticalservices.cpp +++ b/sp/src/game/server/ai_tacticalservices.cpp @@ -411,7 +411,12 @@ int CAI_TacticalServices::FindCoverNode(const Vector &vNearPos, const Vector &vT // -------------------------------------------------------- pNode->Lock( 1.0 ); +#ifdef MAPBASE + if ( pNode->GetHint() && ( pNode->GetHint()->HintType() == HINT_TACTICAL_COVER_MED || pNode->GetHint()->HintType() == HINT_TACTICAL_COVER_LOW + || pNode->GetHint()->HintType() == HINT_TACTICAL_COVER_CUSTOM ) ) +#else if ( pNode->GetHint() && ( pNode->GetHint()->HintType() == HINT_TACTICAL_COVER_MED || pNode->GetHint()->HintType() == HINT_TACTICAL_COVER_LOW ) ) +#endif { if ( GetOuter()->GetHintNode() ) { From 847db9c3e3c74de6de54b8db456927fb26776634 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Thu, 28 Oct 2021 00:01:29 -0500 Subject: [PATCH 201/378] Added AI hint radius from the Alien Swarm SDK as well as an all-new "hint weight" keyvalue --- sp/src/game/server/ai_hint.cpp | 109 +++++++++++++++++++++++++++- sp/src/game/server/ai_hint.h | 31 ++++++++ sp/src/game/server/ai_initutils.cpp | 15 ++++ sp/src/game/server/ai_initutils.h | 5 ++ sp/src/game/server/ai_network.cpp | 35 +++++++++ 5 files changed, 192 insertions(+), 3 deletions(-) diff --git a/sp/src/game/server/ai_hint.cpp b/sp/src/game/server/ai_hint.cpp index 1f8ec4d1..2e8e90af 100644 --- a/sp/src/game/server/ai_hint.cpp +++ b/sp/src/game/server/ai_hint.cpp @@ -35,6 +35,10 @@ CHintCriteria::CHintCriteria( void ) m_strGroup = NULL_STRING; m_iFlags = 0; m_HintTypes.Purge(); +#ifdef MAPBASE // From Alien Swarm SDK + m_pfnFilter = NULL; + m_pFilterContext = NULL; +#endif } //----------------------------------------------------------------------------- @@ -1117,10 +1121,10 @@ void CAI_Hint::NPCHandleStartNav( CAI_BaseNPC *pNPC, bool bDefaultFacing ) HintIgnoreFacing_t facing = GetIgnoreFacing(); if (facing == HIF_DEFAULT) - facing = bDefaultFacing ? HIF_YES : HIF_NO; + facing = bDefaultFacing ? HIF_NO : HIF_YES; - if (facing == HIF_YES) - pNPC->GetNavigator()->SetArrivalDirection(GetDirection()); + if (facing == HIF_NO) + pNPC->GetNavigator()->SetArrivalDirection( GetDirection() ); if (HintActivityName() != NULL_STRING) { @@ -1139,6 +1143,51 @@ void CAI_Hint::NPCHandleStartNav( CAI_BaseNPC *pNPC, bool bDefaultFacing ) } } } + +//----------------------------------------------------------------------------- +// Purpose: Returns true if this hint should override a NPC's yaw even during regular AI. +//----------------------------------------------------------------------------- +bool CAI_Hint::OverridesNPCYaw( CAI_BaseNPC *pNPC ) +{ + switch (HintType()) + { + case HINT_TACTICAL_COVER_CUSTOM: + case HINT_TACTICAL_COVER_MED: + case HINT_TACTICAL_COVER_LOW: + { + if (pNPC->HasMemory( bits_MEMORY_INCOVER )) + { + // By default, don't override yaw on cover nodes unless they use custom activities. + HintIgnoreFacing_t facing = GetIgnoreFacing(); + if (facing == HIF_DEFAULT) + return ( HintActivityName() != NULL_STRING ); + + return facing == HIF_NO; + } + + break; + } + + case HINT_PLAYER_ALLY_MOVE_AWAY_DEST: + { + Vector vHintPos; + GetPosition( pNPC, &vHintPos ); + if (VectorsAreEqual( vHintPos, pNPC->GetAbsOrigin(), 0.1f )) + { + // By default, don't override yaw on move away destinations unless they use custom activities. + HintIgnoreFacing_t facing = GetIgnoreFacing(); + if (facing == HIF_DEFAULT) + return ( HintActivityName() != NULL_STRING ); + + return facing == HIF_NO; + } + + break; + } + } + + return false; +} #endif //----------------------------------------------------------------------------- @@ -1258,6 +1307,30 @@ bool CAI_Hint::HintMatchesCriteria( CAI_BaseNPC *pNPC, const CHintCriteria &hint return false; } +#ifdef MAPBASE + // Test against generic filter + // (From Alien Swarm SDK) + if ( !hintCriteria.PassesFilter( this ) ) + { + REPORTFAILURE( "Failed filter test" ); + return false; + } + + // (From Alien Swarm SDK) + int nRadius = GetRadius(); + if ( nRadius != 0 ) + { + // Calculate our distance + float distance = (GetAbsOrigin() - position).LengthSqr(); + + if ( distance > nRadius * nRadius ) + { + REPORTFAILURE( "NPC is not within the node's radius." ); + return false; + } + } +#endif + if ( hintCriteria.HasFlag(bits_HINT_NPC_IN_NODE_FOV) ) { if ( pNPC == NULL ) @@ -1377,10 +1450,18 @@ bool CAI_Hint::HintMatchesCriteria( CAI_BaseNPC *pNPC, const CHintCriteria &hint { trace_t tr; // Can my bounding box fit there? +#ifdef MAPBASE // From Alien Swarm SDK + Vector vStep( 0, 0, pNPC->StepHeight() ); + AI_TraceHull ( GetAbsOrigin() + vStep, GetAbsOrigin(), pNPC->WorldAlignMins(), pNPC->WorldAlignMaxs() - vStep, + MASK_SOLID, pNPC, COLLISION_GROUP_NONE, &tr ); + + if ( tr.fraction < 0.95 ) +#else AI_TraceHull ( GetAbsOrigin(), GetAbsOrigin(), pNPC->WorldAlignMins(), pNPC->WorldAlignMaxs(), MASK_SOLID, pNPC, COLLISION_GROUP_NONE, &tr ); if ( tr.fraction != 1.0 ) +#endif { REPORTFAILURE( "Node isn't clear." ); return false; @@ -1396,6 +1477,15 @@ bool CAI_Hint::HintMatchesCriteria( CAI_BaseNPC *pNPC, const CHintCriteria &hint // Calculate our distance float distance = (GetAbsOrigin() - position).Length(); +#ifdef MAPBASE + // Divide by hint weight + float flWeight = GetHintWeight(); + if ( flWeight != 1.0f ) + { + distance *= GetHintWeightInverse(); + } +#endif + // Must be closer than the current best if ( distance > *flNearestDistance ) { @@ -1576,6 +1666,14 @@ void CAI_Hint::OnRestore() m_NodeData.nNodeID = g_pAINetworkManager->GetEditOps()->GetNodeIdFromWCId( m_NodeData.nWCNodeID ); FixupTargetNode(); +#ifdef MAPBASE + if (m_NodeData.flWeight != 0.0f && m_NodeData.flWeight != 1.0f) + { + // Re-invert the weight + m_NodeData.flWeightInverse = 1.0f / m_NodeData.flWeight; + } +#endif + CAI_Node *pNode = GetNode(); if ( !pNode ) @@ -1751,6 +1849,11 @@ void CC_ai_drop_hint( const CCommand &args ) nodeData.fIgnoreFacing = HIF_DEFAULT; nodeData.minState = NPC_STATE_IDLE; nodeData.maxState = NPC_STATE_COMBAT; +#ifdef MAPBASE + nodeData.nRadius = 0; // From Alien Swarm SDK + nodeData.flWeight = 1.0f; + nodeData.flWeightInverse = 1.0f; +#endif CAI_Hint *pHint = CAI_HintManager::CreateHint( &nodeData, NULL ); if ( pHint ) { diff --git a/sp/src/game/server/ai_hint.h b/sp/src/game/server/ai_hint.h index 60052ded..570f85ef 100644 --- a/sp/src/game/server/ai_hint.h +++ b/sp/src/game/server/ai_hint.h @@ -112,6 +112,13 @@ enum Hint_e // CS port hints HINT_CSTRIKE_HOSTAGE_ESCAPE = 1100, + +#ifdef MAPBASE + // Mapbase hints + // (these start at a high number to avoid potential conflicts with mod hints) + + HINT_TACTICAL_COVER_CUSTOM = 10000, // Cover node with a custom hint activity (NPCs can take cover and reload here while playing said activity) +#endif }; const char *GetHintTypeDescription( Hint_e iHintType ); const char *GetHintTypeDescription( CAI_Hint *pHint ); @@ -120,6 +127,10 @@ const char *GetHintTypeDescription( CAI_Hint *pHint ); // CHintCriteria //----------------------------------------------------------------------------- +#ifdef MAPBASE // From Alien Swarm SDK +typedef bool (*HintSearchFilterFunc_t)( void *pContext, CAI_Hint *pCandidate ); +#endif + class CHintCriteria { public: @@ -134,6 +145,11 @@ public: void SetGroup( string_t group ); string_t GetGroup( void ) const { return m_strGroup; } +#ifdef MAPBASE // From Alien Swarm SDK + void SetFilterFunc( HintSearchFilterFunc_t pfnFilter, void *pContext = NULL ) { m_pfnFilter = pfnFilter; m_pFilterContext = pContext; } + bool PassesFilter( CAI_Hint *pCandidate ) const { return (m_pfnFilter) ? (*m_pfnFilter)(m_pFilterContext, pCandidate) : true; } +#endif + int GetFirstHintType( void ) const { return m_iFirstHintType; } int GetLastHintType( void ) const { return m_iLastHintType; } bool MatchesHintType( int hintType ) const; @@ -176,6 +192,11 @@ private: zoneList_t m_zoneInclude; zoneList_t m_zoneExclude; + +#ifdef MAPBASE + HintSearchFilterFunc_t m_pfnFilter; + void * m_pFilterContext; +#endif }; class CAI_Node; @@ -310,11 +331,21 @@ public: int GetNodeId() { return m_NodeData.nNodeID; } int GetWCId() { return m_NodeData.nWCNodeID; } +#ifdef MAPBASE + int GetRadius() const { return m_NodeData.nRadius; } // From Alien Swarm SDK + + float GetHintWeight() const { return m_NodeData.flWeight; } + float GetHintWeightInverse() const { return m_NodeData.flWeightInverse; } // Used to multiply distances +#endif + bool HintMatchesCriteria( CAI_BaseNPC *pNPC, const CHintCriteria &hintCriteria, const Vector &position, float *flNearestDistance, bool bIgnoreLock = false, bool bIgnoreHintType = false ); bool IsInNodeFOV( CBaseEntity *pOther ); #ifdef MAPBASE void NPCHandleStartNav( CAI_BaseNPC *pNPC, bool bDefaultFacing ); + + // Returns true if this hint should override a NPC's yaw even during regular AI. + bool OverridesNPCYaw( CAI_BaseNPC *pNPC ); #endif #ifdef MAPBASE_VSCRIPT diff --git a/sp/src/game/server/ai_initutils.cpp b/sp/src/game/server/ai_initutils.cpp index 62d5c6ec..cd792798 100644 --- a/sp/src/game/server/ai_initutils.cpp +++ b/sp/src/game/server/ai_initutils.cpp @@ -173,6 +173,10 @@ BEGIN_SIMPLE_DATADESC( HintNodeData ) DEFINE_KEYFIELD( fIgnoreFacing, FIELD_INTEGER, "IgnoreFacing" ), DEFINE_KEYFIELD( minState, FIELD_INTEGER, "MinimumState" ), DEFINE_KEYFIELD( maxState, FIELD_INTEGER, "MaximumState" ), +#ifdef MAPBASE + DEFINE_KEYFIELD( nRadius, FIELD_INTEGER, "radius" ), // From Alien Swarm SDK + DEFINE_KEYFIELD( flWeight, FIELD_FLOAT, "hintweight" ), +#endif END_DATADESC() @@ -205,6 +209,17 @@ int CNodeEnt::Spawn( const char *pMapData ) m_NodeData.minState = NPC_STATE_IDLE; if ( m_NodeData.maxState == NPC_STATE_NONE ) m_NodeData.maxState = NPC_STATE_COMBAT; +#ifdef MAPBASE + if (m_NodeData.flWeight == 0.0f) + { + m_NodeData.flWeight = 1.0f; + } + else if (m_NodeData.flWeight != 1.0f) + { + // Invert the weight so that it could be used as a direct multiplier for distances, etc. + m_NodeData.flWeightInverse = 1.0f / m_NodeData.flWeight; + } +#endif // --------------------------------------------------------------------------------- // If just a hint node (not used for navigation) just create a hint and bail // --------------------------------------------------------------------------------- diff --git a/sp/src/game/server/ai_initutils.h b/sp/src/game/server/ai_initutils.h index 22aaf5f3..70bd019c 100644 --- a/sp/src/game/server/ai_initutils.h +++ b/sp/src/game/server/ai_initutils.h @@ -42,6 +42,11 @@ struct HintNodeData HintIgnoreFacing_t fIgnoreFacing; NPC_STATE minState; NPC_STATE maxState; +#ifdef MAPBASE + int nRadius; // From Alien Swarm SDK + float flWeight; + float flWeightInverse; // Not saved +#endif int nWCNodeID; // Node ID assigned by worldcraft (not same as engine!) diff --git a/sp/src/game/server/ai_network.cpp b/sp/src/game/server/ai_network.cpp index 16d8a7fa..818324f0 100644 --- a/sp/src/game/server/ai_network.cpp +++ b/sp/src/game/server/ai_network.cpp @@ -144,6 +144,31 @@ public: int m_capabilities; // cache this }; +#ifdef MAPBASE +//------------------------------------- +// Purpose: A version of CNodeFilter which allows hints to influence the result. +//------------------------------------- +class CNodeHintFilter : public CNodeFilter +{ +public: + CNodeHintFilter( CAI_BaseNPC *pNPC, const Vector &pos ) : CNodeFilter( pNPC, pos ) {} + CNodeHintFilter( const Vector &pos ) : CNodeFilter( pos ) {} + + virtual float NodeDistanceSqr( CAI_Node &node ) + { + // Heavier hints are considered closer + if (node.GetHint() && node.GetHint()->GetHintWeight() != 1.0f) + { + return CNodeFilter::NodeDistanceSqr( node ) * node.GetHint()->GetHintWeightInverse(); + } + else + { + return CNodeFilter::NodeDistanceSqr( node ); + } + } +}; +#endif + //----------------------------------------------------------------------------- // CAI_Network //----------------------------------------------------------------------------- @@ -351,7 +376,12 @@ int CAI_Network::NearestNodeToPoint( CAI_BaseNPC *pNPC, const Vector &vecOrigin, // First get nodes distances and eliminate those that are beyond // the maximum allowed distance for local movements // --------------------------------------------------------------- +#ifdef MAPBASE + // Allow hint weight to influence supposed distance + CNodeHintFilter filter( pNPC, vecOrigin ); +#else CNodeFilter filter( pNPC, vecOrigin ); +#endif #ifdef AI_PERF_MON m_nPerfStatNN++; @@ -605,8 +635,13 @@ CAI_Node *CAI_Network::AddNode( const Vector &origin, float yaw ) CAI_Link *CAI_Network::CreateLink( int srcID, int destID, CAI_DynamicLink *pDynamicLink ) { +#ifdef MAPBASE // From Alien Swarm SDK + CAI_Node *pSrcNode = GetNode( srcID ); + CAI_Node *pDestNode = GetNode( destID ); +#else CAI_Node *pSrcNode = g_pBigAINet->GetNode( srcID ); CAI_Node *pDestNode = g_pBigAINet->GetNode( destID ); +#endif Assert( pSrcNode && pDestNode && pSrcNode != pDestNode ); From 440c8b512177bba0615308274e361af946d871c5 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Thu, 4 Nov 2021 08:26:39 -0500 Subject: [PATCH 202/378] Fixed an oversight with new weapon activities preventing NPC weapon pickup --- sp/src/game/server/hl2/weapon_357.cpp | 2 +- sp/src/game/server/hl2/weapon_ar2.cpp | 10 +++++----- sp/src/game/server/hl2/weapon_crossbow.cpp | 2 +- sp/src/game/server/hl2/weapon_pistol.cpp | 10 +++++----- sp/src/game/server/hl2/weapon_rpg.cpp | 2 +- sp/src/game/server/hl2/weapon_shotgun.cpp | 2 +- sp/src/game/server/hl2/weapon_smg1.cpp | 10 +++++----- 7 files changed, 19 insertions(+), 19 deletions(-) diff --git a/sp/src/game/server/hl2/weapon_357.cpp b/sp/src/game/server/hl2/weapon_357.cpp index 16c57991..8b4fe93f 100644 --- a/sp/src/game/server/hl2/weapon_357.cpp +++ b/sp/src/game/server/hl2/weapon_357.cpp @@ -196,7 +196,7 @@ acttable_t CWeapon357::m_acttable[] = #ifdef EXPANDED_HL2_COVER_ACTIVITIES { ACT_RANGE_AIM_MED, ACT_RANGE_AIM_REVOLVER_MED, false }, - { ACT_RANGE_ATTACK1_MED, ACT_RANGE_ATTACK_REVOLVER_MED, true }, + { ACT_RANGE_ATTACK1_MED, ACT_RANGE_ATTACK_REVOLVER_MED, false }, #endif }; diff --git a/sp/src/game/server/hl2/weapon_ar2.cpp b/sp/src/game/server/hl2/weapon_ar2.cpp index 35305f59..e6a32e93 100644 --- a/sp/src/game/server/hl2/weapon_ar2.cpp +++ b/sp/src/game/server/hl2/weapon_ar2.cpp @@ -164,12 +164,12 @@ acttable_t CWeaponAR2::m_acttable[] = #ifdef EXPANDED_HL2_COVER_ACTIVITIES { ACT_RANGE_AIM_MED, ACT_RANGE_AIM_AR2_MED, false }, - { ACT_RANGE_ATTACK1_MED, ACT_RANGE_ATTACK_AR2_MED, true }, + { ACT_RANGE_ATTACK1_MED, ACT_RANGE_ATTACK_AR2_MED, false }, - { ACT_COVER_WALL_R, ACT_COVER_WALL_R_RIFLE, true }, - { ACT_COVER_WALL_L, ACT_COVER_WALL_L_RIFLE, true }, - { ACT_COVER_WALL_LOW_R, ACT_COVER_WALL_LOW_R_RIFLE, true }, - { ACT_COVER_WALL_LOW_L, ACT_COVER_WALL_LOW_L_RIFLE, true }, + { ACT_COVER_WALL_R, ACT_COVER_WALL_R_RIFLE, false }, + { ACT_COVER_WALL_L, ACT_COVER_WALL_L_RIFLE, false }, + { ACT_COVER_WALL_LOW_R, ACT_COVER_WALL_LOW_R_RIFLE, false }, + { ACT_COVER_WALL_LOW_L, ACT_COVER_WALL_LOW_L_RIFLE, false }, #endif }; diff --git a/sp/src/game/server/hl2/weapon_crossbow.cpp b/sp/src/game/server/hl2/weapon_crossbow.cpp index f1b5009a..20ec1cc9 100644 --- a/sp/src/game/server/hl2/weapon_crossbow.cpp +++ b/sp/src/game/server/hl2/weapon_crossbow.cpp @@ -718,7 +718,7 @@ acttable_t CWeaponCrossbow::m_acttable[] = #ifdef EXPANDED_HL2_COVER_ACTIVITIES { ACT_RANGE_AIM_MED, ACT_RANGE_AIM_CROSSBOW_MED, false }, - { ACT_RANGE_ATTACK1_MED, ACT_RANGE_ATTACK_CROSSBOW_MED, true }, + { ACT_RANGE_ATTACK1_MED, ACT_RANGE_ATTACK_CROSSBOW_MED, false }, #endif }; diff --git a/sp/src/game/server/hl2/weapon_pistol.cpp b/sp/src/game/server/hl2/weapon_pistol.cpp index eff09cfe..a04d30b6 100644 --- a/sp/src/game/server/hl2/weapon_pistol.cpp +++ b/sp/src/game/server/hl2/weapon_pistol.cpp @@ -250,12 +250,12 @@ acttable_t CWeaponPistol::m_acttable[] = #ifdef EXPANDED_HL2_COVER_ACTIVITIES { ACT_RANGE_AIM_MED, ACT_RANGE_AIM_PISTOL_MED, false }, - { ACT_RANGE_ATTACK1_MED, ACT_RANGE_ATTACK_PISTOL_MED, true }, + { ACT_RANGE_ATTACK1_MED, ACT_RANGE_ATTACK_PISTOL_MED, false }, - { ACT_COVER_WALL_R, ACT_COVER_WALL_R_PISTOL, true }, - { ACT_COVER_WALL_L, ACT_COVER_WALL_L_PISTOL, true }, - { ACT_COVER_WALL_LOW_R, ACT_COVER_WALL_LOW_R_PISTOL, true }, - { ACT_COVER_WALL_LOW_L, ACT_COVER_WALL_LOW_L_PISTOL, true }, + { ACT_COVER_WALL_R, ACT_COVER_WALL_R_PISTOL, false }, + { ACT_COVER_WALL_L, ACT_COVER_WALL_L_PISTOL, false }, + { ACT_COVER_WALL_LOW_R, ACT_COVER_WALL_LOW_R_PISTOL, false }, + { ACT_COVER_WALL_LOW_L, ACT_COVER_WALL_LOW_L_PISTOL, false }, #endif }; diff --git a/sp/src/game/server/hl2/weapon_rpg.cpp b/sp/src/game/server/hl2/weapon_rpg.cpp index 72ee96f9..2d20211d 100644 --- a/sp/src/game/server/hl2/weapon_rpg.cpp +++ b/sp/src/game/server/hl2/weapon_rpg.cpp @@ -1424,7 +1424,7 @@ acttable_t CWeaponRPG::m_acttable[] = #ifdef EXPANDED_HL2_COVER_ACTIVITIES { ACT_RANGE_AIM_MED, ACT_RANGE_AIM_RPG_MED, false }, - { ACT_RANGE_ATTACK1_MED, ACT_RANGE_ATTACK_RPG_MED, true }, + { ACT_RANGE_ATTACK1_MED, ACT_RANGE_ATTACK_RPG_MED, false }, #endif }; diff --git a/sp/src/game/server/hl2/weapon_shotgun.cpp b/sp/src/game/server/hl2/weapon_shotgun.cpp index a1a228c8..e0b2e336 100644 --- a/sp/src/game/server/hl2/weapon_shotgun.cpp +++ b/sp/src/game/server/hl2/weapon_shotgun.cpp @@ -213,7 +213,7 @@ acttable_t CWeaponShotgun::m_acttable[] = #ifdef EXPANDED_HL2_COVER_ACTIVITIES { ACT_RANGE_AIM_MED, ACT_RANGE_AIM_SHOTGUN_MED, false }, - { ACT_RANGE_ATTACK1_MED, ACT_RANGE_ATTACK_SHOTGUN_MED, true }, + { ACT_RANGE_ATTACK1_MED, ACT_RANGE_ATTACK_SHOTGUN_MED, false }, #endif }; diff --git a/sp/src/game/server/hl2/weapon_smg1.cpp b/sp/src/game/server/hl2/weapon_smg1.cpp index 3589358e..04f7e390 100644 --- a/sp/src/game/server/hl2/weapon_smg1.cpp +++ b/sp/src/game/server/hl2/weapon_smg1.cpp @@ -142,12 +142,12 @@ acttable_t CWeaponSMG1::m_acttable[] = #ifdef EXPANDED_HL2_COVER_ACTIVITIES { ACT_RANGE_AIM_MED, ACT_RANGE_AIM_SMG1_MED, false }, - { ACT_RANGE_ATTACK1_MED, ACT_RANGE_ATTACK_SMG1_MED, true }, + { ACT_RANGE_ATTACK1_MED, ACT_RANGE_ATTACK_SMG1_MED, false }, - { ACT_COVER_WALL_R, ACT_COVER_WALL_R_RIFLE, true }, - { ACT_COVER_WALL_L, ACT_COVER_WALL_L_RIFLE, true }, - { ACT_COVER_WALL_LOW_R, ACT_COVER_WALL_LOW_R_RIFLE, true }, - { ACT_COVER_WALL_LOW_L, ACT_COVER_WALL_LOW_L_RIFLE, true }, + { ACT_COVER_WALL_R, ACT_COVER_WALL_R_RIFLE, false }, + { ACT_COVER_WALL_L, ACT_COVER_WALL_L_RIFLE, false }, + { ACT_COVER_WALL_LOW_R, ACT_COVER_WALL_LOW_R_RIFLE, false }, + { ACT_COVER_WALL_LOW_L, ACT_COVER_WALL_LOW_L_RIFLE, false }, #endif }; From 2c55c6cea753a4991c04e0533361db4c123e1af5 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Thu, 4 Nov 2021 08:44:18 -0500 Subject: [PATCH 203/378] Added a cvar to toggle companion NPCs being able to pick up weapons they couldn't use prior to Mapbase's animation changes --- sp/src/game/server/hl2/npc_playercompanion.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/sp/src/game/server/hl2/npc_playercompanion.cpp b/sp/src/game/server/hl2/npc_playercompanion.cpp index ed782f1b..97bc54be 100644 --- a/sp/src/game/server/hl2/npc_playercompanion.cpp +++ b/sp/src/game/server/hl2/npc_playercompanion.cpp @@ -61,6 +61,10 @@ int AE_COMPANION_RELEASE_FLARE; #define COMPANION_MELEE_DIST 64.0 #endif +#ifdef MAPBASE +ConVar ai_allow_new_weapons( "ai_allow_new_weapons", "1", FCVAR_NONE, "Allows companion NPCs to automatically pick up and use weapons they were unable pick up before, i.e. 357s or crossbows." ); +#endif + #define MAX_TIME_BETWEEN_BARRELS_EXPLODING 5.0f #define MAX_TIME_BETWEEN_CONSECUTIVE_PLAYER_KILLS 3.0f @@ -2737,6 +2741,13 @@ bool CNPC_PlayerCompanion::Weapon_CanUse( CBaseCombatWeapon *pWeapon ) { return (NumWeaponsInSquad("weapon_shotgun") < 1 ); } +#ifdef MAPBASE + else if (EntIsClass( pWeapon, gm_isz_class_Pistol ) || EntIsClass( pWeapon, gm_isz_class_357 ) || EntIsClass( pWeapon, gm_isz_class_Crossbow )) + { + // The AI automatically detects these weapons as usable now that there's animations for them, so ensure this behavior can be toggled in situations where that's not desirable + return ai_allow_new_weapons.GetBool(); + } +#endif else { return true; From a2c2fe09d5bcef205694652928868dd1c2e23003 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Thu, 4 Nov 2021 08:45:10 -0500 Subject: [PATCH 204/378] Added sequence check and backup activity fallback to companion NPC readiness activities --- sp/src/game/server/hl2/npc_playercompanion.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/sp/src/game/server/hl2/npc_playercompanion.cpp b/sp/src/game/server/hl2/npc_playercompanion.cpp index 97bc54be..97901f93 100644 --- a/sp/src/game/server/hl2/npc_playercompanion.cpp +++ b/sp/src/game/server/hl2/npc_playercompanion.cpp @@ -1650,6 +1650,19 @@ Activity CNPC_PlayerCompanion::TranslateActivityReadiness( Activity activity ) continue; } +#ifdef MAPBASE + // If we don't have the readiness activity we selected and there's no backup activity available, break the loop and return the base act. + bool bRequired; + if ( !HaveSequenceForActivity( actremap.mappedActivity ) && !HaveSequenceForActivity( Weapon_TranslateActivity( actremap.mappedActivity, &bRequired ) ) ) + { + Activity backupAct = Weapon_BackupActivity( actremap.mappedActivity, bRequired ); + if ( backupAct != actremap.mappedActivity ) + return backupAct; + else + break; + } +#endif + // We've successfully passed all criteria for remapping this return actremap.mappedActivity; } From 97a6934061afa0a19a8e80be59e0fdcb0ccf7d3d Mon Sep 17 00:00:00 2001 From: Blixibon Date: Thu, 4 Nov 2021 08:48:55 -0500 Subject: [PATCH 205/378] Changed Combine soldier code to reflect the new activity alias overhaul and standoff behavior changes --- sp/src/game/server/hl2/npc_combine.cpp | 50 ++++++++++++-------------- 1 file changed, 22 insertions(+), 28 deletions(-) diff --git a/sp/src/game/server/hl2/npc_combine.cpp b/sp/src/game/server/hl2/npc_combine.cpp index 73f58af5..ebeccf2b 100644 --- a/sp/src/game/server/hl2/npc_combine.cpp +++ b/sp/src/game/server/hl2/npc_combine.cpp @@ -47,9 +47,6 @@ ConVar npc_combine_protected_run( "npc_combine_protected_run", "0", FCVAR_NONE, ConVar npc_combine_altfire_not_allies_only( "npc_combine_altfire_not_allies_only", "1", FCVAR_NONE, "Mapbase: Elites are normally only allowed to fire their alt-fire attack at the player and the player's allies; This allows elites to alt-fire at other enemies too." ); ConVar npc_combine_new_cover_behavior( "npc_combine_new_cover_behavior", "1", FCVAR_NONE, "Mapbase: Toggles small patches for parts of npc_combine AI related to soldiers failing to take cover. These patches are minimal and only change cases where npc_combine would otherwise look at an enemy without shooting or run up to the player to melee attack when they don't have to. Consult the Mapbase wiki for more information." ); - -extern acttable_t *GetSMG1Acttable(); -extern acttable_t *GetPistolActtable(); #endif #define COMBINE_SKIN_DEFAULT 0 @@ -131,10 +128,6 @@ Activity ACT_COMBINE_AR2_ALTFIRE; Activity ACT_WALK_EASY; Activity ACT_WALK_MARCH; #ifdef MAPBASE -Activity ACT_IDLE_UNARMED; -Activity ACT_WALK_UNARMED; -Activity ACT_RUN_UNARMED; -Activity ACT_WALK_EASY_PISTOL; Activity ACT_TURRET_CARRY_IDLE; Activity ACT_TURRET_CARRY_WALK; Activity ACT_TURRET_CARRY_RUN; @@ -553,7 +546,12 @@ void CNPC_Combine::GatherConditions() if( GetState() == NPC_STATE_COMBAT ) { +#ifdef MAPBASE + // Don't override the standoff + if( IsCurSchedule( SCHED_COMBINE_WAIT_IN_COVER, false ) && !m_StandoffBehavior.IsActive() ) +#else if( IsCurSchedule( SCHED_COMBINE_WAIT_IN_COVER, false ) ) +#endif { // Soldiers that are standing around doing nothing poll for attack slots so // that they can respond quickly when one comes available. If they can @@ -1557,12 +1555,6 @@ Activity CNPC_Combine::Weapon_TranslateActivity( Activity eNewActivity, bool *pR //----------------------------------------------------------------------------- Activity CNPC_Combine::NPC_BackupActivity( Activity eNewActivity ) { - // Otherwise we move around, T-posing. - if (eNewActivity == ACT_WALK) - return ACT_WALK_UNARMED; - else if (eNewActivity == ACT_RUN) - return ACT_RUN_RIFLE; - // Some models might not contain ACT_COMBINE_BUGBAIT, which the soldier model uses instead of ACT_IDLE_ON_FIRE. // Contrariwise, soldiers may be called to use ACT_IDLE_ON_FIRE in other parts of the AI and need to translate to ACT_COMBINE_BUGBAIT. if (eNewActivity == ACT_COMBINE_BUGBAIT) @@ -1634,23 +1626,25 @@ Activity CNPC_Combine::NPC_TranslateActivity( Activity eNewActivity ) } } #ifdef MAPBASE - else if (!GetActiveWeapon() && npc_combine_unarmed_anims.GetBool() && HaveSequenceForActivity(ACT_IDLE_UNARMED)) + else if (!GetActiveWeapon() && !npc_combine_unarmed_anims.GetBool()) { if (eNewActivity == ACT_IDLE || eNewActivity == ACT_IDLE_ANGRY) - eNewActivity = ACT_IDLE_UNARMED; + eNewActivity = ACT_IDLE_SMG1; else if (eNewActivity == ACT_WALK) - eNewActivity = ACT_WALK_UNARMED; + eNewActivity = ACT_WALK_RIFLE; else if (eNewActivity == ACT_RUN) - eNewActivity = ACT_RUN_UNARMED; + eNewActivity = ACT_RUN_RIFLE; } - else if (m_NPCState == NPC_STATE_IDLE && npc_combine_idle_walk_easy.GetBool() && HaveSequenceForActivity(ACT_WALK_EASY)) + else if (m_NPCState == NPC_STATE_IDLE && eNewActivity == ACT_WALK) { - if (eNewActivity == ACT_WALK && GetActiveWeapon()) + if (npc_combine_idle_walk_easy.GetBool()) { - if (GetActiveWeapon()->GetBackupActivityList() == GetSMG1Acttable()) - eNewActivity = ACT_WALK_EASY; - else if (GetActiveWeapon()->GetBackupActivityList() == GetPistolActtable()) - eNewActivity = ACT_WALK_EASY_PISTOL; + // ACT_WALK_EASY has been replaced with ACT_WALK_RELAXED for weapon translation purposes + eNewActivity = ACT_WALK_RELAXED; + } + else if (GetActiveWeapon()) + { + eNewActivity = ACT_WALK_RIFLE; } } @@ -2624,7 +2618,6 @@ int CNPC_Combine::TranslateSchedule( int scheduleType ) #ifdef MAPBASE // SCHED_COMBINE_WAIT_IN_COVER uses INCOVER, but only gets out of it when the soldier moves. // That seems to mess up shooting, so this Forget() attempts to fix that. - // I don't know if there's a better workaround. Forget( bits_MEMORY_INCOVER ); #endif @@ -3931,7 +3924,12 @@ bool CNPC_Combine::IsRunningApproachEnemySchedule() bool CNPC_Combine::ShouldPickADeathPose( void ) { +#ifdef MAPBASE + // Check base class as well + return !IsCrouching() && BaseClass::ShouldPickADeathPose(); +#else return !IsCrouching(); +#endif } //----------------------------------------------------------------------------- @@ -3965,10 +3963,6 @@ DECLARE_ACTIVITY( ACT_COMBINE_AR2_ALTFIRE ) DECLARE_ACTIVITY( ACT_WALK_EASY ) DECLARE_ACTIVITY( ACT_WALK_MARCH ) #ifdef MAPBASE -DECLARE_ACTIVITY( ACT_IDLE_UNARMED ) -DECLARE_ACTIVITY( ACT_WALK_UNARMED ) -DECLARE_ACTIVITY( ACT_RUN_UNARMED ) -DECLARE_ACTIVITY( ACT_WALK_EASY_PISTOL ) DECLARE_ACTIVITY( ACT_TURRET_CARRY_IDLE ) DECLARE_ACTIVITY( ACT_TURRET_CARRY_WALK ) DECLARE_ACTIVITY( ACT_TURRET_CARRY_RUN ) From 0ce4251ba3556deab7bc14421abdeeddc676118a Mon Sep 17 00:00:00 2001 From: Blixibon Date: Thu, 4 Nov 2021 09:27:30 -0500 Subject: [PATCH 206/378] Added support for NPC door opening activities and adjustable open distance --- sp/src/game/server/BasePropDoor.h | 12 ++++++ sp/src/game/server/ai_basenpc.cpp | 33 +++++++++++++++ sp/src/game/server/ai_navigator.cpp | 20 ++++++++++ sp/src/game/server/props.cpp | 62 ++++++++++++++++++++++++++++- 4 files changed, 125 insertions(+), 2 deletions(-) diff --git a/sp/src/game/server/BasePropDoor.h b/sp/src/game/server/BasePropDoor.h index d96c75c5..2557bec3 100644 --- a/sp/src/game/server/BasePropDoor.h +++ b/sp/src/game/server/BasePropDoor.h @@ -103,6 +103,12 @@ protected: inline CBaseEntity *GetActivator(); +#ifdef MAPBASE + inline float GetNPCOpenDistance() { return m_flNPCOpenDistance; } + inline Activity GetNPCOpenFrontActivity() { return m_eNPCOpenFrontActivity; } + inline Activity GetNPCOpenBackActivity() { return m_eNPCOpenBackActivity; } +#endif + private: // Implement these in your leaf class. @@ -196,6 +202,12 @@ private: string_t m_SoundOpen; string_t m_SoundClose; +#ifdef MAPBASE + float m_flNPCOpenDistance; + Activity m_eNPCOpenFrontActivity; + Activity m_eNPCOpenBackActivity; +#endif + // dvs: FIXME: can we remove m_flSpeed from CBaseEntity? //float m_flSpeed; // Rotation speed when opening or closing in degrees per second. diff --git a/sp/src/game/server/ai_basenpc.cpp b/sp/src/game/server/ai_basenpc.cpp index 02a8b725..225d8096 100644 --- a/sp/src/game/server/ai_basenpc.cpp +++ b/sp/src/game/server/ai_basenpc.cpp @@ -9763,7 +9763,11 @@ void CAI_BaseNPC::HandleAnimEvent( animevent_t *pEvent ) case NPC_EVENT_OPEN_DOOR: { +#ifdef MAPBASE + CBasePropDoor *pDoor = m_hOpeningDoor; +#else CBasePropDoor *pDoor = (CBasePropDoor *)(CBaseEntity *)GetNavigator()->GetPath()->GetCurWaypoint()->GetEHandleData(); +#endif if (pDoor != NULL) { OpenPropDoorNow( pDoor ); @@ -13951,6 +13955,10 @@ bool CAI_BaseNPC::OnUpcomingPropDoor( AILocalMoveGoal_t *pMoveGoal, GetNavigator()->GetPath()->PrependWaypoints( pOpenDoorRoute ); +#ifdef MAPBASE + GetNavigator()->SetArrivalDirection( opendata.vecFaceDir ); +#endif + m_hOpeningDoor = pDoor; pMoveGoal->maxDist = distClear; *pResult = AIMR_CHANGE_TYPE; @@ -13971,6 +13979,21 @@ bool CAI_BaseNPC::OnUpcomingPropDoor( AILocalMoveGoal_t *pMoveGoal, //----------------------------------------------------------------------------- void CAI_BaseNPC::OpenPropDoorBegin( CBasePropDoor *pDoor ) { +#ifdef MAPBASE + opendata_t opendata; + pDoor->GetNPCOpenData(this, opendata); + + if (HaveSequenceForActivity( opendata.eActivity )) + { + int iLayer = AddGesture( opendata.eActivity ); + float flDuration = GetLayerDuration( iLayer ); + + // Face the door and wait for the activity to finish before trying to move through the doorway. + m_flMoveWaitFinished = gpGlobals->curtime + flDuration + pDoor->GetOpenInterval(); + AddFacingTarget( opendata.vecFaceDir, 1.0, flDuration ); + } + else +#else // dvs: not quite working, disabled for now. //opendata_t opendata; //pDoor->GetNPCOpenData(this, opendata); @@ -13980,6 +14003,7 @@ void CAI_BaseNPC::OpenPropDoorBegin( CBasePropDoor *pDoor ) // SetIdealActivity(opendata.eActivity); //} //else +#endif { // We don't have an appropriate sequence, just open the door magically. OpenPropDoorNow( pDoor ); @@ -13999,6 +14023,15 @@ void CAI_BaseNPC::OpenPropDoorNow( CBasePropDoor *pDoor ) // Wait for the door to finish opening before trying to move through the doorway. m_flMoveWaitFinished = gpGlobals->curtime + pDoor->GetOpenInterval(); + +#ifdef MAPBASE + // Remove the door from our waypoint + if (GetNavigator()->GetPath() && GetNavigator()->GetCurWaypointFlags() & bits_WP_TO_DOOR) + { + GetNavigator()->GetPath()->GetCurWaypoint()->ModifyFlags( bits_WP_TO_DOOR, false ); + GetNavigator()->GetPath()->GetCurWaypoint()->m_hData = NULL; + } +#endif } diff --git a/sp/src/game/server/ai_navigator.cpp b/sp/src/game/server/ai_navigator.cpp index 59c06822..c58471d0 100644 --- a/sp/src/game/server/ai_navigator.cpp +++ b/sp/src/game/server/ai_navigator.cpp @@ -2184,11 +2184,26 @@ bool CAI_Navigator::OnMoveBlocked( AIMoveResult_t *pResult ) if (pDoor != NULL) { GetOuter()->OpenPropDoorBegin( pDoor ); +#ifdef MAPBASE + // Tell the navigation to stop running until we're done. + OnNewGoal(); +#endif *pResult = AIMR_OK; return true; } } +#ifdef MAPBASE + if ( GetOuter()->m_hOpeningDoor ) + { + // In the process of opening a door + // Because navigation is now supposed to terminate when a NPC begins opening a door, this code should not be reached. + DbgNavMsg( GetOuter(), "CAI_Navigator::OnMoveBlocked had to check for m_hOpeningDoor\n" ); + *pResult = AIMR_OK; + return true; + } +#endif + // Allow the NPC to override this behavior if ( GetOuter()->OnMoveBlocked( pResult )) @@ -2719,6 +2734,11 @@ void CAI_Navigator::AdvancePath() if (pDoor != NULL) { GetOuter()->OpenPropDoorBegin(pDoor); + +#ifdef MAPBASE + // Tell the navigation to stop running until we're done. + OnNewGoal(); +#endif } else { diff --git a/sp/src/game/server/props.cpp b/sp/src/game/server/props.cpp index 9263628b..2affea8a 100644 --- a/sp/src/game/server/props.cpp +++ b/sp/src/game/server/props.cpp @@ -4099,6 +4099,11 @@ BEGIN_DATADESC(CBasePropDoor) DEFINE_KEYFIELD(m_SoundClose, FIELD_SOUNDNAME, "soundcloseoverride"), DEFINE_KEYFIELD(m_ls.sLockedSound, FIELD_SOUNDNAME, "soundlockedoverride"), DEFINE_KEYFIELD(m_ls.sUnlockedSound, FIELD_SOUNDNAME, "soundunlockedoverride"), +#ifdef MAPBASE + DEFINE_KEYFIELD(m_flNPCOpenDistance, FIELD_FLOAT, "opendistoverride"), + DEFINE_KEYFIELD(m_eNPCOpenFrontActivity, FIELD_INTEGER, "openfrontactivityoverride"), + DEFINE_KEYFIELD(m_eNPCOpenBackActivity, FIELD_INTEGER, "openbackactivityoverride"), +#endif DEFINE_KEYFIELD(m_SlaveName, FIELD_STRING, "slavename" ), DEFINE_FIELD(m_bLocked, FIELD_BOOLEAN), //DEFINE_KEYFIELD(m_flBlockDamage, FIELD_FLOAT, "dmg"), @@ -4143,6 +4148,11 @@ END_SEND_TABLE() CBasePropDoor::CBasePropDoor( void ) { m_hMaster = NULL; +#ifdef MAPBASE + m_flNPCOpenDistance = -1; + m_eNPCOpenFrontActivity = ACT_INVALID; + m_eNPCOpenBackActivity = ACT_INVALID; +#endif } //----------------------------------------------------------------------------- @@ -4340,6 +4350,32 @@ void CBasePropDoor::CalcDoorSounds() { strSoundLocked = AllocPooledString( pkvHardwareData->GetString( "locked" ) ); strSoundUnlocked = AllocPooledString( pkvHardwareData->GetString( "unlocked" ) ); + +#ifdef MAPBASE + if (m_eNPCOpenFrontActivity == ACT_INVALID) + { + const char *pszActivity = pkvHardwareData->GetString( "activity_front" ); + if (pszActivity[0] != '\0') + { + m_eNPCOpenFrontActivity = (Activity)CAI_BaseNPC::GetActivityID( pszActivity ); + if (m_eNPCOpenFrontActivity == ACT_INVALID) + m_eNPCOpenFrontActivity = ActivityList_RegisterPrivateActivity( pszActivity ); + } + } + if (m_eNPCOpenBackActivity == ACT_INVALID) + { + const char *pszActivity = pkvHardwareData->GetString( "activity_back" ); + if (pszActivity[0] != '\0') + { + m_eNPCOpenBackActivity = (Activity)CAI_BaseNPC::GetActivityID( pszActivity ); + if (m_eNPCOpenBackActivity == ACT_INVALID) + m_eNPCOpenBackActivity = ActivityList_RegisterPrivateActivity( pszActivity ); + } + } + + if (m_flNPCOpenDistance == -1) + m_flNPCOpenDistance = pkvHardwareData->GetFloat( "npc_distance", 32.0 ); +#endif } // If any sounds were missing, try the "defaults" block. @@ -5940,6 +5976,11 @@ void CPropDoorRotating::DoorResume( void ) AngularMove( m_angGoal, m_flSpeed ); } +#ifdef MAPBASE +ConVar ai_door_enable_acts( "ai_door_enable_acts", "1", FCVAR_NONE, "Enables the new door-opening activities." ); +ConVar ai_door_open_dist_override( "ai_door_open_dist_override", "-1", FCVAR_NONE, "Overrides the distance from a door a NPC has to navigate to in order to open a door." ); +#endif + //----------------------------------------------------------------------------- // Purpose: // Input : vecMoveDir - @@ -5961,20 +6002,37 @@ void CPropDoorRotating::GetNPCOpenData(CAI_BaseNPC *pNPC, opendata_t &opendata) Vector vecNPCOrigin = pNPC->GetAbsOrigin(); +#ifdef MAPBASE + float flPosOffset = ai_door_open_dist_override.GetFloat() >= 0.0f ? ai_door_open_dist_override.GetFloat() : GetNPCOpenDistance(); +#else + float flPosOffset = 64; +#endif + if (pNPC->GetAbsOrigin().Dot(vecForward) > GetAbsOrigin().Dot(vecForward)) { // In front of the door relative to the door's forward vector. - opendata.vecStandPos += vecForward * 64; + opendata.vecStandPos += vecForward * flPosOffset; opendata.vecFaceDir = -vecForward; +#ifdef MAPBASE + opendata.eActivity = !ai_door_enable_acts.GetBool() ? ACT_INVALID : GetNPCOpenFrontActivity(); +#endif } else { // Behind the door relative to the door's forward vector. - opendata.vecStandPos -= vecForward * 64; + opendata.vecStandPos -= vecForward * flPosOffset; opendata.vecFaceDir = vecForward; +#ifdef MAPBASE + opendata.eActivity = !ai_door_enable_acts.GetBool() ? ACT_INVALID : GetNPCOpenBackActivity(); +#endif } +#ifdef MAPBASE + if (opendata.eActivity == ACT_INVALID) + opendata.eActivity = ACT_OPEN_DOOR; +#else opendata.eActivity = ACT_OPEN_DOOR; +#endif } From c3176b34d00f88aefd5d45005e7ed2283972ec8c Mon Sep 17 00:00:00 2001 From: Blixibon Date: Thu, 4 Nov 2021 09:30:28 -0500 Subject: [PATCH 207/378] Integrated Reload_NPC into more animation events and changed weapon_crossbow to be able to use a bodygroup instead of a skin for the empty bolt --- sp/src/game/server/ai_basenpc.cpp | 8 ++++++-- sp/src/game/server/hl2/weapon_crossbow.cpp | 18 +++++++++++++----- sp/src/game/shared/basecombatweapon_shared.cpp | 5 +++-- sp/src/game/shared/basecombatweapon_shared.h | 2 +- .../shared/mapbase/weapon_custom_scripted.cpp | 5 +++-- .../shared/mapbase/weapon_custom_scripted.h | 2 +- 6 files changed, 27 insertions(+), 13 deletions(-) diff --git a/sp/src/game/server/ai_basenpc.cpp b/sp/src/game/server/ai_basenpc.cpp index 225d8096..fc8cd287 100644 --- a/sp/src/game/server/ai_basenpc.cpp +++ b/sp/src/game/server/ai_basenpc.cpp @@ -9723,7 +9723,7 @@ void CAI_BaseNPC::HandleAnimEvent( animevent_t *pEvent ) if ( GetActiveWeapon() ) { #ifdef MAPBASE - GetActiveWeapon()->Reload_NPC(); + GetActiveWeapon()->Reload_NPC( true ); #else GetActiveWeapon()->WeaponSound( RELOAD_NPC ); GetActiveWeapon()->m_iClip1 = GetActiveWeapon()->GetMaxClip1(); @@ -9747,8 +9747,12 @@ void CAI_BaseNPC::HandleAnimEvent( animevent_t *pEvent ) case EVENT_WEAPON_RELOAD_FILL_CLIP: { if ( GetActiveWeapon() ) - { + { +#ifdef MAPBASE + GetActiveWeapon()->Reload_NPC( false ); +#else GetActiveWeapon()->m_iClip1 = GetActiveWeapon()->GetMaxClip1(); +#endif ClearCondition(COND_LOW_PRIMARY_AMMO); ClearCondition(COND_NO_PRIMARY_AMMO); ClearCondition(COND_NO_SECONDARY_AMMO); diff --git a/sp/src/game/server/hl2/weapon_crossbow.cpp b/sp/src/game/server/hl2/weapon_crossbow.cpp index 20ec1cc9..1ce3329c 100644 --- a/sp/src/game/server/hl2/weapon_crossbow.cpp +++ b/sp/src/game/server/hl2/weapon_crossbow.cpp @@ -542,7 +542,7 @@ public: virtual bool Holster( CBaseCombatWeapon *pSwitchingTo = NULL ); virtual bool Reload( void ); #ifdef MAPBASE - virtual void Reload_NPC( void ); + virtual void Reload_NPC( bool bPlaySound = true ); #endif virtual void ItemPostFrame( void ); virtual void ItemBusyFrame( void ); @@ -819,11 +819,15 @@ bool CWeaponCrossbow::Reload( void ) //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- -void CWeaponCrossbow::Reload_NPC( void ) +void CWeaponCrossbow::Reload_NPC( bool bPlaySound ) { - BaseClass::Reload_NPC(); + BaseClass::Reload_NPC( bPlaySound ); - m_nSkin = 0; + int iBody = FindBodygroupByName( "bolt" ); + if (iBody != -1) + SetBodygroup( iBody, 0 ); + else + m_nSkin = 0; } #endif @@ -973,7 +977,11 @@ void CWeaponCrossbow::FireNPCBolt( CAI_BaseNPC *pOwner, Vector &vecShootOrigin, m_iClip1--; - m_nSkin = 1; + int iBody = FindBodygroupByName( "bolt" ); + if (iBody != -1) + SetBodygroup( iBody, 1 ); + else + m_nSkin = 1; WeaponSound( SINGLE_NPC ); WeaponSound( SPECIAL2 ); diff --git a/sp/src/game/shared/basecombatweapon_shared.cpp b/sp/src/game/shared/basecombatweapon_shared.cpp index 1036259e..3e23ab0f 100644 --- a/sp/src/game/shared/basecombatweapon_shared.cpp +++ b/sp/src/game/shared/basecombatweapon_shared.cpp @@ -2374,9 +2374,10 @@ bool CBaseCombatWeapon::Reload( void ) //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- -void CBaseCombatWeapon::Reload_NPC( void ) +void CBaseCombatWeapon::Reload_NPC( bool bPlaySound ) { - WeaponSound( RELOAD_NPC ); + if (bPlaySound) + WeaponSound( RELOAD_NPC ); if (UsesClipsForAmmo1()) { diff --git a/sp/src/game/shared/basecombatweapon_shared.h b/sp/src/game/shared/basecombatweapon_shared.h index 0f2fe433..abfdb3b0 100644 --- a/sp/src/game/shared/basecombatweapon_shared.h +++ b/sp/src/game/shared/basecombatweapon_shared.h @@ -321,7 +321,7 @@ public: bool ReloadsSingly( void ) const; #ifdef MAPBASE // Originally created for the crossbow, can be used to add special NPC reloading behavior - virtual void Reload_NPC( void ); + virtual void Reload_NPC( bool bPlaySound = true ); #endif virtual bool AutoFiresFullClip( void ) { return false; } diff --git a/sp/src/game/shared/mapbase/weapon_custom_scripted.cpp b/sp/src/game/shared/mapbase/weapon_custom_scripted.cpp index 7bd4862c..d9155f32 100644 --- a/sp/src/game/shared/mapbase/weapon_custom_scripted.cpp +++ b/sp/src/game/shared/mapbase/weapon_custom_scripted.cpp @@ -398,9 +398,10 @@ bool CWeaponCustomScripted::Reload( void ) return BaseClass::Reload(); } -void CWeaponCustomScripted::Reload_NPC( void ) +void CWeaponCustomScripted::Reload_NPC( bool bPlaySound ) { - SIMPLE_VOID_OVERRIDE( Reload_NPC, NULL ); + ScriptVariant_t pArgs[] = { bPlaySound }; + SIMPLE_VOID_OVERRIDE( Reload_NPC, pArgs ); BaseClass::Reload_NPC(); } diff --git a/sp/src/game/shared/mapbase/weapon_custom_scripted.h b/sp/src/game/shared/mapbase/weapon_custom_scripted.h index f1493ce0..924f1031 100644 --- a/sp/src/game/shared/mapbase/weapon_custom_scripted.h +++ b/sp/src/game/shared/mapbase/weapon_custom_scripted.h @@ -77,7 +77,7 @@ public: void FinishReload( void ); void AbortReload( void ); bool Reload( void ); - void Reload_NPC( void ); + void Reload_NPC( bool bPlaySound = true ); // Weapon firing void PrimaryAttack( void ); // do "+ATTACK" From 6d48f52d12daaeea173debeec219ac0f44d347eb Mon Sep 17 00:00:00 2001 From: Blixibon Date: Thu, 4 Nov 2021 12:00:56 -0500 Subject: [PATCH 208/378] Added weight blending for IK attachment rules --- sp/src/game/client/c_baseanimating.cpp | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/sp/src/game/client/c_baseanimating.cpp b/sp/src/game/client/c_baseanimating.cpp index 13abe166..0dd620d7 100644 --- a/sp/src/game/client/c_baseanimating.cpp +++ b/sp/src/game/client/c_baseanimating.cpp @@ -2797,14 +2797,29 @@ void C_BaseAnimating::CalculateIKLocks( float currentTime ) // debugoverlay->AddBoxOverlay( origin, Vector( -1, -1, -1 ), Vector( 1, 1, 1 ), QAngle( 0, 0, 0 ), 255, 0, 0, 0, 0 ); - float d = (pTarget->est.pos - origin).Length(); + Vector vecDelta = (origin - pTarget->est.pos); + float d = vecDelta.Length(); if ( d >= flDist) continue; flDist = d; - pTarget->SetPos( origin ); - pTarget->SetAngles( angles ); +#ifdef MAPBASE + // For blending purposes, IK attachments should obey weight + if ( pTarget->est.flWeight < 1.0f ) + { + Quaternion qTarget; + AngleQuaternion( angles, qTarget ); + + QuaternionSlerp( pTarget->est.q, qTarget, pTarget->est.flWeight, pTarget->est.q ); + pTarget->SetPos( pTarget->est.pos + (vecDelta * pTarget->est.flWeight) ); + } + else +#endif + { + pTarget->SetPos( origin ); + pTarget->SetAngles( angles ); + } // debugoverlay->AddBoxOverlay( pTarget->est.pos, Vector( -pTarget->est.radius, -pTarget->est.radius, -pTarget->est.radius ), Vector( pTarget->est.radius, pTarget->est.radius, pTarget->est.radius), QAngle( 0, 0, 0 ), 0, 255, 0, 0, 0 ); } From 276d9ff24f9cf68886f29f729bf79b8077b91410 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Thu, 4 Nov 2021 12:04:31 -0500 Subject: [PATCH 209/378] Misc. fixes from prior NPC changes --- sp/src/game/server/ai_basenpc.cpp | 10 ++++++++-- sp/src/game/server/ai_basenpc_schedule.cpp | 9 ++++++--- sp/src/game/server/ai_network.cpp | 2 +- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/sp/src/game/server/ai_basenpc.cpp b/sp/src/game/server/ai_basenpc.cpp index fc8cd287..7167b2c8 100644 --- a/sp/src/game/server/ai_basenpc.cpp +++ b/sp/src/game/server/ai_basenpc.cpp @@ -7308,7 +7308,6 @@ bool CAI_BaseNPC::IsActivityFinished( void ) #ifdef MAPBASE if (GetFakeSequenceGesture() != -1) { - Msg( "Checking if fake sequence gesture is finished\n" ); return IsLayerFinished( GetFakeSequenceGesture() ); } #endif @@ -16260,9 +16259,16 @@ bool CAI_BaseNPC::IsCrouchedActivity( Activity activity ) case ACT_COVER_SMG1_LOW: case ACT_RELOAD_SMG1_LOW: #ifdef MAPBASE - //case ACT_RELOAD_AR2_LOW: +#if AR2_ACTIVITY_FIX == 1 + case ACT_COVER_AR2_LOW: + case ACT_RELOAD_AR2_LOW: +#endif case ACT_RELOAD_PISTOL_LOW: case ACT_RELOAD_SHOTGUN_LOW: +#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES + case ACT_RELOAD_REVOLVER_LOW: + case ACT_RELOAD_CROSSBOW_LOW: +#endif #endif return true; } diff --git a/sp/src/game/server/ai_basenpc_schedule.cpp b/sp/src/game/server/ai_basenpc_schedule.cpp index e0c9feef..61fefb3f 100644 --- a/sp/src/game/server/ai_basenpc_schedule.cpp +++ b/sp/src/game/server/ai_basenpc_schedule.cpp @@ -3374,14 +3374,17 @@ void CAI_BaseNPC::RunTask( const Task_t *pTask ) } else if (IsActivityFinished()) { - // Dismount complete. Fix up our position if we have to + // Dismount complete. + GetMotor()->MoveClimbStop(); + + // Fix up our position if we have to Vector vecTeleportOrigin; if (GetMotor()->MoveClimbShouldTeleportToSequenceEnd( vecTeleportOrigin )) { - GetMotor()->MoveClimbStop(); SetLocalOrigin( vecTeleportOrigin ); - TaskComplete(); } + + TaskComplete(); } break; #else diff --git a/sp/src/game/server/ai_network.cpp b/sp/src/game/server/ai_network.cpp index 818324f0..1323b7ce 100644 --- a/sp/src/game/server/ai_network.cpp +++ b/sp/src/game/server/ai_network.cpp @@ -157,7 +157,7 @@ public: virtual float NodeDistanceSqr( CAI_Node &node ) { // Heavier hints are considered closer - if (node.GetHint() && node.GetHint()->GetHintWeight() != 1.0f) + if ( node.GetHint() && node.GetHint()->GetHintWeight() != 1.0f && (node.GetHint()->GetGroup() == NULL_STRING || node.GetHint()->GetGroup() == m_pNPC->GetHintGroup()) ) { return CNodeFilter::NodeDistanceSqr( node ) * node.GetHint()->GetHintWeightInverse(); } From 67d5d8b20c1239dbaf8cf9d7c219b94b20c987b8 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Fri, 5 Nov 2021 22:13:53 -0500 Subject: [PATCH 210/378] Added proper NPC melee activities --- sp/src/game/server/ai_activity.cpp | 3 +++ sp/src/game/server/hl2/weapon_crowbar.cpp | 5 ++--- sp/src/game/shared/activitylist.cpp | 3 +++ sp/src/game/shared/ai_activity.h | 4 ++++ sp/src/game/shared/hl2mp/weapon_stunstick.cpp | 7 +++---- 5 files changed, 15 insertions(+), 7 deletions(-) diff --git a/sp/src/game/server/ai_activity.cpp b/sp/src/game/server/ai_activity.cpp index f62e38db..02afb3b7 100644 --- a/sp/src/game/server/ai_activity.cpp +++ b/sp/src/game/server/ai_activity.cpp @@ -2272,6 +2272,9 @@ void CAI_BaseNPC::InitDefaultActivitySR(void) ADD_ACTIVITY_TO_SR( ACT_RANGE_ATTACK_RPG_LOW ); ADD_ACTIVITY_TO_SR( ACT_GESTURE_RANGE_ATTACK_RPG ); + ADD_ACTIVITY_TO_SR( ACT_WALK_MELEE ); + ADD_ACTIVITY_TO_SR( ACT_RUN_MELEE ); + ADD_ACTIVITY_TO_SR( ACT_RUN_PACKAGE ); ADD_ACTIVITY_TO_SR( ACT_RUN_SUITCASE ); diff --git a/sp/src/game/server/hl2/weapon_crowbar.cpp b/sp/src/game/server/hl2/weapon_crowbar.cpp index 1a6488c2..8a0daacf 100644 --- a/sp/src/game/server/hl2/weapon_crowbar.cpp +++ b/sp/src/game/server/hl2/weapon_crowbar.cpp @@ -43,9 +43,8 @@ acttable_t CWeaponCrowbar::m_acttable[] = { ACT_IDLE, ACT_IDLE_ANGRY_MELEE, false }, { ACT_IDLE_ANGRY, ACT_IDLE_ANGRY_MELEE, false }, #ifdef EXPANDED_HL2_WEAPON_ACTIVITIES - // Just so we don't have to implement more activities, re-use the MP acts - { ACT_RUN, ACT_MP_RUN_MELEE, false }, - { ACT_WALK, ACT_MP_WALK_MELEE, false }, + { ACT_RUN, ACT_RUN_MELEE, false }, + { ACT_WALK, ACT_WALK_MELEE, false }, { ACT_ARM, ACT_ARM_MELEE, false }, { ACT_DISARM, ACT_DISARM_MELEE, false }, diff --git a/sp/src/game/shared/activitylist.cpp b/sp/src/game/shared/activitylist.cpp index 95ff2144..ecee2eee 100644 --- a/sp/src/game/shared/activitylist.cpp +++ b/sp/src/game/shared/activitylist.cpp @@ -2388,6 +2388,9 @@ void ActivityList_RegisterSharedActivities( void ) REGISTER_SHARED_ACTIVITY( ACT_RANGE_ATTACK_RPG_LOW ); REGISTER_SHARED_ACTIVITY( ACT_GESTURE_RANGE_ATTACK_RPG ); + REGISTER_SHARED_ACTIVITY( ACT_WALK_MELEE ); + REGISTER_SHARED_ACTIVITY( ACT_RUN_MELEE ); + REGISTER_SHARED_ACTIVITY( ACT_RUN_PACKAGE ); REGISTER_SHARED_ACTIVITY( ACT_RUN_SUITCASE ); diff --git a/sp/src/game/shared/ai_activity.h b/sp/src/game/shared/ai_activity.h index 11845787..ad39c548 100644 --- a/sp/src/game/shared/ai_activity.h +++ b/sp/src/game/shared/ai_activity.h @@ -2267,6 +2267,10 @@ typedef enum ACT_RANGE_ATTACK_RPG_LOW, ACT_GESTURE_RANGE_ATTACK_RPG, + // Melee + ACT_WALK_MELEE, + ACT_RUN_MELEE, + // Citizen accessories ACT_RUN_PACKAGE, ACT_RUN_SUITCASE, diff --git a/sp/src/game/shared/hl2mp/weapon_stunstick.cpp b/sp/src/game/shared/hl2mp/weapon_stunstick.cpp index 0884153e..992bd036 100644 --- a/sp/src/game/shared/hl2mp/weapon_stunstick.cpp +++ b/sp/src/game/shared/hl2mp/weapon_stunstick.cpp @@ -82,10 +82,9 @@ acttable_t CWeaponStunStick::m_acttable[] = { ACT_MELEE_ATTACK1, ACT_MELEE_ATTACK_SWING, true }, { ACT_IDLE_ANGRY, ACT_IDLE_ANGRY_MELEE, true }, #ifdef EXPANDED_HL2_WEAPON_ACTIVITIES - // Just so we don't have to implement more activities, re-use the MP acts - { ACT_IDLE, ACT_MP_STAND_MELEE, false }, - { ACT_RUN, ACT_MP_RUN_MELEE, false }, - { ACT_WALK, ACT_MP_WALK_MELEE, false }, + { ACT_IDLE, ACT_IDLE_MELEE, false }, + { ACT_RUN, ACT_RUN_MELEE, false }, + { ACT_WALK, ACT_WALK_MELEE, false }, #endif }; From 447c1850790c45a865cf68b34ba028d2da50eb3c Mon Sep 17 00:00:00 2001 From: Blixibon Date: Fri, 5 Nov 2021 22:14:29 -0500 Subject: [PATCH 211/378] Fixed metrocops not moving to attack --- sp/src/game/server/hl2/npc_metropolice.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sp/src/game/server/hl2/npc_metropolice.cpp b/sp/src/game/server/hl2/npc_metropolice.cpp index b107b971..a8579647 100644 --- a/sp/src/game/server/hl2/npc_metropolice.cpp +++ b/sp/src/game/server/hl2/npc_metropolice.cpp @@ -3907,7 +3907,7 @@ int CNPC_MetroPolice::SelectScheduleNoDirectEnemy() #ifdef MAPBASE // If you see your enemy and you're still arming yourself, wait and don't just charge in // (if your weapon is holstered, you're probably about to arm yourself) - if ( HasCondition( COND_SEE_ENEMY ) && (IsWeaponHolstered() || FindGestureLayer( TranslateActivity( ACT_ARM ) )) ) + if ( HasCondition( COND_SEE_ENEMY ) && GetWeapon(0) && (IsWeaponHolstered() || FindGestureLayer( TranslateActivity( ACT_ARM ) ) != -1) ) { return SCHED_COMBAT_FACE; } From a6d5c079d3ba09a7f6319be4bcd5e37b002d3070 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Fri, 5 Nov 2021 22:18:20 -0500 Subject: [PATCH 212/378] For now, made unhidden npc_sniper translate idle to proper gun-holding activity --- sp/src/game/server/hl2/proto_sniper.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/sp/src/game/server/hl2/proto_sniper.cpp b/sp/src/game/server/hl2/proto_sniper.cpp index 64f11d2a..84eba6df 100644 --- a/sp/src/game/server/hl2/proto_sniper.cpp +++ b/sp/src/game/server/hl2/proto_sniper.cpp @@ -250,6 +250,10 @@ public: virtual int SelectSchedule( void ); virtual int TranslateSchedule( int scheduleType ); +#ifdef MAPBASE + Activity NPC_TranslateActivity( Activity eNewActivity ); +#endif + bool KeyValue( const char *szKeyName, const char *szValue ); void PrescheduleThink( void ); @@ -2036,6 +2040,23 @@ int CProtoSniper::TranslateSchedule( int scheduleType ) return BaseClass::TranslateSchedule( scheduleType ); } +#ifdef MAPBASE +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +Activity CProtoSniper::NPC_TranslateActivity( Activity eNewActivity ) +{ + // ACT_IDLE is now just the soldier's unarmed idle animation. + // Use a gun-holding animation like what unhidden snipers were using before. + if (!HasSpawnFlags( SF_SNIPER_HIDDEN ) && eNewActivity == ACT_IDLE) + { + eNewActivity = ACT_IDLE_SMG1; + } + + return BaseClass::NPC_TranslateActivity( eNewActivity ); +} +#endif + //--------------------------------------------------------- //--------------------------------------------------------- void CProtoSniper::ScopeGlint() From 0f3fd075c23c93c5cf7731015bdaf0c68b9d3dcd Mon Sep 17 00:00:00 2001 From: Blixibon Date: Fri, 5 Nov 2021 23:41:19 -0500 Subject: [PATCH 213/378] Implemented an OverrideMove VScript hook for NPCs --- sp/src/game/server/ai_basenpc.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/sp/src/game/server/ai_basenpc.cpp b/sp/src/game/server/ai_basenpc.cpp index d2ec72bf..8f758e12 100644 --- a/sp/src/game/server/ai_basenpc.cpp +++ b/sp/src/game/server/ai_basenpc.cpp @@ -10690,6 +10690,7 @@ Vector CAI_BaseNPC::GetActualShootPosition( const Vector &shootOrigin ) #ifdef MAPBASE_VSCRIPT if (m_ScriptScope.IsInitialized() && g_Hook_GetActualShootPosition.CanRunInScope(m_ScriptScope)) { + // shootOrigin, target ScriptVariant_t functionReturn; ScriptVariant_t args[] = { shootOrigin, ToHScript( GetEnemy() ) }; if (g_Hook_GetActualShootPosition.Call( m_ScriptScope, &functionReturn, args )) @@ -13544,6 +13545,20 @@ bool CAI_BaseNPC::OverrideMoveFacing( const AILocalMoveGoal_t &move, float flInt bool CAI_BaseNPC::OverrideMove( float flInterval ) { +#ifdef MAPBASE_VSCRIPT + if (m_ScriptScope.IsInitialized() && g_Hook_OverrideMove.CanRunInScope(m_ScriptScope)) + { + // interval + ScriptVariant_t functionReturn; + ScriptVariant_t args[] = { flInterval }; + if (g_Hook_OverrideMove.Call( m_ScriptScope, &functionReturn, args )) + { + if (functionReturn.m_type == FIELD_BOOLEAN) + return functionReturn.m_bool; + } + } +#endif + return false; } From 49cb43d6e7f2a3496704d204f876c39761c32a32 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Fri, 5 Nov 2021 23:53:23 -0500 Subject: [PATCH 214/378] Added prop_dynamic I/O/KV and misc. prop code changes from the Alien Swarm SDK --- sp/src/game/server/props.cpp | 78 +++++++++++++++++++++++++++++++++++- sp/src/game/server/props.h | 9 +++++ 2 files changed, 85 insertions(+), 2 deletions(-) diff --git a/sp/src/game/server/props.cpp b/sp/src/game/server/props.cpp index 9263628b..e29b0e23 100644 --- a/sp/src/game/server/props.cpp +++ b/sp/src/game/server/props.cpp @@ -44,6 +44,7 @@ #ifdef MAPBASE #include "mapbase/GlobalStrings.h" #include "collisionutils.h" +#include "vstdlib/ikeyvaluessystem.h" // From Alien Swarm SDK #endif // memdbgon must be the last include file in a .cpp file!!! @@ -387,8 +388,15 @@ int CBaseProp::ParsePropData( void ) return PARSE_FAILED_NO_DATA; } +#ifdef MAPBASE // From Alien Swarm SDK + static int keyPropData = KeyValuesSystem()->GetSymbolForString( "prop_data" ); + + // Do we have a props section? + KeyValues *pkvPropData = modelKeyValues->FindKey( keyPropData ); +#else // Do we have a props section? KeyValues *pkvPropData = modelKeyValues->FindKey("prop_data"); +#endif if ( !pkvPropData ) { modelKeyValues->deleteThis(); @@ -1200,6 +1208,17 @@ int CBreakableProp::OnTakeDamage( const CTakeDamageInfo &inputInfo ) { m_hLastAttacker.Set( info.GetAttacker() ); } +#ifdef MAPBASE // From Alien Swarm SDK + else if ( info.GetAttacker() ) + { + CBaseEntity *attacker = info.GetAttacker(); + CBaseEntity *attackerOwner = attacker->GetOwnerEntity(); + if ( attackerOwner && attackerOwner->MyCombatCharacterPointer() ) + { + m_hLastAttacker.Set( attackerOwner ); + } + } +#endif float flPropDamage = GetBreakableDamage( info, assert_cast(this) ); info.SetDamage( flPropDamage ); @@ -1999,9 +2018,16 @@ BEGIN_DATADESC( CDynamicProp ) DEFINE_KEYFIELD( m_bDisableBoneFollowers, FIELD_BOOLEAN, "DisableBoneFollowers" ), DEFINE_FIELD( m_bUseHitboxesForRenderBox, FIELD_BOOLEAN ), DEFINE_FIELD( m_nPendingSequence, FIELD_SHORT ), +#ifdef MAPBASE // From Alien Swarm SDK + DEFINE_KEYFIELD( m_bUpdateAttachedChildren, FIELD_BOOLEAN, "updatechildren" ), + DEFINE_KEYFIELD( m_bHoldAnimation, FIELD_BOOLEAN, "HoldAnimation" ), +#endif // Inputs DEFINE_INPUTFUNC( FIELD_STRING, "SetAnimation", InputSetAnimation ), +#ifdef MAPBASE // From Alien Swarm SDK + DEFINE_INPUTFUNC( FIELD_STRING, "SetAnimationNoReset", InputSetAnimationNoReset ), +#endif DEFINE_INPUTFUNC( FIELD_STRING, "SetDefaultAnimation", InputSetDefaultAnimation ), DEFINE_INPUTFUNC( FIELD_VOID, "TurnOn", InputTurnOn ), DEFINE_INPUTFUNC( FIELD_VOID, "TurnOff", InputTurnOff ), @@ -2226,9 +2252,8 @@ void CDynamicProp::CreateBoneFollowers() pBone = pBone->GetNextKey(); } } - - modelKeyValues->deleteThis(); } + modelKeyValues->deleteThis(); // if we got here, we don't have a bone follower section, but if we have a ragdoll // go ahead and create default bone followers for it @@ -2258,7 +2283,11 @@ bool CDynamicProp::TestCollision( const Ray_t &ray, unsigned int mask, trace_t& } } } +#ifdef MAPBASE // From Alien Swarm SDK + return BaseClass::TestCollision( ray, mask, trace ); +#else return false; +#endif } @@ -2366,10 +2395,23 @@ void CDynamicProp::AnimThink( void ) } else { +#ifdef MAPBASE // From Alien Swarm SDK + if ( m_iszDefaultAnim != NULL_STRING && m_bHoldAnimation == false ) + { + PropSetAnim( STRING( m_iszDefaultAnim ) ); + } + + // We need to wait for an animation change to come in + if ( m_bHoldAnimation ) + { + SetNextThink( gpGlobals->curtime + 0.1f ); + } +#else if (m_iszDefaultAnim != NULL_STRING) { PropSetAnim( STRING( m_iszDefaultAnim ) ); } +#endif } } } @@ -2381,6 +2423,17 @@ void CDynamicProp::AnimThink( void ) StudioFrameAdvance(); DispatchAnimEvents(this); m_BoneFollowerManager.UpdateBoneFollowers(this); + +#ifdef MAPBASE // From Alien Swarm SDK + // Update any SetParentAttached children + if ( m_bUpdateAttachedChildren ) + { + for ( CBaseEntity *pChild = FirstMoveChild(); pChild; pChild = pChild->NextMovePeer() ) + { + pChild->PhysicsTouchTriggers(); + } + } +#endif } @@ -2419,6 +2472,19 @@ void CDynamicProp::InputSetAnimation( inputdata_t &inputdata ) PropSetAnim( inputdata.value.String() ); } +#ifdef MAPBASE // From Alien Swarm SDK +//------------------------------------------------------------------------------ +// Purpose: Set the animation unless the prop is already set to this particular animation +//------------------------------------------------------------------------------ +void CDynamicProp::InputSetAnimationNoReset( inputdata_t &inputdata ) +{ + if ( GetSequence() != LookupSequence( inputdata.value.String() ) ) + { + PropSetAnim( inputdata.value.String() ); + } +} +#endif + //------------------------------------------------------------------------------ // Purpose: //------------------------------------------------------------------------------ @@ -6006,6 +6072,14 @@ int CPropDoorRotating::DrawDebugTextOverlays(void) EntityText( text_offset, tempstr, 0); text_offset++; +#ifdef MAPBASE // From Alien Swarm SDK + if ( IsDoorLocked() ) + { + EntityText( text_offset, "LOCKED", 0); + text_offset++; + } +#endif + if ( IsDoorOpen() ) { Q_strncpy(tempstr, "DOOR STATE: OPEN", sizeof(tempstr)); diff --git a/sp/src/game/server/props.h b/sp/src/game/server/props.h index 121dd5c3..ebd87c4d 100644 --- a/sp/src/game/server/props.h +++ b/sp/src/game/server/props.h @@ -329,6 +329,9 @@ public: // Input handlers void InputSetAnimation( inputdata_t &inputdata ); +#ifdef MAPBASE // From Alien Swarm SDK + void InputSetAnimationNoReset( inputdata_t &inputdata ); +#endif void InputSetDefaultAnimation( inputdata_t &inputdata ); void InputTurnOn( inputdata_t &inputdata ); void InputTurnOff( inputdata_t &inputdata ); @@ -345,6 +348,9 @@ public: int m_iTransitionDirection; // Random animations +#ifdef MAPBASE // From Alien Swarm SDK + bool m_bHoldAnimation; +#endif bool m_bRandomAnimator; float m_flNextRandAnim; float m_flMinRandAnimTime; @@ -353,6 +359,9 @@ public: bool m_bStartDisabled; bool m_bDisableBoneFollowers; +#ifdef MAPBASE // From Alien Swarm SDK + bool m_bUpdateAttachedChildren; // For props with children on attachment points, update their child touches as we animate +#endif CNetworkVar( bool, m_bUseHitboxesForRenderBox ); From 03da4d6b583e8107fbb7e10c243c2a01014cd42e Mon Sep 17 00:00:00 2001 From: Blixibon Date: Fri, 5 Nov 2021 23:59:46 -0500 Subject: [PATCH 215/378] Added cvar to ignore timestamps when checking whether or not to rebuild nodegraph, relying on internal map versions instead --- sp/src/game/server/ai_networkmanager.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sp/src/game/server/ai_networkmanager.cpp b/sp/src/game/server/ai_networkmanager.cpp index f366ee57..2477ec67 100644 --- a/sp/src/game/server/ai_networkmanager.cpp +++ b/sp/src/game/server/ai_networkmanager.cpp @@ -71,6 +71,8 @@ CON_COMMAND( ai_debug_node_connect, "Debug the attempted connection between two ConVar g_ai_norebuildgraph( "ai_norebuildgraph", "0" ); #ifdef MAPBASE ConVar g_ai_norebuildgraphmessage( "ai_norebuildgraphmessage", "0", FCVAR_ARCHIVE, "Stops the \"Node graph out of date\" message from appearing when rebuilding node graph" ); + +ConVar g_ai_ignore_graph_timestamps( "g_ai_ignore_graph_timestamps", "1", FCVAR_NONE, "Ignores file timestamps when rebuilding nodegraphs, only relying on internal map version differences" ); #endif @@ -986,6 +988,11 @@ bool CAI_NetworkManager::IsAIFileCurrent ( const char *szMapName ) // dvd build process validates and guarantees correctness, timestamps are allowed to be wrong return true; } + +#ifdef MAPBASE + if (g_ai_ignore_graph_timestamps.GetBool()) + return true; +#endif { const char *pGameDir = CommandLine()->ParmValue( "-game", "hl2" ); From 17d8accd69fde7613a89d8c23d60e3749eb2d02b Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sat, 6 Nov 2021 00:02:05 -0500 Subject: [PATCH 216/378] Fixed a few small issues with NPCs, etc. --- sp/src/game/client/c_effects.cpp | 2 +- sp/src/game/server/hl2/npc_citizen17.cpp | 4 ++++ sp/src/game/server/hl2/npc_combine.cpp | 5 +++-- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/sp/src/game/client/c_effects.cpp b/sp/src/game/client/c_effects.cpp index 135b5645..a273cb28 100644 --- a/sp/src/game/client/c_effects.cpp +++ b/sp/src/game/client/c_effects.cpp @@ -40,7 +40,7 @@ ConVar r_RainSplashPercentage( "r_RainSplashPercentage", "20", FCVAR_CHEAT ); // ConVar r_RainParticleDensity( "r_RainParticleDensity", "1", FCVAR_NONE, "Density of Particle Rain 0-1" ); #ifdef MAPBASE -ConVar r_RainParticleClampOffset_Rain( "r_RainParticleClampOffset_Rain", "112", FCVAR_NONE, "How far inward or outward to extrude clamped precipitation particle systems using the 'Particle Rain' type." ); +ConVar r_RainParticleClampOffset_Rain( "r_RainParticleClampOffset_Rain", "120", FCVAR_NONE, "How far inward or outward to extrude clamped precipitation particle systems using the 'Particle Rain' type." ); ConVar r_RainParticleClampOffset_Ash( "r_RainParticleClampOffset_Ash", "300", FCVAR_NONE, "How far inward or outward to extrude clamped precipitation particle systems using the 'Particle Ash' type." ); ConVar r_RainParticleClampOffset_RainStorm( "r_RainParticleClampOffset_RainStorm", "112", FCVAR_NONE, "How far inward or outward to extrude clamped precipitation particle systems using the 'Particle Rain Storm' type." ); ConVar r_RainParticleClampOffset_Snow( "r_RainParticleClampOffset_Snow", "300", FCVAR_NONE, "How far inward or outward to extrude clamped precipitation particle systems using the 'Particle Snow' type." ); diff --git a/sp/src/game/server/hl2/npc_citizen17.cpp b/sp/src/game/server/hl2/npc_citizen17.cpp index d14fc702..ec49e5a4 100644 --- a/sp/src/game/server/hl2/npc_citizen17.cpp +++ b/sp/src/game/server/hl2/npc_citizen17.cpp @@ -1542,7 +1542,11 @@ int CNPC_Citizen::SelectScheduleRetrieveItem() // Been kicked out of the player squad since the time I located the health. ClearCondition( COND_HEALTH_ITEM_AVAILABLE ); } +#ifdef MAPBASE + else if ( m_FollowBehavior.GetFollowTarget() ) +#else else +#endif { CBaseEntity *pBase = FindHealthItem(m_FollowBehavior.GetFollowTarget()->GetAbsOrigin(), Vector( 120, 120, 120 ) ); CItem *pItem = dynamic_cast(pBase); diff --git a/sp/src/game/server/hl2/npc_combine.cpp b/sp/src/game/server/hl2/npc_combine.cpp index 3076347d..79b30912 100644 --- a/sp/src/game/server/hl2/npc_combine.cpp +++ b/sp/src/game/server/hl2/npc_combine.cpp @@ -748,7 +748,8 @@ Class_T CNPC_Combine::Classify ( void ) //----------------------------------------------------------------------------- bool CNPC_Combine::IsAltFireCapable( void ) { - return IsElite() || m_bAlternateCapable; + // The base class tells us if we're carrying an alt-fire-able weapon. + return (IsElite() || m_bAlternateCapable) && BaseClass::IsAltFireCapable(); } //----------------------------------------------------------------------------- @@ -2024,7 +2025,7 @@ int CNPC_Combine::SelectSchedule( void ) Vector vecTarget = m_hForcedGrenadeTarget->WorldSpaceCenter(); #ifdef MAPBASE - // I switched this to IsAltFireCapable() before, but m_bAlternateCapable makes it necessary to use IsElite() again. + // This was switched to IsAltFireCapable() before, but m_bAlternateCapable makes it necessary to use IsElite() again. #endif if ( IsElite() ) { From 35ca2ab5a69c55374e9c01d2bf18e697c00104f3 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sat, 6 Nov 2021 00:07:06 -0500 Subject: [PATCH 217/378] Added filter keyvalue to npc_heli_avoidsphere --- sp/src/game/server/hl2/cbasehelicopter.h | 4 ++++ sp/src/game/server/hl2/npc_attackchopper.cpp | 25 ++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/sp/src/game/server/hl2/cbasehelicopter.h b/sp/src/game/server/hl2/cbasehelicopter.h index fcf74291..714f62f4 100644 --- a/sp/src/game/server/hl2/cbasehelicopter.h +++ b/sp/src/game/server/hl2/cbasehelicopter.h @@ -267,6 +267,10 @@ private: typedef CHandle AvoidSphereHandle_t; float m_flRadius; +#ifdef MAPBASE + string_t m_iszAvoidFilter; + EHANDLE m_hAvoidFilter; +#endif static CUtlVector< AvoidSphereHandle_t > s_AvoidSpheres; }; diff --git a/sp/src/game/server/hl2/npc_attackchopper.cpp b/sp/src/game/server/hl2/npc_attackchopper.cpp index ddb9752a..ac6efb1c 100644 --- a/sp/src/game/server/hl2/npc_attackchopper.cpp +++ b/sp/src/game/server/hl2/npc_attackchopper.cpp @@ -42,6 +42,10 @@ #include "physics_bone_follower.h" #endif // HL2_EPISODIC +#ifdef MAPBASE +#include "filters.h" +#endif + // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -5680,6 +5684,9 @@ LINK_ENTITY_TO_CLASS( npc_heli_avoidsphere, CAvoidSphere ); BEGIN_DATADESC( CAvoidSphere ) DEFINE_KEYFIELD( m_flRadius, FIELD_FLOAT, "radius" ), +#ifdef MAPBASE + DEFINE_KEYFIELD( m_iszAvoidFilter, FIELD_STRING, "AvoidFilter" ), +#endif END_DATADESC() @@ -5720,6 +5727,18 @@ void CAvoidSphere::Activate( ) { BaseClass::Activate(); s_AvoidSpheres.AddToTail( this ); + +#ifdef MAPBASE + m_hAvoidFilter = gEntList.FindEntityByName( NULL, m_iszAvoidFilter, this ); + if (m_hAvoidFilter) + { + if (dynamic_cast(m_hAvoidFilter.Get()) == NULL) + { + Warning( "%s: \"%s\" is not a valid filter", GetDebugName(), m_hAvoidFilter->GetDebugName() ); + m_hAvoidFilter = NULL; + } + } +#endif } void CAvoidSphere::UpdateOnRemove( ) @@ -5746,6 +5765,12 @@ void CAvoidSphere::ComputeAvoidanceForces( CBaseEntity *pEntity, float flEntityR CAvoidSphere *pSphere = s_AvoidSpheres[i].Get(); const Vector &vecAvoidCenter = pSphere->WorldSpaceCenter(); +#ifdef MAPBASE + // Continue if not passing the avoid sphere filter + if ( pSphere->m_hAvoidFilter && !(static_cast( pSphere->m_hAvoidFilter.Get())->PassesFilter(pSphere, pEntity )) ) + continue; +#endif + // NOTE: This test can be thought of sweeping a sphere through space // and seeing if it intersects the avoidance sphere float flTotalRadius = flEntityRadius + pSphere->m_flRadius; From b22eb9fb06664b3a3aeb3528057f7a6627bee77e Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sat, 6 Nov 2021 09:16:13 -0500 Subject: [PATCH 218/378] Added fog_volume, trigger_tonemap, new color correction code, and various other related changes --- sp/src/game/client/c_baseplayer.cpp | 15 +- sp/src/game/client/c_baseplayer.h | 11 +- sp/src/game/client/c_colorcorrection.cpp | 208 +++++++++-- sp/src/game/client/c_colorcorrection.h | 88 +++++ .../game/client/c_colorcorrectionvolume.cpp | 116 +++++++ sp/src/game/client/clientmode_shared.cpp | 40 +++ sp/src/game/client/clientmode_shared.h | 9 + sp/src/game/client/colorcorrectionmgr.cpp | 125 +++++++ sp/src/game/client/colorcorrectionmgr.h | 36 ++ sp/src/game/client/iclientmode.h | 5 + sp/src/game/client/viewrender.cpp | 5 + sp/src/game/server/colorcorrection.cpp | 193 +++++++---- sp/src/game/server/colorcorrection.h | 147 ++++++++ sp/src/game/server/colorcorrectionvolume.cpp | 13 + sp/src/game/server/env_tonemap_controller.cpp | 328 +++++++++--------- sp/src/game/server/env_tonemap_controller.h | 140 ++++++++ sp/src/game/server/fogvolume.cpp | 153 ++++++++ sp/src/game/server/fogvolume.h | 74 ++++ sp/src/game/server/player.cpp | 205 ++++++++++- sp/src/game/server/player.h | 24 +- sp/src/game/server/playerlocaldata.h | 3 + sp/src/game/server/server_mapbase.vpc | 2 + 22 files changed, 1674 insertions(+), 266 deletions(-) create mode 100644 sp/src/game/client/c_colorcorrection.h create mode 100644 sp/src/game/server/colorcorrection.h create mode 100644 sp/src/game/server/env_tonemap_controller.h create mode 100644 sp/src/game/server/fogvolume.cpp create mode 100644 sp/src/game/server/fogvolume.h diff --git a/sp/src/game/client/c_baseplayer.cpp b/sp/src/game/client/c_baseplayer.cpp index 0b2422fa..57a9c7eb 100644 --- a/sp/src/game/client/c_baseplayer.cpp +++ b/sp/src/game/client/c_baseplayer.cpp @@ -332,7 +332,10 @@ END_RECV_TABLE() RecvPropString( RECVINFO(m_szLastPlaceName) ), - RecvPropEHandle(RECVINFO(m_hPostProcessCtrl)), // Send to everybody - for spectating +#ifdef MAPBASE // From Alien Swarm SDK + RecvPropEHandle( RECVINFO( m_hPostProcessCtrl ) ), // Send to everybody - for spectating + RecvPropEHandle( RECVINFO( m_hColorCorrectionCtrl ) ), // Send to everybody - for spectating +#endif #if defined USES_ECON_ITEMS RecvPropUtlVector( RECVINFO_UTLVECTOR( m_hMyWearables ), MAX_WEARABLES_SENT_FROM_SERVER, RecvPropEHandle(NULL, 0, 0) ), @@ -2918,6 +2921,7 @@ void C_BasePlayer::UpdateFogBlend( void ) } } +#ifdef MAPBASE // From Alien Swarm SDK //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- @@ -2926,6 +2930,15 @@ C_PostProcessController* C_BasePlayer::GetActivePostProcessController() const return m_hPostProcessCtrl.Get(); } +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +C_ColorCorrection* C_BasePlayer::GetActiveColorCorrection() const +{ + return m_hColorCorrectionCtrl.Get(); +} +#endif + //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- diff --git a/sp/src/game/client/c_baseplayer.h b/sp/src/game/client/c_baseplayer.h index 84ccffb5..5b569595 100644 --- a/sp/src/game/client/c_baseplayer.h +++ b/sp/src/game/client/c_baseplayer.h @@ -23,7 +23,10 @@ #include "hintsystem.h" #include "SoundEmitterSystem/isoundemittersystembase.h" #include "c_env_fog_controller.h" +#ifdef MAPBASE // From Alien Swarm SDK #include "c_postprocesscontroller.h" +#include "c_colorcorrection.h" +#endif #include "igameevents.h" #include "GameEventListener.h" @@ -381,7 +384,10 @@ public: void UpdateFogController( void ); void UpdateFogBlend( void ); +#ifdef MAPBASE // From Alien Swarm SDK C_PostProcessController* GetActivePostProcessController() const; + C_ColorCorrection* GetActiveColorCorrection() const; +#endif float GetFOVTime( void ){ return m_flFOVTime; } @@ -647,7 +653,10 @@ private: // One for left and one for right side of step StepSoundCache_t m_StepSoundCache[ 2 ]; - CNetworkHandle(C_PostProcessController, m_hPostProcessCtrl); // active postprocessing controller +#ifdef MAPBASE // From Alien Swarm SDK + CNetworkHandle( C_PostProcessController, m_hPostProcessCtrl ); // active postprocessing controller + CNetworkHandle( C_ColorCorrection, m_hColorCorrectionCtrl ); // active FXVolume color correction +#endif public: diff --git a/sp/src/game/client/c_colorcorrection.cpp b/sp/src/game/client/c_colorcorrection.cpp index 6960031d..12e29768 100644 --- a/sp/src/game/client/c_colorcorrection.cpp +++ b/sp/src/game/client/c_colorcorrection.cpp @@ -6,6 +6,7 @@ //===========================================================================// #include "cbase.h" +#include "c_colorcorrection.h" #include "filesystem.h" #include "cdll_client_int.h" #include "colorcorrectionmgr.h" @@ -17,45 +18,27 @@ static ConVar mat_colcorrection_disableentities( "mat_colcorrection_disableentities", "0", FCVAR_NONE, "Disable map color-correction entities" ); - -//------------------------------------------------------------------------------ -// Purpose : Color correction entity with radial falloff -//------------------------------------------------------------------------------ -class C_ColorCorrection : public C_BaseEntity -{ -public: - DECLARE_CLASS( C_ColorCorrection, C_BaseEntity ); - - DECLARE_CLIENTCLASS(); - - C_ColorCorrection(); - virtual ~C_ColorCorrection(); - - void OnDataChanged(DataUpdateType_t updateType); - bool ShouldDraw(); - - void ClientThink(); - -private: - Vector m_vecOrigin; - - float m_minFalloff; - float m_maxFalloff; - float m_flCurWeight; - char m_netLookupFilename[MAX_PATH]; - - bool m_bEnabled; - - ClientCCHandle_t m_CCHandle; -}; +#ifdef MAPBASE // From Alien Swarm SDK +static ConVar mat_colcorrection_forceentitiesclientside( "mat_colcorrection_forceentitiesclientside", "0", FCVAR_CHEAT, "Forces color correction entities to be updated on the client" ); +#endif IMPLEMENT_CLIENTCLASS_DT(C_ColorCorrection, DT_ColorCorrection, CColorCorrection) RecvPropVector( RECVINFO(m_vecOrigin) ), RecvPropFloat( RECVINFO(m_minFalloff) ), RecvPropFloat( RECVINFO(m_maxFalloff) ), RecvPropFloat( RECVINFO(m_flCurWeight) ), +#ifdef MAPBASE // From Alien Swarm SDK + RecvPropFloat( RECVINFO(m_flMaxWeight) ), + RecvPropFloat( RECVINFO(m_flFadeInDuration) ), + RecvPropFloat( RECVINFO(m_flFadeOutDuration) ), +#endif RecvPropString( RECVINFO(m_netLookupFilename) ), RecvPropBool( RECVINFO(m_bEnabled) ), +#ifdef MAPBASE // From Alien Swarm SDK + RecvPropBool( RECVINFO(m_bMaster) ), + RecvPropBool( RECVINFO(m_bClientSide) ), + RecvPropBool( RECVINFO(m_bExclusive) ) +#endif END_RECV_TABLE() @@ -65,14 +48,43 @@ END_RECV_TABLE() //------------------------------------------------------------------------------ C_ColorCorrection::C_ColorCorrection() { +#ifdef MAPBASE // From Alien Swarm SDK + m_minFalloff = -1.0f; + m_maxFalloff = -1.0f; + m_flFadeInDuration = 0.0f; + m_flFadeOutDuration = 0.0f; + m_flCurWeight = 0.0f; + m_flMaxWeight = 1.0f; + m_netLookupFilename[0] = '\0'; + m_bEnabled = false; + m_bMaster = false; + m_bExclusive = false; +#endif m_CCHandle = INVALID_CLIENT_CCHANDLE; + +#ifdef MAPBASE // From Alien Swarm SDK + m_bFadingIn = false; + m_flFadeStartWeight = 0.0f; + m_flFadeStartTime = 0.0f; + m_flFadeDuration = 0.0f; +#endif } C_ColorCorrection::~C_ColorCorrection() { +#ifdef MAPBASE // From Alien Swarm SDK + g_pColorCorrectionMgr->RemoveColorCorrectionEntity( this, m_CCHandle ); +#else g_pColorCorrectionMgr->RemoveColorCorrection( m_CCHandle ); +#endif } +#ifdef MAPBASE // From Alien Swarm SDK +bool C_ColorCorrection::IsClientSide() const +{ + return m_bClientSide || mat_colcorrection_forceentitiesclientside.GetBool(); +} +#endif //------------------------------------------------------------------------------ // Purpose : @@ -87,11 +99,21 @@ void C_ColorCorrection::OnDataChanged(DataUpdateType_t updateType) { if ( m_CCHandle == INVALID_CLIENT_CCHANDLE ) { +#ifdef MAPBASE // From Alien Swarm SDK + // forming a unique name without extension + char cleanName[MAX_PATH]; + V_StripExtension( m_netLookupFilename, cleanName, sizeof( cleanName ) ); + char name[MAX_PATH]; + Q_snprintf( name, MAX_PATH, "%s_%d", cleanName, entindex() ); + + m_CCHandle = g_pColorCorrectionMgr->AddColorCorrectionEntity( this, name, m_netLookupFilename ); +#else char filename[MAX_PATH]; Q_strncpy( filename, m_netLookupFilename, MAX_PATH ); m_CCHandle = g_pColorCorrectionMgr->AddColorCorrection( filename ); SetNextClientThink( ( m_CCHandle != INVALID_CLIENT_CCHANDLE ) ? CLIENT_THINK_ALWAYS : CLIENT_THINK_NEVER ); +#endif } } } @@ -104,6 +126,129 @@ bool C_ColorCorrection::ShouldDraw() return false; } +#ifdef MAPBASE // From Alien Swarm SDK +void C_ColorCorrection::Update( C_BasePlayer *pPlayer, float ccScale ) +{ + Assert( m_CCHandle != INVALID_CLIENT_CCHANDLE ); + + if ( mat_colcorrection_disableentities.GetInt() ) + { + // Allow the colorcorrectionui panel (or user) to turn off color-correction entities + g_pColorCorrectionMgr->SetColorCorrectionWeight( m_CCHandle, 0.0f, m_bExclusive ); + return; + } + + // fade weight on client + if ( IsClientSide() ) + { + m_flCurWeight = Lerp( GetFadeRatio(), m_flFadeStartWeight, m_bFadingIn ? m_flMaxWeight : 0.0f ); + } + + if( !m_bEnabled && m_flCurWeight == 0.0f ) + { + g_pColorCorrectionMgr->SetColorCorrectionWeight( m_CCHandle, 0.0f, m_bExclusive ); + return; + } + + Vector playerOrigin = pPlayer->GetAbsOrigin(); + + float weight = 0; + if ( ( m_minFalloff != -1 ) && ( m_maxFalloff != -1 ) && m_minFalloff != m_maxFalloff ) + { + float dist = (playerOrigin - m_vecOrigin).Length(); + weight = (dist-m_minFalloff) / (m_maxFalloff-m_minFalloff); + if ( weight<0.0f ) weight = 0.0f; + if ( weight>1.0f ) weight = 1.0f; + } + + g_pColorCorrectionMgr->SetColorCorrectionWeight( m_CCHandle, m_flCurWeight * ( 1.0 - weight ) * ccScale, m_bExclusive ); +} + +void C_ColorCorrection::EnableOnClient( bool bEnable, bool bSkipFade ) +{ + if ( !IsClientSide() ) + { + return; + } + + m_bFadingIn = bEnable; + + // initialize countdown timer + m_flFadeStartWeight = m_flCurWeight; + float flFadeTimeScale = 1.0f; + if ( m_flMaxWeight != 0.0f ) + { + flFadeTimeScale = m_flCurWeight / m_flMaxWeight; + } + + if ( m_bFadingIn ) + { + flFadeTimeScale = 1.0f - flFadeTimeScale; + } + + if ( bSkipFade ) + { + flFadeTimeScale = 0.0f; + } + + StartFade( flFadeTimeScale * ( m_bFadingIn ? m_flFadeInDuration : m_flFadeOutDuration ) ); + + // update the clientside weight once here, in case the fade duration is 0 + m_flCurWeight = Lerp( GetFadeRatio(), m_flFadeStartWeight, m_bFadingIn ? m_flMaxWeight : 0.0f ); +} + +Vector C_ColorCorrection::GetOrigin() +{ + return m_vecOrigin; +} + +float C_ColorCorrection::GetMinFalloff() +{ + return m_minFalloff; +} + +float C_ColorCorrection::GetMaxFalloff() +{ + return m_maxFalloff; +} + +void C_ColorCorrection::SetWeight( float fWeight ) +{ + g_pColorCorrectionMgr->SetColorCorrectionWeight( m_CCHandle, fWeight, false ); +} + +void C_ColorCorrection::StartFade( float flDuration ) +{ + m_flFadeStartTime = gpGlobals->curtime; + m_flFadeDuration = MAX( flDuration, 0.0f ); +} + +float C_ColorCorrection::GetFadeRatio() const +{ + float flRatio = 1.0f; + + if ( m_flFadeDuration != 0.0f ) + { + flRatio = ( gpGlobals->curtime - m_flFadeStartTime ) / m_flFadeDuration; + flRatio = clamp( flRatio, 0.0f, 1.0f ); + } + return flRatio; +} + +bool C_ColorCorrection::IsFadeTimeElapsed() const +{ + return ( ( gpGlobals->curtime - m_flFadeStartTime ) > m_flFadeDuration ) || + ( ( gpGlobals->curtime - m_flFadeStartTime ) < 0.0f ); +} + +void UpdateColorCorrectionEntities( C_BasePlayer *pPlayer, float ccScale, C_ColorCorrection **pList, int listCount ) +{ + for ( int i = 0; i < listCount; i++ ) + { + pList[i]->Update(pPlayer, ccScale); + } +} +#else void C_ColorCorrection::ClientThink() { if ( m_CCHandle == INVALID_CLIENT_CCHANDLE ) @@ -141,6 +286,7 @@ void C_ColorCorrection::ClientThink() BaseClass::ClientThink(); } +#endif diff --git a/sp/src/game/client/c_colorcorrection.h b/sp/src/game/client/c_colorcorrection.h new file mode 100644 index 00000000..63149a0a --- /dev/null +++ b/sp/src/game/client/c_colorcorrection.h @@ -0,0 +1,88 @@ +//========= Mapbase - https://github.com/mapbase-source/source-sdk-2013 ============// +// +// Note that this header exists in the Alien Swarm SDK, but not in stock Source SDK 2013. +// Although technically a new Mapbase file, it only serves to move otherwise identical code, +// so most code and repo conventions will pretend it was always there. +// +// -------------------------------------------------------------------- +// +// Purpose: Color correction entity with simple radial falloff +// +//=============================================================================// + +#ifndef C_COLORCORRECTION_H +#define C_COLORCORRECTION_H +#ifdef _WIN32 +#pragma once +#endif + +#include "colorcorrectionmgr.h" + +//------------------------------------------------------------------------------ +// Purpose : Color correction entity with radial falloff +//------------------------------------------------------------------------------ +class C_ColorCorrection : public C_BaseEntity +{ +public: + DECLARE_CLASS( C_ColorCorrection, C_BaseEntity ); + + DECLARE_CLIENTCLASS(); + + C_ColorCorrection(); + virtual ~C_ColorCorrection(); + + void OnDataChanged(DataUpdateType_t updateType); + bool ShouldDraw(); + +#ifdef MAPBASE // From Alien Swarm SDK + virtual void Update(C_BasePlayer *pPlayer, float ccScale); + + bool IsMaster() const { return m_bMaster; } + bool IsClientSide() const; + bool IsExclusive() const { return m_bExclusive; } + + void EnableOnClient( bool bEnable, bool bSkipFade = false ); + + Vector GetOrigin(); + float GetMinFalloff(); + float GetMaxFalloff(); + + void SetWeight( float fWeight ); + +protected: + void StartFade( float flDuration ); + float GetFadeRatio() const; + bool IsFadeTimeElapsed() const; +#else + void ClientThink(); + +private: +#endif + Vector m_vecOrigin; + + float m_minFalloff; + float m_maxFalloff; + float m_flCurWeight; + char m_netLookupFilename[MAX_PATH]; + + bool m_bEnabled; + +#ifdef MAPBASE // From Alien Swarm SDK + float m_flFadeInDuration; + float m_flFadeOutDuration; + float m_flMaxWeight; + + bool m_bMaster; + bool m_bClientSide; + bool m_bExclusive; + + bool m_bFadingIn; + float m_flFadeStartWeight; + float m_flFadeStartTime; + float m_flFadeDuration; +#endif + + ClientCCHandle_t m_CCHandle; +}; + +#endif diff --git a/sp/src/game/client/c_colorcorrectionvolume.cpp b/sp/src/game/client/c_colorcorrectionvolume.cpp index 4bbcea94..f7e33708 100644 --- a/sp/src/game/client/c_colorcorrectionvolume.cpp +++ b/sp/src/game/client/c_colorcorrectionvolume.cpp @@ -36,9 +36,26 @@ public: void OnDataChanged(DataUpdateType_t updateType); bool ShouldDraw(); +#ifdef MAPBASE // From Alien Swarm SDK + void Update( C_BasePlayer *pPlayer, float ccScale ); + + void StartTouch( C_BaseEntity *pOther ); + void EndTouch( C_BaseEntity *pOther ); +#else void ClientThink(); +#endif private: +#ifdef MAPBASE // From Alien Swarm SDK + float m_LastEnterWeight; + float m_LastEnterTime; + + float m_LastExitWeight; + float m_LastExitTime; + bool m_bEnabled; + float m_MaxWeight; + float m_FadeDuration; +#endif float m_Weight; char m_lookupFilename[MAX_PATH]; @@ -46,6 +63,11 @@ private: }; IMPLEMENT_CLIENTCLASS_DT(C_ColorCorrectionVolume, DT_ColorCorrectionVolume, CColorCorrectionVolume) +#ifdef MAPBASE // From Alien Swarm SDK + RecvPropBool( RECVINFO( m_bEnabled ) ), + RecvPropFloat( RECVINFO( m_MaxWeight ) ), + RecvPropFloat( RECVINFO( m_FadeDuration ) ), +#endif RecvPropFloat( RECVINFO(m_Weight) ), RecvPropString( RECVINFO(m_lookupFilename) ), END_RECV_TABLE() @@ -82,11 +104,21 @@ void C_ColorCorrectionVolume::OnDataChanged(DataUpdateType_t updateType) { if ( m_CCHandle == INVALID_CLIENT_CCHANDLE ) { +#ifdef MAPBASE // From Alien Swarm SDK + // forming a unique name without extension + char cleanName[MAX_PATH]; + V_StripExtension( m_lookupFilename, cleanName, sizeof( cleanName ) ); + char name[MAX_PATH]; + Q_snprintf( name, MAX_PATH, "%s_%d", cleanName, entindex() ); + + m_CCHandle = g_pColorCorrectionMgr->AddColorCorrectionVolume( this, name, m_lookupFilename ); +#else char filename[MAX_PATH]; Q_strncpy( filename, m_lookupFilename, MAX_PATH ); m_CCHandle = g_pColorCorrectionMgr->AddColorCorrection( filename ); SetNextClientThink( ( m_CCHandle != INVALID_CLIENT_CCHANDLE ) ? CLIENT_THINK_ALWAYS : CLIENT_THINK_NEVER ); +#endif } } } @@ -99,11 +131,95 @@ bool C_ColorCorrectionVolume::ShouldDraw() return false; } +#ifdef MAPBASE // From Alien Swarm SDK +//-------------------------------------------------------------------------------------------------------- +void C_ColorCorrectionVolume::StartTouch( CBaseEntity *pEntity ) +{ + m_LastEnterTime = gpGlobals->curtime; + m_LastEnterWeight = m_Weight; +} + + +//-------------------------------------------------------------------------------------------------------- +void C_ColorCorrectionVolume::EndTouch( CBaseEntity *pEntity ) +{ + m_LastExitTime = gpGlobals->curtime; + m_LastExitWeight = m_Weight; +} + + +void C_ColorCorrectionVolume::Update( C_BasePlayer *pPlayer, float ccScale ) +{ + if ( pPlayer ) + { + bool isTouching = CollisionProp()->IsPointInBounds( pPlayer->EyePosition() ); + bool wasTouching = m_LastEnterTime > m_LastExitTime; + + if ( isTouching && !wasTouching ) + { + StartTouch( pPlayer ); + } + else if ( !isTouching && wasTouching ) + { + EndTouch( pPlayer ); + } + } + + if( !m_bEnabled ) + { + m_Weight = 0.0f; + } + else + { + if( m_LastEnterTime > m_LastExitTime ) + { + // we most recently entered the volume + + if( m_Weight < 1.0f ) + { + float dt = gpGlobals->curtime - m_LastEnterTime; + float weight = m_LastEnterWeight + dt / ((1.0f-m_LastEnterWeight)*m_FadeDuration); + if( weight>1.0f ) + weight = 1.0f; + + m_Weight = weight; + } + } + else + { + // we most recently exitted the volume + + if( m_Weight > 0.0f ) + { + float dt = gpGlobals->curtime - m_LastExitTime; + float weight = (1.0f-m_LastExitWeight) + dt / (m_LastExitWeight*m_FadeDuration); + if( weight>1.0f ) + weight = 1.0f; + + m_Weight = 1.0f - weight; + } + } + } + + // Vector entityPosition = GetAbsOrigin(); + g_pColorCorrectionMgr->SetColorCorrectionWeight( m_CCHandle, m_Weight * ccScale ); +} + + +void UpdateColorCorrectionVolumes( C_BasePlayer *pPlayer, float ccScale, C_ColorCorrectionVolume **pList, int listCount ) +{ + for ( int i = 0; i < listCount; i++ ) + { + pList[i]->Update(pPlayer, ccScale); + } +} +#else void C_ColorCorrectionVolume::ClientThink() { Vector entityPosition = GetAbsOrigin(); g_pColorCorrectionMgr->SetColorCorrectionWeight( m_CCHandle, m_Weight ); } +#endif diff --git a/sp/src/game/client/clientmode_shared.cpp b/sp/src/game/client/clientmode_shared.cpp index 6f2aa4b8..f2e6e31d 100644 --- a/sp/src/game/client/clientmode_shared.cpp +++ b/sp/src/game/client/clientmode_shared.cpp @@ -292,8 +292,11 @@ ClientModeShared::ClientModeShared() m_pWeaponSelection = NULL; m_nRootSize[ 0 ] = m_nRootSize[ 1 ] = -1; +#ifdef MAPBASE // From Alien Swarm SDK m_pCurrentPostProcessController = NULL; m_PostProcessLerpTimer.Invalidate(); + m_pCurrentColorCorrection = NULL; +#endif #if defined( REPLAY_ENABLED ) m_pReplayReminderPanel = NULL; @@ -635,6 +638,43 @@ void ClientModeShared::Update() } } +#ifdef MAPBASE // From Alien Swarm SDK +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void ClientModeShared::OnColorCorrectionWeightsReset( void ) +{ + C_ColorCorrection *pNewColorCorrection = NULL; + C_ColorCorrection *pOldColorCorrection = m_pCurrentColorCorrection; + C_BasePlayer* pPlayer = C_BasePlayer::GetLocalPlayer(); + if ( pPlayer ) + { + pNewColorCorrection = pPlayer->GetActiveColorCorrection(); + } + + if ( pNewColorCorrection != pOldColorCorrection ) + { + if ( pOldColorCorrection ) + { + pOldColorCorrection->EnableOnClient( false ); + } + if ( pNewColorCorrection ) + { + pNewColorCorrection->EnableOnClient( true, pOldColorCorrection == NULL ); + } + m_pCurrentColorCorrection = pNewColorCorrection; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +float ClientModeShared::GetColorCorrectionScale( void ) const +{ + return 1.0f; +} +#endif + //----------------------------------------------------------------------------- // This processes all input before SV Move messages are sent //----------------------------------------------------------------------------- diff --git a/sp/src/game/client/clientmode_shared.h b/sp/src/game/client/clientmode_shared.h index a1389f96..20288db8 100644 --- a/sp/src/game/client/clientmode_shared.h +++ b/sp/src/game/client/clientmode_shared.h @@ -91,6 +91,11 @@ public: virtual void ProcessInput(bool bActive); virtual bool CreateMove( float flInputSampleTime, CUserCmd *cmd ); virtual void Update(); +#ifdef MAPBASE // From Alien Swarm SDK + virtual void OnColorCorrectionWeightsReset( void ); + virtual float GetColorCorrectionScale( void ) const; + virtual void ClearCurrentColorCorrection() { m_pCurrentColorCorrection = NULL; } +#endif // Input virtual int KeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding ); @@ -165,12 +170,16 @@ private: CBaseHudWeaponSelection *m_pWeaponSelection; int m_nRootSize[2]; +#ifdef MAPBASE // From Alien Swarm SDK void UpdatePostProcessingEffects(); const C_PostProcessController* m_pCurrentPostProcessController; PostProcessParameters_t m_CurrentPostProcessParameters; PostProcessParameters_t m_LerpStartPostProcessParameters, m_LerpEndPostProcessParameters; CountdownTimer m_PostProcessLerpTimer; + + CHandle m_pCurrentColorCorrection; +#endif }; #endif // CLIENTMODE_NORMAL_H diff --git a/sp/src/game/client/colorcorrectionmgr.cpp b/sp/src/game/client/colorcorrectionmgr.cpp index 770354b0..cf1210ac 100644 --- a/sp/src/game/client/colorcorrectionmgr.cpp +++ b/sp/src/game/client/colorcorrectionmgr.cpp @@ -8,6 +8,12 @@ #include "cbase.h" #include "tier0/vprof.h" #include "colorcorrectionmgr.h" +#ifdef MAPBASE // From Alien Swarm SDK +#include "clientmode_shared.h" //"clientmode.h" + +// NOTE: This has to be the last file included! +#include "tier0/memdbgon.h" +#endif //------------------------------------------------------------------------------ @@ -16,6 +22,13 @@ static CColorCorrectionMgr s_ColorCorrectionMgr; CColorCorrectionMgr *g_pColorCorrectionMgr = &s_ColorCorrectionMgr; +#ifdef MAPBASE // From Alien Swarm SDK +static ConVar mat_colcorrection_editor( "mat_colcorrection_editor", "0" ); + +static CUtlVector g_ColorCorrectionList; +static CUtlVector g_ColorCorrectionVolumeList; +#endif + //------------------------------------------------------------------------------ // Constructor @@ -62,10 +75,89 @@ void CColorCorrectionMgr::RemoveColorCorrection( ClientCCHandle_t h ) } } +#ifdef MAPBASE // From Alien Swarm SDK +ClientCCHandle_t CColorCorrectionMgr::AddColorCorrectionEntity( C_ColorCorrection *pEntity, const char *pName, const char *pFileName ) +{ + ClientCCHandle_t h = AddColorCorrection(pName, pFileName); + if ( h != INVALID_CLIENT_CCHANDLE ) + { + Assert(g_ColorCorrectionList.Find(pEntity) == -1); + g_ColorCorrectionList.AddToTail(pEntity); + } + return h; +} + +void CColorCorrectionMgr::RemoveColorCorrectionEntity( C_ColorCorrection *pEntity, ClientCCHandle_t h) +{ + RemoveColorCorrection(h); + g_ColorCorrectionList.FindAndFastRemove(pEntity); +} + +ClientCCHandle_t CColorCorrectionMgr::AddColorCorrectionVolume( C_ColorCorrectionVolume *pVolume, const char *pName, const char *pFileName ) +{ + ClientCCHandle_t h = AddColorCorrection(pName, pFileName); + if ( h != INVALID_CLIENT_CCHANDLE ) + { + Assert(g_ColorCorrectionVolumeList.Find(pVolume) == -1); + g_ColorCorrectionVolumeList.AddToTail(pVolume); + } + return h; +} + +void CColorCorrectionMgr::RemoveColorCorrectionVolume( C_ColorCorrectionVolume *pVolume, ClientCCHandle_t h) +{ + RemoveColorCorrection(h); + g_ColorCorrectionVolumeList.FindAndFastRemove(pVolume); +} +#endif //------------------------------------------------------------------------------ // Modify color correction weights //------------------------------------------------------------------------------ +#ifdef MAPBASE // From Alien Swarm SDK +void CColorCorrectionMgr::SetColorCorrectionWeight( ClientCCHandle_t h, float flWeight, bool bExclusive ) +{ + if ( h != INVALID_CLIENT_CCHANDLE ) + { + SetWeightParams_t params = { h, flWeight, bExclusive }; + m_colorCorrectionWeights.AddToTail( params ); + if( bExclusive && m_bHaveExclusiveWeight && ( flWeight != 0.0f ) ) + { + DevWarning( "Found multiple active color_correction entities with exclusive setting enabled. This is invalid.\n" ); + } + if ( bExclusive ) + { + m_bHaveExclusiveWeight = true; + m_flExclusiveWeight = flWeight; + } + } +} + +void CColorCorrectionMgr::CommitColorCorrectionWeights() +{ + CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); + + for ( int i = 0; i < m_colorCorrectionWeights.Count(); i++ ) + { + ColorCorrectionHandle_t ccHandle = reinterpret_cast( m_colorCorrectionWeights[i].handle ); + float flWeight = m_colorCorrectionWeights[i].flWeight; + if ( !m_colorCorrectionWeights[i].bExclusive ) + { + flWeight = (1.0f - m_flExclusiveWeight ) * m_colorCorrectionWeights[i].flWeight; + } + pRenderContext->SetLookupWeight( ccHandle, flWeight ); + + // FIXME: NOTE! This doesn't work if the same handle has + // its weight set twice with no intervening calls to ResetColorCorrectionWeights + // which, at the moment, is true + if ( flWeight != 0.0f ) + { + ++m_nActiveWeightCount; + } + } + m_colorCorrectionWeights.RemoveAll(); +} +#else void CColorCorrectionMgr::SetColorCorrectionWeight( ClientCCHandle_t h, float flWeight ) { if ( h != INVALID_CLIENT_CCHANDLE ) @@ -83,6 +175,7 @@ void CColorCorrectionMgr::SetColorCorrectionWeight( ClientCCHandle_t h, float fl } } } +#endif void CColorCorrectionMgr::ResetColorCorrectionWeights() { @@ -93,6 +186,11 @@ void CColorCorrectionMgr::ResetColorCorrectionWeights() CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); pRenderContext->ResetLookupWeights(); m_nActiveWeightCount = 0; +#ifdef MAPBASE // From Alien Swarm SDK + m_bHaveExclusiveWeight = false; + m_flExclusiveWeight = 0.0f; + m_colorCorrectionWeights.RemoveAll(); +#endif } void CColorCorrectionMgr::SetResetable( ClientCCHandle_t h, bool bResetable ) @@ -113,7 +211,34 @@ void CColorCorrectionMgr::SetResetable( ClientCCHandle_t h, bool bResetable ) //------------------------------------------------------------------------------ // Is color correction active? //------------------------------------------------------------------------------ +#ifdef MAPBASE // From Alien Swarm SDK +bool CColorCorrectionMgr::HasNonZeroColorCorrectionWeights() const +{ + return ( m_nActiveWeightCount != 0 ) || mat_colcorrection_editor.GetBool(); +} + +void CColorCorrectionMgr::UpdateColorCorrection() +{ + ResetColorCorrectionWeights(); + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + IClientMode *pClientMode = GetClientModeNormal(); //GetClientMode(); + + Assert( pClientMode ); + if ( !pPlayer || !pClientMode ) + { + return; + } + + pClientMode->OnColorCorrectionWeightsReset(); + float ccScale = pClientMode->GetColorCorrectionScale(); + + UpdateColorCorrectionEntities( pPlayer, ccScale, g_ColorCorrectionList.Base(), g_ColorCorrectionList.Count() ); + UpdateColorCorrectionVolumes( pPlayer, ccScale, g_ColorCorrectionVolumeList.Base(), g_ColorCorrectionVolumeList.Count() ); + CommitColorCorrectionWeights(); +} +#else bool CColorCorrectionMgr::HasNonZeroColorCorrectionWeights() const { return ( m_nActiveWeightCount != 0 ); } +#endif diff --git a/sp/src/game/client/colorcorrectionmgr.h b/sp/src/game/client/colorcorrectionmgr.h index 3d5271db..3eba0f8c 100644 --- a/sp/src/game/client/colorcorrectionmgr.h +++ b/sp/src/game/client/colorcorrectionmgr.h @@ -14,6 +14,10 @@ #include "igamesystem.h" +#ifdef MAPBASE // From Alien Swarm SDK +class C_ColorCorrection; +class C_ColorCorrectionVolume; +#endif //------------------------------------------------------------------------------ // Purpose : Singleton manager for color correction on the client @@ -35,8 +39,21 @@ public: ClientCCHandle_t AddColorCorrection( const char *pName, const char *pFileName = NULL ); void RemoveColorCorrection( ClientCCHandle_t ); +#ifdef MAPBASE // From Alien Swarm SDK + ClientCCHandle_t AddColorCorrectionEntity( C_ColorCorrection *pEntity, const char *pName, const char *pFileName = NULL ); + void RemoveColorCorrectionEntity( C_ColorCorrection *pEntity, ClientCCHandle_t ); + + ClientCCHandle_t AddColorCorrectionVolume( C_ColorCorrectionVolume *pVolume, const char *pName, const char *pFileName = NULL ); + void RemoveColorCorrectionVolume( C_ColorCorrectionVolume *pVolume, ClientCCHandle_t ); +#endif + // Modify color correction weights +#ifdef MAPBASE // From Alien Swarm SDK + void SetColorCorrectionWeight( ClientCCHandle_t h, float flWeight, bool bExclusive = false ); + void UpdateColorCorrection(); +#else void SetColorCorrectionWeight( ClientCCHandle_t h, float flWeight ); +#endif void ResetColorCorrectionWeights(); void SetResetable( ClientCCHandle_t h, bool bResetable ); @@ -45,8 +62,27 @@ public: private: int m_nActiveWeightCount; +#ifdef MAPBASE // From Alien Swarm SDK + bool m_bHaveExclusiveWeight; + float m_flExclusiveWeight; + + struct SetWeightParams_t + { + ClientCCHandle_t handle; + float flWeight; + bool bExclusive; + }; + + CUtlVector< SetWeightParams_t > m_colorCorrectionWeights; + + void CommitColorCorrectionWeights(); +#endif }; +#ifdef MAPBASE // From Alien Swarm SDK +void UpdateColorCorrectionEntities( C_BasePlayer *pPlayer, float ccScale, C_ColorCorrection **pList, int listCount ); +void UpdateColorCorrectionVolumes( C_BasePlayer *pPlayer, float ccScale, C_ColorCorrectionVolume **pList, int listCount ); +#endif //------------------------------------------------------------------------------ // Singleton access diff --git a/sp/src/game/client/iclientmode.h b/sp/src/game/client/iclientmode.h index 2b74f625..38b60047 100644 --- a/sp/src/game/client/iclientmode.h +++ b/sp/src/game/client/iclientmode.h @@ -112,6 +112,11 @@ public: virtual bool CanRecordDemo( char *errorMsg, int length ) const = 0; +#ifdef MAPBASE // From Alien Swarm SDK + virtual void OnColorCorrectionWeightsReset( void ) = 0; + virtual float GetColorCorrectionScale( void ) const = 0; +#endif + virtual void ComputeVguiResConditions( KeyValues *pkvConditions ) = 0; //============================================================================= diff --git a/sp/src/game/client/viewrender.cpp b/sp/src/game/client/viewrender.cpp index e3889d74..c88858d5 100644 --- a/sp/src/game/client/viewrender.cpp +++ b/sp/src/game/client/viewrender.cpp @@ -76,6 +76,7 @@ #ifdef MAPBASE #include "mapbase/c_func_fake_worldportal.h" +#include "colorcorrectionmgr.h" #endif // Projective textures @@ -2133,6 +2134,10 @@ void CViewRender::RenderView( const CViewSetup &view, int nClearFlags, int whatT // Must be first render->SceneBegin(); +#ifdef MAPBASE // From Alien Swarm SDK + g_pColorCorrectionMgr->UpdateColorCorrection(); +#endif + pRenderContext.GetFrom( materials ); pRenderContext->TurnOnToneMapping(); pRenderContext.SafeRelease(); diff --git a/sp/src/game/server/colorcorrection.cpp b/sp/src/game/server/colorcorrection.cpp index 16d01222..69e6db85 100644 --- a/sp/src/game/server/colorcorrection.cpp +++ b/sp/src/game/server/colorcorrection.cpp @@ -5,9 +5,8 @@ // $NoKeywords: $ //===========================================================================// -#include - #include "cbase.h" +#include "colorcorrection.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -16,64 +15,6 @@ static const char *s_pFadeInContextThink = "ColorCorrectionFadeInThink"; static const char *s_pFadeOutContextThink = "ColorCorrectionFadeOutThink"; - -//------------------------------------------------------------------------------ -// FIXME: This really should inherit from something more lightweight -//------------------------------------------------------------------------------ - - -//------------------------------------------------------------------------------ -// Purpose : Shadow control entity -//------------------------------------------------------------------------------ -class CColorCorrection : public CBaseEntity -{ - DECLARE_CLASS( CColorCorrection, CBaseEntity ); -public: - DECLARE_SERVERCLASS(); - DECLARE_DATADESC(); - - CColorCorrection(); - - void Spawn( void ); - int UpdateTransmitState(); - void Activate( void ); - - virtual int ObjectCaps( void ) { return BaseClass::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - - // Inputs - void InputEnable( inputdata_t &inputdata ); - void InputDisable( inputdata_t &inputdata ); - void InputSetFadeInDuration ( inputdata_t &inputdata ); - void InputSetFadeOutDuration ( inputdata_t &inputdata ); - -private: - void FadeIn ( void ); - void FadeOut ( void ); - - void FadeInThink( void ); // Fades lookup weight from Cur->MaxWeight - void FadeOutThink( void ); // Fades lookup weight from CurWeight->0.0 - - - - float m_flFadeInDuration; // Duration for a full 0->MaxWeight transition - float m_flFadeOutDuration; // Duration for a full Max->0 transition - float m_flStartFadeInWeight; - float m_flStartFadeOutWeight; - float m_flTimeStartFadeIn; - float m_flTimeStartFadeOut; - - float m_flMaxWeight; - - bool m_bStartDisabled; - CNetworkVar( bool, m_bEnabled ); - - CNetworkVar( float, m_MinFalloff ); - CNetworkVar( float, m_MaxFalloff ); - CNetworkVar( float, m_flCurWeight ); - CNetworkString( m_netlookupFilename, MAX_PATH ); - - string_t m_lookupFilename; -}; LINK_ENTITY_TO_CLASS(color_correction, CColorCorrection); @@ -97,12 +38,19 @@ BEGIN_DATADESC( CColorCorrection ) DEFINE_KEYFIELD( m_bEnabled, FIELD_BOOLEAN, "enabled" ), DEFINE_KEYFIELD( m_bStartDisabled, FIELD_BOOLEAN, "StartDisabled" ), +#ifdef MAPBASE // From Alien Swarm SDK + DEFINE_KEYFIELD( m_bExclusive, FIELD_BOOLEAN, "exclusive" ), +#endif // DEFINE_ARRAY( m_netlookupFilename, FIELD_CHARACTER, MAX_PATH ), DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ), DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ), DEFINE_INPUTFUNC( FIELD_FLOAT, "SetFadeInDuration", InputSetFadeInDuration ), DEFINE_INPUTFUNC( FIELD_FLOAT, "SetFadeOutDuration", InputSetFadeOutDuration ), +#ifdef MAPBASE + DEFINE_INPUTFUNC( FIELD_FLOAT, "SetMinFalloff", InputSetMinFalloff ), + DEFINE_INPUTFUNC( FIELD_FLOAT, "SetMaxFalloff", InputSetMaxFalloff ), +#endif END_DATADESC() @@ -112,8 +60,18 @@ IMPLEMENT_SERVERCLASS_ST_NOBASE(CColorCorrection, DT_ColorCorrection) SendPropFloat( SENDINFO(m_MinFalloff) ), SendPropFloat( SENDINFO(m_MaxFalloff) ), SendPropFloat( SENDINFO(m_flCurWeight) ), +#ifdef MAPBASE // From Alien Swarm SDK + SendPropFloat( SENDINFO(m_flMaxWeight) ), + SendPropFloat( SENDINFO(m_flFadeInDuration) ), + SendPropFloat( SENDINFO(m_flFadeOutDuration) ), +#endif SendPropString( SENDINFO(m_netlookupFilename) ), SendPropBool( SENDINFO(m_bEnabled) ), +#ifdef MAPBASE // From Alien Swarm SDK + SendPropBool( SENDINFO(m_bMaster) ), + SendPropBool( SENDINFO(m_bClientSide) ), + SendPropBool( SENDINFO(m_bExclusive) ), +#endif END_SEND_TABLE() @@ -132,6 +90,11 @@ CColorCorrection::CColorCorrection() : BaseClass() m_flTimeStartFadeOut = 0.0f; m_netlookupFilename.GetForModify()[0] = 0; m_lookupFilename = NULL_STRING; +#ifdef MAPBASE // From Alien Swarm SDK + m_bMaster = false; + m_bClientSide = false; + m_bExclusive = false; +#endif } @@ -175,6 +138,11 @@ void CColorCorrection::Activate( void ) { BaseClass::Activate(); +#ifdef MAPBASE // From Alien Swarm SDK (moved to Activate() for save/restore support) + m_bMaster = IsMaster(); + m_bClientSide = IsClientSide(); +#endif + Q_strncpy( m_netlookupFilename.GetForModify(), STRING( m_lookupFilename ), MAX_PATH ); } @@ -183,6 +151,11 @@ void CColorCorrection::Activate( void ) //----------------------------------------------------------------------------- void CColorCorrection::FadeIn ( void ) { +#ifdef MAPBASE // From Alien Swarm SDK + if ( m_bClientSide || ( m_bEnabled && m_flCurWeight >= m_flMaxWeight ) ) + return; +#endif + m_bEnabled = true; m_flTimeStartFadeIn = gpGlobals->curtime; m_flStartFadeInWeight = m_flCurWeight; @@ -194,6 +167,11 @@ void CColorCorrection::FadeIn ( void ) //----------------------------------------------------------------------------- void CColorCorrection::FadeOut ( void ) { +#ifdef MAPBASE // From Alien Swarm SDK + if ( m_bClientSide || ( !m_bEnabled && m_flCurWeight <= 0.0f ) ) + return; +#endif + m_bEnabled = false; m_flTimeStartFadeOut = gpGlobals->curtime; m_flStartFadeOutWeight = m_flCurWeight; @@ -230,7 +208,11 @@ void CColorCorrection::FadeInThink( void ) flFadeRatio = clamp ( flFadeRatio, 0.0f, 1.0f ); m_flStartFadeInWeight = clamp ( m_flStartFadeInWeight, 0.0f, 1.0f ); +#ifdef MAPBASE + m_flCurWeight = Lerp( flFadeRatio, m_flStartFadeInWeight, m_flMaxWeight.Get() ); +#else m_flCurWeight = Lerp( flFadeRatio, m_flStartFadeInWeight, m_flMaxWeight ); +#endif SetNextThink( gpGlobals->curtime + COLOR_CORRECTION_ENT_THINK_RATE, s_pFadeInContextThink ); } @@ -312,3 +294,94 @@ void CColorCorrection::InputSetFadeOutDuration( inputdata_t& inputdata ) { m_flFadeOutDuration = inputdata.value.Float(); } + +#ifdef MAPBASE +void CColorCorrection::InputSetMinFalloff( inputdata_t& inputdata ) +{ + m_MinFalloff = inputdata.value.Float(); +} + +void CColorCorrection::InputSetMaxFalloff( inputdata_t& inputdata ) +{ + m_MaxFalloff = inputdata.value.Float(); +} +#endif + +#ifdef MAPBASE // From Alien Swarm SDK +CColorCorrectionSystem s_ColorCorrectionSystem( "ColorCorrectionSystem" ); + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CColorCorrectionSystem *ColorCorrectionSystem( void ) +{ + return &s_ColorCorrectionSystem; +} + + +//----------------------------------------------------------------------------- +// Purpose: Clear out the fog controller. +//----------------------------------------------------------------------------- +void CColorCorrectionSystem::LevelInitPreEntity( void ) +{ + m_hMasterController = NULL; + ListenForGameEvent( "round_start" ); +} + +//----------------------------------------------------------------------------- +// Purpose: Find the master controller. If no controller is +// set as Master, use the first controller found. +//----------------------------------------------------------------------------- +void CColorCorrectionSystem::InitMasterController( void ) +{ + CColorCorrection *pColorCorrection = NULL; + do + { + pColorCorrection = static_cast( gEntList.FindEntityByClassname( pColorCorrection, "color_correction" ) ); + if ( pColorCorrection ) + { + if ( m_hMasterController.Get() == NULL ) + { + m_hMasterController = pColorCorrection; + } + else + { + if ( pColorCorrection->IsMaster() ) + { + m_hMasterController = pColorCorrection; + } + } + } + } while ( pColorCorrection ); +} + +//----------------------------------------------------------------------------- +// Purpose: On a multiplayer map restart, re-find the master controller. +//----------------------------------------------------------------------------- +void CColorCorrectionSystem::FireGameEvent( IGameEvent *pEvent ) +{ + InitMasterController(); +} + +//----------------------------------------------------------------------------- +// Purpose: On level load find the master fog controller. If no controller is +// set as Master, use the first fog controller found. +//----------------------------------------------------------------------------- +void CColorCorrectionSystem::LevelInitPostEntity( void ) +{ + InitMasterController(); + + // HACK: Singleplayer games don't get a call to CBasePlayer::Spawn on level transitions. + // CBasePlayer::Activate is called before this is called so that's too soon to set up the fog controller. + // We don't have a hook similar to Activate that happens after LevelInitPostEntity + // is called, or we could just do this in the player itself. + if ( gpGlobals->maxClients == 1 ) + { + CBasePlayer *pPlayer = UTIL_GetLocalPlayer(); + if ( pPlayer && ( pPlayer->m_hColorCorrectionCtrl.Get() == NULL ) ) + { + pPlayer->InitColorCorrectionController(); + } + } +} +#endif diff --git a/sp/src/game/server/colorcorrection.h b/sp/src/game/server/colorcorrection.h new file mode 100644 index 00000000..2e96eb7c --- /dev/null +++ b/sp/src/game/server/colorcorrection.h @@ -0,0 +1,147 @@ +//========= Mapbase - https://github.com/mapbase-source/source-sdk-2013 ============// +// +// Note that this header exists in the Alien Swarm SDK, but not in stock Source SDK 2013. +// Although technically a new Mapbase file, it only serves to move otherwise identical code, +// so most code and repo conventions will pretend it was always there. +// +// -------------------------------------------------------------------- +// +// Purpose: Color correction entity. +// +//=============================================================================// + +#ifndef COLOR_CORRECTION_H +#define COLOR_CORRECTION_H +#ifdef _WIN32 +#pragma once +#endif + +#include +#include "cbase.h" +#ifdef MAPBASE // From Alien Swarm SDK +#include "GameEventListener.h" + +// Spawn Flags +#define SF_COLORCORRECTION_MASTER 0x0001 +#define SF_COLORCORRECTION_CLIENTSIDE 0x0002 +#endif + +//------------------------------------------------------------------------------ +// FIXME: This really should inherit from something more lightweight +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +// Purpose : Shadow control entity +//------------------------------------------------------------------------------ +class CColorCorrection : public CBaseEntity +{ + DECLARE_CLASS( CColorCorrection, CBaseEntity ); +public: + DECLARE_SERVERCLASS(); + DECLARE_DATADESC(); + + CColorCorrection(); + + void Spawn( void ); + int UpdateTransmitState(); + void Activate( void ); + + virtual int ObjectCaps( void ) { return BaseClass::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } + +#ifdef MAPBASE // From Alien Swarm SDK + bool IsMaster( void ) const { return HasSpawnFlags( SF_COLORCORRECTION_MASTER ); } + + bool IsClientSide( void ) const { return HasSpawnFlags( SF_COLORCORRECTION_CLIENTSIDE ); } + + bool IsExclusive( void ) const { return m_bExclusive; } +#endif + + // Inputs + void InputEnable( inputdata_t &inputdata ); + void InputDisable( inputdata_t &inputdata ); + void InputSetFadeInDuration ( inputdata_t &inputdata ); + void InputSetFadeOutDuration ( inputdata_t &inputdata ); +#ifdef MAPBASE + void InputSetMinFalloff( inputdata_t &inputdata ); + void InputSetMaxFalloff( inputdata_t &inputdata ); +#endif + +private: + void FadeIn ( void ); + void FadeOut ( void ); + + void FadeInThink( void ); // Fades lookup weight from Cur->MaxWeight + void FadeOutThink( void ); // Fades lookup weight from CurWeight->0.0 + + + +#ifdef MAPBASE // From Alien Swarm SDK + CNetworkVar( float, m_flFadeInDuration ); // Duration for a full 0->MaxWeight transition + CNetworkVar( float, m_flFadeOutDuration ); // Duration for a full Max->0 transition +#else + float m_flFadeInDuration; // Duration for a full 0->MaxWeight transition + float m_flFadeOutDuration; // Duration for a full Max->0 transition +#endif + float m_flStartFadeInWeight; + float m_flStartFadeOutWeight; + float m_flTimeStartFadeIn; + float m_flTimeStartFadeOut; + +#ifdef MAPBASE // From Alien Swarm SDK + CNetworkVar( float, m_flMaxWeight ); +#else + float m_flMaxWeight; +#endif + + bool m_bStartDisabled; + CNetworkVar( bool, m_bEnabled ); +#ifdef MAPBASE // From Alien Swarm SDK + CNetworkVar( bool, m_bMaster ); + CNetworkVar( bool, m_bClientSide ); + CNetworkVar( bool, m_bExclusive ); +#endif + + CNetworkVar( float, m_MinFalloff ); + CNetworkVar( float, m_MaxFalloff ); + CNetworkVar( float, m_flCurWeight ); + CNetworkString( m_netlookupFilename, MAX_PATH ); + + string_t m_lookupFilename; +}; + +#ifdef MAPBASE // From Alien Swarm SDK +//============================================================================= +// +// ColorCorrection Controller System. Just a place to store a master controller +// +class CColorCorrectionSystem : public CAutoGameSystem, public CGameEventListener +{ +public: + + // Creation/Init. + CColorCorrectionSystem( char const *name ) : CAutoGameSystem( name ) + { + m_hMasterController = NULL; + } + + ~CColorCorrectionSystem() + { + m_hMasterController = NULL; + } + + virtual void LevelInitPreEntity(); + virtual void LevelInitPostEntity(); + virtual void FireGameEvent( IGameEvent *pEvent ); + CColorCorrection *GetMasterColorCorrection( void ) { return m_hMasterController; } + +private: + + void InitMasterController( void ); + CHandle< CColorCorrection > m_hMasterController; +}; + +CColorCorrectionSystem *ColorCorrectionSystem( void ); +#endif + +#endif // COLOR_CORRECTION_H diff --git a/sp/src/game/server/colorcorrectionvolume.cpp b/sp/src/game/server/colorcorrectionvolume.cpp index a56cd533..abc55d75 100644 --- a/sp/src/game/server/colorcorrectionvolume.cpp +++ b/sp/src/game/server/colorcorrectionvolume.cpp @@ -48,7 +48,11 @@ public: private: +#ifdef MAPBASE // From Alien Swarm SDK + CNetworkVar( bool, m_bEnabled ); +#else bool m_bEnabled; +#endif bool m_bStartDisabled; CNetworkVar( float, m_Weight ); @@ -61,7 +65,11 @@ private: float m_LastExitWeight; float m_LastExitTime; +#ifdef MAPBASE // From Alien Swarm SDK + CNetworkVar( float, m_FadeDuration ); +#else float m_FadeDuration; +#endif }; LINK_ENTITY_TO_CLASS(color_correction_volume, CColorCorrectionVolume); @@ -90,6 +98,11 @@ END_DATADESC() IMPLEMENT_SERVERCLASS_ST_NOBASE(CColorCorrectionVolume, DT_ColorCorrectionVolume) +#ifdef MAPBASE // From Alien Swarm SDK + SendPropBool( SENDINFO(m_bEnabled) ), + SendPropFloat( SENDINFO(m_MaxWeight) ), + SendPropFloat( SENDINFO(m_FadeDuration) ), +#endif SendPropFloat( SENDINFO(m_Weight) ), SendPropString( SENDINFO(m_lookupFilename) ), END_SEND_TABLE() diff --git a/sp/src/game/server/env_tonemap_controller.cpp b/sp/src/game/server/env_tonemap_controller.cpp index bfd4f5a2..492b2046 100644 --- a/sp/src/game/server/env_tonemap_controller.cpp +++ b/sp/src/game/server/env_tonemap_controller.cpp @@ -5,6 +5,7 @@ //============================================================================= #include "cbase.h" +#include "env_tonemap_controller.h" #include "baseentity.h" #include "entityoutput.h" #include "convar.h" @@ -16,50 +17,6 @@ ConVar mat_hdr_tonemapscale( "mat_hdr_tonemapscale", "1.0", FCVAR_CHEAT, "The HDR tonemap scale. 1 = Use autoexposure, 0 = eyes fully closed, 16 = eyes wide open." ); -// 0 - eyes fully closed / fully black -// 1 - nominal -// 16 - eyes wide open / fully white - -//----------------------------------------------------------------------------- -// Purpose: Entity that controls player's tonemap -//----------------------------------------------------------------------------- -class CEnvTonemapController : public CPointEntity -{ - DECLARE_CLASS( CEnvTonemapController, CPointEntity ); -public: - DECLARE_DATADESC(); - DECLARE_SERVERCLASS(); - - void Spawn( void ); - int UpdateTransmitState( void ); - void UpdateTonemapScaleBlend( void ); - - // Inputs - void InputSetTonemapScale( inputdata_t &inputdata ); - void InputBlendTonemapScale( inputdata_t &inputdata ); - void InputSetTonemapRate( inputdata_t &inputdata ); - void InputSetAutoExposureMin( inputdata_t &inputdata ); - void InputSetAutoExposureMax( inputdata_t &inputdata ); - void InputUseDefaultAutoExposure( inputdata_t &inputdata ); - void InputSetBloomScale( inputdata_t &inputdata ); - void InputUseDefaultBloomScale( inputdata_t &inputdata ); - void InputSetBloomScaleRange( inputdata_t &inputdata ); - -private: - float m_flBlendTonemapStart; // HDR Tonemap at the start of the blend - float m_flBlendTonemapEnd; // Target HDR Tonemap at the end of the blend - float m_flBlendEndTime; // Time at which the blend ends - float m_flBlendStartTime; // Time at which the blend started - - CNetworkVar( bool, m_bUseCustomAutoExposureMin ); - CNetworkVar( bool, m_bUseCustomAutoExposureMax ); - CNetworkVar( bool, m_bUseCustomBloomScale ); - CNetworkVar( float, m_flCustomAutoExposureMin ); - CNetworkVar( float, m_flCustomAutoExposureMax ); - CNetworkVar( float, m_flCustomBloomScale); - CNetworkVar( float, m_flCustomBloomScaleMinimum); -}; - LINK_ENTITY_TO_CLASS( env_tonemap_controller, CEnvTonemapController ); BEGIN_DATADESC( CEnvTonemapController ) @@ -120,27 +77,72 @@ int CEnvTonemapController::UpdateTransmitState() return SetTransmitState( FL_EDICT_ALWAYS ); } +#ifdef MAPBASE +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CEnvTonemapController::KeyValue( const char *szKeyName, const char *szValue ) +{ + if ( FStrEq( szKeyName, "TonemapScale" ) ) + { + float flTonemapScale = atof( szValue ); + if (flTonemapScale != -1.0f) + { + mat_hdr_tonemapscale.SetValue( flTonemapScale ); + } + } + else if (FStrEq( szKeyName, "TonemapRate" )) + { + float flTonemapRate = atof( szValue ); + if (flTonemapRate != -1.0f) + { + ConVarRef mat_hdr_manual_tonemap_rate( "mat_hdr_manual_tonemap_rate" ); + if ( mat_hdr_manual_tonemap_rate.IsValid() ) + { + mat_hdr_manual_tonemap_rate.SetValue( flTonemapRate ); + } + } + } + else if (FStrEq( szKeyName, "AutoExposureMin" )) + { + float flAutoExposureMin = atof( szValue ); + if (flAutoExposureMin != 1.0f) + { + m_flCustomAutoExposureMin = flAutoExposureMin; + m_bUseCustomAutoExposureMin = true; + } + } + else if (FStrEq( szKeyName, "AutoExposureMax" )) + { + float flAutoExposureMax = atof( szValue ); + if (flAutoExposureMax != 1.0f) + { + m_flCustomAutoExposureMax = flAutoExposureMax; + m_bUseCustomAutoExposureMax = true; + } + } + else if (FStrEq( szKeyName, "BloomScale" )) + { + float flBloomScale = atof( szValue ); + if (flBloomScale != 1.0f) + { + m_flCustomBloomScale = flBloomScale; + m_flCustomBloomScaleMinimum = flBloomScale; + m_bUseCustomBloomScale = true; + } + } + else + return BaseClass::KeyValue( szKeyName, szValue ); + + return true; +} +#endif + //----------------------------------------------------------------------------- // Purpose: Set the tonemap scale to the specified value //----------------------------------------------------------------------------- void CEnvTonemapController::InputSetTonemapScale( inputdata_t &inputdata ) { - //Tony; in multiplayer, we check to see if the activator is a player, if they are, we trigger an input on them, and then get out. - //if there is no activator, or the activator is not a player; ie: LogicAuto, we set the 'global' values. - if ( ( gpGlobals->maxClients > 1 ) ) - { - if ( inputdata.pActivator != NULL && inputdata.pActivator->IsPlayer() ) - { -// DevMsg("activator is a player: InputSetTonemapScale\n"); - CBasePlayer *pPlayer = ToBasePlayer(inputdata.pActivator); - if (pPlayer) - { - pPlayer->InputSetTonemapScale( inputdata ); - return; - } - } - } - float flRemapped = inputdata.value.Float(); mat_hdr_tonemapscale.SetValue( flRemapped ); } @@ -150,10 +152,6 @@ void CEnvTonemapController::InputSetTonemapScale( inputdata_t &inputdata ) //----------------------------------------------------------------------------- void CEnvTonemapController::InputBlendTonemapScale( inputdata_t &inputdata ) { - //Tony; TODO!!! -- tonemap scale blending does _not_ work properly in multiplayer.. - if ( ( gpGlobals->maxClients > 1 ) ) - return; - char parseString[255]; Q_strncpy(parseString, inputdata.value.String(), sizeof(parseString)); @@ -207,22 +205,6 @@ void CEnvTonemapController::InputSetBloomScaleRange( inputdata_t &inputdata ) //----------------------------------------------------------------------------- void CEnvTonemapController::InputSetTonemapRate( inputdata_t &inputdata ) { - //Tony; in multiplayer, we check to see if the activator is a player, if they are, we trigger an input on them, and then get out. - //if there is no activator, or the activator is not a player; ie: LogicAuto, we set the 'global' values. - if ( ( gpGlobals->maxClients > 1 ) ) - { - if ( inputdata.pActivator != NULL && inputdata.pActivator->IsPlayer() ) - { -// DevMsg("activator is a player: InputSetTonemapRate\n"); - CBasePlayer *pPlayer = ToBasePlayer(inputdata.pActivator); - if (pPlayer) - { - pPlayer->InputSetTonemapRate( inputdata ); - return; - } - } - } - // TODO: There should be a better way to do this. ConVarRef mat_hdr_manual_tonemap_rate( "mat_hdr_manual_tonemap_rate" ); if ( mat_hdr_manual_tonemap_rate.IsValid() ) @@ -254,22 +236,6 @@ void CEnvTonemapController::UpdateTonemapScaleBlend( void ) //----------------------------------------------------------------------------- void CEnvTonemapController::InputSetAutoExposureMin( inputdata_t &inputdata ) { - //Tony; in multiplayer, we check to see if the activator is a player, if they are, we trigger an input on them, and then get out. - //if there is no activator, or the activator is not a player; ie: LogicAuto, we set the 'global' values. - if ( ( gpGlobals->maxClients > 1 ) ) - { - if ( inputdata.pActivator != NULL && inputdata.pActivator->IsPlayer() ) - { -// DevMsg("activator is a player: InputSetAutoExposureMin\n"); - CBasePlayer *pPlayer = ToBasePlayer(inputdata.pActivator); - if (pPlayer) - { - pPlayer->InputSetAutoExposureMin( inputdata ); - return; - } - } - } - m_flCustomAutoExposureMin = inputdata.value.Float(); m_bUseCustomAutoExposureMin = true; } @@ -279,22 +245,6 @@ void CEnvTonemapController::InputSetAutoExposureMin( inputdata_t &inputdata ) //----------------------------------------------------------------------------- void CEnvTonemapController::InputSetAutoExposureMax( inputdata_t &inputdata ) { - //Tony; in multiplayer, we check to see if the activator is a player, if they are, we trigger an input on them, and then get out. - //if there is no activator, or the activator is not a player; ie: LogicAuto, we set the 'global' values. - if ( ( gpGlobals->maxClients > 1 ) ) - { - if ( inputdata.pActivator != NULL && inputdata.pActivator->IsPlayer() ) - { -// DevMsg("activator is a player: InputSetAutoExposureMax\n"); - CBasePlayer *pPlayer = ToBasePlayer(inputdata.pActivator); - if (pPlayer) - { - pPlayer->InputSetAutoExposureMax( inputdata ); - return; - } - } - } - m_flCustomAutoExposureMax = inputdata.value.Float(); m_bUseCustomAutoExposureMax = true; } @@ -304,22 +254,6 @@ void CEnvTonemapController::InputSetAutoExposureMax( inputdata_t &inputdata ) //----------------------------------------------------------------------------- void CEnvTonemapController::InputUseDefaultAutoExposure( inputdata_t &inputdata ) { - //Tony; in multiplayer, we check to see if the activator is a player, if they are, we trigger an input on them, and then get out. - //if there is no activator, or the activator is not a player; ie: LogicAuto, we set the 'global' values. - if ( ( gpGlobals->maxClients > 1 ) ) - { - if ( inputdata.pActivator != NULL && inputdata.pActivator->IsPlayer() ) - { -// DevMsg("activator is a player: InputUseDefaultAutoExposure\n"); - CBasePlayer *pPlayer = ToBasePlayer(inputdata.pActivator); - if (pPlayer) - { - pPlayer->InputUseDefaultAutoExposure( inputdata ); - return; - } - } - } - m_bUseCustomAutoExposureMin = false; m_bUseCustomAutoExposureMax = false; } @@ -329,22 +263,6 @@ void CEnvTonemapController::InputUseDefaultAutoExposure( inputdata_t &inputdata //----------------------------------------------------------------------------- void CEnvTonemapController::InputSetBloomScale( inputdata_t &inputdata ) { - //Tony; in multiplayer, we check to see if the activator is a player, if they are, we trigger an input on them, and then get out. - //if there is no activator, or the activator is not a player; ie: LogicAuto, we set the 'global' values. - if ( ( gpGlobals->maxClients > 1 ) ) - { - if ( inputdata.pActivator != NULL && inputdata.pActivator->IsPlayer() ) - { -// DevMsg("activator is a player: InputSetBloomScale\n"); - CBasePlayer *pPlayer = ToBasePlayer(inputdata.pActivator); - if (pPlayer) - { - pPlayer->InputSetBloomScale( inputdata ); - return; - } - } - } - m_flCustomBloomScale = inputdata.value.Float(); m_flCustomBloomScaleMinimum = m_flCustomBloomScale; m_bUseCustomBloomScale = true; @@ -355,21 +273,111 @@ void CEnvTonemapController::InputSetBloomScale( inputdata_t &inputdata ) //----------------------------------------------------------------------------- void CEnvTonemapController::InputUseDefaultBloomScale( inputdata_t &inputdata ) { - //Tony; in multiplayer, we check to see if the activator is a player, if they are, we trigger an input on them, and then get out. - //if there is no activator, or the activator is not a player; ie: LogicAuto, we set the 'global' values. - if ( ( gpGlobals->maxClients > 1 ) ) - { - if ( inputdata.pActivator != NULL && inputdata.pActivator->IsPlayer() ) - { -// DevMsg("activator is a player: InputUseDefaultBloomScale\n"); - CBasePlayer *pPlayer = ToBasePlayer(inputdata.pActivator); - if (pPlayer) - { - pPlayer->InputUseDefaultBloomScale( inputdata ); - return; - } - } - } - m_bUseCustomBloomScale = false; } + +#ifdef MAPBASE // From Alien Swarm SDK +//-------------------------------------------------------------------------------------------------------- +LINK_ENTITY_TO_CLASS( trigger_tonemap, CTonemapTrigger ); + +BEGIN_DATADESC( CTonemapTrigger ) + DEFINE_KEYFIELD( m_tonemapControllerName, FIELD_STRING, "TonemapName" ), +END_DATADESC() + + +//-------------------------------------------------------------------------------------------------------- +void CTonemapTrigger::Spawn( void ) +{ + AddSpawnFlags( SF_TRIGGER_ALLOW_CLIENTS ); + + BaseClass::Spawn(); + InitTrigger(); + + m_hTonemapController = gEntList.FindEntityByName( NULL, m_tonemapControllerName ); +} + + +//-------------------------------------------------------------------------------------------------------- +void CTonemapTrigger::StartTouch( CBaseEntity *other ) +{ + if ( !PassesTriggerFilters( other ) ) + return; + + BaseClass::StartTouch( other ); + + CBasePlayer *player = ToBasePlayer( other ); + if ( !player ) + return; + + player->OnTonemapTriggerStartTouch( this ); +} + + +//-------------------------------------------------------------------------------------------------------- +void CTonemapTrigger::EndTouch( CBaseEntity *other ) +{ + if ( !PassesTriggerFilters( other ) ) + return; + + BaseClass::EndTouch( other ); + + CBasePlayer *player = ToBasePlayer( other ); + if ( !player ) + return; + + player->OnTonemapTriggerEndTouch( this ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Clear out the tonemap controller. +//----------------------------------------------------------------------------- +void CTonemapSystem::LevelInitPreEntity( void ) +{ + m_hMasterController = NULL; +} + +//----------------------------------------------------------------------------- +// Purpose: On level load find the master fog controller. If no controller is +// set as Master, use the first fog controller found. +//----------------------------------------------------------------------------- +void CTonemapSystem::LevelInitPostEntity( void ) +{ + // Overall master controller + CEnvTonemapController *pTonemapController = NULL; + do + { + pTonemapController = static_cast( gEntList.FindEntityByClassname( pTonemapController, "env_tonemap_controller" ) ); + if ( pTonemapController ) + { + if ( m_hMasterController == NULL ) + { + m_hMasterController = pTonemapController; + } + else + { + if ( pTonemapController->IsMaster() ) + { + m_hMasterController = pTonemapController; + } + } + } + } while ( pTonemapController ); + + +} + + +//-------------------------------------------------------------------------------------------------------- +CTonemapSystem s_TonemapSystem( "TonemapSystem" ); + + +//-------------------------------------------------------------------------------------------------------- +CTonemapSystem *TheTonemapSystem( void ) +{ + return &s_TonemapSystem; +} + + +//-------------------------------------------------------------------------------------------------------- +#endif diff --git a/sp/src/game/server/env_tonemap_controller.h b/sp/src/game/server/env_tonemap_controller.h new file mode 100644 index 00000000..94e3e0f4 --- /dev/null +++ b/sp/src/game/server/env_tonemap_controller.h @@ -0,0 +1,140 @@ +//========= Mapbase - https://github.com/mapbase-source/source-sdk-2013 ============// +// +// Note that this header exists in the Alien Swarm SDK, but not in stock Source SDK 2013. +// Although technically a new Mapbase file, it only serves to move otherwise identical code, +// so most code and repo conventions will pretend it was always there. +// +// -------------------------------------------------------------------- +// +// Purpose: +// +//=============================================================================// + +#ifndef ENV_TONEMAP_CONTROLLER_H +#define ENV_TONEMAP_CONTROLLER_H + +#include "triggers.h" + +// 0 - eyes fully closed / fully black +// 1 - nominal +// 16 - eyes wide open / fully white + +#ifdef MAPBASE // From Alien Swarm SDK +// Spawn Flags +#define SF_TONEMAP_MASTER 0x0001 +#endif + +//----------------------------------------------------------------------------- +// Purpose: Entity that controls player's tonemap +//----------------------------------------------------------------------------- +class CEnvTonemapController : public CPointEntity +{ + DECLARE_CLASS( CEnvTonemapController, CPointEntity ); +public: + DECLARE_DATADESC(); + DECLARE_SERVERCLASS(); + + void Spawn( void ); + int UpdateTransmitState( void ); + void UpdateTonemapScaleBlend( void ); + +#ifdef MAPBASE + bool IsMaster( void ) const { return HasSpawnFlags( SF_TONEMAP_MASTER ); } // From Alien Swarm SDK + + bool KeyValue( const char *szKeyName, const char *szValue ); +#endif + + // Inputs + void InputSetTonemapScale( inputdata_t &inputdata ); + void InputBlendTonemapScale( inputdata_t &inputdata ); + void InputSetTonemapRate( inputdata_t &inputdata ); + void InputSetAutoExposureMin( inputdata_t &inputdata ); + void InputSetAutoExposureMax( inputdata_t &inputdata ); + void InputUseDefaultAutoExposure( inputdata_t &inputdata ); + void InputSetBloomScale( inputdata_t &inputdata ); + void InputUseDefaultBloomScale( inputdata_t &inputdata ); + void InputSetBloomScaleRange( inputdata_t &inputdata ); + +private: + float m_flBlendTonemapStart; // HDR Tonemap at the start of the blend + float m_flBlendTonemapEnd; // Target HDR Tonemap at the end of the blend + float m_flBlendEndTime; // Time at which the blend ends + float m_flBlendStartTime; // Time at which the blend started + +#ifdef MAPBASE // From Alien Swarm SDK +public: +#endif + CNetworkVar( bool, m_bUseCustomAutoExposureMin ); + CNetworkVar( bool, m_bUseCustomAutoExposureMax ); + CNetworkVar( bool, m_bUseCustomBloomScale ); + CNetworkVar( float, m_flCustomAutoExposureMin ); + CNetworkVar( float, m_flCustomAutoExposureMax ); + CNetworkVar( float, m_flCustomBloomScale); + CNetworkVar( float, m_flCustomBloomScaleMinimum); +}; + +#ifdef MAPBASE // From Alien Swarm SDK +//-------------------------------------------------------------------------------------------------------- +class CTonemapTrigger : public CBaseTrigger +{ +public: + DECLARE_CLASS( CTonemapTrigger, CBaseTrigger ); + DECLARE_DATADESC(); + + virtual void Spawn( void ); + virtual void StartTouch( CBaseEntity *other ); + virtual void EndTouch( CBaseEntity *other ); + + CBaseEntity *GetTonemapController( void ) const; + +private: + string_t m_tonemapControllerName; + EHANDLE m_hTonemapController; +}; + + +//-------------------------------------------------------------------------------------------------------- +inline CBaseEntity *CTonemapTrigger::GetTonemapController( void ) const +{ + return m_hTonemapController.Get(); +} + + +//-------------------------------------------------------------------------------------------------------- +// Tonemap Controller System. +class CTonemapSystem : public CAutoGameSystem +{ +public: + + // Creation/Init. + CTonemapSystem( char const *name ) : CAutoGameSystem( name ) + { + m_hMasterController = NULL; + } + + ~CTonemapSystem() + { + m_hMasterController = NULL; + } + + virtual void LevelInitPreEntity(); + virtual void LevelInitPostEntity(); + CBaseEntity *GetMasterTonemapController( void ) const; + +private: + + EHANDLE m_hMasterController; +}; + + +//-------------------------------------------------------------------------------------------------------- +inline CBaseEntity *CTonemapSystem::GetMasterTonemapController( void ) const +{ + return m_hMasterController.Get(); +} + +//-------------------------------------------------------------------------------------------------------- +CTonemapSystem *TheTonemapSystem( void ); +#endif + +#endif //ENV_TONEMAP_CONTROLLER_H \ No newline at end of file diff --git a/sp/src/game/server/fogvolume.cpp b/sp/src/game/server/fogvolume.cpp new file mode 100644 index 00000000..f2f9a718 --- /dev/null +++ b/sp/src/game/server/fogvolume.cpp @@ -0,0 +1,153 @@ +//-------------------------------------------------------------------------------------------------------- +// Copyright (c) 2007 Turtle Rock Studios, Inc. - All Rights Reserved + +#include "cbase.h" +#include "fogvolume.h" +#include "collisionutils.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + +CUtlVector< CFogVolume * > TheFogVolumes; + +ConVar fog_volume_debug( "fog_volume_debug", "0", 0, "If enabled, prints diagnostic information about the current fog volume" ); + +//-------------------------------------------------------------------------------------------------------- +LINK_ENTITY_TO_CLASS(fog_volume, CFogVolume); + +BEGIN_DATADESC( CFogVolume ) + + DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ), + DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ), + + DEFINE_KEYFIELD( m_fogName, FIELD_STRING, "FogName" ), + DEFINE_KEYFIELD( m_postProcessName, FIELD_STRING, "PostProcessName" ), + DEFINE_KEYFIELD( m_colorCorrectionName, FIELD_STRING, "ColorCorrectionName" ), + DEFINE_KEYFIELD( m_bDisabled, FIELD_BOOLEAN, "StartDisabled" ), + + DEFINE_FIELD( m_hFogController, FIELD_EHANDLE ), + DEFINE_FIELD( m_hPostProcessController, FIELD_EHANDLE ), + DEFINE_FIELD( m_hColorCorrectionController, FIELD_EHANDLE ), + +END_DATADESC() + + +//-------------------------------------------------------------------------------------------------------- +CFogVolume *CFogVolume::FindFogVolumeForPosition( const Vector &position ) +{ + CFogVolume *fogVolume = NULL; + for ( int i=0; iCollisionProp()->WorldToCollisionSpace( position, &vecRelativeCenter ); + if ( IsBoxIntersectingSphere( fogVolume->CollisionProp()->OBBMins(), fogVolume->CollisionProp()->OBBMaxs(), vecRelativeCenter, 1.0f ) ) + { + break; + } + fogVolume = NULL; + } + + // This doesn't work well if there are multiple players or multiple fog volume queries per frame; might want to relocate this if that's the case + if ( fog_volume_debug.GetBool() ) + { + if ( fogVolume ) + { + char fogVolumeName[256]; + fogVolume->GetKeyValue( "targetname", fogVolumeName, 256 ); + engine->Con_NPrintf( 0, "Fog Volume ""%s"" found at position (%f %f %f)", fogVolumeName, position.x, position.y, position.z ); + engine->Con_NPrintf( 1, "Fog: %s, post process: %s, color correct: %s", fogVolume->m_fogName, fogVolume->m_postProcessName, fogVolume->m_colorCorrectionName ); + } + else + { + engine->Con_NPrintf( 0, "No Fog Volume found at given position (%f %f %f)", position.x, position.y, position.z ); + } + } + + return fogVolume; +} + + +//-------------------------------------------------------------------------------------------------------- +CFogVolume::CFogVolume() : + BaseClass(), + m_bDisabled( false ), + m_bInFogVolumesList( false ) +{ +} + + +//-------------------------------------------------------------------------------------------------------- +CFogVolume::~CFogVolume() +{ + RemoveFromGlobalList(); +} + + +//-------------------------------------------------------------------------------------------------------- +void CFogVolume::Spawn( void ) +{ + BaseClass::Spawn(); + + SetSolid( SOLID_BSP ); + SetSolidFlags( FSOLID_NOT_SOLID ); + SetModel( STRING( GetModelName() ) ); +} + + +//-------------------------------------------------------------------------------------------------------- +void CFogVolume::AddToGlobalList() +{ + if ( !m_bInFogVolumesList ) + { + TheFogVolumes.AddToTail( this ); + m_bInFogVolumesList = true; + } +} + + +//-------------------------------------------------------------------------------------------------------- +void CFogVolume::RemoveFromGlobalList() +{ + if ( m_bInFogVolumesList ) + { + TheFogVolumes.FindAndRemove( this ); + m_bInFogVolumesList = false; + } +} + + +//---------------------------------------------------------------------------- +void CFogVolume::InputEnable( inputdata_t &data ) +{ + m_bDisabled = false; + AddToGlobalList(); +} + + +//---------------------------------------------------------------------------- +void CFogVolume::InputDisable( inputdata_t &data ) +{ + m_bDisabled = true; + RemoveFromGlobalList(); +} + + +//---------------------------------------------------------------------------- +// Called when the level loads or is restored +//---------------------------------------------------------------------------- +void CFogVolume::Activate() +{ + BaseClass::Activate(); + + m_hFogController = dynamic_cast< CFogController* >( gEntList.FindEntityByName( NULL, m_fogName ) ); + m_hPostProcessController = dynamic_cast< CPostProcessController* >( gEntList.FindEntityByName( NULL, m_postProcessName ) ); + m_hColorCorrectionController = dynamic_cast< CColorCorrection* >( gEntList.FindEntityByName( NULL, m_colorCorrectionName ) ); + + if ( !m_bDisabled ) + { + AddToGlobalList(); + } +} diff --git a/sp/src/game/server/fogvolume.h b/sp/src/game/server/fogvolume.h new file mode 100644 index 00000000..6bd5880a --- /dev/null +++ b/sp/src/game/server/fogvolume.h @@ -0,0 +1,74 @@ +//-------------------------------------------------------------------------------------------------------- +// Copyright (c) 2007 Turtle Rock Studios, Inc. - All Rights Reserved + +#ifndef FOG_VOLUME_H +#define FOG_VOLUME_H + +#ifdef _WIN32 +#pragma once +#endif + + +class CFogController; +class CPostProcessController; +class CColorCorrection; + + +//-------------------------------------------------------------------------------------------------------- +// Fog volume entity +class CFogVolume : public CServerOnlyEntity +{ + DECLARE_CLASS( CFogVolume, CServerOnlyEntity ); + DECLARE_DATADESC(); + +public: + CFogVolume(); + virtual ~CFogVolume(); + virtual void Spawn( void ); + virtual void Activate(); + + static CFogVolume *FindFogVolumeForPosition( const Vector &position ); + + const char *GetFogControllerName() const + { + return STRING( m_fogName ); + } + + CFogController* GetFogController( ) const + { + return m_hFogController.Get(); + } + + CPostProcessController* GetPostProcessController( ) const + { + return m_hPostProcessController.Get(); + } + + CColorCorrection* GetColorCorrectionController( ) const + { + return m_hColorCorrectionController.Get(); + } + + void InputEnable( inputdata_t &data ); + void InputDisable( inputdata_t &data ); + +private: + string_t m_fogName; + string_t m_postProcessName; + string_t m_colorCorrectionName; + + CHandle< CFogController > m_hFogController; + CHandle< CPostProcessController > m_hPostProcessController; + CHandle< CColorCorrection > m_hColorCorrectionController; + + bool m_bDisabled; + bool m_bInFogVolumesList; + + void AddToGlobalList(); + void RemoveFromGlobalList(); +}; + +extern CUtlVector< CFogVolume * > TheFogVolumes; + + +#endif // FOG_VOLUME_H \ No newline at end of file diff --git a/sp/src/game/server/player.cpp b/sp/src/game/server/player.cpp index 5280b60a..524b1e75 100644 --- a/sp/src/game/server/player.cpp +++ b/sp/src/game/server/player.cpp @@ -59,6 +59,10 @@ #include "env_zoom.h" #include "rumble_shared.h" #include "gamestats.h" +#ifdef MAPBASE // From Alien Swarm SDK +#include "env_tonemap_controller.h" +#include "fogvolume.h" +#endif #include "npcevent.h" #include "datacache/imdlcache.h" #include "hintsystem.h" @@ -459,8 +463,13 @@ BEGIN_DATADESC( CBasePlayer ) // Inputs DEFINE_INPUTFUNC( FIELD_INTEGER, "SetHealth", InputSetHealth ), DEFINE_INPUTFUNC( FIELD_BOOLEAN, "SetHUDVisibility", InputSetHUDVisibility ), - DEFINE_INPUTFUNC( FIELD_STRING, "SetFogController", InputSetFogController ), +#ifdef MAPBASE // From Alien Swarm SDK (kind of) + DEFINE_INPUTFUNC( FIELD_INPUT, "SetFogController", InputSetFogController ), DEFINE_INPUTFUNC( FIELD_INPUT, "SetPostProcessController", InputSetPostProcessController ), + DEFINE_INPUTFUNC( FIELD_INPUT, "SetColorCorrectionController", InputSetColorCorrectionController ), +#else + DEFINE_INPUTFUNC( FIELD_STRING, "SetFogController", InputSetFogController ), +#endif DEFINE_INPUTFUNC( FIELD_STRING, "HandleMapEvent", InputHandleMapEvent ), #ifdef MAPBASE DEFINE_INPUTFUNC( FIELD_BOOLEAN, "SetSuppressAttacks", InputSetSuppressAttacks ), @@ -474,9 +483,10 @@ BEGIN_DATADESC( CBasePlayer ) DEFINE_FIELD( m_nNumCrateHudHints, FIELD_INTEGER ), +#ifdef MAPBASE // From Alien Swarm SDK DEFINE_FIELD( m_hPostProcessCtrl, FIELD_EHANDLE ), - - + DEFINE_FIELD( m_hColorCorrectionCtrl, FIELD_EHANDLE ), +#endif // DEFINE_FIELD( m_nBodyPitchPoseParam, FIELD_INTEGER ), // DEFINE_ARRAY( m_StepSoundCache, StepSoundCache_t, 2 ), @@ -4668,6 +4678,55 @@ void CBasePlayer::ForceOrigin( const Vector &vecOrigin ) m_vForcedOrigin = vecOrigin; } +#ifdef MAPBASE // From Alien Swarm SDK +//-------------------------------------------------------------------------------------------------------- +void CBasePlayer::OnTonemapTriggerStartTouch( CTonemapTrigger *pTonemapTrigger ) +{ + m_hTriggerTonemapList.FindAndRemove( pTonemapTrigger ); + m_hTriggerTonemapList.AddToTail( pTonemapTrigger ); +} + + +//-------------------------------------------------------------------------------------------------------- +void CBasePlayer::OnTonemapTriggerEndTouch( CTonemapTrigger *pTonemapTrigger ) +{ + m_hTriggerTonemapList.FindAndRemove( pTonemapTrigger ); +} + + +//-------------------------------------------------------------------------------------------------------- +void CBasePlayer::UpdateTonemapController( void ) +{ + // For now, Mapbase uses Tony Sergi's Source 2007 tonemap fixes. + // Alien Swarm SDK tonemap controller code copies the parameters instead. + + CEnvTonemapController *pController = NULL; + + if (m_hTriggerTonemapList.Count() > 0) + { + pController = static_cast(m_hTriggerTonemapList.Tail()->GetTonemapController()); + } + else if (TheTonemapSystem()->GetMasterTonemapController()) + { + pController = static_cast(TheTonemapSystem()->GetMasterTonemapController()); + } + + if (pController) + { + //m_hTonemapController = TheTonemapSystem()->GetMasterTonemapController(); + + if (pController->m_bUseCustomAutoExposureMax) + m_Local.m_TonemapParams.m_flAutoExposureMax = pController->m_flCustomAutoExposureMax; + + if (pController->m_bUseCustomAutoExposureMin) + m_Local.m_TonemapParams.m_flAutoExposureMin = pController->m_flCustomAutoExposureMin; + + if (pController->m_bUseCustomBloomScale) + m_Local.m_TonemapParams.m_flBloomScale = pController->m_flCustomBloomScale; + } +} +#endif + //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- @@ -4675,6 +4734,11 @@ void CBasePlayer::PostThink() { m_vecSmoothedVelocity = m_vecSmoothedVelocity * SMOOTHING_FACTOR + GetAbsVelocity() * ( 1 - SMOOTHING_FACTOR ); +#ifdef MAPBASE // From Alien Swarm SDK + UpdateTonemapController(); + UpdateFXVolume(); +#endif + if ( !g_fGameOver && !m_iPlayerLocked ) { if ( IsAlive() ) @@ -5151,7 +5215,9 @@ void CBasePlayer::Spawn( void ) // Initialize the fog and postprocess controllers. InitFogController(); +#ifdef MAPBASE // From Alien Swarm SDK InitPostProcessController(); +#endif m_DmgTake = 0; m_DmgSave = 0; @@ -8716,8 +8782,11 @@ void SendProxy_ShiftPlayerSpawnflags( const SendProp *pProp, const void *pStruct SendPropArray ( SendPropEHandle( SENDINFO_ARRAY( m_hViewModel ) ), m_hViewModel ), SendPropString (SENDINFO(m_szLastPlaceName) ), +#ifdef MAPBASE // From Alien Swarm SDK // Postprocess data - SendPropEHandle( SENDINFO( m_hPostProcessCtrl ) ), + SendPropEHandle ( SENDINFO(m_hPostProcessCtrl) ), + SendPropEHandle ( SENDINFO(m_hColorCorrectionCtrl) ), +#endif #if defined USES_ECON_ITEMS SendPropUtlVector( SENDINFO_UTLVECTOR( m_hMyWearables ), MAX_WEARABLES_SENT_FROM_SERVER, SendPropEHandle( NULL, 0 ) ), @@ -9433,7 +9502,19 @@ void CBasePlayer::InputSetSuppressAttacks( inputdata_t &inputdata ) void CBasePlayer::InputSetFogController( inputdata_t &inputdata ) { // Find the fog controller with the given name. +#ifdef MAPBASE // From Alien Swarm SDK + CFogController *pFogController = NULL; + if ( inputdata.value.FieldType() == FIELD_EHANDLE ) + { + pFogController = dynamic_cast( inputdata.value.Entity().Get() ); + } + else + { + pFogController = dynamic_cast( gEntList.FindEntityByName( NULL, inputdata.value.String() ) ); + } +#else CFogController *pFogController = dynamic_cast( gEntList.FindEntityByName( NULL, inputdata.value.String() ) ); +#endif if ( pFogController ) { m_Local.m_PlayerFog.m_hCtrl.Set( pFogController ); @@ -9449,6 +9530,7 @@ void CBasePlayer::InitFogController( void ) m_Local.m_PlayerFog.m_hCtrl = FogSystem()->GetMasterFogController(); } +#ifdef MAPBASE // From Alien Swarm SDK //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- @@ -9461,25 +9543,57 @@ void CBasePlayer::InitPostProcessController( void ) //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- -void CBasePlayer::InputSetPostProcessController( inputdata_t& inputdata ) +void CBasePlayer::InitColorCorrectionController( void ) { - // Find the postprocess controller with the given name. - CPostProcessController* pController = NULL; - if (inputdata.value.FieldType() == FIELD_EHANDLE) + m_hColorCorrectionCtrl = ColorCorrectionSystem()->GetMasterColorCorrection(); +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CBasePlayer::InputSetPostProcessController( inputdata_t &inputdata ) +{ + // Find the fog controller with the given name. + CPostProcessController *pController = NULL; + if ( inputdata.value.FieldType() == FIELD_EHANDLE ) { - pController = dynamic_cast(inputdata.value.Entity().Get()); + pController = dynamic_cast( inputdata.value.Entity().Get() ); } else { - pController = dynamic_cast(gEntList.FindEntityByName( NULL, inputdata.value.String() )); + pController = dynamic_cast( gEntList.FindEntityByName( NULL, inputdata.value.String() ) ); } - if (pController) + if ( pController ) { m_hPostProcessCtrl.Set( pController ); } } +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CBasePlayer::InputSetColorCorrectionController( inputdata_t &inputdata ) +{ + // Find the fog controller with the given name. + CColorCorrection *pController = NULL; + if ( inputdata.value.FieldType() == FIELD_EHANDLE ) + { + pController = dynamic_cast( inputdata.value.Entity().Get() ); + } + else + { + pController = dynamic_cast( gEntList.FindEntityByName( NULL, inputdata.value.String() ) ); + } + + if ( pController ) + { + m_hColorCorrectionCtrl.Set( pController ); + } + +} +#endif + //----------------------------------------------------------------------------- // Purpose: // Input : *pEntity - @@ -10150,4 +10264,71 @@ uint64 CBasePlayer::GetSteamIDAsUInt64( void ) return steamIDForPlayer.ConvertToUint64(); return 0; } -#endif // NO_STEAM \ No newline at end of file +#endif // NO_STEAM + +#ifdef MAPBASE // From Alien Swarm SDK +//-------------------------------------------------------------------------------------------------------- +void CBasePlayer::UpdateFXVolume( void ) +{ + CFogController *pFogController = NULL; + CPostProcessController *pPostProcessController = NULL; + CColorCorrection* pColorCorrectionEnt = NULL; + + Vector eyePos; + CBaseEntity *pViewEntity = GetViewEntity(); + if ( pViewEntity ) + { + eyePos = pViewEntity->GetAbsOrigin(); + } + else + { + eyePos = EyePosition(); + } + + CFogVolume *pFogVolume = CFogVolume::FindFogVolumeForPosition( eyePos ); + if ( pFogVolume ) + { + pFogController = pFogVolume->GetFogController(); + pPostProcessController = pFogVolume->GetPostProcessController(); + pColorCorrectionEnt = pFogVolume->GetColorCorrectionController(); + + if ( !pFogController ) + { + pFogController = FogSystem()->GetMasterFogController(); + } + + if ( !pPostProcessController ) + { + pPostProcessController = PostProcessSystem()->GetMasterPostProcessController(); + } + + if ( !pColorCorrectionEnt ) + { + pColorCorrectionEnt = ColorCorrectionSystem()->GetMasterColorCorrection(); + } + } + else if ( TheFogVolumes.Count() > 0 ) + { + // If we're not in a fog volume, clear our fog volume, if the map has any. + // This will get us back to using the master fog controller. + pFogController = FogSystem()->GetMasterFogController(); + pPostProcessController = PostProcessSystem()->GetMasterPostProcessController(); + pColorCorrectionEnt = ColorCorrectionSystem()->GetMasterColorCorrection(); + } + + if ( pFogController && m_Local.m_PlayerFog.m_hCtrl.Get() != pFogController ) + { + m_Local.m_PlayerFog.m_hCtrl.Set( pFogController ); + } + + if ( pPostProcessController ) + { + m_hPostProcessCtrl.Set( pPostProcessController ); + } + + if ( pColorCorrectionEnt ) + { + m_hColorCorrectionCtrl.Set( pColorCorrectionEnt ); + } +} +#endif diff --git a/sp/src/game/server/player.h b/sp/src/game/server/player.h index bda4a5fe..05bf335b 100644 --- a/sp/src/game/server/player.h +++ b/sp/src/game/server/player.h @@ -88,6 +88,10 @@ class CNavArea; class CHintSystem; class CAI_Expresser; +#ifdef MAPBASE // From Alien Swarm SDK +class CTonemapTrigger; +#endif + #if defined USES_ECON_ITEMS class CEconWearable; #endif // USES_ECON_ITEMS @@ -658,6 +662,8 @@ public: #ifdef MAPBASE bool ShouldUseVisibilityCache( CBaseEntity *pEntity ); + + void UpdateFXVolume( void ); // From Alien Swarm SDK #endif public: @@ -884,9 +890,18 @@ public: void InitFogController( void ); void InputSetFogController( inputdata_t &inputdata ); +#ifdef MAPBASE // From Alien Swarm SDK + void OnTonemapTriggerStartTouch( CTonemapTrigger *pTonemapTrigger ); + void OnTonemapTriggerEndTouch( CTonemapTrigger *pTonemapTrigger ); + CUtlVector< CHandle< CTonemapTrigger > > m_hTriggerTonemapList; + CNetworkHandle( CPostProcessController, m_hPostProcessCtrl ); // active postprocessing controller + CNetworkHandle( CColorCorrection, m_hColorCorrectionCtrl ); // active FXVolume color correction void InitPostProcessController( void ); - void InputSetPostProcessController( inputdata_t& inputdata ); + void InputSetPostProcessController( inputdata_t &inputdata ); + void InitColorCorrectionController( void ); + void InputSetColorCorrectionController( inputdata_t &inputdata ); +#endif // Used by env_soundscape_triggerable to manage when the player is touching multiple // soundscape triggers simultaneously. @@ -1031,6 +1046,13 @@ protected: float m_fReplayEnd; // time to stop replay mode int m_iReplayEntity; // follow this entity in replay +#ifdef MAPBASE // From Alien Swarm SDK + // For now, Mapbase uses Tony Sergi's Source 2007 tonemap fixes. + // Alien Swarm SDK tonemap controller code copies the parameters instead. + virtual void UpdateTonemapController( void ); + //CNetworkHandle( CBaseEntity, m_hTonemapController ); +#endif + private: void HandleFuncTrain(); diff --git a/sp/src/game/server/playerlocaldata.h b/sp/src/game/server/playerlocaldata.h index 587dbd1a..f9ceef70 100644 --- a/sp/src/game/server/playerlocaldata.h +++ b/sp/src/game/server/playerlocaldata.h @@ -15,7 +15,10 @@ #include "playernet_vars.h" #include "networkvar.h" #include "fogcontroller.h" +#ifdef MAPBASE // From Alien Swarm SDK #include "postprocesscontroller.h" +#include "colorcorrection.h" +#endif //----------------------------------------------------------------------------- // Purpose: Player specific data ( sent only to local player, too ) diff --git a/sp/src/game/server/server_mapbase.vpc b/sp/src/game/server/server_mapbase.vpc index 523ba827..80ece7cf 100644 --- a/sp/src/game/server/server_mapbase.vpc +++ b/sp/src/game/server/server_mapbase.vpc @@ -30,6 +30,8 @@ $Project $File "env_dof_controller.h" $File "logic_playmovie.cpp" $File "movie_display.cpp" + $File "fogvolume.cpp" + $File "fogvolume.h" $File "ai_expresserfollowup.cpp" [$NEW_RESPONSE_SYSTEM] $File "ai_speechqueue.cpp" [$NEW_RESPONSE_SYSTEM] $File "ai_speechqueue.h" [$NEW_RESPONSE_SYSTEM] From b1f64f7d21f6d19df0acef5f66360c2db56d38a5 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sat, 6 Nov 2021 13:47:55 -0500 Subject: [PATCH 219/378] Fixed v142 conflict with particles.lib (for now) --- sp/src/game/client/client_base.vpc | 1 + sp/src/vpc_scripts/source_dll_win32_base.vpc | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/sp/src/game/client/client_base.vpc b/sp/src/game/client/client_base.vpc index daf5bf41..8238a0b7 100644 --- a/sp/src/game/client/client_base.vpc +++ b/sp/src/game/client/client_base.vpc @@ -71,6 +71,7 @@ $Configuration $SystemFrameworks "Carbon" [$OSXALL] $SystemLibraries "rt" [$LINUXALL] $IgnoreImportLibrary "TRUE" + $AdditionalOptions "$BASE /force:multiple" [$VS2019] // Required to fix _hypot in particles.lib (this may be a temporary solution) $AdditionalDependencies "$BASE winmm.lib" [$WIN32] $AdditionalDependencies "$BASE wsock32.lib Ws2_32.lib" [$BUILD_REPLAY] } diff --git a/sp/src/vpc_scripts/source_dll_win32_base.vpc b/sp/src/vpc_scripts/source_dll_win32_base.vpc index 4e738920..2bda187c 100644 --- a/sp/src/vpc_scripts/source_dll_win32_base.vpc +++ b/sp/src/vpc_scripts/source_dll_win32_base.vpc @@ -117,7 +117,7 @@ $Project { // General $CommandLine "$QUOTE$(VCInstallDir)bin\ml.exe$QUOTE /safeseh /c /Cp /Zi /Fo$QUOTE$(IntDir)\$(InputName).obj$QUOTE $QUOTE$(InputPath)$QUOTE" [!$VS2019] - $CommandLine "$QUOTE$(VC_ExecutablePath_x64_x86)bin\ml.exe$QUOTE /safeseh /c /Cp /Zi /Fo$QUOTE$(IntDir)\$(InputName).obj$QUOTE $QUOTE$(InputPath)$QUOTE" [$VS2019] + $CommandLine "$QUOTE$(VC_ExecutablePath_x64_x86)\ml.exe$QUOTE /safeseh /c /Cp /Zi /Fo$QUOTE$(IntDir)\$(InputName).obj$QUOTE $QUOTE$(InputPath)$QUOTE" [$VS2019] $Description "Compiling pointeroverride.asm" $Outputs "$(IntDir)\$(InputName).obj" } From 47ed1914cc3a17f9a6d175688c80a0cb2c3c1f6e Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sat, 6 Nov 2021 14:03:05 -0500 Subject: [PATCH 220/378] Fixed VS2013 attempting to compile VS2019 code --- sp/src/public/haptics/haptic_utils.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sp/src/public/haptics/haptic_utils.cpp b/sp/src/public/haptics/haptic_utils.cpp index 70fe86c4..e6d3288a 100644 --- a/sp/src/public/haptics/haptic_utils.cpp +++ b/sp/src/public/haptics/haptic_utils.cpp @@ -138,9 +138,11 @@ void ConnectHaptics(CreateInterfaceFn appFactory) HookHapticMessages(); } +#if _MSC_VER >= 1925 // deleting haptics results in a warning about deleting something with a non-virtual destructor // big yikes but we can't do anything about it as it's accessed via interface #pragma warning (disable: 5205) +#endif void DisconnectHaptics() { From c925a01712e05625a8df25b67772db19be751b81 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sat, 6 Nov 2021 14:04:34 -0500 Subject: [PATCH 221/378] Disabled phonemeextractor and QC_Eyes in VS2019 solution (for now) --- sp/src/vpc_scripts/projects.vgc | 4 ++-- sp/src/vpc_scripts/source_base.vpc | 12 +++++++++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/sp/src/vpc_scripts/projects.vgc b/sp/src/vpc_scripts/projects.vgc index fdfcc57e..e4955ef7 100644 --- a/sp/src/vpc_scripts/projects.vgc +++ b/sp/src/vpc_scripts/projects.vgc @@ -63,7 +63,7 @@ $Project "motionmapper" $Project "phonemeextractor" { - "utils\phonemeextractor\phonemeextractor.vpc" [$WIN32] + "utils\phonemeextractor\phonemeextractor.vpc" [$WIN32 && !$VS2019] // Not currently working with v142; may be fixable with modification } $Project "raytrace" @@ -73,7 +73,7 @@ $Project "raytrace" $Project "qc_eyes" { - "utils\qc_eyes\qc_eyes.vpc" [$WIN32] + "utils\qc_eyes\qc_eyes.vpc" [$WIN32 && !$VS2019] // Not currently working with v142; might be fixed by having C++ MFC for v141 build tools and/or C++ ATL for v141 build tools installed } $Project "serverplugin_empty" diff --git a/sp/src/vpc_scripts/source_base.vpc b/sp/src/vpc_scripts/source_base.vpc index d3d0c73d..3322bcdc 100644 --- a/sp/src/vpc_scripts/source_base.vpc +++ b/sp/src/vpc_scripts/source_base.vpc @@ -17,7 +17,17 @@ //----------------------------------------------------------------------------- -$Conditional VS2019 "1" // Toggles Visual Studio 2019 toolset (NOTE: This makes the solution incompatible with Visual Studio 2013) +// Mapbase - Additional toolsets (NOTE: Newer toolsets make the solution incompatible with Visual Studio 2013) +$Conditional VS2019 "0" // Toggles Visual Studio 2019 (v142) toolset + +// +// Note that the following projects currently do not compile with v142 and are not included in the VS2019 solution: +// +// - phonemeextractor (may be fixable with modification) +// - qc_eyes (might be fixed by having C++ MFC for v141 build tools and/or C++ ATL for v141 build tools installed) +// + +//----------------------------------------------------------------------------- // Mapbase functionality conditionals $Conditional MAPBASE "1" // Equivalent to (and required for) our MAPBASE preprocessor defined below From 47a0bb0fde50b41b3b089ef0eda3ff2aa061a85d Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sat, 6 Nov 2021 15:29:48 -0500 Subject: [PATCH 222/378] Moved toolset conditionals to a more fitting and intuitive place --- sp/src/vpc_scripts/default.vgc | 15 +++++++++++++++ sp/src/vpc_scripts/source_base.vpc | 12 ------------ 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/sp/src/vpc_scripts/default.vgc b/sp/src/vpc_scripts/default.vgc index efcaedfb..e08fa894 100644 --- a/sp/src/vpc_scripts/default.vgc +++ b/sp/src/vpc_scripts/default.vgc @@ -17,6 +17,21 @@ $Games // Makes the VPC scripts work in the SDK's context $Conditional "SOURCESDK" "1" +//----------------------------------------------------------------------------- + +// Mapbase - Additional toolsets (NOTE: Newer toolsets make the solution incompatible with Visual Studio 2013) + +$Conditional VS2019 "0" // Toggles Visual Studio 2019 (v142) toolset + +// +// Note that the following projects currently do not compile with v142 and are not included in the VS2019 solution: +// +// - phonemeextractor (may be fixable with modification) +// - qc_eyes (might be fixed by having C++ MFC for v141 build tools and/or C++ ATL for v141 build tools installed) +// + +//----------------------------------------------------------------------------- + $Include "vpc_scripts\projects.vgc" $Include "vpc_scripts\groups.vgc" diff --git a/sp/src/vpc_scripts/source_base.vpc b/sp/src/vpc_scripts/source_base.vpc index 3322bcdc..fac51e1d 100644 --- a/sp/src/vpc_scripts/source_base.vpc +++ b/sp/src/vpc_scripts/source_base.vpc @@ -17,18 +17,6 @@ //----------------------------------------------------------------------------- -// Mapbase - Additional toolsets (NOTE: Newer toolsets make the solution incompatible with Visual Studio 2013) -$Conditional VS2019 "0" // Toggles Visual Studio 2019 (v142) toolset - -// -// Note that the following projects currently do not compile with v142 and are not included in the VS2019 solution: -// -// - phonemeextractor (may be fixable with modification) -// - qc_eyes (might be fixed by having C++ MFC for v141 build tools and/or C++ ATL for v141 build tools installed) -// - -//----------------------------------------------------------------------------- - // Mapbase functionality conditionals $Conditional MAPBASE "1" // Equivalent to (and required for) our MAPBASE preprocessor defined below $Conditional MAPBASE_RPC "1" // Toggles Mapbase's Rich Presence Client implementations From e30bde782a10aaf8bedc4d0f84800b0902aff6c7 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sun, 7 Nov 2021 00:47:52 -0500 Subject: [PATCH 223/378] Added clientside VScript functions for getting view position/direction --- sp/src/game/client/vscript_client.cpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/sp/src/game/client/vscript_client.cpp b/sp/src/game/client/vscript_client.cpp index 405b2083..a01ba4d2 100644 --- a/sp/src/game/client/vscript_client.cpp +++ b/sp/src/game/client/vscript_client.cpp @@ -15,11 +15,12 @@ #include "gamerules.h" #include "vscript_client.nut" #ifdef MAPBASE_VSCRIPT -#include "mapbase/matchers.h" +#include "view.h" #include "c_world.h" #include "proxyentity.h" #include "materialsystem/imaterial.h" #include "materialsystem/imaterialvar.h" +#include "mapbase/matchers.h" #include "mapbase/vscript_singletons.h" #endif @@ -662,6 +663,20 @@ bool VScriptClientInit() 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, MainViewOrigin, "" ); + ScriptRegisterFunction( g_pScriptVM, MainViewAngles, "" ); + ScriptRegisterFunction( g_pScriptVM, PrevMainViewOrigin, "" ); + ScriptRegisterFunction( g_pScriptVM, PrevMainViewAngles, "" ); + ScriptRegisterFunction( g_pScriptVM, MainViewForward, "" ); + ScriptRegisterFunction( g_pScriptVM, MainViewRight, "" ); + ScriptRegisterFunction( g_pScriptVM, MainViewUp, "" ); + + ScriptRegisterFunction( g_pScriptVM, CurrentViewOrigin, "" ); + ScriptRegisterFunction( g_pScriptVM, CurrentViewAngles, "" ); + ScriptRegisterFunction( g_pScriptVM, CurrentViewForward, "" ); + ScriptRegisterFunction( g_pScriptVM, CurrentViewRight, "" ); + ScriptRegisterFunction( g_pScriptVM, CurrentViewUp, "" ); + ScriptRegisterFunction( g_pScriptVM, CreateProp, "Create an animating prop" ); #endif From 653d48d2c42adb25ccc79dc3eadaffcdca1d5eaf Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sun, 7 Nov 2021 00:48:28 -0500 Subject: [PATCH 224/378] Added ViewProximity and ViewDirection material proxies --- sp/src/game/client/proxyplayer.cpp | 101 ++++++++++++++++++++++++++++- 1 file changed, 100 insertions(+), 1 deletion(-) diff --git a/sp/src/game/client/proxyplayer.cpp b/sp/src/game/client/proxyplayer.cpp index d6521cc9..5fa7f1bc 100644 --- a/sp/src/game/client/proxyplayer.cpp +++ b/sp/src/game/client/proxyplayer.cpp @@ -12,6 +12,9 @@ #include "materialsystem/imaterialsystem.h" #include "functionproxy.h" #include "toolframework_client.h" +#ifdef MAPBASE +#include "view.h" +#endif // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -521,4 +524,100 @@ void CPlayerLogoOnModelProxy::OnBind( void *pC_BaseEntity ) } EXPOSE_INTERFACE( CPlayerLogoOnModelProxy, IMaterialProxy, "PlayerLogoOnModel" IMATERIAL_PROXY_INTERFACE_VERSION ); -*/ \ No newline at end of file +*/ + + +#ifdef MAPBASE +//----------------------------------------------------------------------------- +// Returns the proximity of the current view to the entity +//----------------------------------------------------------------------------- +class CViewProximityProxy : public CResultProxy +{ +public: + bool Init( IMaterial *pMaterial, KeyValues *pKeyValues ); + void OnBind( void *pC_BaseEntity ); + +private: + float m_Factor; +}; + +bool CViewProximityProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues ) +{ + if (!CResultProxy::Init( pMaterial, pKeyValues )) + return false; + + m_Factor = pKeyValues->GetFloat( "scale", 0.002 ); + return true; +} + +void CViewProximityProxy::OnBind( void *pC_BaseEntity ) +{ + if (!pC_BaseEntity) + return; + + // Find the distance between the player and this entity.... + C_BaseEntity *pEntity = BindArgToEntity( pC_BaseEntity ); + + Vector delta; + VectorSubtract( pEntity->WorldSpaceCenter(), CurrentViewOrigin(), delta ); + + Assert( m_pResult ); + SetFloatResult( delta.Length() * m_Factor ); + + if ( ToolsEnabled() ) + { + ToolFramework_RecordMaterialParams( GetMaterial() ); + } +} + +EXPOSE_INTERFACE( CViewProximityProxy, IMaterialProxy, "ViewProximity" IMATERIAL_PROXY_INTERFACE_VERSION ); + +//----------------------------------------------------------------------------- +// Returns the current view direction +//----------------------------------------------------------------------------- +class CViewDirectionProxy : public CResultProxy +{ +public: + bool Init( IMaterial *pMaterial, KeyValues *pKeyValues ); + void OnBind( void *pC_BaseEntity ); + +private: + float m_Factor; +}; + +bool CViewDirectionProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues ) +{ + if (!CResultProxy::Init( pMaterial, pKeyValues )) + return false; + + m_Factor = pKeyValues->GetFloat( "scale", 2 ); + return true; +} + +void CViewDirectionProxy::OnBind( void *pC_BaseEntity ) +{ + if (!pC_BaseEntity) + return; + + // Find the view angle between the player and this entity.... + C_BaseEntity *pEntity = BindArgToEntity( pC_BaseEntity ); + + Vector delta; + Vector forward; + + VectorSubtract( pEntity->WorldSpaceCenter(), CurrentViewOrigin(), delta ); + VectorNormalize( delta ); + + forward = CurrentViewForward(); + + Assert( m_pResult ); + SetFloatResult( DotProduct( forward, delta ) * m_Factor ); + + if ( ToolsEnabled() ) + { + ToolFramework_RecordMaterialParams( GetMaterial() ); + } +} + +EXPOSE_INTERFACE( CViewDirectionProxy, IMaterialProxy, "ViewDirection" IMATERIAL_PROXY_INTERFACE_VERSION ); +#endif From b2116d07e9038467084acc9927d358038f87ecaf Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sun, 7 Nov 2021 07:35:28 -0600 Subject: [PATCH 225/378] Made VBSP's OnMapLoaded into a hook using the new system --- sp/src/utils/vbsp/map.cpp | 6 ++---- sp/src/utils/vbsp/vbsp.h | 2 ++ sp/src/utils/vbsp/vscript_vbsp.cpp | 7 +++++++ 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/sp/src/utils/vbsp/map.cpp b/sp/src/utils/vbsp/map.cpp index dcb9aea5..bca929c9 100644 --- a/sp/src/utils/vbsp/map.cpp +++ b/sp/src/utils/vbsp/map.cpp @@ -2806,14 +2806,12 @@ bool LoadMapFile( const char *pszFileName ) #ifdef MAPBASE_VSCRIPT if ( g_pScriptVM ) { - HSCRIPT hFunc = g_pScriptVM->LookupFunction( "OnMapLoaded" ); - if ( hFunc ) + if (CMapFile::g_Hook_OnMapLoaded.CanRunInScope( NULL )) { // Use GetLoadingMap() //g_pScriptVM->SetValue( "map", g_LoadingMap->GetScriptInstance() ); - g_pScriptVM->Call( hFunc ); - g_pScriptVM->ReleaseFunction( hFunc ); + CMapFile::g_Hook_OnMapLoaded.Call( NULL, NULL, NULL ); //g_pScriptVM->ClearValue( "map" ); } diff --git a/sp/src/utils/vbsp/vbsp.h b/sp/src/utils/vbsp/vbsp.h index 3e9f44c0..e12d63d2 100644 --- a/sp/src/utils/vbsp/vbsp.h +++ b/sp/src/utils/vbsp/vbsp.h @@ -347,6 +347,8 @@ public: #ifdef MAPBASE_VSCRIPT HSCRIPT GetScriptInstance(); + static ScriptHook_t g_Hook_OnMapLoaded; + // VScript functions ALLOW_SCRIPT_ACCESS(); private: diff --git a/sp/src/utils/vbsp/vscript_vbsp.cpp b/sp/src/utils/vbsp/vscript_vbsp.cpp index abaa2d66..bcb94845 100644 --- a/sp/src/utils/vbsp/vscript_vbsp.cpp +++ b/sp/src/utils/vbsp/vscript_vbsp.cpp @@ -169,6 +169,8 @@ bool VScriptRunScript( const char *pszScriptName, HSCRIPT hScope, bool bWarnMiss return bSuccess; } +ScriptHook_t CMapFile::g_Hook_OnMapLoaded; + BEGIN_SCRIPTDESC_ROOT( CMapFile, "Map file" ) DEFINE_SCRIPTFUNC( GetMins, "Get the map's mins." ) @@ -185,6 +187,11 @@ BEGIN_SCRIPTDESC_ROOT( CMapFile, "Map file" ) DEFINE_SCRIPTFUNC( GetNumEntities, "Get the number of entities in the map." ) + // + // Hooks + // + DEFINE_SIMPLE_SCRIPTHOOK( CMapFile::g_Hook_OnMapLoaded, "OnMapLoaded", FIELD_VOID, "Called when the NPC is deciding whether to hear a CSound or not." ) + END_SCRIPTDESC(); From 7e96be39b20dbae2222bc7486898a8486898750f Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sun, 7 Nov 2021 07:37:13 -0600 Subject: [PATCH 226/378] Added support for nested instances relative to their parents, which is what Hammer uses to display them --- sp/src/utils/vbsp/map.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/sp/src/utils/vbsp/map.cpp b/sp/src/utils/vbsp/map.cpp index bca929c9..c479b279 100644 --- a/sp/src/utils/vbsp/map.cpp +++ b/sp/src/utils/vbsp/map.cpp @@ -2603,6 +2603,27 @@ void CMapFile::MergeEntities( entity_t *pInstanceEntity, CMapFile *Instance, Vec SetKeyValue( entity, szKey, epInstance->value ); } } + + // If the parent instance is within a relative path and no file relative to the main map exists, change it to be relative to the parent + char *pParentInstanceFile = ValueForKey( pInstanceEntity, "file" ); + if ( pParentInstanceFile[ 0 ] && (strchr( pParentInstanceFile, '\\' ) || strchr( pParentInstanceFile, '/' )) ) + { + char *pInstanceFile = ValueForKey( entity, "file" ); + if ( pInstanceFile[ 0 ] ) + { + char InstancePath[ MAX_PATH ]; + + if ( !DeterminePath( g_MainMapPath, pInstanceFile, InstancePath ) ) + { + strcpy( InstancePath, pParentInstanceFile ); + V_StripFilename( InstancePath ); + V_strncat( InstancePath, "\\", sizeof( InstancePath ) ); + V_strncat( InstancePath, pInstanceFile, sizeof( InstancePath ) ); + + SetKeyValue( entity, "file", InstancePath ); + } + } + } } #endif } From 2f8e920c3e3e17acb9e63ce7c31ffd2df4a9649e Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sun, 7 Nov 2021 07:37:41 -0600 Subject: [PATCH 227/378] Minor body lean fix from Alien Swarm SDK --- sp/src/game/server/baseflex.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sp/src/game/server/baseflex.cpp b/sp/src/game/server/baseflex.cpp index 3c660a88..921e3fe6 100644 --- a/sp/src/game/server/baseflex.cpp +++ b/sp/src/game/server/baseflex.cpp @@ -2332,8 +2332,13 @@ void CBaseFlex::DoBodyLean( void ) { m_vecPrevVelocity = vecDelta; float decay = ExponentialDecay( 0.5, 0.1, dt ); +#ifdef MAPBASE // From Alien Swarm SDK + m_vecShift = m_vecShift * decay; + m_vecLean = m_vecLean * decay; +#else m_vecShift = m_vecLean * decay; m_vecLean = m_vecShift * decay; +#endif } m_vecPrevOrigin = vecOrigin; From 400d572c03e0b865788f4a9a552fd89e2ffe78b9 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sun, 7 Nov 2021 09:44:46 -0600 Subject: [PATCH 228/378] Added "autocubemap" utility --- sp/src/game/client/client_mapbase.vpc | 1 + .../client/mapbase/mapbase_autocubemap.cpp | 280 ++++++++++++++++++ 2 files changed, 281 insertions(+) create mode 100644 sp/src/game/client/mapbase/mapbase_autocubemap.cpp diff --git a/sp/src/game/client/client_mapbase.vpc b/sp/src/game/client/client_mapbase.vpc index 797325a0..000de791 100644 --- a/sp/src/game/client/client_mapbase.vpc +++ b/sp/src/game/client/client_mapbase.vpc @@ -61,6 +61,7 @@ $Project $File "mapbase\c_func_fake_worldportal.h" $File "mapbase\c_point_glow.cpp" $File "mapbase\c_vgui_text_display.cpp" + $File "mapbase\mapbase_autocubemap.cpp" } $Folder "HL2 DLL" diff --git a/sp/src/game/client/mapbase/mapbase_autocubemap.cpp b/sp/src/game/client/mapbase/mapbase_autocubemap.cpp new file mode 100644 index 00000000..03602ef2 --- /dev/null +++ b/sp/src/game/client/mapbase/mapbase_autocubemap.cpp @@ -0,0 +1,280 @@ +//========= Mapbase - https://github.com/mapbase-source/source-sdk-2013 ============// +// +// Purpose: A utility which automatically generates HDR and LDR cubemaps. +// This has the following purposes: +// +// 1. Allow both HDR and LDR cubemaps to be generated automatically after a map is compiled +// 2. Have a way to batch build cubemaps for several levels at once +// +// Author: Blixibon +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" + +#include "tier0/icommandline.h" +#include "igamesystem.h" +#include "filesystem.h" +#include "utlbuffer.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +extern const char *g_MapName; + +ConVar autocubemap_hdr_do_both( "autocubemap_hdr_do_both", "1" ); +ConVar autocubemap_hdr_value( "autocubemap_hdr_value", "2" ); + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +class CAutoCubemapSystem : public CAutoGameSystem +{ +public: + CAutoCubemapSystem() : CAutoGameSystem( "CAutoCubemapSystem" ) + { + } + + virtual bool Init() + { + const char *pszFile = NULL; + if (CommandLine()->CheckParm( "-autocubemap", &pszFile )) + { + if (!pszFile || pszFile[0] == '\0') + { + // Assume that we just want to autocubemap the first map we load + // (no code here for now) + } + else + { + LoadFile( pszFile ); + } + + // Begin autocubemap with the first level we load + m_bAutoCubemapOnFirstLevel = true; + } + + return true; + } + + virtual void LevelInitPostEntity() + { + if (m_bAutoCubemapActive) + { + if (m_bAutoCubemapBuildingCubemaps) + { + // Check if we need to do the other HDR level + if (autocubemap_hdr_do_both.GetBool() && !m_bAutoCubemapDoingBoth) + { + m_bAutoCubemapBuildingCubemaps = false; + m_bAutoCubemapDoingBoth = true; + + // Change the HDR level and restart the map + //ConVarRef mat_hdr_level( "mat_hdr_level" ); + engine->ClientCmd_Unrestricted( VarArgs( "toggle mat_hdr_level 0 %i; restart", autocubemap_hdr_value.GetInt() ) ); + } + else + { + // Go to the next map + m_bAutoCubemapBuildingCubemaps = false; + m_bAutoCubemapDoingBoth = false; + + m_AutoCubemapMapsIndex++; + if (m_AutoCubemapMapsIndex < m_AutoCubemapMaps.Count()) + { + engine->ClientCmd_Unrestricted( VarArgs( "map %s", m_AutoCubemapMaps[m_AutoCubemapMapsIndex] ) ); + } + else + { + // CUBEMAPPER FINISHED + m_AutoCubemapMaps.PurgeAndDeleteElements(); + m_AutoCubemapMapsIndex = 0; + m_bAutoCubemapActive = false; + + Msg( "CUBEMAPPER FINISHED\n" ); + + if (autocubemap_hdr_do_both.GetBool()) + { + engine->ClientCmd_Unrestricted( VarArgs( "mat_hdr_level %i", m_iAutoCubemapUserHDRLevel ) ); + } + } + } + } + else + { + // Build cubemaps for this map + m_bAutoCubemapBuildingCubemaps = true; + engine->ClientCmd_Unrestricted( "exec buildcubemaps_prep; buildcubemaps" ); + } + } + else if (m_bAutoCubemapOnFirstLevel) + { + // Start autocubemap now + StartAutoCubemap(); + m_bAutoCubemapOnFirstLevel = false; + } + } + + //------------------------------------------------------------------------------------- + + void StartAutoCubemap() + { + if (m_AutoCubemapMaps.Count() <= 0) + { + //Msg("No maps to cubemap with!\n"); + //return; + + // Just do this map + m_AutoCubemapMaps.AddToTail( strdup( g_MapName ) ); + } + + if (autocubemap_hdr_do_both.GetBool()) + { + // Save the user's HDR level + ConVarRef mat_hdr_level( "mat_hdr_level" ); + m_iAutoCubemapUserHDRLevel = mat_hdr_level.GetInt(); + } + + m_bAutoCubemapActive = true; + m_AutoCubemapMapsIndex = 0; + + if (FStrEq( m_AutoCubemapMaps[m_AutoCubemapMapsIndex], g_MapName )) + { + // Build cubemaps right here, right now + m_bAutoCubemapBuildingCubemaps = true; + engine->ClientCmd_Unrestricted( "exec buildcubemaps_prep; buildcubemaps" ); + } + else + { + // Go to that map + engine->ClientCmd_Unrestricted( VarArgs( "map %s", m_AutoCubemapMaps[m_AutoCubemapMapsIndex] ) ); + } + } + + void LoadFile( const char *pszFile ) + { + KeyValues *pKV = new KeyValues( "AutoCubemap" ); + + if ( pKV->LoadFromFile( filesystem, pszFile, NULL ) ) + { + KeyValues *pSubKey = pKV->GetFirstSubKey(); + + while ( pSubKey ) + { + m_AutoCubemapMaps.AddToTail( strdup(pSubKey->GetName()) ); + pSubKey = pSubKey->GetNextKey(); + } + + Msg( "Initted autocubemap\n" ); + } + else + { + Warning( "Unable to load autocubemap file \"%s\"\n", pszFile ); + } + + pKV->deleteThis(); + } + + void Clear() + { + m_bAutoCubemapActive = false; + m_bAutoCubemapBuildingCubemaps = false; + m_bAutoCubemapDoingBoth = false; + + m_AutoCubemapMaps.PurgeAndDeleteElements(); + m_AutoCubemapMapsIndex = 0; + } + + void PrintState() + { + char szCmd[1024] = { 0 }; + + if (m_AutoCubemapMaps.Count() > 0) + { + Q_strncpy( szCmd, "=== CUBEMAPPER MAP LIST ===\n", sizeof( szCmd ) ); + + FOR_EACH_VEC( m_AutoCubemapMaps, i ) + { + Q_snprintf( szCmd, sizeof( szCmd ), "%s%s\n", szCmd, m_AutoCubemapMaps[i] ); + } + + Q_strncat( szCmd, "========================", sizeof( szCmd ), COPY_ALL_CHARACTERS ); + + Q_snprintf( szCmd, sizeof( szCmd ), "%s\nNumber of maps: %i (starting at %i)\n", szCmd, m_AutoCubemapMaps.Count(), m_AutoCubemapMapsIndex ); + } + else + { + Q_strncat( szCmd, "========================\n", sizeof( szCmd ), COPY_ALL_CHARACTERS ); + Q_strncat( szCmd, "There are no maps selected. Use 'autocubemap_init' to load a map list.\nIf 'autocubemap_start' is executed while no maps are selected, only the current map will have cubemaps generated.\n", sizeof( szCmd ), COPY_ALL_CHARACTERS ); + Q_strncat( szCmd, "========================\n", sizeof( szCmd ), COPY_ALL_CHARACTERS ); + } + + Msg( "%s", szCmd ); + } + + //------------------------------------------------------------------------------------- + + bool m_bAutoCubemapActive = false; + bool m_bAutoCubemapBuildingCubemaps = false; + bool m_bAutoCubemapDoingBoth = false; + int m_iAutoCubemapUserHDRLevel; // For setting the user back to the right HDR level when we're finished + + // Start autocubemap with the first level we load (used for launch parameter) + bool m_bAutoCubemapOnFirstLevel = false; + + CUtlVector m_AutoCubemapMaps; + int m_AutoCubemapMapsIndex; +}; + +CAutoCubemapSystem g_AutoCubemapSystem; + +CON_COMMAND( autocubemap_init, "Inits autocubemap" ) +{ + if (gpGlobals->maxClients > 1) + { + Msg( "Can't run autocubemap in multiplayer\n" ); + return; + } + + if (args.ArgC() <= 1) + { + Msg("Format: autocubemap_init \n"); + return; + } + + g_AutoCubemapSystem.LoadFile( args.Arg( 1 ) ); +} + +CON_COMMAND( autocubemap_print, "Prints current autocubemap information" ) +{ + if (gpGlobals->maxClients > 1) + { + Msg("Can't run autocubemap in multiplayer\n"); + return; + } + + g_AutoCubemapSystem.PrintState(); +} + +CON_COMMAND( autocubemap_clear, "Clears autocubemap stuff" ) +{ + if (gpGlobals->maxClients > 1) + { + Msg("Can't run autocubemap in multiplayer\n"); + return; + } + + g_AutoCubemapSystem.Clear(); +} + +CON_COMMAND( autocubemap_start, "Begins the autocubemap (it's recommended to check 'autocubemap_print' before running this command)" ) +{ + if (gpGlobals->maxClients > 1) + { + Msg("Can't run autocubemap in multiplayer\n"); + return; + } + + g_AutoCubemapSystem.StartAutoCubemap(); +} From c8f48407c15931b9107c4a8ca13041d544f304ef Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sun, 7 Nov 2021 14:01:27 -0600 Subject: [PATCH 229/378] Added plant orientation to combine_mine --- sp/src/game/server/hl2/combine_mine.cpp | 59 ++++++++++++++++++++++++- sp/src/game/server/hl2/combine_mine.h | 8 +++- 2 files changed, 65 insertions(+), 2 deletions(-) diff --git a/sp/src/game/server/hl2/combine_mine.cpp b/sp/src/game/server/hl2/combine_mine.cpp index 4e86eb85..e8e401a4 100644 --- a/sp/src/game/server/hl2/combine_mine.cpp +++ b/sp/src/game/server/hl2/combine_mine.cpp @@ -58,6 +58,10 @@ char *pszMineStateNames[] = // Approximate radius of the bomb's model #define BOUNCEBOMB_RADIUS 24 +#ifdef MAPBASE +ConVar combine_mine_trace_dist( "combine_mine_trace_dist", "1024" ); +#endif + BEGIN_DATADESC( CBounceBomb ) DEFINE_THINKFUNC( ExplodeThink ), DEFINE_ENTITYFUNC( ExplodeTouch ), @@ -129,6 +133,8 @@ BEGIN_DATADESC( CBounceBomb ) #ifdef MAPBASE DEFINE_INPUTFUNC( FIELD_VOID, "Bounce", InputBounce ), DEFINE_INPUTFUNC( FIELD_EHANDLE, "BounceAtTarget", InputBounceAtTarget ), + DEFINE_INPUTFUNC( FIELD_VECTOR, "SetPlantOrientation", InputSetPlantOrientation ), + DEFINE_INPUTFUNC( FIELD_VECTOR, "SetPlantOrientationRaw", InputSetPlantOrientationRaw ), DEFINE_OUTPUT( m_OnTriggered, "OnTriggered" ), DEFINE_OUTPUT( m_OnExplode, "OnExplode" ), @@ -266,6 +272,14 @@ void CBounceBomb::Spawn() // pretend like the player set me down. m_bPlacedByPlayer = true; } + +#ifdef MAPBASE + if (m_vecPlantOrientation != vec3_invalid) + { + // Turn angles into direction + AngleVectors( QAngle( m_vecPlantOrientation.x, m_vecPlantOrientation.y, m_vecPlantOrientation.z ), &m_vecPlantOrientation ); + } +#endif } //--------------------------------------------------------- @@ -694,7 +708,20 @@ void CBounceBomb::SettleThink() { // If i'm not resting on the world, jump randomly. trace_t tr; - UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin() - Vector( 0, 0, 1024 ), MASK_SHOT|CONTENTS_GRATE, this, COLLISION_GROUP_NONE, &tr ); +#ifdef MAPBASE + Vector vecTraceDir; + if (m_vecPlantOrientation != vec3_invalid) + { + vecTraceDir = m_vecPlantOrientation * combine_mine_trace_dist.GetFloat(); + } + else + { + vecTraceDir = Vector( 0, 0, combine_mine_trace_dist.GetFloat() ); + } +#else + Vector vecTraceDir = Vector( 0, 0, 1024 ); +#endif + UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin() - vecTraceDir, MASK_SHOT|CONTENTS_GRATE, this, COLLISION_GROUP_NONE, &tr ); bool bHop = false; if( tr.m_pEnt ) @@ -728,6 +755,20 @@ void CBounceBomb::SettleThink() // Check for upside-down Vector vecUp; GetVectors( NULL, NULL, &vecUp ); +#ifdef MAPBASE + if (m_vecPlantOrientation != vec3_invalid) + { + float flDiff = abs(m_vecPlantOrientation.z - vecUp.z); + if ( flDiff >= 0.2f ) + { + // Landed upside down. Right self + Vector vecForce( 0, 0, 2500 ); + Flip( vecForce, AngularImpulse( 60, 0, 0 ) ); + return; + } + } + else +#endif if( vecUp.z <= 0.8 ) { // Landed upside down. Right self @@ -1442,6 +1483,22 @@ void CBounceBomb::InputBounceAtTarget( inputdata_t &inputdata ) m_hNearestNPC = inputdata.value.Entity(); SetMineState(MINE_STATE_TRIGGERED); } + +//--------------------------------------------------------- +//--------------------------------------------------------- +void CBounceBomb::InputSetPlantOrientation( inputdata_t &inputdata ) +{ + Vector vecInput; + inputdata.value.Vector3D( vecInput ); + AngleVectors( QAngle(vecInput.x, vecInput.y, vecInput.z), &m_vecPlantOrientation ); +} + +//--------------------------------------------------------- +//--------------------------------------------------------- +void CBounceBomb::InputSetPlantOrientationRaw( inputdata_t &inputdata ) +{ + inputdata.value.Vector3D( m_vecPlantOrientation ); +} #endif //--------------------------------------------------------- diff --git a/sp/src/game/server/hl2/combine_mine.h b/sp/src/game/server/hl2/combine_mine.h index 4495afb3..097968db 100644 --- a/sp/src/game/server/hl2/combine_mine.h +++ b/sp/src/game/server/hl2/combine_mine.h @@ -34,7 +34,7 @@ class CBounceBomb : public CBaseAnimating, public CDefaultPlayerPickupVPhysics public: #ifdef MAPBASE - CBounceBomb() { m_pWarnSound = NULL; m_bPlacedByPlayer = false; m_flExplosionDelay = 0.5f; m_iLOSMask = MASK_SOLID_BRUSHONLY; } + CBounceBomb() { m_pWarnSound = NULL; m_bPlacedByPlayer = false; m_flExplosionDelay = 0.5f; m_iLOSMask = MASK_SOLID_BRUSHONLY; m_vecPlantOrientation = vec3_invalid; } #else CBounceBomb() { m_pWarnSound = NULL; m_bPlacedByPlayer = false; } #endif @@ -130,6 +130,10 @@ private: int m_iLOSMask; bool m_bUnavoidable; + + // What direction the mine should be facing when planting itself (i.e. facing up, facing left, etc.) + // vec3_invalid = use default (0 0 1 or -90 0 0) + Vector m_vecPlantOrientation; #endif bool m_bPlacedByPlayer; @@ -164,6 +168,8 @@ private: #ifdef MAPBASE void InputBounce( inputdata_t &inputdata ); void InputBounceAtTarget( inputdata_t &inputdata ); + void InputSetPlantOrientation( inputdata_t &inputdata ); + void InputSetPlantOrientationRaw( inputdata_t &inputdata ); COutputEvent m_OnTriggered; COutputEvent m_OnExplode; #endif From 8652b31ed1c20f640c5c000765fc716e937bdefa Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sun, 7 Nov 2021 14:02:13 -0600 Subject: [PATCH 230/378] Fixed the new PrecacheModel/PrecacheOther VScript functions missing serverside parameters --- sp/src/game/shared/mapbase/vscript_funcs_shared.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp b/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp index e57a714d..dd02b2ba 100644 --- a/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp +++ b/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp @@ -775,6 +775,7 @@ static void AddPhysVelocity( HSCRIPT hPhys, const Vector& vecVelocity, const Vec //============================================================================= //============================================================================= +#ifdef CLIENT_DLL static int ScriptPrecacheModel( const char *modelname ) { return CBaseEntity::PrecacheModel( modelname ); @@ -784,8 +785,17 @@ static void ScriptPrecacheOther( const char *classname ) { UTIL_PrecacheOther( classname ); } +#else +static int ScriptPrecacheModel( const char *modelname, bool bPreload ) +{ + return CBaseEntity::PrecacheModel( modelname, bPreload ); +} + +static void ScriptPrecacheOther( const char *classname, const char *modelName ) +{ + UTIL_PrecacheOther( classname, modelName ); +} -#ifndef CLIENT_DLL // TODO: Move this? static void ScriptInsertSound( int iType, const Vector &vecOrigin, int iVolume, float flDuration, HSCRIPT hOwner, int soundChannelIndex, HSCRIPT hSoundTarget ) { From e46dc3a2bdd6aa3d2652564fc46752a27d33f818 Mon Sep 17 00:00:00 2001 From: Alexander 'z33ky' Hirsch <1zeeky@gmail.com> Date: Sun, 7 Nov 2021 22:53:28 +0100 Subject: [PATCH 231/378] Fix gcc build errors & warnings --- sp/src/game/client/convarproxy.cpp | 4 ++-- sp/src/game/server/mapbase/ai_grenade.h | 6 +++--- sp/src/game/server/props.cpp | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/sp/src/game/client/convarproxy.cpp b/sp/src/game/client/convarproxy.cpp index b3670281..6b08bafc 100644 --- a/sp/src/game/client/convarproxy.cpp +++ b/sp/src/game/client/convarproxy.cpp @@ -10,8 +10,8 @@ //#pragma warning(disable: 4786) #include "convar.h" -#include "MaterialSystem/imaterialproxy.h" -#include "materialsystem/IMaterialVar.h" +#include "materialsystem/imaterialproxy.h" +#include "materialsystem/imaterialvar.h" //#include "imaterialproxydict.h" // NOTE: This has to be the last file included! diff --git a/sp/src/game/server/mapbase/ai_grenade.h b/sp/src/game/server/mapbase/ai_grenade.h index 35927333..14ec4a9a 100644 --- a/sp/src/game/server/mapbase/ai_grenade.h +++ b/sp/src/game/server/mapbase/ai_grenade.h @@ -324,12 +324,12 @@ void CAI_GrenadeUser::InputThrowGrenadeGestureAtTarget( inputdata_t &i #ifdef SHARED_COMBINE_ACTIVITIES if (IsAltFireCapable()) { - if (FVisible( m_hForcedGrenadeTarget )) + if (this->FVisible( m_hForcedGrenadeTarget )) { m_vecAltFireTarget = vecTarget; m_hForcedGrenadeTarget = NULL; - int iLayer = AddGesture( ACT_GESTURE_COMBINE_AR2_ALTFIRE ); + int iLayer = this->AddGesture( ACT_GESTURE_COMBINE_AR2_ALTFIRE ); if (iLayer != -1) { this->GetShotRegulator()->FireNoEarlierThan( gpGlobals->curtime + this->GetLayerDuration( iLayer ) ); @@ -342,7 +342,7 @@ void CAI_GrenadeUser::InputThrowGrenadeGestureAtTarget( inputdata_t &i // Ignore grenade count / distance / etc if (CheckCanThrowGrenade( vecTarget )) { - int iLayer = AddGesture( ACT_GESTURE_COMBINE_THROW_GRENADE ); + int iLayer = this->AddGesture( ACT_GESTURE_COMBINE_THROW_GRENADE ); if (iLayer != -1) { this->GetShotRegulator()->FireNoEarlierThan( gpGlobals->curtime + this->GetLayerDuration( iLayer ) ); diff --git a/sp/src/game/server/props.cpp b/sp/src/game/server/props.cpp index 18df0f7b..56428e73 100644 --- a/sp/src/game/server/props.cpp +++ b/sp/src/game/server/props.cpp @@ -44,7 +44,7 @@ #ifdef MAPBASE #include "mapbase/GlobalStrings.h" #include "collisionutils.h" -#include "vstdlib/ikeyvaluessystem.h" // From Alien Swarm SDK +#include "vstdlib/IKeyValuesSystem.h" // From Alien Swarm SDK #endif // memdbgon must be the last include file in a .cpp file!!! From 3a297d0d164648d8fb0ff18f508c0e3d8b924e2a Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sun, 7 Nov 2021 17:10:02 -0600 Subject: [PATCH 232/378] Added default parameter wrappers for PrecacheModel and PrecacheOther VScript functions --- sp/src/game/server/vscript_server.nut | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/sp/src/game/server/vscript_server.nut b/sp/src/game/server/vscript_server.nut index 1846cfdd..0a2d75d7 100644 --- a/sp/src/game/server/vscript_server.nut +++ b/sp/src/game/server/vscript_server.nut @@ -72,6 +72,18 @@ function ImpulseScale( flTargetMass, flDesiredSpeed ) } __Documentation.RegisterHelp( "ImpulseScale", "float ImpulseScale(float, float)", "Returns an impulse scale required to push an object." ); +local PrecacheModel = PrecacheModel +function PrecacheModel( a, b = true ) +{ + return PrecacheModel( a, b ) +} + +local PrecacheOther = PrecacheOther +function PrecacheOther( a, b = "" ) +{ + PrecacheOther( a, b ) +} + function __ReplaceClosures( script, scope ) { if ( !scope ) From 86a5ace57bde814d6883976c253670370a27132b Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sun, 7 Nov 2021 17:38:59 -0600 Subject: [PATCH 233/378] Added proper keyvalue for combine_mine orientation --- sp/src/game/server/hl2/combine_mine.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/sp/src/game/server/hl2/combine_mine.cpp b/sp/src/game/server/hl2/combine_mine.cpp index e8e401a4..aa9bdf29 100644 --- a/sp/src/game/server/hl2/combine_mine.cpp +++ b/sp/src/game/server/hl2/combine_mine.cpp @@ -96,6 +96,7 @@ BEGIN_DATADESC( CBounceBomb ) DEFINE_KEYFIELD( m_bCheapWarnSound, FIELD_BOOLEAN, "CheapWarnSound" ), DEFINE_KEYFIELD( m_iLOSMask, FIELD_INTEGER, "LOSMask" ), DEFINE_INPUT( m_bUnavoidable, FIELD_BOOLEAN, "SetUnavoidable" ), + DEFINE_KEYFIELD( m_vecPlantOrientation, FIELD_VECTOR, "PlantOrientation" ), #endif DEFINE_KEYFIELD( m_iModification, FIELD_INTEGER, "Modification" ), From 49befe0f7727569d8609c04130e6eed75f113823 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Tue, 9 Nov 2021 14:53:46 -0600 Subject: [PATCH 234/378] Updated README for v7.0 thus far --- README | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/README b/README index d6609449..ce19b772 100644 --- a/README +++ b/README @@ -1,6 +1,6 @@ //=================================================================================================================================================== - Mapbase - Source 2013 + Mapbase v7.0 - Source 2013 https://github.com/mapbase-source/source-sdk-2013 https://www.moddb.com/mods/mapbase @@ -47,7 +47,7 @@ Mapbase is intended to be usable by everyone, including licensed Source projects -- Mapbase also implements some of Tony Sergi's code changes from the Source 2007 SDK codebase. Both SDKs are publicly distributed by Valve and are available on Steam. Some of the features backported from the Alien Swarm SDK (e.g. game instructor, particle rain) require assets from later versions of Source in order to work properly. -The required assets have been backported from Alien Swarm and Left 4 Dead for the release build. They are not available in the code repository. +The required assets have been backported from Alien Swarm and Left 4 Dead for Mapbase's release build. They are not available in the code repository. Here's a list of Mapbase's other known external code sources: @@ -59,6 +59,7 @@ including radial fog, rope code, and treesway) - https://github.com/momentum-mod/game (Used as a guide to port postprocess_controller and env_dof_controller to Source 2013) - https://github.com/DeathByNukes/source-sdk-2013 (VBSP manifest fixes) - https://github.com/entropy-zero/source-sdk-2013 (skill_changed game event) +- https://github.com/Nbc66/source-sdk-2013-ce/tree/v142 (Base for VS2019 toolset support) //--------------------------------------------------------------------------------------------------------------------------------------------------- @@ -97,6 +98,8 @@ Direct contributions: - https://github.com/mapbase-source/source-sdk-2013/pull/60 (Adjustment by RoyaleNoir to one of Saul's VDC changes) - https://github.com/mapbase-source/source-sdk-2013/pull/84 (CS:S viewmodel chirality from 1upD) - https://github.com/mapbase-source/source-sdk-2013/pull/116 (vgui_movie_display mute keyvalue from Alivebyte/rzkid) +- https://github.com/mapbase-source/source-sdk-2013/pull/140 (logic_substring entity and icon created by moofemp) +- https://github.com/mapbase-source/source-sdk-2013/pull/143 (Propper features for VBSP from Matty-64) - Demo autorecord code provided by Klems - cc_emit crash fix provided by 1upD - Custom HL2 ammo crate models created by Rara (Textures created by Blixibon; This is asset-based and, aside from the SLAM crate, not reflected in the code) @@ -112,12 +115,16 @@ Direct contributions: =-- https://github.com/mapbase-source/source-sdk-2013/pull/105 (VScript fixes and optimizations, Vector class extensions, custom convars/commands) =-- https://github.com/mapbase-source/source-sdk-2013/pull/114 (VScript fixes and extensions) =-- https://github.com/mapbase-source/source-sdk-2013/pull/122 (Minor VScript-related adjustments) +=-- https://github.com/mapbase-source/source-sdk-2013/pull/148 (Minor fixup) == Contributions from z33ky: =-- https://github.com/mapbase-source/source-sdk-2013/pull/21 (Various GCC/Linux compilation fixes) =-- https://github.com/mapbase-source/source-sdk-2013/pull/95 (Additional GCC/Linux compilation fixes) =-- https://github.com/mapbase-source/source-sdk-2013/pull/117 (Additional GCC/Linux compilation fixes) =-- https://github.com/mapbase-source/source-sdk-2013/pull/124 (Memory error fixes) +=-- https://github.com/mapbase-source/source-sdk-2013/pull/124 (Memory error fixes) +=-- https://github.com/mapbase-source/source-sdk-2013/pull/132 (Console error fix) +=-- https://github.com/mapbase-source/source-sdk-2013/pull/152 (Additional GCC/Linux compilation fixes) //--------------------------------------------------------------------------------------------------------------------------------------------------- From aaeb5f5835e704c74ee5e95b38cc2da565dc8ccd Mon Sep 17 00:00:00 2001 From: Blixibon Date: Thu, 11 Nov 2021 09:33:29 -0600 Subject: [PATCH 235/378] Added experimental support for v143 (VS2022) and v141 (VS2017) toolsets --- sp/src/game/client/client_base.vpc | 2 +- sp/src/utils/captioncompiler/captioncompiler.vpc | 4 ++-- sp/src/vpc_scripts/default.vgc | 7 +++++-- sp/src/vpc_scripts/projects.vgc | 4 ++-- sp/src/vpc_scripts/source_dll_win32_base.vpc | 12 ++++++------ sp/src/vpc_scripts/source_exe_win_win32_base.vpc | 12 ++++++------ sp/src/vpc_scripts/source_lib_win32_base.vpc | 4 ++-- sp/src/vpc_scripts/source_win32_base.vpc | 12 +++++++----- 8 files changed, 31 insertions(+), 26 deletions(-) diff --git a/sp/src/game/client/client_base.vpc b/sp/src/game/client/client_base.vpc index 8238a0b7..b631f9ab 100644 --- a/sp/src/game/client/client_base.vpc +++ b/sp/src/game/client/client_base.vpc @@ -71,7 +71,7 @@ $Configuration $SystemFrameworks "Carbon" [$OSXALL] $SystemLibraries "rt" [$LINUXALL] $IgnoreImportLibrary "TRUE" - $AdditionalOptions "$BASE /force:multiple" [$VS2019] // Required to fix _hypot in particles.lib (this may be a temporary solution) + $AdditionalOptions "$BASE /force:multiple" [($VS2017||$VS2019||$VS2022)] // Required to fix _hypot in particles.lib (this may be a temporary solution) $AdditionalDependencies "$BASE winmm.lib" [$WIN32] $AdditionalDependencies "$BASE wsock32.lib Ws2_32.lib" [$BUILD_REPLAY] } diff --git a/sp/src/utils/captioncompiler/captioncompiler.vpc b/sp/src/utils/captioncompiler/captioncompiler.vpc index 020855fb..b3502e58 100644 --- a/sp/src/utils/captioncompiler/captioncompiler.vpc +++ b/sp/src/utils/captioncompiler/captioncompiler.vpc @@ -14,8 +14,8 @@ $Configuration $Compiler { $AdditionalIncludeDirectories "$BASE,..\common,$SRCDIR\game\shared,.\" - $PreprocessorDefinitions "$BASE;PROTECTED_THINGS_DISABLE;captioncompiler" [$VS2019] - $PreprocessorDefinitions "$BASE;captioncompiler" [!$VS2019] + $PreprocessorDefinitions "$BASE;PROTECTED_THINGS_DISABLE;captioncompiler" [($VS2017||$VS2019||$VS2022)] + $PreprocessorDefinitions "$BASE;captioncompiler" [!($VS2017||$VS2019||$VS2022)] } } diff --git a/sp/src/vpc_scripts/default.vgc b/sp/src/vpc_scripts/default.vgc index e08fa894..76e1ac12 100644 --- a/sp/src/vpc_scripts/default.vgc +++ b/sp/src/vpc_scripts/default.vgc @@ -19,12 +19,15 @@ $Conditional "SOURCESDK" "1" //----------------------------------------------------------------------------- -// Mapbase - Additional toolsets (NOTE: Newer toolsets make the solution incompatible with Visual Studio 2013) +// Mapbase - Additional toolsets (NOTE: Enabling any of these makes the solution incompatible with Visual Studio 2013) +$Conditional VS2017 "0" // Toggles Visual Studio 2017 (v141) toolset $Conditional VS2019 "0" // Toggles Visual Studio 2019 (v142) toolset +$Conditional VS2022 "0" // Toggles Visual Studio 2022 (v143) toolset // -// Note that the following projects currently do not compile with v142 and are not included in the VS2019 solution: +// Note that the following projects currently do not compile with any of the above toolsets and are not included in +// their solutions: // // - phonemeextractor (may be fixable with modification) // - qc_eyes (might be fixed by having C++ MFC for v141 build tools and/or C++ ATL for v141 build tools installed) diff --git a/sp/src/vpc_scripts/projects.vgc b/sp/src/vpc_scripts/projects.vgc index e4955ef7..f37b4970 100644 --- a/sp/src/vpc_scripts/projects.vgc +++ b/sp/src/vpc_scripts/projects.vgc @@ -63,7 +63,7 @@ $Project "motionmapper" $Project "phonemeextractor" { - "utils\phonemeextractor\phonemeextractor.vpc" [$WIN32 && !$VS2019] // Not currently working with v142; may be fixable with modification + "utils\phonemeextractor\phonemeextractor.vpc" [$WIN32 && !($VS2017||$VS2019||$VS2022)] // Not currently working with newer toolsets; may be fixable with modification } $Project "raytrace" @@ -73,7 +73,7 @@ $Project "raytrace" $Project "qc_eyes" { - "utils\qc_eyes\qc_eyes.vpc" [$WIN32 && !$VS2019] // Not currently working with v142; might be fixed by having C++ MFC for v141 build tools and/or C++ ATL for v141 build tools installed + "utils\qc_eyes\qc_eyes.vpc" [$WIN32 && !($VS2017||$VS2019||$VS2022)] // Not currently working with newer toolsets; might be fixed by having C++ MFC for v141 build tools and/or C++ ATL for v141 build tools installed } $Project "serverplugin_empty" diff --git a/sp/src/vpc_scripts/source_dll_win32_base.vpc b/sp/src/vpc_scripts/source_dll_win32_base.vpc index 2bda187c..4428c2c1 100644 --- a/sp/src/vpc_scripts/source_dll_win32_base.vpc +++ b/sp/src/vpc_scripts/source_dll_win32_base.vpc @@ -39,14 +39,14 @@ $Configuration $Compiler [$WIN32] { - $EnableEnhancedInstructionSet "Streaming SIMD Extensions (/arch:SSE)" [!$VS2019] - $EnableEnhancedInstructionSet "Streaming SIMD Extensions 2 (/arch:SSE2)" [$VS2019] + $EnableEnhancedInstructionSet "Streaming SIMD Extensions (/arch:SSE)" [!($VS2017||$VS2019||$VS2022)] + $EnableEnhancedInstructionSet "Streaming SIMD Extensions 2 (/arch:SSE2)" [($VS2017||$VS2019||$VS2022)] } $Linker { - $AdditionalDependencies "$BASE shell32.lib user32.lib advapi32.lib gdi32.lib comdlg32.lib ole32.lib" [($WIN32||$WIN64) && !$VS2019] - $AdditionalDependencies "$BASE shell32.lib user32.lib advapi32.lib gdi32.lib comdlg32.lib ole32.lib legacy_stdio_definitions.lib" [($WIN32||$WIN64) && $VS2019] + $AdditionalDependencies "$BASE shell32.lib user32.lib advapi32.lib gdi32.lib comdlg32.lib ole32.lib" [($WIN32||$WIN64) && !($VS2017||$VS2019||$VS2022)] + $AdditionalDependencies "$BASE shell32.lib user32.lib advapi32.lib gdi32.lib comdlg32.lib ole32.lib legacy_stdio_definitions.lib" [($WIN32||$WIN64) && ($VS2017||$VS2019||$VS2022)] $TargetMachine "MachineX86 (/MACHINE:X86)" [$WIN32] $TargetMachine "MachineX64 (/MACHINE:X64)" [$WIN64] // Suppress this pointless warning using the undocumented /ignore linker switch @@ -116,8 +116,8 @@ $Project $CustomBuildStep { // General - $CommandLine "$QUOTE$(VCInstallDir)bin\ml.exe$QUOTE /safeseh /c /Cp /Zi /Fo$QUOTE$(IntDir)\$(InputName).obj$QUOTE $QUOTE$(InputPath)$QUOTE" [!$VS2019] - $CommandLine "$QUOTE$(VC_ExecutablePath_x64_x86)\ml.exe$QUOTE /safeseh /c /Cp /Zi /Fo$QUOTE$(IntDir)\$(InputName).obj$QUOTE $QUOTE$(InputPath)$QUOTE" [$VS2019] + $CommandLine "$QUOTE$(VCInstallDir)bin\ml.exe$QUOTE /safeseh /c /Cp /Zi /Fo$QUOTE$(IntDir)\$(InputName).obj$QUOTE $QUOTE$(InputPath)$QUOTE" [!($VS2017||$VS2019||$VS2022)] + $CommandLine "$QUOTE$(VC_ExecutablePath_x64_x86)\ml.exe$QUOTE /safeseh /c /Cp /Zi /Fo$QUOTE$(IntDir)\$(InputName).obj$QUOTE $QUOTE$(InputPath)$QUOTE" [($VS2017||$VS2019||$VS2022)] $Description "Compiling pointeroverride.asm" $Outputs "$(IntDir)\$(InputName).obj" } diff --git a/sp/src/vpc_scripts/source_exe_win_win32_base.vpc b/sp/src/vpc_scripts/source_exe_win_win32_base.vpc index e756073f..437a16cd 100644 --- a/sp/src/vpc_scripts/source_exe_win_win32_base.vpc +++ b/sp/src/vpc_scripts/source_exe_win_win32_base.vpc @@ -39,8 +39,8 @@ $Configuration $Compiler [$WIN32] { - $EnableEnhancedInstructionSet "Streaming SIMD Extensions (/arch:SSE)" [!$VS2019] - $EnableEnhancedInstructionSet "Streaming SIMD Extensions 2 (/arch:SSE2)" [$VS2019] + $EnableEnhancedInstructionSet "Streaming SIMD Extensions (/arch:SSE)" [!($VS2017||$VS2019||$VS2022)] + $EnableEnhancedInstructionSet "Streaming SIMD Extensions 2 (/arch:SSE2)" [($VS2017||$VS2019||$VS2022)] } $Linker @@ -67,8 +67,8 @@ $Configuration $PostBuildEvent [!$ANALYZE] { - $CommandLine "call $SRCDIR\vpc_scripts\valve_p4_edit.cmd $OUTBINDIR\$(TargetFileName) $SRCDIR" "\n" [!$SOURCESDK && !$VS2019] - $CommandLine "if not exist $QUOTE$OUTBINDIR$QUOTE mkdir $QUOTE$OUTBINDIR$QUOTE" "\n" [!$SOURCESDK && $VS2019] + $CommandLine "call $SRCDIR\vpc_scripts\valve_p4_edit.cmd $OUTBINDIR\$(TargetFileName) $SRCDIR" "\n" [!$SOURCESDK && !($VS2017||$VS2019||$VS2022)] + $CommandLine "if not exist $QUOTE$OUTBINDIR$QUOTE mkdir $QUOTE$OUTBINDIR$QUOTE" "\n" [!$SOURCESDK && ($VS2017||$VS2019||$VS2022)] $CommandLine "$BASE" "copy $QUOTE$(TargetDir)$QUOTE$(TargetFileName) $OUTBINDIR\$(TargetFileName) >nul" "\n" \ "if ERRORLEVEL 1 goto BuildEventFailed" "\n" \ "if exist $QUOTE$(TargetDir)$QUOTE$(TargetName).map copy $QUOTE$(TargetDir)$QUOTE$(TargetName).map $OUTBINDIR\$(TargetName).map >nul" "\n" @@ -111,8 +111,8 @@ $Project $CustomBuildStep { // General - $CommandLine "$QUOTE$(VCInstallDir)bin\ml.exe$QUOTE /c /Cp /Zi /Fo$QUOTE$(IntDir)\$(InputName).obj$QUOTE $QUOTE$(InputPath)$QUOTE" [!$VS2019] - $CommandLine "$QUOTE$(VC_ExecutablePath_x64_x86)\ml.exe$QUOTE /c /Cp /Zi /Fo$QUOTE$(IntDir)\$(InputName).obj$QUOTE $QUOTE$(InputPath)$QUOTE" [$VS2019] + $CommandLine "$QUOTE$(VCInstallDir)bin\ml.exe$QUOTE /c /Cp /Zi /Fo$QUOTE$(IntDir)\$(InputName).obj$QUOTE $QUOTE$(InputPath)$QUOTE" [!($VS2017||$VS2019||$VS2022)] + $CommandLine "$QUOTE$(VC_ExecutablePath_x64_x86)\ml.exe$QUOTE /c /Cp /Zi /Fo$QUOTE$(IntDir)\$(InputName).obj$QUOTE $QUOTE$(InputPath)$QUOTE" [($VS2017||$VS2019||$VS2022)] $Description "Compiling pointeroverride.asm" $Outputs "$(IntDir)\$(InputName).obj" } diff --git a/sp/src/vpc_scripts/source_lib_win32_base.vpc b/sp/src/vpc_scripts/source_lib_win32_base.vpc index ee62e539..cdd5d1b8 100644 --- a/sp/src/vpc_scripts/source_lib_win32_base.vpc +++ b/sp/src/vpc_scripts/source_lib_win32_base.vpc @@ -38,8 +38,8 @@ $Configuration $Compiler [$WIN32] { - $EnableEnhancedInstructionSet "Streaming SIMD Extensions (/arch:SSE)" [!$VS2019] - $EnableEnhancedInstructionSet "Streaming SIMD Extensions 2 (/arch:SSE2)" [$VS2019] + $EnableEnhancedInstructionSet "Streaming SIMD Extensions (/arch:SSE)" [!($VS2017||$VS2019||$VS2022)] + $EnableEnhancedInstructionSet "Streaming SIMD Extensions 2 (/arch:SSE2)" [($VS2017||$VS2019||$VS2022)] } $PreBuildEvent diff --git a/sp/src/vpc_scripts/source_win32_base.vpc b/sp/src/vpc_scripts/source_win32_base.vpc index 7dd289ed..007e22c1 100644 --- a/sp/src/vpc_scripts/source_win32_base.vpc +++ b/sp/src/vpc_scripts/source_win32_base.vpc @@ -8,11 +8,13 @@ $Configuration $General { // Request a specific compiler toolset. - $PlatformToolset "v110_xp" [$VS2012 && !$ANALYZE && !$VS2019] // VS 2012 targeting Windows XP - http://msdn.microsoft.com/en-us/library/vstudio/jj851139.aspx - $PlatformToolset "v110" [$VS2012 && $ANALYZE && !$VS2019] // VS 2012 for /analyze - $PlatformToolset "v120_xp" [$VS2013 && !$ANALYZE && !$VS2019] // VS 2013 targeting Windows XP - http://msdn.microsoft.com/en-us/library/vstudio/jj851139.aspx - $PlatformToolset "v120" [$VS2013 && $ANALYZE && !$VS2019] // VS 2013 for /analyze + $PlatformToolset "v110_xp" [$VS2012 && !$ANALYZE && !($VS2017||$VS2019||$VS2022)] // VS 2012 targeting Windows XP - http://msdn.microsoft.com/en-us/library/vstudio/jj851139.aspx + $PlatformToolset "v110" [$VS2012 && $ANALYZE && !($VS2017||$VS2019||$VS2022)] // VS 2012 for /analyze + $PlatformToolset "v120_xp" [$VS2013 && !$ANALYZE && !($VS2017||$VS2019||$VS2022)] // VS 2013 targeting Windows XP - http://msdn.microsoft.com/en-us/library/vstudio/jj851139.aspx + $PlatformToolset "v120" [$VS2013 && $ANALYZE && !($VS2017||$VS2019||$VS2022)] // VS 2013 for /analyze + $PlatformToolset "v141" [$VS2017] // VS 2017 $PlatformToolset "v142" [$VS2019] // VS 2019 + $PlatformToolset "v143" [$VS2022] // VS 2022 } $General @@ -35,7 +37,7 @@ $Configuration // warning C4838: conversion requires a narrowing conversion // warning C4456-4459: variable shadowing. TODO: fix those! - $DisableSpecificWarnings "$BASE;4316;4838;4456;4457;4458;4459" [$VS2019] + $DisableSpecificWarnings "$BASE;4316;4838;4456;4457;4458;4459" [($VS2017||$VS2019||$VS2022)] // Having lots of warnings makes it harder to notice new, and possibly // important warnings, both on buildbot and in the output window. Lots From 0d9fefb7dd8e40977065c6dba792be7a2826645b Mon Sep 17 00:00:00 2001 From: Blixibon Date: Thu, 11 Nov 2021 12:28:01 -0600 Subject: [PATCH 236/378] Added experimental support for v140 (VS2015) toolset --- sp/src/game/client/client_base.vpc | 2 +- sp/src/utils/captioncompiler/captioncompiler.vpc | 4 ++-- sp/src/vpc_scripts/projects.vgc | 4 ++-- sp/src/vpc_scripts/source_dll_win32_base.vpc | 12 ++++++------ sp/src/vpc_scripts/source_exe_win_win32_base.vpc | 12 ++++++------ sp/src/vpc_scripts/source_lib_win32_base.vpc | 4 ++-- sp/src/vpc_scripts/source_win32_base.vpc | 2 +- 7 files changed, 20 insertions(+), 20 deletions(-) diff --git a/sp/src/game/client/client_base.vpc b/sp/src/game/client/client_base.vpc index b631f9ab..2fda4762 100644 --- a/sp/src/game/client/client_base.vpc +++ b/sp/src/game/client/client_base.vpc @@ -71,7 +71,7 @@ $Configuration $SystemFrameworks "Carbon" [$OSXALL] $SystemLibraries "rt" [$LINUXALL] $IgnoreImportLibrary "TRUE" - $AdditionalOptions "$BASE /force:multiple" [($VS2017||$VS2019||$VS2022)] // Required to fix _hypot in particles.lib (this may be a temporary solution) + $AdditionalOptions "$BASE /force:multiple" [($VS2015||$VS2017||$VS2019||$VS2022)] // Required to fix _hypot in particles.lib (this may be a temporary solution) $AdditionalDependencies "$BASE winmm.lib" [$WIN32] $AdditionalDependencies "$BASE wsock32.lib Ws2_32.lib" [$BUILD_REPLAY] } diff --git a/sp/src/utils/captioncompiler/captioncompiler.vpc b/sp/src/utils/captioncompiler/captioncompiler.vpc index b3502e58..3d1e24ad 100644 --- a/sp/src/utils/captioncompiler/captioncompiler.vpc +++ b/sp/src/utils/captioncompiler/captioncompiler.vpc @@ -14,8 +14,8 @@ $Configuration $Compiler { $AdditionalIncludeDirectories "$BASE,..\common,$SRCDIR\game\shared,.\" - $PreprocessorDefinitions "$BASE;PROTECTED_THINGS_DISABLE;captioncompiler" [($VS2017||$VS2019||$VS2022)] - $PreprocessorDefinitions "$BASE;captioncompiler" [!($VS2017||$VS2019||$VS2022)] + $PreprocessorDefinitions "$BASE;PROTECTED_THINGS_DISABLE;captioncompiler" [($VS2015||$VS2017||$VS2019||$VS2022)] + $PreprocessorDefinitions "$BASE;captioncompiler" [!($VS2015||$VS2017||$VS2019||$VS2022)] } } diff --git a/sp/src/vpc_scripts/projects.vgc b/sp/src/vpc_scripts/projects.vgc index f37b4970..8ea01147 100644 --- a/sp/src/vpc_scripts/projects.vgc +++ b/sp/src/vpc_scripts/projects.vgc @@ -63,7 +63,7 @@ $Project "motionmapper" $Project "phonemeextractor" { - "utils\phonemeextractor\phonemeextractor.vpc" [$WIN32 && !($VS2017||$VS2019||$VS2022)] // Not currently working with newer toolsets; may be fixable with modification + "utils\phonemeextractor\phonemeextractor.vpc" [$WIN32 && !($VS2015||$VS2017||$VS2019||$VS2022)] // Not currently working with newer toolsets; may be fixable with modification } $Project "raytrace" @@ -73,7 +73,7 @@ $Project "raytrace" $Project "qc_eyes" { - "utils\qc_eyes\qc_eyes.vpc" [$WIN32 && !($VS2017||$VS2019||$VS2022)] // Not currently working with newer toolsets; might be fixed by having C++ MFC for v141 build tools and/or C++ ATL for v141 build tools installed + "utils\qc_eyes\qc_eyes.vpc" [$WIN32 && !($VS2015||$VS2017||$VS2019||$VS2022)] // Not currently working with newer toolsets; might be fixed by having C++ MFC for v141 build tools and/or C++ ATL for v141 build tools installed } $Project "serverplugin_empty" diff --git a/sp/src/vpc_scripts/source_dll_win32_base.vpc b/sp/src/vpc_scripts/source_dll_win32_base.vpc index 4428c2c1..e69456ea 100644 --- a/sp/src/vpc_scripts/source_dll_win32_base.vpc +++ b/sp/src/vpc_scripts/source_dll_win32_base.vpc @@ -39,14 +39,14 @@ $Configuration $Compiler [$WIN32] { - $EnableEnhancedInstructionSet "Streaming SIMD Extensions (/arch:SSE)" [!($VS2017||$VS2019||$VS2022)] - $EnableEnhancedInstructionSet "Streaming SIMD Extensions 2 (/arch:SSE2)" [($VS2017||$VS2019||$VS2022)] + $EnableEnhancedInstructionSet "Streaming SIMD Extensions (/arch:SSE)" [!($VS2015||$VS2017||$VS2019||$VS2022)] + $EnableEnhancedInstructionSet "Streaming SIMD Extensions 2 (/arch:SSE2)" [($VS2015||$VS2017||$VS2019||$VS2022)] } $Linker { - $AdditionalDependencies "$BASE shell32.lib user32.lib advapi32.lib gdi32.lib comdlg32.lib ole32.lib" [($WIN32||$WIN64) && !($VS2017||$VS2019||$VS2022)] - $AdditionalDependencies "$BASE shell32.lib user32.lib advapi32.lib gdi32.lib comdlg32.lib ole32.lib legacy_stdio_definitions.lib" [($WIN32||$WIN64) && ($VS2017||$VS2019||$VS2022)] + $AdditionalDependencies "$BASE shell32.lib user32.lib advapi32.lib gdi32.lib comdlg32.lib ole32.lib" [($WIN32||$WIN64) && !($VS2015||$VS2017||$VS2019||$VS2022)] + $AdditionalDependencies "$BASE shell32.lib user32.lib advapi32.lib gdi32.lib comdlg32.lib ole32.lib legacy_stdio_definitions.lib" [($WIN32||$WIN64) && ($VS2015||$VS2017||$VS2019||$VS2022)] $TargetMachine "MachineX86 (/MACHINE:X86)" [$WIN32] $TargetMachine "MachineX64 (/MACHINE:X64)" [$WIN64] // Suppress this pointless warning using the undocumented /ignore linker switch @@ -116,8 +116,8 @@ $Project $CustomBuildStep { // General - $CommandLine "$QUOTE$(VCInstallDir)bin\ml.exe$QUOTE /safeseh /c /Cp /Zi /Fo$QUOTE$(IntDir)\$(InputName).obj$QUOTE $QUOTE$(InputPath)$QUOTE" [!($VS2017||$VS2019||$VS2022)] - $CommandLine "$QUOTE$(VC_ExecutablePath_x64_x86)\ml.exe$QUOTE /safeseh /c /Cp /Zi /Fo$QUOTE$(IntDir)\$(InputName).obj$QUOTE $QUOTE$(InputPath)$QUOTE" [($VS2017||$VS2019||$VS2022)] + $CommandLine "$QUOTE$(VCInstallDir)bin\ml.exe$QUOTE /safeseh /c /Cp /Zi /Fo$QUOTE$(IntDir)\$(InputName).obj$QUOTE $QUOTE$(InputPath)$QUOTE" [!($VS2015||$VS2017||$VS2019||$VS2022)] + $CommandLine "$QUOTE$(VC_ExecutablePath_x64_x86)\ml.exe$QUOTE /safeseh /c /Cp /Zi /Fo$QUOTE$(IntDir)\$(InputName).obj$QUOTE $QUOTE$(InputPath)$QUOTE" [($VS2015||$VS2017||$VS2019||$VS2022)] $Description "Compiling pointeroverride.asm" $Outputs "$(IntDir)\$(InputName).obj" } diff --git a/sp/src/vpc_scripts/source_exe_win_win32_base.vpc b/sp/src/vpc_scripts/source_exe_win_win32_base.vpc index 437a16cd..a6d812ba 100644 --- a/sp/src/vpc_scripts/source_exe_win_win32_base.vpc +++ b/sp/src/vpc_scripts/source_exe_win_win32_base.vpc @@ -39,8 +39,8 @@ $Configuration $Compiler [$WIN32] { - $EnableEnhancedInstructionSet "Streaming SIMD Extensions (/arch:SSE)" [!($VS2017||$VS2019||$VS2022)] - $EnableEnhancedInstructionSet "Streaming SIMD Extensions 2 (/arch:SSE2)" [($VS2017||$VS2019||$VS2022)] + $EnableEnhancedInstructionSet "Streaming SIMD Extensions (/arch:SSE)" [!($VS2015||$VS2017||$VS2019||$VS2022)] + $EnableEnhancedInstructionSet "Streaming SIMD Extensions 2 (/arch:SSE2)" [($VS2015||$VS2017||$VS2019||$VS2022)] } $Linker @@ -67,8 +67,8 @@ $Configuration $PostBuildEvent [!$ANALYZE] { - $CommandLine "call $SRCDIR\vpc_scripts\valve_p4_edit.cmd $OUTBINDIR\$(TargetFileName) $SRCDIR" "\n" [!$SOURCESDK && !($VS2017||$VS2019||$VS2022)] - $CommandLine "if not exist $QUOTE$OUTBINDIR$QUOTE mkdir $QUOTE$OUTBINDIR$QUOTE" "\n" [!$SOURCESDK && ($VS2017||$VS2019||$VS2022)] + $CommandLine "call $SRCDIR\vpc_scripts\valve_p4_edit.cmd $OUTBINDIR\$(TargetFileName) $SRCDIR" "\n" [!$SOURCESDK && !($VS2015||$VS2017||$VS2019||$VS2022)] + $CommandLine "if not exist $QUOTE$OUTBINDIR$QUOTE mkdir $QUOTE$OUTBINDIR$QUOTE" "\n" [!$SOURCESDK && ($VS2015||$VS2017||$VS2019||$VS2022)] $CommandLine "$BASE" "copy $QUOTE$(TargetDir)$QUOTE$(TargetFileName) $OUTBINDIR\$(TargetFileName) >nul" "\n" \ "if ERRORLEVEL 1 goto BuildEventFailed" "\n" \ "if exist $QUOTE$(TargetDir)$QUOTE$(TargetName).map copy $QUOTE$(TargetDir)$QUOTE$(TargetName).map $OUTBINDIR\$(TargetName).map >nul" "\n" @@ -111,8 +111,8 @@ $Project $CustomBuildStep { // General - $CommandLine "$QUOTE$(VCInstallDir)bin\ml.exe$QUOTE /c /Cp /Zi /Fo$QUOTE$(IntDir)\$(InputName).obj$QUOTE $QUOTE$(InputPath)$QUOTE" [!($VS2017||$VS2019||$VS2022)] - $CommandLine "$QUOTE$(VC_ExecutablePath_x64_x86)\ml.exe$QUOTE /c /Cp /Zi /Fo$QUOTE$(IntDir)\$(InputName).obj$QUOTE $QUOTE$(InputPath)$QUOTE" [($VS2017||$VS2019||$VS2022)] + $CommandLine "$QUOTE$(VCInstallDir)bin\ml.exe$QUOTE /c /Cp /Zi /Fo$QUOTE$(IntDir)\$(InputName).obj$QUOTE $QUOTE$(InputPath)$QUOTE" [!($VS2015||$VS2017||$VS2019||$VS2022)] + $CommandLine "$QUOTE$(VC_ExecutablePath_x64_x86)\ml.exe$QUOTE /c /Cp /Zi /Fo$QUOTE$(IntDir)\$(InputName).obj$QUOTE $QUOTE$(InputPath)$QUOTE" [($VS2015||$VS2017||$VS2019||$VS2022)] $Description "Compiling pointeroverride.asm" $Outputs "$(IntDir)\$(InputName).obj" } diff --git a/sp/src/vpc_scripts/source_lib_win32_base.vpc b/sp/src/vpc_scripts/source_lib_win32_base.vpc index cdd5d1b8..bea9d867 100644 --- a/sp/src/vpc_scripts/source_lib_win32_base.vpc +++ b/sp/src/vpc_scripts/source_lib_win32_base.vpc @@ -38,8 +38,8 @@ $Configuration $Compiler [$WIN32] { - $EnableEnhancedInstructionSet "Streaming SIMD Extensions (/arch:SSE)" [!($VS2017||$VS2019||$VS2022)] - $EnableEnhancedInstructionSet "Streaming SIMD Extensions 2 (/arch:SSE2)" [($VS2017||$VS2019||$VS2022)] + $EnableEnhancedInstructionSet "Streaming SIMD Extensions (/arch:SSE)" [!($VS2015||$VS2017||$VS2019||$VS2022)] + $EnableEnhancedInstructionSet "Streaming SIMD Extensions 2 (/arch:SSE2)" [($VS2015||$VS2017||$VS2019||$VS2022)] } $PreBuildEvent diff --git a/sp/src/vpc_scripts/source_win32_base.vpc b/sp/src/vpc_scripts/source_win32_base.vpc index 007e22c1..d57d7d49 100644 --- a/sp/src/vpc_scripts/source_win32_base.vpc +++ b/sp/src/vpc_scripts/source_win32_base.vpc @@ -37,7 +37,7 @@ $Configuration // warning C4838: conversion requires a narrowing conversion // warning C4456-4459: variable shadowing. TODO: fix those! - $DisableSpecificWarnings "$BASE;4316;4838;4456;4457;4458;4459" [($VS2017||$VS2019||$VS2022)] + $DisableSpecificWarnings "$BASE;4316;4838;4456;4457;4458;4459" [($VS2015||$VS2017||$VS2019||$VS2022)] // Having lots of warnings makes it harder to notice new, and possibly // important warnings, both on buildbot and in the output window. Lots From 3d3ef7e5877c16b8686bd24afd216691b1fa097f Mon Sep 17 00:00:00 2001 From: Blixibon Date: Thu, 11 Nov 2021 12:29:17 -0600 Subject: [PATCH 237/378] Moved the new toolsets into their own VPC file so that projects are detected as stale --- sp/src/vpc_scripts/default.vgc | 18 ------------------ sp/src/vpc_scripts/newer_vs_toolsets.vpc | 23 +++++++++++++++++++++++ sp/src/vpc_scripts/source_win32_base.vpc | 12 ++++++++---- 3 files changed, 31 insertions(+), 22 deletions(-) create mode 100644 sp/src/vpc_scripts/newer_vs_toolsets.vpc diff --git a/sp/src/vpc_scripts/default.vgc b/sp/src/vpc_scripts/default.vgc index 76e1ac12..efcaedfb 100644 --- a/sp/src/vpc_scripts/default.vgc +++ b/sp/src/vpc_scripts/default.vgc @@ -17,24 +17,6 @@ $Games // Makes the VPC scripts work in the SDK's context $Conditional "SOURCESDK" "1" -//----------------------------------------------------------------------------- - -// Mapbase - Additional toolsets (NOTE: Enabling any of these makes the solution incompatible with Visual Studio 2013) - -$Conditional VS2017 "0" // Toggles Visual Studio 2017 (v141) toolset -$Conditional VS2019 "0" // Toggles Visual Studio 2019 (v142) toolset -$Conditional VS2022 "0" // Toggles Visual Studio 2022 (v143) toolset - -// -// Note that the following projects currently do not compile with any of the above toolsets and are not included in -// their solutions: -// -// - phonemeextractor (may be fixable with modification) -// - qc_eyes (might be fixed by having C++ MFC for v141 build tools and/or C++ ATL for v141 build tools installed) -// - -//----------------------------------------------------------------------------- - $Include "vpc_scripts\projects.vgc" $Include "vpc_scripts\groups.vgc" diff --git a/sp/src/vpc_scripts/newer_vs_toolsets.vpc b/sp/src/vpc_scripts/newer_vs_toolsets.vpc new file mode 100644 index 00000000..447b3cec --- /dev/null +++ b/sp/src/vpc_scripts/newer_vs_toolsets.vpc @@ -0,0 +1,23 @@ +//----------------------------------------------------------------------------- +// NEWER_VS_TOOLSETS.VPC +// +// Additional toolsets added by Mapbase. +// +// NOTE: Enabling any of these makes the solution incompatible with Visual Studio 2013! +// +//----------------------------------------------------------------------------- + +$Conditional VS2015 "0" // Toggles Visual Studio 2015 (v140) toolset +$Conditional VS2017 "0" // Toggles Visual Studio 2017 (v141) toolset +$Conditional VS2019 "0" // Toggles Visual Studio 2019 (v142) toolset +$Conditional VS2022 "0" // Toggles Visual Studio 2022 (v143) toolset + +// +// Note that the following projects currently do not compile with any of the above toolsets and are not included in +// their solutions: +// +// - phonemeextractor (may be fixable with modification) +// - qc_eyes (might be fixed by having C++ MFC for v141 build tools and/or C++ ATL for v141 build tools installed) +// + +//----------------------------------------------------------------------------- diff --git a/sp/src/vpc_scripts/source_win32_base.vpc b/sp/src/vpc_scripts/source_win32_base.vpc index d57d7d49..e94ebd76 100644 --- a/sp/src/vpc_scripts/source_win32_base.vpc +++ b/sp/src/vpc_scripts/source_win32_base.vpc @@ -3,15 +3,19 @@ // builds the analyze.vpc file will not be listed as a dependency. $Include "$SRCDIR\vpc_scripts\source_win32_analyze.vpc" [$ANALYZE] +// Mapbase - Implement any newer toolsets +$Include "$SRCDIR\vpc_scripts\newer_vs_toolsets.vpc" + $Configuration { $General { // Request a specific compiler toolset. - $PlatformToolset "v110_xp" [$VS2012 && !$ANALYZE && !($VS2017||$VS2019||$VS2022)] // VS 2012 targeting Windows XP - http://msdn.microsoft.com/en-us/library/vstudio/jj851139.aspx - $PlatformToolset "v110" [$VS2012 && $ANALYZE && !($VS2017||$VS2019||$VS2022)] // VS 2012 for /analyze - $PlatformToolset "v120_xp" [$VS2013 && !$ANALYZE && !($VS2017||$VS2019||$VS2022)] // VS 2013 targeting Windows XP - http://msdn.microsoft.com/en-us/library/vstudio/jj851139.aspx - $PlatformToolset "v120" [$VS2013 && $ANALYZE && !($VS2017||$VS2019||$VS2022)] // VS 2013 for /analyze + $PlatformToolset "v110_xp" [$VS2012 && !$ANALYZE && !($VS2015||$VS2017||$VS2019||$VS2022)] // VS 2012 targeting Windows XP - http://msdn.microsoft.com/en-us/library/vstudio/jj851139.aspx + $PlatformToolset "v110" [$VS2012 && $ANALYZE && !($VS2015||$VS2017||$VS2019||$VS2022)] // VS 2012 for /analyze + $PlatformToolset "v120_xp" [$VS2013 && !$ANALYZE && !($VS2015||$VS2017||$VS2019||$VS2022)] // VS 2013 targeting Windows XP - http://msdn.microsoft.com/en-us/library/vstudio/jj851139.aspx + $PlatformToolset "v120" [$VS2013 && $ANALYZE && !($VS2015||$VS2017||$VS2019||$VS2022)] // VS 2013 for /analyze + $PlatformToolset "v140" [$VS2015] // VS 2015 $PlatformToolset "v141" [$VS2017] // VS 2017 $PlatformToolset "v142" [$VS2019] // VS 2019 $PlatformToolset "v143" [$VS2022] // VS 2022 From 4fbb9bc60246562c7c6e4f38c4c1c11a2bba5904 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Thu, 11 Nov 2021 19:05:09 -0600 Subject: [PATCH 238/378] Added basic support for vortigaunts using the grenade AI from CNPC_PlayerCompanion --- sp/src/game/server/hl2/npc_vortigaunt_episodic.cpp | 10 +++++++++- sp/src/game/server/hl2/npc_vortigaunt_episodic.h | 2 ++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/sp/src/game/server/hl2/npc_vortigaunt_episodic.cpp b/sp/src/game/server/hl2/npc_vortigaunt_episodic.cpp index 839c18d9..218da1a5 100644 --- a/sp/src/game/server/hl2/npc_vortigaunt_episodic.cpp +++ b/sp/src/game/server/hl2/npc_vortigaunt_episodic.cpp @@ -1070,9 +1070,17 @@ Activity CNPC_Vortigaunt::NPC_TranslateActivity( Activity eNewActivity ) if ( GetReadinessLevel() >= AIRL_STIMULATED ) return ACT_IDLE_STIMULATED; } - + if ( eNewActivity == ACT_RANGE_ATTACK2 ) + { +#ifdef MAPBASE + // If we're capable of using grenades, use ACT_COMBINE_THROW_GRENADE + if (IsGrenadeCapable()) + return ACT_COMBINE_THROW_GRENADE; + else +#endif return (Activity) ACT_VORTIGAUNT_DISPEL; + } return BaseClass::NPC_TranslateActivity( eNewActivity ); } diff --git a/sp/src/game/server/hl2/npc_vortigaunt_episodic.h b/sp/src/game/server/hl2/npc_vortigaunt_episodic.h index 5c281d59..91e6a3c6 100644 --- a/sp/src/game/server/hl2/npc_vortigaunt_episodic.h +++ b/sp/src/game/server/hl2/npc_vortigaunt_episodic.h @@ -141,6 +141,8 @@ public: #ifdef MAPBASE // Use the vortigaunts' default subtitle color (188,241,174) bool GetGameTextSpeechParams( hudtextparms_t ¶ms ) { params.r1 = 188; params.g1 = 241; params.b1 = 174; return BaseClass::GetGameTextSpeechParams( params ); } + + const char* GetGrenadeAttachment() { return "rightclaw"; } #endif private: From ad9e02885ea7a431e4947c0b72f6f67d57226a20 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Thu, 11 Nov 2021 19:06:04 -0600 Subject: [PATCH 239/378] Added crossbow readiness activities --- sp/src/game/server/hl2/weapon_crossbow.cpp | 63 +++++++++++++++------- sp/src/game/shared/activitylist.cpp | 11 ++++ sp/src/game/shared/ai_activity.h | 11 ++++ 3 files changed, 65 insertions(+), 20 deletions(-) diff --git a/sp/src/game/server/hl2/weapon_crossbow.cpp b/sp/src/game/server/hl2/weapon_crossbow.cpp index 1ce3329c..2287ce84 100644 --- a/sp/src/game/server/hl2/weapon_crossbow.cpp +++ b/sp/src/game/server/hl2/weapon_crossbow.cpp @@ -644,8 +644,50 @@ acttable_t CWeaponCrossbow::m_acttable[] = { ACT_IDLE, ACT_IDLE_CROSSBOW, true }, { ACT_IDLE_ANGRY, ACT_IDLE_ANGRY_CROSSBOW, true }, +// Readiness activities (not aiming) + { ACT_IDLE_RELAXED, ACT_IDLE_CROSSBOW_RELAXED, false },//never aims + { ACT_IDLE_STIMULATED, ACT_IDLE_CROSSBOW_STIMULATED, false }, + { ACT_IDLE_AGITATED, ACT_IDLE_ANGRY_CROSSBOW, false },//always aims + + { ACT_WALK_RELAXED, ACT_WALK_CROSSBOW_RELAXED, false },//never aims + { ACT_WALK_STIMULATED, ACT_WALK_CROSSBOW_STIMULATED, false }, + { ACT_WALK_AGITATED, ACT_WALK_AIM_CROSSBOW, false },//always aims + + { ACT_RUN_RELAXED, ACT_RUN_CROSSBOW_RELAXED, false },//never aims + { ACT_RUN_STIMULATED, ACT_RUN_CROSSBOW_STIMULATED, false }, + { ACT_RUN_AGITATED, ACT_RUN_AIM_CROSSBOW, false },//always aims + +// Readiness activities (aiming) + { ACT_IDLE_AIM_RELAXED, ACT_IDLE_CROSSBOW_RELAXED, false },//never aims + { ACT_IDLE_AIM_STIMULATED, ACT_IDLE_AIM_CROSSBOW_STIMULATED, false }, + { ACT_IDLE_AIM_AGITATED, ACT_IDLE_ANGRY_CROSSBOW, false },//always aims + + { ACT_WALK_AIM_RELAXED, ACT_WALK_CROSSBOW_RELAXED, false },//never aims + { ACT_WALK_AIM_STIMULATED, ACT_WALK_AIM_CROSSBOW_STIMULATED, false }, + { ACT_WALK_AIM_AGITATED, ACT_WALK_AIM_CROSSBOW, false },//always aims + + { ACT_RUN_AIM_RELAXED, ACT_RUN_CROSSBOW_RELAXED, false },//never aims + { ACT_RUN_AIM_STIMULATED, ACT_RUN_AIM_CROSSBOW_STIMULATED, false }, + { ACT_RUN_AIM_AGITATED, ACT_RUN_AIM_CROSSBOW, false },//always aims +//End readiness activities + { ACT_WALK, ACT_WALK_CROSSBOW, true }, - { ACT_WALK_AIM, ACT_WALK_AIM_CROSSBOW, true }, + { ACT_WALK_AIM, ACT_WALK_AIM_CROSSBOW, true }, + { ACT_WALK_CROUCH, ACT_WALK_CROUCH_RIFLE, true }, + { ACT_WALK_CROUCH_AIM, ACT_WALK_CROUCH_AIM_RIFLE, true }, + { ACT_RUN, ACT_RUN_CROSSBOW, true }, + { ACT_RUN_AIM, ACT_RUN_AIM_CROSSBOW, true }, + { ACT_RUN_CROUCH, ACT_RUN_CROUCH_RIFLE, true }, + { ACT_RUN_CROUCH_AIM, ACT_RUN_CROUCH_AIM_RIFLE, true }, + { ACT_GESTURE_RANGE_ATTACK1, ACT_GESTURE_RANGE_ATTACK_CROSSBOW, true }, + { ACT_RANGE_ATTACK1_LOW, ACT_RANGE_ATTACK_CROSSBOW_LOW, true }, + { ACT_COVER_LOW, ACT_COVER_CROSSBOW_LOW, false }, + { ACT_RANGE_AIM_LOW, ACT_RANGE_AIM_CROSSBOW_LOW, false }, + { ACT_RELOAD_LOW, ACT_RELOAD_CROSSBOW_LOW, false }, + { ACT_GESTURE_RELOAD, ACT_GESTURE_RELOAD_CROSSBOW, true }, + + { ACT_ARM, ACT_ARM_RIFLE, false }, + { ACT_DISARM, ACT_DISARM_RIFLE, false }, #else { ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_SMG1, true }, { ACT_RELOAD, ACT_RELOAD_SMG1, true }, @@ -654,7 +696,6 @@ acttable_t CWeaponCrossbow::m_acttable[] = { ACT_WALK, ACT_WALK_RIFLE, true }, { ACT_WALK_AIM, ACT_WALK_AIM_RIFLE, true }, -#endif // Readiness activities (not aiming) { ACT_IDLE_RELAXED, ACT_IDLE_SMG1_RELAXED, false },//never aims @@ -683,24 +724,6 @@ acttable_t CWeaponCrossbow::m_acttable[] = { ACT_RUN_AIM_AGITATED, ACT_RUN_AIM_RIFLE, false },//always aims //End readiness activities -#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES - { ACT_WALK_AIM, ACT_WALK_AIM_CROSSBOW, true }, - { ACT_WALK_CROUCH, ACT_WALK_CROUCH_RIFLE, true }, - { ACT_WALK_CROUCH_AIM, ACT_WALK_CROUCH_AIM_RIFLE, true }, - { ACT_RUN, ACT_RUN_CROSSBOW, true }, - { ACT_RUN_AIM, ACT_RUN_AIM_CROSSBOW, true }, - { ACT_RUN_CROUCH, ACT_RUN_CROUCH_RIFLE, true }, - { ACT_RUN_CROUCH_AIM, ACT_RUN_CROUCH_AIM_RIFLE, true }, - { ACT_GESTURE_RANGE_ATTACK1, ACT_GESTURE_RANGE_ATTACK_CROSSBOW, true }, - { ACT_RANGE_ATTACK1_LOW, ACT_RANGE_ATTACK_CROSSBOW_LOW, true }, - { ACT_COVER_LOW, ACT_COVER_CROSSBOW_LOW, false }, - { ACT_RANGE_AIM_LOW, ACT_RANGE_AIM_CROSSBOW_LOW, false }, - { ACT_RELOAD_LOW, ACT_RELOAD_CROSSBOW_LOW, false }, - { ACT_GESTURE_RELOAD, ACT_GESTURE_RELOAD_CROSSBOW, true }, - - { ACT_ARM, ACT_ARM_RIFLE, false }, - { ACT_DISARM, ACT_DISARM_RIFLE, false }, -#else { ACT_WALK_AIM, ACT_WALK_AIM_RIFLE, true }, { ACT_WALK_CROUCH, ACT_WALK_CROUCH_RIFLE, true }, { ACT_WALK_CROUCH_AIM, ACT_WALK_CROUCH_AIM_RIFLE, true }, diff --git a/sp/src/game/shared/activitylist.cpp b/sp/src/game/shared/activitylist.cpp index ecee2eee..5b13c750 100644 --- a/sp/src/game/shared/activitylist.cpp +++ b/sp/src/game/shared/activitylist.cpp @@ -2352,6 +2352,17 @@ void ActivityList_RegisterSharedActivities( void ) REGISTER_SHARED_ACTIVITY( ACT_GESTURE_RANGE_ATTACK_CROSSBOW ); REGISTER_SHARED_ACTIVITY( ACT_GESTURE_RELOAD_CROSSBOW ); + REGISTER_SHARED_ACTIVITY( ACT_IDLE_CROSSBOW_RELAXED ); + REGISTER_SHARED_ACTIVITY( ACT_IDLE_CROSSBOW_STIMULATED ); + REGISTER_SHARED_ACTIVITY( ACT_WALK_CROSSBOW_RELAXED ); + REGISTER_SHARED_ACTIVITY( ACT_RUN_CROSSBOW_RELAXED ); + REGISTER_SHARED_ACTIVITY( ACT_WALK_CROSSBOW_STIMULATED ); + REGISTER_SHARED_ACTIVITY( ACT_RUN_CROSSBOW_STIMULATED ); + + REGISTER_SHARED_ACTIVITY( ACT_IDLE_AIM_CROSSBOW_STIMULATED ); + REGISTER_SHARED_ACTIVITY( ACT_WALK_AIM_CROSSBOW_STIMULATED ); + REGISTER_SHARED_ACTIVITY( ACT_RUN_AIM_CROSSBOW_STIMULATED ); + REGISTER_SHARED_ACTIVITY( ACT_IDLE_PISTOL_RELAXED ); REGISTER_SHARED_ACTIVITY( ACT_IDLE_PISTOL_STIMULATED ); REGISTER_SHARED_ACTIVITY( ACT_WALK_PISTOL_RELAXED ); diff --git a/sp/src/game/shared/ai_activity.h b/sp/src/game/shared/ai_activity.h index ad39c548..8663ce3a 100644 --- a/sp/src/game/shared/ai_activity.h +++ b/sp/src/game/shared/ai_activity.h @@ -2228,6 +2228,17 @@ typedef enum ACT_GESTURE_RANGE_ATTACK_CROSSBOW, ACT_GESTURE_RELOAD_CROSSBOW, + ACT_IDLE_CROSSBOW_RELAXED, + ACT_IDLE_CROSSBOW_STIMULATED, + ACT_WALK_CROSSBOW_RELAXED, + ACT_RUN_CROSSBOW_RELAXED, + ACT_WALK_CROSSBOW_STIMULATED, + ACT_RUN_CROSSBOW_STIMULATED, + + ACT_IDLE_AIM_CROSSBOW_STIMULATED, + ACT_WALK_AIM_CROSSBOW_STIMULATED, + ACT_RUN_AIM_CROSSBOW_STIMULATED, + // Pistol ACT_IDLE_PISTOL_RELAXED, ACT_IDLE_PISTOL_STIMULATED, From 5a8c6350bb607877c633a70441aad153a5a3d67a Mon Sep 17 00:00:00 2001 From: Blixibon Date: Thu, 11 Nov 2021 19:06:45 -0600 Subject: [PATCH 240/378] Fixed some NPCs T-posing at medium crouch cover nodes --- sp/src/game/server/ai_basenpc.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/sp/src/game/server/ai_basenpc.cpp b/sp/src/game/server/ai_basenpc.cpp index 4cf69736..8c736cab 100644 --- a/sp/src/game/server/ai_basenpc.cpp +++ b/sp/src/game/server/ai_basenpc.cpp @@ -6623,8 +6623,14 @@ Activity CAI_BaseNPC::NPC_BackupActivity( Activity eNewActivity ) // --------------------------------------------- - if (eNewActivity == ACT_COVER_MED) - eNewActivity = ACT_COVER_LOW; + switch (eNewActivity) + { + case ACT_COVER_MED: eNewActivity = ACT_COVER_LOW; break; +#ifdef EXPANDED_HL2_COVER_ACTIVITIES + case ACT_RANGE_AIM_MED: eNewActivity = ACT_RANGE_AIM_LOW; break; + case ACT_RANGE_ATTACK1_MED: eNewActivity = ACT_RANGE_ATTACK1_LOW; break; +#endif + } //if (eNewActivity == ACT_COVER) // return TranslateActivity(ACT_IDLE); From c1f28c45503930379c5add889ab1be26e356a568 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Thu, 11 Nov 2021 19:07:04 -0600 Subject: [PATCH 241/378] Added VScript functions for NPC crouching --- sp/src/game/server/ai_basenpc.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sp/src/game/server/ai_basenpc.cpp b/sp/src/game/server/ai_basenpc.cpp index 8c736cab..dd6c5b6f 100644 --- a/sp/src/game/server/ai_basenpc.cpp +++ b/sp/src/game/server/ai_basenpc.cpp @@ -12330,6 +12330,10 @@ BEGIN_ENT_SCRIPTDESC( CAI_BaseNPC, CBaseCombatCharacter, "The base class all NPC DEFINE_SCRIPTFUNC_NAMED( VScriptGetSquad, "GetSquad", "Get the NPC's squad if it has one." ) DEFINE_SCRIPTFUNC( IsInSquad, "Returns true if the NPC is in a squad." ) DEFINE_SCRIPTFUNC( NumWeaponsInSquad, "Get the number of weapons in a squad." ) + + DEFINE_SCRIPTFUNC( IsCrouching, "Returns true if the NPC is crouching." ) + DEFINE_SCRIPTFUNC( Crouch, "Tells the NPC to crouch." ) + DEFINE_SCRIPTFUNC( Stand, "Tells the NPC to stand if it is crouching." ) // // Hooks From 301309f76bd3cae1345819a9ffe99278d76962fb Mon Sep 17 00:00:00 2001 From: Blixibon Date: Thu, 11 Nov 2021 19:07:35 -0600 Subject: [PATCH 242/378] Added forgotten code from crossbow readiness activities --- sp/src/game/server/ai_activity.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/sp/src/game/server/ai_activity.cpp b/sp/src/game/server/ai_activity.cpp index 02afb3b7..7a64a963 100644 --- a/sp/src/game/server/ai_activity.cpp +++ b/sp/src/game/server/ai_activity.cpp @@ -2236,6 +2236,17 @@ void CAI_BaseNPC::InitDefaultActivitySR(void) ADD_ACTIVITY_TO_SR( ACT_GESTURE_RANGE_ATTACK_CROSSBOW ); ADD_ACTIVITY_TO_SR( ACT_GESTURE_RELOAD_CROSSBOW ); + ADD_ACTIVITY_TO_SR( ACT_IDLE_CROSSBOW_RELAXED ); + ADD_ACTIVITY_TO_SR( ACT_IDLE_CROSSBOW_STIMULATED ); + ADD_ACTIVITY_TO_SR( ACT_WALK_CROSSBOW_RELAXED ); + ADD_ACTIVITY_TO_SR( ACT_RUN_CROSSBOW_RELAXED ); + ADD_ACTIVITY_TO_SR( ACT_WALK_CROSSBOW_STIMULATED ); + ADD_ACTIVITY_TO_SR( ACT_RUN_CROSSBOW_STIMULATED ); + + ADD_ACTIVITY_TO_SR( ACT_IDLE_AIM_CROSSBOW_STIMULATED ); + ADD_ACTIVITY_TO_SR( ACT_WALK_AIM_CROSSBOW_STIMULATED ); + ADD_ACTIVITY_TO_SR( ACT_RUN_AIM_CROSSBOW_STIMULATED ); + ADD_ACTIVITY_TO_SR( ACT_IDLE_PISTOL_RELAXED ); ADD_ACTIVITY_TO_SR( ACT_IDLE_PISTOL_STIMULATED ); ADD_ACTIVITY_TO_SR( ACT_WALK_PISTOL_RELAXED ); From 7161dee1a34723bf8dea5300f834a5f49a560d51 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sat, 13 Nov 2021 09:12:51 -0600 Subject: [PATCH 243/378] Fixed a crash involving clientside ragdoll impact decals --- sp/src/game/client/fx_impact.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sp/src/game/client/fx_impact.cpp b/sp/src/game/client/fx_impact.cpp index 0ef81cc5..236e39b4 100644 --- a/sp/src/game/client/fx_impact.cpp +++ b/sp/src/game/client/fx_impact.cpp @@ -173,7 +173,7 @@ bool Impact( Vector &vecOrigin, Vector &vecStart, int iMaterial, int iDamageType { bHitRagdoll = true; - if (g_ragdoll_client_impact_decals.GetBool()) + if (g_ragdoll_client_impact_decals.GetBool() && pRagdoll->IsRagdoll()) { pEntity = pRagdoll; From 76af96e3aee7dcdff7d8e728d2492abfc0c97bf8 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sat, 13 Nov 2021 09:13:25 -0600 Subject: [PATCH 244/378] Added TranslateActivity VScript function to CAI_BaseNPC --- sp/src/game/server/ai_basenpc.cpp | 3 +++ sp/src/game/shared/mapbase/vscript_funcs_shared.cpp | 3 +++ 2 files changed, 6 insertions(+) diff --git a/sp/src/game/server/ai_basenpc.cpp b/sp/src/game/server/ai_basenpc.cpp index dd6c5b6f..d9ad0e60 100644 --- a/sp/src/game/server/ai_basenpc.cpp +++ b/sp/src/game/server/ai_basenpc.cpp @@ -12297,6 +12297,9 @@ BEGIN_ENT_SCRIPTDESC( CAI_BaseNPC, CBaseCombatCharacter, "The base class all NPC DEFINE_SCRIPTFUNC_NAMED( ScriptSetActivityID, "SetActivityID", "Set the NPC's current activity ID." ) DEFINE_SCRIPTFUNC( ResetActivity, "Reset the NPC's current activity." ) + DEFINE_SCRIPTFUNC_NAMED( ScriptTranslateActivity, "TranslateActivity", "Translates the specified activity string and returns the translated activity ID." ) + DEFINE_SCRIPTFUNC_NAMED( ScriptTranslateActivityID, "TranslateActivityID", "Translates the specified activity ID and returns the translated activity ID." ) + DEFINE_SCRIPTFUNC_NAMED( VScriptGetGestureVersionOfActivity, "GetGestureVersionOfActivity", "Get the gesture activity counterpart of the specified sequence activity, if one exists." ) DEFINE_SCRIPTFUNC_NAMED( VScriptGetGestureVersionOfActivityID, "GetGestureVersionOfActivityID", "Get the gesture activity ID counterpart of the specified sequence activity ID, if one exists." ) DEFINE_SCRIPTFUNC_NAMED( VScriptGetSequenceVersionOfGesture, "GetSequenceVersionOfGesture", "Get the sequence activity counterpart of the specified gesture activity, if one exists." ) diff --git a/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp b/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp index dd02b2ba..ef410283 100644 --- a/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp +++ b/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp @@ -23,6 +23,7 @@ #include "vscript_server.h" #include "soundent.h" #include "rope.h" +#include "ai_basenpc.h" #else #include "c_rope.h" #endif // CLIENT_DLL @@ -1026,6 +1027,8 @@ void RegisterSharedScriptFunctions() // #ifndef CLIENT_DLL ScriptRegisterFunctionNamed( g_pScriptVM, ScriptInsertSound, "InsertAISound", "Inserts an AI sound." ); + + ScriptRegisterFunctionNamed( g_pScriptVM, CAI_BaseNPC::GetActivityName, "GetActivityName", "Gets the name of the specified activity index." ); #endif // From 13ee304ce0b1622e21a204791384fdc8231532b6 Mon Sep 17 00:00:00 2001 From: Alexander 'z33ky' Hirsch <1zeeky@gmail.com> Date: Sun, 14 Nov 2021 17:17:28 +0100 Subject: [PATCH 245/378] Fix VS2019 _msize_base() exception specification --- sp/src/public/tier0/memoverride.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sp/src/public/tier0/memoverride.cpp b/sp/src/public/tier0/memoverride.cpp index 269d44ec..5ff4dbb4 100644 --- a/sp/src/public/tier0/memoverride.cpp +++ b/sp/src/public/tier0/memoverride.cpp @@ -282,6 +282,9 @@ ALLOC_CALL void * __cdecl _recalloc ( void * memblock, size_t count, size_t size } size_t _msize_base( void *pMem ) +#if _MSC_VER >= 1925 //VS2019+ + throw() +#endif { return g_pMemAlloc->GetSize(pMem); } From 1c3b374d9e18d3eea60e995e3849175c181ead50 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sun, 14 Nov 2021 11:57:24 -0600 Subject: [PATCH 246/378] Fixed m_bDrawPlayerModelExternally causing the player's model to block flashlight shadows --- sp/src/game/client/c_baseplayer.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sp/src/game/client/c_baseplayer.cpp b/sp/src/game/client/c_baseplayer.cpp index 57a9c7eb..c02a54a8 100644 --- a/sp/src/game/client/c_baseplayer.cpp +++ b/sp/src/game/client/c_baseplayer.cpp @@ -1489,8 +1489,9 @@ int C_BasePlayer::DrawModel( int flags ) if (m_bDrawPlayerModelExternally) { // Draw the player in any view except the main or "intro" view, both of which are default first-person views. + // HACKHACK: Also don't draw in shadow depth textures if the player's flashlight is on, as that causes the playermodel to block it. view_id_t viewID = CurrentViewID(); - if (viewID == VIEW_MAIN || viewID == VIEW_INTRO_CAMERA) + if (viewID == VIEW_MAIN || viewID == VIEW_INTRO_CAMERA || (viewID == VIEW_SHADOW_DEPTH_TEXTURE && IsEffectActive(EF_DIMLIGHT))) { // Make sure the player model wouldn't draw anyway... if (!ShouldDrawThisPlayer()) From 61bbe331dd65c30ce025c3c1162645108acb4e2b Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sun, 14 Nov 2021 11:58:11 -0600 Subject: [PATCH 247/378] Fixed m_bDrawPlayerModelExternally drawing the weapon's viewmodel instead of its worldmodel --- sp/src/game/client/c_basecombatweapon.cpp | 39 +++++++++++++++++------ 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/sp/src/game/client/c_basecombatweapon.cpp b/sp/src/game/client/c_basecombatweapon.cpp index 639fd4c5..0545d0a3 100644 --- a/sp/src/game/client/c_basecombatweapon.cpp +++ b/sp/src/game/client/c_basecombatweapon.cpp @@ -502,25 +502,44 @@ int C_BaseCombatWeapon::DrawModel( int flags ) // check if local player chases owner of this weapon in first person C_BasePlayer *localplayer = C_BasePlayer::GetLocalPlayer(); - if ( localplayer && localplayer->IsObserver() && GetOwner() ) + if ( localplayer ) { #ifdef MAPBASE if (localplayer->m_bDrawPlayerModelExternally) { // If this isn't the main view, draw the weapon. view_id_t viewID = CurrentViewID(); - if (viewID != VIEW_MAIN && viewID != VIEW_INTRO_CAMERA) - return BaseClass::DrawModel( flags ); + if (viewID != VIEW_MAIN && viewID != VIEW_INTRO_CAMERA && (viewID != VIEW_SHADOW_DEPTH_TEXTURE || !localplayer->IsEffectActive(EF_DIMLIGHT))) + { + // TODO: Is this inefficient? + int nModelIndex = GetModelIndex(); + int nWorldModelIndex = GetWorldModelIndex(); + if (nModelIndex != nWorldModelIndex) + { + SetModelIndex(nWorldModelIndex); + } + + int iDraw = BaseClass::DrawModel(flags); + + if (nModelIndex != nWorldModelIndex) + { + SetModelIndex(nModelIndex); + } + + return iDraw; + } } #endif - - // don't draw weapon if chasing this guy as spectator - // we don't check that in ShouldDraw() since this may change - // without notification + if ( localplayer->IsObserver() && GetOwner() ) + { + // don't draw weapon if chasing this guy as spectator + // we don't check that in ShouldDraw() since this may change + // without notification - if ( localplayer->GetObserverMode() == OBS_MODE_IN_EYE && - localplayer->GetObserverTarget() == GetOwner() ) - return false; + if ( localplayer->GetObserverMode() == OBS_MODE_IN_EYE && + localplayer->GetObserverTarget() == GetOwner() ) + return false; + } } return BaseClass::DrawModel( flags ); From 72e846ec278421d9b5116f46844f31f38aab3bba Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sun, 14 Nov 2021 11:59:13 -0600 Subject: [PATCH 248/378] Fixed env_tonemap_controller keyvalues ignoring default values --- sp/src/game/server/env_tonemap_controller.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sp/src/game/server/env_tonemap_controller.cpp b/sp/src/game/server/env_tonemap_controller.cpp index 492b2046..95cf6135 100644 --- a/sp/src/game/server/env_tonemap_controller.cpp +++ b/sp/src/game/server/env_tonemap_controller.cpp @@ -106,7 +106,7 @@ bool CEnvTonemapController::KeyValue( const char *szKeyName, const char *szValue else if (FStrEq( szKeyName, "AutoExposureMin" )) { float flAutoExposureMin = atof( szValue ); - if (flAutoExposureMin != 1.0f) + if (flAutoExposureMin != -1.0f) { m_flCustomAutoExposureMin = flAutoExposureMin; m_bUseCustomAutoExposureMin = true; @@ -115,7 +115,7 @@ bool CEnvTonemapController::KeyValue( const char *szKeyName, const char *szValue else if (FStrEq( szKeyName, "AutoExposureMax" )) { float flAutoExposureMax = atof( szValue ); - if (flAutoExposureMax != 1.0f) + if (flAutoExposureMax != -1.0f) { m_flCustomAutoExposureMax = flAutoExposureMax; m_bUseCustomAutoExposureMax = true; @@ -124,7 +124,7 @@ bool CEnvTonemapController::KeyValue( const char *szKeyName, const char *szValue else if (FStrEq( szKeyName, "BloomScale" )) { float flBloomScale = atof( szValue ); - if (flBloomScale != 1.0f) + if (flBloomScale != -1.0f) { m_flCustomBloomScale = flBloomScale; m_flCustomBloomScaleMinimum = flBloomScale; From 2ca681431bc6ee06d72a141f1ac5f38bccb0aa18 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sun, 14 Nov 2021 12:02:26 -0600 Subject: [PATCH 249/378] Added experimental singleplayer anim state --- sp/src/game/client/c_baseplayer.cpp | 4 + sp/src/game/client/client_mapbase.vpc | 2 + sp/src/game/server/basebludgeonweapon.cpp | 4 + sp/src/game/server/hl2/hl2_player.cpp | 29 + sp/src/game/server/hl2/hl2_player.h | 7 + sp/src/game/server/hl2/weapon_357.cpp | 11 + sp/src/game/server/hl2/weapon_ar2.cpp | 11 + sp/src/game/server/hl2/weapon_crossbow.cpp | 11 + sp/src/game/server/hl2/weapon_crowbar.cpp | 12 + sp/src/game/server/hl2/weapon_frag.cpp | 23 + sp/src/game/server/hl2/weapon_physcannon.cpp | 20 + sp/src/game/server/hl2/weapon_pistol.cpp | 11 + sp/src/game/server/hl2/weapon_rpg.cpp | 11 + sp/src/game/server/hl2/weapon_shotgun.cpp | 19 + sp/src/game/server/hl2/weapon_smg1.cpp | 11 + sp/src/game/server/server_mapbase.vpc | 2 + .../shared/mapbase/singleplayer_animstate.cpp | 504 ++++++++++++++++++ .../shared/mapbase/singleplayer_animstate.h | 88 +++ 18 files changed, 780 insertions(+) create mode 100644 sp/src/game/shared/mapbase/singleplayer_animstate.cpp create mode 100644 sp/src/game/shared/mapbase/singleplayer_animstate.h diff --git a/sp/src/game/client/c_baseplayer.cpp b/sp/src/game/client/c_baseplayer.cpp index c02a54a8..acb398f0 100644 --- a/sp/src/game/client/c_baseplayer.cpp +++ b/sp/src/game/client/c_baseplayer.cpp @@ -1367,6 +1367,10 @@ void C_BasePlayer::AddEntity( void ) // Add in lighting effects CreateLightEffects(); + +#ifdef MAPBASE + SetLocalAnglesDim( X_INDEX, 0 ); +#endif } extern float UTIL_WaterLevel( const Vector &position, float minz, float maxz ); diff --git a/sp/src/game/client/client_mapbase.vpc b/sp/src/game/client/client_mapbase.vpc index 4d593fc5..97a2217d 100644 --- a/sp/src/game/client/client_mapbase.vpc +++ b/sp/src/game/client/client_mapbase.vpc @@ -47,6 +47,8 @@ $Project $File "$SRCDIR\game\shared\mapbase\MapEdit.h" $File "$SRCDIR\game\shared\mapbase\matchers.cpp" $File "$SRCDIR\game\shared\mapbase\matchers.h" + $File "$SRCDIR\game\shared\mapbase\singleplayer_animstate.cpp" + $File "$SRCDIR\game\shared\mapbase\singleplayer_animstate.h" $File "$SRCDIR\game\shared\mapbase\vscript_funcs_shared.cpp" [$MAPBASE_VSCRIPT] $File "$SRCDIR\game\shared\mapbase\vscript_funcs_shared.h" [$MAPBASE_VSCRIPT] $File "$SRCDIR\game\shared\mapbase\vscript_singletons.cpp" [$MAPBASE_VSCRIPT] diff --git a/sp/src/game/server/basebludgeonweapon.cpp b/sp/src/game/server/basebludgeonweapon.cpp index cb9c1fc8..57683a19 100644 --- a/sp/src/game/server/basebludgeonweapon.cpp +++ b/sp/src/game/server/basebludgeonweapon.cpp @@ -406,4 +406,8 @@ void CBaseHLBludgeonWeapon::Swing( int bIsSecondary ) //Play swing sound WeaponSound( SINGLE ); #endif + +#ifdef MAPBASE + pOwner->SetAnimation( PLAYER_ATTACK1 ); +#endif } diff --git a/sp/src/game/server/hl2/hl2_player.cpp b/sp/src/game/server/hl2/hl2_player.cpp index 46e80cc5..e3dc3f03 100644 --- a/sp/src/game/server/hl2/hl2_player.cpp +++ b/sp/src/game/server/hl2/hl2_player.cpp @@ -621,6 +621,12 @@ END_SCRIPTDESC(); CHL2_Player::CHL2_Player() { +#ifdef SP_ANIM_STATE + // Here we create and init the player animation state. + m_pPlayerAnimState = CreatePlayerAnimationState(this); + m_angEyeAngles.Init(); +#endif + m_nNumMissPositions = 0; m_pPlayerAISquad = 0; m_bSprintEnabled = true; @@ -1144,6 +1150,16 @@ void CHL2_Player::PostThink( void ) { HandleAdmireGlovesAnimation(); } + +#ifdef SP_ANIM_STATE + m_angEyeAngles = EyeAngles(); + + QAngle angles = GetLocalAngles(); + angles[PITCH] = 0; + SetLocalAngles(angles); + + m_pPlayerAnimState->Update(); // m_pPlayerAnimState->Update( m_angEyeAngles.y, m_angEyeAngles.x ); +#endif } void CHL2_Player::StartAdmireGlovesAnimation( void ) @@ -1490,6 +1506,11 @@ void CHL2_Player::SetAnimation( PLAYER_ANIM playerAnim ) } } } + + if ( IsInAVehicle() ) + { + idealActivity = ACT_COVER_LOW; + } if ( idealActivity == ACT_HL2MP_GESTURE_RANGE_ATTACK ) { @@ -1835,6 +1856,14 @@ void CHL2_Player::InitVCollision( const Vector &vecAbsOrigin, const Vector &vecA CHL2_Player::~CHL2_Player( void ) { +#ifdef SP_ANIM_STATE + // Clears the animation state. + if ( m_pPlayerAnimState != NULL ) + { + m_pPlayerAnimState->Release(); + m_pPlayerAnimState = NULL; + } +#endif } //----------------------------------------------------------------------------- diff --git a/sp/src/game/server/hl2/hl2_player.h b/sp/src/game/server/hl2/hl2_player.h index 0ffc68f5..a4886730 100644 --- a/sp/src/game/server/hl2/hl2_player.h +++ b/sp/src/game/server/hl2/hl2_player.h @@ -18,6 +18,8 @@ // In HL2MP we need to inherit from BaseMultiplayerPlayer! #if defined ( HL2MP ) #include "basemultiplayerplayer.h" +#elif defined ( MAPBASE ) +#include "mapbase/singleplayer_animstate.h" #endif class CAI_Squad; @@ -432,6 +434,11 @@ private: float m_flTimeNextLadderHint; // Next time we're eligible to display a HUD hint about a ladder. friend class CHL2GameMovement; + +#ifdef SP_ANIM_STATE + CSinglePlayerAnimState* m_pPlayerAnimState; + QAngle m_angEyeAngles; +#endif }; diff --git a/sp/src/game/server/hl2/weapon_357.cpp b/sp/src/game/server/hl2/weapon_357.cpp index 8b4fe93f..a73a97ba 100644 --- a/sp/src/game/server/hl2/weapon_357.cpp +++ b/sp/src/game/server/hl2/weapon_357.cpp @@ -198,6 +198,17 @@ acttable_t CWeapon357::m_acttable[] = { ACT_RANGE_AIM_MED, ACT_RANGE_AIM_REVOLVER_MED, false }, { ACT_RANGE_ATTACK1_MED, ACT_RANGE_ATTACK_REVOLVER_MED, false }, #endif + +#ifdef MAPBASE + // HL2:DM activities (for third-person animations in SP) + { ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_PISTOL, false }, + { ACT_HL2MP_RUN, ACT_HL2MP_RUN_PISTOL, false }, + { ACT_HL2MP_IDLE_CROUCH, ACT_HL2MP_IDLE_CROUCH_PISTOL, false }, + { ACT_HL2MP_WALK_CROUCH, ACT_HL2MP_WALK_CROUCH_PISTOL, false }, + { ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_PISTOL, false }, + { ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_PISTOL, false }, + { ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_PISTOL, false }, +#endif }; diff --git a/sp/src/game/server/hl2/weapon_ar2.cpp b/sp/src/game/server/hl2/weapon_ar2.cpp index e6a32e93..6b634de0 100644 --- a/sp/src/game/server/hl2/weapon_ar2.cpp +++ b/sp/src/game/server/hl2/weapon_ar2.cpp @@ -171,6 +171,17 @@ acttable_t CWeaponAR2::m_acttable[] = { ACT_COVER_WALL_LOW_R, ACT_COVER_WALL_LOW_R_RIFLE, false }, { ACT_COVER_WALL_LOW_L, ACT_COVER_WALL_LOW_L_RIFLE, false }, #endif + +#ifdef MAPBASE + // HL2:DM activities (for third-person animations in SP) + { ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_AR2, false }, + { ACT_HL2MP_RUN, ACT_HL2MP_RUN_AR2, false }, + { ACT_HL2MP_IDLE_CROUCH, ACT_HL2MP_IDLE_CROUCH_AR2, false }, + { ACT_HL2MP_WALK_CROUCH, ACT_HL2MP_WALK_CROUCH_AR2, false }, + { ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_AR2, false }, + { ACT_HL2MP_GESTURE_RELOAD, ACT_GESTURE_RELOAD_SMG1, false }, + { ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_AR2, false }, +#endif }; IMPLEMENT_ACTTABLE(CWeaponAR2); diff --git a/sp/src/game/server/hl2/weapon_crossbow.cpp b/sp/src/game/server/hl2/weapon_crossbow.cpp index 2287ce84..b8d9db71 100644 --- a/sp/src/game/server/hl2/weapon_crossbow.cpp +++ b/sp/src/game/server/hl2/weapon_crossbow.cpp @@ -743,6 +743,17 @@ acttable_t CWeaponCrossbow::m_acttable[] = { ACT_RANGE_AIM_MED, ACT_RANGE_AIM_CROSSBOW_MED, false }, { ACT_RANGE_ATTACK1_MED, ACT_RANGE_ATTACK_CROSSBOW_MED, false }, #endif + +#ifdef MAPBASE + // HL2:DM activities (for third-person animations in SP) + { ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_CROSSBOW, false }, + { ACT_HL2MP_RUN, ACT_HL2MP_RUN_CROSSBOW, false }, + { ACT_HL2MP_IDLE_CROUCH, ACT_HL2MP_IDLE_CROUCH_CROSSBOW, false }, + { ACT_HL2MP_WALK_CROUCH, ACT_HL2MP_WALK_CROUCH_CROSSBOW, false }, + { ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_CROSSBOW, false }, + { ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_CROSSBOW, false }, + { ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_CROSSBOW, false }, +#endif }; IMPLEMENT_ACTTABLE(CWeaponCrossbow); diff --git a/sp/src/game/server/hl2/weapon_crowbar.cpp b/sp/src/game/server/hl2/weapon_crowbar.cpp index 8a0daacf..46c935a8 100644 --- a/sp/src/game/server/hl2/weapon_crowbar.cpp +++ b/sp/src/game/server/hl2/weapon_crowbar.cpp @@ -49,6 +49,18 @@ acttable_t CWeaponCrowbar::m_acttable[] = { ACT_ARM, ACT_ARM_MELEE, false }, { ACT_DISARM, ACT_DISARM_MELEE, false }, #endif + +#ifdef MAPBASE + // HL2:DM activities (for third-person animations in SP) + { ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_SLAM, true }, + { ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_MELEE, false }, + { ACT_HL2MP_RUN, ACT_HL2MP_RUN_MELEE, false }, + { ACT_HL2MP_IDLE_CROUCH, ACT_HL2MP_IDLE_CROUCH_MELEE, false }, + { ACT_HL2MP_WALK_CROUCH, ACT_HL2MP_WALK_CROUCH_MELEE, false }, + { ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_MELEE, false }, + { ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_MELEE, false }, + { ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_MELEE, false }, +#endif }; IMPLEMENT_ACTTABLE(CWeaponCrowbar); diff --git a/sp/src/game/server/hl2/weapon_frag.cpp b/sp/src/game/server/hl2/weapon_frag.cpp index b0e188aa..c248c74e 100644 --- a/sp/src/game/server/hl2/weapon_frag.cpp +++ b/sp/src/game/server/hl2/weapon_frag.cpp @@ -82,6 +82,17 @@ END_DATADESC() acttable_t CWeaponFrag::m_acttable[] = { { ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_SLAM, true }, + +#ifdef MAPBASE + // HL2:DM activities (for third-person animations in SP) + { ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_GRENADE, false }, + { ACT_HL2MP_RUN, ACT_HL2MP_RUN_GRENADE, false }, + { ACT_HL2MP_IDLE_CROUCH, ACT_HL2MP_IDLE_CROUCH_GRENADE, false }, + { ACT_HL2MP_WALK_CROUCH, ACT_HL2MP_WALK_CROUCH_GRENADE, false }, + { ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_GRENADE, false }, + { ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_GRENADE, false }, + { ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_GRENADE, false }, +#endif }; IMPLEMENT_ACTTABLE(CWeaponFrag); @@ -404,6 +415,10 @@ void CWeaponFrag::ThrowGrenade( CBasePlayer *pPlayer ) WeaponSound( SINGLE ); +#ifdef MAPBASE + pPlayer->SetAnimation( PLAYER_ATTACK1 ); +#endif + m_iPrimaryAttacks++; gamestats->Event_WeaponFired( pPlayer, true, GetClassname() ); } @@ -428,6 +443,10 @@ void CWeaponFrag::LobGrenade( CBasePlayer *pPlayer ) WeaponSound( WPN_DOUBLE ); +#ifdef MAPBASE + pPlayer->SetAnimation( PLAYER_ATTACK1 ); +#endif + m_bRedraw = true; m_iPrimaryAttacks++; @@ -472,6 +491,10 @@ void CWeaponFrag::RollGrenade( CBasePlayer *pPlayer ) WeaponSound( SPECIAL1 ); +#ifdef MAPBASE + pPlayer->SetAnimation( PLAYER_ATTACK1 ); +#endif + m_bRedraw = true; m_iPrimaryAttacks++; diff --git a/sp/src/game/server/hl2/weapon_physcannon.cpp b/sp/src/game/server/hl2/weapon_physcannon.cpp index 87fddf4e..3dfe86c3 100644 --- a/sp/src/game/server/hl2/weapon_physcannon.cpp +++ b/sp/src/game/server/hl2/weapon_physcannon.cpp @@ -1238,6 +1238,9 @@ public: DECLARE_SERVERCLASS(); DECLARE_DATADESC(); +#ifdef MAPBASE + DECLARE_ACTTABLE(); +#endif CWeaponPhysCannon( void ); @@ -1455,6 +1458,23 @@ BEGIN_DATADESC( CWeaponPhysCannon ) END_DATADESC() +#ifdef MAPBASE +acttable_t CWeaponPhysCannon::m_acttable[] = +{ + // HL2:DM activities (for third-person animations in SP) + { ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_PHYSGUN, false }, + { ACT_HL2MP_RUN, ACT_HL2MP_RUN_PHYSGUN, false }, + { ACT_HL2MP_IDLE_CROUCH, ACT_HL2MP_IDLE_CROUCH_PHYSGUN, false }, + { ACT_HL2MP_WALK_CROUCH, ACT_HL2MP_WALK_CROUCH_PHYSGUN, false }, + { ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_PHYSGUN, false }, + { ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_PHYSGUN, false }, + { ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_PHYSGUN, false }, + { ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_SLAM, false }, +}; + +IMPLEMENT_ACTTABLE( CWeaponPhysCannon ); +#endif + enum { diff --git a/sp/src/game/server/hl2/weapon_pistol.cpp b/sp/src/game/server/hl2/weapon_pistol.cpp index a04d30b6..66084797 100644 --- a/sp/src/game/server/hl2/weapon_pistol.cpp +++ b/sp/src/game/server/hl2/weapon_pistol.cpp @@ -257,6 +257,17 @@ acttable_t CWeaponPistol::m_acttable[] = { ACT_COVER_WALL_LOW_R, ACT_COVER_WALL_LOW_R_PISTOL, false }, { ACT_COVER_WALL_LOW_L, ACT_COVER_WALL_LOW_L_PISTOL, false }, #endif + +#ifdef MAPBASE + // HL2:DM activities (for third-person animations in SP) + { ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_PISTOL, false }, + { ACT_HL2MP_RUN, ACT_HL2MP_RUN_PISTOL, false }, + { ACT_HL2MP_IDLE_CROUCH, ACT_HL2MP_IDLE_CROUCH_PISTOL, false }, + { ACT_HL2MP_WALK_CROUCH, ACT_HL2MP_WALK_CROUCH_PISTOL, false }, + { ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_PISTOL, false }, + { ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_PISTOL, false }, + { ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_PISTOL, false }, +#endif }; diff --git a/sp/src/game/server/hl2/weapon_rpg.cpp b/sp/src/game/server/hl2/weapon_rpg.cpp index 2d20211d..3a8be219 100644 --- a/sp/src/game/server/hl2/weapon_rpg.cpp +++ b/sp/src/game/server/hl2/weapon_rpg.cpp @@ -1426,6 +1426,17 @@ acttable_t CWeaponRPG::m_acttable[] = { ACT_RANGE_AIM_MED, ACT_RANGE_AIM_RPG_MED, false }, { ACT_RANGE_ATTACK1_MED, ACT_RANGE_ATTACK_RPG_MED, false }, #endif + +#ifdef MAPBASE + // HL2:DM activities (for third-person animations in SP) + { ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_RPG, false }, + { ACT_HL2MP_RUN, ACT_HL2MP_RUN_RPG, false }, + { ACT_HL2MP_IDLE_CROUCH, ACT_HL2MP_IDLE_CROUCH_RPG, false }, + { ACT_HL2MP_WALK_CROUCH, ACT_HL2MP_WALK_CROUCH_RPG, false }, + { ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_RPG, false }, + { ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_RPG, false }, + { ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_RPG, false }, +#endif }; IMPLEMENT_ACTTABLE(CWeaponRPG); diff --git a/sp/src/game/server/hl2/weapon_shotgun.cpp b/sp/src/game/server/hl2/weapon_shotgun.cpp index e0b2e336..50752e8c 100644 --- a/sp/src/game/server/hl2/weapon_shotgun.cpp +++ b/sp/src/game/server/hl2/weapon_shotgun.cpp @@ -215,6 +215,17 @@ acttable_t CWeaponShotgun::m_acttable[] = { ACT_RANGE_AIM_MED, ACT_RANGE_AIM_SHOTGUN_MED, false }, { ACT_RANGE_ATTACK1_MED, ACT_RANGE_ATTACK_SHOTGUN_MED, false }, #endif + +#ifdef MAPBASE + // HL2:DM activities (for third-person animations in SP) + { ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_SHOTGUN, false }, + { ACT_HL2MP_RUN, ACT_HL2MP_RUN_SHOTGUN, false }, + { ACT_HL2MP_IDLE_CROUCH, ACT_HL2MP_IDLE_CROUCH_SHOTGUN, false }, + { ACT_HL2MP_WALK_CROUCH, ACT_HL2MP_WALK_CROUCH_SHOTGUN, false }, + { ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_SHOTGUN, false }, + { ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_SHOTGUN, false }, + { ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_SHOTGUN, false }, +#endif }; IMPLEMENT_ACTTABLE(CWeaponShotgun); @@ -531,7 +542,11 @@ void CWeaponShotgun::PrimaryAttack( void ) pPlayer->SetAnimation( PLAYER_ATTACK1 ); // Don't fire again until fire animation has completed +#ifdef MAPBASE + m_flNextPrimaryAttack = gpGlobals->curtime + GetViewModelSequenceDuration(); +#else m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration(); +#endif m_iClip1 -= 1; Vector vecSrc = pPlayer->Weapon_ShootPosition( ); @@ -589,7 +604,11 @@ void CWeaponShotgun::SecondaryAttack( void ) pPlayer->SetAnimation( PLAYER_ATTACK1 ); // Don't fire again until fire animation has completed +#ifdef MAPBASE + m_flNextPrimaryAttack = gpGlobals->curtime + GetViewModelSequenceDuration(); +#else m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration(); +#endif m_iClip1 -= 2; // Shotgun uses same clip for primary and secondary attacks Vector vecSrc = pPlayer->Weapon_ShootPosition(); diff --git a/sp/src/game/server/hl2/weapon_smg1.cpp b/sp/src/game/server/hl2/weapon_smg1.cpp index 04f7e390..96cfdd2c 100644 --- a/sp/src/game/server/hl2/weapon_smg1.cpp +++ b/sp/src/game/server/hl2/weapon_smg1.cpp @@ -149,6 +149,17 @@ acttable_t CWeaponSMG1::m_acttable[] = { ACT_COVER_WALL_LOW_R, ACT_COVER_WALL_LOW_R_RIFLE, false }, { ACT_COVER_WALL_LOW_L, ACT_COVER_WALL_LOW_L_RIFLE, false }, #endif + +#ifdef MAPBASE + // HL2:DM activities (for third-person animations in SP) + { ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_SMG1, false }, + { ACT_HL2MP_RUN, ACT_HL2MP_RUN_SMG1, false }, + { ACT_HL2MP_IDLE_CROUCH, ACT_HL2MP_IDLE_CROUCH_SMG1, false }, + { ACT_HL2MP_WALK_CROUCH, ACT_HL2MP_WALK_CROUCH_SMG1, false }, + { ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_SMG1, false }, + { ACT_HL2MP_GESTURE_RELOAD, ACT_GESTURE_RELOAD_SMG1, false }, + { ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_SMG1, false }, +#endif }; IMPLEMENT_ACTTABLE(CWeaponSMG1); diff --git a/sp/src/game/server/server_mapbase.vpc b/sp/src/game/server/server_mapbase.vpc index 80ece7cf..b04706d4 100644 --- a/sp/src/game/server/server_mapbase.vpc +++ b/sp/src/game/server/server_mapbase.vpc @@ -46,6 +46,8 @@ $Project $File "$SRCDIR\game\shared\mapbase\MapEdit.h" $File "$SRCDIR\game\shared\mapbase\matchers.cpp" $File "$SRCDIR\game\shared\mapbase\matchers.h" + $File "$SRCDIR\game\shared\mapbase\singleplayer_animstate.cpp" + $File "$SRCDIR\game\shared\mapbase\singleplayer_animstate.h" $File "$SRCDIR\game\shared\mapbase\vscript_funcs_shared.cpp" [$MAPBASE_VSCRIPT] $File "$SRCDIR\game\shared\mapbase\vscript_funcs_shared.h" [$MAPBASE_VSCRIPT] $File "$SRCDIR\game\shared\mapbase\vscript_singletons.cpp" [$MAPBASE_VSCRIPT] diff --git a/sp/src/game/shared/mapbase/singleplayer_animstate.cpp b/sp/src/game/shared/mapbase/singleplayer_animstate.cpp new file mode 100644 index 00000000..3936040f --- /dev/null +++ b/sp/src/game/shared/mapbase/singleplayer_animstate.cpp @@ -0,0 +1,504 @@ +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: Single Player animation state 'handler'. This utility is used +// to evaluate the pose parameter value based on the direction +// and speed of the player. +// +//====================================================================================// + +#include "cbase.h" +#include "singleplayer_animstate.h" +#include "tier0/vprof.h" +#include "animation.h" +#include "studio.h" +#include "apparent_velocity_helper.h" +#include "utldict.h" +#include "filesystem.h" +#include "..\public\datacache\imdlcache.h" + +extern ConVar mp_facefronttime, mp_feetyawrate, mp_ik; + +#define MIN_TURN_ANGLE_REQUIRING_TURN_ANIMATION 15.0f + +CSinglePlayerAnimState *CreatePlayerAnimationState( CBasePlayer *pPlayer ) +{ + MDLCACHE_CRITICAL_SECTION(); + + CSinglePlayerAnimState *pState = new CSinglePlayerAnimState( pPlayer ); + pState->Init(pPlayer); + + return pState; +} + +// Below this many degrees, slow down turning rate linearly +#define FADE_TURN_DEGREES 45.0f +// After this, need to start turning feet +#define MAX_TORSO_ANGLE 90.0f +// Below this amount, don't play a turning animation/perform IK +#define MIN_TURN_ANGLE_REQUIRING_TURN_ANIMATION 15.0f + +//static ConVar tf2_feetyawrunscale( "tf2_feetyawrunscale", "2", FCVAR_REPLICATED, "Multiplier on tf2_feetyawrate to allow turning faster when running." ); +extern ConVar sv_backspeed; +extern ConVar mp_feetyawrate; +extern ConVar mp_facefronttime; +extern ConVar mp_ik; + +CSinglePlayerAnimState::CSinglePlayerAnimState( CBasePlayer *pPlayer ): m_pPlayer( pPlayer ) +{ + m_flGaitYaw = 0.0f; + m_flGoalFeetYaw = 0.0f; + m_flCurrentFeetYaw = 0.0f; + m_flCurrentTorsoYaw = 0.0f; + m_flLastYaw = 0.0f; + m_flLastTurnTime = 0.0f; + m_flTurnCorrectionTime = 0.0f; + + m_pPlayer = NULL; +}; + +void CSinglePlayerAnimState::Init( CBasePlayer *pPlayer ) +{ + m_pPlayer = pPlayer; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CSinglePlayerAnimState::Update() +{ + m_angRender = GetBasePlayer()->GetLocalAngles(); + + ComputePoseParam_BodyYaw(); + ComputePoseParam_BodyPitch(GetBasePlayer()->GetModelPtr()); + ComputePoseParam_BodyLookYaw(); + ComputePoseParam_HeadPitch(GetBasePlayer()->GetModelPtr()); + + ComputePlaybackRate(); +} + +void CSinglePlayerAnimState::Release() +{ + delete this; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CSinglePlayerAnimState::ComputePlaybackRate() +{ + // Determine ideal playback rate + Vector vel; + GetOuterAbsVelocity( vel ); + + float speed = vel.Length2D(); + + bool isMoving = ( speed > 0.5f ) ? true : false; + + float maxspeed = GetBasePlayer()->GetSequenceGroundSpeed( GetBasePlayer()->GetSequence() ); + + if ( isMoving && ( maxspeed > 0.0f ) ) + { + float flFactor = 1.0f; + + // Note this gets set back to 1.0 if sequence changes due to ResetSequenceInfo below + GetBasePlayer()->SetPlaybackRate( ( speed * flFactor ) / maxspeed ); + + // BUG BUG: + // This stuff really should be m_flPlaybackRate = speed / m_flGroundSpeed + } + else + { + GetBasePlayer()->SetPlaybackRate( 1.0f ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : CBasePlayer +//----------------------------------------------------------------------------- +CBasePlayer *CSinglePlayerAnimState::GetBasePlayer() +{ + return m_pPlayer; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : dt - +//----------------------------------------------------------------------------- +void CSinglePlayerAnimState::EstimateYaw( void ) +{ + float dt = gpGlobals->frametime; + + if ( !dt ) + { + return; + } + + Vector est_velocity; + QAngle angles; + + GetOuterAbsVelocity( est_velocity ); + + angles = GetBasePlayer()->GetLocalAngles(); + + if ( est_velocity[1] == 0 && est_velocity[0] == 0 ) + { + float flYawDiff = angles[YAW] - m_flGaitYaw; + flYawDiff = flYawDiff - (int)(flYawDiff / 360) * 360; + if (flYawDiff > 180) + flYawDiff -= 360; + if (flYawDiff < -180) + flYawDiff += 360; + + if (dt < 0.25) + flYawDiff *= dt * 4; + else + flYawDiff *= dt; + + m_flGaitYaw += flYawDiff; + m_flGaitYaw = m_flGaitYaw - (int)(m_flGaitYaw / 360) * 360; + } + else + { + m_flGaitYaw = (atan2(est_velocity[1], est_velocity[0]) * 180 / M_PI); + + if (m_flGaitYaw > 180) + m_flGaitYaw = 180; + else if (m_flGaitYaw < -180) + m_flGaitYaw = -180; + } +} + +//----------------------------------------------------------------------------- +// Purpose: Override for backpeddling +// Input : dt - +//----------------------------------------------------------------------------- +void CSinglePlayerAnimState::ComputePoseParam_BodyYaw( void ) +{ + int iYaw = GetBasePlayer()->LookupPoseParameter( "move_yaw" ); + if ( iYaw < 0 ) + return; + + // view direction relative to movement + float flYaw; + + EstimateYaw(); + + QAngle angles = GetBasePlayer()->GetLocalAngles(); + float ang = angles[ YAW ]; + if ( ang > 180.0f ) + { + ang -= 360.0f; + } + else if ( ang < -180.0f ) + { + ang += 360.0f; + } + + // calc side to side turning + flYaw = ang - m_flGaitYaw; + // Invert for mapping into 8way blend + flYaw = -flYaw; + flYaw = flYaw - (int)(flYaw / 360) * 360; + + if (flYaw < -180) + { + flYaw = flYaw + 360; + } + else if (flYaw > 180) + { + flYaw = flYaw - 360; + } + + GetBasePlayer()->SetPoseParameter( iYaw, flYaw ); + +#ifndef CLIENT_DLL + //Adrian: Make the model's angle match the legs so the hitboxes match on both sides. + GetBasePlayer()->SetLocalAngles( QAngle( GetBasePlayer()->EyeAngles().x, m_flCurrentFeetYaw, 0 ) ); +#endif +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CSinglePlayerAnimState::ComputePoseParam_BodyPitch( CStudioHdr *pStudioHdr ) +{ + // Get pitch from v_angle + float flPitch = GetBasePlayer()->GetLocalAngles()[ PITCH ]; + + if ( flPitch > 180.0f ) + { + flPitch -= 360.0f; + } + flPitch = clamp( flPitch, -90, 90 ); + + QAngle absangles = GetBasePlayer()->GetAbsAngles(); + absangles.x = 0.0f; + m_angRender = absangles; + + // See if we have a blender for pitch + GetBasePlayer()->SetPoseParameter( pStudioHdr, "aim_pitch", flPitch ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : goal - +// maxrate - +// dt - +// current - +// Output : int +//----------------------------------------------------------------------------- +int CSinglePlayerAnimState::ConvergeAngles( float goal,float maxrate, float dt, float& current ) +{ + int direction = TURN_NONE; + + float anglediff = goal - current; + float anglediffabs = fabs( anglediff ); + + anglediff = AngleNormalize( anglediff ); + + float scale = 1.0f; + if ( anglediffabs <= FADE_TURN_DEGREES ) + { + scale = anglediffabs / FADE_TURN_DEGREES; + // Always do at least a bit of the turn ( 1% ) + scale = clamp( scale, 0.01f, 1.0f ); + } + + float maxmove = maxrate * dt * scale; + + if ( fabs( anglediff ) < maxmove ) + { + current = goal; + } + else + { + if ( anglediff > 0 ) + { + current += maxmove; + direction = TURN_LEFT; + } + else + { + current -= maxmove; + direction = TURN_RIGHT; + } + } + + current = AngleNormalize( current ); + + return direction; +} + +void CSinglePlayerAnimState::ComputePoseParam_BodyLookYaw( void ) +{ + QAngle absangles = GetBasePlayer()->GetAbsAngles(); + absangles.y = AngleNormalize( absangles.y ); + m_angRender = absangles; + + // See if we even have a blender for pitch + int upper_body_yaw = GetBasePlayer()->LookupPoseParameter( "aim_yaw" ); + if ( upper_body_yaw < 0 ) + { + return; + } + + // Assume upper and lower bodies are aligned and that we're not turning + float flGoalTorsoYaw = 0.0f; + int turning = TURN_NONE; + float turnrate = 360.0f; + + Vector vel; + + GetOuterAbsVelocity( vel ); + + bool isMoving = ( vel.Length() > 1.0f ) ? true : false; + + if ( !isMoving ) + { + // Just stopped moving, try and clamp feet + if ( m_flLastTurnTime <= 0.0f ) + { + m_flLastTurnTime = gpGlobals->curtime; + m_flLastYaw = GetBasePlayer()->EyeAngles().y; + // Snap feet to be perfectly aligned with torso/eyes + m_flGoalFeetYaw = GetBasePlayer()->EyeAngles().y; + m_flCurrentFeetYaw = m_flGoalFeetYaw; + m_nTurningInPlace = TURN_NONE; + } + + // If rotating in place, update stasis timer + + if ( m_flLastYaw != GetBasePlayer()->EyeAngles().y ) + { + m_flLastTurnTime = gpGlobals->curtime; + m_flLastYaw = GetBasePlayer()->EyeAngles().y; + } + + if ( m_flGoalFeetYaw != m_flCurrentFeetYaw ) + { + m_flLastTurnTime = gpGlobals->curtime; + } + + turning = ConvergeAngles( m_flGoalFeetYaw, turnrate, gpGlobals->frametime, m_flCurrentFeetYaw ); + + QAngle eyeAngles = GetBasePlayer()->EyeAngles(); + QAngle vAngle = GetBasePlayer()->GetLocalAngles(); + + // See how far off current feetyaw is from true yaw + float yawdelta = GetBasePlayer()->EyeAngles().y - m_flCurrentFeetYaw; + yawdelta = AngleNormalize( yawdelta ); + + bool rotated_too_far = false; + + float yawmagnitude = fabs( yawdelta ); + + // If too far, then need to turn in place + if ( yawmagnitude > 45 ) + { + rotated_too_far = true; + } + + // Standing still for a while, rotate feet around to face forward + // Or rotated too far + // FIXME: Play an in place turning animation + if ( rotated_too_far || + ( gpGlobals->curtime > m_flLastTurnTime + mp_facefronttime.GetFloat() ) ) + { + m_flGoalFeetYaw = GetBasePlayer()->EyeAngles().y; + m_flLastTurnTime = gpGlobals->curtime; + + /* float yd = m_flCurrentFeetYaw - m_flGoalFeetYaw; + if ( yd > 0 ) + { + m_nTurningInPlace = TURN_RIGHT; + } + else if ( yd < 0 ) + { + m_nTurningInPlace = TURN_LEFT; + } + else + { + m_nTurningInPlace = TURN_NONE; + } + + turning = ConvergeAngles( m_flGoalFeetYaw, turnrate, gpGlobals->frametime, m_flCurrentFeetYaw ); + yawdelta = GetBasePlayer()->EyeAngles().y - m_flCurrentFeetYaw;*/ + + } + + // Snap upper body into position since the delta is already smoothed for the feet + flGoalTorsoYaw = yawdelta; + m_flCurrentTorsoYaw = flGoalTorsoYaw; + } + else + { + m_flLastTurnTime = 0.0f; + m_nTurningInPlace = TURN_NONE; + m_flCurrentFeetYaw = m_flGoalFeetYaw = GetBasePlayer()->EyeAngles().y; + flGoalTorsoYaw = 0.0f; + m_flCurrentTorsoYaw = GetBasePlayer()->EyeAngles().y - m_flCurrentFeetYaw; + } + + if ( turning == TURN_NONE ) + { + m_nTurningInPlace = turning; + } + + if ( m_nTurningInPlace != TURN_NONE ) + { + // If we're close to finishing the turn, then turn off the turning animation + if ( fabs( m_flCurrentFeetYaw - m_flGoalFeetYaw ) < MIN_TURN_ANGLE_REQUIRING_TURN_ANIMATION ) + { + m_nTurningInPlace = TURN_NONE; + } + } + + // Rotate entire body into position + absangles = GetBasePlayer()->GetAbsAngles(); + absangles.y = m_flCurrentFeetYaw; + m_angRender = absangles; + + GetBasePlayer()->SetPoseParameter( upper_body_yaw, clamp( m_flCurrentTorsoYaw, -60.0f, 60.0f ) ); + + /* + // FIXME: Adrian, what is this? + int body_yaw = GetBasePlayer()->LookupPoseParameter( "body_yaw" ); + + if ( body_yaw >= 0 ) + { + GetBasePlayer()->SetPoseParameter( body_yaw, 30 ); + } + */ + +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CSinglePlayerAnimState::ComputePoseParam_HeadPitch( CStudioHdr *pStudioHdr ) +{ + // Get pitch from v_angle + int iHeadPitch = GetBasePlayer()->LookupPoseParameter("head_pitch"); + + float flPitch = GetBasePlayer()->EyeAngles()[PITCH]; + + if ( flPitch > 180.0f ) + { + flPitch -= 360.0f; + } + flPitch = clamp( flPitch, -90, 90 ); + + QAngle absangles = GetBasePlayer()->GetAbsAngles(); + absangles.x = 0.0f; + m_angRender = absangles; + + GetBasePlayer()->SetPoseParameter( pStudioHdr, iHeadPitch, flPitch ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : activity - +// Output : Activity +//----------------------------------------------------------------------------- +Activity CSinglePlayerAnimState::BodyYawTranslateActivity( Activity activity ) +{ + // Not even standing still, sigh + if ( activity != ACT_IDLE ) + return activity; + + // Not turning + switch ( m_nTurningInPlace ) + { + default: + case TURN_NONE: + return activity; + /* + case TURN_RIGHT: + return ACT_TURNRIGHT45; + case TURN_LEFT: + return ACT_TURNLEFT45; + */ + case TURN_RIGHT: + case TURN_LEFT: + return mp_ik.GetBool() ? ACT_TURN : activity; + } + + Assert( 0 ); + return activity; +} + +const QAngle& CSinglePlayerAnimState::GetRenderAngles() +{ + return m_angRender; +} + +void CSinglePlayerAnimState::GetOuterAbsVelocity( Vector& vel ) +{ +#if defined( CLIENT_DLL ) + GetBasePlayer()->EstimateAbsVelocity( vel ); +#else + vel = GetBasePlayer()->GetAbsVelocity(); +#endif +} diff --git a/sp/src/game/shared/mapbase/singleplayer_animstate.h b/sp/src/game/shared/mapbase/singleplayer_animstate.h new file mode 100644 index 00000000..7609237a --- /dev/null +++ b/sp/src/game/shared/mapbase/singleplayer_animstate.h @@ -0,0 +1,88 @@ +//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +// +// Purpose: Single Player animation state 'handler'. This utility is used +// to evaluate the pose parameter value based on the direction +// and speed of the player. +// +//====================================================================================// + +#ifndef SINGLEPLAYER_ANIMSTATE_H +#define SINGLEPLAYER_ANIMSTATE_H +#ifdef _WIN32 +#pragma once +#endif + +#include "cbase.h" + +#ifdef CLIENT_DLL +#include "c_baseplayer.h" +#else +#include "player.h" +#endif + +#ifdef MAPBASE +// Special definition for differentiating between SP and HL2:DM anim states +#define SP_ANIM_STATE 1 +#endif + +class CSinglePlayerAnimState +{ +public: + enum + { + TURN_NONE = 0, + TURN_LEFT, + TURN_RIGHT + }; + + CSinglePlayerAnimState( CBasePlayer *pPlayer ); + + void Init( CBasePlayer *pPlayer ); + + Activity BodyYawTranslateActivity( Activity activity ); + + void Update(); + + const QAngle& GetRenderAngles(); + + void GetPoseParameters( CStudioHdr *pStudioHdr, float poseParameter[MAXSTUDIOPOSEPARAM] ); + + CBasePlayer *GetBasePlayer(); + + void Release(); + +private: + void GetOuterAbsVelocity( Vector& vel ); + + int ConvergeAngles( float goal,float maxrate, float dt, float& current ); + + void EstimateYaw( void ); + void ComputePoseParam_BodyYaw( void ); + void ComputePoseParam_BodyPitch( CStudioHdr *pStudioHdr ); + void ComputePoseParam_BodyLookYaw( void ); + void ComputePoseParam_HeadPitch( CStudioHdr *pStudioHdr ); + void ComputePlaybackRate(); + + CBasePlayer *m_pPlayer; + + float m_flGaitYaw; + float m_flStoredCycle; + + float m_flGoalFeetYaw; + float m_flCurrentFeetYaw; + + float m_flCurrentTorsoYaw; + + float m_flLastYaw; + float m_flLastTurnTime; + + int m_nTurningInPlace; + + QAngle m_angRender; + + float m_flTurnCorrectionTime; +}; + +CSinglePlayerAnimState *CreatePlayerAnimationState( CBasePlayer *pPlayer ); + +#endif // SINGLEPLAYER_ANIMSTATE_H From 2d5e6f4adb143326b8414821970c4541bf15ec5e Mon Sep 17 00:00:00 2001 From: Blixibon Date: Mon, 15 Nov 2021 01:00:28 -0600 Subject: [PATCH 250/378] Ported the singleplayer anim state to CBasePlayerAnimState and fixed it up to use 9-way blends --- sp/src/game/server/hl2/hl2_player.cpp | 205 +---- sp/src/game/server/hl2/hl2_player.h | 3 +- sp/src/game/shared/base_playeranimstate.cpp | 19 + .../shared/mapbase/singleplayer_animstate.cpp | 713 +++++++++++------- .../shared/mapbase/singleplayer_animstate.h | 98 ++- 5 files changed, 520 insertions(+), 518 deletions(-) diff --git a/sp/src/game/server/hl2/hl2_player.cpp b/sp/src/game/server/hl2/hl2_player.cpp index e3dc3f03..02e1d9e0 100644 --- a/sp/src/game/server/hl2/hl2_player.cpp +++ b/sp/src/game/server/hl2/hl2_player.cpp @@ -118,6 +118,11 @@ ConVar sv_stickysprint("sv_stickysprint", "0", FCVAR_ARCHIVE | FCVAR_ARCHIVE_XBO #ifdef MAPBASE ConVar player_autoswitch_enabled( "player_autoswitch_enabled", "1", FCVAR_NONE, "This convar was added by Mapbase to toggle whether players automatically switch to their ''best'' weapon upon picking up ammo for it after it was dry." ); + +#ifdef SP_ANIM_STATE +ConVar hl2_use_sp_animstate( "hl2_use_sp_animstate", "1", FCVAR_NONE, "Allows SP HL2 players to use HL2:DM animations (for custom player models)" ); +#endif + #endif #define FLASH_DRAIN_TIME 1.1111 // 100 units / 90 secs @@ -1152,13 +1157,16 @@ void CHL2_Player::PostThink( void ) } #ifdef SP_ANIM_STATE - m_angEyeAngles = EyeAngles(); + if (hl2_use_sp_animstate.GetBool()) + { + m_angEyeAngles = EyeAngles(); - QAngle angles = GetLocalAngles(); - angles[PITCH] = 0; - SetLocalAngles(angles); + QAngle angles = GetLocalAngles(); + angles[PITCH] = 0; + SetLocalAngles(angles); - m_pPlayerAnimState->Update(); // m_pPlayerAnimState->Update( m_angEyeAngles.y, m_angEyeAngles.x ); + m_pPlayerAnimState->Update( m_angEyeAngles.y, m_angEyeAngles.x ); + } #endif } @@ -1369,199 +1377,20 @@ void CHL2_Player::SpawnedAtPoint( CBaseEntity *pSpawnPoint ) //----------------------------------------------------------------------------- -ConVar hl2_use_hl2dm_anims( "hl2_use_hl2dm_anims", "0", FCVAR_NONE, "Allows SP HL2 players to use HL2:DM animations (for custom player models)" ); - -void CHL2_Player::ResetAnimation( void ) -{ - if (!hl2_use_hl2dm_anims.GetBool()) - return; - - if (IsAlive()) - { - SetSequence( -1 ); - SetActivity( ACT_INVALID ); - - if (!GetAbsVelocity().x && !GetAbsVelocity().y) - SetAnimation( PLAYER_IDLE ); - else if ((GetAbsVelocity().x || GetAbsVelocity().y) && (GetFlags() & FL_ONGROUND)) - SetAnimation( PLAYER_WALK ); - else if (GetWaterLevel() > 1) - SetAnimation( PLAYER_WALK ); - } -} - +#ifdef SP_ANIM_STATE // Set the activity based on an event or current state void CHL2_Player::SetAnimation( PLAYER_ANIM playerAnim ) { - if (!hl2_use_hl2dm_anims.GetBool()) + if (!hl2_use_sp_animstate.GetBool()) { BaseClass::SetAnimation( playerAnim ); return; } - int animDesired; - - float speed; - - speed = GetAbsVelocity().Length2D(); - - - // bool bRunning = true; - - //Revisit! -/* if ( ( m_nButtons & ( IN_FORWARD | IN_BACK | IN_MOVELEFT | IN_MOVERIGHT ) ) ) - { - if ( speed > 1.0f && speed < hl2_normspeed.GetFloat() - 20.0f ) - { - bRunning = false; - } - }*/ - - if ( GetFlags() & ( FL_FROZEN | FL_ATCONTROLS ) ) - { - speed = 0; - playerAnim = PLAYER_IDLE; - } - - Activity idealActivity = ACT_HL2MP_RUN; - - // This could stand to be redone. Why is playerAnim abstracted from activity? (sjb) - if ( playerAnim == PLAYER_JUMP ) - { - idealActivity = ACT_HL2MP_JUMP; - } - else if ( playerAnim == PLAYER_DIE ) - { - if ( m_lifeState == LIFE_ALIVE ) - { - return; - } - } - else if ( playerAnim == PLAYER_ATTACK1 ) - { - if ( GetActivity( ) == ACT_HOVER || - GetActivity( ) == ACT_SWIM || - GetActivity( ) == ACT_HOP || - GetActivity( ) == ACT_LEAP || - GetActivity( ) == ACT_DIESIMPLE ) - { - idealActivity = GetActivity( ); - } - else - { - idealActivity = ACT_HL2MP_GESTURE_RANGE_ATTACK; - } - } - else if ( playerAnim == PLAYER_RELOAD ) - { - idealActivity = ACT_HL2MP_GESTURE_RELOAD; - } - else if ( playerAnim == PLAYER_IDLE || playerAnim == PLAYER_WALK ) - { - if ( !( GetFlags() & FL_ONGROUND ) && GetActivity( ) == ACT_HL2MP_JUMP ) // Still jumping - { - idealActivity = GetActivity( ); - } - /* - else if ( GetWaterLevel() > 1 ) - { - if ( speed == 0 ) - idealActivity = ACT_HOVER; - else - idealActivity = ACT_SWIM; - } - */ - else - { - if ( GetFlags() & FL_DUCKING ) - { - if ( speed > 0 ) - { - idealActivity = ACT_HL2MP_WALK_CROUCH; - } - else - { - idealActivity = ACT_HL2MP_IDLE_CROUCH; - } - } - else - { - if ( speed > 0 ) - { - /* - if ( bRunning == false ) - { - idealActivity = ACT_WALK; - } - else - */ - { - idealActivity = ACT_HL2MP_RUN; - } - } - else - { - idealActivity = ACT_HL2MP_IDLE; - } - } - } - } - - if ( IsInAVehicle() ) - { - idealActivity = ACT_COVER_LOW; - } - - if ( idealActivity == ACT_HL2MP_GESTURE_RANGE_ATTACK ) - { - RestartGesture( Weapon_TranslateActivity( idealActivity ) ); - - // FIXME: this seems a bit wacked - Weapon_SetActivity( Weapon_TranslateActivity( ACT_RANGE_ATTACK1 ), 0 ); - - return; - } - else if ( idealActivity == ACT_HL2MP_GESTURE_RELOAD ) - { - RestartGesture( Weapon_TranslateActivity( idealActivity ) ); - return; - } - else - { - SetActivity( idealActivity ); - - animDesired = SelectWeightedSequence( Weapon_TranslateActivity ( idealActivity ) ); - - if (animDesired == -1) - { - animDesired = SelectWeightedSequence( idealActivity ); - - if ( animDesired == -1 ) - { - animDesired = 0; - } - } - - // Already using the desired animation? - if ( GetSequence() == animDesired ) - return; - - m_flPlaybackRate = 1.0; - ResetSequence( animDesired ); - SetCycle( 0 ); - return; - } - - // Already using the desired animation? - if ( GetSequence() == animDesired ) - return; - - //Msg( "Set animation to %d\n", animDesired ); - // Reset to first frame of desired animation - ResetSequence( animDesired ); - SetCycle( 0 ); + m_pPlayerAnimState->SetPlayerAnimation( playerAnim ); } #endif +#endif //----------------------------------------------------------------------------- // Purpose: Sets HL2 specific defaults. diff --git a/sp/src/game/server/hl2/hl2_player.h b/sp/src/game/server/hl2/hl2_player.h index a4886730..b493f78a 100644 --- a/sp/src/game/server/hl2/hl2_player.h +++ b/sp/src/game/server/hl2/hl2_player.h @@ -132,8 +132,9 @@ public: // For the logic_playerproxy output void SpawnedAtPoint( CBaseEntity *pSpawnPoint ); - void ResetAnimation( void ); +#ifdef SP_ANIM_STATE void SetAnimation( PLAYER_ANIM playerAnim ); +#endif virtual const char *GetOverrideStepSound( const char *pszBaseStepSoundName ); #endif diff --git a/sp/src/game/shared/base_playeranimstate.cpp b/sp/src/game/shared/base_playeranimstate.cpp index d90655ac..82cb75aa 100644 --- a/sp/src/game/shared/base_playeranimstate.cpp +++ b/sp/src/game/shared/base_playeranimstate.cpp @@ -539,7 +539,26 @@ bool CBasePlayerAnimState::CanThePlayerMove() void CBasePlayerAnimState::ComputePlaybackRate() { VPROF( "CBasePlayerAnimState::ComputePlaybackRate" ); +#ifdef MAPBASE + if ( m_AnimConfig.m_LegAnimType == LEGANIM_9WAY ) + { + // If the movement would be greater than the pose range, set playback rate anyway + if ( abs(m_vLastMovePose.x) > 1.0f || abs(m_vLastMovePose.y) > 1.0f ) + { + bool bIsMoving; + float flRate = CalcMovementPlaybackRate( &bIsMoving ); + if ( bIsMoving ) + GetOuter()->SetPlaybackRate( flRate ); + else + GetOuter()->SetPlaybackRate( 1 ); + } + else + GetOuter()->SetPlaybackRate( 1 ); + } + else // Allow LEGANIM_8WAY to change playback rate +#else if ( m_AnimConfig.m_LegAnimType != LEGANIM_9WAY && m_AnimConfig.m_LegAnimType != LEGANIM_8WAY ) +#endif { // When using a 9-way blend, playback rate is always 1 and we just scale the pose params // to speed up or slow down the animation. diff --git a/sp/src/game/shared/mapbase/singleplayer_animstate.cpp b/sp/src/game/shared/mapbase/singleplayer_animstate.cpp index 3936040f..8f184c7a 100644 --- a/sp/src/game/shared/mapbase/singleplayer_animstate.cpp +++ b/sp/src/game/shared/mapbase/singleplayer_animstate.cpp @@ -1,10 +1,18 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +//========= Mapbase - https://github.com/mapbase-source/source-sdk-2013 ============// // // Purpose: Single Player animation state 'handler'. This utility is used // to evaluate the pose parameter value based on the direction // and speed of the player. +// +// ------------------------------------------------------------------------------ // -//====================================================================================// +// This was originally based on the following VDC article: +// https://developer.valvesoftware.com/wiki/Fixing_the_player_animation_state_(Single_Player) +// +// It has been modified by Blixibon to derive from CBasePlayerAnimState instead and support 9-way blends. +// Much of the work done to make this derive from CBasePlayerAnimState utilized code from the Alien Swarm SDK. +// +//=============================================================================// #include "cbase.h" #include "singleplayer_animstate.h" @@ -18,14 +26,29 @@ extern ConVar mp_facefronttime, mp_feetyawrate, mp_ik; +ConVar sv_playeranimstate_animtype( "sv_playeranimstate_animtype", "0", FCVAR_NONE, "The leg animation type used by the singleplayer animation state. 9way = 0, 8way = 1, GoldSrc = 2" ); +ConVar sv_playeranimstate_bodyyaw( "sv_playeranimstate_bodyyaw", "45.0", FCVAR_NONE, "The maximum body yaw used by the singleplayer animation state." ); +ConVar sv_playeranimstate_use_aim_sequences( "sv_playeranimstate_use_aim_sequences", "1", FCVAR_NONE, "Allows the singleplayer animation state to use aim sequences." ); + #define MIN_TURN_ANGLE_REQUIRING_TURN_ANIMATION 15.0f +#define FIRESEQUENCE_LAYER (AIMSEQUENCE_LAYER+NUM_AIMSEQUENCE_LAYERS) +#define RELOADSEQUENCE_LAYER (FIRESEQUENCE_LAYER + 1) +#define NUM_LAYERS_WANTED (RELOADSEQUENCE_LAYER + 1) + CSinglePlayerAnimState *CreatePlayerAnimationState( CBasePlayer *pPlayer ) { MDLCACHE_CRITICAL_SECTION(); CSinglePlayerAnimState *pState = new CSinglePlayerAnimState( pPlayer ); - pState->Init(pPlayer); + + // Setup the movement data. + CModAnimConfig movementData; + movementData.m_LegAnimType = (LegAnimType_t)sv_playeranimstate_animtype.GetInt(); + movementData.m_flMaxBodyYawDegrees = sv_playeranimstate_bodyyaw.GetFloat(); + movementData.m_bUseAimSequences = sv_playeranimstate_use_aim_sequences.GetBool(); + + pState->Init( pPlayer, movementData ); return pState; } @@ -45,128 +68,368 @@ extern ConVar mp_ik; CSinglePlayerAnimState::CSinglePlayerAnimState( CBasePlayer *pPlayer ): m_pPlayer( pPlayer ) { - m_flGaitYaw = 0.0f; - m_flGoalFeetYaw = 0.0f; - m_flCurrentFeetYaw = 0.0f; - m_flCurrentTorsoYaw = 0.0f; - m_flLastYaw = 0.0f; - m_flLastTurnTime = 0.0f; - m_flTurnCorrectionTime = 0.0f; - - m_pPlayer = NULL; }; -void CSinglePlayerAnimState::Init( CBasePlayer *pPlayer ) -{ - m_pPlayer = pPlayer; -} - //----------------------------------------------------------------------------- -// Purpose: +// Purpose: //----------------------------------------------------------------------------- -void CSinglePlayerAnimState::Update() +Activity CSinglePlayerAnimState::CalcMainActivity() { - m_angRender = GetBasePlayer()->GetLocalAngles(); +#ifdef CLIENT_DLL + return ACT_IDLE; +#else + float speed = GetOuter()->GetAbsVelocity().Length2D(); - ComputePoseParam_BodyYaw(); - ComputePoseParam_BodyPitch(GetBasePlayer()->GetModelPtr()); - ComputePoseParam_BodyLookYaw(); - ComputePoseParam_HeadPitch(GetBasePlayer()->GetModelPtr()); - - ComputePlaybackRate(); -} - -void CSinglePlayerAnimState::Release() -{ - delete this; -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CSinglePlayerAnimState::ComputePlaybackRate() -{ - // Determine ideal playback rate - Vector vel; - GetOuterAbsVelocity( vel ); - - float speed = vel.Length2D(); - - bool isMoving = ( speed > 0.5f ) ? true : false; - - float maxspeed = GetBasePlayer()->GetSequenceGroundSpeed( GetBasePlayer()->GetSequence() ); - - if ( isMoving && ( maxspeed > 0.0f ) ) - { - float flFactor = 1.0f; - - // Note this gets set back to 1.0 if sequence changes due to ResetSequenceInfo below - GetBasePlayer()->SetPlaybackRate( ( speed * flFactor ) / maxspeed ); - - // BUG BUG: - // This stuff really should be m_flPlaybackRate = speed / m_flGroundSpeed - } + if ( HandleJumping() ) + { + return ACT_HL2MP_JUMP; + } else { - GetBasePlayer()->SetPlaybackRate( 1.0f ); - } -} + Activity idealActivity = ACT_HL2MP_IDLE; -//----------------------------------------------------------------------------- -// Purpose: -// Output : CBasePlayer -//----------------------------------------------------------------------------- -CBasePlayer *CSinglePlayerAnimState::GetBasePlayer() -{ - return m_pPlayer; -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : dt - -//----------------------------------------------------------------------------- -void CSinglePlayerAnimState::EstimateYaw( void ) -{ - float dt = gpGlobals->frametime; - - if ( !dt ) - { - return; - } - - Vector est_velocity; - QAngle angles; - - GetOuterAbsVelocity( est_velocity ); - - angles = GetBasePlayer()->GetLocalAngles(); - - if ( est_velocity[1] == 0 && est_velocity[0] == 0 ) - { - float flYawDiff = angles[YAW] - m_flGaitYaw; - flYawDiff = flYawDiff - (int)(flYawDiff / 360) * 360; - if (flYawDiff > 180) - flYawDiff -= 360; - if (flYawDiff < -180) - flYawDiff += 360; - - if (dt < 0.25) - flYawDiff *= dt * 4; + if ( GetOuter()->GetFlags() & ( FL_FROZEN | FL_ATCONTROLS ) ) + { + speed = 0; + } else - flYawDiff *= dt; + { + if ( GetOuter()->GetFlags() & FL_DUCKING ) + { + if ( speed > 0 ) + { + idealActivity = ACT_HL2MP_WALK_CROUCH; + } + else + { + idealActivity = ACT_HL2MP_IDLE_CROUCH; + } + } + else + { + if ( speed > 0 ) + { + /* + if ( bRunning == false ) + { + idealActivity = ACT_WALK; + } + else + */ + { + idealActivity = ACT_HL2MP_RUN; + } + } + else + { + idealActivity = ACT_HL2MP_IDLE; + } + } + } - m_flGaitYaw += flYawDiff; - m_flGaitYaw = m_flGaitYaw - (int)(m_flGaitYaw / 360) * 360; + return idealActivity; } - else + + //return m_pPlayer->GetActivity(); +#endif +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CSinglePlayerAnimState::SetPlayerAnimation( PLAYER_ANIM playerAnim ) +{ + if ( playerAnim == PLAYER_ATTACK1 ) { - m_flGaitYaw = (atan2(est_velocity[1], est_velocity[0]) * 180 / M_PI); - - if (m_flGaitYaw > 180) - m_flGaitYaw = 180; - else if (m_flGaitYaw < -180) - m_flGaitYaw = -180; + m_iFireSequence = SelectWeightedSequence( TranslateActivity( ACT_HL2MP_GESTURE_RANGE_ATTACK ) ); + m_bFiring = m_iFireSequence != -1; + m_flFireCycle = 0; } + else if ( playerAnim == PLAYER_JUMP ) + { + // Play the jump animation. + if (!m_bJumping) + { + m_bJumping = true; + m_bFirstJumpFrame = true; + m_flJumpStartTime = gpGlobals->curtime; + } + } + else if ( playerAnim == PLAYER_RELOAD ) + { + m_iReloadSequence = SelectWeightedSequence( TranslateActivity( ACT_HL2MP_GESTURE_RELOAD ) ); + if (m_iReloadSequence != -1) + { + // clear other events that might be playing in our layer + m_bWeaponSwitching = false; + m_fReloadPlaybackRate = 1.0f; + m_bReloading = true; + m_flReloadCycle = 0; + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +Activity CSinglePlayerAnimState::TranslateActivity( Activity actDesired ) +{ +#ifdef CLIENT_DLL + return actDesired; +#else + return m_pPlayer->Weapon_TranslateActivity( actDesired ); +#endif +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CSinglePlayerAnimState::HandleJumping() +{ + if ( m_bJumping ) + { + if ( m_bFirstJumpFrame ) + { + m_bFirstJumpFrame = false; + RestartMainSequence(); // Reset the animation. + } + + // Don't check if he's on the ground for a sec.. sometimes the client still has the + // on-ground flag set right when the message comes in. + if (m_flJumpStartTime > gpGlobals->curtime) + m_flJumpStartTime = gpGlobals->curtime; + if ( gpGlobals->curtime - m_flJumpStartTime > 0.2f) + { + if ( m_pOuter->GetFlags() & FL_ONGROUND || GetOuter()->GetGroundEntity() != NULL) + { + m_bJumping = false; + RestartMainSequence(); // Reset the animation. + } + } + } + + // Are we still jumping? If so, keep playing the jump animation. + return m_bJumping; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CSinglePlayerAnimState::ComputeSequences( CStudioHdr *pStudioHdr ) +{ + CBasePlayerAnimState::ComputeSequences(pStudioHdr); + + ComputeFireSequence(); + ComputeMiscSequence(); + ComputeReloadSequence(); + ComputeWeaponSwitchSequence(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CSinglePlayerAnimState::ClearAnimationState() +{ + m_bJumping = false; + m_bFiring = false; + m_bReloading = false; + m_bWeaponSwitching = false; + m_bPlayingMisc = false; + CBasePlayerAnimState::ClearAnimationState(); +} + +void CSinglePlayerAnimState::ClearAnimationLayers() +{ + VPROF( "CBasePlayerAnimState::ClearAnimationLayers" ); + if ( !m_pOuter ) + return; + + m_pOuter->SetNumAnimOverlays( NUM_LAYERS_WANTED ); + for ( int i=0; i < m_pOuter->GetNumAnimOverlays(); i++ ) + { + m_pOuter->GetAnimOverlay( i )->SetOrder( CBaseAnimatingOverlay::MAX_OVERLAYS ); +#ifndef CLIENT_DLL + m_pOuter->GetAnimOverlay( i )->m_fFlags = 0; +#endif + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int CSinglePlayerAnimState::CalcAimLayerSequence( float *flCycle, float *flAimSequenceWeight, bool bForceIdle ) +{ + // TODO? + return m_pOuter->LookupSequence( "soldier_Aim_9_directions" ); +} + +void CSinglePlayerAnimState::UpdateLayerSequenceGeneric( int iLayer, bool &bEnabled, + float &flCurCycle, int &iSequence, bool bWaitAtEnd, + float fBlendIn, float fBlendOut, bool bMoveBlend, float fPlaybackRate, bool bUpdateCycle /* = true */ ) +{ + if ( !bEnabled ) + return; + + CStudioHdr *hdr = GetOuter()->GetModelPtr(); + if ( !hdr ) + return; + + if ( iSequence < 0 || iSequence >= hdr->GetNumSeq() ) + return; + + // Increment the fire sequence's cycle. + if ( bUpdateCycle ) + { + flCurCycle += m_pOuter->GetSequenceCycleRate( hdr, iSequence ) * gpGlobals->frametime * fPlaybackRate; + } + + // temp: if the sequence is looping, don't override it - we need better handling of looping anims, + // especially in misc layer from melee (right now the same melee attack is looped manually in asw_melee_system.cpp) + bool bLooping = m_pOuter->IsSequenceLooping( hdr, iSequence ); + + if ( flCurCycle > 1 && !bLooping ) + { + if ( iLayer == RELOADSEQUENCE_LAYER ) + { + m_bReloading = false; + } + if ( bWaitAtEnd ) + { + flCurCycle = 1; + } + else + { + // Not firing anymore. + bEnabled = false; + iSequence = 0; + return; + } + } + + // if this animation should blend out as we move, then check for dropping it completely since we're moving too fast + float speed = 0; + if (bMoveBlend) + { + Vector vel; + GetOuterAbsVelocity( vel ); + + float speed = vel.Length2D(); + + if (speed > 50) + { + bEnabled = false; + iSequence = 0; + return; + } + } + + // Now dump the state into its animation layer. + CAnimationLayer *pLayer = m_pOuter->GetAnimOverlay( iLayer ); + + pLayer->m_flCycle = flCurCycle; + pLayer->m_nSequence = iSequence; + + pLayer->m_flPlaybackRate = fPlaybackRate; + pLayer->m_flWeight = 1.0f; + + if (iLayer == RELOADSEQUENCE_LAYER) + { + // blend this layer in and out for smooth reloading + if (flCurCycle < fBlendIn && fBlendIn>0) + { + pLayer->m_flWeight = ( clamp(flCurCycle / fBlendIn, + 0.001f, 1.0f) ); + } + else if (flCurCycle >= (1.0f - fBlendOut) && fBlendOut>0) + { + pLayer->m_flWeight = ( clamp((1.0f - flCurCycle) / fBlendOut, + 0.001f, 1.0f) ); + } + else + { + pLayer->m_flWeight = 1.0f; + } + } + else + { + pLayer->m_flWeight = 1.0f; + } + if (bMoveBlend) + { + // blend the animation out as we move faster + if (speed <= 50) + pLayer->m_flWeight = ( pLayer->m_flWeight * (50.0f - speed) / 50.0f ); + } + +#ifndef CLIENT_DLL + pLayer->m_fFlags |= ANIM_LAYER_ACTIVE; +#endif + pLayer->SetOrder( iLayer ); +} + +void CSinglePlayerAnimState::ComputeFireSequence() +{ + UpdateLayerSequenceGeneric( FIRESEQUENCE_LAYER, m_bFiring, m_flFireCycle, m_iFireSequence, false ); +} + +void CSinglePlayerAnimState::ComputeReloadSequence() +{ + UpdateLayerSequenceGeneric( RELOADSEQUENCE_LAYER, m_bReloading, m_flReloadCycle, m_iReloadSequence, false, m_flReloadBlendIn, m_flReloadBlendOut, false, m_fReloadPlaybackRate ); +} + +void CSinglePlayerAnimState::ComputeWeaponSwitchSequence() +{ + UpdateLayerSequenceGeneric( RELOADSEQUENCE_LAYER, m_bWeaponSwitching, m_flWeaponSwitchCycle, m_iWeaponSwitchSequence, false, 0, 0.5f ); +} + +// does misc gestures if we're not firing +void CSinglePlayerAnimState::ComputeMiscSequence() +{ + bool bHoldAtEnd = false; + + UpdateLayerSequenceGeneric( RELOADSEQUENCE_LAYER, m_bPlayingMisc, m_flMiscCycle, m_iMiscSequence, bHoldAtEnd, m_flMiscBlendIn, m_flMiscBlendOut, m_bMiscOnlyWhenStill, m_fMiscPlaybackRate ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : - +// Output : float +//----------------------------------------------------------------------------- +float CSinglePlayerAnimState::GetCurrentMaxGroundSpeed() +{ + CStudioHdr *pStudioHdr = GetOuter()->GetModelPtr(); + + if ( pStudioHdr == NULL ) + return 1.0f; + + int iMoveX = GetOuter()->LookupPoseParameter( "move_x" ); + int iMoveY = GetOuter()->LookupPoseParameter( "move_y" ); + + float prevX = GetOuter()->GetPoseParameter( iMoveX ); + float prevY = GetOuter()->GetPoseParameter( iMoveY ); + + float d = MAX( fabs( prevX ), fabs( prevY ) ); + float newX, newY; + if ( d == 0.0 ) + { + newX = 1.0; + newY = 0.0; + } + else + { + newX = prevX / d; + newY = prevY / d; + } + + GetOuter()->SetPoseParameter( pStudioHdr, iMoveX, newX ); + GetOuter()->SetPoseParameter( pStudioHdr, iMoveY, newY ); + + float speed = GetOuter()->GetSequenceGroundSpeed(GetOuter()->GetSequence() ); + + GetOuter()->SetPoseParameter( pStudioHdr, iMoveX, prevX ); + GetOuter()->SetPoseParameter( pStudioHdr, iMoveY, prevY ); + + return speed; } //----------------------------------------------------------------------------- @@ -175,129 +438,22 @@ void CSinglePlayerAnimState::EstimateYaw( void ) //----------------------------------------------------------------------------- void CSinglePlayerAnimState::ComputePoseParam_BodyYaw( void ) { - int iYaw = GetBasePlayer()->LookupPoseParameter( "move_yaw" ); - if ( iYaw < 0 ) - return; + CBasePlayerAnimState::ComputePoseParam_BodyYaw(); - // view direction relative to movement - float flYaw; - - EstimateYaw(); - - QAngle angles = GetBasePlayer()->GetLocalAngles(); - float ang = angles[ YAW ]; - if ( ang > 180.0f ) - { - ang -= 360.0f; - } - else if ( ang < -180.0f ) - { - ang += 360.0f; - } - - // calc side to side turning - flYaw = ang - m_flGaitYaw; - // Invert for mapping into 8way blend - flYaw = -flYaw; - flYaw = flYaw - (int)(flYaw / 360) * 360; - - if (flYaw < -180) - { - flYaw = flYaw + 360; - } - else if (flYaw > 180) - { - flYaw = flYaw - 360; - } - - GetBasePlayer()->SetPoseParameter( iYaw, flYaw ); - -#ifndef CLIENT_DLL - //Adrian: Make the model's angle match the legs so the hitboxes match on both sides. - GetBasePlayer()->SetLocalAngles( QAngle( GetBasePlayer()->EyeAngles().x, m_flCurrentFeetYaw, 0 ) ); -#endif + //ComputePoseParam_BodyLookYaw(); } //----------------------------------------------------------------------------- -// Purpose: +// Purpose: //----------------------------------------------------------------------------- -void CSinglePlayerAnimState::ComputePoseParam_BodyPitch( CStudioHdr *pStudioHdr ) -{ - // Get pitch from v_angle - float flPitch = GetBasePlayer()->GetLocalAngles()[ PITCH ]; - - if ( flPitch > 180.0f ) - { - flPitch -= 360.0f; - } - flPitch = clamp( flPitch, -90, 90 ); - - QAngle absangles = GetBasePlayer()->GetAbsAngles(); - absangles.x = 0.0f; - m_angRender = absangles; - - // See if we have a blender for pitch - GetBasePlayer()->SetPoseParameter( pStudioHdr, "aim_pitch", flPitch ); -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : goal - -// maxrate - -// dt - -// current - -// Output : int -//----------------------------------------------------------------------------- -int CSinglePlayerAnimState::ConvergeAngles( float goal,float maxrate, float dt, float& current ) -{ - int direction = TURN_NONE; - - float anglediff = goal - current; - float anglediffabs = fabs( anglediff ); - - anglediff = AngleNormalize( anglediff ); - - float scale = 1.0f; - if ( anglediffabs <= FADE_TURN_DEGREES ) - { - scale = anglediffabs / FADE_TURN_DEGREES; - // Always do at least a bit of the turn ( 1% ) - scale = clamp( scale, 0.01f, 1.0f ); - } - - float maxmove = maxrate * dt * scale; - - if ( fabs( anglediff ) < maxmove ) - { - current = goal; - } - else - { - if ( anglediff > 0 ) - { - current += maxmove; - direction = TURN_LEFT; - } - else - { - current -= maxmove; - direction = TURN_RIGHT; - } - } - - current = AngleNormalize( current ); - - return direction; -} - void CSinglePlayerAnimState::ComputePoseParam_BodyLookYaw( void ) { - QAngle absangles = GetBasePlayer()->GetAbsAngles(); + QAngle absangles = GetOuter()->GetAbsAngles(); absangles.y = AngleNormalize( absangles.y ); m_angRender = absangles; // See if we even have a blender for pitch - int upper_body_yaw = GetBasePlayer()->LookupPoseParameter( "aim_yaw" ); + int upper_body_yaw = GetOuter()->LookupPoseParameter( "aim_yaw" ); if ( upper_body_yaw < 0 ) { return; @@ -320,19 +476,19 @@ void CSinglePlayerAnimState::ComputePoseParam_BodyLookYaw( void ) if ( m_flLastTurnTime <= 0.0f ) { m_flLastTurnTime = gpGlobals->curtime; - m_flLastYaw = GetBasePlayer()->EyeAngles().y; + m_flLastYaw = GetOuter()->EyeAngles().y; // Snap feet to be perfectly aligned with torso/eyes - m_flGoalFeetYaw = GetBasePlayer()->EyeAngles().y; + m_flGoalFeetYaw = GetOuter()->EyeAngles().y; m_flCurrentFeetYaw = m_flGoalFeetYaw; m_nTurningInPlace = TURN_NONE; } // If rotating in place, update stasis timer - if ( m_flLastYaw != GetBasePlayer()->EyeAngles().y ) + if ( m_flLastYaw != GetOuter()->EyeAngles().y ) { m_flLastTurnTime = gpGlobals->curtime; - m_flLastYaw = GetBasePlayer()->EyeAngles().y; + m_flLastYaw = GetOuter()->EyeAngles().y; } if ( m_flGoalFeetYaw != m_flCurrentFeetYaw ) @@ -340,13 +496,13 @@ void CSinglePlayerAnimState::ComputePoseParam_BodyLookYaw( void ) m_flLastTurnTime = gpGlobals->curtime; } - turning = ConvergeAngles( m_flGoalFeetYaw, turnrate, gpGlobals->frametime, m_flCurrentFeetYaw ); + turning = ConvergeAngles( m_flGoalFeetYaw, turnrate, m_AnimConfig.m_flMaxBodyYawDegrees, gpGlobals->frametime, m_flCurrentFeetYaw ); - QAngle eyeAngles = GetBasePlayer()->EyeAngles(); - QAngle vAngle = GetBasePlayer()->GetLocalAngles(); + QAngle eyeAngles = GetOuter()->EyeAngles(); + QAngle vAngle = GetOuter()->GetLocalAngles(); // See how far off current feetyaw is from true yaw - float yawdelta = GetBasePlayer()->EyeAngles().y - m_flCurrentFeetYaw; + float yawdelta = GetOuter()->EyeAngles().y - m_flCurrentFeetYaw; yawdelta = AngleNormalize( yawdelta ); bool rotated_too_far = false; @@ -365,7 +521,7 @@ void CSinglePlayerAnimState::ComputePoseParam_BodyLookYaw( void ) if ( rotated_too_far || ( gpGlobals->curtime > m_flLastTurnTime + mp_facefronttime.GetFloat() ) ) { - m_flGoalFeetYaw = GetBasePlayer()->EyeAngles().y; + m_flGoalFeetYaw = GetOuter()->EyeAngles().y; m_flLastTurnTime = gpGlobals->curtime; /* float yd = m_flCurrentFeetYaw - m_flGoalFeetYaw; @@ -383,7 +539,7 @@ void CSinglePlayerAnimState::ComputePoseParam_BodyLookYaw( void ) } turning = ConvergeAngles( m_flGoalFeetYaw, turnrate, gpGlobals->frametime, m_flCurrentFeetYaw ); - yawdelta = GetBasePlayer()->EyeAngles().y - m_flCurrentFeetYaw;*/ + yawdelta = GetOuter()->EyeAngles().y - m_flCurrentFeetYaw;*/ } @@ -395,9 +551,9 @@ void CSinglePlayerAnimState::ComputePoseParam_BodyLookYaw( void ) { m_flLastTurnTime = 0.0f; m_nTurningInPlace = TURN_NONE; - m_flCurrentFeetYaw = m_flGoalFeetYaw = GetBasePlayer()->EyeAngles().y; + m_flCurrentFeetYaw = m_flGoalFeetYaw = GetOuter()->EyeAngles().y; flGoalTorsoYaw = 0.0f; - m_flCurrentTorsoYaw = GetBasePlayer()->EyeAngles().y - m_flCurrentFeetYaw; + m_flCurrentTorsoYaw = GetOuter()->EyeAngles().y - m_flCurrentFeetYaw; } if ( turning == TURN_NONE ) @@ -415,33 +571,57 @@ void CSinglePlayerAnimState::ComputePoseParam_BodyLookYaw( void ) } // Rotate entire body into position - absangles = GetBasePlayer()->GetAbsAngles(); + absangles = GetOuter()->GetAbsAngles(); absangles.y = m_flCurrentFeetYaw; m_angRender = absangles; - GetBasePlayer()->SetPoseParameter( upper_body_yaw, clamp( m_flCurrentTorsoYaw, -60.0f, 60.0f ) ); + GetOuter()->SetPoseParameter( upper_body_yaw, clamp( m_flCurrentTorsoYaw, -60.0f, 60.0f ) ); /* // FIXME: Adrian, what is this? - int body_yaw = GetBasePlayer()->LookupPoseParameter( "body_yaw" ); + int body_yaw = GetOuter()->LookupPoseParameter( "body_yaw" ); if ( body_yaw >= 0 ) { - GetBasePlayer()->SetPoseParameter( body_yaw, 30 ); + GetOuter()->SetPoseParameter( body_yaw, 30 ); } */ } +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CSinglePlayerAnimState::ComputePoseParam_BodyPitch( CStudioHdr *pStudioHdr ) +{ + // Get pitch from v_angle + float flPitch = m_flEyePitch; + + if ( flPitch > 180.0f ) + { + flPitch -= 360.0f; + } + flPitch = clamp( flPitch, -90, 90 ); + + QAngle absangles = GetOuter()->GetAbsAngles(); + absangles.x = 0.0f; + m_angRender = absangles; + + // See if we have a blender for pitch + GetOuter()->SetPoseParameter( pStudioHdr, "aim_pitch", flPitch ); + + ComputePoseParam_HeadPitch( pStudioHdr ); +} + //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CSinglePlayerAnimState::ComputePoseParam_HeadPitch( CStudioHdr *pStudioHdr ) { // Get pitch from v_angle - int iHeadPitch = GetBasePlayer()->LookupPoseParameter("head_pitch"); + int iHeadPitch = GetOuter()->LookupPoseParameter("head_pitch"); - float flPitch = GetBasePlayer()->EyeAngles()[PITCH]; + float flPitch = m_flEyePitch; if ( flPitch > 180.0f ) { @@ -449,56 +629,9 @@ void CSinglePlayerAnimState::ComputePoseParam_HeadPitch( CStudioHdr *pStudioHdr } flPitch = clamp( flPitch, -90, 90 ); - QAngle absangles = GetBasePlayer()->GetAbsAngles(); + QAngle absangles = GetOuter()->GetAbsAngles(); absangles.x = 0.0f; m_angRender = absangles; - GetBasePlayer()->SetPoseParameter( pStudioHdr, iHeadPitch, flPitch ); -} - - -//----------------------------------------------------------------------------- -// Purpose: -// Input : activity - -// Output : Activity -//----------------------------------------------------------------------------- -Activity CSinglePlayerAnimState::BodyYawTranslateActivity( Activity activity ) -{ - // Not even standing still, sigh - if ( activity != ACT_IDLE ) - return activity; - - // Not turning - switch ( m_nTurningInPlace ) - { - default: - case TURN_NONE: - return activity; - /* - case TURN_RIGHT: - return ACT_TURNRIGHT45; - case TURN_LEFT: - return ACT_TURNLEFT45; - */ - case TURN_RIGHT: - case TURN_LEFT: - return mp_ik.GetBool() ? ACT_TURN : activity; - } - - Assert( 0 ); - return activity; -} - -const QAngle& CSinglePlayerAnimState::GetRenderAngles() -{ - return m_angRender; -} - -void CSinglePlayerAnimState::GetOuterAbsVelocity( Vector& vel ) -{ -#if defined( CLIENT_DLL ) - GetBasePlayer()->EstimateAbsVelocity( vel ); -#else - vel = GetBasePlayer()->GetAbsVelocity(); -#endif + GetOuter()->SetPoseParameter( pStudioHdr, iHeadPitch, flPitch ); } diff --git a/sp/src/game/shared/mapbase/singleplayer_animstate.h b/sp/src/game/shared/mapbase/singleplayer_animstate.h index 7609237a..460e6e12 100644 --- a/sp/src/game/shared/mapbase/singleplayer_animstate.h +++ b/sp/src/game/shared/mapbase/singleplayer_animstate.h @@ -1,10 +1,18 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +//========= Mapbase - https://github.com/mapbase-source/source-sdk-2013 ============// // // Purpose: Single Player animation state 'handler'. This utility is used // to evaluate the pose parameter value based on the direction // and speed of the player. +// +// ------------------------------------------------------------------------------ // -//====================================================================================// +// This was originally based on the following VDC article: +// https://developer.valvesoftware.com/wiki/Fixing_the_player_animation_state_(Single_Player) +// +// It has been modified by Blixibon to derive from CBasePlayerAnimState instead and support 9-way blends. +// Much of the work done to make this derive from CBasePlayerAnimState utilized code from the Alien Swarm SDK. +// +//=============================================================================// #ifndef SINGLEPLAYER_ANIMSTATE_H #define SINGLEPLAYER_ANIMSTATE_H @@ -13,6 +21,7 @@ #endif #include "cbase.h" +#include "base_playeranimstate.h" #ifdef CLIENT_DLL #include "c_baseplayer.h" @@ -25,62 +34,73 @@ #define SP_ANIM_STATE 1 #endif -class CSinglePlayerAnimState +class CSinglePlayerAnimState : public CBasePlayerAnimState { public: - enum - { - TURN_NONE = 0, - TURN_LEFT, - TURN_RIGHT - }; - CSinglePlayerAnimState( CBasePlayer *pPlayer ); + + Activity CalcMainActivity(); + int CalcAimLayerSequence( float *flCycle, float *flAimSequenceWeight, bool bForceIdle ); + float GetCurrentMaxGroundSpeed(); - void Init( CBasePlayer *pPlayer ); + void SetPlayerAnimation( PLAYER_ANIM playerAnim ); + Activity TranslateActivity( Activity actDesired ); - Activity BodyYawTranslateActivity( Activity activity ); + void ComputeSequences( CStudioHdr *pStudioHdr ); - void Update(); - - const QAngle& GetRenderAngles(); - - void GetPoseParameters( CStudioHdr *pStudioHdr, float poseParameter[MAXSTUDIOPOSEPARAM] ); - - CBasePlayer *GetBasePlayer(); - - void Release(); + void ClearAnimationState(); + void ClearAnimationLayers(); private: - void GetOuterAbsVelocity( Vector& vel ); - int ConvergeAngles( float goal,float maxrate, float dt, float& current ); + bool HandleJumping(); + + void ComputeFireSequence(); + void ComputeReloadSequence(); + void ComputeWeaponSwitchSequence(); + void ComputeMiscSequence(); + + void UpdateLayerSequenceGeneric( int iLayer, bool &bEnabled, float &flCurCycle, + int &iSequence, bool bWaitAtEnd, + float fBlendIn=0.15f, float fBlendOut=0.15f, bool bMoveBlend = false, + float fPlaybackRate=1.0f, bool bUpdateCycle = true ); - void EstimateYaw( void ); void ComputePoseParam_BodyYaw( void ); void ComputePoseParam_BodyPitch( CStudioHdr *pStudioHdr ); void ComputePoseParam_BodyLookYaw( void ); void ComputePoseParam_HeadPitch( CStudioHdr *pStudioHdr ); - void ComputePlaybackRate(); - CBasePlayer *m_pPlayer; + CBasePlayer* m_pPlayer; - float m_flGaitYaw; - float m_flStoredCycle; + // Current state variables. + bool m_bJumping; // Set on a jump event. + float m_flJumpStartTime; + bool m_bFirstJumpFrame; - float m_flGoalFeetYaw; - float m_flCurrentFeetYaw; + // Aim sequence plays reload while this is on. + bool m_bReloading; + float m_flReloadCycle; + int m_iReloadSequence; + float m_flReloadBlendOut, m_flReloadBlendIn; + float m_fReloadPlaybackRate; - float m_flCurrentTorsoYaw; + bool m_bWeaponSwitching; + float m_flWeaponSwitchCycle; + int m_iWeaponSwitchSequence; - float m_flLastYaw; - float m_flLastTurnTime; - - int m_nTurningInPlace; - - QAngle m_angRender; - - float m_flTurnCorrectionTime; + bool m_bPlayingMisc; + float m_flMiscCycle, m_flMiscBlendOut, m_flMiscBlendIn; + int m_iMiscSequence; + bool m_bMiscOnlyWhenStill; + bool m_bMiscNoOverride; + float m_fMiscPlaybackRate; + bool m_bMiscCycleRewound; + float m_flMiscRewindCycle; + // This is set to true if ANY animation is being played in the fire layer. + bool m_bFiring; // If this is on, then it'll continue the fire animation in the fire layer + // until it completes. + int m_iFireSequence; // (For any sequences in the fire layer, including grenade throw). + float m_flFireCycle; }; CSinglePlayerAnimState *CreatePlayerAnimationState( CBasePlayer *pPlayer ); From b9a46bc4e03962c655f143bd7cbec09d6f57322b Mon Sep 17 00:00:00 2001 From: Blixibon Date: Mon, 15 Nov 2021 01:00:56 -0600 Subject: [PATCH 251/378] Added backup activities to players --- sp/src/game/server/basecombatcharacter.cpp | 10 +++--- sp/src/game/server/player.cpp | 38 +++++----------------- 2 files changed, 14 insertions(+), 34 deletions(-) diff --git a/sp/src/game/server/basecombatcharacter.cpp b/sp/src/game/server/basecombatcharacter.cpp index c3927156..c11eb9fa 100644 --- a/sp/src/game/server/basecombatcharacter.cpp +++ b/sp/src/game/server/basecombatcharacter.cpp @@ -2727,8 +2727,7 @@ bool CBaseCombatCharacter::Weapon_CanUse( CBaseCombatWeapon *pWeapon ) #ifdef MAPBASE //----------------------------------------------------------------------------- // Purpose: Uses an activity from a different weapon when the activity we were originally looking for does not exist on this character. -// Created to give NPCs the ability to use weapons they are not otherwise allowed to use. -// Right now, everyone falls back to the SMG act table. +// This gives NPCs and players the ability to use weapons they are otherwise unable to use. //----------------------------------------------------------------------------- Activity CBaseCombatCharacter::Weapon_BackupActivity( Activity activity, bool weaponTranslationWasRequired, CBaseCombatWeapon *pSpecificWeapon ) { @@ -2740,8 +2739,9 @@ Activity CBaseCombatCharacter::Weapon_BackupActivity( Activity activity, bool we if (!pWeapon->SupportsBackupActivity(activity)) return activity; - // Sometimes, the NPC is supposed to use the default activity. Return that if the weapon translation was "not required" and we have an original activity. - if (!weaponTranslationWasRequired && GetModelPtr()->HaveSequenceForActivity(activity)) + // Sometimes, a NPC is supposed to use the default activity. Return that if the weapon translation was "not required" and we have an original activity. + // Don't do this with players. + if (!weaponTranslationWasRequired && GetModelPtr()->HaveSequenceForActivity(activity) && !IsPlayer()) { return activity; } @@ -2754,7 +2754,7 @@ Activity CBaseCombatCharacter::Weapon_BackupActivity( Activity activity, bool we { if ( activity == pTable->baseAct ) { - // Don't pick SMG animations we don't actually have an animation for. + // Don't pick backup activities we don't actually have an animation for. if (GetModelPtr() ? !GetModelPtr()->HaveSequenceForActivity(pTable->weaponAct) : false) { return activity; diff --git a/sp/src/game/server/player.cpp b/sp/src/game/server/player.cpp index 524b1e75..1f52ea4f 100644 --- a/sp/src/game/server/player.cpp +++ b/sp/src/game/server/player.cpp @@ -7817,39 +7817,19 @@ void CBasePlayer::Weapon_Equip( CBaseCombatWeapon *pWeapon ) //----------------------------------------------------------------------------- Activity CBasePlayer::Weapon_TranslateActivity( Activity baseAct, bool *pRequired ) { -#ifdef HL2_DLL - // HAAAAAAAAAAAAAACKS! - if (GetActiveWeapon()) + Activity weaponTranslation = BaseClass::Weapon_TranslateActivity( baseAct, pRequired ); + + if ( GetModelPtr() && !GetModelPtr()->HaveSequenceForActivity(weaponTranslation) ) { - int translated = baseAct; - int iActOffset = (baseAct - ACT_HL2MP_IDLE); + // This is used so players can fall back to backup activities in the same way NPCs in Mapbase can + Activity backupActivity = Weapon_BackupActivity(baseAct, pRequired); + if ( baseAct != backupActivity && GetModelPtr()->HaveSequenceForActivity(backupActivity) ) + return backupActivity; - string_t iszClassname = GetActiveWeapon()->m_iClassname; - if (iszClassname == gm_isz_class_Pistol || iszClassname == gm_isz_class_357) - translated = (ACT_HL2MP_IDLE_PISTOL + iActOffset); - else if (iszClassname == gm_isz_class_SMG1) - translated = (ACT_HL2MP_IDLE_SMG1 + iActOffset); - else if (iszClassname == gm_isz_class_AR2) - translated = (ACT_HL2MP_IDLE_AR2 + iActOffset); - else if (iszClassname == gm_isz_class_Shotgun) - translated = (ACT_HL2MP_IDLE_SHOTGUN + iActOffset); - else if (iszClassname == gm_isz_class_RPG) - translated = (ACT_HL2MP_IDLE_RPG + iActOffset); - else if (iszClassname == gm_isz_class_Grenade) - translated = (ACT_HL2MP_IDLE_GRENADE + iActOffset); - else if (iszClassname == gm_isz_class_Physcannon) - translated = (ACT_HL2MP_IDLE_PHYSGUN + iActOffset); - else if (iszClassname == gm_isz_class_Crossbow) - translated = (ACT_HL2MP_IDLE_CROSSBOW + iActOffset); - else if (iszClassname == gm_isz_class_Crowbar || iszClassname == gm_isz_class_Stunstick) - translated = (ACT_HL2MP_IDLE_MELEE + iActOffset); - - if (translated != baseAct) - return (Activity)translated; + return baseAct; } -#endif - return BaseClass::Weapon_TranslateActivity( baseAct, pRequired ); + return weaponTranslation; } #endif From 5855c634de848303aff68e42eeb066ac77cefce0 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Mon, 15 Nov 2021 01:02:12 -0600 Subject: [PATCH 252/378] Improved implementaton of player model activities on SP HL2 weapons --- sp/src/game/server/ai_activity.cpp | 10 ++++++++++ sp/src/game/server/hl2/weapon_357.cpp | 10 ++++++++++ sp/src/game/server/hl2/weapon_ar2.cpp | 2 +- sp/src/game/server/hl2/weapon_bugbait.cpp | 23 +++++++++++++++++++++++ sp/src/game/server/hl2/weapon_shotgun.cpp | 7 +++++++ sp/src/game/server/hl2/weapon_smg1.cpp | 2 +- sp/src/game/shared/activitylist.cpp | 10 ++++++++++ sp/src/game/shared/ai_activity.h | 14 ++++++++++++++ 8 files changed, 76 insertions(+), 2 deletions(-) diff --git a/sp/src/game/server/ai_activity.cpp b/sp/src/game/server/ai_activity.cpp index 7a64a963..14687118 100644 --- a/sp/src/game/server/ai_activity.cpp +++ b/sp/src/game/server/ai_activity.cpp @@ -2344,6 +2344,16 @@ void CAI_BaseNPC::InitDefaultActivitySR(void) ADD_ACTIVITY_TO_SR( ACT_COVER_WALL_LOW_R_PISTOL ); ADD_ACTIVITY_TO_SR( ACT_COVER_WALL_LOW_L_PISTOL ); #endif + +#ifdef EXPANDED_HL2DM_ACTIVITIES + ADD_ACTIVITY_TO_SR( ACT_HL2MP_IDLE_357 ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_RUN_357 ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_IDLE_CROUCH_357 ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_WALK_CROUCH_357 ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RANGE_ATTACK_357 ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RELOAD_357 ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_JUMP_357 ); +#endif } #ifdef MAPBASE diff --git a/sp/src/game/server/hl2/weapon_357.cpp b/sp/src/game/server/hl2/weapon_357.cpp index a73a97ba..4c180932 100644 --- a/sp/src/game/server/hl2/weapon_357.cpp +++ b/sp/src/game/server/hl2/weapon_357.cpp @@ -201,6 +201,15 @@ acttable_t CWeapon357::m_acttable[] = #ifdef MAPBASE // HL2:DM activities (for third-person animations in SP) +#ifdef EXPANDED_HL2DM_ACTIVITIES + { ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_357, false }, + { ACT_HL2MP_RUN, ACT_HL2MP_RUN_357, false }, + { ACT_HL2MP_IDLE_CROUCH, ACT_HL2MP_IDLE_CROUCH_357, false }, + { ACT_HL2MP_WALK_CROUCH, ACT_HL2MP_WALK_CROUCH_357, false }, + { ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_357, false }, + { ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_357, false }, + { ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_357, false }, +#else { ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_PISTOL, false }, { ACT_HL2MP_RUN, ACT_HL2MP_RUN_PISTOL, false }, { ACT_HL2MP_IDLE_CROUCH, ACT_HL2MP_IDLE_CROUCH_PISTOL, false }, @@ -209,6 +218,7 @@ acttable_t CWeapon357::m_acttable[] = { ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_PISTOL, false }, { ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_PISTOL, false }, #endif +#endif }; diff --git a/sp/src/game/server/hl2/weapon_ar2.cpp b/sp/src/game/server/hl2/weapon_ar2.cpp index 6b634de0..54576eb1 100644 --- a/sp/src/game/server/hl2/weapon_ar2.cpp +++ b/sp/src/game/server/hl2/weapon_ar2.cpp @@ -179,7 +179,7 @@ acttable_t CWeaponAR2::m_acttable[] = { ACT_HL2MP_IDLE_CROUCH, ACT_HL2MP_IDLE_CROUCH_AR2, false }, { ACT_HL2MP_WALK_CROUCH, ACT_HL2MP_WALK_CROUCH_AR2, false }, { ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_AR2, false }, - { ACT_HL2MP_GESTURE_RELOAD, ACT_GESTURE_RELOAD_SMG1, false }, + { ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_AR2, false }, { ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_AR2, false }, #endif }; diff --git a/sp/src/game/server/hl2/weapon_bugbait.cpp b/sp/src/game/server/hl2/weapon_bugbait.cpp index 612fe142..f8fcabf3 100644 --- a/sp/src/game/server/hl2/weapon_bugbait.cpp +++ b/sp/src/game/server/hl2/weapon_bugbait.cpp @@ -58,6 +58,9 @@ public: bool ShouldDisplayHUDHint() { return true; } DECLARE_DATADESC(); +#ifdef MAPBASE + DECLARE_ACTTABLE(); +#endif protected: @@ -86,6 +89,22 @@ BEGIN_DATADESC( CWeaponBugBait ) END_DATADESC() +#ifdef MAPBASE +acttable_t CWeaponBugBait::m_acttable[] = +{ + // HL2:DM activities (for third-person animations in SP) + { ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_GRENADE, false }, + { ACT_HL2MP_RUN, ACT_HL2MP_RUN_GRENADE, false }, + { ACT_HL2MP_IDLE_CROUCH, ACT_HL2MP_IDLE_CROUCH_GRENADE, false }, + { ACT_HL2MP_WALK_CROUCH, ACT_HL2MP_WALK_CROUCH_GRENADE, false }, + { ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_GRENADE, false }, + { ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_GRENADE, false }, + { ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_GRENADE, false }, +}; + +IMPLEMENT_ACTTABLE( CWeaponBugBait ); +#endif + //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- @@ -225,6 +244,10 @@ void CWeaponBugBait::PrimaryAttack( void ) return; SendWeaponAnim( ACT_VM_HAULBACK ); + +#ifdef MAPBASE + pPlayer->SetAnimation( PLAYER_ATTACK1 ); +#endif m_flTimeWeaponIdle = FLT_MAX; m_flNextPrimaryAttack = FLT_MAX; diff --git a/sp/src/game/server/hl2/weapon_shotgun.cpp b/sp/src/game/server/hl2/weapon_shotgun.cpp index 50752e8c..539cceed 100644 --- a/sp/src/game/server/hl2/weapon_shotgun.cpp +++ b/sp/src/game/server/hl2/weapon_shotgun.cpp @@ -389,6 +389,13 @@ bool CWeaponShotgun::StartReload( void ) pOwner->m_flNextAttack = gpGlobals->curtime; m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration(); +#ifdef MAPBASE + if ( pOwner->IsPlayer() ) + { + static_cast(pOwner)->SetAnimation( PLAYER_RELOAD ); + } +#endif + m_bInReload = true; return true; } diff --git a/sp/src/game/server/hl2/weapon_smg1.cpp b/sp/src/game/server/hl2/weapon_smg1.cpp index 96cfdd2c..bfafeb58 100644 --- a/sp/src/game/server/hl2/weapon_smg1.cpp +++ b/sp/src/game/server/hl2/weapon_smg1.cpp @@ -157,7 +157,7 @@ acttable_t CWeaponSMG1::m_acttable[] = { ACT_HL2MP_IDLE_CROUCH, ACT_HL2MP_IDLE_CROUCH_SMG1, false }, { ACT_HL2MP_WALK_CROUCH, ACT_HL2MP_WALK_CROUCH_SMG1, false }, { ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_SMG1, false }, - { ACT_HL2MP_GESTURE_RELOAD, ACT_GESTURE_RELOAD_SMG1, false }, + { ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_SMG1, false }, { ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_SMG1, false }, #endif }; diff --git a/sp/src/game/shared/activitylist.cpp b/sp/src/game/shared/activitylist.cpp index 5b13c750..3c888c6f 100644 --- a/sp/src/game/shared/activitylist.cpp +++ b/sp/src/game/shared/activitylist.cpp @@ -2461,6 +2461,16 @@ void ActivityList_RegisterSharedActivities( void ) REGISTER_SHARED_ACTIVITY( ACT_COVER_WALL_LOW_L_PISTOL ); #endif +#ifdef EXPANDED_HL2DM_ACTIVITIES + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_IDLE_357 ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_RUN_357 ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_IDLE_CROUCH_357 ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_WALK_CROUCH_357 ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RANGE_ATTACK_357 ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RELOAD_357 ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_JUMP_357 ); +#endif + AssertMsg( g_HighestActivity == LAST_SHARED_ACTIVITY - 1, "Not all activities from ai_activity.h registered in activitylist.cpp" ); } diff --git a/sp/src/game/shared/ai_activity.h b/sp/src/game/shared/ai_activity.h index 8663ce3a..5b5f3468 100644 --- a/sp/src/game/shared/ai_activity.h +++ b/sp/src/game/shared/ai_activity.h @@ -49,6 +49,10 @@ // This enables some new cover-related activities. #define EXPANDED_HL2_COVER_ACTIVITIES 1 +// EXPANDED HL2DM ACTIVITIES +// This enables some new activities for the HL2:DM set. +#define EXPANDED_HL2DM_ACTIVITIES 1 + #endif #define ACTIVITY_NOT_AVAILABLE -1 @@ -2345,6 +2349,16 @@ typedef enum ACT_COVER_WALL_LOW_L_PISTOL, #endif +#ifdef EXPANDED_HL2DM_ACTIVITIES + ACT_HL2MP_IDLE_357, + ACT_HL2MP_RUN_357, + ACT_HL2MP_IDLE_CROUCH_357, + ACT_HL2MP_WALK_CROUCH_357, + ACT_HL2MP_GESTURE_RANGE_ATTACK_357, + ACT_HL2MP_GESTURE_RELOAD_357, + ACT_HL2MP_JUMP_357, +#endif + // this is the end of the global activities, private per-monster activities start here. LAST_SHARED_ACTIVITY, } Activity; From 0139390c3e59c2f5380ecb4bf3ea5a57ca8085a8 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Mon, 15 Nov 2021 14:39:54 -0600 Subject: [PATCH 253/378] Added more HL2:DM activities --- sp/src/game/server/ai_activity.cpp | 26 ++++++++++++++++ sp/src/game/server/hl2/weapon_357.cpp | 30 ++++++++++--------- sp/src/game/server/hl2/weapon_alyxgun.cpp | 15 ++++++++++ sp/src/game/server/hl2/weapon_annabelle.cpp | 15 ++++++++++ sp/src/game/server/hl2/weapon_ar2.cpp | 18 ++++++----- sp/src/game/server/hl2/weapon_bugbait.cpp | 18 ++++++----- sp/src/game/server/hl2/weapon_crossbow.cpp | 4 +++ sp/src/game/server/hl2/weapon_crowbar.cpp | 4 +++ sp/src/game/server/hl2/weapon_frag.cpp | 18 ++++++----- sp/src/game/server/hl2/weapon_physcannon.cpp | 4 +++ sp/src/game/server/hl2/weapon_pistol.cpp | 4 +++ sp/src/game/server/hl2/weapon_rpg.cpp | 4 +++ sp/src/game/server/hl2/weapon_shotgun.cpp | 4 +++ sp/src/game/server/hl2/weapon_smg1.cpp | 4 +++ sp/src/game/shared/activitylist.cpp | 26 ++++++++++++++++ sp/src/game/shared/ai_activity.h | 26 ++++++++++++++++ sp/src/game/shared/hl2mp/weapon_slam.cpp | 4 +++ sp/src/game/shared/hl2mp/weapon_stunstick.cpp | 16 ++++++++++ 18 files changed, 205 insertions(+), 35 deletions(-) diff --git a/sp/src/game/server/ai_activity.cpp b/sp/src/game/server/ai_activity.cpp index 14687118..f1a36cf8 100644 --- a/sp/src/game/server/ai_activity.cpp +++ b/sp/src/game/server/ai_activity.cpp @@ -2346,11 +2346,37 @@ void CAI_BaseNPC::InitDefaultActivitySR(void) #endif #ifdef EXPANDED_HL2DM_ACTIVITIES + ADD_ACTIVITY_TO_SR( ACT_HL2MP_WALK ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_WALK_PISTOL ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_WALK_SHOTGUN ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_WALK_SMG1 ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_WALK_AR2 ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_WALK_PHYSGUN ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_WALK_GRENADE ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_WALK_RPG ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_WALK_CROSSBOW ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_WALK_MELEE ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_WALK_SLAM ); + + ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RANGE_ATTACK2 ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RANGE_ATTACK2_PISTOL ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RANGE_ATTACK2_SHOTGUN ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RANGE_ATTACK2_SMG1 ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RANGE_ATTACK2_AR2 ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RANGE_ATTACK2_PHYSGUN ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RANGE_ATTACK2_GRENADE ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RANGE_ATTACK2_RPG ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RANGE_ATTACK2_CROSSBOW ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RANGE_ATTACK2_MELEE ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RANGE_ATTACK2_SLAM ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_IDLE_357 ); ADD_ACTIVITY_TO_SR( ACT_HL2MP_RUN_357 ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_WALK_357 ); ADD_ACTIVITY_TO_SR( ACT_HL2MP_IDLE_CROUCH_357 ); ADD_ACTIVITY_TO_SR( ACT_HL2MP_WALK_CROUCH_357 ); ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RANGE_ATTACK_357 ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RANGE_ATTACK2_357 ); ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RELOAD_357 ); ADD_ACTIVITY_TO_SR( ACT_HL2MP_JUMP_357 ); #endif diff --git a/sp/src/game/server/hl2/weapon_357.cpp b/sp/src/game/server/hl2/weapon_357.cpp index 4c180932..b0ae2131 100644 --- a/sp/src/game/server/hl2/weapon_357.cpp +++ b/sp/src/game/server/hl2/weapon_357.cpp @@ -202,21 +202,23 @@ acttable_t CWeapon357::m_acttable[] = #ifdef MAPBASE // HL2:DM activities (for third-person animations in SP) #ifdef EXPANDED_HL2DM_ACTIVITIES - { ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_357, false }, - { ACT_HL2MP_RUN, ACT_HL2MP_RUN_357, false }, - { ACT_HL2MP_IDLE_CROUCH, ACT_HL2MP_IDLE_CROUCH_357, false }, - { ACT_HL2MP_WALK_CROUCH, ACT_HL2MP_WALK_CROUCH_357, false }, - { ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_357, false }, - { ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_357, false }, - { ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_357, false }, + { ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_357, false }, + { ACT_HL2MP_RUN, ACT_HL2MP_RUN_357, false }, + { ACT_HL2MP_WALK, ACT_HL2MP_WALK_357, false }, + { ACT_HL2MP_IDLE_CROUCH, ACT_HL2MP_IDLE_CROUCH_357, false }, + { ACT_HL2MP_WALK_CROUCH, ACT_HL2MP_WALK_CROUCH_357, false }, + { ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_357, false }, + { ACT_HL2MP_GESTURE_RANGE_ATTACK2, ACT_HL2MP_GESTURE_RANGE_ATTACK2_357, false }, + { ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_357, false }, + { ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_357, false }, #else - { ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_PISTOL, false }, - { ACT_HL2MP_RUN, ACT_HL2MP_RUN_PISTOL, false }, - { ACT_HL2MP_IDLE_CROUCH, ACT_HL2MP_IDLE_CROUCH_PISTOL, false }, - { ACT_HL2MP_WALK_CROUCH, ACT_HL2MP_WALK_CROUCH_PISTOL, false }, - { ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_PISTOL, false }, - { ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_PISTOL, false }, - { ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_PISTOL, false }, + { ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_PISTOL, false }, + { ACT_HL2MP_RUN, ACT_HL2MP_RUN_PISTOL, false }, + { ACT_HL2MP_IDLE_CROUCH, ACT_HL2MP_IDLE_CROUCH_PISTOL, false }, + { ACT_HL2MP_WALK_CROUCH, ACT_HL2MP_WALK_CROUCH_PISTOL, false }, + { ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_PISTOL, false }, + { ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_PISTOL, false }, + { ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_PISTOL, false }, #endif #endif }; diff --git a/sp/src/game/server/hl2/weapon_alyxgun.cpp b/sp/src/game/server/hl2/weapon_alyxgun.cpp index 538f6312..dbd57cec 100644 --- a/sp/src/game/server/hl2/weapon_alyxgun.cpp +++ b/sp/src/game/server/hl2/weapon_alyxgun.cpp @@ -105,6 +105,21 @@ acttable_t CWeaponAlyxGun::m_acttable[] = // { ACT_ARM, ACT_ARM_PISTOL, true }, // { ACT_DISARM, ACT_DISARM_PISTOL, true }, + +#ifdef MAPBASE + // HL2:DM activities (for third-person animations in SP) + { ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_PISTOL, false }, + { ACT_HL2MP_RUN, ACT_HL2MP_RUN_PISTOL, false }, + { ACT_HL2MP_IDLE_CROUCH, ACT_HL2MP_IDLE_CROUCH_PISTOL, false }, + { ACT_HL2MP_WALK_CROUCH, ACT_HL2MP_WALK_CROUCH_PISTOL, false }, + { ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_PISTOL, false }, + { ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_PISTOL, false }, + { ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_PISTOL, false }, +#ifdef EXPANDED_HL2DM_ACTIVITIES + { ACT_HL2MP_WALK, ACT_HL2MP_WALK_PISTOL, false }, + { ACT_HL2MP_GESTURE_RANGE_ATTACK2, ACT_HL2MP_GESTURE_RANGE_ATTACK2_PISTOL, false }, +#endif +#endif }; IMPLEMENT_ACTTABLE(CWeaponAlyxGun); diff --git a/sp/src/game/server/hl2/weapon_annabelle.cpp b/sp/src/game/server/hl2/weapon_annabelle.cpp index 47ee9e39..23b0c196 100644 --- a/sp/src/game/server/hl2/weapon_annabelle.cpp +++ b/sp/src/game/server/hl2/weapon_annabelle.cpp @@ -99,6 +99,21 @@ acttable_t CWeaponAnnabelle::m_acttable[] = { ACT_GESTURE_RANGE_ATTACK1, ACT_GESTURE_RANGE_ATTACK_SHOTGUN, true }, { ACT_RELOAD_LOW, ACT_RELOAD_SMG1_LOW, false }, { ACT_GESTURE_RELOAD, ACT_GESTURE_RELOAD_SMG1, false }, + +#ifdef MAPBASE + // HL2:DM activities (for third-person animations in SP) + { ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_AR2, false }, + { ACT_HL2MP_RUN, ACT_HL2MP_RUN_AR2, false }, + { ACT_HL2MP_IDLE_CROUCH, ACT_HL2MP_IDLE_CROUCH_AR2, false }, + { ACT_HL2MP_WALK_CROUCH, ACT_HL2MP_WALK_CROUCH_AR2, false }, + { ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_SHOTGUN, false }, + { ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_AR2, false }, + { ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_AR2, false }, +#ifdef EXPANDED_HL2DM_ACTIVITIES + { ACT_HL2MP_WALK, ACT_HL2MP_WALK_AR2, false }, + { ACT_HL2MP_GESTURE_RANGE_ATTACK2, ACT_HL2MP_GESTURE_RANGE_ATTACK2_SHOTGUN, false }, +#endif +#endif }; IMPLEMENT_ACTTABLE(CWeaponAnnabelle); diff --git a/sp/src/game/server/hl2/weapon_ar2.cpp b/sp/src/game/server/hl2/weapon_ar2.cpp index 54576eb1..c9c27388 100644 --- a/sp/src/game/server/hl2/weapon_ar2.cpp +++ b/sp/src/game/server/hl2/weapon_ar2.cpp @@ -174,13 +174,17 @@ acttable_t CWeaponAR2::m_acttable[] = #ifdef MAPBASE // HL2:DM activities (for third-person animations in SP) - { ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_AR2, false }, - { ACT_HL2MP_RUN, ACT_HL2MP_RUN_AR2, false }, - { ACT_HL2MP_IDLE_CROUCH, ACT_HL2MP_IDLE_CROUCH_AR2, false }, - { ACT_HL2MP_WALK_CROUCH, ACT_HL2MP_WALK_CROUCH_AR2, false }, - { ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_AR2, false }, - { ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_AR2, false }, - { ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_AR2, false }, + { ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_AR2, false }, + { ACT_HL2MP_RUN, ACT_HL2MP_RUN_AR2, false }, + { ACT_HL2MP_IDLE_CROUCH, ACT_HL2MP_IDLE_CROUCH_AR2, false }, + { ACT_HL2MP_WALK_CROUCH, ACT_HL2MP_WALK_CROUCH_AR2, false }, + { ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_AR2, false }, + { ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_AR2, false }, + { ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_AR2, false }, +#ifdef EXPANDED_HL2DM_ACTIVITIES + { ACT_HL2MP_WALK, ACT_HL2MP_WALK_AR2, false }, + { ACT_HL2MP_GESTURE_RANGE_ATTACK2, ACT_HL2MP_GESTURE_RANGE_ATTACK2_AR2, false }, +#endif #endif }; diff --git a/sp/src/game/server/hl2/weapon_bugbait.cpp b/sp/src/game/server/hl2/weapon_bugbait.cpp index f8fcabf3..330cf2c6 100644 --- a/sp/src/game/server/hl2/weapon_bugbait.cpp +++ b/sp/src/game/server/hl2/weapon_bugbait.cpp @@ -93,13 +93,17 @@ END_DATADESC() acttable_t CWeaponBugBait::m_acttable[] = { // HL2:DM activities (for third-person animations in SP) - { ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_GRENADE, false }, - { ACT_HL2MP_RUN, ACT_HL2MP_RUN_GRENADE, false }, - { ACT_HL2MP_IDLE_CROUCH, ACT_HL2MP_IDLE_CROUCH_GRENADE, false }, - { ACT_HL2MP_WALK_CROUCH, ACT_HL2MP_WALK_CROUCH_GRENADE, false }, - { ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_GRENADE, false }, - { ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_GRENADE, false }, - { ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_GRENADE, false }, + { ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_GRENADE, false }, + { ACT_HL2MP_RUN, ACT_HL2MP_RUN_GRENADE, false }, + { ACT_HL2MP_IDLE_CROUCH, ACT_HL2MP_IDLE_CROUCH_GRENADE, false }, + { ACT_HL2MP_WALK_CROUCH, ACT_HL2MP_WALK_CROUCH_GRENADE, false }, + { ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_GRENADE, false }, + { ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_GRENADE, false }, + { ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_GRENADE, false }, +#ifdef EXPANDED_HL2DM_ACTIVITIES + { ACT_HL2MP_WALK, ACT_HL2MP_WALK_GRENADE, false }, + { ACT_HL2MP_GESTURE_RANGE_ATTACK2, ACT_HL2MP_GESTURE_RANGE_ATTACK2_GRENADE, false }, +#endif }; IMPLEMENT_ACTTABLE( CWeaponBugBait ); diff --git a/sp/src/game/server/hl2/weapon_crossbow.cpp b/sp/src/game/server/hl2/weapon_crossbow.cpp index b8d9db71..7766ff98 100644 --- a/sp/src/game/server/hl2/weapon_crossbow.cpp +++ b/sp/src/game/server/hl2/weapon_crossbow.cpp @@ -753,6 +753,10 @@ acttable_t CWeaponCrossbow::m_acttable[] = { ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_CROSSBOW, false }, { ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_CROSSBOW, false }, { ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_CROSSBOW, false }, +#ifdef EXPANDED_HL2DM_ACTIVITIES + { ACT_HL2MP_WALK, ACT_HL2MP_WALK_CROSSBOW, false }, + { ACT_HL2MP_GESTURE_RANGE_ATTACK2, ACT_HL2MP_GESTURE_RANGE_ATTACK2_CROSSBOW, false }, +#endif #endif }; diff --git a/sp/src/game/server/hl2/weapon_crowbar.cpp b/sp/src/game/server/hl2/weapon_crowbar.cpp index 46c935a8..cee8d0f9 100644 --- a/sp/src/game/server/hl2/weapon_crowbar.cpp +++ b/sp/src/game/server/hl2/weapon_crowbar.cpp @@ -60,6 +60,10 @@ acttable_t CWeaponCrowbar::m_acttable[] = { ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_MELEE, false }, { ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_MELEE, false }, { ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_MELEE, false }, +#ifdef EXPANDED_HL2DM_ACTIVITIES + { ACT_HL2MP_GESTURE_RANGE_ATTACK2, ACT_HL2MP_GESTURE_RANGE_ATTACK2_MELEE, false }, + { ACT_HL2MP_WALK, ACT_HL2MP_WALK_MELEE, false }, +#endif #endif }; diff --git a/sp/src/game/server/hl2/weapon_frag.cpp b/sp/src/game/server/hl2/weapon_frag.cpp index c248c74e..01a9b17a 100644 --- a/sp/src/game/server/hl2/weapon_frag.cpp +++ b/sp/src/game/server/hl2/weapon_frag.cpp @@ -85,13 +85,17 @@ acttable_t CWeaponFrag::m_acttable[] = #ifdef MAPBASE // HL2:DM activities (for third-person animations in SP) - { ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_GRENADE, false }, - { ACT_HL2MP_RUN, ACT_HL2MP_RUN_GRENADE, false }, - { ACT_HL2MP_IDLE_CROUCH, ACT_HL2MP_IDLE_CROUCH_GRENADE, false }, - { ACT_HL2MP_WALK_CROUCH, ACT_HL2MP_WALK_CROUCH_GRENADE, false }, - { ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_GRENADE, false }, - { ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_GRENADE, false }, - { ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_GRENADE, false }, + { ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_GRENADE, false }, + { ACT_HL2MP_RUN, ACT_HL2MP_RUN_GRENADE, false }, + { ACT_HL2MP_IDLE_CROUCH, ACT_HL2MP_IDLE_CROUCH_GRENADE, false }, + { ACT_HL2MP_WALK_CROUCH, ACT_HL2MP_WALK_CROUCH_GRENADE, false }, + { ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_GRENADE, false }, + { ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_GRENADE, false }, + { ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_GRENADE, false }, +#ifdef EXPANDED_HL2DM_ACTIVITIES + { ACT_HL2MP_WALK, ACT_HL2MP_WALK_GRENADE, false }, + { ACT_HL2MP_GESTURE_RANGE_ATTACK2, ACT_HL2MP_GESTURE_RANGE_ATTACK2_GRENADE, false }, +#endif #endif }; diff --git a/sp/src/game/server/hl2/weapon_physcannon.cpp b/sp/src/game/server/hl2/weapon_physcannon.cpp index 3dfe86c3..a08dc220 100644 --- a/sp/src/game/server/hl2/weapon_physcannon.cpp +++ b/sp/src/game/server/hl2/weapon_physcannon.cpp @@ -1470,6 +1470,10 @@ acttable_t CWeaponPhysCannon::m_acttable[] = { ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_PHYSGUN, false }, { ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_PHYSGUN, false }, { ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_SLAM, false }, +#ifdef EXPANDED_HL2DM_ACTIVITIES + { ACT_HL2MP_WALK, ACT_HL2MP_WALK_PHYSGUN, false }, + { ACT_HL2MP_GESTURE_RANGE_ATTACK2, ACT_HL2MP_GESTURE_RANGE_ATTACK2_PHYSGUN, false }, +#endif }; IMPLEMENT_ACTTABLE( CWeaponPhysCannon ); diff --git a/sp/src/game/server/hl2/weapon_pistol.cpp b/sp/src/game/server/hl2/weapon_pistol.cpp index 66084797..dce93262 100644 --- a/sp/src/game/server/hl2/weapon_pistol.cpp +++ b/sp/src/game/server/hl2/weapon_pistol.cpp @@ -267,6 +267,10 @@ acttable_t CWeaponPistol::m_acttable[] = { ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_PISTOL, false }, { ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_PISTOL, false }, { ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_PISTOL, false }, +#ifdef EXPANDED_HL2DM_ACTIVITIES + { ACT_HL2MP_WALK, ACT_HL2MP_WALK_PISTOL, false }, + { ACT_HL2MP_GESTURE_RANGE_ATTACK2, ACT_HL2MP_GESTURE_RANGE_ATTACK2_PISTOL, false }, +#endif #endif }; diff --git a/sp/src/game/server/hl2/weapon_rpg.cpp b/sp/src/game/server/hl2/weapon_rpg.cpp index 3a8be219..9f49684f 100644 --- a/sp/src/game/server/hl2/weapon_rpg.cpp +++ b/sp/src/game/server/hl2/weapon_rpg.cpp @@ -1436,6 +1436,10 @@ acttable_t CWeaponRPG::m_acttable[] = { ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_RPG, false }, { ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_RPG, false }, { ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_RPG, false }, +#ifdef EXPANDED_HL2DM_ACTIVITIES + { ACT_HL2MP_WALK, ACT_HL2MP_WALK_RPG, false }, + { ACT_HL2MP_GESTURE_RANGE_ATTACK2, ACT_HL2MP_GESTURE_RANGE_ATTACK2_RPG, false }, +#endif #endif }; diff --git a/sp/src/game/server/hl2/weapon_shotgun.cpp b/sp/src/game/server/hl2/weapon_shotgun.cpp index 539cceed..9724408a 100644 --- a/sp/src/game/server/hl2/weapon_shotgun.cpp +++ b/sp/src/game/server/hl2/weapon_shotgun.cpp @@ -225,6 +225,10 @@ acttable_t CWeaponShotgun::m_acttable[] = { ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_SHOTGUN, false }, { ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_SHOTGUN, false }, { ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_SHOTGUN, false }, +#ifdef EXPANDED_HL2DM_ACTIVITIES + { ACT_HL2MP_WALK, ACT_HL2MP_WALK_SHOTGUN, false }, + { ACT_HL2MP_GESTURE_RANGE_ATTACK2, ACT_HL2MP_GESTURE_RANGE_ATTACK2_SHOTGUN, false }, +#endif #endif }; diff --git a/sp/src/game/server/hl2/weapon_smg1.cpp b/sp/src/game/server/hl2/weapon_smg1.cpp index bfafeb58..4097f2ae 100644 --- a/sp/src/game/server/hl2/weapon_smg1.cpp +++ b/sp/src/game/server/hl2/weapon_smg1.cpp @@ -159,6 +159,10 @@ acttable_t CWeaponSMG1::m_acttable[] = { ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_SMG1, false }, { ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_SMG1, false }, { ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_SMG1, false }, +#ifdef EXPANDED_HL2DM_ACTIVITIES + { ACT_HL2MP_WALK, ACT_HL2MP_WALK_SMG1, false }, + { ACT_HL2MP_GESTURE_RANGE_ATTACK2, ACT_HL2MP_GESTURE_RANGE_ATTACK2_SMG1, false }, +#endif #endif }; diff --git a/sp/src/game/shared/activitylist.cpp b/sp/src/game/shared/activitylist.cpp index 3c888c6f..4493a50c 100644 --- a/sp/src/game/shared/activitylist.cpp +++ b/sp/src/game/shared/activitylist.cpp @@ -2462,11 +2462,37 @@ void ActivityList_RegisterSharedActivities( void ) #endif #ifdef EXPANDED_HL2DM_ACTIVITIES + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_WALK ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_WALK_PISTOL ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_WALK_SHOTGUN ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_WALK_SMG1 ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_WALK_AR2 ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_WALK_PHYSGUN ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_WALK_GRENADE ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_WALK_RPG ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_WALK_CROSSBOW ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_WALK_MELEE ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_WALK_SLAM ); + + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RANGE_ATTACK2 ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RANGE_ATTACK2_PISTOL ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RANGE_ATTACK2_SHOTGUN ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RANGE_ATTACK2_SMG1 ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RANGE_ATTACK2_AR2 ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RANGE_ATTACK2_PHYSGUN ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RANGE_ATTACK2_GRENADE ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RANGE_ATTACK2_RPG ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RANGE_ATTACK2_CROSSBOW ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RANGE_ATTACK2_MELEE ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RANGE_ATTACK2_SLAM ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_IDLE_357 ); REGISTER_SHARED_ACTIVITY( ACT_HL2MP_RUN_357 ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_WALK_357 ); REGISTER_SHARED_ACTIVITY( ACT_HL2MP_IDLE_CROUCH_357 ); REGISTER_SHARED_ACTIVITY( ACT_HL2MP_WALK_CROUCH_357 ); REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RANGE_ATTACK_357 ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RANGE_ATTACK2_357 ); REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RELOAD_357 ); REGISTER_SHARED_ACTIVITY( ACT_HL2MP_JUMP_357 ); #endif diff --git a/sp/src/game/shared/ai_activity.h b/sp/src/game/shared/ai_activity.h index 5b5f3468..e73c571a 100644 --- a/sp/src/game/shared/ai_activity.h +++ b/sp/src/game/shared/ai_activity.h @@ -2350,11 +2350,37 @@ typedef enum #endif #ifdef EXPANDED_HL2DM_ACTIVITIES + ACT_HL2MP_WALK, + ACT_HL2MP_WALK_PISTOL, + ACT_HL2MP_WALK_SHOTGUN, + ACT_HL2MP_WALK_SMG1, + ACT_HL2MP_WALK_AR2, + ACT_HL2MP_WALK_PHYSGUN, + ACT_HL2MP_WALK_GRENADE, + ACT_HL2MP_WALK_RPG, + ACT_HL2MP_WALK_CROSSBOW, + ACT_HL2MP_WALK_MELEE, + ACT_HL2MP_WALK_SLAM, + + ACT_HL2MP_GESTURE_RANGE_ATTACK2, + ACT_HL2MP_GESTURE_RANGE_ATTACK2_PISTOL, + ACT_HL2MP_GESTURE_RANGE_ATTACK2_SHOTGUN, + ACT_HL2MP_GESTURE_RANGE_ATTACK2_SMG1, + ACT_HL2MP_GESTURE_RANGE_ATTACK2_AR2, + ACT_HL2MP_GESTURE_RANGE_ATTACK2_PHYSGUN, + ACT_HL2MP_GESTURE_RANGE_ATTACK2_GRENADE, + ACT_HL2MP_GESTURE_RANGE_ATTACK2_RPG, + ACT_HL2MP_GESTURE_RANGE_ATTACK2_CROSSBOW, + ACT_HL2MP_GESTURE_RANGE_ATTACK2_MELEE, + ACT_HL2MP_GESTURE_RANGE_ATTACK2_SLAM, + ACT_HL2MP_IDLE_357, ACT_HL2MP_RUN_357, + ACT_HL2MP_WALK_357, ACT_HL2MP_IDLE_CROUCH_357, ACT_HL2MP_WALK_CROUCH_357, ACT_HL2MP_GESTURE_RANGE_ATTACK_357, + ACT_HL2MP_GESTURE_RANGE_ATTACK2_357, ACT_HL2MP_GESTURE_RELOAD_357, ACT_HL2MP_JUMP_357, #endif diff --git a/sp/src/game/shared/hl2mp/weapon_slam.cpp b/sp/src/game/shared/hl2mp/weapon_slam.cpp index 5bdea44f..36dd9825 100644 --- a/sp/src/game/shared/hl2mp/weapon_slam.cpp +++ b/sp/src/game/shared/hl2mp/weapon_slam.cpp @@ -115,6 +115,10 @@ acttable_t CWeapon_SLAM::m_acttable[] = { ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_SLAM, false }, { ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_SLAM, false }, { ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_SLAM, false }, +#ifdef EXPANDED_HL2DM_ACTIVITIES + { ACT_HL2MP_WALK, ACT_HL2MP_WALK_SLAM, false }, + { ACT_HL2MP_GESTURE_RANGE_ATTACK2, ACT_HL2MP_GESTURE_RANGE_ATTACK2_SLAM, false }, +#endif }; IMPLEMENT_ACTTABLE(CWeapon_SLAM); diff --git a/sp/src/game/shared/hl2mp/weapon_stunstick.cpp b/sp/src/game/shared/hl2mp/weapon_stunstick.cpp index 992bd036..b936b194 100644 --- a/sp/src/game/shared/hl2mp/weapon_stunstick.cpp +++ b/sp/src/game/shared/hl2mp/weapon_stunstick.cpp @@ -86,6 +86,22 @@ acttable_t CWeaponStunStick::m_acttable[] = { ACT_RUN, ACT_RUN_MELEE, false }, { ACT_WALK, ACT_WALK_MELEE, false }, #endif + +#ifdef MAPBASE + // HL2:DM activities (for third-person animations in SP) + { ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_SLAM, true }, + { ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_MELEE, false }, + { ACT_HL2MP_RUN, ACT_HL2MP_RUN_MELEE, false }, + { ACT_HL2MP_IDLE_CROUCH, ACT_HL2MP_IDLE_CROUCH_MELEE, false }, + { ACT_HL2MP_WALK_CROUCH, ACT_HL2MP_WALK_CROUCH_MELEE, false }, + { ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_MELEE, false }, + { ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_MELEE, false }, + { ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_MELEE, false }, +#ifdef EXPANDED_HL2DM_ACTIVITIES + { ACT_HL2MP_GESTURE_RANGE_ATTACK2, ACT_HL2MP_GESTURE_RANGE_ATTACK2_MELEE, false }, + { ACT_HL2MP_WALK, ACT_HL2MP_WALK_MELEE, false }, +#endif +#endif }; IMPLEMENT_ACTTABLE(CWeaponStunStick); From 6755a4d3f61e691339176c657a47d62b1e900650 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Mon, 15 Nov 2021 14:40:51 -0600 Subject: [PATCH 254/378] Added walking to singleplayer anim state --- sp/src/game/shared/mapbase/singleplayer_animstate.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/sp/src/game/shared/mapbase/singleplayer_animstate.cpp b/sp/src/game/shared/mapbase/singleplayer_animstate.cpp index 8f184c7a..e3b84b4d 100644 --- a/sp/src/game/shared/mapbase/singleplayer_animstate.cpp +++ b/sp/src/game/shared/mapbase/singleplayer_animstate.cpp @@ -22,6 +22,7 @@ #include "apparent_velocity_helper.h" #include "utldict.h" #include "filesystem.h" +#include "in_buttons.h" #include "..\public\datacache\imdlcache.h" extern ConVar mp_facefronttime, mp_feetyawrate, mp_ik; @@ -109,13 +110,13 @@ Activity CSinglePlayerAnimState::CalcMainActivity() { if ( speed > 0 ) { - /* - if ( bRunning == false ) +#ifdef EXPANDED_HL2DM_ACTIVITIES + if ( m_pPlayer->GetButtons() & IN_WALK ) { - idealActivity = ACT_WALK; + idealActivity = ACT_HL2MP_WALK; } else - */ +#endif { idealActivity = ACT_HL2MP_RUN; } From 41d799bbdf73af5f43d16d2e5a4d8b57cb73d7c9 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Mon, 15 Nov 2021 14:43:58 -0600 Subject: [PATCH 255/378] Added new player animation types and applied more player animations to SP HL2 weapons --- sp/src/game/server/hl2/basehlcombatweapon.cpp | 4 ++ sp/src/game/server/hl2/hl2_player.cpp | 12 +++++ sp/src/game/server/hl2/hl2_player.h | 2 + sp/src/game/server/hl2/weapon_ar2.cpp | 3 ++ sp/src/game/server/hl2/weapon_frag.cpp | 4 +- sp/src/game/server/hl2/weapon_physcannon.cpp | 16 ++++++ sp/src/game/server/hl2/weapon_rpg.cpp | 4 ++ sp/src/game/server/hl2/weapon_shotgun.cpp | 4 ++ sp/src/game/server/hl2/weapon_smg1.cpp | 4 ++ .../game/shared/basecombatweapon_shared.cpp | 9 ++++ .../shared/mapbase/singleplayer_animstate.cpp | 50 +++++++++++++++++-- .../shared/mapbase/singleplayer_animstate.h | 4 +- sp/src/game/shared/shareddefs.h | 8 +++ 13 files changed, 118 insertions(+), 6 deletions(-) diff --git a/sp/src/game/server/hl2/basehlcombatweapon.cpp b/sp/src/game/server/hl2/basehlcombatweapon.cpp index 33a700fc..894c290b 100644 --- a/sp/src/game/server/hl2/basehlcombatweapon.cpp +++ b/sp/src/game/server/hl2/basehlcombatweapon.cpp @@ -394,6 +394,10 @@ void CHLSelectFireMachineGun::SecondaryAttack( void ) { m_iSecondaryAttacks++; gamestats->Event_WeaponFired( pOwner, false, GetClassname() ); + +#ifdef MAPBASE + pOwner->SetAnimation( PLAYER_ATTACK2 ); +#endif } } diff --git a/sp/src/game/server/hl2/hl2_player.cpp b/sp/src/game/server/hl2/hl2_player.cpp index 02e1d9e0..be1ecf11 100644 --- a/sp/src/game/server/hl2/hl2_player.cpp +++ b/sp/src/game/server/hl2/hl2_player.cpp @@ -621,6 +621,10 @@ BEGIN_ENT_SCRIPTDESC( CHL2_Player, CBasePlayer, "The HL2 player entity." ) DEFINE_SCRIPTFUNC( RemoveCustomSuitDevice, "Removes a custom suit device ID. (1-3)" ) DEFINE_SCRIPTFUNC( IsCustomSuitDeviceActive, "Checks if a custom suit device is active." ) +#ifdef SP_ANIM_STATE + DEFINE_SCRIPTFUNC( AddAnimStateLayer, "Adds a custom sequence index as a misc. layer for the singleplayer anim state, wtih parameters for blending in/out, setting the playback rate, holding the animation at the end, and only playing when the player is still." ) +#endif + END_SCRIPTDESC(); #endif @@ -1389,6 +1393,14 @@ void CHL2_Player::SetAnimation( PLAYER_ANIM playerAnim ) m_pPlayerAnimState->SetPlayerAnimation( playerAnim ); } + +void CHL2_Player::AddAnimStateLayer( int iSequence, float flBlendIn, float flBlendOut, float flPlaybackRate, bool bHoldAtEnd, bool bOnlyWhenStill ) +{ + if (!hl2_use_sp_animstate.GetBool()) + return; + + m_pPlayerAnimState->AddMiscSequence( iSequence, flBlendIn, flBlendOut, flPlaybackRate, bHoldAtEnd, bOnlyWhenStill ); +} #endif #endif diff --git a/sp/src/game/server/hl2/hl2_player.h b/sp/src/game/server/hl2/hl2_player.h index b493f78a..49f41deb 100644 --- a/sp/src/game/server/hl2/hl2_player.h +++ b/sp/src/game/server/hl2/hl2_player.h @@ -134,6 +134,8 @@ public: #ifdef SP_ANIM_STATE void SetAnimation( PLAYER_ANIM playerAnim ); + + void AddAnimStateLayer( int iSequence, float flBlendIn = 0.0f, float flBlendOut = 0.0f, float flPlaybackRate = 1.0f, bool bHoldAtEnd = false, bool bOnlyWhenStill = false ); #endif virtual const char *GetOverrideStepSound( const char *pszBaseStepSoundName ); diff --git a/sp/src/game/server/hl2/weapon_ar2.cpp b/sp/src/game/server/hl2/weapon_ar2.cpp index c9c27388..6bb1f120 100644 --- a/sp/src/game/server/hl2/weapon_ar2.cpp +++ b/sp/src/game/server/hl2/weapon_ar2.cpp @@ -369,6 +369,9 @@ void CWeaponAR2::SecondaryAttack( void ) if( pPlayer ) { pPlayer->RumbleEffect(RUMBLE_AR2_ALT_FIRE, 0, RUMBLE_FLAG_RESTART ); +#ifdef MAPBASE + pPlayer->SetAnimation( PLAYER_ATTACK2 ); +#endif } SendWeaponAnim( ACT_VM_FIDGET ); diff --git a/sp/src/game/server/hl2/weapon_frag.cpp b/sp/src/game/server/hl2/weapon_frag.cpp index 01a9b17a..aeba2785 100644 --- a/sp/src/game/server/hl2/weapon_frag.cpp +++ b/sp/src/game/server/hl2/weapon_frag.cpp @@ -448,7 +448,7 @@ void CWeaponFrag::LobGrenade( CBasePlayer *pPlayer ) WeaponSound( WPN_DOUBLE ); #ifdef MAPBASE - pPlayer->SetAnimation( PLAYER_ATTACK1 ); + pPlayer->SetAnimation( PLAYER_ATTACK2 ); #endif m_bRedraw = true; @@ -496,7 +496,7 @@ void CWeaponFrag::RollGrenade( CBasePlayer *pPlayer ) WeaponSound( SPECIAL1 ); #ifdef MAPBASE - pPlayer->SetAnimation( PLAYER_ATTACK1 ); + pPlayer->SetAnimation( PLAYER_ATTACK2 ); #endif m_bRedraw = true; diff --git a/sp/src/game/server/hl2/weapon_physcannon.cpp b/sp/src/game/server/hl2/weapon_physcannon.cpp index a08dc220..6585a59c 100644 --- a/sp/src/game/server/hl2/weapon_physcannon.cpp +++ b/sp/src/game/server/hl2/weapon_physcannon.cpp @@ -1818,6 +1818,11 @@ void CWeaponPhysCannon::PuntNonVPhysics( CBaseEntity *pEntity, const Vector &for PrimaryFireEffect(); SendWeaponAnim( ACT_VM_SECONDARYATTACK ); +#ifdef MAPBASE + CBasePlayer *pPlayer = ToBasePlayer( GetOwner() ); + if (pPlayer) + pPlayer->SetAnimation( PLAYER_ATTACK1 ); +#endif m_nChangeState = ELEMENT_STATE_CLOSED; m_flElementDebounce = gpGlobals->curtime + 0.5f; @@ -1968,6 +1973,10 @@ void CWeaponPhysCannon::PuntVPhysics( CBaseEntity *pEntity, const Vector &vecFor PrimaryFireEffect(); SendWeaponAnim( ACT_VM_SECONDARYATTACK ); +#ifdef MAPBASE + pOwner->SetAnimation( PLAYER_ATTACK1 ); +#endif + m_nChangeState = ELEMENT_STATE_CLOSED; m_flElementDebounce = gpGlobals->curtime + 0.5f; m_flCheckSuppressTime = gpGlobals->curtime + 0.25f; @@ -2086,6 +2095,10 @@ void CWeaponPhysCannon::PuntRagdoll( CBaseEntity *pEntity, const Vector &vecForw PrimaryFireEffect(); SendWeaponAnim( ACT_VM_SECONDARYATTACK ); +#ifdef MAPBASE + pOwner->SetAnimation( PLAYER_ATTACK1 ); +#endif + m_nChangeState = ELEMENT_STATE_CLOSED; m_flElementDebounce = gpGlobals->curtime + 0.5f; m_flCheckSuppressTime = gpGlobals->curtime + 0.25f; @@ -2191,6 +2204,9 @@ void CWeaponPhysCannon::PrimaryAttack( void ) PrimaryFireEffect(); SendWeaponAnim( ACT_VM_SECONDARYATTACK ); +#ifdef MAPBASE + pOwner->SetAnimation( PLAYER_ATTACK1 ); +#endif return; } diff --git a/sp/src/game/server/hl2/weapon_rpg.cpp b/sp/src/game/server/hl2/weapon_rpg.cpp index 9f49684f..750dbf8a 100644 --- a/sp/src/game/server/hl2/weapon_rpg.cpp +++ b/sp/src/game/server/hl2/weapon_rpg.cpp @@ -1664,6 +1664,10 @@ void CWeaponRPG::PrimaryAttack( void ) SendWeaponAnim( ACT_VM_PRIMARYATTACK ); WeaponSound( SINGLE ); + +#ifdef MAPBASE + pOwner->SetAnimation( PLAYER_ATTACK1 ); +#endif pOwner->RumbleEffect( RUMBLE_SHOTGUN_SINGLE, 0, RUMBLE_FLAG_RESTART ); diff --git a/sp/src/game/server/hl2/weapon_shotgun.cpp b/sp/src/game/server/hl2/weapon_shotgun.cpp index 9724408a..74656058 100644 --- a/sp/src/game/server/hl2/weapon_shotgun.cpp +++ b/sp/src/game/server/hl2/weapon_shotgun.cpp @@ -612,7 +612,11 @@ void CWeaponShotgun::SecondaryAttack( void ) SendWeaponAnim( ACT_VM_SECONDARYATTACK ); // player "shoot" animation +#ifdef MAPBASE + pPlayer->SetAnimation( PLAYER_ATTACK2 ); +#else pPlayer->SetAnimation( PLAYER_ATTACK1 ); +#endif // Don't fire again until fire animation has completed #ifdef MAPBASE diff --git a/sp/src/game/server/hl2/weapon_smg1.cpp b/sp/src/game/server/hl2/weapon_smg1.cpp index 4097f2ae..280d8e08 100644 --- a/sp/src/game/server/hl2/weapon_smg1.cpp +++ b/sp/src/game/server/hl2/weapon_smg1.cpp @@ -469,7 +469,11 @@ void CWeaponSMG1::SecondaryAttack( void ) CSoundEnt::InsertSound( SOUND_COMBAT, GetAbsOrigin(), 1000, 0.2, GetOwner(), SOUNDENT_CHANNEL_WEAPON ); // player "shoot" animation +#ifdef MAPBASE + pPlayer->SetAnimation( PLAYER_ATTACK2 ); +#else pPlayer->SetAnimation( PLAYER_ATTACK1 ); +#endif // Decrease ammo pPlayer->RemoveAmmo( 1, m_iSecondaryAmmoType ); diff --git a/sp/src/game/shared/basecombatweapon_shared.cpp b/sp/src/game/shared/basecombatweapon_shared.cpp index 3e23ab0f..50c2ea25 100644 --- a/sp/src/game/shared/basecombatweapon_shared.cpp +++ b/sp/src/game/shared/basecombatweapon_shared.cpp @@ -1581,6 +1581,10 @@ bool CBaseCombatWeapon::DefaultDeploy( char *szViewModel, char *szWeaponModel, i SetViewModel(); SendWeaponAnim( iActivity ); + +#ifdef MAPBASE + pOwner->SetAnimation( PLAYER_UNHOLSTER ); +#endif pOwner->SetNextAttack( gpGlobals->curtime + SequenceDuration() ); } @@ -1652,6 +1656,11 @@ bool CBaseCombatWeapon::Holster( CBaseCombatWeapon *pSwitchingTo ) if (pOwner) { pOwner->SetNextAttack( gpGlobals->curtime + flSequenceDuration ); + +#ifdef MAPBASE + if (pOwner->IsPlayer()) + static_cast(pOwner)->SetAnimation( PLAYER_HOLSTER ); +#endif } // If we don't have a holster anim, hide immediately to avoid timing issues diff --git a/sp/src/game/shared/mapbase/singleplayer_animstate.cpp b/sp/src/game/shared/mapbase/singleplayer_animstate.cpp index e3b84b4d..380dbd89 100644 --- a/sp/src/game/shared/mapbase/singleplayer_animstate.cpp +++ b/sp/src/game/shared/mapbase/singleplayer_animstate.cpp @@ -146,6 +146,16 @@ void CSinglePlayerAnimState::SetPlayerAnimation( PLAYER_ANIM playerAnim ) m_bFiring = m_iFireSequence != -1; m_flFireCycle = 0; } + else if ( playerAnim == PLAYER_ATTACK2 ) + { +#ifdef EXPANDED_HL2DM_ACTIVITIES + m_iFireSequence = SelectWeightedSequence( TranslateActivity( ACT_HL2MP_GESTURE_RANGE_ATTACK2 ) ); +#else + m_iFireSequence = SelectWeightedSequence( TranslateActivity( ACT_HL2MP_GESTURE_RANGE_ATTACK ) ); +#endif + m_bFiring = m_iFireSequence != -1; + m_flFireCycle = 0; + } else if ( playerAnim == PLAYER_JUMP ) { // Play the jump animation. @@ -168,6 +178,22 @@ void CSinglePlayerAnimState::SetPlayerAnimation( PLAYER_ANIM playerAnim ) m_flReloadCycle = 0; } } + else if ( playerAnim == PLAYER_UNHOLSTER || playerAnim == PLAYER_HOLSTER ) + { + m_iWeaponSwitchSequence = SelectWeightedSequence( TranslateActivity( playerAnim == PLAYER_UNHOLSTER ? ACT_ARM : ACT_DISARM ) ); + if (m_iWeaponSwitchSequence != -1) + { + // clear other events that might be playing in our layer + m_bPlayingMisc = false; + m_bReloading = false; + + m_bWeaponSwitching = true; + m_flWeaponSwitchCycle = 0; + m_flMiscBlendOut = 0.1f; + m_flMiscBlendIn = 0.1f; + m_bMiscNoOverride = false; + } + } } //----------------------------------------------------------------------------- @@ -226,6 +252,26 @@ void CSinglePlayerAnimState::ComputeSequences( CStudioHdr *pStudioHdr ) ComputeWeaponSwitchSequence(); } +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CSinglePlayerAnimState::AddMiscSequence( int iSequence, float flBlendIn, float flBlendOut, float flPlaybackRate, bool bHoldAtEnd, bool bOnlyWhenStill ) +{ + Assert( iSequence != -1 ); + + m_iMiscSequence = iSequence; + m_flMiscBlendIn = flBlendIn; + m_flMiscBlendOut = flBlendOut; + + m_bPlayingMisc = true; + m_bMiscHoldAtEnd = bHoldAtEnd; + m_bReloading = false; + m_flMiscCycle = 0; + m_bMiscOnlyWhenStill = bOnlyWhenStill; + m_bMiscNoOverride = true; + m_fMiscPlaybackRate = flPlaybackRate; +} + //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- @@ -386,9 +432,7 @@ void CSinglePlayerAnimState::ComputeWeaponSwitchSequence() // does misc gestures if we're not firing void CSinglePlayerAnimState::ComputeMiscSequence() { - bool bHoldAtEnd = false; - - UpdateLayerSequenceGeneric( RELOADSEQUENCE_LAYER, m_bPlayingMisc, m_flMiscCycle, m_iMiscSequence, bHoldAtEnd, m_flMiscBlendIn, m_flMiscBlendOut, m_bMiscOnlyWhenStill, m_fMiscPlaybackRate ); + UpdateLayerSequenceGeneric( RELOADSEQUENCE_LAYER, m_bPlayingMisc, m_flMiscCycle, m_iMiscSequence, m_bMiscHoldAtEnd, m_flMiscBlendIn, m_flMiscBlendOut, m_bMiscOnlyWhenStill, m_fMiscPlaybackRate ); } //----------------------------------------------------------------------------- diff --git a/sp/src/game/shared/mapbase/singleplayer_animstate.h b/sp/src/game/shared/mapbase/singleplayer_animstate.h index 460e6e12..a805dffc 100644 --- a/sp/src/game/shared/mapbase/singleplayer_animstate.h +++ b/sp/src/game/shared/mapbase/singleplayer_animstate.h @@ -48,6 +48,8 @@ public: void ComputeSequences( CStudioHdr *pStudioHdr ); + void AddMiscSequence( int iSequence, float flBlendIn = 0.0f, float flBlendOut = 0.0f, float flPlaybackRate = 1.0f, bool bHoldAtEnd = false, bool bOnlyWhenStill = false ); + void ClearAnimationState(); void ClearAnimationLayers(); @@ -91,7 +93,7 @@ private: bool m_bPlayingMisc; float m_flMiscCycle, m_flMiscBlendOut, m_flMiscBlendIn; int m_iMiscSequence; - bool m_bMiscOnlyWhenStill; + bool m_bMiscOnlyWhenStill, m_bMiscHoldAtEnd; bool m_bMiscNoOverride; float m_fMiscPlaybackRate; bool m_bMiscCycleRewound; diff --git a/sp/src/game/shared/shareddefs.h b/sp/src/game/shared/shareddefs.h index 11f8e8aa..7e533ceb 100644 --- a/sp/src/game/shared/shareddefs.h +++ b/sp/src/game/shared/shareddefs.h @@ -366,6 +366,14 @@ enum PLAYER_ANIM PLAYER_RELOAD, PLAYER_START_AIMING, PLAYER_LEAVE_AIMING, + +#ifdef MAPBASE + // New player animations from Mapbase + PLAYER_ATTACK2, + PLAYER_ATTACK3, + PLAYER_UNHOLSTER, + PLAYER_HOLSTER, +#endif }; #ifdef HL2_DLL From abc34c0c85df254becdbb338739f217e2176ef21 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Mon, 15 Nov 2021 14:45:32 -0600 Subject: [PATCH 256/378] Added holstered activity handling for players --- sp/src/game/server/player.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sp/src/game/server/player.cpp b/sp/src/game/server/player.cpp index 1f52ea4f..659eb748 100644 --- a/sp/src/game/server/player.cpp +++ b/sp/src/game/server/player.cpp @@ -7819,6 +7819,11 @@ Activity CBasePlayer::Weapon_TranslateActivity( Activity baseAct, bool *pRequire { Activity weaponTranslation = BaseClass::Weapon_TranslateActivity( baseAct, pRequired ); + if ( GetActiveWeapon() && GetActiveWeapon()->IsEffectActive(EF_NODRAW) && baseAct != ACT_ARM ) + { + // Our weapon is holstered. Use the base activity. + return baseAct; + } if ( GetModelPtr() && !GetModelPtr()->HaveSequenceForActivity(weaponTranslation) ) { // This is used so players can fall back to backup activities in the same way NPCs in Mapbase can From 91978b2934a0f2136d0fb62f97cd68ea8cde3e70 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Mon, 15 Nov 2021 14:48:47 -0600 Subject: [PATCH 257/378] Fixed issues with third person player models --- sp/src/game/client/c_basecombatweapon.cpp | 2 +- sp/src/game/client/c_baseplayer.cpp | 32 +++++++++++++++++++++++ sp/src/game/client/c_baseplayer.h | 6 +++++ 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/sp/src/game/client/c_basecombatweapon.cpp b/sp/src/game/client/c_basecombatweapon.cpp index 0545d0a3..b1973c51 100644 --- a/sp/src/game/client/c_basecombatweapon.cpp +++ b/sp/src/game/client/c_basecombatweapon.cpp @@ -509,7 +509,7 @@ int C_BaseCombatWeapon::DrawModel( int flags ) { // If this isn't the main view, draw the weapon. view_id_t viewID = CurrentViewID(); - if (viewID != VIEW_MAIN && viewID != VIEW_INTRO_CAMERA && (viewID != VIEW_SHADOW_DEPTH_TEXTURE || !localplayer->IsEffectActive(EF_DIMLIGHT))) + if ( (!localplayer->InFirstPersonView() || (viewID != VIEW_MAIN && viewID != VIEW_INTRO_CAMERA)) && (viewID != VIEW_SHADOW_DEPTH_TEXTURE || !localplayer->IsEffectActive(EF_DIMLIGHT)) ) { // TODO: Is this inefficient? int nModelIndex = GetModelIndex(); diff --git a/sp/src/game/client/c_baseplayer.cpp b/sp/src/game/client/c_baseplayer.cpp index acb398f0..6e068341 100644 --- a/sp/src/game/client/c_baseplayer.cpp +++ b/sp/src/game/client/c_baseplayer.cpp @@ -1518,6 +1518,38 @@ int C_BasePlayer::DrawModel( int flags ) return BaseClass::DrawModel( flags ); } +#ifdef MAPBASE +ConVar cl_player_allow_thirdperson_projtex( "cl_player_allow_thirdperson_projtex", "1", FCVAR_NONE, "Allows players to receive projected textures if they're non-local or in third person." ); +ConVar cl_player_allow_thirdperson_rttshadows( "cl_player_allow_thirdperson_rttshadows", "0", FCVAR_NONE, "Allows players to cast RTT shadows if they're non-local or in third person." ); +ConVar cl_player_allow_firstperson_projtex( "cl_player_allow_firstperson_projtex", "1", FCVAR_NONE, "Allows players to receive projected textures even if they're in first person." ); +ConVar cl_player_allow_firstperson_rttshadows( "cl_player_allow_firstperson_rttshadows", "0", FCVAR_NONE, "Allows players to cast RTT shadows even if they're in first person." ); + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +ShadowType_t C_BasePlayer::ShadowCastType() +{ + if ( (!IsLocalPlayer() || ShouldDraw()) ? !cl_player_allow_thirdperson_rttshadows.GetBool() : !cl_player_allow_firstperson_rttshadows.GetBool() ) + return SHADOWS_NONE; + + if ( !IsVisible() ) + return SHADOWS_NONE; + + return SHADOWS_RENDER_TO_TEXTURE_DYNAMIC; +} + +//----------------------------------------------------------------------------- +// Should this object receive shadows? +//----------------------------------------------------------------------------- +bool C_BasePlayer::ShouldReceiveProjectedTextures( int flags ) +{ + if ( (!IsLocalPlayer() || ShouldDraw()) ? !cl_player_allow_thirdperson_projtex.GetBool() : !cl_player_allow_firstperson_projtex.GetBool() ) + return false; + + return BaseClass::ShouldReceiveProjectedTextures( flags ); +} +#endif + //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- diff --git a/sp/src/game/client/c_baseplayer.h b/sp/src/game/client/c_baseplayer.h index 5b569595..bc8ca654 100644 --- a/sp/src/game/client/c_baseplayer.h +++ b/sp/src/game/client/c_baseplayer.h @@ -207,6 +207,11 @@ public: void SetMaxSpeed( float flMaxSpeed ) { m_flMaxspeed = flMaxSpeed; } float MaxSpeed() const { return m_flMaxspeed; } +#ifdef MAPBASE + // See c_baseplayer.cpp + virtual ShadowType_t ShadowCastType(); + virtual bool ShouldReceiveProjectedTextures( int flags ); +#else // Should this object cast shadows? virtual ShadowType_t ShadowCastType() { return SHADOWS_NONE; } @@ -214,6 +219,7 @@ public: { return false; } +#endif bool IsLocalPlayer( void ) const; From f975e7d10d170076a5d2d040116d3a1bf6ad7240 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Mon, 15 Nov 2021 16:19:27 -0600 Subject: [PATCH 258/378] Changed the singleplayer animation state to only be active when the model has appropriate animations --- sp/src/game/server/hl2/hl2_player.cpp | 35 ++++++++++++++++++++++----- sp/src/game/server/hl2/hl2_player.h | 2 ++ 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/sp/src/game/server/hl2/hl2_player.cpp b/sp/src/game/server/hl2/hl2_player.cpp index be1ecf11..903033ee 100644 --- a/sp/src/game/server/hl2/hl2_player.cpp +++ b/sp/src/game/server/hl2/hl2_player.cpp @@ -120,7 +120,7 @@ ConVar sv_stickysprint("sv_stickysprint", "0", FCVAR_ARCHIVE | FCVAR_ARCHIVE_XBO ConVar player_autoswitch_enabled( "player_autoswitch_enabled", "1", FCVAR_NONE, "This convar was added by Mapbase to toggle whether players automatically switch to their ''best'' weapon upon picking up ammo for it after it was dry." ); #ifdef SP_ANIM_STATE -ConVar hl2_use_sp_animstate( "hl2_use_sp_animstate", "1", FCVAR_NONE, "Allows SP HL2 players to use HL2:DM animations (for custom player models)" ); +ConVar hl2_use_sp_animstate( "hl2_use_sp_animstate", "1", FCVAR_NONE, "Allows SP HL2 players to use HL2:DM animations for custom player models. (changes may not apply until model is reloaded)" ); #endif #endif @@ -631,8 +631,6 @@ END_SCRIPTDESC(); CHL2_Player::CHL2_Player() { #ifdef SP_ANIM_STATE - // Here we create and init the player animation state. - m_pPlayerAnimState = CreatePlayerAnimationState(this); m_angEyeAngles.Init(); #endif @@ -1161,7 +1159,7 @@ void CHL2_Player::PostThink( void ) } #ifdef SP_ANIM_STATE - if (hl2_use_sp_animstate.GetBool()) + if (m_pPlayerAnimState) { m_angEyeAngles = EyeAngles(); @@ -1385,7 +1383,7 @@ void CHL2_Player::SpawnedAtPoint( CBaseEntity *pSpawnPoint ) // Set the activity based on an event or current state void CHL2_Player::SetAnimation( PLAYER_ANIM playerAnim ) { - if (!hl2_use_sp_animstate.GetBool()) + if (!m_pPlayerAnimState) { BaseClass::SetAnimation( playerAnim ); return; @@ -1396,12 +1394,37 @@ void CHL2_Player::SetAnimation( PLAYER_ANIM playerAnim ) void CHL2_Player::AddAnimStateLayer( int iSequence, float flBlendIn, float flBlendOut, float flPlaybackRate, bool bHoldAtEnd, bool bOnlyWhenStill ) { - if (!hl2_use_sp_animstate.GetBool()) + if (!m_pPlayerAnimState) return; m_pPlayerAnimState->AddMiscSequence( iSequence, flBlendIn, flBlendOut, flPlaybackRate, bHoldAtEnd, bOnlyWhenStill ); } #endif + +//----------------------------------------------------------------------------- +// Purpose: model-change notification. Fires on dynamic load completion as well +//----------------------------------------------------------------------------- +CStudioHdr *CHL2_Player::OnNewModel() +{ + CStudioHdr *hdr = BaseClass::OnNewModel(); + +#ifdef SP_ANIM_STATE + if ( hdr && hdr->HaveSequenceForActivity(ACT_HL2MP_IDLE) && hl2_use_sp_animstate.GetBool() ) + { + // Clears the animation state if we already have one. + if ( m_pPlayerAnimState != NULL ) + { + m_pPlayerAnimState->Release(); + m_pPlayerAnimState = NULL; + } + + // Here we create and init the player animation state. + m_pPlayerAnimState = CreatePlayerAnimationState(this); + } +#endif + + return hdr; +} #endif //----------------------------------------------------------------------------- diff --git a/sp/src/game/server/hl2/hl2_player.h b/sp/src/game/server/hl2/hl2_player.h index 49f41deb..0f0087c4 100644 --- a/sp/src/game/server/hl2/hl2_player.h +++ b/sp/src/game/server/hl2/hl2_player.h @@ -138,6 +138,8 @@ public: void AddAnimStateLayer( int iSequence, float flBlendIn = 0.0f, float flBlendOut = 0.0f, float flPlaybackRate = 1.0f, bool bHoldAtEnd = false, bool bOnlyWhenStill = false ); #endif + virtual CStudioHdr* OnNewModel(); + virtual const char *GetOverrideStepSound( const char *pszBaseStepSoundName ); #endif From 450e6a2ff2ea95429b79f96b55308a0ee2b7f5eb Mon Sep 17 00:00:00 2001 From: Blixibon Date: Mon, 15 Nov 2021 16:21:52 -0600 Subject: [PATCH 259/378] Implemented crossbow worldmodel bolt disappearance on player reload --- sp/src/game/server/hl2/weapon_crossbow.cpp | 40 ++++++++++++++++------ 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/sp/src/game/server/hl2/weapon_crossbow.cpp b/sp/src/game/server/hl2/weapon_crossbow.cpp index 7766ff98..71df75f3 100644 --- a/sp/src/game/server/hl2/weapon_crossbow.cpp +++ b/sp/src/game/server/hl2/weapon_crossbow.cpp @@ -591,6 +591,7 @@ private: void CheckZoomToggle( void ); void FireBolt( void ); #ifdef MAPBASE + void SetBolt( int iSetting ); void FireNPCBolt( CAI_BaseNPC *pOwner, Vector &vecShootOrigin, Vector &vecShootDir ); #endif void ToggleZoom( void ); @@ -861,11 +862,7 @@ void CWeaponCrossbow::Reload_NPC( bool bPlaySound ) { BaseClass::Reload_NPC( bPlaySound ); - int iBody = FindBodygroupByName( "bolt" ); - if (iBody != -1) - SetBodygroup( iBody, 0 ); - else - m_nSkin = 0; + SetBolt( 0 ); } #endif @@ -970,6 +967,10 @@ void CWeaponCrossbow::FireBolt( void ) m_iClip1--; +#ifdef MAPBASE + SetBolt( 1 ); +#endif + pOwner->ViewPunch( QAngle( -2, 0, 0 ) ); WeaponSound( SINGLE ); @@ -992,6 +993,18 @@ void CWeaponCrossbow::FireBolt( void ) } #ifdef MAPBASE +//----------------------------------------------------------------------------- +// Purpose: Sets whether or not the bolt is visible +//----------------------------------------------------------------------------- +inline void CWeaponCrossbow::SetBolt( int iSetting ) +{ + int iBody = FindBodygroupByName( "bolt" ); + if (iBody != -1 || (GetOwner() && GetOwner()->IsPlayer())) // HACKHACK: Player models check the viewmodel instead of the worldmodel, so we have to do this manually + SetBodygroup( iBody, iSetting ); + else + m_nSkin = iSetting; +} + //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- @@ -1015,11 +1028,7 @@ void CWeaponCrossbow::FireNPCBolt( CAI_BaseNPC *pOwner, Vector &vecShootOrigin, m_iClip1--; - int iBody = FindBodygroupByName( "bolt" ); - if (iBody != -1) - SetBodygroup( iBody, 1 ); - else - m_nSkin = 1; + SetBolt( 1 ); WeaponSound( SINGLE_NPC ); WeaponSound( SPECIAL2 ); @@ -1041,11 +1050,18 @@ bool CWeaponCrossbow::Deploy( void ) { if ( m_iClip1 <= 0 ) { +#ifdef MAPBASE + SetBolt( 1 ); +#endif return DefaultDeploy( (char*)GetViewModel(), (char*)GetWorldModel(), ACT_CROSSBOW_DRAW_UNLOADED, (char*)GetAnimPrefix() ); } SetSkin( BOLT_SKIN_GLOW ); +#ifdef MAPBASE + SetBolt( 0 ); +#endif + return BaseClass::Deploy(); } @@ -1193,6 +1209,10 @@ void CWeaponCrossbow::SetChargerState( ChargerState_t state ) // Shoot some sparks and draw a beam between the two outer points DoLoadEffect(); +#ifdef MAPBASE + SetBolt( 0 ); +#endif + break; case CHARGER_STATE_START_CHARGE: From 777f45a3237c87119eda9c7549d24df4e396ef58 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Mon, 15 Nov 2021 16:22:10 -0600 Subject: [PATCH 260/378] Added arm/disarm activities to gravity gun --- sp/src/game/server/hl2/weapon_physcannon.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sp/src/game/server/hl2/weapon_physcannon.cpp b/sp/src/game/server/hl2/weapon_physcannon.cpp index 6585a59c..8a52143c 100644 --- a/sp/src/game/server/hl2/weapon_physcannon.cpp +++ b/sp/src/game/server/hl2/weapon_physcannon.cpp @@ -1474,6 +1474,9 @@ acttable_t CWeaponPhysCannon::m_acttable[] = { ACT_HL2MP_WALK, ACT_HL2MP_WALK_PHYSGUN, false }, { ACT_HL2MP_GESTURE_RANGE_ATTACK2, ACT_HL2MP_GESTURE_RANGE_ATTACK2_PHYSGUN, false }, #endif + + { ACT_ARM, ACT_ARM_RIFLE, false }, + { ACT_DISARM, ACT_DISARM_RIFLE, false }, }; IMPLEMENT_ACTTABLE( CWeaponPhysCannon ); From 3a3d9a45b60ae255350249df6fb0175a62b98b7a Mon Sep 17 00:00:00 2001 From: Blixibon Date: Tue, 16 Nov 2021 10:27:01 -0600 Subject: [PATCH 261/378] Made the singleplayer anim state able to apply render angles from the server --- sp/src/game/client/hl2/c_basehlplayer.cpp | 28 +++++++++++++++++++ sp/src/game/client/hl2/c_basehlplayer.h | 16 ++++++++++- sp/src/game/server/hl2/hl2_player.cpp | 34 +++++++++++------------ sp/src/game/server/hl2/hl2_player.h | 5 +++- 4 files changed, 64 insertions(+), 19 deletions(-) diff --git a/sp/src/game/client/hl2/c_basehlplayer.cpp b/sp/src/game/client/hl2/c_basehlplayer.cpp index 17b3cf53..15a33ea8 100644 --- a/sp/src/game/client/hl2/c_basehlplayer.cpp +++ b/sp/src/game/client/hl2/c_basehlplayer.cpp @@ -31,6 +31,9 @@ ConVar cl_npc_speedmod_outtime( "cl_npc_speedmod_outtime", "1.5", FCVAR_CLIENTDL IMPLEMENT_CLIENTCLASS_DT(C_BaseHLPlayer, DT_HL2_Player, CHL2_Player) RecvPropDataTable( RECVINFO_DT(m_HL2Local),0, &REFERENCE_RECV_TABLE(DT_HL2Local) ), RecvPropBool( RECVINFO( m_fIsSprinting ) ), +#ifdef SP_ANIM_STATE + RecvPropFloat( RECVINFO( m_flAnimRenderYaw ) ), +#endif END_RECV_TABLE() BEGIN_PREDICTION_DATA( C_BaseHLPlayer ) @@ -90,6 +93,13 @@ void C_BaseHLPlayer::OnDataChanged( DataUpdateType_t updateType ) SetNextClientThink( CLIENT_THINK_ALWAYS ); } +#ifdef SP_ANIM_STATE + if (m_flAnimRenderYaw != FLT_MAX) + { + m_angAnimRender = QAngle( 0, m_flAnimRenderYaw, 0 ); + } +#endif + BaseClass::OnDataChanged( updateType ); } @@ -657,3 +667,21 @@ void C_BaseHLPlayer::BuildTransformations( CStudioHdr *hdr, Vector *pos, Quatern BuildFirstPersonMeathookTransformations( hdr, pos, q, cameraTransform, boneMask, boneComputed, "ValveBiped.Bip01_Head1" ); } + +#ifdef SP_ANIM_STATE +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +const QAngle& C_BaseHLPlayer::GetRenderAngles( void ) +{ + if ( m_flAnimRenderYaw != FLT_MAX ) + { + return m_angAnimRender; + } + else + { + return BaseClass::GetRenderAngles(); + } +} +#endif + diff --git a/sp/src/game/client/hl2/c_basehlplayer.h b/sp/src/game/client/hl2/c_basehlplayer.h index fe838cad..368c9bb1 100644 --- a/sp/src/game/client/hl2/c_basehlplayer.h +++ b/sp/src/game/client/hl2/c_basehlplayer.h @@ -15,6 +15,10 @@ #include "c_baseplayer.h" #include "c_hl2_playerlocaldata.h" +#if !defined( HL2MP ) && defined ( MAPBASE ) +#include "mapbase/singleplayer_animstate.h" +#endif + class C_BaseHLPlayer : public C_BasePlayer { public: @@ -58,6 +62,10 @@ public: bool IsWeaponLowered( void ) { return m_HL2Local.m_bWeaponLowered; } +#ifdef SP_ANIM_STATE + virtual const QAngle& GetRenderAngles( void ); +#endif + public: C_HL2PlayerLocalData m_HL2Local; @@ -78,7 +86,13 @@ private: bool m_bPlayUseDenySound; // Signaled by PlayerUse, but can be unset by HL2 ladder code... float m_flSpeedMod; float m_flExitSpeedMod; - + +#ifdef SP_ANIM_STATE + // At the moment, we network the render angles since almost none of the player anim stuff is done on the client in SP. + // If any of this is ever adapted for MP, this method should be replaced with replicating/moving the anim state to the client. + float m_flAnimRenderYaw; + QAngle m_angAnimRender; +#endif friend class CHL2GameMovement; }; diff --git a/sp/src/game/server/hl2/hl2_player.cpp b/sp/src/game/server/hl2/hl2_player.cpp index 903033ee..5668ee7a 100644 --- a/sp/src/game/server/hl2/hl2_player.cpp +++ b/sp/src/game/server/hl2/hl2_player.cpp @@ -630,10 +630,6 @@ END_SCRIPTDESC(); CHL2_Player::CHL2_Player() { -#ifdef SP_ANIM_STATE - m_angEyeAngles.Init(); -#endif - m_nNumMissPositions = 0; m_pPlayerAISquad = 0; m_bSprintEnabled = true; @@ -674,6 +670,9 @@ CSuitPowerDevice SuitDeviceCustom[] = IMPLEMENT_SERVERCLASS_ST(CHL2_Player, DT_HL2_Player) SendPropDataTable(SENDINFO_DT(m_HL2Local), &REFERENCE_SEND_TABLE(DT_HL2Local), SendProxy_SendLocalDataTable), SendPropBool( SENDINFO(m_fIsSprinting) ), +#ifdef SP_ANIM_STATE + SendPropFloat( SENDINFO(m_flAnimRenderYaw), 0, SPROP_NOSCALE ), +#endif END_SEND_TABLE() @@ -1161,13 +1160,10 @@ void CHL2_Player::PostThink( void ) #ifdef SP_ANIM_STATE if (m_pPlayerAnimState) { - m_angEyeAngles = EyeAngles(); + QAngle angEyeAngles = EyeAngles(); + m_pPlayerAnimState->Update( angEyeAngles.y, angEyeAngles.x ); - QAngle angles = GetLocalAngles(); - angles[PITCH] = 0; - SetLocalAngles(angles); - - m_pPlayerAnimState->Update( m_angEyeAngles.y, m_angEyeAngles.x ); + m_flAnimRenderYaw.Set( m_pPlayerAnimState->GetRenderAngles().y ); } #endif } @@ -1409,18 +1405,22 @@ CStudioHdr *CHL2_Player::OnNewModel() CStudioHdr *hdr = BaseClass::OnNewModel(); #ifdef SP_ANIM_STATE + // Clears the animation state if we already have one. + if ( m_pPlayerAnimState != NULL ) + { + m_pPlayerAnimState->Release(); + m_pPlayerAnimState = NULL; + } + if ( hdr && hdr->HaveSequenceForActivity(ACT_HL2MP_IDLE) && hl2_use_sp_animstate.GetBool() ) { - // Clears the animation state if we already have one. - if ( m_pPlayerAnimState != NULL ) - { - m_pPlayerAnimState->Release(); - m_pPlayerAnimState = NULL; - } - // Here we create and init the player animation state. m_pPlayerAnimState = CreatePlayerAnimationState(this); } + else + { + m_flAnimRenderYaw = FLT_MAX; + } #endif return hdr; diff --git a/sp/src/game/server/hl2/hl2_player.h b/sp/src/game/server/hl2/hl2_player.h index 0f0087c4..9f418269 100644 --- a/sp/src/game/server/hl2/hl2_player.h +++ b/sp/src/game/server/hl2/hl2_player.h @@ -442,7 +442,10 @@ private: #ifdef SP_ANIM_STATE CSinglePlayerAnimState* m_pPlayerAnimState; - QAngle m_angEyeAngles; + + // At the moment, we network the render angles since almost none of the player anim stuff is done on the client in SP. + // If any of this is ever adapted for MP, this method should be replaced with replicating/moving the anim state to the client. + CNetworkVar( float, m_flAnimRenderYaw ); #endif }; From 1b1218f5fe0bb4076cd1f40f66b577ea1f4d39ab Mon Sep 17 00:00:00 2001 From: Blixibon Date: Tue, 16 Nov 2021 10:27:24 -0600 Subject: [PATCH 262/378] Fixed singleplayer anim state reload not working --- sp/src/game/shared/mapbase/singleplayer_animstate.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sp/src/game/shared/mapbase/singleplayer_animstate.cpp b/sp/src/game/shared/mapbase/singleplayer_animstate.cpp index 380dbd89..251681da 100644 --- a/sp/src/game/shared/mapbase/singleplayer_animstate.cpp +++ b/sp/src/game/shared/mapbase/singleplayer_animstate.cpp @@ -282,6 +282,10 @@ void CSinglePlayerAnimState::ClearAnimationState() m_bReloading = false; m_bWeaponSwitching = false; m_bPlayingMisc = false; + m_flReloadBlendIn = 0.0f; + m_flReloadBlendOut = 0.0f; + m_flMiscBlendIn = 0.0f; + m_flMiscBlendOut = 0.0f; CBasePlayerAnimState::ClearAnimationState(); } From 045cc293f3f553dd72795146ed525c67737bac00 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Tue, 16 Nov 2021 13:20:24 -0600 Subject: [PATCH 263/378] Removed some redundant singleplayer animation state code --- .../shared/mapbase/singleplayer_animstate.cpp | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/sp/src/game/shared/mapbase/singleplayer_animstate.cpp b/sp/src/game/shared/mapbase/singleplayer_animstate.cpp index 251681da..53f4e284 100644 --- a/sp/src/game/shared/mapbase/singleplayer_animstate.cpp +++ b/sp/src/game/shared/mapbase/singleplayer_animstate.cpp @@ -497,10 +497,6 @@ void CSinglePlayerAnimState::ComputePoseParam_BodyYaw( void ) //----------------------------------------------------------------------------- void CSinglePlayerAnimState::ComputePoseParam_BodyLookYaw( void ) { - QAngle absangles = GetOuter()->GetAbsAngles(); - absangles.y = AngleNormalize( absangles.y ); - m_angRender = absangles; - // See if we even have a blender for pitch int upper_body_yaw = GetOuter()->LookupPoseParameter( "aim_yaw" ); if ( upper_body_yaw < 0 ) @@ -619,11 +615,6 @@ void CSinglePlayerAnimState::ComputePoseParam_BodyLookYaw( void ) } } - // Rotate entire body into position - absangles = GetOuter()->GetAbsAngles(); - absangles.y = m_flCurrentFeetYaw; - m_angRender = absangles; - GetOuter()->SetPoseParameter( upper_body_yaw, clamp( m_flCurrentTorsoYaw, -60.0f, 60.0f ) ); /* @@ -652,10 +643,6 @@ void CSinglePlayerAnimState::ComputePoseParam_BodyPitch( CStudioHdr *pStudioHdr } flPitch = clamp( flPitch, -90, 90 ); - QAngle absangles = GetOuter()->GetAbsAngles(); - absangles.x = 0.0f; - m_angRender = absangles; - // See if we have a blender for pitch GetOuter()->SetPoseParameter( pStudioHdr, "aim_pitch", flPitch ); @@ -678,9 +665,5 @@ void CSinglePlayerAnimState::ComputePoseParam_HeadPitch( CStudioHdr *pStudioHdr } flPitch = clamp( flPitch, -90, 90 ); - QAngle absangles = GetOuter()->GetAbsAngles(); - absangles.x = 0.0f; - m_angRender = absangles; - GetOuter()->SetPoseParameter( pStudioHdr, iHeadPitch, flPitch ); } From dc6d4e09634fc53ccac67c937c6ed72b0d188832 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Wed, 17 Nov 2021 00:19:46 -0600 Subject: [PATCH 264/378] Applied even more player animations to SP HL2 weapons --- sp/src/game/server/hl2/weapon_crossbow.cpp | 4 ++++ sp/src/game/server/hl2/weapon_physcannon.cpp | 3 +++ 2 files changed, 7 insertions(+) diff --git a/sp/src/game/server/hl2/weapon_crossbow.cpp b/sp/src/game/server/hl2/weapon_crossbow.cpp index 71df75f3..2dc487da 100644 --- a/sp/src/game/server/hl2/weapon_crossbow.cpp +++ b/sp/src/game/server/hl2/weapon_crossbow.cpp @@ -828,6 +828,10 @@ void CWeaponCrossbow::PrimaryAttack( void ) { m_iPrimaryAttacks++; gamestats->Event_WeaponFired( pPlayer, true, GetClassname() ); + +#ifdef MAPBASE + pPlayer->SetAnimation( PLAYER_ATTACK1 ); +#endif } } diff --git a/sp/src/game/server/hl2/weapon_physcannon.cpp b/sp/src/game/server/hl2/weapon_physcannon.cpp index 8a52143c..842d6a5f 100644 --- a/sp/src/game/server/hl2/weapon_physcannon.cpp +++ b/sp/src/game/server/hl2/weapon_physcannon.cpp @@ -1765,6 +1765,9 @@ void CWeaponPhysCannon::DryFire( void ) if ( pOwner ) { pOwner->RumbleEffect( RUMBLE_PISTOL, 0, RUMBLE_FLAG_RESTART ); +#ifdef MAPBASE // TODO: Is this animation too dramatic? + pOwner->SetAnimation( PLAYER_ATTACK1 ); +#endif } } From 4d0ca13efb2ece02206e3d4c7889d4c2f777d0c4 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Wed, 17 Nov 2021 00:20:48 -0600 Subject: [PATCH 265/378] Renamed the new HL2:DM "357" activities to "REVOLVER" activities --- sp/src/game/server/ai_activity.cpp | 18 +++++++++--------- sp/src/game/server/hl2/weapon_357.cpp | 18 +++++++++--------- sp/src/game/shared/activitylist.cpp | 18 +++++++++--------- sp/src/game/shared/ai_activity.h | 18 +++++++++--------- 4 files changed, 36 insertions(+), 36 deletions(-) diff --git a/sp/src/game/server/ai_activity.cpp b/sp/src/game/server/ai_activity.cpp index f1a36cf8..4fd0300b 100644 --- a/sp/src/game/server/ai_activity.cpp +++ b/sp/src/game/server/ai_activity.cpp @@ -2370,15 +2370,15 @@ void CAI_BaseNPC::InitDefaultActivitySR(void) ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RANGE_ATTACK2_MELEE ); ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RANGE_ATTACK2_SLAM ); - ADD_ACTIVITY_TO_SR( ACT_HL2MP_IDLE_357 ); - ADD_ACTIVITY_TO_SR( ACT_HL2MP_RUN_357 ); - ADD_ACTIVITY_TO_SR( ACT_HL2MP_WALK_357 ); - ADD_ACTIVITY_TO_SR( ACT_HL2MP_IDLE_CROUCH_357 ); - ADD_ACTIVITY_TO_SR( ACT_HL2MP_WALK_CROUCH_357 ); - ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RANGE_ATTACK_357 ); - ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RANGE_ATTACK2_357 ); - ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RELOAD_357 ); - ADD_ACTIVITY_TO_SR( ACT_HL2MP_JUMP_357 ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_IDLE_REVOLVER ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_RUN_REVOLVER ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_WALK_REVOLVER ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_IDLE_CROUCH_REVOLVER ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_WALK_CROUCH_REVOLVER ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RANGE_ATTACK_REVOLVER ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RANGE_ATTACK2_REVOLVER ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RELOAD_REVOLVER ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_JUMP_REVOLVER ); #endif } diff --git a/sp/src/game/server/hl2/weapon_357.cpp b/sp/src/game/server/hl2/weapon_357.cpp index b0ae2131..38a15246 100644 --- a/sp/src/game/server/hl2/weapon_357.cpp +++ b/sp/src/game/server/hl2/weapon_357.cpp @@ -202,15 +202,15 @@ acttable_t CWeapon357::m_acttable[] = #ifdef MAPBASE // HL2:DM activities (for third-person animations in SP) #ifdef EXPANDED_HL2DM_ACTIVITIES - { ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_357, false }, - { ACT_HL2MP_RUN, ACT_HL2MP_RUN_357, false }, - { ACT_HL2MP_WALK, ACT_HL2MP_WALK_357, false }, - { ACT_HL2MP_IDLE_CROUCH, ACT_HL2MP_IDLE_CROUCH_357, false }, - { ACT_HL2MP_WALK_CROUCH, ACT_HL2MP_WALK_CROUCH_357, false }, - { ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_357, false }, - { ACT_HL2MP_GESTURE_RANGE_ATTACK2, ACT_HL2MP_GESTURE_RANGE_ATTACK2_357, false }, - { ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_357, false }, - { ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_357, false }, + { ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_REVOLVER, false }, + { ACT_HL2MP_RUN, ACT_HL2MP_RUN_REVOLVER, false }, + { ACT_HL2MP_WALK, ACT_HL2MP_WALK_REVOLVER, false }, + { ACT_HL2MP_IDLE_CROUCH, ACT_HL2MP_IDLE_CROUCH_REVOLVER, false }, + { ACT_HL2MP_WALK_CROUCH, ACT_HL2MP_WALK_CROUCH_REVOLVER, false }, + { ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_REVOLVER, false }, + { ACT_HL2MP_GESTURE_RANGE_ATTACK2, ACT_HL2MP_GESTURE_RANGE_ATTACK2_REVOLVER, false }, + { ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_REVOLVER, false }, + { ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_REVOLVER, false }, #else { ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_PISTOL, false }, { ACT_HL2MP_RUN, ACT_HL2MP_RUN_PISTOL, false }, diff --git a/sp/src/game/shared/activitylist.cpp b/sp/src/game/shared/activitylist.cpp index 4493a50c..e7326e64 100644 --- a/sp/src/game/shared/activitylist.cpp +++ b/sp/src/game/shared/activitylist.cpp @@ -2486,15 +2486,15 @@ void ActivityList_RegisterSharedActivities( void ) REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RANGE_ATTACK2_MELEE ); REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RANGE_ATTACK2_SLAM ); - REGISTER_SHARED_ACTIVITY( ACT_HL2MP_IDLE_357 ); - REGISTER_SHARED_ACTIVITY( ACT_HL2MP_RUN_357 ); - REGISTER_SHARED_ACTIVITY( ACT_HL2MP_WALK_357 ); - REGISTER_SHARED_ACTIVITY( ACT_HL2MP_IDLE_CROUCH_357 ); - REGISTER_SHARED_ACTIVITY( ACT_HL2MP_WALK_CROUCH_357 ); - REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RANGE_ATTACK_357 ); - REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RANGE_ATTACK2_357 ); - REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RELOAD_357 ); - REGISTER_SHARED_ACTIVITY( ACT_HL2MP_JUMP_357 ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_IDLE_REVOLVER ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_RUN_REVOLVER ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_WALK_REVOLVER ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_IDLE_CROUCH_REVOLVER ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_WALK_CROUCH_REVOLVER ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RANGE_ATTACK_REVOLVER ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RANGE_ATTACK2_REVOLVER ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RELOAD_REVOLVER ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_JUMP_REVOLVER ); #endif AssertMsg( g_HighestActivity == LAST_SHARED_ACTIVITY - 1, "Not all activities from ai_activity.h registered in activitylist.cpp" ); diff --git a/sp/src/game/shared/ai_activity.h b/sp/src/game/shared/ai_activity.h index e73c571a..39cc48fc 100644 --- a/sp/src/game/shared/ai_activity.h +++ b/sp/src/game/shared/ai_activity.h @@ -2374,15 +2374,15 @@ typedef enum ACT_HL2MP_GESTURE_RANGE_ATTACK2_MELEE, ACT_HL2MP_GESTURE_RANGE_ATTACK2_SLAM, - ACT_HL2MP_IDLE_357, - ACT_HL2MP_RUN_357, - ACT_HL2MP_WALK_357, - ACT_HL2MP_IDLE_CROUCH_357, - ACT_HL2MP_WALK_CROUCH_357, - ACT_HL2MP_GESTURE_RANGE_ATTACK_357, - ACT_HL2MP_GESTURE_RANGE_ATTACK2_357, - ACT_HL2MP_GESTURE_RELOAD_357, - ACT_HL2MP_JUMP_357, + ACT_HL2MP_IDLE_REVOLVER, + ACT_HL2MP_RUN_REVOLVER, + ACT_HL2MP_WALK_REVOLVER, + ACT_HL2MP_IDLE_CROUCH_REVOLVER, + ACT_HL2MP_WALK_CROUCH_REVOLVER, + ACT_HL2MP_GESTURE_RANGE_ATTACK_REVOLVER, + ACT_HL2MP_GESTURE_RANGE_ATTACK2_REVOLVER, + ACT_HL2MP_GESTURE_RELOAD_REVOLVER, + ACT_HL2MP_JUMP_REVOLVER, #endif // this is the end of the global activities, private per-monster activities start here. From 049c513ccefafe1ca4dbf1666d291ce93c8aef6d Mon Sep 17 00:00:00 2001 From: Blixibon Date: Thu, 18 Nov 2021 13:04:26 -0600 Subject: [PATCH 266/378] Clarified notes regarding new toolsets --- sp/src/vpc_scripts/newer_vs_toolsets.vpc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sp/src/vpc_scripts/newer_vs_toolsets.vpc b/sp/src/vpc_scripts/newer_vs_toolsets.vpc index 447b3cec..950e1677 100644 --- a/sp/src/vpc_scripts/newer_vs_toolsets.vpc +++ b/sp/src/vpc_scripts/newer_vs_toolsets.vpc @@ -13,8 +13,9 @@ $Conditional VS2019 "0" // Toggles Visual Studio 2019 (v142) toolset $Conditional VS2022 "0" // Toggles Visual Studio 2022 (v143) toolset // -// Note that the following projects currently do not compile with any of the above toolsets and are not included in -// their solutions: +// VPC may still say "Generating for Visual Studio 2013" even when using one of the above toolsets. This message is irrelevant and can be ignored. +// +// The following projects currently do not compile with any of the above toolsets and are not included in their solutions: // // - phonemeextractor (may be fixable with modification) // - qc_eyes (might be fixed by having C++ MFC for v141 build tools and/or C++ ATL for v141 build tools installed) From 4ac5a2f3311f8813b0ecb61522d65fae9194a3e7 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Thu, 18 Nov 2021 13:05:21 -0600 Subject: [PATCH 267/378] Added recent PRs to README --- README | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README b/README index ce19b772..f51ed144 100644 --- a/README +++ b/README @@ -125,6 +125,8 @@ Direct contributions: =-- https://github.com/mapbase-source/source-sdk-2013/pull/124 (Memory error fixes) =-- https://github.com/mapbase-source/source-sdk-2013/pull/132 (Console error fix) =-- https://github.com/mapbase-source/source-sdk-2013/pull/152 (Additional GCC/Linux compilation fixes) +=-- https://github.com/mapbase-source/source-sdk-2013/pull/159 (Additional GCC/Linux compilation fixes) +=-- https://github.com/mapbase-source/source-sdk-2013/pull/162 (VS2019 exception specification fix) //--------------------------------------------------------------------------------------------------------------------------------------------------- From ebfd7158434a793a720977619627df35adda3284 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Thu, 18 Nov 2021 20:31:37 -0600 Subject: [PATCH 268/378] Fixed a mistake in the README's referenced PRs --- README | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README b/README index f51ed144..a8b0244f 100644 --- a/README +++ b/README @@ -122,7 +122,8 @@ Direct contributions: =-- https://github.com/mapbase-source/source-sdk-2013/pull/95 (Additional GCC/Linux compilation fixes) =-- https://github.com/mapbase-source/source-sdk-2013/pull/117 (Additional GCC/Linux compilation fixes) =-- https://github.com/mapbase-source/source-sdk-2013/pull/124 (Memory error fixes) -=-- https://github.com/mapbase-source/source-sdk-2013/pull/124 (Memory error fixes) +=-- https://github.com/mapbase-source/source-sdk-2013/pull/130 (Memory error fixes) +=-- https://github.com/mapbase-source/source-sdk-2013/pull/131 (env_projectedtexture target shadows fix) =-- https://github.com/mapbase-source/source-sdk-2013/pull/132 (Console error fix) =-- https://github.com/mapbase-source/source-sdk-2013/pull/152 (Additional GCC/Linux compilation fixes) =-- https://github.com/mapbase-source/source-sdk-2013/pull/159 (Additional GCC/Linux compilation fixes) From 7dab0390997aad25cad8cd1bbfa665c9665bdbf1 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Thu, 18 Nov 2021 23:21:28 -0600 Subject: [PATCH 269/378] Added unique annabelle activities and adjusted AI to better-handle the weapon --- sp/src/game/server/ai_activity.cpp | 7 +++ sp/src/game/server/basecombatcharacter.h | 3 ++ sp/src/game/server/hl2/npc_metropolice.cpp | 4 +- sp/src/game/server/hl2/npc_monk.cpp | 43 ++++++++++++++++++ sp/src/game/server/hl2/weapon_annabelle.cpp | 50 +++++++++++++++++++++ sp/src/game/server/hl2/weapon_shotgun.cpp | 13 ++++++ sp/src/game/shared/activitylist.cpp | 7 +++ sp/src/game/shared/ai_activity.h | 8 ++++ 8 files changed, 133 insertions(+), 2 deletions(-) diff --git a/sp/src/game/server/ai_activity.cpp b/sp/src/game/server/ai_activity.cpp index 4fd0300b..a2ac4c14 100644 --- a/sp/src/game/server/ai_activity.cpp +++ b/sp/src/game/server/ai_activity.cpp @@ -2283,6 +2283,13 @@ void CAI_BaseNPC::InitDefaultActivitySR(void) ADD_ACTIVITY_TO_SR( ACT_RANGE_ATTACK_RPG_LOW ); ADD_ACTIVITY_TO_SR( ACT_GESTURE_RANGE_ATTACK_RPG ); + ADD_ACTIVITY_TO_SR( ACT_RANGE_ATTACK_ANNABELLE ); + ADD_ACTIVITY_TO_SR( ACT_RANGE_ATTACK_ANNABELLE_LOW ); + ADD_ACTIVITY_TO_SR( ACT_GESTURE_RANGE_ATTACK_ANNABELLE ); + ADD_ACTIVITY_TO_SR( ACT_RELOAD_ANNABELLE ); + ADD_ACTIVITY_TO_SR( ACT_RELOAD_ANNABELLE_LOW ); + ADD_ACTIVITY_TO_SR( ACT_GESTURE_RELOAD_ANNABELLE ); + ADD_ACTIVITY_TO_SR( ACT_WALK_MELEE ); ADD_ACTIVITY_TO_SR( ACT_RUN_MELEE ); diff --git a/sp/src/game/server/basecombatcharacter.h b/sp/src/game/server/basecombatcharacter.h index d2d76394..ccdd16c8 100644 --- a/sp/src/game/server/basecombatcharacter.h +++ b/sp/src/game/server/basecombatcharacter.h @@ -412,6 +412,9 @@ public: } void SetCurrentWeaponProficiency( WeaponProficiency_t iProficiency ) { m_CurrentWeaponProficiency = iProficiency; } virtual WeaponProficiency_t CalcWeaponProficiency( CBaseCombatWeapon *pWeapon ); +#ifdef MAPBASE + inline bool OverridingWeaponProficiency() { return (m_ProficiencyOverride > WEAPON_PROFICIENCY_INVALID); } +#endif virtual Vector GetAttackSpread( CBaseCombatWeapon *pWeapon, CBaseEntity *pTarget = NULL ); virtual float GetSpreadBias( CBaseCombatWeapon *pWeapon, CBaseEntity *pTarget ); virtual void DoMuzzleFlash(); diff --git a/sp/src/game/server/hl2/npc_metropolice.cpp b/sp/src/game/server/hl2/npc_metropolice.cpp index a8579647..229db7b0 100644 --- a/sp/src/game/server/hl2/npc_metropolice.cpp +++ b/sp/src/game/server/hl2/npc_metropolice.cpp @@ -4933,8 +4933,8 @@ int CNPC_MetroPolice::SelectSchedule( void ) if ( !bHighHealth && !HasBaton() ) { #ifdef MAPBASE - // Don't do this with the 357 or any weapons which don't use clips - if ( GetActiveWeapon() && GetActiveWeapon()->UsesClipsForAmmo1() && GetActiveWeapon()->m_iClassname != gm_isz_class_357 && (GetActiveWeapon()->m_iClip1 <= 5) ) + // Don't do this with low-capacity weapons or weapons which don't use clips + if ( GetActiveWeapon() && GetActiveWeapon()->UsesClipsForAmmo1() && GetActiveWeapon()->GetMaxClip1() > 10 && (GetActiveWeapon()->m_iClip1 <= 5) ) #else if ( GetActiveWeapon() && (GetActiveWeapon()->m_iClip1 <= 5) ) #endif diff --git a/sp/src/game/server/hl2/npc_monk.cpp b/sp/src/game/server/hl2/npc_monk.cpp index 63a4ee6d..e517a6fe 100644 --- a/sp/src/game/server/hl2/npc_monk.cpp +++ b/sp/src/game/server/hl2/npc_monk.cpp @@ -196,6 +196,9 @@ Class_T CNPC_Monk::Classify( void ) return CLASS_PLAYER_ALLY_VITAL; } +#ifdef MAPBASE +ConVar npc_monk_use_old_acts( "npc_monk_use_old_acts", "1" ); +#endif //----------------------------------------------------------------------------- // Purpose: @@ -229,6 +232,45 @@ Activity CNPC_Monk::NPC_TranslateActivity( Activity eNewActivity ) } } +#if defined(EXPANDED_HL2_WEAPON_ACTIVITIES) && AR2_ACTIVITY_FIX == 1 + if (npc_monk_use_old_acts.GetBool()) + { + // HACKHACK: Don't break the balcony scene + if ( FStrEq( STRING(gpGlobals->mapname), "d1_town_02" ) && eNewActivity == ACT_IDLE ) + { + eNewActivity = ACT_IDLE_SMG1; + } + else + { + switch (eNewActivity) + { + case ACT_IDLE_AR2: + eNewActivity = ACT_IDLE_SMG1; + break; + + case ACT_IDLE_ANGRY_SHOTGUN: + case ACT_IDLE_ANGRY_AR2: + eNewActivity = ACT_IDLE_ANGRY_SMG1; + break; + + case ACT_WALK_AIM_SHOTGUN: + case ACT_WALK_AIM_AR2: + eNewActivity = ACT_WALK_AIM_RIFLE; + break; + + case ACT_RUN_AIM_SHOTGUN: + case ACT_RUN_AIM_AR2: + eNewActivity = ACT_RUN_AIM_RIFLE; + break; + + case ACT_RANGE_ATTACK_SHOTGUN_LOW: + case ACT_RANGE_ATTACK_AR2_LOW: + eNewActivity = ACT_RANGE_ATTACK_SMG1_LOW; + break; + } + } + } +#else // We need these so that we can pick up the shotgun to throw it in the balcony scene if ( eNewActivity == ACT_IDLE_ANGRY_SHOTGUN ) { @@ -246,6 +288,7 @@ Activity CNPC_Monk::NPC_TranslateActivity( Activity eNewActivity ) { return ACT_RANGE_ATTACK_SMG1_LOW; } +#endif return eNewActivity; } diff --git a/sp/src/game/server/hl2/weapon_annabelle.cpp b/sp/src/game/server/hl2/weapon_annabelle.cpp index 23b0c196..ae499a49 100644 --- a/sp/src/game/server/hl2/weapon_annabelle.cpp +++ b/sp/src/game/server/hl2/weapon_annabelle.cpp @@ -20,6 +20,11 @@ extern ConVar sk_auto_reload_time; +#ifdef MAPBASE +extern acttable_t *GetShotgunActtable(); +extern int GetShotgunActtableCount(); +#endif + class CWeaponAnnabelle : public CBaseHLCombatWeapon { DECLARE_DATADESC(); @@ -41,6 +46,16 @@ public: virtual const Vector& GetBulletSpread( void ) { static Vector cone = vec3_origin; + +#ifdef MAPBASE + if (GetOwner() && GetOwner()->OverridingWeaponProficiency()) + { + // If the owner's weapon proficiency is being overridden, return a more realistic spread + static Vector cone2 = VECTOR_CONE_6DEGREES; + return cone2; + } +#endif + return cone; } @@ -61,6 +76,11 @@ public: void Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatCharacter *pOperator ); +#ifdef MAPBASE + virtual acttable_t *GetBackupActivityList() { return GetShotgunActtable(); } + virtual int GetBackupActivityListCount() { return GetShotgunActtableCount(); } +#endif + DECLARE_ACTTABLE(); CWeaponAnnabelle(void); @@ -82,6 +102,28 @@ END_DATADESC() acttable_t CWeaponAnnabelle::m_acttable[] = { +#if defined(EXPANDED_HL2_WEAPON_ACTIVITIES) && AR2_ACTIVITY_FIX == 1 + { ACT_IDLE, ACT_IDLE_AR2, false }, + { ACT_IDLE_ANGRY, ACT_IDLE_ANGRY_AR2, true }, + { ACT_RANGE_AIM_LOW, ACT_RANGE_AIM_AR2_LOW, false }, + { ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_ANNABELLE, true }, + { ACT_RANGE_ATTACK1_LOW, ACT_RANGE_ATTACK_ANNABELLE_LOW, true }, + { ACT_RELOAD, ACT_RELOAD_ANNABELLE, true }, + { ACT_WALK, ACT_WALK_AR2, true }, + { ACT_WALK_AIM, ACT_WALK_AIM_AR2, true }, + { ACT_WALK_CROUCH, ACT_WALK_CROUCH_RIFLE, false }, + { ACT_WALK_CROUCH_AIM, ACT_WALK_CROUCH_AIM_RIFLE, false }, + { ACT_RUN, ACT_RUN_AR2, true }, + { ACT_RUN_AIM, ACT_RUN_AIM_AR2, true }, + { ACT_RUN_CROUCH, ACT_RUN_CROUCH_RIFLE, false }, + { ACT_RUN_CROUCH_AIM, ACT_RUN_CROUCH_AIM_RIFLE, false }, + { ACT_GESTURE_RANGE_ATTACK1, ACT_GESTURE_RANGE_ATTACK_ANNABELLE, true }, + { ACT_RELOAD_LOW, ACT_RELOAD_ANNABELLE_LOW, false }, + { ACT_GESTURE_RELOAD, ACT_GESTURE_RELOAD_ANNABELLE, false }, + + { ACT_ARM, ACT_ARM_RIFLE, true }, + { ACT_DISARM, ACT_DISARM_RIFLE, true }, +#else #ifdef MAPBASE { ACT_IDLE, ACT_IDLE_SMG1, false }, #endif @@ -99,6 +141,7 @@ acttable_t CWeaponAnnabelle::m_acttable[] = { ACT_GESTURE_RANGE_ATTACK1, ACT_GESTURE_RANGE_ATTACK_SHOTGUN, true }, { ACT_RELOAD_LOW, ACT_RELOAD_SMG1_LOW, false }, { ACT_GESTURE_RELOAD, ACT_GESTURE_RELOAD_SMG1, false }, +#endif #ifdef MAPBASE // HL2:DM activities (for third-person animations in SP) @@ -190,6 +233,13 @@ bool CWeaponAnnabelle::StartReload( void ) pOwner->m_flNextAttack = gpGlobals->curtime; m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration(); +#ifdef MAPBASE + if ( pOwner->IsPlayer() ) + { + static_cast(pOwner)->SetAnimation( PLAYER_RELOAD ); + } +#endif + m_bInReload = true; return true; } diff --git a/sp/src/game/server/hl2/weapon_shotgun.cpp b/sp/src/game/server/hl2/weapon_shotgun.cpp index 74656058..71df2695 100644 --- a/sp/src/game/server/hl2/weapon_shotgun.cpp +++ b/sp/src/game/server/hl2/weapon_shotgun.cpp @@ -234,6 +234,19 @@ acttable_t CWeaponShotgun::m_acttable[] = IMPLEMENT_ACTTABLE(CWeaponShotgun); +#ifdef MAPBASE +// Allows Weapon_BackupActivity() to access the shotgun's activity table. +acttable_t *GetShotgunActtable() +{ + return CWeaponShotgun::m_acttable; +} + +int GetShotgunActtableCount() +{ + return ARRAYSIZE(CWeaponShotgun::m_acttable); +} +#endif + void CWeaponShotgun::Precache( void ) { CBaseCombatWeapon::Precache(); diff --git a/sp/src/game/shared/activitylist.cpp b/sp/src/game/shared/activitylist.cpp index e7326e64..8c7d24ae 100644 --- a/sp/src/game/shared/activitylist.cpp +++ b/sp/src/game/shared/activitylist.cpp @@ -2399,6 +2399,13 @@ void ActivityList_RegisterSharedActivities( void ) REGISTER_SHARED_ACTIVITY( ACT_RANGE_ATTACK_RPG_LOW ); REGISTER_SHARED_ACTIVITY( ACT_GESTURE_RANGE_ATTACK_RPG ); + REGISTER_SHARED_ACTIVITY( ACT_RANGE_ATTACK_ANNABELLE ); + REGISTER_SHARED_ACTIVITY( ACT_RANGE_ATTACK_ANNABELLE_LOW ); + REGISTER_SHARED_ACTIVITY( ACT_GESTURE_RANGE_ATTACK_ANNABELLE ); + REGISTER_SHARED_ACTIVITY( ACT_RELOAD_ANNABELLE ); + REGISTER_SHARED_ACTIVITY( ACT_RELOAD_ANNABELLE_LOW ); + REGISTER_SHARED_ACTIVITY( ACT_GESTURE_RELOAD_ANNABELLE ); + REGISTER_SHARED_ACTIVITY( ACT_WALK_MELEE ); REGISTER_SHARED_ACTIVITY( ACT_RUN_MELEE ); diff --git a/sp/src/game/shared/ai_activity.h b/sp/src/game/shared/ai_activity.h index 39cc48fc..7177c5cd 100644 --- a/sp/src/game/shared/ai_activity.h +++ b/sp/src/game/shared/ai_activity.h @@ -2282,6 +2282,14 @@ typedef enum ACT_RANGE_ATTACK_RPG_LOW, ACT_GESTURE_RANGE_ATTACK_RPG, + // Annabelle + ACT_RANGE_ATTACK_ANNABELLE, + ACT_RANGE_ATTACK_ANNABELLE_LOW, + ACT_GESTURE_RANGE_ATTACK_ANNABELLE, + ACT_RELOAD_ANNABELLE, + ACT_RELOAD_ANNABELLE_LOW, + ACT_GESTURE_RELOAD_ANNABELLE, + // Melee ACT_WALK_MELEE, ACT_RUN_MELEE, From 013da89b2762c00f067335f54de9a6319eab69ca Mon Sep 17 00:00:00 2001 From: Blixibon Date: Thu, 18 Nov 2021 23:23:09 -0600 Subject: [PATCH 270/378] Fixed issues with unique cases in companion readiness --- .../game/server/hl2/npc_playercompanion.cpp | 22 +++++++++++++++---- sp/src/game/server/hl2/npc_playercompanion.h | 3 +++ 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/sp/src/game/server/hl2/npc_playercompanion.cpp b/sp/src/game/server/hl2/npc_playercompanion.cpp index 97901f93..08def106 100644 --- a/sp/src/game/server/hl2/npc_playercompanion.cpp +++ b/sp/src/game/server/hl2/npc_playercompanion.cpp @@ -1956,10 +1956,9 @@ bool CNPC_PlayerCompanion::IsReadinessCapable() { // Rather than looking up the activity string, we just make sure our weapon accepts a few basic readiness activity overrides. // This lets us make sure our weapon is readiness-capable to begin with. - CBaseCombatWeapon *pWeapon = GetActiveWeapon(); - if ( pWeapon->ActivityOverride(ACT_IDLE_RELAXED, NULL) == ACT_IDLE_RELAXED && - pWeapon->ActivityOverride( ACT_IDLE_STIMULATED, NULL ) == ACT_IDLE_STIMULATED && - pWeapon->ActivityOverride( ACT_IDLE_AGITATED, NULL ) == ACT_IDLE_AGITATED ) + if ( TranslateActivity( ACT_IDLE_RELAXED ) == ACT_IDLE_RELAXED && + TranslateActivity( ACT_IDLE_STIMULATED ) == ACT_IDLE_STIMULATED && + TranslateActivity( ACT_IDLE_AGITATED ) == ACT_IDLE_AGITATED ) return false; if (LookupActivity( "ACT_IDLE_AIM_RIFLE_STIMULATED" ) == ACT_INVALID) @@ -2797,6 +2796,21 @@ void CNPC_PlayerCompanion::Weapon_Equip( CBaseCombatWeapon *pWeapon ) m_bReadinessCapable = IsReadinessCapable(); } +#ifdef MAPBASE +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +bool CNPC_PlayerCompanion::DoUnholster() +{ + if ( BaseClass::DoUnholster() ) + { + m_bReadinessCapable = IsReadinessCapable(); + return true; + } + + return false; +} +#endif + //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ void CNPC_PlayerCompanion::PickupWeapon( CBaseCombatWeapon *pWeapon ) diff --git a/sp/src/game/server/hl2/npc_playercompanion.h b/sp/src/game/server/hl2/npc_playercompanion.h index ce23058b..8dcf1aa1 100644 --- a/sp/src/game/server/hl2/npc_playercompanion.h +++ b/sp/src/game/server/hl2/npc_playercompanion.h @@ -282,6 +282,9 @@ public: bool ShouldLookForBetterWeapon(); bool Weapon_CanUse( CBaseCombatWeapon *pWeapon ); void Weapon_Equip( CBaseCombatWeapon *pWeapon ); +#ifdef MAPBASE + bool DoUnholster( void ); +#endif void PickupWeapon( CBaseCombatWeapon *pWeapon ); #if COMPANION_MELEE_ATTACK From db0b51bf76199ac1a146be321b935053184a8714 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Thu, 18 Nov 2021 23:23:58 -0600 Subject: [PATCH 271/378] Fixed ForcePrimaryFire not working on RPG --- sp/src/game/server/hl2/weapon_rpg.cpp | 48 +++++++++++++++++++++++++++ sp/src/game/server/hl2/weapon_rpg.h | 3 ++ 2 files changed, 51 insertions(+) diff --git a/sp/src/game/server/hl2/weapon_rpg.cpp b/sp/src/game/server/hl2/weapon_rpg.cpp index 750dbf8a..36a60dd1 100644 --- a/sp/src/game/server/hl2/weapon_rpg.cpp +++ b/sp/src/game/server/hl2/weapon_rpg.cpp @@ -1589,6 +1589,54 @@ void CWeaponRPG::Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatChara } } +#ifdef MAPBASE +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CWeaponRPG::Operator_ForceNPCFire( CBaseCombatCharacter *pOperator, bool bSecondary ) +{ + if ( m_hMissile != NULL ) + return; + + Vector muzzlePoint, vecShootDir; + QAngle angShootDir; + GetAttachment( LookupAttachment( "muzzle" ), muzzlePoint, angShootDir ); + AngleVectors( angShootDir, &vecShootDir ); + + // look for a better launch location + Vector altLaunchPoint; + if (GetAttachment( "missile", altLaunchPoint )) + { + // check to see if it's relativly free + trace_t tr; + AI_TraceHull( altLaunchPoint, altLaunchPoint + vecShootDir * (10.0f*12.0f), Vector( -24, -24, -24 ), Vector( 24, 24, 24 ), MASK_NPCSOLID, NULL, &tr ); + + if( tr.fraction == 1.0) + { + muzzlePoint = altLaunchPoint; + } + } + + m_hMissile = CMissile::Create( muzzlePoint, angShootDir, pOperator->edict() ); + m_hMissile->m_hOwner = this; + + // NPCs always get a grace period + m_hMissile->SetGracePeriod( 0.5 ); + + pOperator->DoMuzzleFlash(); + + WeaponSound( SINGLE_NPC ); + + // Make sure our laserdot is off + m_bGuiding = false; + + if ( m_hLaserDot ) + { + m_hLaserDot->TurnOff(); + } +} +#endif + //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- diff --git a/sp/src/game/server/hl2/weapon_rpg.h b/sp/src/game/server/hl2/weapon_rpg.h index 3c9dae5f..a536d1c2 100644 --- a/sp/src/game/server/hl2/weapon_rpg.h +++ b/sp/src/game/server/hl2/weapon_rpg.h @@ -216,6 +216,9 @@ public: int WeaponRangeAttack1Condition( float flDot, float flDist ); void Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatCharacter *pOperator ); +#ifdef MAPBASE + void Operator_ForceNPCFire( CBaseCombatCharacter *pOperator, bool bSecondary ); +#endif void StartGuiding( void ); void StopGuiding( void ); void ToggleGuiding( void ); From 1d768e4816c506196a008b6617e644662cf28214 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Fri, 19 Nov 2021 13:35:00 -0600 Subject: [PATCH 272/378] Update sp/src/game/shared/mapbase/singleplayer_animstate.cpp Co-authored-by: z33ky <1zeeky@gmail.com> --- sp/src/game/shared/mapbase/singleplayer_animstate.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sp/src/game/shared/mapbase/singleplayer_animstate.cpp b/sp/src/game/shared/mapbase/singleplayer_animstate.cpp index 53f4e284..8cc9337e 100644 --- a/sp/src/game/shared/mapbase/singleplayer_animstate.cpp +++ b/sp/src/game/shared/mapbase/singleplayer_animstate.cpp @@ -23,7 +23,7 @@ #include "utldict.h" #include "filesystem.h" #include "in_buttons.h" -#include "..\public\datacache\imdlcache.h" +#include "datacache/imdlcache.h" extern ConVar mp_facefronttime, mp_feetyawrate, mp_ik; From fecddb3ecc85fa4317c30f5f7f1bcc644780c5ad Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sat, 20 Nov 2021 01:01:52 -0600 Subject: [PATCH 273/378] Added player +USE animations --- sp/src/game/server/ai_activity.cpp | 14 ++++++++ sp/src/game/server/hl2/hl2_player.cpp | 49 +++++++++++++++++++++++++++ sp/src/game/server/hl2/hl2_player.h | 2 ++ sp/src/game/shared/activitylist.cpp | 14 ++++++++ sp/src/game/shared/ai_activity.h | 14 ++++++++ 5 files changed, 93 insertions(+) diff --git a/sp/src/game/server/ai_activity.cpp b/sp/src/game/server/ai_activity.cpp index a2ac4c14..530f27a7 100644 --- a/sp/src/game/server/ai_activity.cpp +++ b/sp/src/game/server/ai_activity.cpp @@ -2386,6 +2386,20 @@ void CAI_BaseNPC::InitDefaultActivitySR(void) ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RANGE_ATTACK2_REVOLVER ); ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RELOAD_REVOLVER ); ADD_ACTIVITY_TO_SR( ACT_HL2MP_JUMP_REVOLVER ); + + ADD_ACTIVITY_TO_SR( ACT_HL2MP_IDLE_USE ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_RUN_USE ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_WALK_USE ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_IDLE_CROUCH_USE ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_WALK_CROUCH_USE ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_JUMP_USE ); + + ADD_ACTIVITY_TO_SR( ACT_HL2MP_IDLE_USE_HEAVY ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_RUN_USE_HEAVY ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_WALK_USE_HEAVY ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_IDLE_CROUCH_USE_HEAVY ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_WALK_CROUCH_USE_HEAVY ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_JUMP_USE_HEAVY ); #endif } diff --git a/sp/src/game/server/hl2/hl2_player.cpp b/sp/src/game/server/hl2/hl2_player.cpp index 5668ee7a..b7939607 100644 --- a/sp/src/game/server/hl2/hl2_player.cpp +++ b/sp/src/game/server/hl2/hl2_player.cpp @@ -1375,6 +1375,55 @@ void CHL2_Player::SpawnedAtPoint( CBaseEntity *pSpawnPoint ) //----------------------------------------------------------------------------- +ConVar player_use_anim_enabled( "player_carry_anim_enabled", "1" ); +ConVar player_use_anim_heavy_mass( "player_carry_anim_heavy_mass", "20.0" ); + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +Activity CHL2_Player::Weapon_TranslateActivity( Activity baseAct, bool *pRequired ) +{ + Activity weaponTranslation = BaseClass::Weapon_TranslateActivity( baseAct, pRequired ); + +#ifdef EXPANDED_HL2DM_ACTIVITIES + // +USE activities + if ( m_hUseEntity && player_use_anim_enabled.GetBool() ) + { + CBaseEntity* pHeldEnt = GetPlayerHeldEntity( this ); + float flMass = pHeldEnt ? + PlayerPickupGetHeldObjectMass( m_hUseEntity, pHeldEnt->VPhysicsGetObject() ) : + (m_hUseEntity->VPhysicsGetObject() ? m_hUseEntity->GetMass() : player_use_anim_heavy_mass.GetFloat()); + if ( flMass >= player_use_anim_heavy_mass.GetFloat() ) + { + // Heavy versions + switch (baseAct) + { + case ACT_HL2MP_IDLE: weaponTranslation = ACT_HL2MP_IDLE_USE_HEAVY; break; + case ACT_HL2MP_RUN: weaponTranslation = ACT_HL2MP_RUN_USE_HEAVY; break; + case ACT_HL2MP_WALK: weaponTranslation = ACT_HL2MP_WALK_USE_HEAVY; break; + case ACT_HL2MP_IDLE_CROUCH: weaponTranslation = ACT_HL2MP_IDLE_CROUCH_USE_HEAVY; break; + case ACT_HL2MP_WALK_CROUCH: weaponTranslation = ACT_HL2MP_WALK_CROUCH_USE_HEAVY; break; + case ACT_HL2MP_JUMP: weaponTranslation = ACT_HL2MP_JUMP_USE_HEAVY; break; + } + } + else + { + switch (baseAct) + { + case ACT_HL2MP_IDLE: weaponTranslation = ACT_HL2MP_IDLE_USE; break; + case ACT_HL2MP_RUN: weaponTranslation = ACT_HL2MP_RUN_USE; break; + case ACT_HL2MP_WALK: weaponTranslation = ACT_HL2MP_WALK_USE; break; + case ACT_HL2MP_IDLE_CROUCH: weaponTranslation = ACT_HL2MP_IDLE_CROUCH_USE; break; + case ACT_HL2MP_WALK_CROUCH: weaponTranslation = ACT_HL2MP_WALK_CROUCH_USE; break; + case ACT_HL2MP_JUMP: weaponTranslation = ACT_HL2MP_JUMP_USE; break; + } + } + } +#endif + + return weaponTranslation; +} + #ifdef SP_ANIM_STATE // Set the activity based on an event or current state void CHL2_Player::SetAnimation( PLAYER_ANIM playerAnim ) diff --git a/sp/src/game/server/hl2/hl2_player.h b/sp/src/game/server/hl2/hl2_player.h index 9f418269..12c0386c 100644 --- a/sp/src/game/server/hl2/hl2_player.h +++ b/sp/src/game/server/hl2/hl2_player.h @@ -132,6 +132,8 @@ public: // For the logic_playerproxy output void SpawnedAtPoint( CBaseEntity *pSpawnPoint ); + Activity Weapon_TranslateActivity( Activity baseAct, bool *pRequired = NULL ); + #ifdef SP_ANIM_STATE void SetAnimation( PLAYER_ANIM playerAnim ); diff --git a/sp/src/game/shared/activitylist.cpp b/sp/src/game/shared/activitylist.cpp index 8c7d24ae..98fe580b 100644 --- a/sp/src/game/shared/activitylist.cpp +++ b/sp/src/game/shared/activitylist.cpp @@ -2502,6 +2502,20 @@ void ActivityList_RegisterSharedActivities( void ) REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RANGE_ATTACK2_REVOLVER ); REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RELOAD_REVOLVER ); REGISTER_SHARED_ACTIVITY( ACT_HL2MP_JUMP_REVOLVER ); + + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_IDLE_USE ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_RUN_USE ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_WALK_USE ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_IDLE_CROUCH_USE ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_WALK_CROUCH_USE ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_JUMP_USE ); + + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_IDLE_USE_HEAVY ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_RUN_USE_HEAVY ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_WALK_USE_HEAVY ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_IDLE_CROUCH_USE_HEAVY ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_WALK_CROUCH_USE_HEAVY ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_JUMP_USE_HEAVY ); #endif AssertMsg( g_HighestActivity == LAST_SHARED_ACTIVITY - 1, "Not all activities from ai_activity.h registered in activitylist.cpp" ); diff --git a/sp/src/game/shared/ai_activity.h b/sp/src/game/shared/ai_activity.h index 7177c5cd..c13df83f 100644 --- a/sp/src/game/shared/ai_activity.h +++ b/sp/src/game/shared/ai_activity.h @@ -2391,6 +2391,20 @@ typedef enum ACT_HL2MP_GESTURE_RANGE_ATTACK2_REVOLVER, ACT_HL2MP_GESTURE_RELOAD_REVOLVER, ACT_HL2MP_JUMP_REVOLVER, + + ACT_HL2MP_IDLE_USE, + ACT_HL2MP_RUN_USE, + ACT_HL2MP_WALK_USE, + ACT_HL2MP_IDLE_CROUCH_USE, + ACT_HL2MP_WALK_CROUCH_USE, + ACT_HL2MP_JUMP_USE, + + ACT_HL2MP_IDLE_USE_HEAVY, + ACT_HL2MP_RUN_USE_HEAVY, + ACT_HL2MP_WALK_USE_HEAVY, + ACT_HL2MP_IDLE_CROUCH_USE_HEAVY, + ACT_HL2MP_WALK_CROUCH_USE_HEAVY, + ACT_HL2MP_JUMP_USE_HEAVY, #endif // this is the end of the global activities, private per-monster activities start here. From 37c3cd5e1c2553f7af282e30d77a64c6bd069b8d Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sat, 20 Nov 2021 01:02:16 -0600 Subject: [PATCH 274/378] Fixed bugbait player throw animation --- sp/src/game/server/hl2/weapon_bugbait.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sp/src/game/server/hl2/weapon_bugbait.cpp b/sp/src/game/server/hl2/weapon_bugbait.cpp index 330cf2c6..72967d7d 100644 --- a/sp/src/game/server/hl2/weapon_bugbait.cpp +++ b/sp/src/game/server/hl2/weapon_bugbait.cpp @@ -248,10 +248,6 @@ void CWeaponBugBait::PrimaryAttack( void ) return; SendWeaponAnim( ACT_VM_HAULBACK ); - -#ifdef MAPBASE - pPlayer->SetAnimation( PLAYER_ATTACK1 ); -#endif m_flTimeWeaponIdle = FLT_MAX; m_flNextPrimaryAttack = FLT_MAX; @@ -319,6 +315,10 @@ void CWeaponBugBait::ThrowGrenade( CBasePlayer *pPlayer ) } m_bRedraw = true; + +#ifdef MAPBASE + pPlayer->SetAnimation( PLAYER_ATTACK1 ); +#endif } //----------------------------------------------------------------------------- From b3c3ecb8a5e9f8387f9b717b57525cc97d5fff01 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sat, 20 Nov 2021 01:02:41 -0600 Subject: [PATCH 275/378] Fixed player holster animation repeating --- sp/src/game/shared/basecombatweapon_shared.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sp/src/game/shared/basecombatweapon_shared.cpp b/sp/src/game/shared/basecombatweapon_shared.cpp index 50c2ea25..e6b61249 100644 --- a/sp/src/game/shared/basecombatweapon_shared.cpp +++ b/sp/src/game/shared/basecombatweapon_shared.cpp @@ -1658,7 +1658,7 @@ bool CBaseCombatWeapon::Holster( CBaseCombatWeapon *pSwitchingTo ) pOwner->SetNextAttack( gpGlobals->curtime + flSequenceDuration ); #ifdef MAPBASE - if (pOwner->IsPlayer()) + if (IsWeaponVisible() && pOwner->IsPlayer()) static_cast(pOwner)->SetAnimation( PLAYER_HOLSTER ); #endif } From b24b1054aa0d3bf52af1d3b8129b201924aed3fe Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sat, 20 Nov 2021 20:32:46 -0600 Subject: [PATCH 276/378] Fixed func_commandredirect not cancelling orders correctly and rewrote its code/comments so that it doesn't appear to be bizarre nonsense --- sp/src/game/server/hl2/hl2_player.cpp | 39 +++++++++++++-------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/sp/src/game/server/hl2/hl2_player.cpp b/sp/src/game/server/hl2/hl2_player.cpp index b7939607..00fdbcfd 100644 --- a/sp/src/game/server/hl2/hl2_player.cpp +++ b/sp/src/game/server/hl2/hl2_player.cpp @@ -331,39 +331,41 @@ public: } // Will the command point change? - // True = Judged guilty and changed. - // False = Judged not guilty and unchanged. - bool GetVerdict(Vector *defendant, CHL2_Player *pPlayer) + // True = Command point changes + // False = Comand point doesn't change + bool TestRedirect(Vector *vecNewCommandPoint, CHL2_Player *pPlayer) { - // Deliver goal to relevant destinations before sentencing. - m_OnCommandGoal.Set(*defendant, pPlayer, this); + // Output the goal before doing anything else. + m_OnCommandGoal.Set(*vecNewCommandPoint, pPlayer, this); if (m_target == NULL_STRING) { - // Abort sentencing. + // Not targeting anything. Don't redirect and just leave it at the output return false; } else if (FStrEq(STRING(m_target), "-1")) { - // Deliver verdict immediately. - *defendant = Vector(0, 0, 0); - return false; + // Completely cancel the squad command. + *vecNewCommandPoint = vec3_origin; + return true; } else { - // Locate entity of interest. // Player is caller. // Player squad representative is activator. CBaseEntity *pEntOfInterest = gEntList.FindEntityGeneric(NULL, STRING(m_target), this, pPlayer->GetSquadCommandRepresentative(), pPlayer); if (pEntOfInterest) { - // Deliver their local origin. - *defendant = pEntOfInterest->GetLocalOrigin(); + // Use the entity's absolute origin as the new command point. + *vecNewCommandPoint = pEntOfInterest->GetAbsOrigin(); return true; } + else + { + Warning("%s couldn't find target entity \"%s\"\n", GetDebugName(), STRING(m_target)); + } } - // No sentence. return false; } @@ -1816,25 +1818,22 @@ bool CHL2_Player::CommanderFindGoal( commandgoal_t *pGoal ) if (!pCommandRedirect || pCommandRedirect->IsDisabled() || !pCommandRedirect->PointIsWithin(tr.endpos)) continue; - // First, GIVE IT OUR ALLIES so it could fire outputs + // First, give it our allies so it could fire outputs pCommandRedirect->HandleAllies(m_pPlayerAISquad, this); Vector vec = tr.endpos; - if (pCommandRedirect->GetVerdict(&vec, this)) + if (pCommandRedirect->TestRedirect(&vec, this)) { - // It doesn't want us moving, so just don't find a goal at all + // If it returned a 0 vector, cancel the command if (vec.IsZero()) { return false; } - // Just set our goal to this, the mapper didn't sign up for these checks + // Just set our goal to this and skip the code below which checks the target position's validity pGoal->m_vecGoalLocation = vec; return true; } - - // Only one should be necessary - break; } } //else From 5090c8b74326b4c452777786495eef4f87467c53 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sat, 20 Nov 2021 20:33:27 -0600 Subject: [PATCH 277/378] Fixed player +USE animation cvar aliasing issue --- sp/src/game/server/hl2/hl2_player.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sp/src/game/server/hl2/hl2_player.cpp b/sp/src/game/server/hl2/hl2_player.cpp index 00fdbcfd..afb2c1cb 100644 --- a/sp/src/game/server/hl2/hl2_player.cpp +++ b/sp/src/game/server/hl2/hl2_player.cpp @@ -1377,8 +1377,8 @@ void CHL2_Player::SpawnedAtPoint( CBaseEntity *pSpawnPoint ) //----------------------------------------------------------------------------- -ConVar player_use_anim_enabled( "player_carry_anim_enabled", "1" ); -ConVar player_use_anim_heavy_mass( "player_carry_anim_heavy_mass", "20.0" ); +ConVar player_use_anim_enabled( "player_use_anim_enabled", "1" ); +ConVar player_use_anim_heavy_mass( "player_use_anim_heavy_mass", "20.0" ); //----------------------------------------------------------------------------- // Purpose: From d2fdfd3fe1c072c0250e6675c6c76c52cd7d8e4b Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sat, 20 Nov 2021 20:37:37 -0600 Subject: [PATCH 278/378] Changed activity preprocessors to use #if instead of #ifdef --- sp/src/game/server/ai_activity.cpp | 12 ++++++------ sp/src/game/server/ai_basenpc.cpp | 8 ++++---- sp/src/game/server/ai_behavior_standoff.cpp | 8 ++++---- sp/src/game/server/ai_behavior_standoff.h | 2 +- sp/src/game/server/ai_motor.cpp | 10 +++++----- sp/src/game/server/ai_navigator.cpp | 2 +- sp/src/game/server/hl2/hl2_player.cpp | 2 +- sp/src/game/server/hl2/npc_alyx_episodic.cpp | 6 +++--- sp/src/game/server/hl2/npc_citizen17.cpp | 2 +- sp/src/game/server/hl2/npc_combine.cpp | 10 +++++----- sp/src/game/server/hl2/npc_fastzombie.cpp | 4 ++-- sp/src/game/server/hl2/weapon_357.cpp | 12 ++++++------ sp/src/game/server/hl2/weapon_alyxgun.cpp | 8 ++++---- sp/src/game/server/hl2/weapon_annabelle.cpp | 2 +- sp/src/game/server/hl2/weapon_ar2.cpp | 6 +++--- sp/src/game/server/hl2/weapon_bugbait.cpp | 2 +- sp/src/game/server/hl2/weapon_citizenpackage.cpp | 4 ++-- sp/src/game/server/hl2/weapon_crossbow.cpp | 6 +++--- sp/src/game/server/hl2/weapon_crowbar.cpp | 4 ++-- sp/src/game/server/hl2/weapon_frag.cpp | 2 +- sp/src/game/server/hl2/weapon_physcannon.cpp | 2 +- sp/src/game/server/hl2/weapon_pistol.cpp | 8 ++++---- sp/src/game/server/hl2/weapon_rpg.cpp | 8 ++++---- sp/src/game/server/hl2/weapon_shotgun.cpp | 8 ++++---- sp/src/game/server/hl2/weapon_smg1.cpp | 6 +++--- sp/src/game/server/mapbase/ai_grenade.h | 2 +- sp/src/game/shared/activitylist.cpp | 8 ++++---- sp/src/game/shared/ai_activity.h | 8 ++++---- sp/src/game/shared/basecombatweapon_shared.cpp | 4 ++-- sp/src/game/shared/hl2mp/weapon_slam.cpp | 2 +- sp/src/game/shared/hl2mp/weapon_stunstick.cpp | 4 ++-- .../game/shared/mapbase/singleplayer_animstate.cpp | 4 ++-- 32 files changed, 88 insertions(+), 88 deletions(-) diff --git a/sp/src/game/server/ai_activity.cpp b/sp/src/game/server/ai_activity.cpp index 530f27a7..dc090f7e 100644 --- a/sp/src/game/server/ai_activity.cpp +++ b/sp/src/game/server/ai_activity.cpp @@ -2187,7 +2187,7 @@ void CAI_BaseNPC::InitDefaultActivitySR(void) ADD_ACTIVITY_TO_SR( ACT_COVER_AR2_LOW ); #endif -#ifdef SHARED_COMBINE_ACTIVITIES +#if SHARED_COMBINE_ACTIVITIES ADD_ACTIVITY_TO_SR( ACT_COMBINE_THROW_GRENADE ); ADD_ACTIVITY_TO_SR( ACT_COMBINE_AR2_ALTFIRE ); @@ -2205,7 +2205,7 @@ void CAI_BaseNPC::InitDefaultActivitySR(void) ADD_ACTIVITY_TO_SR( ACT_GESTURE_SIGNAL_TAKECOVER ); #endif -#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES +#if EXPANDED_HL2_WEAPON_ACTIVITIES ADD_ACTIVITY_TO_SR( ACT_IDLE_REVOLVER ); ADD_ACTIVITY_TO_SR( ACT_IDLE_ANGRY_REVOLVER ); ADD_ACTIVITY_TO_SR( ACT_WALK_REVOLVER ); @@ -2315,7 +2315,7 @@ void CAI_BaseNPC::InitDefaultActivitySR(void) ADD_ACTIVITY_TO_SR( ACT_CLIMB_DISMOUNT_BOTTOM ); #endif -#ifdef EXPANDED_HL2_COVER_ACTIVITIES +#if EXPANDED_HL2_COVER_ACTIVITIES ADD_ACTIVITY_TO_SR( ACT_RANGE_ATTACK1_MED ); ADD_ACTIVITY_TO_SR( ACT_RANGE_ATTACK2_MED ); ADD_ACTIVITY_TO_SR( ACT_RANGE_AIM_MED ); @@ -2352,7 +2352,7 @@ void CAI_BaseNPC::InitDefaultActivitySR(void) ADD_ACTIVITY_TO_SR( ACT_COVER_WALL_LOW_L_PISTOL ); #endif -#ifdef EXPANDED_HL2DM_ACTIVITIES +#if EXPANDED_HL2DM_ACTIVITIES ADD_ACTIVITY_TO_SR( ACT_HL2MP_WALK ); ADD_ACTIVITY_TO_SR( ACT_HL2MP_WALK_PISTOL ); ADD_ACTIVITY_TO_SR( ACT_HL2MP_WALK_SHOTGUN ); @@ -2457,7 +2457,7 @@ CAI_BaseNPC::actlink_t CAI_BaseNPC::gm_ActivityGestureLinks[] = { ACT_RELOAD_PISTOL, ACT_GESTURE_RELOAD_PISTOL }, { ACT_RELOAD_PISTOL_LOW, ACT_GESTURE_RELOAD_PISTOL }, -#ifdef SHARED_COMBINE_ACTIVITIES +#if SHARED_COMBINE_ACTIVITIES { ACT_SPECIAL_ATTACK1, ACT_GESTURE_SPECIAL_ATTACK1 }, { ACT_SPECIAL_ATTACK2, ACT_GESTURE_SPECIAL_ATTACK2 }, { ACT_COMBINE_THROW_GRENADE, ACT_GESTURE_COMBINE_THROW_GRENADE }, @@ -2472,7 +2472,7 @@ CAI_BaseNPC::actlink_t CAI_BaseNPC::gm_ActivityGestureLinks[] = { ACT_SIGNAL_TAKECOVER, ACT_GESTURE_SIGNAL_TAKECOVER }, #endif -#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES +#if EXPANDED_HL2_WEAPON_ACTIVITIES { ACT_RANGE_ATTACK_REVOLVER, ACT_GESTURE_RANGE_ATTACK_REVOLVER }, { ACT_RANGE_ATTACK_REVOLVER_LOW, ACT_GESTURE_RANGE_ATTACK_REVOLVER }, { ACT_RANGE_ATTACK_CROSSBOW, ACT_GESTURE_RANGE_ATTACK_CROSSBOW }, diff --git a/sp/src/game/server/ai_basenpc.cpp b/sp/src/game/server/ai_basenpc.cpp index d9ad0e60..8c3fbc61 100644 --- a/sp/src/game/server/ai_basenpc.cpp +++ b/sp/src/game/server/ai_basenpc.cpp @@ -6555,7 +6555,7 @@ Activity CAI_BaseNPC::TranslateCrouchActivity( Activity eNewActivity ) } else if (pHint->HintType() == HINT_TACTICAL_COVER_MED) { -#ifdef EXPANDED_HL2_COVER_ACTIVITIES +#if EXPANDED_HL2_COVER_ACTIVITIES nCoverActivity = ACT_RANGE_ATTACK1_MED; #else nCoverActivity = ACT_RANGE_ATTACK1_LOW; @@ -6626,7 +6626,7 @@ Activity CAI_BaseNPC::NPC_BackupActivity( Activity eNewActivity ) switch (eNewActivity) { case ACT_COVER_MED: eNewActivity = ACT_COVER_LOW; break; -#ifdef EXPANDED_HL2_COVER_ACTIVITIES +#if EXPANDED_HL2_COVER_ACTIVITIES case ACT_RANGE_AIM_MED: eNewActivity = ACT_RANGE_AIM_LOW; break; case ACT_RANGE_ATTACK1_MED: eNewActivity = ACT_RANGE_ATTACK1_LOW; break; #endif @@ -6646,7 +6646,7 @@ Activity CAI_BaseNPC::NPC_BackupActivity( Activity eNewActivity ) //----------------------------------------------------------------------------- Activity CAI_BaseNPC::NPC_TranslateActivity( Activity eNewActivity ) { -#ifdef EXPANDED_NAVIGATION_ACTIVITIES +#if EXPANDED_NAVIGATION_ACTIVITIES if ( GetNavType() == NAV_CLIMB && eNewActivity == ACT_IDLE ) { // Schedules which break into idle activities should try to maintain the climbing animation. @@ -16293,7 +16293,7 @@ bool CAI_BaseNPC::IsCrouchedActivity( Activity activity ) #endif case ACT_RELOAD_PISTOL_LOW: case ACT_RELOAD_SHOTGUN_LOW: -#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES +#if EXPANDED_HL2_WEAPON_ACTIVITIES case ACT_RELOAD_REVOLVER_LOW: case ACT_RELOAD_CROSSBOW_LOW: #endif diff --git a/sp/src/game/server/ai_behavior_standoff.cpp b/sp/src/game/server/ai_behavior_standoff.cpp index 85740876..29c89e39 100644 --- a/sp/src/game/server/ai_behavior_standoff.cpp +++ b/sp/src/game/server/ai_behavior_standoff.cpp @@ -558,7 +558,7 @@ int CAI_StandoffBehavior::SelectScheduleEstablishAim( void ) { if ( HasCondition( COND_ENEMY_OCCLUDED ) ) { -#ifdef EXPANDED_HL2_COVER_ACTIVITIES +#if EXPANDED_HL2_COVER_ACTIVITIES if ( GetPosture() == AIP_CROUCHING || GetPosture() == AIP_CROUCHING_MED ) #else if ( GetPosture() == AIP_CROUCHING ) @@ -673,7 +673,7 @@ Activity CAI_MappedActivityBehavior_Temporary::GetMappedActivity( AI_Posture_t p { if ( posture != AIP_STANDING ) { -#ifdef EXPANDED_HL2_COVER_ACTIVITIES +#if EXPANDED_HL2_COVER_ACTIVITIES // See UpdateTranslateActivityMap() for more information on what this is for if ( posture == AIP_CROUCHING_MED ) { @@ -1121,7 +1121,7 @@ void CAI_StandoffBehavior::UnlockHintNode() Activity CAI_StandoffBehavior::GetCoverActivity() { -#ifdef EXPANDED_HL2_COVER_ACTIVITIES +#if EXPANDED_HL2_COVER_ACTIVITIES // GetCoverActivity() already checks everything we checked here. Activity coverActivity = GetOuter()->GetCoverActivity( GetHintNode() ); @@ -1186,7 +1186,7 @@ void CAI_MappedActivityBehavior_Temporary::UpdateTranslateActivityMap() { AIP_CROUCHING, ACT_RANGE_ATTACK_AR2, NULL, ACT_RANGE_ATTACK_AR2_LOW, }, #endif -#ifdef EXPANDED_HL2_COVER_ACTIVITIES +#if EXPANDED_HL2_COVER_ACTIVITIES // // ============ Really long explanation that should be in a wiki/documentation article somewhere ~ Blixibon, 10/27/2021 ============ // diff --git a/sp/src/game/server/ai_behavior_standoff.h b/sp/src/game/server/ai_behavior_standoff.h index 2de2a072..9141e874 100644 --- a/sp/src/game/server/ai_behavior_standoff.h +++ b/sp/src/game/server/ai_behavior_standoff.h @@ -51,7 +51,7 @@ enum AI_Posture_t AIP_INDIFFERENT, AIP_STANDING, AIP_CROUCHING, -#ifdef EXPANDED_HL2_COVER_ACTIVITIES +#if EXPANDED_HL2_COVER_ACTIVITIES AIP_CROUCHING_MED, // See UpdateTranslateActivityMap() for more information on what this is for #endif AIP_PEEKING, diff --git a/sp/src/game/server/ai_motor.cpp b/sp/src/game/server/ai_motor.cpp index f54432ff..87a8ec6e 100644 --- a/sp/src/game/server/ai_motor.cpp +++ b/sp/src/game/server/ai_motor.cpp @@ -239,7 +239,7 @@ void CAI_Motor::MoveClimbStart( const Vector &climbDest, const Vector &climbDir // > other state? bool bGoingUp = (climbDir.z > 0.01); -#ifdef EXPANDED_NAVIGATION_ACTIVITIES +#if EXPANDED_NAVIGATION_ACTIVITIES if ( bGoingUp && GetOuter()->HaveSequenceForActivity( ACT_CLIMB_MOUNT_BOTTOM ) ) { SetActivity( ACT_CLIMB_MOUNT_BOTTOM ); @@ -270,7 +270,7 @@ void CAI_Motor::MoveClimbStart( const Vector &climbDest, const Vector &climbDir m_nDismountSequence = SelectWeightedSequence( ACT_CLIMB_DISMOUNT ); if (m_nDismountSequence != ACT_INVALID) { -#ifdef EXPANDED_NAVIGATION_ACTIVITIES +#if EXPANDED_NAVIGATION_ACTIVITIES if ( !bGoingUp ) { int nBottomDismount = SelectWeightedSequence( ACT_CLIMB_DISMOUNT_BOTTOM ); @@ -294,7 +294,7 @@ void CAI_Motor::MoveClimbStart( const Vector &climbDest, const Vector &climbDir AIMoveResult_t CAI_Motor::MoveClimbExecute( const Vector &climbDest, const Vector &climbDir, float climbDist, float yaw, int climbNodesLeft ) { -#ifdef EXPANDED_NAVIGATION_ACTIVITIES +#if EXPANDED_NAVIGATION_ACTIVITIES if ( (GetActivity() == ACT_CLIMB_MOUNT_TOP || GetActivity() == ACT_CLIMB_MOUNT_BOTTOM) ) { if (!GetOuter()->IsActivityFinished()) @@ -401,7 +401,7 @@ AIMoveResult_t CAI_Motor::MoveClimbExecute( const Vector &climbDest, const Vecto if (m_nDismountSequence != ACT_INVALID) { // catch situations where the climb mount/dismount finished before reaching goal -#ifdef EXPANDED_NAVIGATION_ACTIVITIES +#if EXPANDED_NAVIGATION_ACTIVITIES if ((GetActivity() == ACT_CLIMB_DISMOUNT || GetActivity() == ACT_CLIMB_DISMOUNT_BOTTOM)) { SetGroundEntity( NULL ); @@ -494,7 +494,7 @@ void CAI_Motor::MoveClimbStop() void CAI_Motor::MoveClimbPause() { if (GetActivity() != ACT_CLIMB_DISMOUNT -#ifdef EXPANDED_NAVIGATION_ACTIVITIES +#if EXPANDED_NAVIGATION_ACTIVITIES && GetActivity() != ACT_CLIMB_MOUNT_TOP && GetActivity() != ACT_CLIMB_MOUNT_BOTTOM #endif ) diff --git a/sp/src/game/server/ai_navigator.cpp b/sp/src/game/server/ai_navigator.cpp index c58471d0..dacab2aa 100644 --- a/sp/src/game/server/ai_navigator.cpp +++ b/sp/src/game/server/ai_navigator.cpp @@ -3924,7 +3924,7 @@ bool CAI_Navigator::GetStoppingPath( CAI_WaypointList * pClippedWaypoints ) AI_Waypoint_t *pCurWaypoint = GetPath()->GetCurWaypoint(); if ( pCurWaypoint ) { -#ifdef EXPANDED_NAVIGATION_ACTIVITIES +#if EXPANDED_NAVIGATION_ACTIVITIES // Since regular climb nav can interrupt itself now, only do this when dismounting bool bMustCompleteCurrent = ( (pCurWaypoint->NavType() == NAV_CLIMB && (GetActivity() == ACT_CLIMB_DISMOUNT || GetActivity() == ACT_CLIMB_MOUNT_TOP)) || pCurWaypoint->NavType() == NAV_JUMP ); #else diff --git a/sp/src/game/server/hl2/hl2_player.cpp b/sp/src/game/server/hl2/hl2_player.cpp index afb2c1cb..c148ba3e 100644 --- a/sp/src/game/server/hl2/hl2_player.cpp +++ b/sp/src/game/server/hl2/hl2_player.cpp @@ -1387,7 +1387,7 @@ Activity CHL2_Player::Weapon_TranslateActivity( Activity baseAct, bool *pRequire { Activity weaponTranslation = BaseClass::Weapon_TranslateActivity( baseAct, pRequired ); -#ifdef EXPANDED_HL2DM_ACTIVITIES +#if EXPANDED_HL2DM_ACTIVITIES // +USE activities if ( m_hUseEntity && player_use_anim_enabled.GetBool() ) { diff --git a/sp/src/game/server/hl2/npc_alyx_episodic.cpp b/sp/src/game/server/hl2/npc_alyx_episodic.cpp index 9df7a3ee..ee8b197c 100644 --- a/sp/src/game/server/hl2/npc_alyx_episodic.cpp +++ b/sp/src/game/server/hl2/npc_alyx_episodic.cpp @@ -1695,7 +1695,7 @@ Activity CNPC_Alyx::NPC_TranslateActivity( Activity activity ) case ACT_DROP_WEAPON: if ( HasShotgun() ) return (Activity)ACT_DROP_WEAPON_SHOTGUN; } -#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES +#if EXPANDED_HL2_WEAPON_ACTIVITIES // Alyx has her own pistol readiness animations which use the default activities switch (activity) { @@ -1725,7 +1725,7 @@ Activity CNPC_Alyx::Weapon_TranslateActivity( Activity activity, bool *pRequired { activity = BaseClass::Weapon_TranslateActivity( activity, pRequired ); -#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES +#if EXPANDED_HL2_WEAPON_ACTIVITIES // Alyx has her own pistol readiness animations which use the default activities switch (activity) { @@ -1754,7 +1754,7 @@ Activity CNPC_Alyx::Weapon_BackupActivity( Activity activity, bool weaponTransla { activity = BaseClass::Weapon_BackupActivity( activity, weaponTranslationWasRequired, pSpecificWeapon ); -#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES +#if EXPANDED_HL2_WEAPON_ACTIVITIES // Alyx has her own pistol readiness animations which use the default activities switch (activity) { diff --git a/sp/src/game/server/hl2/npc_citizen17.cpp b/sp/src/game/server/hl2/npc_citizen17.cpp index 79ff9a0e..42822d2f 100644 --- a/sp/src/game/server/hl2/npc_citizen17.cpp +++ b/sp/src/game/server/hl2/npc_citizen17.cpp @@ -2091,7 +2091,7 @@ Activity CNPC_Citizen::NPC_TranslateActivity( Activity activity ) if (activity == ACT_WALK_AIM_AR2) return ACT_WALK_AIM_AR2_STIMULATED; -#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES +#if EXPANDED_HL2_WEAPON_ACTIVITIES if (activity == ACT_RUN_AIM_PISTOL) return ACT_RUN_AIM_PISTOL_STIMULATED; if (activity == ACT_WALK_AIM_PISTOL) diff --git a/sp/src/game/server/hl2/npc_combine.cpp b/sp/src/game/server/hl2/npc_combine.cpp index aedf23ac..50d10982 100644 --- a/sp/src/game/server/hl2/npc_combine.cpp +++ b/sp/src/game/server/hl2/npc_combine.cpp @@ -117,12 +117,12 @@ int COMBINE_AE_ALTFIRE; //Activity ACT_COMBINE_WALKING_AR2; //Activity ACT_COMBINE_STANDING_SHOTGUN; //Activity ACT_COMBINE_CROUCHING_SHOTGUN; -#ifndef SHARED_COMBINE_ACTIVITIES +#if !SHARED_COMBINE_ACTIVITIES Activity ACT_COMBINE_THROW_GRENADE; #endif Activity ACT_COMBINE_LAUNCH_GRENADE; Activity ACT_COMBINE_BUGBAIT; -#ifndef SHARED_COMBINE_ACTIVITIES +#if !SHARED_COMBINE_ACTIVITIES Activity ACT_COMBINE_AR2_ALTFIRE; #endif Activity ACT_WALK_EASY; @@ -1594,7 +1594,7 @@ Activity CNPC_Combine::NPC_TranslateActivity( Activity eNewActivity ) else #endif { -#ifdef SHARED_COMBINE_ACTIVITIES +#if SHARED_COMBINE_ACTIVITIES return ACT_COMBINE_THROW_GRENADE; #else return ( Activity )ACT_COMBINE_THROW_GRENADE; @@ -3953,12 +3953,12 @@ DECLARE_TASK( TASK_COMBINE_GET_PATH_TO_FORCED_GREN_LOS ) DECLARE_TASK( TASK_COMBINE_SET_STANDING ) //Activities -#ifndef SHARED_COMBINE_ACTIVITIES +#if !SHARED_COMBINE_ACTIVITIES DECLARE_ACTIVITY( ACT_COMBINE_THROW_GRENADE ) #endif DECLARE_ACTIVITY( ACT_COMBINE_LAUNCH_GRENADE ) DECLARE_ACTIVITY( ACT_COMBINE_BUGBAIT ) -#ifndef SHARED_COMBINE_ACTIVITIES +#if !SHARED_COMBINE_ACTIVITIES DECLARE_ACTIVITY( ACT_COMBINE_AR2_ALTFIRE ) #endif DECLARE_ACTIVITY( ACT_WALK_EASY ) diff --git a/sp/src/game/server/hl2/npc_fastzombie.cpp b/sp/src/game/server/hl2/npc_fastzombie.cpp index be53f344..6e5ec136 100644 --- a/sp/src/game/server/hl2/npc_fastzombie.cpp +++ b/sp/src/game/server/hl2/npc_fastzombie.cpp @@ -1297,7 +1297,7 @@ void CFastZombie::StartTask( const Task_t *pTask ) Vector vecJumpDir; if ( GetActivity() == ACT_CLIMB_UP || GetActivity() == ACT_CLIMB_DOWN -#ifdef EXPANDED_NAVIGATION_ACTIVITIES +#if EXPANDED_NAVIGATION_ACTIVITIES || GetActivity() == ACT_CLIMB_ALL #endif ) @@ -1454,7 +1454,7 @@ int CFastZombie::TranslateSchedule( int scheduleType ) case SCHED_FASTZOMBIE_UNSTICK_JUMP: if ( GetActivity() == ACT_CLIMB_UP || GetActivity() == ACT_CLIMB_DOWN || GetActivity() == ACT_CLIMB_DISMOUNT -#ifdef EXPANDED_NAVIGATION_ACTIVITIES +#if EXPANDED_NAVIGATION_ACTIVITIES || (GetActivity() >= ACT_CLIMB_ALL && GetActivity() <= ACT_CLIMB_DISMOUNT_BOTTOM) #endif ) diff --git a/sp/src/game/server/hl2/weapon_357.cpp b/sp/src/game/server/hl2/weapon_357.cpp index 38a15246..ac415c9e 100644 --- a/sp/src/game/server/hl2/weapon_357.cpp +++ b/sp/src/game/server/hl2/weapon_357.cpp @@ -99,7 +99,7 @@ END_DATADESC() #ifdef MAPBASE acttable_t CWeapon357::m_acttable[] = { -#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES +#if EXPANDED_HL2_WEAPON_ACTIVITIES { ACT_IDLE, ACT_IDLE_REVOLVER, true }, { ACT_IDLE_ANGRY, ACT_IDLE_ANGRY_REVOLVER, true }, { ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_REVOLVER, true }, @@ -136,7 +136,7 @@ acttable_t CWeapon357::m_acttable[] = // // Readiness activities (not aiming) -#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES +#if EXPANDED_HL2_WEAPON_ACTIVITIES { ACT_IDLE_RELAXED, ACT_IDLE_PISTOL_RELAXED, false },//never aims { ACT_IDLE_STIMULATED, ACT_IDLE_PISTOL_STIMULATED, false }, #else @@ -146,7 +146,7 @@ acttable_t CWeapon357::m_acttable[] = { ACT_IDLE_AGITATED, ACT_IDLE_ANGRY_PISTOL, false },//always aims { ACT_IDLE_STEALTH, ACT_IDLE_STEALTH_PISTOL, false }, -#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES +#if EXPANDED_HL2_WEAPON_ACTIVITIES { ACT_WALK_RELAXED, ACT_WALK_PISTOL_RELAXED, false },//never aims { ACT_WALK_STIMULATED, ACT_WALK_PISTOL_STIMULATED, false }, #else @@ -156,7 +156,7 @@ acttable_t CWeapon357::m_acttable[] = { ACT_WALK_AGITATED, ACT_WALK_AIM_PISTOL, false },//always aims { ACT_WALK_STEALTH, ACT_WALK_STEALTH_PISTOL, false }, -#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES +#if EXPANDED_HL2_WEAPON_ACTIVITIES { ACT_RUN_RELAXED, ACT_RUN_PISTOL_RELAXED, false },//never aims { ACT_RUN_STIMULATED, ACT_RUN_PISTOL_STIMULATED, false }, #else @@ -194,14 +194,14 @@ acttable_t CWeapon357::m_acttable[] = { ACT_READINESS_AGITATED_TO_STIMULATED, ACT_READINESS_PISTOL_AGITATED_TO_STIMULATED, false }, { ACT_READINESS_STIMULATED_TO_RELAXED, ACT_READINESS_PISTOL_STIMULATED_TO_RELAXED, false }, -#ifdef EXPANDED_HL2_COVER_ACTIVITIES +#if EXPANDED_HL2_COVER_ACTIVITIES { ACT_RANGE_AIM_MED, ACT_RANGE_AIM_REVOLVER_MED, false }, { ACT_RANGE_ATTACK1_MED, ACT_RANGE_ATTACK_REVOLVER_MED, false }, #endif #ifdef MAPBASE // HL2:DM activities (for third-person animations in SP) -#ifdef EXPANDED_HL2DM_ACTIVITIES +#if EXPANDED_HL2DM_ACTIVITIES { ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_REVOLVER, false }, { ACT_HL2MP_RUN, ACT_HL2MP_RUN_REVOLVER, false }, { ACT_HL2MP_WALK, ACT_HL2MP_WALK_REVOLVER, false }, diff --git a/sp/src/game/server/hl2/weapon_alyxgun.cpp b/sp/src/game/server/hl2/weapon_alyxgun.cpp index dbd57cec..5bf20eb6 100644 --- a/sp/src/game/server/hl2/weapon_alyxgun.cpp +++ b/sp/src/game/server/hl2/weapon_alyxgun.cpp @@ -44,7 +44,7 @@ acttable_t CWeaponAlyxGun::m_acttable[] = #endif // Readiness activities (not aiming) -#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES +#if EXPANDED_HL2_WEAPON_ACTIVITIES { ACT_IDLE_RELAXED, ACT_IDLE_PISTOL_RELAXED, false },//never aims { ACT_IDLE_STIMULATED, ACT_IDLE_PISTOL_STIMULATED, false }, #else @@ -54,7 +54,7 @@ acttable_t CWeaponAlyxGun::m_acttable[] = { ACT_IDLE_AGITATED, ACT_IDLE_ANGRY_PISTOL, false },//always aims { ACT_IDLE_STEALTH, ACT_IDLE_STEALTH_PISTOL, false }, -#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES +#if EXPANDED_HL2_WEAPON_ACTIVITIES { ACT_WALK_RELAXED, ACT_WALK_PISTOL_RELAXED, false },//never aims { ACT_WALK_STIMULATED, ACT_WALK_PISTOL_STIMULATED, false }, #else @@ -64,7 +64,7 @@ acttable_t CWeaponAlyxGun::m_acttable[] = { ACT_WALK_AGITATED, ACT_WALK_AIM_PISTOL, false },//always aims { ACT_WALK_STEALTH, ACT_WALK_STEALTH_PISTOL, false }, -#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES +#if EXPANDED_HL2_WEAPON_ACTIVITIES { ACT_RUN_RELAXED, ACT_RUN_PISTOL_RELAXED, false },//never aims { ACT_RUN_STIMULATED, ACT_RUN_PISTOL_STIMULATED, false }, #else @@ -115,7 +115,7 @@ acttable_t CWeaponAlyxGun::m_acttable[] = { ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_PISTOL, false }, { ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_PISTOL, false }, { ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_PISTOL, false }, -#ifdef EXPANDED_HL2DM_ACTIVITIES +#if EXPANDED_HL2DM_ACTIVITIES { ACT_HL2MP_WALK, ACT_HL2MP_WALK_PISTOL, false }, { ACT_HL2MP_GESTURE_RANGE_ATTACK2, ACT_HL2MP_GESTURE_RANGE_ATTACK2_PISTOL, false }, #endif diff --git a/sp/src/game/server/hl2/weapon_annabelle.cpp b/sp/src/game/server/hl2/weapon_annabelle.cpp index ae499a49..6b7ecdd9 100644 --- a/sp/src/game/server/hl2/weapon_annabelle.cpp +++ b/sp/src/game/server/hl2/weapon_annabelle.cpp @@ -152,7 +152,7 @@ acttable_t CWeaponAnnabelle::m_acttable[] = { ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_SHOTGUN, false }, { ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_AR2, false }, { ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_AR2, false }, -#ifdef EXPANDED_HL2DM_ACTIVITIES +#if EXPANDED_HL2DM_ACTIVITIES { ACT_HL2MP_WALK, ACT_HL2MP_WALK_AR2, false }, { ACT_HL2MP_GESTURE_RANGE_ATTACK2, ACT_HL2MP_GESTURE_RANGE_ATTACK2_SHOTGUN, false }, #endif diff --git a/sp/src/game/server/hl2/weapon_ar2.cpp b/sp/src/game/server/hl2/weapon_ar2.cpp index 6bb1f120..0437c15d 100644 --- a/sp/src/game/server/hl2/weapon_ar2.cpp +++ b/sp/src/game/server/hl2/weapon_ar2.cpp @@ -157,12 +157,12 @@ acttable_t CWeaponAR2::m_acttable[] = // { ACT_RANGE_ATTACK2, ACT_RANGE_ATTACK_AR2_GRENADE, true }, #endif -#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES +#if EXPANDED_HL2_WEAPON_ACTIVITIES { ACT_ARM, ACT_ARM_RIFLE, false }, { ACT_DISARM, ACT_DISARM_RIFLE, false }, #endif -#ifdef EXPANDED_HL2_COVER_ACTIVITIES +#if EXPANDED_HL2_COVER_ACTIVITIES { ACT_RANGE_AIM_MED, ACT_RANGE_AIM_AR2_MED, false }, { ACT_RANGE_ATTACK1_MED, ACT_RANGE_ATTACK_AR2_MED, false }, @@ -181,7 +181,7 @@ acttable_t CWeaponAR2::m_acttable[] = { ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_AR2, false }, { ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_AR2, false }, { ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_AR2, false }, -#ifdef EXPANDED_HL2DM_ACTIVITIES +#if EXPANDED_HL2DM_ACTIVITIES { ACT_HL2MP_WALK, ACT_HL2MP_WALK_AR2, false }, { ACT_HL2MP_GESTURE_RANGE_ATTACK2, ACT_HL2MP_GESTURE_RANGE_ATTACK2_AR2, false }, #endif diff --git a/sp/src/game/server/hl2/weapon_bugbait.cpp b/sp/src/game/server/hl2/weapon_bugbait.cpp index 72967d7d..d9e6f94c 100644 --- a/sp/src/game/server/hl2/weapon_bugbait.cpp +++ b/sp/src/game/server/hl2/weapon_bugbait.cpp @@ -100,7 +100,7 @@ acttable_t CWeaponBugBait::m_acttable[] = { ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_GRENADE, false }, { ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_GRENADE, false }, { ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_GRENADE, false }, -#ifdef EXPANDED_HL2DM_ACTIVITIES +#if EXPANDED_HL2DM_ACTIVITIES { ACT_HL2MP_WALK, ACT_HL2MP_WALK_GRENADE, false }, { ACT_HL2MP_GESTURE_RANGE_ATTACK2, ACT_HL2MP_GESTURE_RANGE_ATTACK2_GRENADE, false }, #endif diff --git a/sp/src/game/server/hl2/weapon_citizenpackage.cpp b/sp/src/game/server/hl2/weapon_citizenpackage.cpp index 3d82e46c..95a02296 100644 --- a/sp/src/game/server/hl2/weapon_citizenpackage.cpp +++ b/sp/src/game/server/hl2/weapon_citizenpackage.cpp @@ -23,7 +23,7 @@ acttable_t CWeaponCitizenPackage::m_acttable[] = { { ACT_IDLE, ACT_IDLE_PACKAGE, false }, { ACT_WALK, ACT_WALK_PACKAGE, false }, -#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES +#if EXPANDED_HL2_WEAPON_ACTIVITIES { ACT_RUN, ACT_RUN_PACKAGE, false }, { ACT_IDLE_ANGRY, ACT_IDLE_PACKAGE, false }, @@ -77,7 +77,7 @@ acttable_t CWeaponCitizenSuitcase::m_acttable[] = { { ACT_IDLE, ACT_IDLE_SUITCASE, false }, { ACT_WALK, ACT_WALK_SUITCASE, false }, -#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES +#if EXPANDED_HL2_WEAPON_ACTIVITIES { ACT_RUN, ACT_RUN_SUITCASE, false }, { ACT_IDLE_ANGRY, ACT_IDLE_SUITCASE, false }, diff --git a/sp/src/game/server/hl2/weapon_crossbow.cpp b/sp/src/game/server/hl2/weapon_crossbow.cpp index 2dc487da..8a0f306b 100644 --- a/sp/src/game/server/hl2/weapon_crossbow.cpp +++ b/sp/src/game/server/hl2/weapon_crossbow.cpp @@ -639,7 +639,7 @@ END_DATADESC() #ifdef MAPBASE acttable_t CWeaponCrossbow::m_acttable[] = { -#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES +#if EXPANDED_HL2_WEAPON_ACTIVITIES { ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_CROSSBOW, true }, { ACT_RELOAD, ACT_RELOAD_CROSSBOW, true }, { ACT_IDLE, ACT_IDLE_CROSSBOW, true }, @@ -740,7 +740,7 @@ acttable_t CWeaponCrossbow::m_acttable[] = { ACT_GESTURE_RELOAD, ACT_GESTURE_RELOAD_SMG1, true }, #endif -#ifdef EXPANDED_HL2_COVER_ACTIVITIES +#if EXPANDED_HL2_COVER_ACTIVITIES { ACT_RANGE_AIM_MED, ACT_RANGE_AIM_CROSSBOW_MED, false }, { ACT_RANGE_ATTACK1_MED, ACT_RANGE_ATTACK_CROSSBOW_MED, false }, #endif @@ -754,7 +754,7 @@ acttable_t CWeaponCrossbow::m_acttable[] = { ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_CROSSBOW, false }, { ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_CROSSBOW, false }, { ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_CROSSBOW, false }, -#ifdef EXPANDED_HL2DM_ACTIVITIES +#if EXPANDED_HL2DM_ACTIVITIES { ACT_HL2MP_WALK, ACT_HL2MP_WALK_CROSSBOW, false }, { ACT_HL2MP_GESTURE_RANGE_ATTACK2, ACT_HL2MP_GESTURE_RANGE_ATTACK2_CROSSBOW, false }, #endif diff --git a/sp/src/game/server/hl2/weapon_crowbar.cpp b/sp/src/game/server/hl2/weapon_crowbar.cpp index cee8d0f9..7cc34b9c 100644 --- a/sp/src/game/server/hl2/weapon_crowbar.cpp +++ b/sp/src/game/server/hl2/weapon_crowbar.cpp @@ -42,7 +42,7 @@ acttable_t CWeaponCrowbar::m_acttable[] = { ACT_MELEE_ATTACK1, ACT_MELEE_ATTACK_SWING, true }, { ACT_IDLE, ACT_IDLE_ANGRY_MELEE, false }, { ACT_IDLE_ANGRY, ACT_IDLE_ANGRY_MELEE, false }, -#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES +#if EXPANDED_HL2_WEAPON_ACTIVITIES { ACT_RUN, ACT_RUN_MELEE, false }, { ACT_WALK, ACT_WALK_MELEE, false }, @@ -60,7 +60,7 @@ acttable_t CWeaponCrowbar::m_acttable[] = { ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_MELEE, false }, { ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_MELEE, false }, { ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_MELEE, false }, -#ifdef EXPANDED_HL2DM_ACTIVITIES +#if EXPANDED_HL2DM_ACTIVITIES { ACT_HL2MP_GESTURE_RANGE_ATTACK2, ACT_HL2MP_GESTURE_RANGE_ATTACK2_MELEE, false }, { ACT_HL2MP_WALK, ACT_HL2MP_WALK_MELEE, false }, #endif diff --git a/sp/src/game/server/hl2/weapon_frag.cpp b/sp/src/game/server/hl2/weapon_frag.cpp index aeba2785..91eddcd3 100644 --- a/sp/src/game/server/hl2/weapon_frag.cpp +++ b/sp/src/game/server/hl2/weapon_frag.cpp @@ -92,7 +92,7 @@ acttable_t CWeaponFrag::m_acttable[] = { ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_GRENADE, false }, { ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_GRENADE, false }, { ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_GRENADE, false }, -#ifdef EXPANDED_HL2DM_ACTIVITIES +#if EXPANDED_HL2DM_ACTIVITIES { ACT_HL2MP_WALK, ACT_HL2MP_WALK_GRENADE, false }, { ACT_HL2MP_GESTURE_RANGE_ATTACK2, ACT_HL2MP_GESTURE_RANGE_ATTACK2_GRENADE, false }, #endif diff --git a/sp/src/game/server/hl2/weapon_physcannon.cpp b/sp/src/game/server/hl2/weapon_physcannon.cpp index 842d6a5f..2e985460 100644 --- a/sp/src/game/server/hl2/weapon_physcannon.cpp +++ b/sp/src/game/server/hl2/weapon_physcannon.cpp @@ -1470,7 +1470,7 @@ acttable_t CWeaponPhysCannon::m_acttable[] = { ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_PHYSGUN, false }, { ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_PHYSGUN, false }, { ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_SLAM, false }, -#ifdef EXPANDED_HL2DM_ACTIVITIES +#if EXPANDED_HL2DM_ACTIVITIES { ACT_HL2MP_WALK, ACT_HL2MP_WALK_PHYSGUN, false }, { ACT_HL2MP_GESTURE_RANGE_ATTACK2, ACT_HL2MP_GESTURE_RANGE_ATTACK2_PHYSGUN, false }, #endif diff --git a/sp/src/game/server/hl2/weapon_pistol.cpp b/sp/src/game/server/hl2/weapon_pistol.cpp index dce93262..9819f748 100644 --- a/sp/src/game/server/hl2/weapon_pistol.cpp +++ b/sp/src/game/server/hl2/weapon_pistol.cpp @@ -161,7 +161,7 @@ acttable_t CWeaponPistol::m_acttable[] = // Activities ported from weapon_alyxgun below // -#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES +#if EXPANDED_HL2_WEAPON_ACTIVITIES // Readiness activities (not aiming) { ACT_IDLE_RELAXED, ACT_IDLE_PISTOL_RELAXED, false },//never aims { ACT_IDLE_STIMULATED, ACT_IDLE_PISTOL_STIMULATED, false }, @@ -241,14 +241,14 @@ acttable_t CWeaponPistol::m_acttable[] = { ACT_READINESS_STIMULATED_TO_RELAXED, ACT_READINESS_PISTOL_STIMULATED_TO_RELAXED, false }, #endif -#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES +#if EXPANDED_HL2_WEAPON_ACTIVITIES { ACT_WALK_CROUCH, ACT_WALK_CROUCH_PISTOL, true }, { ACT_WALK_CROUCH_AIM, ACT_WALK_CROUCH_AIM_PISTOL, true }, { ACT_RUN_CROUCH, ACT_RUN_CROUCH_PISTOL, true }, { ACT_RUN_CROUCH_AIM, ACT_RUN_CROUCH_AIM_PISTOL, true }, #endif -#ifdef EXPANDED_HL2_COVER_ACTIVITIES +#if EXPANDED_HL2_COVER_ACTIVITIES { ACT_RANGE_AIM_MED, ACT_RANGE_AIM_PISTOL_MED, false }, { ACT_RANGE_ATTACK1_MED, ACT_RANGE_ATTACK_PISTOL_MED, false }, @@ -267,7 +267,7 @@ acttable_t CWeaponPistol::m_acttable[] = { ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_PISTOL, false }, { ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_PISTOL, false }, { ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_PISTOL, false }, -#ifdef EXPANDED_HL2DM_ACTIVITIES +#if EXPANDED_HL2DM_ACTIVITIES { ACT_HL2MP_WALK, ACT_HL2MP_WALK_PISTOL, false }, { ACT_HL2MP_GESTURE_RANGE_ATTACK2, ACT_HL2MP_GESTURE_RANGE_ATTACK2_PISTOL, false }, #endif diff --git a/sp/src/game/server/hl2/weapon_rpg.cpp b/sp/src/game/server/hl2/weapon_rpg.cpp index 36a60dd1..645ca8e6 100644 --- a/sp/src/game/server/hl2/weapon_rpg.cpp +++ b/sp/src/game/server/hl2/weapon_rpg.cpp @@ -1399,7 +1399,7 @@ PRECACHE_WEAPON_REGISTER(weapon_rpg); acttable_t CWeaponRPG::m_acttable[] = { { ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_RPG, true }, -#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES +#if EXPANDED_HL2_WEAPON_ACTIVITIES { ACT_RANGE_AIM_LOW, ACT_RANGE_AIM_RPG_LOW, false }, { ACT_RANGE_ATTACK1_LOW, ACT_RANGE_ATTACK_RPG_LOW, false }, { ACT_GESTURE_RANGE_ATTACK1, ACT_GESTURE_RANGE_ATTACK_RPG, false }, @@ -1417,12 +1417,12 @@ acttable_t CWeaponRPG::m_acttable[] = { ACT_RUN_CROUCH, ACT_RUN_CROUCH_RPG, true }, { ACT_COVER_LOW, ACT_COVER_LOW_RPG, true }, -#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES +#if EXPANDED_HL2_WEAPON_ACTIVITIES { ACT_ARM, ACT_ARM_RPG, false }, { ACT_DISARM, ACT_DISARM_RPG, false }, #endif -#ifdef EXPANDED_HL2_COVER_ACTIVITIES +#if EXPANDED_HL2_COVER_ACTIVITIES { ACT_RANGE_AIM_MED, ACT_RANGE_AIM_RPG_MED, false }, { ACT_RANGE_ATTACK1_MED, ACT_RANGE_ATTACK_RPG_MED, false }, #endif @@ -1436,7 +1436,7 @@ acttable_t CWeaponRPG::m_acttable[] = { ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_RPG, false }, { ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_RPG, false }, { ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_RPG, false }, -#ifdef EXPANDED_HL2DM_ACTIVITIES +#if EXPANDED_HL2DM_ACTIVITIES { ACT_HL2MP_WALK, ACT_HL2MP_WALK_RPG, false }, { ACT_HL2MP_GESTURE_RANGE_ATTACK2, ACT_HL2MP_GESTURE_RANGE_ATTACK2_RPG, false }, #endif diff --git a/sp/src/game/server/hl2/weapon_shotgun.cpp b/sp/src/game/server/hl2/weapon_shotgun.cpp index 71df2695..5348e08a 100644 --- a/sp/src/game/server/hl2/weapon_shotgun.cpp +++ b/sp/src/game/server/hl2/weapon_shotgun.cpp @@ -108,7 +108,7 @@ END_DATADESC() acttable_t CWeaponShotgun::m_acttable[] = { -#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES +#if EXPANDED_HL2_WEAPON_ACTIVITIES // Note that ACT_IDLE_SHOTGUN_AGITATED seems to be a stand-in for ACT_IDLE_SHOTGUN on citizens, // but that isn't acceptable for NPCs which don't use readiness activities. { ACT_IDLE, ACT_IDLE_SHOTGUN, true }, @@ -206,12 +206,12 @@ acttable_t CWeaponShotgun::m_acttable[] = { ACT_GESTURE_RELOAD, ACT_GESTURE_RELOAD_SHOTGUN, false }, #endif -#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES +#if EXPANDED_HL2_WEAPON_ACTIVITIES { ACT_ARM, ACT_ARM_SHOTGUN, true }, { ACT_DISARM, ACT_DISARM_SHOTGUN, true }, #endif -#ifdef EXPANDED_HL2_COVER_ACTIVITIES +#if EXPANDED_HL2_COVER_ACTIVITIES { ACT_RANGE_AIM_MED, ACT_RANGE_AIM_SHOTGUN_MED, false }, { ACT_RANGE_ATTACK1_MED, ACT_RANGE_ATTACK_SHOTGUN_MED, false }, #endif @@ -225,7 +225,7 @@ acttable_t CWeaponShotgun::m_acttable[] = { ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_SHOTGUN, false }, { ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_SHOTGUN, false }, { ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_SHOTGUN, false }, -#ifdef EXPANDED_HL2DM_ACTIVITIES +#if EXPANDED_HL2DM_ACTIVITIES { ACT_HL2MP_WALK, ACT_HL2MP_WALK_SHOTGUN, false }, { ACT_HL2MP_GESTURE_RANGE_ATTACK2, ACT_HL2MP_GESTURE_RANGE_ATTACK2_SHOTGUN, false }, #endif diff --git a/sp/src/game/server/hl2/weapon_smg1.cpp b/sp/src/game/server/hl2/weapon_smg1.cpp index 280d8e08..b11fbedc 100644 --- a/sp/src/game/server/hl2/weapon_smg1.cpp +++ b/sp/src/game/server/hl2/weapon_smg1.cpp @@ -135,12 +135,12 @@ acttable_t CWeaponSMG1::m_acttable[] = { ACT_RELOAD_LOW, ACT_RELOAD_SMG1_LOW, false }, { ACT_GESTURE_RELOAD, ACT_GESTURE_RELOAD_SMG1, true }, -#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES +#if EXPANDED_HL2_WEAPON_ACTIVITIES { ACT_ARM, ACT_ARM_RIFLE, false }, { ACT_DISARM, ACT_DISARM_RIFLE, false }, #endif -#ifdef EXPANDED_HL2_COVER_ACTIVITIES +#if EXPANDED_HL2_COVER_ACTIVITIES { ACT_RANGE_AIM_MED, ACT_RANGE_AIM_SMG1_MED, false }, { ACT_RANGE_ATTACK1_MED, ACT_RANGE_ATTACK_SMG1_MED, false }, @@ -159,7 +159,7 @@ acttable_t CWeaponSMG1::m_acttable[] = { ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_SMG1, false }, { ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_SMG1, false }, { ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_SMG1, false }, -#ifdef EXPANDED_HL2DM_ACTIVITIES +#if EXPANDED_HL2DM_ACTIVITIES { ACT_HL2MP_WALK, ACT_HL2MP_WALK_SMG1, false }, { ACT_HL2MP_GESTURE_RANGE_ATTACK2, ACT_HL2MP_GESTURE_RANGE_ATTACK2_SMG1, false }, #endif diff --git a/sp/src/game/server/mapbase/ai_grenade.h b/sp/src/game/server/mapbase/ai_grenade.h index 14ec4a9a..543969c2 100644 --- a/sp/src/game/server/mapbase/ai_grenade.h +++ b/sp/src/game/server/mapbase/ai_grenade.h @@ -321,7 +321,7 @@ void CAI_GrenadeUser::InputThrowGrenadeGestureAtTarget( inputdata_t &i Vector vecTarget = m_hForcedGrenadeTarget->WorldSpaceCenter(); -#ifdef SHARED_COMBINE_ACTIVITIES +#if SHARED_COMBINE_ACTIVITIES if (IsAltFireCapable()) { if (this->FVisible( m_hForcedGrenadeTarget )) diff --git a/sp/src/game/shared/activitylist.cpp b/sp/src/game/shared/activitylist.cpp index 98fe580b..1a2c1955 100644 --- a/sp/src/game/shared/activitylist.cpp +++ b/sp/src/game/shared/activitylist.cpp @@ -2303,7 +2303,7 @@ void ActivityList_RegisterSharedActivities( void ) REGISTER_SHARED_ACTIVITY( ACT_COVER_AR2_LOW ); #endif -#ifdef SHARED_COMBINE_ACTIVITIES +#if SHARED_COMBINE_ACTIVITIES REGISTER_SHARED_ACTIVITY( ACT_COMBINE_THROW_GRENADE ); REGISTER_SHARED_ACTIVITY( ACT_COMBINE_AR2_ALTFIRE ); @@ -2321,7 +2321,7 @@ void ActivityList_RegisterSharedActivities( void ) REGISTER_SHARED_ACTIVITY( ACT_GESTURE_SIGNAL_TAKECOVER ); #endif -#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES +#if EXPANDED_HL2_WEAPON_ACTIVITIES REGISTER_SHARED_ACTIVITY( ACT_IDLE_REVOLVER ); REGISTER_SHARED_ACTIVITY( ACT_IDLE_ANGRY_REVOLVER ); REGISTER_SHARED_ACTIVITY( ACT_WALK_REVOLVER ); @@ -2431,7 +2431,7 @@ void ActivityList_RegisterSharedActivities( void ) REGISTER_SHARED_ACTIVITY( ACT_CLIMB_DISMOUNT_BOTTOM ); #endif -#ifdef EXPANDED_HL2_COVER_ACTIVITIES +#if EXPANDED_HL2_COVER_ACTIVITIES REGISTER_SHARED_ACTIVITY( ACT_RANGE_ATTACK1_MED ); REGISTER_SHARED_ACTIVITY( ACT_RANGE_ATTACK2_MED ); REGISTER_SHARED_ACTIVITY( ACT_RANGE_AIM_MED ); @@ -2468,7 +2468,7 @@ void ActivityList_RegisterSharedActivities( void ) REGISTER_SHARED_ACTIVITY( ACT_COVER_WALL_LOW_L_PISTOL ); #endif -#ifdef EXPANDED_HL2DM_ACTIVITIES +#if EXPANDED_HL2DM_ACTIVITIES REGISTER_SHARED_ACTIVITY( ACT_HL2MP_WALK ); REGISTER_SHARED_ACTIVITY( ACT_HL2MP_WALK_PISTOL ); REGISTER_SHARED_ACTIVITY( ACT_HL2MP_WALK_SHOTGUN ); diff --git a/sp/src/game/shared/ai_activity.h b/sp/src/game/shared/ai_activity.h index c13df83f..99d09312 100644 --- a/sp/src/game/shared/ai_activity.h +++ b/sp/src/game/shared/ai_activity.h @@ -2180,7 +2180,7 @@ typedef enum ACT_COVER_AR2_LOW, #endif -#ifdef SHARED_COMBINE_ACTIVITIES +#if SHARED_COMBINE_ACTIVITIES ACT_COMBINE_THROW_GRENADE, ACT_COMBINE_AR2_ALTFIRE, @@ -2199,7 +2199,7 @@ typedef enum ACT_GESTURE_SIGNAL_TAKECOVER, #endif -#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES +#if EXPANDED_HL2_WEAPON_ACTIVITIES // Revolver (357) ACT_IDLE_REVOLVER, ACT_IDLE_ANGRY_REVOLVER, @@ -2318,7 +2318,7 @@ typedef enum ACT_CLIMB_DISMOUNT_BOTTOM, #endif -#ifdef EXPANDED_HL2_COVER_ACTIVITIES +#if EXPANDED_HL2_COVER_ACTIVITIES // Crouch Cover Medium ACT_RANGE_ATTACK1_MED, ACT_RANGE_ATTACK2_MED, @@ -2357,7 +2357,7 @@ typedef enum ACT_COVER_WALL_LOW_L_PISTOL, #endif -#ifdef EXPANDED_HL2DM_ACTIVITIES +#if EXPANDED_HL2DM_ACTIVITIES ACT_HL2MP_WALK, ACT_HL2MP_WALK_PISTOL, ACT_HL2MP_WALK_SHOTGUN, diff --git a/sp/src/game/shared/basecombatweapon_shared.cpp b/sp/src/game/shared/basecombatweapon_shared.cpp index e6b61249..c95a0189 100644 --- a/sp/src/game/shared/basecombatweapon_shared.cpp +++ b/sp/src/game/shared/basecombatweapon_shared.cpp @@ -1046,11 +1046,11 @@ WeaponClass_t CBaseCombatWeapon::WeaponClassify() Activity idleact = ActivityOverride(ACT_IDLE_ANGRY, NULL); switch (idleact) { -#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES +#if EXPANDED_HL2_WEAPON_ACTIVITIES case ACT_IDLE_ANGRY_REVOLVER: #endif case ACT_IDLE_ANGRY_PISTOL: return WEPCLASS_HANDGUN; -#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES +#if EXPANDED_HL2_WEAPON_ACTIVITIES case ACT_IDLE_ANGRY_CROSSBOW: // For now, crossbows are rifles #endif case ACT_IDLE_ANGRY_SMG1: diff --git a/sp/src/game/shared/hl2mp/weapon_slam.cpp b/sp/src/game/shared/hl2mp/weapon_slam.cpp index 36dd9825..c4eb7140 100644 --- a/sp/src/game/shared/hl2mp/weapon_slam.cpp +++ b/sp/src/game/shared/hl2mp/weapon_slam.cpp @@ -115,7 +115,7 @@ acttable_t CWeapon_SLAM::m_acttable[] = { ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_SLAM, false }, { ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_SLAM, false }, { ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_SLAM, false }, -#ifdef EXPANDED_HL2DM_ACTIVITIES +#if EXPANDED_HL2DM_ACTIVITIES { ACT_HL2MP_WALK, ACT_HL2MP_WALK_SLAM, false }, { ACT_HL2MP_GESTURE_RANGE_ATTACK2, ACT_HL2MP_GESTURE_RANGE_ATTACK2_SLAM, false }, #endif diff --git a/sp/src/game/shared/hl2mp/weapon_stunstick.cpp b/sp/src/game/shared/hl2mp/weapon_stunstick.cpp index b936b194..1d6ae161 100644 --- a/sp/src/game/shared/hl2mp/weapon_stunstick.cpp +++ b/sp/src/game/shared/hl2mp/weapon_stunstick.cpp @@ -81,7 +81,7 @@ acttable_t CWeaponStunStick::m_acttable[] = #endif { ACT_MELEE_ATTACK1, ACT_MELEE_ATTACK_SWING, true }, { ACT_IDLE_ANGRY, ACT_IDLE_ANGRY_MELEE, true }, -#ifdef EXPANDED_HL2_WEAPON_ACTIVITIES +#if EXPANDED_HL2_WEAPON_ACTIVITIES { ACT_IDLE, ACT_IDLE_MELEE, false }, { ACT_RUN, ACT_RUN_MELEE, false }, { ACT_WALK, ACT_WALK_MELEE, false }, @@ -97,7 +97,7 @@ acttable_t CWeaponStunStick::m_acttable[] = { ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_MELEE, false }, { ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_MELEE, false }, { ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_MELEE, false }, -#ifdef EXPANDED_HL2DM_ACTIVITIES +#if EXPANDED_HL2DM_ACTIVITIES { ACT_HL2MP_GESTURE_RANGE_ATTACK2, ACT_HL2MP_GESTURE_RANGE_ATTACK2_MELEE, false }, { ACT_HL2MP_WALK, ACT_HL2MP_WALK_MELEE, false }, #endif diff --git a/sp/src/game/shared/mapbase/singleplayer_animstate.cpp b/sp/src/game/shared/mapbase/singleplayer_animstate.cpp index 8cc9337e..7c8b92c9 100644 --- a/sp/src/game/shared/mapbase/singleplayer_animstate.cpp +++ b/sp/src/game/shared/mapbase/singleplayer_animstate.cpp @@ -110,7 +110,7 @@ Activity CSinglePlayerAnimState::CalcMainActivity() { if ( speed > 0 ) { -#ifdef EXPANDED_HL2DM_ACTIVITIES +#if EXPANDED_HL2DM_ACTIVITIES if ( m_pPlayer->GetButtons() & IN_WALK ) { idealActivity = ACT_HL2MP_WALK; @@ -148,7 +148,7 @@ void CSinglePlayerAnimState::SetPlayerAnimation( PLAYER_ANIM playerAnim ) } else if ( playerAnim == PLAYER_ATTACK2 ) { -#ifdef EXPANDED_HL2DM_ACTIVITIES +#if EXPANDED_HL2DM_ACTIVITIES m_iFireSequence = SelectWeightedSequence( TranslateActivity( ACT_HL2MP_GESTURE_RANGE_ATTACK2 ) ); #else m_iFireSequence = SelectWeightedSequence( TranslateActivity( ACT_HL2MP_GESTURE_RANGE_ATTACK ) ); From 4e3287842e6ec28ed8fd7ef3ebde46cafc1fba60 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sat, 20 Nov 2021 20:49:24 -0600 Subject: [PATCH 279/378] Added optional new activities for unused HL2 weapons included in the Source SDK (deactivated by default) --- sp/src/game/server/ai_activity.cpp | 145 +++++++++++++++++- sp/src/game/server/hl2/weapon_ar1.cpp | 81 ++++++++++ sp/src/game/server/hl2/weapon_ar2.cpp | 13 ++ sp/src/game/server/hl2/weapon_ar2.h | 3 + sp/src/game/server/hl2/weapon_smg2.cpp | 71 +++++++++ sp/src/game/server/hl2/weapon_sniperrifle.cpp | 80 ++++++++++ sp/src/game/shared/activitylist.cpp | 123 ++++++++++++++- sp/src/game/shared/ai_activity.h | 134 +++++++++++++++- 8 files changed, 647 insertions(+), 3 deletions(-) diff --git a/sp/src/game/server/ai_activity.cpp b/sp/src/game/server/ai_activity.cpp index dc090f7e..2627f081 100644 --- a/sp/src/game/server/ai_activity.cpp +++ b/sp/src/game/server/ai_activity.cpp @@ -2306,7 +2306,87 @@ void CAI_BaseNPC::InitDefaultActivitySR(void) ADD_ACTIVITY_TO_SR( ACT_DISARM_MELEE ); #endif -#ifdef EXPANDED_NAVIGATION_ACTIVITIES +#if EXPANDED_HL2_UNUSED_WEAPON_ACTIVITIES + ADD_ACTIVITY_TO_SR( ACT_IDLE_AR1 ); + ADD_ACTIVITY_TO_SR( ACT_IDLE_ANGRY_AR1 ); + ADD_ACTIVITY_TO_SR( ACT_WALK_AR1 ); + ADD_ACTIVITY_TO_SR( ACT_RUN_AR1 ); + ADD_ACTIVITY_TO_SR( ACT_WALK_AIM_AR1 ); + ADD_ACTIVITY_TO_SR( ACT_RUN_AIM_AR1 ); + ADD_ACTIVITY_TO_SR( ACT_RANGE_ATTACK_AR1 ); + ADD_ACTIVITY_TO_SR( ACT_RELOAD_AR1 ); + ADD_ACTIVITY_TO_SR( ACT_RANGE_ATTACK_AR1_LOW ); + ADD_ACTIVITY_TO_SR( ACT_RELOAD_AR1_LOW ); + ADD_ACTIVITY_TO_SR( ACT_COVER_AR1_LOW ); + ADD_ACTIVITY_TO_SR( ACT_RANGE_AIM_AR1_LOW ); + ADD_ACTIVITY_TO_SR( ACT_GESTURE_RANGE_ATTACK_AR1 ); + ADD_ACTIVITY_TO_SR( ACT_GESTURE_RELOAD_AR1 ); + + ADD_ACTIVITY_TO_SR( ACT_IDLE_AR1_RELAXED ); + ADD_ACTIVITY_TO_SR( ACT_IDLE_AR1_STIMULATED ); + ADD_ACTIVITY_TO_SR( ACT_WALK_AR1_RELAXED ); + ADD_ACTIVITY_TO_SR( ACT_RUN_AR1_RELAXED ); + ADD_ACTIVITY_TO_SR( ACT_WALK_AR1_STIMULATED ); + ADD_ACTIVITY_TO_SR( ACT_RUN_AR1_STIMULATED ); + + ADD_ACTIVITY_TO_SR( ACT_IDLE_AIM_AR1_STIMULATED ); + ADD_ACTIVITY_TO_SR( ACT_WALK_AIM_AR1_STIMULATED ); + ADD_ACTIVITY_TO_SR( ACT_RUN_AIM_AR1_STIMULATED ); + + ADD_ACTIVITY_TO_SR( ACT_IDLE_SMG2 ); + ADD_ACTIVITY_TO_SR( ACT_IDLE_ANGRY_SMG2 ); + ADD_ACTIVITY_TO_SR( ACT_WALK_SMG2 ); + ADD_ACTIVITY_TO_SR( ACT_RUN_SMG2 ); + ADD_ACTIVITY_TO_SR( ACT_WALK_AIM_SMG2 ); + ADD_ACTIVITY_TO_SR( ACT_RUN_AIM_SMG2 ); + ADD_ACTIVITY_TO_SR( ACT_RANGE_ATTACK_SMG2 ); + ADD_ACTIVITY_TO_SR( ACT_RELOAD_SMG2 ); + ADD_ACTIVITY_TO_SR( ACT_RANGE_ATTACK_SMG2_LOW ); + ADD_ACTIVITY_TO_SR( ACT_RELOAD_SMG2_LOW ); + ADD_ACTIVITY_TO_SR( ACT_COVER_SMG2_LOW ); + ADD_ACTIVITY_TO_SR( ACT_RANGE_AIM_SMG2_LOW ); + ADD_ACTIVITY_TO_SR( ACT_GESTURE_RANGE_ATTACK_SMG2 ); + ADD_ACTIVITY_TO_SR( ACT_GESTURE_RELOAD_SMG2 ); + + ADD_ACTIVITY_TO_SR( ACT_IDLE_SMG2_RELAXED ); + ADD_ACTIVITY_TO_SR( ACT_IDLE_SMG2_STIMULATED ); + ADD_ACTIVITY_TO_SR( ACT_WALK_SMG2_RELAXED ); + ADD_ACTIVITY_TO_SR( ACT_RUN_SMG2_RELAXED ); + ADD_ACTIVITY_TO_SR( ACT_WALK_SMG2_STIMULATED ); + ADD_ACTIVITY_TO_SR( ACT_RUN_SMG2_STIMULATED ); + + ADD_ACTIVITY_TO_SR( ACT_IDLE_AIM_SMG2_STIMULATED ); + ADD_ACTIVITY_TO_SR( ACT_WALK_AIM_SMG2_STIMULATED ); + ADD_ACTIVITY_TO_SR( ACT_RUN_AIM_SMG2_STIMULATED ); + + ADD_ACTIVITY_TO_SR( ACT_IDLE_SNIPER_RIFLE ); + ADD_ACTIVITY_TO_SR( ACT_IDLE_ANGRY_SNIPER_RIFLE ); + ADD_ACTIVITY_TO_SR( ACT_WALK_SNIPER_RIFLE ); + ADD_ACTIVITY_TO_SR( ACT_RUN_SNIPER_RIFLE ); + ADD_ACTIVITY_TO_SR( ACT_WALK_AIM_SNIPER_RIFLE ); + ADD_ACTIVITY_TO_SR( ACT_RUN_AIM_SNIPER_RIFLE ); + ADD_ACTIVITY_TO_SR( ACT_RANGE_ATTACK_SNIPER_RIFLE ); + ADD_ACTIVITY_TO_SR( ACT_RELOAD_SNIPER_RIFLE ); + ADD_ACTIVITY_TO_SR( ACT_RANGE_ATTACK_SNIPER_RIFLE_LOW ); + ADD_ACTIVITY_TO_SR( ACT_RELOAD_SNIPER_RIFLE_LOW ); + ADD_ACTIVITY_TO_SR( ACT_COVER_SNIPER_RIFLE_LOW ); + ADD_ACTIVITY_TO_SR( ACT_RANGE_AIM_SNIPER_RIFLE_LOW ); + ADD_ACTIVITY_TO_SR( ACT_GESTURE_RANGE_ATTACK_SNIPER_RIFLE ); + ADD_ACTIVITY_TO_SR( ACT_GESTURE_RELOAD_SNIPER_RIFLE ); + + ADD_ACTIVITY_TO_SR( ACT_IDLE_SNIPER_RIFLE_RELAXED ); + ADD_ACTIVITY_TO_SR( ACT_IDLE_SNIPER_RIFLE_STIMULATED ); + ADD_ACTIVITY_TO_SR( ACT_WALK_SNIPER_RIFLE_RELAXED ); + ADD_ACTIVITY_TO_SR( ACT_RUN_SNIPER_RIFLE_RELAXED ); + ADD_ACTIVITY_TO_SR( ACT_WALK_SNIPER_RIFLE_STIMULATED ); + ADD_ACTIVITY_TO_SR( ACT_RUN_SNIPER_RIFLE_STIMULATED ); + + ADD_ACTIVITY_TO_SR( ACT_IDLE_AIM_SNIPER_RIFLE_STIMULATED ); + ADD_ACTIVITY_TO_SR( ACT_WALK_AIM_SNIPER_RIFLE_STIMULATED ); + ADD_ACTIVITY_TO_SR( ACT_RUN_AIM_SNIPER_RIFLE_STIMULATED ); +#endif + +#if EXPANDED_NAVIGATION_ACTIVITIES ADD_ACTIVITY_TO_SR( ACT_CLIMB_ALL ); ADD_ACTIVITY_TO_SR( ACT_CLIMB_IDLE ); @@ -2336,6 +2416,15 @@ void CAI_BaseNPC::InitDefaultActivitySR(void) ADD_ACTIVITY_TO_SR( ACT_RANGE_AIM_REVOLVER_MED ); ADD_ACTIVITY_TO_SR( ACT_RANGE_AIM_CROSSBOW_MED ); +#if EXPANDED_HL2_UNUSED_WEAPON_ACTIVITIES + ADD_ACTIVITY_TO_SR( ACT_RANGE_AIM_AR1_MED ); + ADD_ACTIVITY_TO_SR( ACT_RANGE_ATTACK_AR1_MED ); + ADD_ACTIVITY_TO_SR( ACT_RANGE_AIM_SMG2_MED ); + ADD_ACTIVITY_TO_SR( ACT_RANGE_ATTACK_SMG2_MED ); + ADD_ACTIVITY_TO_SR( ACT_RANGE_AIM_SNIPER_RIFLE_MED ); + ADD_ACTIVITY_TO_SR( ACT_RANGE_ATTACK_SNIPER_RIFLE_MED ); +#endif + ADD_ACTIVITY_TO_SR( ACT_COVER_WALL_R ); ADD_ACTIVITY_TO_SR( ACT_COVER_WALL_L ); ADD_ACTIVITY_TO_SR( ACT_COVER_WALL_LOW_R ); @@ -2387,6 +2476,38 @@ void CAI_BaseNPC::InitDefaultActivitySR(void) ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RELOAD_REVOLVER ); ADD_ACTIVITY_TO_SR( ACT_HL2MP_JUMP_REVOLVER ); +#if EXPANDED_HL2_UNUSED_WEAPON_ACTIVITIES + ADD_ACTIVITY_TO_SR( ACT_HL2MP_IDLE_AR1 ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_RUN_AR1 ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_WALK_AR1 ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_IDLE_CROUCH_AR1 ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_WALK_CROUCH_AR1 ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RANGE_ATTACK_AR1 ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RANGE_ATTACK2_AR1 ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RELOAD_AR1 ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_JUMP_AR1 ); + + ADD_ACTIVITY_TO_SR( ACT_HL2MP_IDLE_SMG2 ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_RUN_SMG2 ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_WALK_SMG2 ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_IDLE_CROUCH_SMG2 ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_WALK_CROUCH_SMG2 ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RANGE_ATTACK_SMG2 ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RANGE_ATTACK2_SMG2 ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RELOAD_SMG2 ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_JUMP_SMG2 ); + + ADD_ACTIVITY_TO_SR( ACT_HL2MP_IDLE_SNIPER_RIFLE ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_RUN_SNIPER_RIFLE ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_WALK_SNIPER_RIFLE ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_IDLE_CROUCH_SNIPER_RIFLE ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_WALK_CROUCH_SNIPER_RIFLE ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RANGE_ATTACK_SNIPER_RIFLE ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RANGE_ATTACK2_SNIPER_RIFLE ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RELOAD_SNIPER_RIFLE ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_JUMP_SNIPER_RIFLE ); +#endif + ADD_ACTIVITY_TO_SR( ACT_HL2MP_IDLE_USE ); ADD_ACTIVITY_TO_SR( ACT_HL2MP_RUN_USE ); ADD_ACTIVITY_TO_SR( ACT_HL2MP_WALK_USE ); @@ -2485,6 +2606,28 @@ CAI_BaseNPC::actlink_t CAI_BaseNPC::gm_ActivityGestureLinks[] = { ACT_RELOAD_CROSSBOW, ACT_GESTURE_RELOAD_CROSSBOW }, { ACT_RELOAD_CROSSBOW_LOW, ACT_GESTURE_RELOAD_CROSSBOW }, #endif + +#if EXPANDED_HL2_UNUSED_WEAPON_ACTIVITIES + { ACT_RANGE_ATTACK_AR1, ACT_GESTURE_RANGE_ATTACK_AR1 }, + { ACT_RANGE_ATTACK_AR1_LOW, ACT_GESTURE_RANGE_ATTACK_AR1 }, + { ACT_RANGE_ATTACK_AR2_GRENADE, ACT_GESTURE_RANGE_ATTACK_AR2_GRENADE }, + { ACT_RANGE_ATTACK_HMG1, ACT_GESTURE_RANGE_ATTACK_HMG1 }, + { ACT_RANGE_ATTACK_ML, ACT_GESTURE_RANGE_ATTACK_ML }, + { ACT_RANGE_ATTACK_SMG2, ACT_GESTURE_RANGE_ATTACK_SMG2 }, + { ACT_RANGE_ATTACK_SMG2_LOW, ACT_GESTURE_RANGE_ATTACK_SMG2 }, + { ACT_RANGE_ATTACK_SLAM, ACT_GESTURE_RANGE_ATTACK_SLAM }, + { ACT_RANGE_ATTACK_TRIPWIRE, ACT_GESTURE_RANGE_ATTACK_TRIPWIRE }, + { ACT_RANGE_ATTACK_THROW, ACT_GESTURE_RANGE_ATTACK_THROW }, + { ACT_RANGE_ATTACK_SNIPER_RIFLE, ACT_GESTURE_RANGE_ATTACK_SNIPER_RIFLE }, + { ACT_RANGE_ATTACK_SNIPER_RIFLE_LOW, ACT_GESTURE_RANGE_ATTACK_SNIPER_RIFLE }, + + { ACT_RELOAD_AR1, ACT_GESTURE_RELOAD_AR1 }, + { ACT_RELOAD_AR1_LOW, ACT_GESTURE_RELOAD_AR1 }, + { ACT_RELOAD_SMG2, ACT_GESTURE_RELOAD_SMG2 }, + { ACT_RELOAD_SMG2_LOW, ACT_GESTURE_RELOAD_SMG2 }, + { ACT_RELOAD_SNIPER_RIFLE, ACT_GESTURE_RELOAD_SNIPER_RIFLE }, + { ACT_RELOAD_SNIPER_RIFLE_LOW, ACT_GESTURE_RELOAD_SNIPER_RIFLE }, +#endif }; Activity CAI_BaseNPC::GetGestureVersionOfActivity( Activity inActivity ) diff --git a/sp/src/game/server/hl2/weapon_ar1.cpp b/sp/src/game/server/hl2/weapon_ar1.cpp index 994cdabb..c6e49239 100644 --- a/sp/src/game/server/hl2/weapon_ar1.cpp +++ b/sp/src/game/server/hl2/weapon_ar1.cpp @@ -37,6 +37,10 @@ float Damage[ MAX_SETTINGS ] = 20, }; +#ifdef MAPBASE +extern acttable_t *GetAR2Acttable(); +extern int GetAR2ActtableCount(); +#endif //========================================================= //========================================================= @@ -93,6 +97,12 @@ public: break; } } + +#ifdef MAPBSAE + virtual acttable_t *GetBackupActivityList() { return GetAR2Acttable(); } + virtual int GetBackupActivityListCount() { return GetAR2ActtableCount(); } +#endif + DECLARE_ACTTABLE(); }; @@ -105,6 +115,77 @@ PRECACHE_WEAPON_REGISTER(weapon_ar1); acttable_t CWeaponAR1::m_acttable[] = { { ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_AR1, true }, + +#if EXPANDED_HL2_UNUSED_WEAPON_ACTIVITIES + // Optional new NPC activities + // (these should fall back to AR2 animations when they don't exist on an NPC) + { ACT_RELOAD, ACT_RELOAD_AR1, true }, + { ACT_IDLE, ACT_IDLE_AR1, true }, + { ACT_IDLE_ANGRY, ACT_IDLE_ANGRY_AR1, true }, + +// Readiness activities (not aiming) + { ACT_IDLE_RELAXED, ACT_IDLE_AR1_RELAXED, false },//never aims + { ACT_IDLE_STIMULATED, ACT_IDLE_AR1_STIMULATED, false }, + { ACT_IDLE_AGITATED, ACT_IDLE_ANGRY_AR1, false },//always aims + + { ACT_WALK_RELAXED, ACT_WALK_AR1_RELAXED, false },//never aims + { ACT_WALK_STIMULATED, ACT_WALK_AR1_STIMULATED, false }, + { ACT_WALK_AGITATED, ACT_WALK_AIM_AR1, false },//always aims + + { ACT_RUN_RELAXED, ACT_RUN_AR1_RELAXED, false },//never aims + { ACT_RUN_STIMULATED, ACT_RUN_AR1_STIMULATED, false }, + { ACT_RUN_AGITATED, ACT_RUN_AIM_AR1, false },//always aims + +// Readiness activities (aiming) + { ACT_IDLE_AIM_RELAXED, ACT_IDLE_AR1_RELAXED, false },//never aims + { ACT_IDLE_AIM_STIMULATED, ACT_IDLE_AIM_AR1_STIMULATED, false }, + { ACT_IDLE_AIM_AGITATED, ACT_IDLE_ANGRY_AR1, false },//always aims + + { ACT_WALK_AIM_RELAXED, ACT_WALK_AR1_RELAXED, false },//never aims + { ACT_WALK_AIM_STIMULATED, ACT_WALK_AIM_AR1_STIMULATED, false }, + { ACT_WALK_AIM_AGITATED, ACT_WALK_AIM_AR1, false },//always aims + + { ACT_RUN_AIM_RELAXED, ACT_RUN_AR1_RELAXED, false },//never aims + { ACT_RUN_AIM_STIMULATED, ACT_RUN_AIM_AR1_STIMULATED, false }, + { ACT_RUN_AIM_AGITATED, ACT_RUN_AIM_AR1, false },//always aims +//End readiness activities + + { ACT_WALK, ACT_WALK_AR1, true }, + { ACT_WALK_AIM, ACT_WALK_AIM_AR1, true }, + { ACT_WALK_CROUCH, ACT_WALK_CROUCH_RIFLE, true }, + { ACT_WALK_CROUCH_AIM, ACT_WALK_CROUCH_AIM_RIFLE, true }, + { ACT_RUN, ACT_RUN_AR1, true }, + { ACT_RUN_AIM, ACT_RUN_AIM_AR1, true }, + { ACT_RUN_CROUCH, ACT_RUN_CROUCH_RIFLE, true }, + { ACT_RUN_CROUCH_AIM, ACT_RUN_CROUCH_AIM_RIFLE, true }, + { ACT_GESTURE_RANGE_ATTACK1, ACT_GESTURE_RANGE_ATTACK_AR1, true }, + { ACT_RANGE_ATTACK1_LOW, ACT_RANGE_ATTACK_AR1_LOW, true }, + { ACT_COVER_LOW, ACT_COVER_AR1_LOW, false }, + { ACT_RANGE_AIM_LOW, ACT_RANGE_AIM_AR1_LOW, false }, + { ACT_RELOAD_LOW, ACT_RELOAD_AR1_LOW, false }, + { ACT_GESTURE_RELOAD, ACT_GESTURE_RELOAD_AR1, true }, + + { ACT_ARM, ACT_ARM_RIFLE, false }, + { ACT_DISARM, ACT_DISARM_RIFLE, false }, + +#if EXPANDED_HL2_COVER_ACTIVITIES + { ACT_RANGE_AIM_MED, ACT_RANGE_AIM_AR1_MED, false }, + { ACT_RANGE_ATTACK1_MED, ACT_RANGE_ATTACK_AR1_MED, false }, +#endif + +#if EXPANDED_HL2DM_ACTIVITIES + // HL2:DM activities (for third-person animations in SP) + { ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_AR1, false }, + { ACT_HL2MP_RUN, ACT_HL2MP_RUN_AR1, false }, + { ACT_HL2MP_IDLE_CROUCH, ACT_HL2MP_IDLE_CROUCH_AR1, false }, + { ACT_HL2MP_WALK_CROUCH, ACT_HL2MP_WALK_CROUCH_AR1, false }, + { ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_AR1, false }, + { ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_AR1, false }, + { ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_AR1, false }, + { ACT_HL2MP_WALK, ACT_HL2MP_WALK_AR1, false }, + { ACT_HL2MP_GESTURE_RANGE_ATTACK2, ACT_HL2MP_GESTURE_RANGE_ATTACK2_AR1, false }, +#endif +#endif }; IMPLEMENT_ACTTABLE(CWeaponAR1); diff --git a/sp/src/game/server/hl2/weapon_ar2.cpp b/sp/src/game/server/hl2/weapon_ar2.cpp index 0437c15d..1a3a1633 100644 --- a/sp/src/game/server/hl2/weapon_ar2.cpp +++ b/sp/src/game/server/hl2/weapon_ar2.cpp @@ -190,6 +190,19 @@ acttable_t CWeaponAR2::m_acttable[] = IMPLEMENT_ACTTABLE(CWeaponAR2); +#ifdef MAPBASE +// Allows Weapon_BackupActivity() to access the AR2's activity table. +acttable_t *GetAR2Acttable() +{ + return CWeaponAR2::m_acttable; +} + +int GetSAR2ActtableCount() +{ + return ARRAYSIZE(CWeaponAR2::m_acttable); +} +#endif + CWeaponAR2::CWeaponAR2( ) { m_fMinRange1 = 65; diff --git a/sp/src/game/server/hl2/weapon_ar2.h b/sp/src/game/server/hl2/weapon_ar2.h index d5376a83..5a855f2c 100644 --- a/sp/src/game/server/hl2/weapon_ar2.h +++ b/sp/src/game/server/hl2/weapon_ar2.h @@ -71,6 +71,9 @@ protected: bool m_bShotDelayed; int m_nVentPose; +#ifdef MAPBASE // Make act table accessible outside class +public: +#endif DECLARE_ACTTABLE(); DECLARE_DATADESC(); }; diff --git a/sp/src/game/server/hl2/weapon_smg2.cpp b/sp/src/game/server/hl2/weapon_smg2.cpp index 498faddd..9c5037b9 100644 --- a/sp/src/game/server/hl2/weapon_smg2.cpp +++ b/sp/src/game/server/hl2/weapon_smg2.cpp @@ -46,6 +46,77 @@ PRECACHE_WEAPON_REGISTER(weapon_smg2); acttable_t CWeaponSMG2::m_acttable[] = { { ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_SMG2, true }, + +#if EXPANDED_HL2_UNUSED_WEAPON_ACTIVITIES + // Optional new NPC activities + // (these should fall back to SMG animations when they don't exist on an NPC) + { ACT_RELOAD, ACT_RELOAD_SMG2, true }, + { ACT_IDLE, ACT_IDLE_SMG2, true }, + { ACT_IDLE_ANGRY, ACT_IDLE_ANGRY_SMG2, true }, + +// Readiness activities (not aiming) + { ACT_IDLE_RELAXED, ACT_IDLE_SMG2_RELAXED, false },//never aims + { ACT_IDLE_STIMULATED, ACT_IDLE_SMG2_STIMULATED, false }, + { ACT_IDLE_AGITATED, ACT_IDLE_ANGRY_SMG2, false },//always aims + + { ACT_WALK_RELAXED, ACT_WALK_SMG2_RELAXED, false },//never aims + { ACT_WALK_STIMULATED, ACT_WALK_SMG2_STIMULATED, false }, + { ACT_WALK_AGITATED, ACT_WALK_AIM_SMG2, false },//always aims + + { ACT_RUN_RELAXED, ACT_RUN_SMG2_RELAXED, false },//never aims + { ACT_RUN_STIMULATED, ACT_RUN_SMG2_STIMULATED, false }, + { ACT_RUN_AGITATED, ACT_RUN_AIM_SMG2, false },//always aims + +// Readiness activities (aiming) + { ACT_IDLE_AIM_RELAXED, ACT_IDLE_SMG2_RELAXED, false },//never aims + { ACT_IDLE_AIM_STIMULATED, ACT_IDLE_AIM_SMG2_STIMULATED, false }, + { ACT_IDLE_AIM_AGITATED, ACT_IDLE_ANGRY_SMG2, false },//always aims + + { ACT_WALK_AIM_RELAXED, ACT_WALK_SMG2_RELAXED, false },//never aims + { ACT_WALK_AIM_STIMULATED, ACT_WALK_AIM_SMG2_STIMULATED, false }, + { ACT_WALK_AIM_AGITATED, ACT_WALK_AIM_SMG2, false },//always aims + + { ACT_RUN_AIM_RELAXED, ACT_RUN_SMG2_RELAXED, false },//never aims + { ACT_RUN_AIM_STIMULATED, ACT_RUN_AIM_SMG2_STIMULATED, false }, + { ACT_RUN_AIM_AGITATED, ACT_RUN_AIM_SMG2, false },//always aims +//End readiness activities + + { ACT_WALK, ACT_WALK_SMG2, true }, + { ACT_WALK_AIM, ACT_WALK_AIM_SMG2, true }, + { ACT_WALK_CROUCH, ACT_WALK_CROUCH_RIFLE, true }, + { ACT_WALK_CROUCH_AIM, ACT_WALK_CROUCH_AIM_RIFLE, true }, + { ACT_RUN, ACT_RUN_SMG2, true }, + { ACT_RUN_AIM, ACT_RUN_AIM_SMG2, true }, + { ACT_RUN_CROUCH, ACT_RUN_CROUCH_RIFLE, true }, + { ACT_RUN_CROUCH_AIM, ACT_RUN_CROUCH_AIM_RIFLE, true }, + { ACT_GESTURE_RANGE_ATTACK1, ACT_GESTURE_RANGE_ATTACK_SMG2, true }, + { ACT_RANGE_ATTACK1_LOW, ACT_RANGE_ATTACK_SMG2_LOW, true }, + { ACT_COVER_LOW, ACT_COVER_SMG2_LOW, false }, + { ACT_RANGE_AIM_LOW, ACT_RANGE_AIM_SMG2_LOW, false }, + { ACT_RELOAD_LOW, ACT_RELOAD_SMG2_LOW, false }, + { ACT_GESTURE_RELOAD, ACT_GESTURE_RELOAD_SMG2, true }, + + { ACT_ARM, ACT_ARM_RIFLE, false }, + { ACT_DISARM, ACT_DISARM_RIFLE, false }, + +#if EXPANDED_HL2_COVER_ACTIVITIES + { ACT_RANGE_AIM_MED, ACT_RANGE_AIM_SMG2_MED, false }, + { ACT_RANGE_ATTACK1_MED, ACT_RANGE_ATTACK_SMG2_MED, false }, +#endif + +#if EXPANDED_HL2DM_ACTIVITIES + // HL2:DM activities (for third-person animations in SP) + { ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_SMG2, false }, + { ACT_HL2MP_RUN, ACT_HL2MP_RUN_SMG2, false }, + { ACT_HL2MP_IDLE_CROUCH, ACT_HL2MP_IDLE_CROUCH_SMG2, false }, + { ACT_HL2MP_WALK_CROUCH, ACT_HL2MP_WALK_CROUCH_SMG2, false }, + { ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_SMG2, false }, + { ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_SMG2, false }, + { ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_SMG2, false }, + { ACT_HL2MP_WALK, ACT_HL2MP_WALK_SMG2, false }, + { ACT_HL2MP_GESTURE_RANGE_ATTACK2, ACT_HL2MP_GESTURE_RANGE_ATTACK2_SMG2, false }, +#endif +#endif }; IMPLEMENT_ACTTABLE(CWeaponSMG2); diff --git a/sp/src/game/server/hl2/weapon_sniperrifle.cpp b/sp/src/game/server/hl2/weapon_sniperrifle.cpp index 901a73ae..10777f89 100644 --- a/sp/src/game/server/hl2/weapon_sniperrifle.cpp +++ b/sp/src/game/server/hl2/weapon_sniperrifle.cpp @@ -46,6 +46,10 @@ static int g_nZoomFOV[] = 5 }; +#ifdef MAPBASE +extern acttable_t *GetAR2Acttable(); +extern int GetAR2ActtableCount(); +#endif class CWeaponSniperRifle : public CBaseHLCombatWeapon { @@ -72,6 +76,11 @@ public: void Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatCharacter *pOperator ); +#ifdef MAPBSAE + virtual acttable_t *GetBackupActivityList() { return GetAR2Acttable(); } + virtual int GetBackupActivityListCount() { return GetAR2ActtableCount(); } +#endif + DECLARE_ACTTABLE(); protected: @@ -99,6 +108,77 @@ END_DATADESC() acttable_t CWeaponSniperRifle::m_acttable[] = { { ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_SNIPER_RIFLE, true } + +#if EXPANDED_HL2_UNUSED_WEAPON_ACTIVITIES + // Optional new NPC activities + // (these should fall back to AR2 animations when they don't exist on an NPC) + { ACT_RELOAD, ACT_RELOAD_SNIPER_RIFLE, true }, + { ACT_IDLE, ACT_IDLE_SNIPER_RIFLE, true }, + { ACT_IDLE_ANGRY, ACT_IDLE_ANGRY_SNIPER_RIFLE, true }, + +// Readiness activities (not aiming) + { ACT_IDLE_RELAXED, ACT_IDLE_SNIPER_RIFLE_RELAXED, false },//never aims + { ACT_IDLE_STIMULATED, ACT_IDLE_SNIPER_RIFLE_STIMULATED, false }, + { ACT_IDLE_AGITATED, ACT_IDLE_ANGRY_SNIPER_RIFLE, false },//always aims + + { ACT_WALK_RELAXED, ACT_WALK_SNIPER_RIFLE_RELAXED, false },//never aims + { ACT_WALK_STIMULATED, ACT_WALK_SNIPER_RIFLE_STIMULATED, false }, + { ACT_WALK_AGITATED, ACT_WALK_AIM_SNIPER_RIFLE, false },//always aims + + { ACT_RUN_RELAXED, ACT_RUN_SNIPER_RIFLE_RELAXED, false },//never aims + { ACT_RUN_STIMULATED, ACT_RUN_SNIPER_RIFLE_STIMULATED, false }, + { ACT_RUN_AGITATED, ACT_RUN_AIM_SNIPER_RIFLE, false },//always aims + +// Readiness activities (aiming) + { ACT_IDLE_AIM_RELAXED, ACT_IDLE_SNIPER_RIFLE_RELAXED, false },//never aims + { ACT_IDLE_AIM_STIMULATED, ACT_IDLE_AIM_SNIPER_RIFLE_STIMULATED, false }, + { ACT_IDLE_AIM_AGITATED, ACT_IDLE_ANGRY_SNIPER_RIFLE, false },//always aims + + { ACT_WALK_AIM_RELAXED, ACT_WALK_SNIPER_RIFLE_RELAXED, false },//never aims + { ACT_WALK_AIM_STIMULATED, ACT_WALK_AIM_SNIPER_RIFLE_STIMULATED, false }, + { ACT_WALK_AIM_AGITATED, ACT_WALK_AIM_SNIPER_RIFLE, false },//always aims + + { ACT_RUN_AIM_RELAXED, ACT_RUN_SNIPER_RIFLE_RELAXED, false },//never aims + { ACT_RUN_AIM_STIMULATED, ACT_RUN_AIM_SNIPER_RIFLE_STIMULATED, false }, + { ACT_RUN_AIM_AGITATED, ACT_RUN_AIM_SNIPER_RIFLE, false },//always aims +//End readiness activities + + { ACT_WALK, ACT_WALK_SNIPER_RIFLE, true }, + { ACT_WALK_AIM, ACT_WALK_AIM_SNIPER_RIFLE, true }, + { ACT_WALK_CROUCH, ACT_WALK_CROUCH_RIFLE, true }, + { ACT_WALK_CROUCH_AIM, ACT_WALK_CROUCH_AIM_RIFLE, true }, + { ACT_RUN, ACT_RUN_SNIPER_RIFLE, true }, + { ACT_RUN_AIM, ACT_RUN_AIM_SNIPER_RIFLE, true }, + { ACT_RUN_CROUCH, ACT_RUN_CROUCH_RIFLE, true }, + { ACT_RUN_CROUCH_AIM, ACT_RUN_CROUCH_AIM_RIFLE, true }, + { ACT_GESTURE_RANGE_ATTACK1, ACT_GESTURE_RANGE_ATTACK_SNIPER_RIFLE, true }, + { ACT_RANGE_ATTACK1_LOW, ACT_RANGE_ATTACK_SNIPER_RIFLE_LOW, true }, + { ACT_COVER_LOW, ACT_COVER_SNIPER_RIFLE_LOW, false }, + { ACT_RANGE_AIM_LOW, ACT_RANGE_AIM_SNIPER_RIFLE_LOW, false }, + { ACT_RELOAD_LOW, ACT_RELOAD_SNIPER_RIFLE_LOW, false }, + { ACT_GESTURE_RELOAD, ACT_GESTURE_RELOAD_SNIPER_RIFLE, true }, + + { ACT_ARM, ACT_ARM_RIFLE, false }, + { ACT_DISARM, ACT_DISARM_RIFLE, false }, + +#if EXPANDED_HL2_COVER_ACTIVITIES + { ACT_RANGE_AIM_MED, ACT_RANGE_AIM_SNIPER_RIFLE_MED, false }, + { ACT_RANGE_ATTACK1_MED, ACT_RANGE_ATTACK_SNIPER_RIFLE_MED, false }, +#endif + +#if EXPANDED_HL2DM_ACTIVITIES + // HL2:DM activities (for third-person animations in SP) + { ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_SNIPER_RIFLE, false }, + { ACT_HL2MP_RUN, ACT_HL2MP_RUN_SNIPER_RIFLE, false }, + { ACT_HL2MP_IDLE_CROUCH, ACT_HL2MP_IDLE_CROUCH_SNIPER_RIFLE, false }, + { ACT_HL2MP_WALK_CROUCH, ACT_HL2MP_WALK_CROUCH_SNIPER_RIFLE, false }, + { ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_SNIPER_RIFLE, false }, + { ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_SNIPER_RIFLE, false }, + { ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_SNIPER_RIFLE, false }, + { ACT_HL2MP_WALK, ACT_HL2MP_WALK_SNIPER_RIFLE, false }, + { ACT_HL2MP_GESTURE_RANGE_ATTACK2, ACT_HL2MP_GESTURE_RANGE_ATTACK2_SNIPER_RIFLE, false }, +#endif +#endif }; IMPLEMENT_ACTTABLE(CWeaponSniperRifle); diff --git a/sp/src/game/shared/activitylist.cpp b/sp/src/game/shared/activitylist.cpp index 1a2c1955..0b17d272 100644 --- a/sp/src/game/shared/activitylist.cpp +++ b/sp/src/game/shared/activitylist.cpp @@ -2422,7 +2422,87 @@ void ActivityList_RegisterSharedActivities( void ) REGISTER_SHARED_ACTIVITY( ACT_DISARM_MELEE ); #endif -#ifdef EXPANDED_NAVIGATION_ACTIVITIES +#if EXPANDED_HL2_UNUSED_WEAPON_ACTIVITIES + REGISTER_SHARED_ACTIVITY( ACT_IDLE_AR1 ); + REGISTER_SHARED_ACTIVITY( ACT_IDLE_ANGRY_AR1 ); + REGISTER_SHARED_ACTIVITY( ACT_WALK_AR1 ); + REGISTER_SHARED_ACTIVITY( ACT_RUN_AR1 ); + REGISTER_SHARED_ACTIVITY( ACT_WALK_AIM_AR1 ); + REGISTER_SHARED_ACTIVITY( ACT_RUN_AIM_AR1 ); + REGISTER_SHARED_ACTIVITY( ACT_RANGE_ATTACK_AR1 ); + REGISTER_SHARED_ACTIVITY( ACT_RELOAD_AR1 ); + REGISTER_SHARED_ACTIVITY( ACT_RANGE_ATTACK_AR1_LOW ); + REGISTER_SHARED_ACTIVITY( ACT_RELOAD_AR1_LOW ); + REGISTER_SHARED_ACTIVITY( ACT_COVER_AR1_LOW ); + REGISTER_SHARED_ACTIVITY( ACT_RANGE_AIM_AR1_LOW ); + REGISTER_SHARED_ACTIVITY( ACT_GESTURE_RANGE_ATTACK_AR1 ); + REGISTER_SHARED_ACTIVITY( ACT_GESTURE_RELOAD_AR1 ); + + REGISTER_SHARED_ACTIVITY( ACT_IDLE_AR1_RELAXED ); + REGISTER_SHARED_ACTIVITY( ACT_IDLE_AR1_STIMULATED ); + REGISTER_SHARED_ACTIVITY( ACT_WALK_AR1_RELAXED ); + REGISTER_SHARED_ACTIVITY( ACT_RUN_AR1_RELAXED ); + REGISTER_SHARED_ACTIVITY( ACT_WALK_AR1_STIMULATED ); + REGISTER_SHARED_ACTIVITY( ACT_RUN_AR1_STIMULATED ); + + REGISTER_SHARED_ACTIVITY( ACT_IDLE_AIM_AR1_STIMULATED ); + REGISTER_SHARED_ACTIVITY( ACT_WALK_AIM_AR1_STIMULATED ); + REGISTER_SHARED_ACTIVITY( ACT_RUN_AIM_AR1_STIMULATED ); + + REGISTER_SHARED_ACTIVITY( ACT_IDLE_SMG2 ); + REGISTER_SHARED_ACTIVITY( ACT_IDLE_ANGRY_SMG2 ); + REGISTER_SHARED_ACTIVITY( ACT_WALK_SMG2 ); + REGISTER_SHARED_ACTIVITY( ACT_RUN_SMG2 ); + REGISTER_SHARED_ACTIVITY( ACT_WALK_AIM_SMG2 ); + REGISTER_SHARED_ACTIVITY( ACT_RUN_AIM_SMG2 ); + REGISTER_SHARED_ACTIVITY( ACT_RANGE_ATTACK_SMG2 ); + REGISTER_SHARED_ACTIVITY( ACT_RELOAD_SMG2 ); + REGISTER_SHARED_ACTIVITY( ACT_RANGE_ATTACK_SMG2_LOW ); + REGISTER_SHARED_ACTIVITY( ACT_RELOAD_SMG2_LOW ); + REGISTER_SHARED_ACTIVITY( ACT_COVER_SMG2_LOW ); + REGISTER_SHARED_ACTIVITY( ACT_RANGE_AIM_SMG2_LOW ); + REGISTER_SHARED_ACTIVITY( ACT_GESTURE_RANGE_ATTACK_SMG2 ); + REGISTER_SHARED_ACTIVITY( ACT_GESTURE_RELOAD_SMG2 ); + + REGISTER_SHARED_ACTIVITY( ACT_IDLE_SMG2_RELAXED ); + REGISTER_SHARED_ACTIVITY( ACT_IDLE_SMG2_STIMULATED ); + REGISTER_SHARED_ACTIVITY( ACT_WALK_SMG2_RELAXED ); + REGISTER_SHARED_ACTIVITY( ACT_RUN_SMG2_RELAXED ); + REGISTER_SHARED_ACTIVITY( ACT_WALK_SMG2_STIMULATED ); + REGISTER_SHARED_ACTIVITY( ACT_RUN_SMG2_STIMULATED ); + + REGISTER_SHARED_ACTIVITY( ACT_IDLE_AIM_SMG2_STIMULATED ); + REGISTER_SHARED_ACTIVITY( ACT_WALK_AIM_SMG2_STIMULATED ); + REGISTER_SHARED_ACTIVITY( ACT_RUN_AIM_SMG2_STIMULATED ); + + REGISTER_SHARED_ACTIVITY( ACT_IDLE_SNIPER_RIFLE ); + REGISTER_SHARED_ACTIVITY( ACT_IDLE_ANGRY_SNIPER_RIFLE ); + REGISTER_SHARED_ACTIVITY( ACT_WALK_SNIPER_RIFLE ); + REGISTER_SHARED_ACTIVITY( ACT_RUN_SNIPER_RIFLE ); + REGISTER_SHARED_ACTIVITY( ACT_WALK_AIM_SNIPER_RIFLE ); + REGISTER_SHARED_ACTIVITY( ACT_RUN_AIM_SNIPER_RIFLE ); + REGISTER_SHARED_ACTIVITY( ACT_RANGE_ATTACK_SNIPER_RIFLE ); + REGISTER_SHARED_ACTIVITY( ACT_RELOAD_SNIPER_RIFLE ); + REGISTER_SHARED_ACTIVITY( ACT_RANGE_ATTACK_SNIPER_RIFLE_LOW ); + REGISTER_SHARED_ACTIVITY( ACT_RELOAD_SNIPER_RIFLE_LOW ); + REGISTER_SHARED_ACTIVITY( ACT_COVER_SNIPER_RIFLE_LOW ); + REGISTER_SHARED_ACTIVITY( ACT_RANGE_AIM_SNIPER_RIFLE_LOW ); + REGISTER_SHARED_ACTIVITY( ACT_GESTURE_RANGE_ATTACK_SNIPER_RIFLE ); + REGISTER_SHARED_ACTIVITY( ACT_GESTURE_RELOAD_SNIPER_RIFLE ); + + REGISTER_SHARED_ACTIVITY( ACT_IDLE_SNIPER_RIFLE_RELAXED ); + REGISTER_SHARED_ACTIVITY( ACT_IDLE_SNIPER_RIFLE_STIMULATED ); + REGISTER_SHARED_ACTIVITY( ACT_WALK_SNIPER_RIFLE_RELAXED ); + REGISTER_SHARED_ACTIVITY( ACT_RUN_SNIPER_RIFLE_RELAXED ); + REGISTER_SHARED_ACTIVITY( ACT_WALK_SNIPER_RIFLE_STIMULATED ); + REGISTER_SHARED_ACTIVITY( ACT_RUN_SNIPER_RIFLE_STIMULATED ); + + REGISTER_SHARED_ACTIVITY( ACT_IDLE_AIM_SNIPER_RIFLE_STIMULATED ); + REGISTER_SHARED_ACTIVITY( ACT_WALK_AIM_SNIPER_RIFLE_STIMULATED ); + REGISTER_SHARED_ACTIVITY( ACT_RUN_AIM_SNIPER_RIFLE_STIMULATED ); +#endif + +#if EXPANDED_NAVIGATION_ACTIVITIES REGISTER_SHARED_ACTIVITY( ACT_CLIMB_ALL ); REGISTER_SHARED_ACTIVITY( ACT_CLIMB_IDLE ); @@ -2452,6 +2532,15 @@ void ActivityList_RegisterSharedActivities( void ) REGISTER_SHARED_ACTIVITY( ACT_RANGE_AIM_REVOLVER_MED ); REGISTER_SHARED_ACTIVITY( ACT_RANGE_AIM_CROSSBOW_MED ); +#if EXPANDED_HL2_UNUSED_WEAPON_ACTIVITIES + REGISTER_SHARED_ACTIVITY( ACT_RANGE_AIM_AR1_MED ); + REGISTER_SHARED_ACTIVITY( ACT_RANGE_ATTACK_AR1_MED ); + REGISTER_SHARED_ACTIVITY( ACT_RANGE_AIM_SMG2_MED ); + REGISTER_SHARED_ACTIVITY( ACT_RANGE_ATTACK_SMG2_MED ); + REGISTER_SHARED_ACTIVITY( ACT_RANGE_AIM_SNIPER_RIFLE_MED ); + REGISTER_SHARED_ACTIVITY( ACT_RANGE_ATTACK_SNIPER_RIFLE_MED ); +#endif + REGISTER_SHARED_ACTIVITY( ACT_COVER_WALL_R ); REGISTER_SHARED_ACTIVITY( ACT_COVER_WALL_L ); REGISTER_SHARED_ACTIVITY( ACT_COVER_WALL_LOW_R ); @@ -2503,6 +2592,38 @@ void ActivityList_RegisterSharedActivities( void ) REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RELOAD_REVOLVER ); REGISTER_SHARED_ACTIVITY( ACT_HL2MP_JUMP_REVOLVER ); +#if EXPANDED_HL2_UNUSED_WEAPON_ACTIVITIES + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_IDLE_AR1 ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_RUN_AR1 ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_WALK_AR1 ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_IDLE_CROUCH_AR1 ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_WALK_CROUCH_AR1 ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RANGE_ATTACK_AR1 ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RANGE_ATTACK2_AR1 ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RELOAD_AR1 ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_JUMP_AR1 ); + + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_IDLE_SMG2 ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_RUN_SMG2 ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_WALK_SMG2 ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_IDLE_CROUCH_SMG2 ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_WALK_CROUCH_SMG2 ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RANGE_ATTACK_SMG2 ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RANGE_ATTACK2_SMG2 ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RELOAD_SMG2 ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_JUMP_SMG2 ); + + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_IDLE_SNIPER_RIFLE ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_RUN_SNIPER_RIFLE ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_WALK_SNIPER_RIFLE ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_IDLE_CROUCH_SNIPER_RIFLE ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_WALK_CROUCH_SNIPER_RIFLE ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RANGE_ATTACK_SNIPER_RIFLE ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RANGE_ATTACK2_SNIPER_RIFLE ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RELOAD_SNIPER_RIFLE ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_JUMP_SNIPER_RIFLE ); +#endif + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_IDLE_USE ); REGISTER_SHARED_ACTIVITY( ACT_HL2MP_RUN_USE ); REGISTER_SHARED_ACTIVITY( ACT_HL2MP_WALK_USE ); diff --git a/sp/src/game/shared/ai_activity.h b/sp/src/game/shared/ai_activity.h index 99d09312..2373f2f9 100644 --- a/sp/src/game/shared/ai_activity.h +++ b/sp/src/game/shared/ai_activity.h @@ -41,6 +41,12 @@ // This enables a bunch of new activities for Half-Life 2 weapons, including new 357 animations and readiness activities for pistols. #define EXPANDED_HL2_WEAPON_ACTIVITIES 1 +// EXPANDED HL2 UNUSED WEAPON ACTIVITIES +// This enables a bunch of new activities for unused Half-Life 2 weapons, particularly those which exist in the SDK, but are deactivated by default. +// This essentially just means mods which restore those weapons have the option of using custom activities for them. +// Mapbase's backup activity system would allow them to fall back to other weapons if the relevant activities do not exist. +#define EXPANDED_HL2_UNUSED_WEAPON_ACTIVITIES 0 + // EXPANDED NAVIGATION ACTIVITIES // This enables some new navigation-related activities. #define EXPANDED_NAVIGATION_ACTIVITIES 1 @@ -2309,7 +2315,90 @@ typedef enum ACT_DISARM_MELEE, #endif -#ifdef EXPANDED_NAVIGATION_ACTIVITIES +#if EXPANDED_HL2_UNUSED_WEAPON_ACTIVITIES + // AR1 + ACT_IDLE_AR1, + ACT_IDLE_ANGRY_AR1, + ACT_WALK_AR1, + ACT_RUN_AR1, + ACT_WALK_AIM_AR1, + ACT_RUN_AIM_AR1, + //ACT_RANGE_ATTACK_AR1, + ACT_RELOAD_AR1, + ACT_RANGE_ATTACK_AR1_LOW, + ACT_RELOAD_AR1_LOW, + ACT_COVER_AR1_LOW, + ACT_RANGE_AIM_AR1_LOW, + //ACT_GESTURE_RANGE_ATTACK_AR1, + ACT_GESTURE_RELOAD_AR1, + + ACT_IDLE_AR1_RELAXED, + ACT_IDLE_AR1_STIMULATED, + ACT_WALK_AR1_RELAXED, + ACT_RUN_AR1_RELAXED, + ACT_WALK_AR1_STIMULATED, + ACT_RUN_AR1_STIMULATED, + + ACT_IDLE_AIM_AR1_STIMULATED, + ACT_WALK_AIM_AR1_STIMULATED, + ACT_RUN_AIM_AR1_STIMULATED, + + // SMG2 + ACT_IDLE_SMG2, + ACT_IDLE_ANGRY_SMG2, + ACT_WALK_SMG2, + ACT_RUN_SMG2, + ACT_WALK_AIM_SMG2, + ACT_RUN_AIM_SMG2, + //ACT_RANGE_ATTACK_SMG2, + ACT_RELOAD_SMG2, + ACT_RANGE_ATTACK_SMG2_LOW, + ACT_RELOAD_SMG2_LOW, + ACT_COVER_SMG2_LOW, + ACT_RANGE_AIM_SMG2_LOW, + //ACT_GESTURE_RANGE_ATTACK_SMG2, + ACT_GESTURE_RELOAD_SMG2, + + ACT_IDLE_SMG2_RELAXED, + ACT_IDLE_SMG2_STIMULATED, + ACT_WALK_SMG2_RELAXED, + ACT_RUN_SMG2_RELAXED, + ACT_WALK_SMG2_STIMULATED, + ACT_RUN_SMG2_STIMULATED, + + ACT_IDLE_AIM_SMG2_STIMULATED, + ACT_WALK_AIM_SMG2_STIMULATED, + ACT_RUN_AIM_SMG2_STIMULATED, + + // Sniper Rifle + ACT_IDLE_SNIPER_RIFLE, + ACT_IDLE_ANGRY_SNIPER_RIFLE, + ACT_WALK_SNIPER_RIFLE, + ACT_RUN_SNIPER_RIFLE, + ACT_WALK_AIM_SNIPER_RIFLE, + ACT_RUN_AIM_SNIPER_RIFLE, + //ACT_RANGE_ATTACK_SNIPER_RIFLE, + ACT_RELOAD_SNIPER_RIFLE, + ACT_RANGE_ATTACK_SNIPER_RIFLE_LOW, + ACT_RELOAD_SNIPER_RIFLE_LOW, + ACT_COVER_SNIPER_RIFLE_LOW, + ACT_RANGE_AIM_SNIPER_RIFLE_LOW, + //ACT_GESTURE_RANGE_ATTACK_SNIPER_RIFLE, + ACT_GESTURE_RELOAD_SNIPER_RIFLE, + + ACT_IDLE_SNIPER_RIFLE_RELAXED, + ACT_IDLE_SNIPER_RIFLE_STIMULATED, + ACT_WALK_SNIPER_RIFLE_RELAXED, + ACT_RUN_SNIPER_RIFLE_RELAXED, + ACT_WALK_SNIPER_RIFLE_STIMULATED, + ACT_RUN_SNIPER_RIFLE_STIMULATED, + + ACT_IDLE_AIM_SNIPER_RIFLE_STIMULATED, + ACT_WALK_AIM_SNIPER_RIFLE_STIMULATED, + ACT_RUN_AIM_SNIPER_RIFLE_STIMULATED, +#endif + +#if EXPANDED_NAVIGATION_ACTIVITIES ACT_CLIMB_ALL, // An actual blend animation which uses pose parameters for direction ACT_CLIMB_IDLE, @@ -2340,6 +2429,16 @@ typedef enum ACT_RANGE_AIM_REVOLVER_MED, ACT_RANGE_AIM_CROSSBOW_MED, +#if EXPANDED_HL2_UNUSED_WEAPON_ACTIVITIES + // MED activities for unused weapons + ACT_RANGE_AIM_AR1_MED, + ACT_RANGE_ATTACK_AR1_MED, + ACT_RANGE_AIM_SMG2_MED, + ACT_RANGE_ATTACK_SMG2_MED, + ACT_RANGE_AIM_SNIPER_RIFLE_MED, + ACT_RANGE_ATTACK_SNIPER_RIFLE_MED, +#endif + // Wall Cover (for use in custom cover hints) ACT_COVER_WALL_R, ACT_COVER_WALL_L, @@ -2392,6 +2491,39 @@ typedef enum ACT_HL2MP_GESTURE_RELOAD_REVOLVER, ACT_HL2MP_JUMP_REVOLVER, +#if EXPANDED_HL2_UNUSED_WEAPON_ACTIVITIES + // Player activities for unused weapons + ACT_HL2MP_IDLE_AR1, + ACT_HL2MP_RUN_AR1, + ACT_HL2MP_WALK_AR1, + ACT_HL2MP_IDLE_CROUCH_AR1, + ACT_HL2MP_WALK_CROUCH_AR1, + ACT_HL2MP_GESTURE_RANGE_ATTACK_AR1, + ACT_HL2MP_GESTURE_RANGE_ATTACK2_AR1, + ACT_HL2MP_GESTURE_RELOAD_AR1, + ACT_HL2MP_JUMP_AR1, + + ACT_HL2MP_IDLE_SMG2, + ACT_HL2MP_RUN_SMG2, + ACT_HL2MP_WALK_SMG2, + ACT_HL2MP_IDLE_CROUCH_SMG2, + ACT_HL2MP_WALK_CROUCH_SMG2, + ACT_HL2MP_GESTURE_RANGE_ATTACK_SMG2, + ACT_HL2MP_GESTURE_RANGE_ATTACK2_SMG2, + ACT_HL2MP_GESTURE_RELOAD_SMG2, + ACT_HL2MP_JUMP_SMG2, + + ACT_HL2MP_IDLE_SNIPER_RIFLE, + ACT_HL2MP_RUN_SNIPER_RIFLE, + ACT_HL2MP_WALK_SNIPER_RIFLE, + ACT_HL2MP_IDLE_CROUCH_SNIPER_RIFLE, + ACT_HL2MP_WALK_CROUCH_SNIPER_RIFLE, + ACT_HL2MP_GESTURE_RANGE_ATTACK_SNIPER_RIFLE, + ACT_HL2MP_GESTURE_RANGE_ATTACK2_SNIPER_RIFLE, + ACT_HL2MP_GESTURE_RELOAD_SNIPER_RIFLE, + ACT_HL2MP_JUMP_SNIPER_RIFLE, +#endif + ACT_HL2MP_IDLE_USE, ACT_HL2MP_RUN_USE, ACT_HL2MP_WALK_USE, From 79ff53ecdfee5dcfbe172da0db77398cfe2b618f Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sun, 21 Nov 2021 00:13:56 -0600 Subject: [PATCH 280/378] Added support for NPCs with innate range attacks (e.g. vorts) in standoffs --- sp/src/game/server/ai_behavior_standoff.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sp/src/game/server/ai_behavior_standoff.cpp b/sp/src/game/server/ai_behavior_standoff.cpp index 29c89e39..00e1565b 100644 --- a/sp/src/game/server/ai_behavior_standoff.cpp +++ b/sp/src/game/server/ai_behavior_standoff.cpp @@ -296,7 +296,12 @@ bool CAI_StandoffBehavior::CanSelectSchedule() if ( !m_fActive ) return false; +#ifdef MAPBASE + // Allow NPCs with innate range attacks to use standoffs + return ( GetNpcState() == NPC_STATE_COMBAT && (GetOuter()->GetActiveWeapon() != NULL || GetOuter()->CapabilitiesGet() & bits_CAP_INNATE_RANGE_ATTACK1) ); +#else return ( GetNpcState() == NPC_STATE_COMBAT && GetOuter()->GetActiveWeapon() != NULL ); +#endif } //------------------------------------- @@ -600,7 +605,11 @@ int CAI_StandoffBehavior::SelectScheduleAttack( void ) !HasCondition( COND_CAN_MELEE_ATTACK1 ) && HasCondition( COND_TOO_FAR_TO_ATTACK ) ) { +#ifdef MAPBASE + if ( (GetOuter()->GetActiveWeapon() && ( GetOuter()->GetActiveWeapon()->CapabilitiesGet() & bits_CAP_WEAPON_RANGE_ATTACK1 )) || GetOuter()->CapabilitiesGet() & bits_CAP_INNATE_RANGE_ATTACK1 ) +#else if ( GetOuter()->GetActiveWeapon() && ( GetOuter()->GetActiveWeapon()->CapabilitiesGet() & bits_CAP_WEAPON_RANGE_ATTACK1 ) ) +#endif { if ( !HasCondition( COND_ENEMY_OCCLUDED ) || random->RandomInt(0,99) < 50 ) // Don't advance, just fire anyway From 1130a40d1ebeaad655626768b0d63c7fd292cb55 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sun, 21 Nov 2021 00:14:13 -0600 Subject: [PATCH 281/378] Added SetViewtarget function to VScript --- sp/src/game/server/baseflex.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sp/src/game/server/baseflex.cpp b/sp/src/game/server/baseflex.cpp index 921e3fe6..49f3c189 100644 --- a/sp/src/game/server/baseflex.cpp +++ b/sp/src/game/server/baseflex.cpp @@ -102,6 +102,10 @@ BEGIN_ENT_SCRIPTDESC( CBaseFlex, CBaseAnimating, "Animated characters who have v #endif DEFINE_SCRIPTFUNC_NAMED( ScriptGetOldestScene, "GetCurrentScene", "Returns the instance of the oldest active scene entity (if any)." ) DEFINE_SCRIPTFUNC_NAMED( ScriptGetSceneByIndex, "GetSceneByIndex", "Returns the instance of the scene entity at the specified index." ) + +#ifdef MAPBASE + DEFINE_SCRIPTFUNC( SetViewtarget, "Sets the entity's eye target." ) +#endif END_SCRIPTDESC(); From 808ea9bb8ca8f655a283aa044a2ec57df00f480b Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sun, 21 Nov 2021 11:00:27 -0600 Subject: [PATCH 282/378] Fixed shared activity collisions involving the new unused weapon activities --- sp/src/game/server/ai_activity.cpp | 12 ++++++------ sp/src/game/shared/activitylist.cpp | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/sp/src/game/server/ai_activity.cpp b/sp/src/game/server/ai_activity.cpp index 2627f081..1f7245ab 100644 --- a/sp/src/game/server/ai_activity.cpp +++ b/sp/src/game/server/ai_activity.cpp @@ -2313,13 +2313,13 @@ void CAI_BaseNPC::InitDefaultActivitySR(void) ADD_ACTIVITY_TO_SR( ACT_RUN_AR1 ); ADD_ACTIVITY_TO_SR( ACT_WALK_AIM_AR1 ); ADD_ACTIVITY_TO_SR( ACT_RUN_AIM_AR1 ); - ADD_ACTIVITY_TO_SR( ACT_RANGE_ATTACK_AR1 ); + //ADD_ACTIVITY_TO_SR( ACT_RANGE_ATTACK_AR1 ); ADD_ACTIVITY_TO_SR( ACT_RELOAD_AR1 ); ADD_ACTIVITY_TO_SR( ACT_RANGE_ATTACK_AR1_LOW ); ADD_ACTIVITY_TO_SR( ACT_RELOAD_AR1_LOW ); ADD_ACTIVITY_TO_SR( ACT_COVER_AR1_LOW ); ADD_ACTIVITY_TO_SR( ACT_RANGE_AIM_AR1_LOW ); - ADD_ACTIVITY_TO_SR( ACT_GESTURE_RANGE_ATTACK_AR1 ); + //ADD_ACTIVITY_TO_SR( ACT_GESTURE_RANGE_ATTACK_AR1 ); ADD_ACTIVITY_TO_SR( ACT_GESTURE_RELOAD_AR1 ); ADD_ACTIVITY_TO_SR( ACT_IDLE_AR1_RELAXED ); @@ -2339,13 +2339,13 @@ void CAI_BaseNPC::InitDefaultActivitySR(void) ADD_ACTIVITY_TO_SR( ACT_RUN_SMG2 ); ADD_ACTIVITY_TO_SR( ACT_WALK_AIM_SMG2 ); ADD_ACTIVITY_TO_SR( ACT_RUN_AIM_SMG2 ); - ADD_ACTIVITY_TO_SR( ACT_RANGE_ATTACK_SMG2 ); + //ADD_ACTIVITY_TO_SR( ACT_RANGE_ATTACK_SMG2 ); ADD_ACTIVITY_TO_SR( ACT_RELOAD_SMG2 ); ADD_ACTIVITY_TO_SR( ACT_RANGE_ATTACK_SMG2_LOW ); ADD_ACTIVITY_TO_SR( ACT_RELOAD_SMG2_LOW ); ADD_ACTIVITY_TO_SR( ACT_COVER_SMG2_LOW ); ADD_ACTIVITY_TO_SR( ACT_RANGE_AIM_SMG2_LOW ); - ADD_ACTIVITY_TO_SR( ACT_GESTURE_RANGE_ATTACK_SMG2 ); + //ADD_ACTIVITY_TO_SR( ACT_GESTURE_RANGE_ATTACK_SMG2 ); ADD_ACTIVITY_TO_SR( ACT_GESTURE_RELOAD_SMG2 ); ADD_ACTIVITY_TO_SR( ACT_IDLE_SMG2_RELAXED ); @@ -2365,13 +2365,13 @@ void CAI_BaseNPC::InitDefaultActivitySR(void) ADD_ACTIVITY_TO_SR( ACT_RUN_SNIPER_RIFLE ); ADD_ACTIVITY_TO_SR( ACT_WALK_AIM_SNIPER_RIFLE ); ADD_ACTIVITY_TO_SR( ACT_RUN_AIM_SNIPER_RIFLE ); - ADD_ACTIVITY_TO_SR( ACT_RANGE_ATTACK_SNIPER_RIFLE ); + //ADD_ACTIVITY_TO_SR( ACT_RANGE_ATTACK_SNIPER_RIFLE ); ADD_ACTIVITY_TO_SR( ACT_RELOAD_SNIPER_RIFLE ); ADD_ACTIVITY_TO_SR( ACT_RANGE_ATTACK_SNIPER_RIFLE_LOW ); ADD_ACTIVITY_TO_SR( ACT_RELOAD_SNIPER_RIFLE_LOW ); ADD_ACTIVITY_TO_SR( ACT_COVER_SNIPER_RIFLE_LOW ); ADD_ACTIVITY_TO_SR( ACT_RANGE_AIM_SNIPER_RIFLE_LOW ); - ADD_ACTIVITY_TO_SR( ACT_GESTURE_RANGE_ATTACK_SNIPER_RIFLE ); + //ADD_ACTIVITY_TO_SR( ACT_GESTURE_RANGE_ATTACK_SNIPER_RIFLE ); ADD_ACTIVITY_TO_SR( ACT_GESTURE_RELOAD_SNIPER_RIFLE ); ADD_ACTIVITY_TO_SR( ACT_IDLE_SNIPER_RIFLE_RELAXED ); diff --git a/sp/src/game/shared/activitylist.cpp b/sp/src/game/shared/activitylist.cpp index 0b17d272..b8aea0bf 100644 --- a/sp/src/game/shared/activitylist.cpp +++ b/sp/src/game/shared/activitylist.cpp @@ -2429,13 +2429,13 @@ void ActivityList_RegisterSharedActivities( void ) REGISTER_SHARED_ACTIVITY( ACT_RUN_AR1 ); REGISTER_SHARED_ACTIVITY( ACT_WALK_AIM_AR1 ); REGISTER_SHARED_ACTIVITY( ACT_RUN_AIM_AR1 ); - REGISTER_SHARED_ACTIVITY( ACT_RANGE_ATTACK_AR1 ); + //REGISTER_SHARED_ACTIVITY( ACT_RANGE_ATTACK_AR1 ); REGISTER_SHARED_ACTIVITY( ACT_RELOAD_AR1 ); REGISTER_SHARED_ACTIVITY( ACT_RANGE_ATTACK_AR1_LOW ); REGISTER_SHARED_ACTIVITY( ACT_RELOAD_AR1_LOW ); REGISTER_SHARED_ACTIVITY( ACT_COVER_AR1_LOW ); REGISTER_SHARED_ACTIVITY( ACT_RANGE_AIM_AR1_LOW ); - REGISTER_SHARED_ACTIVITY( ACT_GESTURE_RANGE_ATTACK_AR1 ); + //REGISTER_SHARED_ACTIVITY( ACT_GESTURE_RANGE_ATTACK_AR1 ); REGISTER_SHARED_ACTIVITY( ACT_GESTURE_RELOAD_AR1 ); REGISTER_SHARED_ACTIVITY( ACT_IDLE_AR1_RELAXED ); @@ -2455,13 +2455,13 @@ void ActivityList_RegisterSharedActivities( void ) REGISTER_SHARED_ACTIVITY( ACT_RUN_SMG2 ); REGISTER_SHARED_ACTIVITY( ACT_WALK_AIM_SMG2 ); REGISTER_SHARED_ACTIVITY( ACT_RUN_AIM_SMG2 ); - REGISTER_SHARED_ACTIVITY( ACT_RANGE_ATTACK_SMG2 ); + //REGISTER_SHARED_ACTIVITY( ACT_RANGE_ATTACK_SMG2 ); REGISTER_SHARED_ACTIVITY( ACT_RELOAD_SMG2 ); REGISTER_SHARED_ACTIVITY( ACT_RANGE_ATTACK_SMG2_LOW ); REGISTER_SHARED_ACTIVITY( ACT_RELOAD_SMG2_LOW ); REGISTER_SHARED_ACTIVITY( ACT_COVER_SMG2_LOW ); REGISTER_SHARED_ACTIVITY( ACT_RANGE_AIM_SMG2_LOW ); - REGISTER_SHARED_ACTIVITY( ACT_GESTURE_RANGE_ATTACK_SMG2 ); + //REGISTER_SHARED_ACTIVITY( ACT_GESTURE_RANGE_ATTACK_SMG2 ); REGISTER_SHARED_ACTIVITY( ACT_GESTURE_RELOAD_SMG2 ); REGISTER_SHARED_ACTIVITY( ACT_IDLE_SMG2_RELAXED ); @@ -2481,13 +2481,13 @@ void ActivityList_RegisterSharedActivities( void ) REGISTER_SHARED_ACTIVITY( ACT_RUN_SNIPER_RIFLE ); REGISTER_SHARED_ACTIVITY( ACT_WALK_AIM_SNIPER_RIFLE ); REGISTER_SHARED_ACTIVITY( ACT_RUN_AIM_SNIPER_RIFLE ); - REGISTER_SHARED_ACTIVITY( ACT_RANGE_ATTACK_SNIPER_RIFLE ); + //REGISTER_SHARED_ACTIVITY( ACT_RANGE_ATTACK_SNIPER_RIFLE ); REGISTER_SHARED_ACTIVITY( ACT_RELOAD_SNIPER_RIFLE ); REGISTER_SHARED_ACTIVITY( ACT_RANGE_ATTACK_SNIPER_RIFLE_LOW ); REGISTER_SHARED_ACTIVITY( ACT_RELOAD_SNIPER_RIFLE_LOW ); REGISTER_SHARED_ACTIVITY( ACT_COVER_SNIPER_RIFLE_LOW ); REGISTER_SHARED_ACTIVITY( ACT_RANGE_AIM_SNIPER_RIFLE_LOW ); - REGISTER_SHARED_ACTIVITY( ACT_GESTURE_RANGE_ATTACK_SNIPER_RIFLE ); + //REGISTER_SHARED_ACTIVITY( ACT_GESTURE_RANGE_ATTACK_SNIPER_RIFLE ); REGISTER_SHARED_ACTIVITY( ACT_GESTURE_RELOAD_SNIPER_RIFLE ); REGISTER_SHARED_ACTIVITY( ACT_IDLE_SNIPER_RIFLE_RELAXED ); From 17e8558ca4675a5f5ccd29eedef9c463da0a6746 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sun, 21 Nov 2021 11:01:38 -0600 Subject: [PATCH 283/378] Added activity gesture links for some of the recently added activities --- sp/src/game/server/ai_activity.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/sp/src/game/server/ai_activity.cpp b/sp/src/game/server/ai_activity.cpp index 1f7245ab..d2316857 100644 --- a/sp/src/game/server/ai_activity.cpp +++ b/sp/src/game/server/ai_activity.cpp @@ -2600,11 +2600,15 @@ CAI_BaseNPC::actlink_t CAI_BaseNPC::gm_ActivityGestureLinks[] = { ACT_RANGE_ATTACK_CROSSBOW_LOW, ACT_GESTURE_RANGE_ATTACK_CROSSBOW }, { ACT_RANGE_ATTACK_RPG, ACT_GESTURE_RANGE_ATTACK_RPG }, { ACT_RANGE_ATTACK_RPG_LOW, ACT_GESTURE_RANGE_ATTACK_RPG }, + { ACT_RANGE_ATTACK_ANNABELLE, ACT_GESTURE_RANGE_ATTACK_ANNABELLE }, + { ACT_RANGE_ATTACK_ANNABELLE_LOW, ACT_GESTURE_RANGE_ATTACK_ANNABELLE }, { ACT_RELOAD_REVOLVER, ACT_GESTURE_RELOAD_REVOLVER }, { ACT_RELOAD_REVOLVER_LOW, ACT_GESTURE_RELOAD_REVOLVER }, { ACT_RELOAD_CROSSBOW, ACT_GESTURE_RELOAD_CROSSBOW }, { ACT_RELOAD_CROSSBOW_LOW, ACT_GESTURE_RELOAD_CROSSBOW }, + { ACT_RELOAD_ANNABELLE, ACT_GESTURE_RELOAD_ANNABELLE }, + { ACT_RELOAD_ANNABELLE_LOW, ACT_GESTURE_RELOAD_ANNABELLE }, #endif #if EXPANDED_HL2_UNUSED_WEAPON_ACTIVITIES @@ -2628,6 +2632,21 @@ CAI_BaseNPC::actlink_t CAI_BaseNPC::gm_ActivityGestureLinks[] = { ACT_RELOAD_SNIPER_RIFLE, ACT_GESTURE_RELOAD_SNIPER_RIFLE }, { ACT_RELOAD_SNIPER_RIFLE_LOW, ACT_GESTURE_RELOAD_SNIPER_RIFLE }, #endif + +#if EXPANDED_HL2_COVER_ACTIVITIES + { ACT_RANGE_ATTACK1_MED, ACT_GESTURE_RANGE_ATTACK1 }, + { ACT_RANGE_ATTACK2_MED, ACT_GESTURE_RANGE_ATTACK2 }, + + { ACT_RANGE_ATTACK_AR2_MED, ACT_GESTURE_RANGE_ATTACK_AR2 }, + { ACT_RANGE_ATTACK_SMG1_MED, ACT_GESTURE_RANGE_ATTACK_SMG1 }, + { ACT_RANGE_ATTACK_SHOTGUN_MED, ACT_GESTURE_RANGE_ATTACK_SHOTGUN }, + { ACT_RANGE_ATTACK_PISTOL_MED, ACT_GESTURE_RANGE_ATTACK_PISTOL }, +#if EXPANDED_HL2_WEAPON_ACTIVITIES + { ACT_RANGE_ATTACK_RPG_MED, ACT_GESTURE_RANGE_ATTACK_RPG }, + { ACT_RANGE_ATTACK_REVOLVER_MED, ACT_GESTURE_RANGE_ATTACK_REVOLVER }, + { ACT_RANGE_ATTACK_CROSSBOW_MED, ACT_GESTURE_RANGE_ATTACK_CROSSBOW }, +#endif +#endif }; Activity CAI_BaseNPC::GetGestureVersionOfActivity( Activity inActivity ) From 9b84980a77d08f56488a8e3b7eb03d6c100de467 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Mon, 22 Nov 2021 23:02:37 -0600 Subject: [PATCH 284/378] Improved player backup activities --- sp/src/game/server/player.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sp/src/game/server/player.cpp b/sp/src/game/server/player.cpp index 659eb748..d713a8c3 100644 --- a/sp/src/game/server/player.cpp +++ b/sp/src/game/server/player.cpp @@ -7824,7 +7824,7 @@ Activity CBasePlayer::Weapon_TranslateActivity( Activity baseAct, bool *pRequire // Our weapon is holstered. Use the base activity. return baseAct; } - if ( GetModelPtr() && !GetModelPtr()->HaveSequenceForActivity(weaponTranslation) ) + if ( GetModelPtr() && (!GetModelPtr()->HaveSequenceForActivity(weaponTranslation) || baseAct == weaponTranslation) ) { // This is used so players can fall back to backup activities in the same way NPCs in Mapbase can Activity backupActivity = Weapon_BackupActivity(baseAct, pRequired); From 6b13b8323101d6888b1352d8bf41d76de8c51830 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Mon, 22 Nov 2021 23:03:26 -0600 Subject: [PATCH 285/378] Added ability to translate actbusy forced move activity translation --- sp/src/game/server/hl2/ai_behavior_actbusy.cpp | 18 ++++++++++++++++++ sp/src/game/server/hl2/ai_behavior_actbusy.h | 3 +++ 2 files changed, 21 insertions(+) diff --git a/sp/src/game/server/hl2/ai_behavior_actbusy.cpp b/sp/src/game/server/hl2/ai_behavior_actbusy.cpp index c5ad733d..069960f6 100644 --- a/sp/src/game/server/hl2/ai_behavior_actbusy.cpp +++ b/sp/src/game/server/hl2/ai_behavior_actbusy.cpp @@ -1802,6 +1802,20 @@ bool CAI_ActBusyBehavior::PlayAnimForActBusy( busyanimparts_t AnimPart ) return false; } +#ifdef MAPBASE +//----------------------------------------------------------------------------- +// Purpose: Get the busy's move activity +//----------------------------------------------------------------------------- +Activity CAI_ActBusyBehavior::GetMoveActivityForActBusy() +{ + busyanim_t *pBusyAnim = g_ActBusyAnimDataSystem.GetBusyAnim( m_iCurrentBusyAnim ); + if ( !pBusyAnim ) + return m_ForcedActivity; + + return pBusyAnim->bTranslateActivity ? GetOuter()->TranslateActivity( m_ForcedActivity ) : m_ForcedActivity; +} +#endif + //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- @@ -2030,7 +2044,11 @@ void CAI_ActBusyBehavior::StartTask( const Task_t *pTask ) // If we have a forced activity, use that. Otherwise, walk. if ( m_ForcedActivity != ACT_INVALID && m_ForcedActivity != ACT_RESET ) { +#ifdef MAPBASE + GetNavigator()->SetMovementActivity( GetMoveActivityForActBusy() ); +#else GetNavigator()->SetMovementActivity( m_ForcedActivity ); +#endif // Cover is void once I move Forget( bits_MEMORY_INCOVER ); diff --git a/sp/src/game/server/hl2/ai_behavior_actbusy.h b/sp/src/game/server/hl2/ai_behavior_actbusy.h index 264fdb3d..63ebecec 100644 --- a/sp/src/game/server/hl2/ai_behavior_actbusy.h +++ b/sp/src/game/server/hl2/ai_behavior_actbusy.h @@ -167,6 +167,9 @@ private: void NotifyBusyEnding( void ); bool HasAnimForActBusy( int iActBusy, busyanimparts_t AnimPart ); bool PlayAnimForActBusy( busyanimparts_t AnimPart ); +#ifdef MAPBASE + Activity GetMoveActivityForActBusy(); +#endif void PlaySoundForActBusy( busyanimparts_t AnimPart ); private: From 4bc56b214bfc9d160272f964b106727b04de1bf5 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Mon, 22 Nov 2021 23:03:55 -0600 Subject: [PATCH 286/378] Fixed an issue with env_instructor_hint crashing in some maps --- sp/src/game/server/env_instructor_hint.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/sp/src/game/server/env_instructor_hint.cpp b/sp/src/game/server/env_instructor_hint.cpp index 20b2379c..3ee20fb2 100644 --- a/sp/src/game/server/env_instructor_hint.cpp +++ b/sp/src/game/server/env_instructor_hint.cpp @@ -8,6 +8,9 @@ #include "cbase.h" #include "baseentity.h" #include "world.h" +#ifdef MAPBASE +#include "eventqueue.h" +#endif #ifdef INFESTED_DLL #include "asw_marine.h" @@ -135,6 +138,8 @@ CEnvInstructorHint::CEnvInstructorHint( void ) //----------------------------------------------------------------------------- void CEnvInstructorHint::OnRestore( void ) { + BaseClass::OnRestore(); + int iTimeLeft = 0; if ( m_flActiveUntil < 0.0f ) { @@ -151,8 +156,7 @@ void CEnvInstructorHint::OnRestore( void ) int iOriginalTimeout = m_iTimeout; m_iTimeout = iTimeLeft; - inputdata_t inputdata; - InputShowHint( inputdata ); + g_EventQueue.AddEvent( this, "ShowHint", 0.01f, NULL, this ); m_iTimeout = iOriginalTimeout; } #endif From cea38f03ec1834ac9f3ab60340746b308df872ec Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sat, 27 Nov 2021 15:47:13 -0600 Subject: [PATCH 287/378] Added support for ragdoll prop gibs + related ragdoll LRU forced fade from Alien Swarm SDK --- sp/src/game/client/c_baseanimating.cpp | 10 ++ sp/src/game/client/c_baseanimating.h | 4 + sp/src/game/client/physpropclientside.cpp | 150 ++++++++++++++++++++++ sp/src/game/shared/ragdoll_shared.cpp | 81 +++++++++++- sp/src/game/shared/ragdoll_shared.h | 25 ++++ 5 files changed, 263 insertions(+), 7 deletions(-) diff --git a/sp/src/game/client/c_baseanimating.cpp b/sp/src/game/client/c_baseanimating.cpp index 0dd620d7..1c867472 100644 --- a/sp/src/game/client/c_baseanimating.cpp +++ b/sp/src/game/client/c_baseanimating.cpp @@ -259,6 +259,9 @@ LINK_ENTITY_TO_CLASS( client_ragdoll, C_ClientRagdoll ); BEGIN_DATADESC( C_ClientRagdoll ) DEFINE_FIELD( m_bFadeOut, FIELD_BOOLEAN ), DEFINE_FIELD( m_bImportant, FIELD_BOOLEAN ), +#ifdef MAPBASE + DEFINE_FIELD( m_flForcedRetireTime, FIELD_FLOAT ), +#endif DEFINE_FIELD( m_iCurrentFriction, FIELD_INTEGER ), DEFINE_FIELD( m_iMinFriction, FIELD_INTEGER ), DEFINE_FIELD( m_iMaxFriction, FIELD_INTEGER ), @@ -377,6 +380,9 @@ C_ClientRagdoll::C_ClientRagdoll( bool bRestoring ) m_bFadeOut = false; m_bFadingOut = false; m_bImportant = false; +#ifdef MAPBASE + m_flForcedRetireTime = 0.0f; +#endif m_bNoModelParticles = false; SetClassname("client_ragdoll"); @@ -457,7 +463,11 @@ void C_ClientRagdoll::OnRestore( void ) if ( m_bFadeOut == true ) { +#ifdef MAPBASE + s_RagdollLRU.MoveToTopOfLRU( this, m_bImportant, m_flForcedRetireTime ); +#else s_RagdollLRU.MoveToTopOfLRU( this, m_bImportant ); +#endif } NoteRagdollCreationTick( this ); diff --git a/sp/src/game/client/c_baseanimating.h b/sp/src/game/client/c_baseanimating.h index 6082be1f..0f2f57df 100644 --- a/sp/src/game/client/c_baseanimating.h +++ b/sp/src/game/client/c_baseanimating.h @@ -737,6 +737,10 @@ public: bool m_bFadeOut; bool m_bImportant; +#ifdef MAPBASE + // Required to save/restore Alien Swarm SDK ragdoll LRU forced fade + float m_flForcedRetireTime; +#endif float m_flEffectTime; private: diff --git a/sp/src/game/client/physpropclientside.cpp b/sp/src/game/client/physpropclientside.cpp index 3dd2d7b5..3db90618 100644 --- a/sp/src/game/client/physpropclientside.cpp +++ b/sp/src/game/client/physpropclientside.cpp @@ -704,9 +704,157 @@ void C_PhysPropClientside::ParseAllEntities(const char *pMapData) } } +#ifdef MAPBASE +CBaseAnimating *BreakModelCreate_Ragdoll( CBaseEntity *pOwnerEnt, breakmodel_t *pModel, const Vector &position, const QAngle &angles, const Vector &velocity, const AngularImpulse &angVelocity ) +{ + C_BaseAnimating *pOwner = dynamic_cast( pOwnerEnt ); + if ( !pOwner ) + return NULL; + + C_ClientRagdoll *pRagdoll = new C_ClientRagdoll( false ); + if ( pRagdoll == NULL ) + return NULL; + + const char *pModelName = pModel->modelName; + if ( pRagdoll->InitializeAsClientEntity( pModelName, RENDER_GROUP_OPAQUE_ENTITY ) == false ) + { + pRagdoll->Release(); + return NULL; + } + + pRagdoll->SetAbsOrigin( position ); + pRagdoll->SetAbsAngles( angles ); + + matrix3x4_t boneDelta0[MAXSTUDIOBONES]; + matrix3x4_t boneDelta1[MAXSTUDIOBONES]; + matrix3x4_t currentBones[MAXSTUDIOBONES]; + const float boneDt = 0.1f; + + pRagdoll->SetParent( pOwner ); + pRagdoll->ForceSetupBonesAtTime( boneDelta0, gpGlobals->curtime - boneDt ); + pRagdoll->ForceSetupBonesAtTime( boneDelta1, gpGlobals->curtime ); + pRagdoll->ForceSetupBonesAtTime( currentBones, gpGlobals->curtime ); + pRagdoll->SetParent( NULL ); + + // We need to take these from the entity + //pRagdoll->SetAbsOrigin( position ); + //pRagdoll->SetAbsAngles( angles ); + + pRagdoll->IgniteRagdoll( pOwner ); + pRagdoll->TransferDissolveFrom( pOwner ); + pRagdoll->InitModelEffects(); + + if ( pOwner->IsEffectActive( EF_NOSHADOW ) ) + { + pRagdoll->AddEffects( EF_NOSHADOW ); + } + + pRagdoll->m_nRenderFX = kRenderFxRagdoll; + pRagdoll->SetRenderMode( pOwner->GetRenderMode() ); + pRagdoll->SetRenderColor( pOwner->GetRenderColor().r, pOwner->GetRenderColor().g, pOwner->GetRenderColor().b, pOwner->GetRenderColor().a ); + //pRagdoll->SetGlobalFadeScale( pOwner->GetGlobalFadeScale() ); + + pRagdoll->SetSkin( pOwner->GetSkin() ); + //pRagdoll->m_vecForce = pOwner->m_vecForce; + //pRagdoll->m_nForceBone = 0; //pOwner->m_nForceBone; + pRagdoll->SetNextClientThink( CLIENT_THINK_ALWAYS ); + + pRagdoll->SetModelName( AllocPooledString( pModelName ) ); + pRagdoll->ResetSequence( 0 ); + pRagdoll->SetModelScale( pOwner->GetModelScale() ); + pRagdoll->SetCollisionGroup( COLLISION_GROUP_DEBRIS ); + //pRagdoll->m_builtRagdoll = true; + + CStudioHdr *hdr = pRagdoll->GetModelPtr(); + if ( !hdr ) + { + pRagdoll->Release(); + Warning( "Couldn't create ragdoll gib for %s (no model pointer)\n", pModel->modelName ); + return NULL; + } + + pRagdoll->m_pRagdoll = CreateRagdoll( + pRagdoll, + hdr, + vec3_origin, + 0, + boneDelta0, + boneDelta1, + currentBones, + boneDt ); + + if ( !pRagdoll->m_pRagdoll ) + { + pRagdoll->Release(); + Warning( "Couldn't create ragdoll gib for %s\n", pModel->modelName ); + return NULL; + } + + IPhysicsObject *pPhysicsObject = pRagdoll->VPhysicsGetObject(); + if ( pPhysicsObject ) + { + // randomize velocity by 5% + float rndf = RandomFloat( -0.025, 0.025 ); + Vector rndVel = velocity + rndf*velocity; + + pPhysicsObject->AddVelocity( &rndVel, &angVelocity ); + } + pRagdoll->ApplyLocalAngularVelocityImpulse( angVelocity ); + + if ( pRagdoll->m_pRagdoll ) + { + pRagdoll->m_bImportant = false; + pRagdoll->m_flForcedRetireTime = pModel->fadeTime > 0.0f ? gpGlobals->curtime + pModel->fadeTime : 0.0f; + s_RagdollLRU.MoveToTopOfLRU( pRagdoll, pRagdoll->m_bImportant, pRagdoll->m_flForcedRetireTime ); + pRagdoll->m_bFadeOut = true; + } + + // Cause the entity to recompute its shadow type and make a + // version which only updates when physics state changes + // NOTE: We have to do this after m_pRagdoll is assigned above + // because that's what ShadowCastType uses to figure out which type of shadow to use. + pRagdoll->DestroyShadow(); + pRagdoll->CreateShadow(); + + pRagdoll->SetAbsOrigin( position ); + pRagdoll->SetAbsAngles( angles ); + + pRagdoll->SetPlaybackRate( 0 ); + pRagdoll->SetCycle( 0 ); + + // put into ACT_DIERAGDOLL if it exists, otherwise use sequence 0 + int nSequence = pRagdoll->SelectWeightedSequence( ACT_DIERAGDOLL ); + if ( nSequence < 0 ) + { + pRagdoll->ResetSequence( 0 ); + } + else + { + pRagdoll->ResetSequence( nSequence ); + } + + pRagdoll->UpdatePartitionListEntry(); + pRagdoll->MarkRenderHandleDirty(); + + NoteRagdollCreationTick( pRagdoll ); + + //pRagdoll->InitAsClientRagdoll( boneDelta0, boneDelta1, currentBones, boneDt ); + + return pRagdoll; +} +#endif + CBaseEntity *BreakModelCreateSingle( CBaseEntity *pOwner, breakmodel_t *pModel, const Vector &position, const QAngle &angles, const Vector &velocity, const AngularImpulse &angVelocity, int nSkin, const breakablepropparams_t ¶ms ) { +#ifdef MAPBASE + if ( pModel->isRagdoll ) + { + CBaseEntity *pEntity = BreakModelCreate_Ragdoll( pOwner, pModel, position, angles, velocity, angVelocity ); + return pEntity; + } +#endif + C_PhysPropClientside *pEntity = C_PhysPropClientside::CreateNew(); if ( !pEntity ) @@ -778,10 +926,12 @@ CBaseEntity *BreakModelCreateSingle( CBaseEntity *pOwner, breakmodel_t *pModel, pEntity->SetFadeMinMax( pModel->fadeMinDist, pModel->fadeMaxDist ); } +#ifndef MAPBASE if ( pModel->isRagdoll ) { DevMsg( "BreakModelCreateSingle: clientside doesn't support ragdoll breakmodels.\n" ); } +#endif IPhysicsObject *pPhysicsObject = pEntity->VPhysicsGetObject(); diff --git a/sp/src/game/shared/ragdoll_shared.cpp b/sp/src/game/shared/ragdoll_shared.cpp index ded93773..86938039 100644 --- a/sp/src/game/shared/ragdoll_shared.cpp +++ b/sp/src/game/shared/ragdoll_shared.cpp @@ -830,6 +830,33 @@ void CRagdollLRURetirement::Update( float frametime ) // EPISODIC VERSION m_iRagdollCount = 0; m_iSimulatedRagdollCount = 0; +#ifdef MAPBASE // From Alien Swarm SDK + // remove ragdolls with a forced retire time + for ( i = m_LRU.Head(); i < m_LRU.InvalidIndex(); i = next ) + { + next = m_LRU.Next(i); + + CBaseAnimating *pRagdoll = m_LRU[i].Get(); + + //Just ignore it until we're done burning/dissolving. + if ( pRagdoll && pRagdoll->GetEffectEntity() ) + continue; + + // ignore if it's not time to force retire this ragdoll + if ( m_LRU[i].GetForcedRetireTime() == 0.0f || gpGlobals->curtime < m_LRU[i].GetForcedRetireTime() ) + continue; + + //Msg(" Removing ragdoll %s due to forced retire time of %f (now = %f)\n", pRagdoll->GetModelName(), m_LRU[i].GetForcedRetireTime(), gpGlobals->curtime ); + +#ifdef CLIENT_DLL + pRagdoll->SUB_Remove(); +#else + pRagdoll->SUB_StartFadeOut( 0 ); +#endif + m_LRU.Remove(i); + } +#endif + // First, find ragdolls that are good candidates for deletion because they are not // visible at all, or are in a culled visibility box for ( i = m_LRU.Head(); i < m_LRU.InvalidIndex(); i = next ) @@ -847,12 +874,12 @@ void CRagdollLRURetirement::Update( float frametime ) // EPISODIC VERSION if ( m_LRU.Count() > iMaxRagdollCount ) { //Found one, we're done. - if ( ShouldRemoveThisRagdoll( m_LRU[i] ) == true ) + if ( ShouldRemoveThisRagdoll( pRagdoll ) == true ) { #ifdef CLIENT_DLL - m_LRU[ i ]->SUB_Remove(); + pRagdoll->SUB_Remove(); #else - m_LRU[ i ]->SUB_StartFadeOut( 0 ); + pRagdoll->SUB_StartFadeOut( 0 ); #endif m_LRU.Remove(i); @@ -933,10 +960,11 @@ void CRagdollLRURetirement::Update( float frametime ) // EPISODIC VERSION } } + CBaseAnimating *pRemoveRagdoll = m_LRU[ furthestOne ].Get(); #ifdef CLIENT_DLL - m_LRU[ furthestOne ]->SUB_Remove(); + pRemoveRagdoll->SUB_Remove(); #else - m_LRU[ furthestOne ]->SUB_StartFadeOut( 0 ); + pRemoveRagdoll->SUB_StartFadeOut( 0 ); #endif } @@ -957,9 +985,9 @@ void CRagdollLRURetirement::Update( float frametime ) // EPISODIC VERSION continue; #ifdef CLIENT_DLL - m_LRU[ i ]->SUB_Remove(); + pRagdoll->SUB_Remove(); #else - m_LRU[ i ]->SUB_StartFadeOut( 0 ); + pRagdoll->SUB_StartFadeOut( 0 ); #endif m_LRU.Remove(i); } @@ -989,6 +1017,33 @@ void CRagdollLRURetirement::Update( float frametime ) // Non-episodic version m_iRagdollCount = 0; m_iSimulatedRagdollCount = 0; +#ifdef MAPBASE // From Alien Swarm SDK + // remove ragdolls with a forced retire time + for ( i = m_LRU.Head(); i < m_LRU.InvalidIndex(); i = next ) + { + next = m_LRU.Next(i); + + CBaseAnimating *pRagdoll = m_LRU[i].Get(); + + //Just ignore it until we're done burning/dissolving. + if ( pRagdoll && pRagdoll->GetEffectEntity() ) + continue; + + // ignore if it's not time to force retire this ragdoll + if ( m_LRU[i].GetForcedRetireTime() == 0.0f || gpGlobals->curtime < m_LRU[i].GetForcedRetireTime() ) + continue; + + //Msg(" Removing ragdoll %s due to forced retire time of %f (now = %f)\n", pRagdoll->GetModelName(), m_LRU[i].GetForcedRetireTime(), gpGlobals->curtime ); + +#ifdef CLIENT_DLL + pRagdoll->SUB_Remove(); +#else + pRagdoll->SUB_StartFadeOut( 0 ); +#endif + m_LRU.Remove(i); + } +#endif + for ( i = m_LRU.Head(); i < m_LRU.InvalidIndex(); i = next ) { next = m_LRU.Next(i); @@ -1074,11 +1129,19 @@ ConVar g_ragdoll_important_maxcount( "g_ragdoll_important_maxcount", "2", FCVAR_ //----------------------------------------------------------------------------- // Move it to the top of the LRU //----------------------------------------------------------------------------- +#ifdef MAPBASE // From Alien Swarm SDK +void CRagdollLRURetirement::MoveToTopOfLRU( CBaseAnimating *pRagdoll, bool bImportant, float flForcedRetireTime ) +#else void CRagdollLRURetirement::MoveToTopOfLRU( CBaseAnimating *pRagdoll, bool bImportant ) +#endif { if ( bImportant ) { +#ifdef MAPBASE // From Alien Swarm SDK + m_LRUImportantRagdolls.AddToTail( CRagdollEntry( pRagdoll, flForcedRetireTime ) ); +#else m_LRUImportantRagdolls.AddToTail( pRagdoll ); +#endif if ( m_LRUImportantRagdolls.Count() > g_ragdoll_important_maxcount.GetInt() ) { @@ -1108,7 +1171,11 @@ void CRagdollLRURetirement::MoveToTopOfLRU( CBaseAnimating *pRagdoll, bool bImpo } } +#ifdef MAPBASE // From Alien Swarm SDK + m_LRU.AddToTail( CRagdollEntry( pRagdoll, flForcedRetireTime ) ); +#else m_LRU.AddToTail( pRagdoll ); +#endif } diff --git a/sp/src/game/shared/ragdoll_shared.h b/sp/src/game/shared/ragdoll_shared.h index 758f4719..5f4f7058 100644 --- a/sp/src/game/shared/ragdoll_shared.h +++ b/sp/src/game/shared/ragdoll_shared.h @@ -83,6 +83,22 @@ struct ragdollparams_t bool fixedConstraints; }; +#ifdef MAPBASE // From Alien Swarm SDK +class CRagdollEntry +{ +public: + CRagdollEntry( CBaseAnimating *pRagdoll, float flForcedRetireTime ) : m_hRagdoll( pRagdoll ), m_flForcedRetireTime( flForcedRetireTime ) + { + } + CBaseAnimating* Get() { return m_hRagdoll.Get(); } + float GetForcedRetireTime() { return m_flForcedRetireTime; } + +private: + CHandle m_hRagdoll; + float m_flForcedRetireTime; +}; +#endif + //----------------------------------------------------------------------------- // This hooks the main game systems callbacks to allow the AI system to manage memory //----------------------------------------------------------------------------- @@ -98,7 +114,11 @@ public: virtual void FrameUpdatePostEntityThink( void ); // Move it to the top of the LRU +#ifdef MAPBASE // From Alien Swarm SDK + void MoveToTopOfLRU( CBaseAnimating *pRagdoll, bool bImportant = false, float flForcedRetireTime = 0.0f ); +#else void MoveToTopOfLRU( CBaseAnimating *pRagdoll, bool bImportant = false ); +#endif void SetMaxRagdollCount( int iMaxCount ){ m_iMaxRagdolls = iMaxCount; } virtual void LevelInitPreEntity( void ); @@ -106,8 +126,13 @@ public: private: typedef CHandle CRagdollHandle; +#ifdef MAPBASE + CUtlLinkedList< CRagdollEntry > m_LRU; + CUtlLinkedList< CRagdollEntry > m_LRUImportantRagdolls; +#else CUtlLinkedList< CRagdollHandle > m_LRU; CUtlLinkedList< CRagdollHandle > m_LRUImportantRagdolls; +#endif int m_iMaxRagdolls; int m_iSimulatedRagdollCount; From 483abff3b3e818353a738fc4cec9a756a6e45f31 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sat, 27 Nov 2021 15:48:51 -0600 Subject: [PATCH 288/378] Added custom gameinfo.txt values for HL2 default player model + enabling external drawing by default --- sp/src/game/server/hl2/hl2_player.cpp | 10 ++++++++++ sp/src/game/shared/mapbase/mapbase_shared.cpp | 11 +++++++++++ 2 files changed, 21 insertions(+) diff --git a/sp/src/game/server/hl2/hl2_player.cpp b/sp/src/game/server/hl2/hl2_player.cpp index c148ba3e..d44849e7 100644 --- a/sp/src/game/server/hl2/hl2_player.cpp +++ b/sp/src/game/server/hl2/hl2_player.cpp @@ -1476,6 +1476,9 @@ CStudioHdr *CHL2_Player::OnNewModel() return hdr; } + +extern char g_szDefaultPlayerModel[MAX_PATH]; +extern bool g_bDefaultPlayerDrawExternally; #endif //----------------------------------------------------------------------------- @@ -1486,8 +1489,13 @@ void CHL2_Player::Spawn(void) #ifndef HL2MP #ifndef PORTAL +#ifdef MAPBASE + if ( GetModelName() == NULL_STRING ) + SetModel( g_szDefaultPlayerModel ); +#else SetModel( "models/player.mdl" ); #endif +#endif #endif BaseClass::Spawn(); @@ -1501,6 +1509,8 @@ void CHL2_Player::Spawn(void) RemoveEffects( EF_NODRAW ); } + + SetDrawPlayerModelExternally( g_bDefaultPlayerDrawExternally ); #endif // diff --git a/sp/src/game/shared/mapbase/mapbase_shared.cpp b/sp/src/game/shared/mapbase/mapbase_shared.cpp index 877cf9ff..8550b6dc 100644 --- a/sp/src/game/shared/mapbase/mapbase_shared.cpp +++ b/sp/src/game/shared/mapbase/mapbase_shared.cpp @@ -82,6 +82,12 @@ static bool g_bMapbaseCore; // The game's name found in gameinfo.txt. Mostly used for Discord RPC. char g_iszGameName[128]; +#ifdef GAME_DLL +// Default player configuration +char g_szDefaultPlayerModel[MAX_PATH]; +bool g_bDefaultPlayerDrawExternally; +#endif + enum { MANIFEST_SOUNDSCRIPTS, @@ -216,6 +222,11 @@ public: Q_strncpy(g_iszGameName, pszGameName, sizeof(g_iszGameName)); } + +#ifdef GAME_DLL + Q_strncpy( g_szDefaultPlayerModel, gameinfo->GetString( "player_default_model", "models/player.mdl" ), sizeof( g_szDefaultPlayerModel ) ); + g_bDefaultPlayerDrawExternally = gameinfo->GetBool( "player_default_draw_externally", false ); +#endif } gameinfo->deleteThis(); From c25053d1d2cd386156817a4df37c3e7c0fc17f2f Mon Sep 17 00:00:00 2001 From: Blixibon Date: Fri, 10 Dec 2021 15:07:16 -0600 Subject: [PATCH 289/378] Fixed a typo --- sp/src/game/server/hl2/weapon_ar2.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sp/src/game/server/hl2/weapon_ar2.cpp b/sp/src/game/server/hl2/weapon_ar2.cpp index 1a3a1633..6e7d4cac 100644 --- a/sp/src/game/server/hl2/weapon_ar2.cpp +++ b/sp/src/game/server/hl2/weapon_ar2.cpp @@ -197,7 +197,7 @@ acttable_t *GetAR2Acttable() return CWeaponAR2::m_acttable; } -int GetSAR2ActtableCount() +int GetAR2ActtableCount() { return ARRAYSIZE(CWeaponAR2::m_acttable); } From 0de9cf41eb2f77f98e0d7e74568bacc40cacb30a Mon Sep 17 00:00:00 2001 From: samisalreadytaken <46823719+samisalreadytaken@users.noreply.github.com> Date: Sat, 11 Dec 2021 22:20:00 +0300 Subject: [PATCH 290/378] Update Squirrel --- .../doc/source/stdlib/stdstringlib.rst | 8 +++- .../vscript/squirrel/sqstdlib/sqstdblob.cpp | 4 +- .../vscript/squirrel/sqstdlib/sqstdstring.cpp | 42 ++++++++++++------- .../vscript/squirrel/squirrel/sqbaselib.cpp | 14 +++++-- sp/src/vscript/squirrel/squirrel/sqclass.cpp | 3 ++ sp/src/vscript/squirrel/squirrel/sqclass.h | 1 + sp/src/vscript/squirrel/squirrel/sqtable.h | 2 +- 7 files changed, 51 insertions(+), 23 deletions(-) diff --git a/sp/src/vscript/squirrel/doc/source/stdlib/stdstringlib.rst b/sp/src/vscript/squirrel/doc/source/stdlib/stdstringlib.rst index 19c18d7a..dd929346 100644 --- a/sp/src/vscript/squirrel/doc/source/stdlib/stdstringlib.rst +++ b/sp/src/vscript/squirrel/doc/source/stdlib/stdstringlib.rst @@ -50,16 +50,20 @@ Global Symbols Strips white-space-only characters that might appear at the end of the given string and returns the new stripped string. -.. js:function:: split(str, separators) +.. js:function:: split(str, separators [, skipempty]) returns an array of strings split at each point where a separator character occurs in `str`. The separator is not returned as part of any array element. The parameter `separators` is a string that specifies the characters as to be used for the splitting. + The parameter `skipempty` is a boolean (default false). If `skipempty` is true, empty strings are not added to array. :: eg. - local a = split("1.2-3;4/5",".-/;"); + local a = split("1.2-3;;4/5",".-/;"); + // the result will be [1,2,3,,4,5] + or + local b = split("1.2-3;;4/5",".-/;",true); // the result will be [1,2,3,4,5] diff --git a/sp/src/vscript/squirrel/sqstdlib/sqstdblob.cpp b/sp/src/vscript/squirrel/sqstdlib/sqstdblob.cpp index 261b938b..776a9680 100644 --- a/sp/src/vscript/squirrel/sqstdlib/sqstdblob.cpp +++ b/sp/src/vscript/squirrel/sqstdlib/sqstdblob.cpp @@ -205,8 +205,8 @@ static SQInteger _g_blob_swap2(HSQUIRRELVM v) { SQInteger i; sq_getinteger(v,2,&i); - short s=(short)i; - sq_pushinteger(v,(s<<8)|((s>>8)&0x00FF)); + unsigned short s = (unsigned short)i; + sq_pushinteger(v, ((s << 8) | ((s >> 8) & 0x00FFu)) & 0xFFFFu); return 1; } diff --git a/sp/src/vscript/squirrel/sqstdlib/sqstdstring.cpp b/sp/src/vscript/squirrel/sqstdlib/sqstdstring.cpp index 919bd9e9..5747d8ed 100644 --- a/sp/src/vscript/squirrel/sqstdlib/sqstdstring.cpp +++ b/sp/src/vscript/squirrel/sqstdlib/sqstdstring.cpp @@ -12,6 +12,8 @@ #define MAX_WFORMAT_LEN 3 #define ADDITIONAL_FORMAT_SPACE (100*sizeof(SQChar)) +static SQUserPointer rex_typetag = NULL; + static SQBool isfmtchr(SQChar ch) { switch(ch) { @@ -247,16 +249,16 @@ static SQInteger _string_rstrip(HSQUIRRELVM v) static SQInteger _string_split(HSQUIRRELVM v) { const SQChar *str,*seps; - SQChar *stemp; + SQInteger sepsize; + SQBool skipempty = SQFalse; sq_getstring(v,2,&str); - sq_getstring(v,3,&seps); - SQInteger sepsize = sq_getsize(v,3); + sq_getstringandsize(v,3,&seps,&sepsize); if(sepsize == 0) return sq_throwerror(v,_SC("empty separators string")); - SQInteger memsize = (sq_getsize(v,2)+1)*sizeof(SQChar); - stemp = sq_getscratchpad(v,memsize); - memcpy(stemp,str,memsize); - SQChar *start = stemp; - SQChar *end = stemp; + if(sq_gettop(v)>3) { + sq_getbool(v,4,&skipempty); + } + const SQChar *start = str; + const SQChar *end = str; sq_newarray(v,0); while(*end != '\0') { @@ -265,9 +267,10 @@ static SQInteger _string_split(HSQUIRRELVM v) { if(cur == seps[i]) { - *end = 0; - sq_pushstring(v,start,-1); - sq_arrayappend(v,-2); + if(!skipempty || (end != start)) { + sq_pushstring(v,start,end-start); + sq_arrayappend(v,-2); + } start = end + 1; break; } @@ -276,7 +279,7 @@ static SQInteger _string_split(HSQUIRRELVM v) } if(end != start) { - sq_pushstring(v,start,-1); + sq_pushstring(v,start,end-start); sq_arrayappend(v,-2); } return 1; @@ -384,7 +387,9 @@ static SQInteger _string_endswith(HSQUIRRELVM v) #define SETUP_REX(v) \ SQRex *self = NULL; \ - sq_getinstanceup(v,1,(SQUserPointer *)&self,0); + if(SQ_FAILED(sq_getinstanceup(v,1,(SQUserPointer *)&self,rex_typetag))) { \ + return sq_throwerror(v,_SC("invalid type tag")); \ + } static SQInteger _rexobj_releasehook(SQUserPointer p, SQInteger SQ_UNUSED_ARG(size)) { @@ -465,6 +470,13 @@ static SQInteger _regexp_subexpcount(HSQUIRRELVM v) static SQInteger _regexp_constructor(HSQUIRRELVM v) { + SQRex *self = NULL; + if (SQ_FAILED(sq_getinstanceup(v, 1, (SQUserPointer *)&self, rex_typetag))) { + return sq_throwerror(v, _SC("invalid type tag")); + } + if (self != NULL) { + return sq_throwerror(v, _SC("invalid regexp object")); + } const SQChar *error,*pattern; sq_getstring(v,2,&pattern); SQRex *rex = sqstd_rex_compile(pattern,&error); @@ -499,7 +511,7 @@ static const SQRegFunction stringlib_funcs[]={ _DECL_FUNC(strip,2,_SC(".s")), _DECL_FUNC(lstrip,2,_SC(".s")), _DECL_FUNC(rstrip,2,_SC(".s")), - _DECL_FUNC(split,3,_SC(".ss")), + _DECL_FUNC(split,-3,_SC(".ssb")), _DECL_FUNC(escape,2,_SC(".s")), _DECL_FUNC(startswith,3,_SC(".ss")), _DECL_FUNC(endswith,3,_SC(".ss")), @@ -512,6 +524,8 @@ SQInteger sqstd_register_stringlib(HSQUIRRELVM v) { sq_pushstring(v,_SC("regexp"),-1); sq_newclass(v,SQFalse); + rex_typetag = (SQUserPointer)rexobj_funcs; + sq_settypetag(v, -1, rex_typetag); SQInteger i = 0; while(rexobj_funcs[i].name != 0) { const SQRegFunction &f = rexobj_funcs[i]; diff --git a/sp/src/vscript/squirrel/squirrel/sqbaselib.cpp b/sp/src/vscript/squirrel/squirrel/sqbaselib.cpp index fb6545f9..5c03e839 100644 --- a/sp/src/vscript/squirrel/squirrel/sqbaselib.cpp +++ b/sp/src/vscript/squirrel/squirrel/sqbaselib.cpp @@ -754,7 +754,7 @@ static SQInteger array_find(HSQUIRRELVM v) } -static bool _sort_compare(HSQUIRRELVM v,SQObjectPtr &a,SQObjectPtr &b,SQInteger func,SQInteger &ret) +static bool _sort_compare(HSQUIRRELVM v, SQArray *arr, SQObjectPtr &a,SQObjectPtr &b,SQInteger func,SQInteger &ret) { if(func < 0) { if(!v->ObjCmp(a,b,ret)) return false; @@ -765,15 +765,21 @@ static bool _sort_compare(HSQUIRRELVM v,SQObjectPtr &a,SQObjectPtr &b,SQInteger sq_pushroottable(v); v->Push(a); v->Push(b); + SQObjectPtr *valptr = arr->_values._vals; + SQUnsignedInteger precallsize = arr->_values.size(); if(SQ_FAILED(sq_call(v, 3, SQTrue, SQFalse))) { if(!sq_isstring( v->_lasterror)) v->Raise_Error(_SC("compare func failed")); return false; } - if(SQ_FAILED(sq_getinteger(v, -1, &ret))) { + if(SQ_FAILED(sq_getinteger(v, -1, &ret))) { v->Raise_Error(_SC("numeric value expected as return value of the compare function")); return false; } + if (precallsize != arr->_values.size() || valptr != arr->_values._vals) { + v->Raise_Error(_SC("array resized during sort operation")); + return false; + } sq_settop(v, top); return true; } @@ -792,7 +798,7 @@ static bool _hsort_sift_down(HSQUIRRELVM v,SQArray *arr, SQInteger root, SQInteg maxChild = root2; } else { - if(!_sort_compare(v,arr->_values[root2],arr->_values[root2 + 1],func,ret)) + if(!_sort_compare(v,arr,arr->_values[root2],arr->_values[root2 + 1],func,ret)) return false; if (ret > 0) { maxChild = root2; @@ -802,7 +808,7 @@ static bool _hsort_sift_down(HSQUIRRELVM v,SQArray *arr, SQInteger root, SQInteg } } - if(!_sort_compare(v,arr->_values[root],arr->_values[maxChild],func,ret)) + if(!_sort_compare(v,arr,arr->_values[root],arr->_values[maxChild],func,ret)) return false; if (ret < 0) { if (root == maxChild) { diff --git a/sp/src/vscript/squirrel/squirrel/sqclass.cpp b/sp/src/vscript/squirrel/squirrel/sqclass.cpp index fc619616..53a29763 100644 --- a/sp/src/vscript/squirrel/squirrel/sqclass.cpp +++ b/sp/src/vscript/squirrel/squirrel/sqclass.cpp @@ -61,6 +61,9 @@ bool SQClass::NewSlot(SQSharedState *ss,const SQObjectPtr &key,const SQObjectPtr _defaultvalues[_member_idx(temp)].val = val; return true; } + if (_members->CountUsed() >= MEMBER_MAX_COUNT) { + return false; + } if(belongs_to_static_table) { SQInteger mmidx; if((sq_type(val) == OT_CLOSURE || sq_type(val) == OT_NATIVECLOSURE) && diff --git a/sp/src/vscript/squirrel/squirrel/sqclass.h b/sp/src/vscript/squirrel/squirrel/sqclass.h index 7d402172..60d3d21b 100644 --- a/sp/src/vscript/squirrel/squirrel/sqclass.h +++ b/sp/src/vscript/squirrel/squirrel/sqclass.h @@ -17,6 +17,7 @@ typedef sqvector SQClassMemberVec; #define MEMBER_TYPE_METHOD 0x01000000 #define MEMBER_TYPE_FIELD 0x02000000 +#define MEMBER_MAX_COUNT 0x00FFFFFF #define _ismethod(o) (_integer(o)&MEMBER_TYPE_METHOD) #define _isfield(o) (_integer(o)&MEMBER_TYPE_FIELD) diff --git a/sp/src/vscript/squirrel/squirrel/sqtable.h b/sp/src/vscript/squirrel/squirrel/sqtable.h index 59db3317..8ca3ae7c 100644 --- a/sp/src/vscript/squirrel/squirrel/sqtable.h +++ b/sp/src/vscript/squirrel/squirrel/sqtable.h @@ -12,7 +12,7 @@ #define hashptr(p) ((SQHash)(((SQInteger)p) >> 3)) -inline SQHash HashObj(const SQObjectPtr &key) +inline SQHash HashObj(const SQObject &key) { switch(sq_type(key)) { case OT_STRING: return _string(key)->_hash; From 6579e943052614d1221408b1f3be89bf5dccf3b2 Mon Sep 17 00:00:00 2001 From: samisalreadytaken <46823719+samisalreadytaken@users.noreply.github.com> Date: Wed, 22 Dec 2021 16:10:00 +0300 Subject: [PATCH 291/378] Less memory usage in CScriptConCommand::CommandCompletionCallback --- sp/src/game/shared/mapbase/vscript_singletons.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/sp/src/game/shared/mapbase/vscript_singletons.cpp b/sp/src/game/shared/mapbase/vscript_singletons.cpp index dc3092f1..4b1a8344 100644 --- a/sp/src/game/shared/mapbase/vscript_singletons.cpp +++ b/sp/src/game/shared/mapbase/vscript_singletons.cpp @@ -2290,9 +2290,18 @@ public: { if ( val.m_type == FIELD_CSTRING ) { - CUtlString s = val.m_pszString; - //s.SetLength( COMMAND_COMPLETION_ITEM_LENGTH - 1 ); - commands.AddToTail( s ); + CUtlString &s = commands.Element( commands.AddToTail() ); + int len = V_strlen( val.m_pszString ); + + if ( len <= COMMAND_COMPLETION_ITEM_LENGTH - 1 ) + { + s.Set( val.m_pszString ); + } + else + { + s.SetDirect( val.m_pszString, COMMAND_COMPLETION_ITEM_LENGTH - 1 ); + } + ++count; } g_pScriptVM->ReleaseValue(val); From 192b6983ea15eab4d56725bb187c6155f012783d Mon Sep 17 00:00:00 2001 From: Alexander 'z33ky' Hirsch <1zeeky@gmail.com> Date: Sat, 25 Dec 2021 11:26:15 +0100 Subject: [PATCH 292/378] Fix HL2 (non-episodic) build Broke in cea38f03ec1834ac9f3ab60340746b308df872ec. --- sp/src/game/shared/ragdoll_shared.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sp/src/game/shared/ragdoll_shared.cpp b/sp/src/game/shared/ragdoll_shared.cpp index 86938039..a9da2613 100644 --- a/sp/src/game/shared/ragdoll_shared.cpp +++ b/sp/src/game/shared/ragdoll_shared.cpp @@ -1059,12 +1059,12 @@ void CRagdollLRURetirement::Update( float frametime ) // Non-episodic version if ( m_LRU.Count() > iMaxRagdollCount ) { //Found one, we're done. - if ( ShouldRemoveThisRagdoll( m_LRU[i] ) == true ) + if ( ShouldRemoveThisRagdoll( pRagdoll ) == true ) { #ifdef CLIENT_DLL - m_LRU[ i ]->SUB_Remove(); + pRagdoll->SUB_Remove(); #else - m_LRU[ i ]->SUB_StartFadeOut( 0 ); + pRagdoll->SUB_StartFadeOut( 0 ); #endif m_LRU.Remove(i); @@ -1108,9 +1108,9 @@ void CRagdollLRURetirement::Update( float frametime ) // Non-episodic version #endif #ifdef CLIENT_DLL - m_LRU[ i ]->SUB_Remove(); + pRagdoll->SUB_Remove(); #else - m_LRU[ i ]->SUB_StartFadeOut( 0 ); + pRagdoll->SUB_StartFadeOut( 0 ); #endif m_LRU.Remove(i); } From 023512dcc3af13e7f55e0991480b51d1ab6646dd Mon Sep 17 00:00:00 2001 From: samisalreadytaken <46823719+samisalreadytaken@users.noreply.github.com> Date: Sun, 26 Dec 2021 18:33:53 +0300 Subject: [PATCH 293/378] Minor perf improvement in CScriptMaterialProxy --- sp/src/game/client/vscript_client.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/sp/src/game/client/vscript_client.cpp b/sp/src/game/client/vscript_client.cpp index a01ba4d2..1b2891ab 100644 --- a/sp/src/game/client/vscript_client.cpp +++ b/sp/src/game/client/vscript_client.cpp @@ -252,10 +252,7 @@ CScriptMaterialProxy::CScriptMaterialProxy() m_hScriptInstance = NULL; m_hFuncOnBind = NULL; - for (int i = 0; i < SCRIPT_MAT_PROXY_MAX_VARS; i++) - { - m_MaterialVars[i] = NULL; - } + V_memset( m_MaterialVars, 0, sizeof(m_MaterialVars) ); } CScriptMaterialProxy::~CScriptMaterialProxy() @@ -387,13 +384,10 @@ void CScriptMaterialProxy::OnBind( void *pRenderable ) if (!pEnt) { - // Needs to register as a null value so the script doesn't break if it looks for an entity g_pScriptVM->SetValue( m_ScriptScope, "entity", SCRIPT_VARIANT_NULL ); } m_ScriptScope.Call( m_hFuncOnBind, NULL ); - - g_pScriptVM->ClearValue( m_ScriptScope, "entity" ); } else { From c1eae4a4f91a41db12b768938808c2712ac12474 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sat, 8 Jan 2022 15:34:06 -0600 Subject: [PATCH 294/378] Added new weapon script values for viewmodel FOV override, bob scale, sway scale, and sway speed scale --- sp/src/game/client/view.cpp | 19 +++++++++++++++- .../game/shared/basecombatweapon_shared.cpp | 22 +++++++++++++++++++ sp/src/game/shared/basecombatweapon_shared.h | 6 +++++ sp/src/game/shared/baseviewmodel_shared.cpp | 17 ++++++++++++++ .../shared/hl2/basehlcombatweapon_shared.cpp | 8 +++++++ sp/src/game/shared/weapon_parse.cpp | 13 +++++++++++ sp/src/game/shared/weapon_parse.h | 7 ++++++ 7 files changed, 91 insertions(+), 1 deletion(-) diff --git a/sp/src/game/client/view.cpp b/sp/src/game/client/view.cpp index 17988d18..8cd5293d 100644 --- a/sp/src/game/client/view.cpp +++ b/sp/src/game/client/view.cpp @@ -111,6 +111,7 @@ static ConVar v_centerspeed( "v_centerspeed","500" ); // 54 degrees approximates a 35mm camera - we determined that this makes the viewmodels // and motions look the most natural. ConVar v_viewmodel_fov( "viewmodel_fov", "54", FCVAR_ARCHIVE ); +ConVar v_viewmodel_fov_script_override( "viewmodel_fov_script_override", "0", FCVAR_NONE, "If nonzero, overrides the viewmodel FOV of weapon scripts which override the viewmodel FOV." ); #else ConVar v_viewmodel_fov( "viewmodel_fov", "54", FCVAR_CHEAT ); #endif @@ -675,6 +676,10 @@ void CViewRender::SetUpViews() Vector ViewModelOrigin; QAngle ViewModelAngles; +#ifdef MAPBASE + view.fovViewmodel = g_pClientMode->GetViewModelFOV(); +#endif + if ( engine->IsHLTV() ) { HLTVCamera()->CalcView( view.origin, view.angles, view.fov ); @@ -710,6 +715,18 @@ void CViewRender::SetUpViews() bCalcViewModelView = true; ViewModelOrigin = view.origin; ViewModelAngles = view.angles; + +#ifdef MAPBASE + // Allow weapons to override viewmodel FOV + C_BaseCombatWeapon *pWeapon = pPlayer->GetActiveWeapon(); + if (pWeapon && pWeapon->GetViewmodelFOVOverride() != 0.0f) + { + if (v_viewmodel_fov_script_override.GetFloat() > 0.0f) + view.fovViewmodel = v_viewmodel_fov_script_override.GetFloat(); + else + view.fovViewmodel = pWeapon->GetViewmodelFOVOverride(); + } +#endif } else { @@ -745,7 +762,7 @@ void CViewRender::SetUpViews() //Adjust the viewmodel's FOV to move with any FOV offsets on the viewer's end #ifdef MAPBASE - view.fovViewmodel = max(0.001f, g_pClientMode->GetViewModelFOV() - flFOVOffset); + view.fovViewmodel = max(0.001f, view.fovViewmodel - flFOVOffset); #else view.fovViewmodel = g_pClientMode->GetViewModelFOV() - flFOVOffset; #endif diff --git a/sp/src/game/shared/basecombatweapon_shared.cpp b/sp/src/game/shared/basecombatweapon_shared.cpp index c95a0189..551fc52d 100644 --- a/sp/src/game/shared/basecombatweapon_shared.cpp +++ b/sp/src/game/shared/basecombatweapon_shared.cpp @@ -461,6 +461,28 @@ bool CBaseCombatWeapon::IsMeleeWeapon() const return GetWpnData().m_bMeleeWeapon; } +#ifdef MAPBASE +float CBaseCombatWeapon::GetViewmodelFOVOverride() const +{ + return GetWpnData().m_flViewmodelFOV; +} + +float CBaseCombatWeapon::GetBobScale() const +{ + return GetWpnData().m_flBobScale; +} + +float CBaseCombatWeapon::GetSwayScale() const +{ + return GetWpnData().m_flSwayScale; +} + +float CBaseCombatWeapon::GetSwaySpeedScale() const +{ + return GetWpnData().m_flSwaySpeedScale; +} +#endif + //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- diff --git a/sp/src/game/shared/basecombatweapon_shared.h b/sp/src/game/shared/basecombatweapon_shared.h index abfdb3b0..88078e3e 100644 --- a/sp/src/game/shared/basecombatweapon_shared.h +++ b/sp/src/game/shared/basecombatweapon_shared.h @@ -417,6 +417,12 @@ public: virtual bool UsesClipsForAmmo1( void ) const; virtual bool UsesClipsForAmmo2( void ) const; bool IsMeleeWeapon() const; +#ifdef MAPBASE + float GetViewmodelFOVOverride() const; + float GetBobScale() const; + float GetSwayScale() const; + float GetSwaySpeedScale() const; +#endif // derive this function if you mod uses encrypted weapon info files virtual const unsigned char *GetEncryptionKey( void ); diff --git a/sp/src/game/shared/baseviewmodel_shared.cpp b/sp/src/game/shared/baseviewmodel_shared.cpp index 47acecd6..7c4a4013 100644 --- a/sp/src/game/shared/baseviewmodel_shared.cpp +++ b/sp/src/game/shared/baseviewmodel_shared.cpp @@ -513,6 +513,23 @@ void CBaseViewModel::CalcViewModelLag( Vector& origin, QAngle& angles, QAngle& o float flSpeed = 5.0f; +#ifdef MAPBASE + CBaseCombatWeapon *pWeapon = m_hWeapon.Get(); + if (pWeapon) + { + const FileWeaponInfo_t *pInfo = &pWeapon->GetWpnData(); + if (pInfo->m_flSwayScale != 1.0f) + { + vDifference *= pInfo->m_flSwayScale; + pInfo->m_flSwayScale != 0.0f ? flSpeed /= pInfo->m_flSwayScale : flSpeed = 0.0f; + } + if (pInfo->m_flSwaySpeedScale != 1.0f) + { + flSpeed *= pInfo->m_flSwaySpeedScale; + } + } +#endif + // If we start to lag too far behind, we'll increase the "catch up" speed. Solves the problem with fast cl_yawspeed, m_yaw or joysticks // rotating quickly. The old code would slam lastfacing with origin causing the viewmodel to pop to a new position float flDiff = vDifference.Length(); diff --git a/sp/src/game/shared/hl2/basehlcombatweapon_shared.cpp b/sp/src/game/shared/hl2/basehlcombatweapon_shared.cpp index 8d64f4a5..06c69df7 100644 --- a/sp/src/game/shared/hl2/basehlcombatweapon_shared.cpp +++ b/sp/src/game/shared/hl2/basehlcombatweapon_shared.cpp @@ -317,6 +317,14 @@ float CBaseHLCombatWeapon::CalcViewmodelBob( void ) g_lateralBob = speed*0.005f; g_lateralBob = g_lateralBob*0.3 + g_lateralBob*0.7*sin(cycle); g_lateralBob = clamp( g_lateralBob, -7.0f, 4.0f ); + +#ifdef MAPBASE + if (GetBobScale() != 1.0f) + { + //g_verticalBob *= GetBobScale(); + g_lateralBob *= GetBobScale(); + } +#endif //NOTENOTE: We don't use this return value in our case (need to restructure the calculation function setup!) return 0.0f; diff --git a/sp/src/game/shared/weapon_parse.cpp b/sp/src/game/shared/weapon_parse.cpp index 51dcff10..54b9429a 100644 --- a/sp/src/game/shared/weapon_parse.cpp +++ b/sp/src/game/shared/weapon_parse.cpp @@ -401,6 +401,12 @@ FileWeaponInfo_t::FileWeaponInfo_t() bShowUsageHint = false; m_bAllowFlipping = true; m_bBuiltRightHanded = true; +#ifdef MAPBASE + m_flViewmodelFOV = 0.0f; + m_flBobScale = 1.0f; + m_flSwayScale = 1.0f; + m_flSwaySpeedScale = 1.0f; +#endif } #ifdef CLIENT_DLL @@ -466,6 +472,13 @@ void FileWeaponInfo_t::Parse( KeyValues *pKeyValuesData, const char *szWeaponNam m_bAllowFlipping = ( pKeyValuesData->GetInt( "AllowFlipping", 1 ) != 0 ) ? true : false; m_bMeleeWeapon = ( pKeyValuesData->GetInt( "MeleeWeapon", 0 ) != 0 ) ? true : false; +#ifdef MAPBASE + m_flViewmodelFOV = pKeyValuesData->GetFloat( "viewmodel_fov", 0.0f ); + m_flBobScale = pKeyValuesData->GetFloat( "bob_scale", 1.0f ); + m_flSwayScale = pKeyValuesData->GetFloat( "sway_scale", 1.0f ); + m_flSwaySpeedScale = pKeyValuesData->GetFloat( "sway_speed_scale", 1.0f ); +#endif + #ifndef MAPBASE // Mapbase makes weapons in the same slot & position swap each other out, which is a feature mods can intentionally use. #if defined(_DEBUG) && defined(HL2_CLIENT_DLL) // make sure two weapons aren't in the same slot & position diff --git a/sp/src/game/shared/weapon_parse.h b/sp/src/game/shared/weapon_parse.h index 56803dfa..d3995ee1 100644 --- a/sp/src/game/shared/weapon_parse.h +++ b/sp/src/game/shared/weapon_parse.h @@ -116,6 +116,13 @@ public: bool m_bAllowFlipping; // False to disallow flipping the model, regardless of whether // it is built left or right handed. +#ifdef MAPBASE + float m_flViewmodelFOV; + float m_flBobScale; + float m_flSwayScale; + float m_flSwaySpeedScale; +#endif + // CLIENT DLL // Sprite data, read from the data file int iSpriteCount; From eb05dba580d012e38f8ce9f6461d729c3c401ade Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sat, 8 Jan 2022 15:34:36 -0600 Subject: [PATCH 295/378] Fixed env_credits logo not working properly --- sp/src/game/shared/hl2/hl2_usermessages.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sp/src/game/shared/hl2/hl2_usermessages.cpp b/sp/src/game/shared/hl2/hl2_usermessages.cpp index 0ab97330..93ca871e 100644 --- a/sp/src/game/shared/hl2/hl2_usermessages.cpp +++ b/sp/src/game/shared/hl2/hl2_usermessages.cpp @@ -44,10 +44,11 @@ void RegisterUserMessages( void ) #ifdef MAPBASE // This sends the credits file now usermessages->Register( "CreditsMsg", -1 ); + usermessages->Register( "LogoTimeMsg", -1 ); #else usermessages->Register( "CreditsMsg", 1 ); -#endif usermessages->Register( "LogoTimeMsg", 4 ); +#endif usermessages->Register( "AchievementEvent", -1 ); usermessages->Register( "UpdateJalopyRadar", -1 ); From 125eb70a800924b820430dd5d0784b3b9012eb46 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sat, 8 Jan 2022 15:36:33 -0600 Subject: [PATCH 296/378] Added DisappearMinDist to func_lod for forwards compatibility --- sp/src/game/server/func_lod.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sp/src/game/server/func_lod.cpp b/sp/src/game/server/func_lod.cpp index e1c41c12..7a71e270 100644 --- a/sp/src/game/server/func_lod.cpp +++ b/sp/src/game/server/func_lod.cpp @@ -112,6 +112,10 @@ bool CFunc_LOD::KeyValue( const char *szKeyName, const char *szValue ) { m_fDisappearMaxDist = (float)atof(szValue); } + else if (FStrEq(szKeyName, "DisappearMinDist")) // Forwards compatibility + { + m_fDisappearDist = (float)atof(szValue); + } #endif else if (FStrEq(szKeyName, "Solid")) { From 214f79ebbc758b9fa03e4d1e31f6d8c037165254 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sat, 8 Jan 2022 15:37:34 -0600 Subject: [PATCH 297/378] Added two activity accessor functions for CAI_BaseNPC --- sp/src/game/server/ai_basenpc.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sp/src/game/server/ai_basenpc.h b/sp/src/game/server/ai_basenpc.h index fe63f36e..878a6f81 100644 --- a/sp/src/game/server/ai_basenpc.h +++ b/sp/src/game/server/ai_basenpc.h @@ -1005,6 +1005,10 @@ public: virtual void SetActivity( Activity NewActivity ); Activity GetIdealActivity( void ) { return m_IdealActivity; } void SetIdealActivity( Activity NewActivity ); +#ifdef MAPBASE + Activity GetTranslatedActivity( void ) { return m_translatedActivity; } + Activity GetIdealTranslatedActivity( void ) { return m_IdealTranslatedActivity; } +#endif void ResetIdealActivity( Activity newIdealActivity ); void SetSequenceByName( const char *szSequence ); void SetSequenceById( int iSequence ); From 9156ba84bd46f1b20c7863f5e731792651b53cd2 Mon Sep 17 00:00:00 2001 From: samisalreadytaken <46823719+samisalreadytaken@users.noreply.github.com> Date: Fri, 14 Jan 2022 22:47:00 +0300 Subject: [PATCH 298/378] Add vscript documentation sorting --- sp/src/vscript/vscript_squirrel.nut | 39 +++++++++++++++++------------ 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/sp/src/vscript/vscript_squirrel.nut b/sp/src/vscript/vscript_squirrel.nut index b1700118..334ae92c 100644 --- a/sp/src/vscript/vscript_squirrel.nut +++ b/sp/src/vscript/vscript_squirrel.nut @@ -1,8 +1,8 @@ static char g_Script_vscript_squirrel[] = R"vscript( //========= Mapbase - https://github.com/mapbase-source/source-sdk-2013 ============// // -// Purpose: -// +// Purpose: +// //=============================================================================// Warning <- error; @@ -452,20 +452,28 @@ if (developer) printdocl(text); } - local function PrintMatchesInDocList(pattern, list, printfunc) + local function PrintMatches( pattern, docs, printfunc ) { - local foundMatches = 0; + local matches = []; + local always = pattern == "*"; - foreach(name, doc in list) + foreach( name, doc in docs ) { - if (pattern == "*" || name.tolower().find(pattern) != null || (doc[1].len() && doc[1].tolower().find(pattern) != null)) + if (always || name.tolower().find(pattern) != null || (doc[1].len() && doc[1].tolower().find(pattern) != null)) { - foundMatches = 1; - printfunc(name, doc) + matches.append( name ); } } - return foundMatches; + if ( !matches.len() ) + return 0; + + matches.sort(); + + foreach( name in matches ) + printfunc( name, docs[name] ); + + return 1; } function __Documentation::PrintHelp(pattern = "*") @@ -474,12 +482,12 @@ if (developer) // Have a specific order if (!( - PrintMatchesInDocList( patternLower, DocumentedEnums, PrintEnum ) | - PrintMatchesInDocList( patternLower, DocumentedConsts, PrintConst ) | - PrintMatchesInDocList( patternLower, DocumentedClasses, PrintClass ) | - PrintMatchesInDocList( patternLower, DocumentedFuncs, PrintFunc ) | - PrintMatchesInDocList( patternLower, DocumentedMembers, PrintMember ) | - PrintMatchesInDocList( patternLower, DocumentedHooks, PrintHook ) + PrintMatches( patternLower, DocumentedEnums, PrintEnum ) | + PrintMatches( patternLower, DocumentedConsts, PrintConst ) | + PrintMatches( patternLower, DocumentedClasses, PrintClass ) | + PrintMatches( patternLower, DocumentedFuncs, PrintFunc ) | + PrintMatches( patternLower, DocumentedMembers, PrintMember ) | + PrintMatches( patternLower, DocumentedHooks, PrintHook ) )) { printdocl("Pattern " + pattern + " not found"); @@ -503,7 +511,6 @@ else if (developer) { - // Vector documentation __Documentation.RegisterClassHelp( "Vector", "", "Basic 3-float Vector class." ); __Documentation.RegisterHelp( "Vector::Length", "float Vector::Length()", "Return the vector's length." ); __Documentation.RegisterHelp( "Vector::LengthSqr", "float Vector::LengthSqr()", "Return the vector's squared length." ); From 2be559d50d90fbebdc86d2da647c78452dc200c5 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sat, 15 Jan 2022 13:09:19 -0600 Subject: [PATCH 299/378] Updated README and contribution guidelines --- .github/CONTRIBUTING.md | 9 ++++++++- README | 32 ++++++++++++++++++++++---------- 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 77fa8112..c51715cf 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -23,7 +23,12 @@ All contributions must follow the following rules: is usually not fit for Mapbase. * All content in a contribution must be either already legally open-source or done with the - full permission of the content's original creator(s). + full permission of the content's original creator(s). If licensing is involved, the contribution + must ensure Mapbase follows said licensing. + * **NOTE:** Due to concerns with mods which do not wish to be open-source, content using GPL licenses (or any + license with similar open-source requirements) are currently not allowed to be distributed with Mapbase. + Contributions which can draw from them without actually distributing the licensed content may theoretically + be excepted from this rule. * Contributions must not break existing maps/content or interfere with them in a negative or non-objective way. @@ -34,6 +39,8 @@ All contributions must follow the following rules: use the custom "Mapbase - Source 2013" header used in other Mapbase files as of Mapbase v5.0. You are encouraged to append an "Author(s)" part to that header in your file in order to clarify who wrote it. + * Do not modify the README to add attribution for your contribution. That is handled by Mapbase's maintainers. + Contributions which do not follow these guidelines cannot be accepted into Mapbase. Attempting to contribute content which seriously violates the rules above can lead to being blocked from contributing, diff --git a/README b/README index a8b0244f..924b32fe 100644 --- a/README +++ b/README @@ -25,8 +25,9 @@ https://github.com/mapbase-source/source-sdk-2013/wiki/Introduction-to-Mapbase //=================================================================================================================================================== -Mapbase is an open-source project and its contents can be distributed and used at the discretion of its users. However, this project represents many parts of -the Source modding community packaged into a whole, so credit is taken very seriously. +Mapbase is an open-source project and its contents can be distributed and used at the discretion of its users. However, this project contains content from +a vast number of different sources which have their own licensing or attribution requirements. We try to handle most of that ourselves, but users who plan on +distributing Mapbase content are expected to comply with certain rules. Up-to-date information about Mapbase content usage and credit are addressed in this article on Mapbase's wiki: https://github.com/mapbase-source/source-sdk-2013/wiki/Using-Mapbase-Content @@ -43,20 +44,27 @@ or complicated code changes accessible and easy to use for level designers and o If you believe any content in Mapbase originates from any leak or unauthorized source (Valve or otherwise), please contact Blixibon immediately. Mapbase is intended to be usable by everyone, including licensed Source projects and Steam mods. *** --- The Alien Swarm SDK was used to backport features and code from newer branches of Source into a Source 2013/Half-Life 2 environment. --- Mapbase also implements some of Tony Sergi's code changes from the Source 2007 SDK codebase. Both SDKs are publicly distributed by Valve and are available on Steam. +Mapbase uses content from the following non-Source SDK 2013 Valve games or SDKs: -Some of the features backported from the Alien Swarm SDK (e.g. game instructor, particle rain) require assets from later versions of Source in order to work properly. -The required assets have been backported from Alien Swarm and Left 4 Dead for Mapbase's release build. They are not available in the code repository. +-- Alien Swarm SDK (Used to backport features and code from newer branches of Source into a Source 2013/Half-Life 2 environment) +-- Source SDK 2007 Code (Used to implement some of Tony Sergi's code changes) -Here's a list of Mapbase's other known external code sources: +-- Alien Swarm (Used to port assets from the aforementioned SDK code features, e.g. game instructor icons) +-- Left 4 Dead (Used to port certain animations as well as assets from the aforementioned SDK code features, e.g. particle rain) +-- Half-Life: Source (Used to port friction tool textures) + +Valve allows assets from these titles to be distributed for modding purposes. Note that ported assets are only used in the release build, not the code repository. + +Mapbase may also contain new third-party software distributed under specific licensing. Please see the bottom of thirdpartylegalnotices.txt for more information. + +Here's a list of Mapbase's other external code sources: - https://github.com/95Navigator/insolence-2013 (Initial custom shader code and projected texture improvements; also used to implement ASW SDK particle precipitation code) -- https://github.com/Biohazard90/g-string_2013 (Custom shadow filters, included indirectly via Insolence repo) -- https://github.com/KyleGospo/City-17-Episode-One-Source (Brush phong and projected texture changes, included indirectly via Insolence repo) +-- https://github.com/Biohazard90/g-string_2013 (Custom shadow filters, included indirectly via Insolence repo) +-- https://github.com/KyleGospo/City-17-Episode-One-Source (Brush phong and projected texture changes, included indirectly via Insolence repo) - https://github.com/DownFall-Team/DownFall (Multiple skybox code and fix for ent_fire delay not using floats; Also used as a guide to port certain Alien Swarm SDK changes to Source 2013, including radial fog, rope code, and treesway) -- https://github.com/momentum-mod/game (Used as a guide to port postprocess_controller and env_dof_controller to Source 2013) +- https://github.com/momentum-mod/game (Used as a guide to port postprocess_controller and env_dof_controller to Source 2013 from the Alien Swarm SDK) - https://github.com/DeathByNukes/source-sdk-2013 (VBSP manifest fixes) - https://github.com/entropy-zero/source-sdk-2013 (skill_changed game event) - https://github.com/Nbc66/source-sdk-2013-ce/tree/v142 (Base for VS2019 toolset support) @@ -116,6 +124,9 @@ Direct contributions: =-- https://github.com/mapbase-source/source-sdk-2013/pull/114 (VScript fixes and extensions) =-- https://github.com/mapbase-source/source-sdk-2013/pull/122 (Minor VScript-related adjustments) =-- https://github.com/mapbase-source/source-sdk-2013/pull/148 (Minor fixup) +=-- https://github.com/mapbase-source/source-sdk-2013/pull/167 (Security fixes) +=-- https://github.com/mapbase-source/source-sdk-2013/pull/168 (Squirrel update) +=-- https://github.com/mapbase-source/source-sdk-2013/pull/171 (VScript documentation sorting) == Contributions from z33ky: =-- https://github.com/mapbase-source/source-sdk-2013/pull/21 (Various GCC/Linux compilation fixes) @@ -128,6 +139,7 @@ Direct contributions: =-- https://github.com/mapbase-source/source-sdk-2013/pull/152 (Additional GCC/Linux compilation fixes) =-- https://github.com/mapbase-source/source-sdk-2013/pull/159 (Additional GCC/Linux compilation fixes) =-- https://github.com/mapbase-source/source-sdk-2013/pull/162 (VS2019 exception specification fix) +=-- https://github.com/mapbase-source/source-sdk-2013/pull/170 (HL2 non-Episodic build fix) //--------------------------------------------------------------------------------------------------------------------------------------------------- From 4fdc0624a965ce2533661b33e4fc2490eab83faf Mon Sep 17 00:00:00 2001 From: Blixibon Date: Mon, 17 Jan 2022 11:44:40 -0600 Subject: [PATCH 300/378] Added support for custom VScript procedural targets --- sp/src/game/server/basecombatcharacter.cpp | 5 +- sp/src/game/server/cbase.cpp | 84 ++----- sp/src/game/server/entitylist.cpp | 271 +++++++++++++++++++++ sp/src/game/server/entitylist.h | 36 ++- sp/src/game/server/vscript_server.cpp | 22 ++ 5 files changed, 346 insertions(+), 72 deletions(-) diff --git a/sp/src/game/server/basecombatcharacter.cpp b/sp/src/game/server/basecombatcharacter.cpp index c11eb9fa..c0bb5f1b 100644 --- a/sp/src/game/server/basecombatcharacter.cpp +++ b/sp/src/game/server/basecombatcharacter.cpp @@ -4376,9 +4376,8 @@ CBaseEntity *CBaseCombatCharacter::FindNamedEntity( const char *szName, IEntityF return GetActiveWeapon(); } - // FindEntityProcedural can go through this now, so running this code would likely cause an infinite loop or something. - // As a result, FindEntityProcedural identifies itself with this weird new entity filter. - // Hey, if you've got a better idea, go ahead. + // HACKHACK: FindEntityProcedural can go through this now, so running this code could cause an infinite loop. + // As a result, FindEntityProcedural currently identifies itself with this entity filter. else if (!pFilter || !dynamic_cast(pFilter)) { // search for up to 32 entities with the same name and choose one randomly diff --git a/sp/src/game/server/cbase.cpp b/sp/src/game/server/cbase.cpp index d98ea9cd..abee7a5d 100644 --- a/sp/src/game/server/cbase.cpp +++ b/sp/src/game/server/cbase.cpp @@ -987,83 +987,31 @@ void CEventQueue::ServiceEvents( void ) // In the context the event, the searching entity is also the caller CBaseEntity *pSearchingEntity = pe->m_pCaller; #ifdef MAPBASE - //=============================================================== - // - // This is the code that the I/O system uses to look for its targets. - // - // I wanted a good way to access a COutputEHANDLE's handle parameter. - // Sure, you could do it through logic_register_activator, but what if that's not good enough? - // - // Basic gEntList searches, which this originally used, would require extra implementation for another entity pointer to be passed. - // Without changing the way entity searching works, I just created a custom version of it here. - // - // Yes, all of this for mere "!output" support. - // - // I don't think there's much harm in this anyway. It's functionally identical and might even run a few nanoseconds faster - // since we don't need to check for filters or call the same loop over and over again. - // - //=============================================================== - const char *szName = STRING(pe->m_iTarget); - if ( szName[0] == '!' ) + // This is a hack to access the entity from a FIELD_EHANDLE input + if ( FStrEq( STRING( pe->m_iTarget ), "!output" ) ) { - CBaseEntity *target = gEntList.FindEntityProcedural( szName, pSearchingEntity, pe->m_pActivator, pe->m_pCaller ); + pe->m_VariantValue.Convert( FIELD_EHANDLE ); + CBaseEntity *target = pe->m_VariantValue.Entity(); - if (!target) + // pump the action into the target + target->AcceptInput( STRING( pe->m_iTargetInput ), pe->m_pActivator, pe->m_pCaller, pe->m_VariantValue, pe->m_iOutputID ); + targetFound = true; + } + else +#endif + { + CBaseEntity *target = NULL; + while ( 1 ) { - // Here's the !output I was talking about. - // It only checks for it if we're looking for a procedural entity ('!' confirmed) - // and we didn't find one from FindEntityProcedural. - if (FStrEq(szName, "!output")) - { - pe->m_VariantValue.Convert( FIELD_EHANDLE ); - target = pe->m_VariantValue.Entity(); - } - } + target = gEntList.FindEntityByName( target, pe->m_iTarget, pSearchingEntity, pe->m_pActivator, pe->m_pCaller ); + if ( !target ) + break; - if (target) - { // pump the action into the target target->AcceptInput( STRING(pe->m_iTargetInput), pe->m_pActivator, pe->m_pCaller, pe->m_VariantValue, pe->m_iOutputID ); targetFound = true; } } - else - { - const CEntInfo *pInfo = gEntList.FirstEntInfo(); - - for ( ;pInfo; pInfo = pInfo->m_pNext ) - { - CBaseEntity *ent = (CBaseEntity *)pInfo->m_pEntity; - if ( !ent ) - { - DevWarning( "NULL entity in global entity list!\n" ); - continue; - } - - if ( !ent->GetEntityName() ) - continue; - - if ( ent->NameMatches( szName ) ) - { - // pump the action into the target - ent->AcceptInput( STRING(pe->m_iTargetInput), pe->m_pActivator, pe->m_pCaller, pe->m_VariantValue, pe->m_iOutputID ); - targetFound = true; - } - } - } -#else - CBaseEntity *target = NULL; - while ( 1 ) - { - target = gEntList.FindEntityByName( target, pe->m_iTarget, pSearchingEntity, pe->m_pActivator, pe->m_pCaller ); - if ( !target ) - break; - - // pump the action into the target - target->AcceptInput( STRING(pe->m_iTargetInput), pe->m_pActivator, pe->m_pCaller, pe->m_VariantValue, pe->m_iOutputID ); - targetFound = true; - } -#endif } // direct pointer diff --git a/sp/src/game/server/entitylist.cpp b/sp/src/game/server/entitylist.cpp index bb555a1f..dd886ab3 100644 --- a/sp/src/game/server/entitylist.cpp +++ b/sp/src/game/server/entitylist.cpp @@ -22,6 +22,7 @@ #include "npc_playercompanion.h" #ifdef MAPBASE #include "hl2_player.h" +#include "mapbase_matchers_base.h" #endif #endif // HL2_DLL @@ -78,6 +79,15 @@ public: // IEntityListener virtual void OnEntityCreated( CBaseEntity *pEntity ) {} + virtual void OnEntitySpawned( CBaseEntity *pEntity ) + { + // From Alien Swarm SDK + if ( ShouldAddEntity( pEntity ) ) + { + RemoveEntity( pEntity ); + AddEntity( pEntity ); + } + } virtual void OnEntityDeleted( CBaseEntity *pEntity ) { if ( !(pEntity->GetFlags() & FL_AIMTARGET) ) @@ -105,6 +115,10 @@ public: memcpy( pList, m_targetList.Base(), sizeof(CBaseEntity *) * count ); return count; } + CBaseEntity *ListElement( int iIndex ) // From Alien Swarm SDK + { + return m_targetList[iIndex]; + } private: CUtlVector m_targetList; @@ -120,6 +134,10 @@ int AimTarget_ListCopy( CBaseEntity *pList[], int listMax ) { return g_AimManager.ListCopy( pList, listMax ); } +CBaseEntity *AimTarget_ListElement( int iIndex ) +{ + return g_AimManager.ListElement( iIndex ); +} void AimTarget_ForceRepopulateList() { g_AimManager.ForceRepopulateList(); @@ -293,6 +311,10 @@ CBaseEntityClassList::~CBaseEntityClassList() { } +#ifdef MAPBASE_VSCRIPT +static CUtlVector g_CustomProcedurals; +#endif + CGlobalEntityList::CGlobalEntityList() { m_iHighestEnt = m_iNumEnts = m_iNumEdicts = 0; @@ -380,6 +402,18 @@ void CGlobalEntityList::Clear( void ) // free the memory g_DeleteList.Purge(); +#ifdef _DEBUG // From Alien Swarm SDK + for ( UtlHashHandle_t handle = g_EntsByClassname.GetFirstHandle(); g_EntsByClassname.IsValidHandle(handle); handle = g_EntsByClassname.GetNextHandle(handle) ) + { + EntsByStringList_t &element = g_EntsByClassname[handle]; + Assert( element.pHead == NULL ); + } +#endif + +#ifdef MAPBASE_VSCRIPT + g_CustomProcedurals.Purge(); +#endif + CBaseEntity::m_nDebugPlayer = -1; CBaseEntity::m_bInDebugSelect = false; m_iHighestEnt = 0; @@ -516,6 +550,43 @@ CBaseEntity *CGlobalEntityList::FindEntityByClassname( CBaseEntity *pStartEntity return NULL; } +// From Alien Swarm SDK +CBaseEntity *CGlobalEntityList::FindEntityByClassnameFast( CBaseEntity *pStartEntity, string_t iszClassname ) +{ + /* + if ( pStartEntity ) + { + return pStartEntity->m_pNextByClass; + } + + EntsByStringList_t key = { iszClassname }; + UtlHashHandle_t hEntry = g_EntsByClassname.Find( key ); + if ( hEntry != g_EntsByClassname.InvalidHandle() ) + { + return g_EntsByClassname[hEntry].pHead; + } + */ + + const CEntInfo *pInfo = pStartEntity ? GetEntInfoPtr( pStartEntity->GetRefEHandle() )->m_pNext : FirstEntInfo(); + + for ( ;pInfo; pInfo = pInfo->m_pNext ) + { + CBaseEntity *pEntity = (CBaseEntity *)pInfo->m_pEntity; + if ( !pEntity ) + { + DevWarning( "NULL entity in global entity list!\n" ); + continue; + } + + if ( pEntity->m_iClassname == iszClassname) + { + return pEntity; + } + } + + return NULL; +} + //----------------------------------------------------------------------------- // Purpose: Finds an entity given a procedural name. @@ -633,6 +704,93 @@ CBaseEntity *CGlobalEntityList::FindEntityProcedural( const char *szName, CBaseE } +#ifdef MAPBASE_VSCRIPT +//----------------------------------------------------------------------------- +// Purpose: Finds an entity given a custom procedural name. +// Input : szName - The procedural name to search for, should start with '!'. +// pSearchingEntity - +// pActivator - The activator entity if this was called from an input +// or Use handler. +//----------------------------------------------------------------------------- +CBaseEntity *CGlobalEntityList::FindEntityCustomProcedural( CBaseEntity *pStartEntity, const char *szName, CBaseEntity *pSearchingEntity, CBaseEntity *pActivator, CBaseEntity *pCaller ) +{ + const char *pName = szName; + + // + // Check for the name escape character. + // + if ( szName[0] == '!' ) + pName = szName + 1; + + // + // Look through the custom procedural list. + // + for (int i = 0; i < g_CustomProcedurals.Count(); i++) + { + if (Matcher_NamesMatch( g_CustomProcedurals[i].szName, pName )) + { + if (pStartEntity && g_CustomProcedurals[i].bCanReturnMultiple == false) + return NULL; + + // name, startEntity, searchingEntity, activator, caller + ScriptVariant_t functionReturn; + ScriptVariant_t args[] = { + ScriptVariant_t( pName ), + ScriptVariant_t( ToHScript( pStartEntity ) ), + ScriptVariant_t( ToHScript( pSearchingEntity ) ), + ScriptVariant_t( ToHScript( pActivator ) ), + ScriptVariant_t( ToHScript( pCaller ) ), + }; + + g_pScriptVM->ExecuteFunction( g_CustomProcedurals[i].hFunc, args, 5, &functionReturn, NULL, true ); + + return ToEnt( functionReturn.m_hScript ); + } + } + + return NULL; +} + +void CGlobalEntityList::AddCustomProcedural( const char *pszName, HSCRIPT hFunc, bool bCanReturnMultiple ) +{ + // + // Check for any existing custom procedurals to replace. + // + for (int i = 0; i < g_CustomProcedurals.Count(); i++) + { + if (FStrEq( pszName, g_CustomProcedurals[i].szName )) + { + g_CustomProcedurals.FastRemove( i ); + break; + } + } + + // + // Add a new custom procedural. + // + int i = g_CustomProcedurals.AddToTail(); + g_CustomProcedurals[i].szName = pszName; + g_CustomProcedurals[i].hFunc = hFunc; + g_CustomProcedurals[i].bCanReturnMultiple = bCanReturnMultiple; +} + +void CGlobalEntityList::RemoveCustomProcedural( const char *pszName ) +{ + // + // Remove the specified custom procedural. + // + for (int i = 0; i < g_CustomProcedurals.Count(); i++) + { + if (FStrEq( pszName, g_CustomProcedurals[i].szName )) + { + g_CustomProcedurals.FastRemove( i ); + break; + } + } +} +#endif + + //----------------------------------------------------------------------------- // Purpose: Iterates the entities with a given name. // Input : pStartEntity - Last entity found, NULL to start a new iteration. @@ -647,6 +805,16 @@ CBaseEntity *CGlobalEntityList::FindEntityByName( CBaseEntity *pStartEntity, con if ( szName[0] == '!' ) { +#ifdef MAPBASE + if (g_CustomProcedurals.Count() > 0) + { + // Search for a custom procedural + CBaseEntity *ent = FindEntityCustomProcedural( pStartEntity, szName, pSearchingEntity, pActivator, pCaller ); + if (ent != NULL) + return ent; + } +#endif + // // Avoid an infinite loop, only find one match per procedural search! // @@ -682,6 +850,35 @@ CBaseEntity *CGlobalEntityList::FindEntityByName( CBaseEntity *pStartEntity, con return NULL; } +// From Alien Swarm SDK +CBaseEntity *CGlobalEntityList::FindEntityByNameFast( CBaseEntity *pStartEntity, string_t iszName ) +{ + if ( iszName == NULL_STRING || STRING(iszName)[0] == 0 ) + return NULL; + + const CEntInfo *pInfo = pStartEntity ? GetEntInfoPtr( pStartEntity->GetRefEHandle() )->m_pNext : FirstEntInfo(); + + for ( ;pInfo; pInfo = pInfo->m_pNext ) + { + CBaseEntity *ent = (CBaseEntity *)pInfo->m_pEntity; + if ( !ent ) + { + DevWarning( "NULL entity in global entity list!\n" ); + continue; + } + + if ( !ent->m_iName.Get() ) + continue; + + if ( ent->m_iName.Get() == iszName ) + { + return ent; + } + } + + return NULL; +} + //----------------------------------------------------------------------------- // Purpose: // Input : pStartEntity - @@ -899,6 +1096,80 @@ CBaseEntity *CGlobalEntityList::FindEntityByClassnameNearest( const char *szName } +// From Alien Swarm SDK +CBaseEntity *CGlobalEntityList::FindEntityByClassnameNearestFast( string_t iszName, const Vector &vecSrc, float flRadius ) +{ + CBaseEntity *pEntity = NULL; + + // + // Check for matching class names within the search radius. + // + float flMaxDist2 = flRadius * flRadius; + if (flMaxDist2 == 0) + { + flMaxDist2 = MAX_TRACE_LENGTH * MAX_TRACE_LENGTH; + } + + CBaseEntity *pSearch = NULL; + while ((pSearch = gEntList.FindEntityByClassnameFast( pSearch, iszName )) != NULL) + { + if ( !pSearch->edict() ) + continue; + + float flDist2 = (pSearch->GetAbsOrigin() - vecSrc).LengthSqr(); + + if (flMaxDist2 > flDist2) + { + pEntity = pSearch; + flMaxDist2 = flDist2; + } + } + + return pEntity; +} + + +//----------------------------------------------------------------------------- +// Purpose: Finds the nearest entity by class name withing given search radius. +// From Alien Swarm SDK +// Input : szName - Entity name to search for. Treated as a target name first, +// then as an entity class name, ie "info_target". +// vecSrc - Center of search radius. +// flRadius - Search radius for classname search, 0 to search everywhere. +// Output : Returns a pointer to the found entity, NULL if none. +//----------------------------------------------------------------------------- +CBaseEntity *CGlobalEntityList::FindEntityByClassnameNearest2D( const char *szName, const Vector &vecSrc, float flRadius ) +{ + CBaseEntity *pEntity = NULL; + + // + // Check for matching class names within the search radius. + // + float flMaxDist2 = flRadius * flRadius; + if (flMaxDist2 == 0) + { + flMaxDist2 = MAX_TRACE_LENGTH * MAX_TRACE_LENGTH; + } + + CBaseEntity *pSearch = NULL; + while ((pSearch = gEntList.FindEntityByClassname( pSearch, szName )) != NULL) + { + if ( !pSearch->edict() ) + continue; + + float flDist2 = (pSearch->GetAbsOrigin().AsVector2D() - vecSrc.AsVector2D()).LengthSqr(); + + if (flMaxDist2 > flDist2) + { + pEntity = pSearch; + flMaxDist2 = flDist2; + } + } + + return pEntity; +} + + //----------------------------------------------------------------------------- // Purpose: Finds the first entity within radius distance by class name. diff --git a/sp/src/game/server/entitylist.h b/sp/src/game/server/entitylist.h index 505b1968..e2339ada 100644 --- a/sp/src/game/server/entitylist.h +++ b/sp/src/game/server/entitylist.h @@ -74,6 +74,26 @@ public: virtual bool ShouldFindEntity( CBaseEntity *pEntity ) { return false; } virtual CBaseEntity *GetFilterResult( void ) { return NULL; } }; + +//----------------------------------------------------------------------------- +// Custom procedural names via VScript. This allows users to reference new '!' targets +// or override existing ones. It is capable of returning multiple entities when needed. +// +// This is useful if you want I/O and beyond to reference an entity/a number of entities +// which may possess differing or ambiguous targetnames, or if you want to reference an +// entity specific to the context of the operation (e.g. getting the searching entity's +// current weapon). +// +// For example, you could add a new procedural called "!first_child" which uses VScript to +// return the searching entity's first child entity. You could also add a procedural called +// "!children" which returns all of the searching entity's child entities. +//----------------------------------------------------------------------------- +struct CustomProcedural_t +{ + HSCRIPT hFunc; + const char *szName; + bool bCanReturnMultiple; +}; #endif //----------------------------------------------------------------------------- @@ -160,6 +180,7 @@ public: CBaseEntity *FindEntityByNameNearest( const char *szName, const Vector &vecSrc, float flRadius, CBaseEntity *pSearchingEntity = NULL, CBaseEntity *pActivator = NULL, CBaseEntity *pCaller = NULL ); CBaseEntity *FindEntityByNameWithin( CBaseEntity *pStartEntity, const char *szName, const Vector &vecSrc, float flRadius, CBaseEntity *pSearchingEntity = NULL, CBaseEntity *pActivator = NULL, CBaseEntity *pCaller = NULL ); CBaseEntity *FindEntityByClassnameNearest( const char *szName, const Vector &vecSrc, float flRadius ); + CBaseEntity *FindEntityByClassnameNearest2D( const char *szName, const Vector &vecSrc, float flRadius ); // From Alien Swarm SDK CBaseEntity *FindEntityByClassnameWithin( CBaseEntity *pStartEntity , const char *szName, const Vector &vecSrc, float flRadius ); CBaseEntity *FindEntityByClassnameWithin( CBaseEntity *pStartEntity , const char *szName, const Vector &vecMins, const Vector &vecMaxs ); @@ -176,7 +197,19 @@ public: CBaseEntity *FindEntityByNetname( CBaseEntity *pStartEntity, const char *szModelName ); CBaseEntity *FindEntityProcedural( const char *szName, CBaseEntity *pSearchingEntity = NULL, CBaseEntity *pActivator = NULL, CBaseEntity *pCaller = NULL ); - +#ifdef MAPBASE_VSCRIPT + CBaseEntity *FindEntityCustomProcedural( CBaseEntity *pStartEntity, const char *szName, CBaseEntity *pSearchingEntity = NULL, CBaseEntity *pActivator = NULL, CBaseEntity *pCaller = NULL ); + + void AddCustomProcedural( const char *pszName, HSCRIPT hFunc, bool bCanReturnMultiple ); + void RemoveCustomProcedural( const char *pszName ); +#endif + + // Fast versions that require a (real) string_t, and won't do wildcarding + // From Alien Swarm SDK + CBaseEntity *FindEntityByClassnameFast( CBaseEntity *pStartEntity, string_t iszClassname ); + CBaseEntity *FindEntityByClassnameNearestFast( string_t iszClassname, const Vector &vecSrc, float flRadius ); + CBaseEntity *FindEntityByNameFast( CBaseEntity *pStartEntity, string_t iszName ); + CGlobalEntityList(); // CBaseEntityList overrides. @@ -373,6 +406,7 @@ extern INotify *g_pNotify; void EntityTouch_Add( CBaseEntity *pEntity ); int AimTarget_ListCount(); int AimTarget_ListCopy( CBaseEntity *pList[], int listMax ); +CBaseEntity *AimTarget_ListElement( int iIndex ); void AimTarget_ForceRepopulateList(); void SimThink_EntityChanged( CBaseEntity *pEntity ); diff --git a/sp/src/game/server/vscript_server.cpp b/sp/src/game/server/vscript_server.cpp index 76d66a83..559c57e3 100644 --- a/sp/src/game/server/vscript_server.cpp +++ b/sp/src/game/server/vscript_server.cpp @@ -122,6 +122,24 @@ public: return ToHScript( gEntList.FindEntityClassNearestFacing( origin, facing, threshold, const_cast(classname) ) ); } + HSCRIPT FindByClassnameNearest2D( const char *szName, const Vector &vecSrc, float flRadius ) + { + return ToHScript( gEntList.FindEntityByClassnameNearest2D( szName, vecSrc, flRadius ) ); + } + + // + // Custom Procedurals + // + void AddCustomProcedural( const char *pszName, HSCRIPT hFunc, bool bCanReturnMultiple ) + { + gEntList.AddCustomProcedural( pszName, hFunc, bCanReturnMultiple ); + } + + void RemoveCustomProcedural( const char *pszName ) + { + gEntList.RemoveCustomProcedural( pszName ); + } + void EnableEntityListening() { // Start getting entity updates! @@ -186,6 +204,10 @@ BEGIN_SCRIPTDESC_ROOT_NAMED( CScriptEntityIterator, "CEntities", SCRIPT_SINGLETO #ifdef MAPBASE_VSCRIPT DEFINE_SCRIPTFUNC( FindByClassnameWithinBox, "Find entities by class name within an AABB. Pass 'null' to start an iteration, or reference to a previously found entity to continue a search" ) DEFINE_SCRIPTFUNC( FindByClassNearestFacing, "Find the nearest entity along the facing direction from the given origin within the angular threshold with the given classname." ) + DEFINE_SCRIPTFUNC( FindByClassnameNearest2D, "Find entities by class name nearest to a point in 2D space." ) + + DEFINE_SCRIPTFUNC( AddCustomProcedural, "Adds a custom '!' target name. The first parameter is the name of the procedural (which should NOT include the '!'), the second parameter is a function which should support 5 arguments (name, startEntity, searchingEntity, activator, caller), and the third parameter is whether or not this procedural can return multiple entities. Note that these are NOT saved and must be redeclared on restore!" ) + DEFINE_SCRIPTFUNC( RemoveCustomProcedural, "Removes a custom '!' target name previously defined with AddCustomProcedural." ) DEFINE_SCRIPTFUNC( EnableEntityListening, "Enables the 'OnEntity' hooks. This function must be called before using them." ) DEFINE_SCRIPTFUNC( DisableEntityListening, "Disables the 'OnEntity' hooks." ) From 551de3fe1959124e51b4828c23066cd954fd28de Mon Sep 17 00:00:00 2001 From: Blixibon Date: Mon, 17 Jan 2022 12:35:17 -0600 Subject: [PATCH 301/378] Added CreateRopeWithSecondPointDetached function for VScript --- .../game/shared/mapbase/vscript_funcs_shared.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp b/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp index 492a4939..9f3d78b7 100644 --- a/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp +++ b/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp @@ -861,6 +861,17 @@ static HSCRIPT ScriptCreateRope( HSCRIPT hStart, HSCRIPT hEnd, int iStartAttachm return ToHScript( pRope ); } +#ifndef CLIENT_DLL +static HSCRIPT ScriptCreateRopeWithSecondPointDetached( HSCRIPT hStart, int iStartAttachment, int ropeLength, float ropeWidth, const char *pMaterialName, int numSegments, bool initialHang, int ropeFlags ) +{ + CRopeKeyframe *pRope = CRopeKeyframe::CreateWithSecondPointDetached( ToEnt( hStart ), iStartAttachment, ropeLength, ropeWidth, pMaterialName, numSegments, initialHang ); + if (pRope) + pRope->m_RopeFlags |= ropeFlags; // HACKHACK + + return ToHScript( pRope ); +} +#endif + static void EmitSoundParamsOn( HSCRIPT hParams, HSCRIPT hEnt ) { CBaseEntity *pEnt = ToEnt( hEnt ); @@ -1042,6 +1053,9 @@ void RegisterSharedScriptFunctions() ScriptRegisterFunctionNamed( g_pScriptVM, ScriptDispatchParticleEffect, "DoDispatchParticleEffect", SCRIPT_ALIAS( "DispatchParticleEffect", "Dispatches a one-off particle system" ) ); ScriptRegisterFunctionNamed( g_pScriptVM, ScriptCreateRope, "CreateRope", "Creates a single rope between two entities. Can optionally follow specific attachments." ); +#ifndef CLIENT_DLL + ScriptRegisterFunctionNamed( g_pScriptVM, ScriptCreateRopeWithSecondPointDetached, "CreateRopeWithSecondPointDetached", "Creates a single detached rope hanging from a point. Can optionally follow a specific start attachment." ); +#endif ScriptRegisterFunction( g_pScriptVM, EmitSoundParamsOn, "Play EmitSound_t params on an entity." ); From ef19f1455d056453157d0e670bdd9d5d37fc1e3e Mon Sep 17 00:00:00 2001 From: Blixibon Date: Mon, 17 Jan 2022 16:39:25 -0600 Subject: [PATCH 302/378] Fixed fake sequence gestures not identifying movement correctly --- sp/src/game/server/ai_basenpc.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sp/src/game/server/ai_basenpc.cpp b/sp/src/game/server/ai_basenpc.cpp index 8c3fbc61..c5fa8c7b 100644 --- a/sp/src/game/server/ai_basenpc.cpp +++ b/sp/src/game/server/ai_basenpc.cpp @@ -7228,8 +7228,8 @@ bool CAI_BaseNPC::ShouldPlayFakeSequenceGesture( Activity nActivity, Activity nT if (GetActivity() == ACT_RESET) return false; - // No need to do this while we're moving - if (IsCurTaskContinuousMove()) + // No need to do this while we're moving or for sequences which will make us move + if (IsMoving()) return false; if (ai_debug_fake_sequence_gestures_always_play.GetBool()) From f448be8c2b788db8022b87ef8219d379df7bdaeb Mon Sep 17 00:00:00 2001 From: Blixibon Date: Mon, 17 Jan 2022 16:45:31 -0600 Subject: [PATCH 303/378] Added misc. speech/choreo utilities --- sp/src/game/server/ai_speech.cpp | 26 ++++++++++ sp/src/game/server/ai_speech.h | 4 ++ sp/src/game/server/sceneentity.cpp | 83 ++++++++++++++++++++++++++++++ sp/src/game/server/sceneentity.h | 1 + 4 files changed, 114 insertions(+) diff --git a/sp/src/game/server/ai_speech.cpp b/sp/src/game/server/ai_speech.cpp index dafad41e..1bc7caf8 100644 --- a/sp/src/game/server/ai_speech.cpp +++ b/sp/src/game/server/ai_speech.cpp @@ -1153,6 +1153,32 @@ void CAI_Expresser::ClearSpokeConcept( AIConcept_t concept ) m_ConceptHistories.Remove( concept ); } +#ifdef MAPBASE +//------------------------------------- + +AIConcept_t CAI_Expresser::GetLastSpokeConcept( AIConcept_t excludeConcept /* = NULL */ ) +{ + int iLastSpokenIndex = m_ConceptHistories.InvalidIndex(); + float flLast = 0.0f; + for ( int i = m_ConceptHistories.First(); i != m_ConceptHistories.InvalidIndex(); i = m_ConceptHistories.Next(i ) ) + { + ConceptHistory_t *h = &m_ConceptHistories[ i ]; + + // If an 'exclude concept' was provided, skip over this entry in the history if it matches the exclude concept + if ( excludeConcept != NULL && FStrEq( m_ConceptHistories.GetElementName( i ), excludeConcept ) ) + continue; + + if ( h->timeSpoken >= flLast ) + { + iLastSpokenIndex = i; + flLast = h->timeSpoken; + } + } + + return iLastSpokenIndex != m_ConceptHistories.InvalidIndex() ? m_ConceptHistories.GetElementName( iLastSpokenIndex ) : NULL; +} +#endif + //------------------------------------- void CAI_Expresser::DumpHistories() diff --git a/sp/src/game/server/ai_speech.h b/sp/src/game/server/ai_speech.h index 5ed12255..69406fa5 100644 --- a/sp/src/game/server/ai_speech.h +++ b/sp/src/game/server/ai_speech.h @@ -192,6 +192,10 @@ public: float GetTimeSpokeConcept( AIConcept_t concept ); // returns -1 if never void SetSpokeConcept( AIConcept_t concept, AI_Response *response, bool bCallback = true ); void ClearSpokeConcept( AIConcept_t concept ); + +#ifdef MAPBASE + AIConcept_t GetLastSpokeConcept( AIConcept_t excludeConcept = NULL ); +#endif // -------------------------------- diff --git a/sp/src/game/server/sceneentity.cpp b/sp/src/game/server/sceneentity.cpp index 0437c280..9f0f3010 100644 --- a/sp/src/game/server/sceneentity.cpp +++ b/sp/src/game/server/sceneentity.cpp @@ -159,6 +159,7 @@ public: #ifdef MAPBASE bool IsRunningScriptedSceneWithFlexAndNotPaused( CBaseFlex *pActor, bool bIgnoreInstancedScenes, const char *pszNotThisScene = NULL ); + bool IsTalkingInAScriptedScene( CBaseFlex *pActor, bool bIgnoreInstancedScenes = false ); CUtlVector< CHandle< CSceneEntity > > *GetActiveSceneList(); #endif @@ -485,6 +486,9 @@ public: bool HasUnplayedSpeech( void ); bool HasFlexAnimation( void ); +#ifdef MAPBASE + bool IsPlayingSpeech( void ); +#endif void SetCurrentTime( float t, bool forceClientSync ); @@ -1157,6 +1161,31 @@ bool CSceneEntity::HasFlexAnimation( void ) return false; } +#ifdef MAPBASE +//----------------------------------------------------------------------------- +// Purpose: +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CSceneEntity::IsPlayingSpeech( void ) +{ + if ( m_pScene ) + { + float flTime = m_pScene->GetTime(); + for ( int i = 0; i < m_pScene->GetNumEvents(); i++ ) + { + CChoreoEvent *e = m_pScene->GetEvent( i ); + if ( e->GetType() == CChoreoEvent::SPEAK ) + { + if ( /*flTime >= e->GetStartTime() &&*/ flTime <= e->GetEndTime() ) + return true; + } + } + } + + return false; +} +#endif + //----------------------------------------------------------------------------- // Purpose: @@ -2576,6 +2605,30 @@ bool CSceneEntity::CheckActors() return false; } } +#ifdef MAPBASE + else if ( pTestActor->IsPlayer() ) + { + // Blixibon - Player speech handling + CBasePlayer *pPlayer = static_cast(pTestActor); + bool bShouldWait = false; + if ( pPlayer->GetExpresser() && pPlayer->GetExpresser()->IsSpeaking() ) + { + bShouldWait = true; + } + else if ( IsTalkingInAScriptedScene( pPlayer ) ) + { + bShouldWait = true; + } + + if ( bShouldWait ) + { + // One of the actors for this scene is talking already. + // Try again next think. + m_bWaitingForActor = true; + return false; + } + } +#endif } else if ( m_BusyActor == SCENE_BUSYACTOR_INTERRUPT || m_BusyActor == SCENE_BUSYACTOR_INTERRUPT_CANCEL ) { @@ -5937,6 +5990,31 @@ bool CSceneManager::IsRunningScriptedSceneWithFlexAndNotPaused( CBaseFlex *pActo } +bool CSceneManager::IsTalkingInAScriptedScene( CBaseFlex *pActor, bool bIgnoreInstancedScenes ) +{ + int c = m_ActiveScenes.Count(); + for ( int i = 0; i < c; i++ ) + { + CSceneEntity *pScene = m_ActiveScenes[ i ].Get(); + if ( !pScene || + !pScene->IsPlayingBack() || + pScene->IsPaused() || + ( bIgnoreInstancedScenes && dynamic_cast(pScene) != NULL ) + ) + { + continue; + } + + if ( pScene->InvolvesActor( pActor ) ) + { + if ( pScene->IsPlayingSpeech() ) + return true; + } + } + return false; +} + + CUtlVector< CHandle< CSceneEntity > > *CSceneManager::GetActiveSceneList() { return &m_ActiveScenes; @@ -6035,6 +6113,11 @@ bool IsRunningScriptedSceneWithFlexAndNotPaused( CBaseFlex *pActor, bool bIgnore return GetSceneManager()->IsRunningScriptedSceneWithFlexAndNotPaused( pActor, bIgnoreInstancedScenes, pszNotThisScene ); } +bool IsTalkingInAScriptedScene( CBaseFlex *pActor, bool bIgnoreInstancedScenes ) +{ + return GetSceneManager()->IsTalkingInAScriptedScene( pActor, bIgnoreInstancedScenes ); +} + CUtlVector< CHandle< CSceneEntity > > *GetActiveSceneList() { return GetSceneManager()->GetActiveSceneList(); diff --git a/sp/src/game/server/sceneentity.h b/sp/src/game/server/sceneentity.h index 6e005a60..8f221540 100644 --- a/sp/src/game/server/sceneentity.h +++ b/sp/src/game/server/sceneentity.h @@ -41,6 +41,7 @@ bool IsRunningScriptedSceneWithSpeech( CBaseFlex *pActor, bool bIgnoreInstancedS bool IsRunningScriptedSceneWithSpeechAndNotPaused( CBaseFlex *pActor, bool bIgnoreInstancedScenes = false ); #ifdef MAPBASE bool IsRunningScriptedSceneWithFlexAndNotPaused( CBaseFlex *pActor, bool bIgnoreInstancedScenes = false, const char *pszNotThisScene = NULL ); +bool IsTalkingInAScriptedScene( CBaseFlex *pActor, bool bIgnoreInstancedScenes = false ); CUtlVector< CHandle< CSceneEntity > > *GetActiveSceneList(); #endif float GetSceneDuration( char const *pszScene ); From 06d2da374297eb98ab207d9be9947003ad45ea34 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Mon, 17 Jan 2022 16:49:30 -0600 Subject: [PATCH 304/378] Added GetRealTimeSpeechComplete --- sp/src/game/server/ai_speech.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sp/src/game/server/ai_speech.h b/sp/src/game/server/ai_speech.h index 69406fa5..72c704b8 100644 --- a/sp/src/game/server/ai_speech.h +++ b/sp/src/game/server/ai_speech.h @@ -184,6 +184,10 @@ public: bool CanSpeakAfterMyself(); float GetTimeSpeechComplete() const { return m_flStopTalkTime; } void BlockSpeechUntil( float time ); + +#ifdef EZ2 + float GetRealTimeSpeechComplete() const { return m_flStopTalkTimeWithoutDelay; } +#endif // -------------------------------- From ed21bb3d1d3e6fcd869fc4923d3a8035113d8fee Mon Sep 17 00:00:00 2001 From: Blixibon Date: Mon, 17 Jan 2022 16:49:52 -0600 Subject: [PATCH 305/378] Added misc. speech/choreo utilities to ai_speech_new --- sp/src/game/server/ai_speech_new.cpp | 26 ++++++++++++++++++++++++++ sp/src/game/server/ai_speech_new.h | 4 ++++ 2 files changed, 30 insertions(+) diff --git a/sp/src/game/server/ai_speech_new.cpp b/sp/src/game/server/ai_speech_new.cpp index 41fe6182..8d73911f 100644 --- a/sp/src/game/server/ai_speech_new.cpp +++ b/sp/src/game/server/ai_speech_new.cpp @@ -1528,6 +1528,32 @@ void CAI_Expresser::ClearSpokeConcept( const AIConcept_t &concept ) m_ConceptHistories.Remove( concept ); } +#ifdef MAPBASE +//------------------------------------- + +AIConcept_t CAI_Expresser::GetLastSpokeConcept( AIConcept_t excludeConcept /* = NULL */ ) +{ + int iLastSpokenIndex = m_ConceptHistories.InvalidIndex(); + float flLast = 0.0f; + for ( int i = m_ConceptHistories.First(); i != m_ConceptHistories.InvalidIndex(); i = m_ConceptHistories.Next(i ) ) + { + ConceptHistory_t *h = &m_ConceptHistories[ i ]; + + // If an 'exclude concept' was provided, skip over this entry in the history if it matches the exclude concept + if ( excludeConcept != NULL && FStrEq( m_ConceptHistories.GetElementName( i ), excludeConcept ) ) + continue; + + if ( h->timeSpoken >= flLast ) + { + iLastSpokenIndex = i; + flLast = h->timeSpoken; + } + } + + return iLastSpokenIndex != m_ConceptHistories.InvalidIndex() ? m_ConceptHistories.GetElementName( iLastSpokenIndex ) : NULL; +} +#endif + //------------------------------------- void CAI_Expresser::DumpHistories() diff --git a/sp/src/game/server/ai_speech_new.h b/sp/src/game/server/ai_speech_new.h index 1882e66e..70e73354 100644 --- a/sp/src/game/server/ai_speech_new.h +++ b/sp/src/game/server/ai_speech_new.h @@ -211,6 +211,10 @@ public: float GetTimeSpokeConcept( const AIConcept_t &concept ); // returns -1 if never void SetSpokeConcept( const AIConcept_t &concept, AI_Response *response, bool bCallback = true ); void ClearSpokeConcept( const AIConcept_t &concept ); + +#ifdef MAPBASE + AIConcept_t GetLastSpokeConcept( AIConcept_t excludeConcept = NULL ); +#endif // -------------------------------- From 45191b97f82c948e0ea413f8e605c0e683ce615d Mon Sep 17 00:00:00 2001 From: Blixibon Date: Mon, 17 Jan 2022 19:11:23 -0600 Subject: [PATCH 306/378] Fixed incorrect ifdef preprocessor --- sp/src/game/server/ai_speech.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sp/src/game/server/ai_speech.h b/sp/src/game/server/ai_speech.h index 72c704b8..a0a82318 100644 --- a/sp/src/game/server/ai_speech.h +++ b/sp/src/game/server/ai_speech.h @@ -185,7 +185,7 @@ public: float GetTimeSpeechComplete() const { return m_flStopTalkTime; } void BlockSpeechUntil( float time ); -#ifdef EZ2 +#ifdef MAPBASE float GetRealTimeSpeechComplete() const { return m_flStopTalkTimeWithoutDelay; } #endif From aac91b6487a7694a8b17ebd9c5fbda5572cacd6f Mon Sep 17 00:00:00 2001 From: samisalreadytaken <46823719+samisalreadytaken@users.noreply.github.com> Date: Wed, 19 Jan 2022 18:39:59 +0300 Subject: [PATCH 307/378] Set vscript integer param typemask to allow float --- sp/src/vscript/vscript_squirrel.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/sp/src/vscript/vscript_squirrel.cpp b/sp/src/vscript/vscript_squirrel.cpp index cd5fe6f6..101a5252 100644 --- a/sp/src/vscript/vscript_squirrel.cpp +++ b/sp/src/vscript/vscript_squirrel.cpp @@ -1091,7 +1091,8 @@ bool CreateParamCheck(const ScriptFunctionBinding_t& func, char* output) switch (func.m_desc.m_Parameters[i]) { case FIELD_FLOAT: - *output++ = 'n'; // NOTE: Can be int or float + case FIELD_INTEGER: + *output++ = 'n'; break; case FIELD_CSTRING: *output++ = 's'; @@ -1099,9 +1100,6 @@ bool CreateParamCheck(const ScriptFunctionBinding_t& func, char* output) case FIELD_VECTOR: *output++ = 'x'; // Generic instance, we validate on arrival break; - case FIELD_INTEGER: - *output++ = 'i'; // could use 'n' also which is int or float - break; case FIELD_BOOLEAN: *output++ = 'b'; break; From 439d3c75ab6cd6f9408526f35e233a1755bcf66c Mon Sep 17 00:00:00 2001 From: samisalreadytaken <46823719+samisalreadytaken@users.noreply.github.com> Date: Thu, 27 Jan 2022 00:22:00 +0300 Subject: [PATCH 308/378] Fix VM stack corruption --- sp/src/vscript/vscript_squirrel.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/sp/src/vscript/vscript_squirrel.cpp b/sp/src/vscript/vscript_squirrel.cpp index 101a5252..b8465419 100644 --- a/sp/src/vscript/vscript_squirrel.cpp +++ b/sp/src/vscript/vscript_squirrel.cpp @@ -1699,7 +1699,9 @@ struct SquirrelSafeCheck ~SquirrelSafeCheck() { - if (top_ != (sq_gettop(vm_) - outputCount_)) + SQInteger curtop = sq_gettop(vm_); + SQInteger diff = curtop - outputCount_; + if ( top_ != diff ) { Assert(!"Squirrel VM stack is not consistent"); Error("Squirrel VM stack is not consistent\n"); @@ -2352,6 +2354,8 @@ bool SquirrelVM::ScopeIsHooked( HSCRIPT hScope, const char *pszEventName ) if (!hScope) return true; + SquirrelSafeCheck safeCheck(vm_); + Assert(hScope != INVALID_HSCRIPT); sq_pushroottable(vm_); @@ -2371,7 +2375,7 @@ bool SquirrelVM::ScopeIsHooked( HSCRIPT hScope, const char *pszEventName ) return false; } - sq_pop(vm_, 3); + sq_pop(vm_, 4); return val ? true : false; } @@ -2391,6 +2395,8 @@ HSCRIPT SquirrelVM::LookupHookFunction(const char *pszEventName, HSCRIPT hScope, if (!ScopeIsHooked(hScope, pszEventName)) return nullptr; + SquirrelSafeCheck safeCheck(vm_); + sq_pushroottable(vm_); sq_pushstring(vm_, "Hooks", -1); sq_get(vm_, -2); @@ -2401,7 +2407,7 @@ HSCRIPT SquirrelVM::LookupHookFunction(const char *pszEventName, HSCRIPT hScope, sq_resetobject(&obj); sq_getstackobj(vm_, -1, &obj); sq_addref(vm_, &obj); - sq_pop(vm_, 2); + sq_pop(vm_, 3); HSQOBJECT* pObj = new HSQOBJECT; *pObj = obj; From 236a9a146862ad4885eb311330101007962119dd Mon Sep 17 00:00:00 2001 From: samisalreadytaken <46823719+samisalreadytaken@users.noreply.github.com> Date: Fri, 11 Feb 2022 20:10:00 +0300 Subject: [PATCH 309/378] Set no instanceid warning print level 1 --- sp/src/vscript/vscript_squirrel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sp/src/vscript/vscript_squirrel.cpp b/sp/src/vscript/vscript_squirrel.cpp index b8465419..15d8c1ff 100644 --- a/sp/src/vscript/vscript_squirrel.cpp +++ b/sp/src/vscript/vscript_squirrel.cpp @@ -3531,7 +3531,7 @@ void SquirrelVM::WriteObject(CUtlBuffer* pBuffer, WriteStateMap& writeState, SQI } else { - Warning("SquirrelVM::WriteObject: Unable to find instanceID for object of type %s, unable to serialize\n", + DevWarning("SquirrelVM::WriteObject: Unable to find instanceID for object of type %s, unable to serialize\n", pClassInstanceData->desc->m_pszClassname); pBuffer->PutString(""); } From 0afc503affcfed1399f97e65a7fbfac011656d6c Mon Sep 17 00:00:00 2001 From: samisalreadytaken <46823719+samisalreadytaken@users.noreply.github.com> Date: Sat, 12 Feb 2022 19:25:05 +0300 Subject: [PATCH 310/378] Add CSteamAPI::GetSteam2ID() --- .../shared/mapbase/vscript_singletons.cpp | 30 +++++++++++++++---- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/sp/src/game/shared/mapbase/vscript_singletons.cpp b/sp/src/game/shared/mapbase/vscript_singletons.cpp index 4b1a8344..535e1d1d 100644 --- a/sp/src/game/shared/mapbase/vscript_singletons.cpp +++ b/sp/src/game/shared/mapbase/vscript_singletons.cpp @@ -1264,6 +1264,7 @@ CNetMsgScriptHelper *g_ScriptNetMsg = &scriptnetmsg; #endif + void CNetMsgScriptHelper::WriteToBuffer( bf_write *bf ) { bf->WriteBits( m_MsgOut.GetData(), m_MsgOut.GetNumBitsWritten() ); @@ -1291,9 +1292,6 @@ void CNetMsgScriptHelper::InitPostVM() { ScriptVariant_t hHooks; g_pScriptVM->CreateTable( hHooks ); -#if _DEBUG - g_pScriptVM->SetValue( NULL, "__NetMsg_hooks", hHooks ); -#endif m_Hooks = (HSCRIPT)hHooks; } @@ -1416,9 +1414,13 @@ void CNetMsgScriptHelper::Send() void CNetMsgScriptHelper::Receive( const char *msg, HSCRIPT func ) { if ( func ) + { g_pScriptVM->SetValue( m_Hooks, int( HashStringCaseless(msg) ), func ); + } else + { g_pScriptVM->ClearValue( m_Hooks, int( HashStringCaseless(msg) ) ); + } } #ifdef GAME_DLL @@ -3017,6 +3019,23 @@ END_SCRIPTDESC(); class CScriptSteamAPI { public: + const char *GetSteam2ID() + { + if ( !steamapicontext || !steamapicontext->SteamUser() ) + return NULL; + + CSteamID id = steamapicontext->SteamUser()->GetSteamID(); + + uint32 accountID = id.GetAccountID(); + uint32 steamInstanceID = 0; + uint32 high32bits = accountID % 2; + uint32 low32bits = accountID / 2; + + static char ret[48]; + V_snprintf( ret, sizeof(ret), "STEAM_%u:%u:%u", steamInstanceID, high32bits, low32bits ); + return ret; + } + int GetSecondsSinceComputerActive() { if ( !steamapicontext || !steamapicontext->SteamUtils() ) @@ -3032,7 +3051,7 @@ public: return steamapicontext->SteamUtils()->GetCurrentBatteryPower(); } - +#if 0 const char *GetIPCountry() { if ( !steamapicontext || !steamapicontext->SteamUtils() ) @@ -3047,7 +3066,7 @@ public: return ret; } - +#endif const char *GetCurrentGameLanguage() { if ( !steamapicontext || !steamapicontext->SteamApps() ) @@ -3066,6 +3085,7 @@ public: } g_ScriptSteamAPI; BEGIN_SCRIPTDESC_ROOT_NAMED( CScriptSteamAPI, "CSteamAPI", SCRIPT_SINGLETON "" ) + DEFINE_SCRIPTFUNC( GetSteam2ID, "" ) //DEFINE_SCRIPTFUNC( IsVACBanned, "" ) DEFINE_SCRIPTFUNC( GetSecondsSinceComputerActive, "Returns the number of seconds since the user last moved the mouse." ) DEFINE_SCRIPTFUNC( GetCurrentBatteryPower, "Return the amount of battery power left in the current system in % [0..100], 255 for being on AC power" ) From 0ae9c8bc8eb62307006611d21f55682dbaef6abc Mon Sep 17 00:00:00 2001 From: samisalreadytaken <46823719+samisalreadytaken@users.noreply.github.com> Date: Sat, 12 Feb 2022 19:30:00 +0300 Subject: [PATCH 311/378] Debug print script NetMsg names --- .../shared/mapbase/vscript_singletons.cpp | 64 +++++++++++++++++-- 1 file changed, 59 insertions(+), 5 deletions(-) diff --git a/sp/src/game/shared/mapbase/vscript_singletons.cpp b/sp/src/game/shared/mapbase/vscript_singletons.cpp index 535e1d1d..bf28a31b 100644 --- a/sp/src/game/shared/mapbase/vscript_singletons.cpp +++ b/sp/src/game/shared/mapbase/vscript_singletons.cpp @@ -1264,6 +1264,51 @@ CNetMsgScriptHelper *g_ScriptNetMsg = &scriptnetmsg; #endif +// Keep track of message names to print on failure +#ifdef _DEBUG +struct NetMsgHook_t +{ + void Set( const char *s ) + { + hash = (int)HashStringCaseless( s ); + name = strdup(s); + } + + ~NetMsgHook_t() + { + free( name ); + } + + int hash; + char *name; +}; + +CUtlVector< NetMsgHook_t > g_NetMsgHooks; + +static const char *GetNetMsgName( int hash ) +{ + FOR_EACH_VEC( g_NetMsgHooks, i ) + { + if ( g_NetMsgHooks[i].hash == hash ) + return g_NetMsgHooks[i].name; + } + return 0; +} + +static const char *HasNetMsgCollision( int hash, const char *ignore ) +{ + FOR_EACH_VEC( g_NetMsgHooks, i ) + { + if ( g_NetMsgHooks[i].hash == hash && V_strcmp( g_NetMsgHooks[i].name, ignore ) != 0 ) + { + return g_NetMsgHooks[i].name; + } + } + return 0; +} +#endif // _DEBUG + + void CNetMsgScriptHelper::WriteToBuffer( bf_write *bf ) { @@ -1303,6 +1348,10 @@ void CNetMsgScriptHelper::LevelShutdownPreVM() g_pScriptVM->ReleaseScript( m_Hooks ); } m_Hooks = NULL; + +#ifdef _DEBUG + g_NetMsgHooks.Purge(); +#endif } #ifdef CLIENT_DLL @@ -1354,13 +1403,17 @@ void CNetMsgScriptHelper::ReceiveMessage( bf_read &msg ) if ( g_pScriptVM->ExecuteFunction( hfn, NULL, 0, NULL, NULL, true ) == SCRIPT_ERROR ) #endif { - DevWarning( 2, DLL_LOC_STR " NetMsg: invalid callback [%d]\n", hash ); +#ifdef _DEBUG + DevWarning( 1, DLL_LOC_STR " NetMsg: invalid callback '%s'\n", GetNetMsgName( hash ) ); +#else + DevWarning( 1, DLL_LOC_STR " NetMsg: invalid callback [%d]\n", hash ); +#endif } g_pScriptVM->ReleaseValue( hfn ); } else { - DevWarning( 2, DLL_LOC_STR " NetMsg hook not found [%d]\n", hash ); + DevWarning( 1, DLL_LOC_STR " NetMsg hook not found [%d]\n", hash ); } } @@ -1415,6 +1468,10 @@ void CNetMsgScriptHelper::Receive( const char *msg, HSCRIPT func ) { if ( func ) { +#ifdef _DEBUG + NetMsgHook_t &hook = g_NetMsgHooks[ g_NetMsgHooks.AddToTail() ]; + hook.Set( msg ); +#endif g_pScriptVM->SetValue( m_Hooks, int( HashStringCaseless(msg) ), func ); } else @@ -1675,7 +1732,6 @@ float CNetMsgScriptHelper::ReadCoord() const Vector& CNetMsgScriptHelper::ReadVec3Coord() { static Vector vec3; - //vec3.Init(); m_MsgIn_()ReadBitVec3Coord(vec3); return vec3; } @@ -1683,7 +1739,6 @@ const Vector& CNetMsgScriptHelper::ReadVec3Coord() const Vector& CNetMsgScriptHelper::ReadVec3Normal() { static Vector vec3; - //vec3.Init(); m_MsgIn_()ReadBitVec3Normal(vec3); return vec3; } @@ -1691,7 +1746,6 @@ const Vector& CNetMsgScriptHelper::ReadVec3Normal() const QAngle& CNetMsgScriptHelper::ReadAngles() { static QAngle vec3; - //vec3.Init(); m_MsgIn_()ReadBitAngles(vec3); return vec3; } From 4b8f386c94500b90e79848fbfb50beed7a7592b1 Mon Sep 17 00:00:00 2001 From: samisalreadytaken <46823719+samisalreadytaken@users.noreply.github.com> Date: Sat, 12 Feb 2022 19:35:00 +0300 Subject: [PATCH 312/378] Clientside vscript additions: Added C_BaseCombatCharacter script desc Added boundary checks for script funcs --- sp/src/game/client/c_basecombatcharacter.cpp | 36 ++++++++++++ sp/src/game/client/c_basecombatcharacter.h | 9 +++ sp/src/game/server/basecombatcharacter.cpp | 37 +++++++----- sp/src/game/server/basecombatcharacter.h | 10 ++-- .../game/shared/basecombatweapon_shared.cpp | 56 ++++++++++++------- 5 files changed, 110 insertions(+), 38 deletions(-) diff --git a/sp/src/game/client/c_basecombatcharacter.cpp b/sp/src/game/client/c_basecombatcharacter.cpp index fee63118..1656f567 100644 --- a/sp/src/game/client/c_basecombatcharacter.cpp +++ b/sp/src/game/client/c_basecombatcharacter.cpp @@ -178,3 +178,39 @@ BEGIN_PREDICTION_DATA( C_BaseCombatCharacter ) DEFINE_PRED_ARRAY( m_hMyWeapons, FIELD_EHANDLE, MAX_WEAPONS, FTYPEDESC_INSENDTABLE ), END_PREDICTION_DATA() + +#ifdef MAPBASE_VSCRIPT + +BEGIN_ENT_SCRIPTDESC( C_BaseCombatCharacter, CBaseEntity, "" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptGetAmmoCount, "GetAmmoCount", "" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptGetActiveWeapon, "GetActiveWeapon", "" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptGetWeapon, "GetWeapon", "" ) +END_SCRIPTDESC(); + + +int C_BaseCombatCharacter::ScriptGetAmmoCount( int i ) +{ + Assert( i == -1 || i < MAX_AMMO_SLOTS ); + + if ( i < 0 || i >= MAX_AMMO_SLOTS ) + return NULL; + + return GetAmmoCount( i ); +} + +HSCRIPT C_BaseCombatCharacter::ScriptGetActiveWeapon() +{ + return ToHScript( GetActiveWeapon() ); +} + +HSCRIPT C_BaseCombatCharacter::ScriptGetWeapon( int i ) +{ + Assert( i >= 0 && i < MAX_WEAPONS ); + + if ( i < 0 || i >= MAX_WEAPONS ) + return NULL; + + return ToHScript( GetWeapon(i) ); +} + +#endif diff --git a/sp/src/game/client/c_basecombatcharacter.h b/sp/src/game/client/c_basecombatcharacter.h index 1d84e4ce..f580fe46 100644 --- a/sp/src/game/client/c_basecombatcharacter.h +++ b/sp/src/game/client/c_basecombatcharacter.h @@ -29,6 +29,9 @@ class C_BaseCombatCharacter : public C_BaseFlex public: DECLARE_CLIENTCLASS(); DECLARE_PREDICTABLE(); +#ifdef MAPBASE_VSCRIPT + DECLARE_ENT_SCRIPTDESC(); +#endif C_BaseCombatCharacter( void ); virtual ~C_BaseCombatCharacter( void ); @@ -99,6 +102,12 @@ public: virtual void GetGlowEffectColor( float *r, float *g, float *b ); #endif // GLOWS_ENABLE +#ifdef MAPBASE_VSCRIPT + int ScriptGetAmmoCount( int i ); + HSCRIPT ScriptGetActiveWeapon(); + HSCRIPT ScriptGetWeapon( int i ); +#endif + public: float m_flNextAttack; diff --git a/sp/src/game/server/basecombatcharacter.cpp b/sp/src/game/server/basecombatcharacter.cpp index c11eb9fa..53c2802a 100644 --- a/sp/src/game/server/basecombatcharacter.cpp +++ b/sp/src/game/server/basecombatcharacter.cpp @@ -151,11 +151,11 @@ 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." ) + DEFINE_SCRIPTFUNC_NAMED( ScriptGetActiveWeapon, "GetActiveWeapon", "Get the character's active weapon entity." ) DEFINE_SCRIPTFUNC( WeaponCount, "Get the number of weapons a character possesses." ) - DEFINE_SCRIPTFUNC_NAMED( GetScriptWeaponIndex, "GetWeapon", "Get a specific weapon in the character's inventory." ) - DEFINE_SCRIPTFUNC_NAMED( GetScriptWeaponByType, "FindWeapon", "Find a specific weapon in the character's inventory by its classname." ) - DEFINE_SCRIPTFUNC_NAMED( GetScriptAllWeapons, "GetAllWeapons", "Get the character's weapon inventory." ) + DEFINE_SCRIPTFUNC_NAMED( ScriptGetWeapon, "GetWeapon", "Get a specific weapon in the character's inventory." ) + DEFINE_SCRIPTFUNC_NAMED( ScriptGetWeaponByType, "FindWeapon", "Find a specific weapon in the character's inventory by its classname." ) + DEFINE_SCRIPTFUNC_NAMED( ScriptGetAllWeapons, "GetAllWeapons", "Get the character's weapon inventory." ) DEFINE_SCRIPTFUNC_NAMED( ScriptGetCurrentWeaponProficiency, "GetCurrentWeaponProficiency", "Get the character's current proficiency (accuracy) with their current weapon." ) DEFINE_SCRIPTFUNC_NAMED( Weapon_ShootPosition, "ShootPosition", "Get the character's shoot position." ) @@ -174,7 +174,7 @@ BEGIN_ENT_SCRIPTDESC( CBaseCombatCharacter, CBaseFlex, "The base class shared by DEFINE_SCRIPTFUNC_NAMED( ScriptRelationPriority, "GetRelationPriority", "Get a character's relationship priority for a specific entity." ) DEFINE_SCRIPTFUNC_NAMED( ScriptSetRelationship, "SetRelationship", "Set a character's relationship with a specific entity." ) - DEFINE_SCRIPTFUNC_NAMED( GetScriptVehicleEntity, "GetVehicleEntity", "Get the entity for a character's current vehicle if they're in one." ) + DEFINE_SCRIPTFUNC_NAMED( ScriptGetVehicleEntity, "GetVehicleEntity", "Get the entity for a character's current vehicle if they're in one." ) DEFINE_SCRIPTFUNC_NAMED( ScriptInViewCone, "InViewCone", "Check if the specified position is in the character's viewcone." ) DEFINE_SCRIPTFUNC_NAMED( ScriptEntInViewCone, "EntInViewCone", "Check if the specified entity is in the character's viewcone." ) @@ -4430,28 +4430,33 @@ void CBaseCombatCharacter::DoMuzzleFlash() #ifdef MAPBASE_VSCRIPT //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- -HSCRIPT CBaseCombatCharacter::GetScriptActiveWeapon() +HSCRIPT CBaseCombatCharacter::ScriptGetActiveWeapon() { return ToHScript( GetActiveWeapon() ); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- -HSCRIPT CBaseCombatCharacter::GetScriptWeaponIndex( int i ) +HSCRIPT CBaseCombatCharacter::ScriptGetWeapon( int i ) { + Assert( i >= 0 && i < MAX_WEAPONS ); + + if ( i < 0 || i >= MAX_WEAPONS ) + return NULL; + return ToHScript( GetWeapon( i ) ); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- -HSCRIPT CBaseCombatCharacter::GetScriptWeaponByType( const char *pszWeapon, int iSubType ) +HSCRIPT CBaseCombatCharacter::ScriptGetWeaponByType( const char *pszWeapon, int iSubType ) { return ToHScript( Weapon_OwnsThisType( pszWeapon, iSubType ) ); } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- -void CBaseCombatCharacter::GetScriptAllWeapons( HSCRIPT hTable ) +void CBaseCombatCharacter::ScriptGetAllWeapons( HSCRIPT hTable ) { for (int i=0;i= MAX_AMMO_SLOTS ) + return 0; + return GetAmmoCount( iType ); } @@ -4527,11 +4537,10 @@ int CBaseCombatCharacter::ScriptGetAmmoCount( int iType ) const //----------------------------------------------------------------------------- void CBaseCombatCharacter::ScriptSetAmmoCount( int iType, int iCount ) { - if (iType == -1) - { - Warning("%i is not a valid ammo type\n", iType); + Assert( iType == -1 || iType < MAX_AMMO_SLOTS ); + + if ( iType < 0 || iType >= MAX_AMMO_SLOTS ) return; - } return SetAmmoCount( iCount, iType ); } @@ -4590,7 +4599,7 @@ void CBaseCombatCharacter::ScriptSetRelationship( HSCRIPT pTarget, int dispositi //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- -HSCRIPT CBaseCombatCharacter::GetScriptVehicleEntity() +HSCRIPT CBaseCombatCharacter::ScriptGetVehicleEntity() { return ToHScript( GetVehicleEntity() ); } diff --git a/sp/src/game/server/basecombatcharacter.h b/sp/src/game/server/basecombatcharacter.h index ccdd16c8..b9bb7481 100644 --- a/sp/src/game/server/basecombatcharacter.h +++ b/sp/src/game/server/basecombatcharacter.h @@ -420,10 +420,10 @@ public: virtual void DoMuzzleFlash(); #ifdef MAPBASE_VSCRIPT - HSCRIPT GetScriptActiveWeapon(); - HSCRIPT GetScriptWeaponIndex( int i ); - HSCRIPT GetScriptWeaponByType( const char *pszWeapon, int iSubType = 0 ); - void GetScriptAllWeapons( HSCRIPT hTable ); + HSCRIPT ScriptGetActiveWeapon(); + HSCRIPT ScriptGetWeapon( int i ); + HSCRIPT ScriptGetWeaponByType( const char *pszWeapon, int iSubType = 0 ); + void ScriptGetAllWeapons( HSCRIPT hTable ); int ScriptGetCurrentWeaponProficiency() { return GetCurrentWeaponProficiency(); } void ScriptDropWeapon( HSCRIPT hWeapon ); @@ -439,7 +439,7 @@ public: int ScriptRelationPriority( HSCRIPT pTarget ); void ScriptSetRelationship( HSCRIPT pTarget, int disposition, int priority ); - HSCRIPT GetScriptVehicleEntity(); + HSCRIPT ScriptGetVehicleEntity(); bool ScriptInViewCone( const Vector &vecSpot ) { return FInViewCone( vecSpot ); } bool ScriptEntInViewCone( HSCRIPT pEntity ) { return FInViewCone( ToEnt( pEntity ) ); } diff --git a/sp/src/game/shared/basecombatweapon_shared.cpp b/sp/src/game/shared/basecombatweapon_shared.cpp index c95a0189..e4adfc62 100644 --- a/sp/src/game/shared/basecombatweapon_shared.cpp +++ b/sp/src/game/shared/basecombatweapon_shared.cpp @@ -2949,15 +2949,33 @@ END_PREDICTION_DATA() IMPLEMENT_NETWORKCLASS_ALIASED( BaseCombatWeapon, DT_BaseCombatWeapon ) #ifdef MAPBASE_VSCRIPT + +// Don't allow client to use Set functions. +// They will only cause visual discrepancies, +// and will be reverted on the next update from the server. +#ifdef GAME_DLL +#define DEFINE_SCRIPTFUNC_SV( p1, p2 ) DEFINE_SCRIPTFUNC( p1, p2 ) +#define DEFINE_SCRIPTFUNC_NAMED_SV( p1, p2, p3 ) DEFINE_SCRIPTFUNC_NAMED( p1, p2, p3 ) + +#define DEFINE_SCRIPTFUNC_CL( p1, p2 ) +#define DEFINE_SCRIPTFUNC_NAMED_CL( p1, p2, p3 ) +#else +#define DEFINE_SCRIPTFUNC_SV( p1, p2 ) +#define DEFINE_SCRIPTFUNC_NAMED_SV( p1, p2, p3 ) + +#define DEFINE_SCRIPTFUNC_CL( p1, p2 ) DEFINE_SCRIPTFUNC( p1, p2 ) +#define DEFINE_SCRIPTFUNC_NAMED_CL( p1, p2, p3 ) DEFINE_SCRIPTFUNC_NAMED( p1, p2, p3 ) +#endif + BEGIN_ENT_SCRIPTDESC( CBaseCombatWeapon, CBaseAnimating, "The base class for all equippable weapons." ) DEFINE_SCRIPTFUNC_NAMED( ScriptGetOwner, "GetOwner", "Get the weapon's owner." ) - DEFINE_SCRIPTFUNC_NAMED( ScriptSetOwner, "SetOwner", "Set the weapon's owner." ) + DEFINE_SCRIPTFUNC_NAMED_SV( ScriptSetOwner, "SetOwner", "Set the weapon's owner." ) DEFINE_SCRIPTFUNC( Clip1, "Get the weapon's current primary ammo." ) DEFINE_SCRIPTFUNC( Clip2, "Get the weapon's current secondary ammo." ) - DEFINE_SCRIPTFUNC_NAMED( ScriptSetClip1, "SetClip1", "Set the weapon's current primary ammo." ) - DEFINE_SCRIPTFUNC_NAMED( ScriptSetClip2, "SetClip2", "Set the weapon's current secondary ammo." ) + DEFINE_SCRIPTFUNC_NAMED_SV( ScriptSetClip1, "SetClip1", "Set the weapon's current primary ammo." ) + DEFINE_SCRIPTFUNC_NAMED_SV( ScriptSetClip2, "SetClip2", "Set the weapon's current secondary ammo." ) DEFINE_SCRIPTFUNC( GetMaxClip1, "Get the weapon's maximum primary ammo." ) DEFINE_SCRIPTFUNC( GetMaxClip2, "Get the weapon's maximum secondary ammo." ) DEFINE_SCRIPTFUNC( GetDefaultClip1, "Get the weapon's default primary ammo." ) @@ -2968,18 +2986,16 @@ BEGIN_ENT_SCRIPTDESC( CBaseCombatWeapon, CBaseAnimating, "The base class for all DEFINE_SCRIPTFUNC( HasSecondaryAmmo, "Check if the weapon currently has ammo or doesn't need secondary ammo." ) DEFINE_SCRIPTFUNC( UsesPrimaryAmmo, "Check if the weapon uses primary ammo." ) DEFINE_SCRIPTFUNC( UsesSecondaryAmmo, "Check if the weapon uses secondary ammo." ) - DEFINE_SCRIPTFUNC( GiveDefaultAmmo, "Fill the weapon back up to default ammo." ) + DEFINE_SCRIPTFUNC_SV( GiveDefaultAmmo, "Fill the weapon back up to default ammo." ) DEFINE_SCRIPTFUNC( UsesClipsForAmmo1, "Check if the weapon uses clips for primary ammo." ) DEFINE_SCRIPTFUNC( UsesClipsForAmmo2, "Check if the weapon uses clips for secondary ammo." ) -#ifndef CLIENT_DLL DEFINE_SCRIPTFUNC( GetPrimaryAmmoType, "Get the weapon's primary ammo type." ) DEFINE_SCRIPTFUNC( GetSecondaryAmmoType, "Get the weapon's secondary ammo type." ) -#endif DEFINE_SCRIPTFUNC( GetSubType, "Get the weapon's subtype." ) - DEFINE_SCRIPTFUNC( SetSubType, "Set the weapon's subtype." ) + DEFINE_SCRIPTFUNC_SV( SetSubType, "Set the weapon's subtype." ) DEFINE_SCRIPTFUNC( GetFireRate, "Get the weapon's firing rate." ) DEFINE_SCRIPTFUNC( AddViewKick, "Applies the weapon's view kick." ) @@ -2988,16 +3004,18 @@ BEGIN_ENT_SCRIPTDESC( CBaseCombatWeapon, CBaseAnimating, "The base class for all DEFINE_SCRIPTFUNC( GetViewModel, "Get the weapon's view model." ) DEFINE_SCRIPTFUNC( GetWeight, "Get the weapon's weight." ) + DEFINE_SCRIPTFUNC( GetPrintName, "" ) + + DEFINE_SCRIPTFUNC_CL( GetSlot, "" ) + DEFINE_SCRIPTFUNC_CL( GetPosition, "" ) DEFINE_SCRIPTFUNC( CanBePickedUpByNPCs, "Check if the weapon can be picked up by NPCs." ) -#ifndef CLIENT_DLL - DEFINE_SCRIPTFUNC( CapabilitiesGet, "Get the capabilities the weapon currently possesses." ) -#endif + DEFINE_SCRIPTFUNC_SV( CapabilitiesGet, "Get the capabilities the weapon currently possesses." ) DEFINE_SCRIPTFUNC( HasWeaponIdleTimeElapsed, "Returns true if the idle time has elapsed." ) DEFINE_SCRIPTFUNC( GetWeaponIdleTime, "Returns the next time WeaponIdle() will run." ) - DEFINE_SCRIPTFUNC( SetWeaponIdleTime, "Sets the next time WeaponIdle() will run." ) + DEFINE_SCRIPTFUNC_SV( SetWeaponIdleTime, "Sets the next time WeaponIdle() will run." ) DEFINE_SCRIPTFUNC_NAMED( ScriptWeaponClassify, "WeaponClassify", "Returns the weapon's classify class from the WEPCLASS_ constant group" ) DEFINE_SCRIPTFUNC_NAMED( ScriptWeaponSound, "WeaponSound", "Plays one of the weapon's sounds." ) @@ -3014,22 +3032,22 @@ BEGIN_ENT_SCRIPTDESC( CBaseCombatWeapon, CBaseAnimating, "The base class for all DEFINE_SCRIPTFUNC( IsViewModelSequenceFinished, "Returns true if the current view model animation is finished." ) DEFINE_SCRIPTFUNC( FiresUnderwater, "Returns true if this weapon can fire underwater." ) - DEFINE_SCRIPTFUNC( SetFiresUnderwater, "Sets whether this weapon can fire underwater." ) + DEFINE_SCRIPTFUNC_SV( SetFiresUnderwater, "Sets whether this weapon can fire underwater." ) DEFINE_SCRIPTFUNC( AltFiresUnderwater, "Returns true if this weapon can alt-fire underwater." ) - DEFINE_SCRIPTFUNC( SetAltFiresUnderwater, "Sets whether this weapon can alt-fire underwater." ) + DEFINE_SCRIPTFUNC_SV( SetAltFiresUnderwater, "Sets whether this weapon can alt-fire underwater." ) DEFINE_SCRIPTFUNC( MinRange1, "Returns the closest this weapon can be used." ) - DEFINE_SCRIPTFUNC( SetMinRange1, "Sets the closest this weapon can be used." ) + DEFINE_SCRIPTFUNC_SV( SetMinRange1, "Sets the closest this weapon can be used." ) DEFINE_SCRIPTFUNC( MinRange2, "Returns the closest this weapon can be used." ) - DEFINE_SCRIPTFUNC( SetMinRange2, "Sets the closest this weapon can be used." ) + DEFINE_SCRIPTFUNC_SV( SetMinRange2, "Sets the closest this weapon can be used." ) DEFINE_SCRIPTFUNC( ReloadsSingly, "Returns true if this weapon reloads 1 round at a time." ) - DEFINE_SCRIPTFUNC( SetReloadsSingly, "Sets whether this weapon reloads 1 round at a time." ) + DEFINE_SCRIPTFUNC_SV( SetReloadsSingly, "Sets whether this weapon reloads 1 round at a time." ) DEFINE_SCRIPTFUNC( FireDuration, "Returns the amount of time that the weapon has sustained firing." ) - DEFINE_SCRIPTFUNC( SetFireDuration, "Sets the amount of time that the weapon has sustained firing." ) + DEFINE_SCRIPTFUNC_SV( SetFireDuration, "Sets the amount of time that the weapon has sustained firing." ) DEFINE_SCRIPTFUNC( NextPrimaryAttack, "Returns the next time PrimaryAttack() will run when the player is pressing +ATTACK." ) - DEFINE_SCRIPTFUNC( SetNextPrimaryAttack, "Sets the next time PrimaryAttack() will run when the player is pressing +ATTACK." ) + DEFINE_SCRIPTFUNC_SV( SetNextPrimaryAttack, "Sets the next time PrimaryAttack() will run when the player is pressing +ATTACK." ) DEFINE_SCRIPTFUNC( NextSecondaryAttack, "Returns the next time SecondaryAttack() will run when the player is pressing +ATTACK2." ) - DEFINE_SCRIPTFUNC( SetNextSecondaryAttack, "Sets the next time SecondaryAttack() will run when the player is pressing +ATTACK2." ) + DEFINE_SCRIPTFUNC_SV( SetNextSecondaryAttack, "Sets the next time SecondaryAttack() will run when the player is pressing +ATTACK2." ) END_SCRIPTDESC(); #endif From 6d3c53fe0f84ca971f7bcd950e6979828e09f40e Mon Sep 17 00:00:00 2001 From: samisalreadytaken <46823719+samisalreadytaken@users.noreply.github.com> Date: Fri, 18 Feb 2022 17:00:00 +0300 Subject: [PATCH 313/378] Fix writing multiple messages on client script NetMsg --- .../shared/mapbase/vscript_singletons.cpp | 200 ++++++++++++++---- .../game/shared/mapbase/vscript_singletons.h | 29 ++- 2 files changed, 185 insertions(+), 44 deletions(-) diff --git a/sp/src/game/shared/mapbase/vscript_singletons.cpp b/sp/src/game/shared/mapbase/vscript_singletons.cpp index bf28a31b..f1b72c1d 100644 --- a/sp/src/game/shared/mapbase/vscript_singletons.cpp +++ b/sp/src/game/shared/mapbase/vscript_singletons.cpp @@ -1263,6 +1263,24 @@ CNetMsgScriptHelper *g_ScriptNetMsg = &scriptnetmsg; #define DLL_LOC_STR "[Client]" #endif +#ifdef GAME_DLL +#define SCRIPT_NETMSG_WRITE_FUNC +#else +#define SCRIPT_NETMSG_WRITE_FUNC if ( m_bWriteIgnore ) { return; } +#endif + +#ifdef _DEBUG +#ifdef GAME_DLL +#define DebugNetMsg( l, ... ) do { extern ConVar developer; if (developer.GetInt() >= l) ConColorMsg( Color(100, 225, 255, 255), __VA_ARGS__ ); } while (0); +#else +#define DebugNetMsg( l, ... ) do { extern ConVar developer; if (developer.GetInt() >= l) ConColorMsg( Color(100, 225, 175, 255), __VA_ARGS__ ); } while (0); +#endif +#define DebugWarning(...) Warning( __VA_ARGS__ ) +#else +#define DebugNetMsg(...) (void)(0) +#define DebugWarning(...) (void)(0) +#endif + // Keep track of message names to print on failure #ifdef _DEBUG @@ -1270,7 +1288,7 @@ struct NetMsgHook_t { void Set( const char *s ) { - hash = (int)HashStringCaseless( s ); + hash = CNetMsgScriptHelper::Hash( s ); name = strdup(s); } @@ -1310,8 +1328,23 @@ static const char *HasNetMsgCollision( int hash, const char *ignore ) +inline int CNetMsgScriptHelper::Hash( const char *key ) +{ + int hash = HashStringCaseless( key ); + Assert( hash < (1 << SCRIPT_NETMSG_HEADER_BITS) ); + return hash; +} + void CNetMsgScriptHelper::WriteToBuffer( bf_write *bf ) { +#ifdef CLIENT_DLL + Assert( m_nQueueCount < ( 1 << SCRIPT_NETMSG_QUEUE_BITS ) ); + bf->WriteUBitLong( m_nQueueCount, SCRIPT_NETMSG_QUEUE_BITS ); + + DebugNetMsg( 2, DLL_LOC_STR " CNetMsgScriptHelper::WriteToBuffer() count(%d) size(%d)\n", + m_nQueueCount, m_MsgOut.GetNumBitsWritten() + SCRIPT_NETMSG_QUEUE_BITS ); +#endif + bf->WriteBits( m_MsgOut.GetData(), m_MsgOut.GetNumBitsWritten() ); } @@ -1324,8 +1357,7 @@ void CNetMsgScriptHelper::Reset() #ifdef GAME_DLL m_filter.Reset(); #else - m_MsgIn_()Reset(); - m_bWriteReady = false; + m_iLastBit = 0; #endif } @@ -1344,11 +1376,16 @@ void CNetMsgScriptHelper::LevelShutdownPreVM() { Reset(); if ( m_Hooks ) - { g_pScriptVM->ReleaseScript( m_Hooks ); - } m_Hooks = NULL; +#ifdef CLIENT_DLL + m_bWriteReady = m_bWriteIgnore = false; + m_MsgIn.Reset(); +#else + m_MsgIn = NULL; +#endif + #ifdef _DEBUG g_NetMsgHooks.Purge(); #endif @@ -1385,7 +1422,7 @@ void CNetMsgScriptHelper::ReceiveMessage( bf_read &msg ) m_MsgIn.StartReading( msg.m_pData, msg.m_nDataBytes ); #endif - word hash = m_MsgIn_()ReadWord(); + DebugNetMsg( 2, DLL_LOC_STR " " __FUNCTION__ "()\n" ); // Don't do anything if there's no VM here. This can happen if a message from the server goes to a VM-less client, or vice versa. if ( !g_pScriptVM ) @@ -1394,26 +1431,42 @@ void CNetMsgScriptHelper::ReceiveMessage( bf_read &msg ) return; } - ScriptVariant_t hfn; - if ( g_pScriptVM->GetValue( m_Hooks, hash, &hfn ) ) - { #ifdef GAME_DLL - if ( g_pScriptVM->Call( hfn, NULL, true, NULL, pPlayer->m_hScriptInstance ) == SCRIPT_ERROR ) -#else - if ( g_pScriptVM->ExecuteFunction( hfn, NULL, 0, NULL, NULL, true ) == SCRIPT_ERROR ) + int count = m_MsgIn_()ReadUBitLong( SCRIPT_NETMSG_QUEUE_BITS ); + DebugNetMsg( 2, " msg count %d\n", count ); + while ( count-- ) #endif - { -#ifdef _DEBUG - DevWarning( 1, DLL_LOC_STR " NetMsg: invalid callback '%s'\n", GetNetMsgName( hash ) ); -#else - DevWarning( 1, DLL_LOC_STR " NetMsg: invalid callback [%d]\n", hash ); -#endif - } - g_pScriptVM->ReleaseValue( hfn ); - } - else { - DevWarning( 1, DLL_LOC_STR " NetMsg hook not found [%d]\n", hash ); + int hash = m_MsgIn_()ReadWord(); + +#ifdef _DEBUG + const char *msgName = GetNetMsgName( hash ); + DebugNetMsg( 2, " -- begin msg [%d]%s\n", hash, msgName ); +#endif + + ScriptVariant_t hfn; + if ( g_pScriptVM->GetValue( m_Hooks, hash, &hfn ) ) + { +#ifdef GAME_DLL + if ( g_pScriptVM->Call( hfn, NULL, true, NULL, pPlayer->m_hScriptInstance ) == SCRIPT_ERROR ) +#else + if ( g_pScriptVM->ExecuteFunction( hfn, NULL, 0, NULL, NULL, true ) == SCRIPT_ERROR ) +#endif + { +#ifdef _DEBUG + DevWarning( 1, DLL_LOC_STR " NetMsg: invalid callback '%s'\n", GetNetMsgName( hash ) ); +#else + DevWarning( 1, DLL_LOC_STR " NetMsg: invalid callback [%d]\n", hash ); +#endif + } + g_pScriptVM->ReleaseValue( hfn ); + } + else + { + DevWarning( 1, DLL_LOC_STR " NetMsg hook not found [%d]\n", hash ); + } + + DebugNetMsg( 2, " -- end msg\n" ); } } @@ -1422,18 +1475,50 @@ void CNetMsgScriptHelper::ReceiveMessage( bf_read &msg ) //----------------------------------------------------------------------------- void CNetMsgScriptHelper::Start( const char *msg ) { + if ( !msg || !msg[0] ) + { + g_pScriptVM->RaiseException( DLL_LOC_STR "NetMsg: invalid message name" ); + return; + } + + DebugNetMsg( 1, DLL_LOC_STR " " __FUNCTION__ "() [%d]%s\n", Hash( msg ), msg ); + +#ifdef CLIENT_DLL + // Client can write multiple messages in a frame before the usercmd is sent, + // this queue system ensures client messages are written to the cmd all at once. + // NOTE: All messages share the same buffer. + if ( !m_bWriteReady ) + { + Reset(); + m_nQueueCount = 0; + m_bWriteIgnore = false; + } + else if ( m_nQueueCount == ((1< client // // Sends an exclusive usermessage. //----------------------------------------------------------------------------- -#ifdef GAME_DLL void CNetMsgScriptHelper::Send( HSCRIPT player, bool bReliable ) { + DebugNetMsg( 1, DLL_LOC_STR " " __FUNCTION__ "() size(%d)\n", GetNumBitsWritten() ); + CBaseEntity *pPlayer = ToEnt(player); if ( pPlayer ) { @@ -1457,6 +1542,8 @@ void CNetMsgScriptHelper::Send( HSCRIPT player, bool bReliable ) //----------------------------------------------------------------------------- void CNetMsgScriptHelper::Send() { + DebugNetMsg( 1, DLL_LOC_STR " " __FUNCTION__ "() size(%d)\n", m_bWriteIgnore ? 0 : GetNumBitsWritten() ); + m_bWriteReady = true; } #endif @@ -1466,17 +1553,29 @@ void CNetMsgScriptHelper::Send() //----------------------------------------------------------------------------- void CNetMsgScriptHelper::Receive( const char *msg, HSCRIPT func ) { + if ( !msg || !msg[0] ) + { + g_pScriptVM->RaiseException( DLL_LOC_STR "NetMsg: invalid message name" ); + return; + } + +#ifdef _DEBUG + int hash = Hash( msg ); + + const char *psz = HasNetMsgCollision( hash, msg ); + AssertMsg3( !psz, DLL_LOC_STR " NetMsg hash collision! [%d] '%s', '%s'\n", hash, msg, psz ); + + NetMsgHook_t &hook = g_NetMsgHooks[ g_NetMsgHooks.AddToTail() ]; + hook.Set( msg ); +#endif + if ( func ) { -#ifdef _DEBUG - NetMsgHook_t &hook = g_NetMsgHooks[ g_NetMsgHooks.AddToTail() ]; - hook.Set( msg ); -#endif - g_pScriptVM->SetValue( m_Hooks, int( HashStringCaseless(msg) ), func ); + g_pScriptVM->SetValue( m_Hooks, Hash( msg ), func ); } else { - g_pScriptVM->ClearValue( m_Hooks, int( HashStringCaseless(msg) ) ); + g_pScriptVM->ClearValue( m_Hooks, Hash( msg ) ); } } @@ -1572,86 +1671,107 @@ void CNetMsgScriptHelper::AddAllPlayers() void CNetMsgScriptHelper::WriteInt( int iValue, int bits ) { + SCRIPT_NETMSG_WRITE_FUNC m_MsgOut.WriteSBitLong( iValue, bits ); } void CNetMsgScriptHelper::WriteUInt( int iValue, int bits ) { + SCRIPT_NETMSG_WRITE_FUNC m_MsgOut.WriteUBitLong( iValue, bits ); } void CNetMsgScriptHelper::WriteByte( int iValue ) { + SCRIPT_NETMSG_WRITE_FUNC m_MsgOut.WriteByte( iValue ); } void CNetMsgScriptHelper::WriteChar( int iValue ) { + SCRIPT_NETMSG_WRITE_FUNC m_MsgOut.WriteChar( iValue ); } void CNetMsgScriptHelper::WriteShort( int iValue ) { + SCRIPT_NETMSG_WRITE_FUNC m_MsgOut.WriteShort( iValue ); } void CNetMsgScriptHelper::WriteWord( int iValue ) { + SCRIPT_NETMSG_WRITE_FUNC m_MsgOut.WriteWord( iValue ); } void CNetMsgScriptHelper::WriteLong( int iValue ) { + SCRIPT_NETMSG_WRITE_FUNC m_MsgOut.WriteLong( iValue ); } void CNetMsgScriptHelper::WriteFloat( float flValue ) { + SCRIPT_NETMSG_WRITE_FUNC m_MsgOut.WriteFloat( flValue ); } void CNetMsgScriptHelper::WriteNormal( float flValue ) { + SCRIPT_NETMSG_WRITE_FUNC m_MsgOut.WriteBitNormal( flValue ); } void CNetMsgScriptHelper::WriteAngle( float flValue ) { + SCRIPT_NETMSG_WRITE_FUNC m_MsgOut.WriteBitAngle( flValue, 8 ); } void CNetMsgScriptHelper::WriteCoord( float flValue ) { + SCRIPT_NETMSG_WRITE_FUNC m_MsgOut.WriteBitCoord( flValue ); } void CNetMsgScriptHelper::WriteVec3Coord( const Vector& rgflValue ) { + SCRIPT_NETMSG_WRITE_FUNC m_MsgOut.WriteBitVec3Coord( rgflValue ); } void CNetMsgScriptHelper::WriteVec3Normal( const Vector& rgflValue ) { + SCRIPT_NETMSG_WRITE_FUNC m_MsgOut.WriteBitVec3Normal( rgflValue ); } void CNetMsgScriptHelper::WriteAngles( const QAngle& rgflValue ) { + SCRIPT_NETMSG_WRITE_FUNC m_MsgOut.WriteBitAngles( rgflValue ); } void CNetMsgScriptHelper::WriteString( const char *sz ) { + SCRIPT_NETMSG_WRITE_FUNC + + // Larger strings can be written but cannot be read + Assert( V_strlen(sz) < SCRIPT_NETMSG_STRING_SIZE ); + m_MsgOut.WriteString( sz ); } void CNetMsgScriptHelper::WriteBool( bool bValue ) { + SCRIPT_NETMSG_WRITE_FUNC m_MsgOut.WriteOneBit( bValue ? 1 : 0 ); } void CNetMsgScriptHelper::WriteEntity( HSCRIPT hEnt ) { + SCRIPT_NETMSG_WRITE_FUNC CBaseEntity *p = ToEnt(hEnt); int i = p ? p->entindex() : -1; m_MsgOut.WriteSBitLong( i, MAX_EDICT_BITS ); @@ -1659,6 +1779,7 @@ void CNetMsgScriptHelper::WriteEntity( HSCRIPT hEnt ) void CNetMsgScriptHelper::WriteEHandle( HSCRIPT hEnt ) { + SCRIPT_NETMSG_WRITE_FUNC CBaseEntity *pEnt = ToEnt( hEnt ); long iEncodedEHandle; if ( pEnt ) @@ -1752,7 +1873,7 @@ const QAngle& CNetMsgScriptHelper::ReadAngles() const char* CNetMsgScriptHelper::ReadString() { - static char buf[512]; + static char buf[ SCRIPT_NETMSG_STRING_SIZE ]; m_MsgIn_()ReadString( buf, sizeof(buf) ); return buf; } @@ -1790,12 +1911,15 @@ HSCRIPT CNetMsgScriptHelper::ReadEHandle() return ToHScript( EHANDLE( iEntry, iSerialNum ) ); } -int CNetMsgScriptHelper::GetNumBitsWritten() +inline int CNetMsgScriptHelper::GetNumBitsWritten() { - return m_MsgOut.GetNumBitsWritten(); +#ifdef GAME_DLL + return m_MsgOut.GetNumBitsWritten() - SCRIPT_NETMSG_HEADER_BITS; +#else + return m_MsgOut.m_iCurBit - m_iLastBit - SCRIPT_NETMSG_HEADER_BITS; +#endif } -#undef m_MsgIn_ BEGIN_SCRIPTDESC_ROOT_NAMED( CNetMsgScriptHelper, "CNetMsg", SCRIPT_SINGLETON "Network messages" ) @@ -1818,7 +1942,7 @@ BEGIN_SCRIPTDESC_ROOT_NAMED( CNetMsgScriptHelper, "CNetMsg", SCRIPT_SINGLETON "N #ifdef GAME_DLL DEFINE_SCRIPTFUNC( Send, "Send a custom network message from the server to the client (max 252 bytes)" ) #else - DEFINE_SCRIPTFUNC( Send, "Send a custom network message from the client to the server (max 2045 bytes)" ) + DEFINE_SCRIPTFUNC( Send, "Send a custom network message from the client to the server (max 2044 bytes)" ) #endif DEFINE_SCRIPTFUNC( WriteInt, "variable bit signed int" ) @@ -1835,7 +1959,7 @@ BEGIN_SCRIPTDESC_ROOT_NAMED( CNetMsgScriptHelper, "CNetMsg", SCRIPT_SINGLETON "N DEFINE_SCRIPTFUNC( WriteVec3Coord, "" ) DEFINE_SCRIPTFUNC( WriteVec3Normal, "27 bit" ) DEFINE_SCRIPTFUNC( WriteAngles, "" ) - DEFINE_SCRIPTFUNC( WriteString, "" ) + DEFINE_SCRIPTFUNC( WriteString, "max 512 bytes at once" ) DEFINE_SCRIPTFUNC( WriteBool, "1 bit" ) DEFINE_SCRIPTFUNC( WriteEntity, "11 bit (entindex)" ) DEFINE_SCRIPTFUNC( WriteEHandle, "32 bit long" ) @@ -1854,7 +1978,7 @@ BEGIN_SCRIPTDESC_ROOT_NAMED( CNetMsgScriptHelper, "CNetMsg", SCRIPT_SINGLETON "N DEFINE_SCRIPTFUNC( ReadVec3Coord, "" ) DEFINE_SCRIPTFUNC( ReadVec3Normal, "" ) DEFINE_SCRIPTFUNC( ReadAngles, "" ) - DEFINE_SCRIPTFUNC( ReadString, "max 512 bytes at once" ) + DEFINE_SCRIPTFUNC( ReadString, "" ) DEFINE_SCRIPTFUNC( ReadBool, "" ) DEFINE_SCRIPTFUNC( ReadEntity, "" ) DEFINE_SCRIPTFUNC( ReadEHandle, "" ) diff --git a/sp/src/game/shared/mapbase/vscript_singletons.h b/sp/src/game/shared/mapbase/vscript_singletons.h index a18d4a38..825320c0 100644 --- a/sp/src/game/shared/mapbase/vscript_singletons.h +++ b/sp/src/game/shared/mapbase/vscript_singletons.h @@ -17,12 +17,17 @@ void RegisterScriptSingletons(); #ifdef CLIENT_DLL // usercmd -#define SCRIPT_NETMSG_DATA_SIZE ( ( 1 << 11 ) - 1 ) +#define SCRIPT_NETMSG_DATA_SIZE ( ( 1 << 11 ) - 1 ) #else // usermsg -#define SCRIPT_NETMSG_DATA_SIZE MAX_USER_MSG_DATA +#define SCRIPT_NETMSG_DATA_SIZE MAX_USER_MSG_DATA #endif +#define SCRIPT_NETMSG_QUEUE_BITS 3 // determines the number of custom messages client can write to a usercmd +#define SCRIPT_NETMSG_HEADER_BITS (sizeof(word) << 3) +#define SCRIPT_NETMSG_STRING_SIZE 512 + + #ifdef CLIENT_DLL class CNetMsgScriptHelper : public CAutoGameSystem #else @@ -40,18 +45,28 @@ private: CRecipientFilter m_filter; #else bf_read m_MsgIn; + unsigned int m_nQueueCount; + bool m_bWriteIgnore; #endif HSCRIPT m_Hooks; bf_write m_MsgOut; byte m_MsgData[ PAD_NUMBER( SCRIPT_NETMSG_DATA_SIZE, 4 ) ]; -public: #ifdef CLIENT_DLL - CNetMsgScriptHelper() : m_Hooks(NULL), m_bWriteReady(false) {} -#else - CNetMsgScriptHelper() : m_Hooks(NULL) {} + int m_iLastBit; #endif +public: + CNetMsgScriptHelper() : m_Hooks(NULL) + +#ifdef CLIENT_DLL + , m_bWriteReady(0), m_bWriteIgnore(0), m_nQueueCount(0), m_iLastBit(0) +#else + , m_MsgIn(0) +#endif + + {} + public: #ifdef CLIENT_DLL bool Init(); // IGameSystem @@ -135,6 +150,8 @@ public: //int GetNumBitsLeft(); // unreliable on server because of usercmds. so just do away with it int GetNumBitsWritten(); +public: + static inline int Hash( const char *key ); }; extern CNetMsgScriptHelper *g_ScriptNetMsg; From 9c942903e97b681de0a43e0cb1f4d1238665a588 Mon Sep 17 00:00:00 2001 From: samisalreadytaken <46823719+samisalreadytaken@users.noreply.github.com> Date: Fri, 18 Feb 2022 17:04:00 +0300 Subject: [PATCH 314/378] Remove CNetMsgScriptHelper multiplayer recipient functions --- .../shared/mapbase/vscript_singletons.cpp | 33 ++----------------- .../game/shared/mapbase/vscript_singletons.h | 8 ----- 2 files changed, 2 insertions(+), 39 deletions(-) diff --git a/sp/src/game/shared/mapbase/vscript_singletons.cpp b/sp/src/game/shared/mapbase/vscript_singletons.cpp index f1b72c1d..64212d44 100644 --- a/sp/src/game/shared/mapbase/vscript_singletons.cpp +++ b/sp/src/game/shared/mapbase/vscript_singletons.cpp @@ -1643,32 +1643,6 @@ void CNetMsgScriptHelper::DispatchUserMessage( const char *msg ) } #endif // GAME_DLL -#ifdef GAME_DLL -void CNetMsgScriptHelper::AddRecipient( HSCRIPT player ) -{ - CBaseEntity *pPlayer = ToEnt(player); - if ( pPlayer ) - { - m_filter.AddRecipient( (CBasePlayer*)pPlayer ); - } -} - -void CNetMsgScriptHelper::AddRecipientsByPVS( const Vector &pos ) -{ - m_filter.AddRecipientsByPVS(pos); -} - -void CNetMsgScriptHelper::AddRecipientsByPAS( const Vector &pos ) -{ - m_filter.AddRecipientsByPAS(pos); -} - -void CNetMsgScriptHelper::AddAllPlayers() -{ - m_filter.AddAllPlayers(); -} -#endif // GAME_DLL - void CNetMsgScriptHelper::WriteInt( int iValue, int bits ) { SCRIPT_NETMSG_WRITE_FUNC @@ -1926,11 +1900,8 @@ BEGIN_SCRIPTDESC_ROOT_NAMED( CNetMsgScriptHelper, "CNetMsg", SCRIPT_SINGLETON "N #ifdef GAME_DLL DEFINE_SCRIPTFUNC( SendUserMessage, "Send a usermessage from the server to the client" ) DEFINE_SCRIPTFUNC( SendEntityMessage, "Send a message from a server side entity to its client side counterpart" ) - DEFINE_SCRIPTFUNC( AddRecipient, "" ) - //DEFINE_SCRIPTFUNC( RemoveRecipient, "" ) - DEFINE_SCRIPTFUNC( AddRecipientsByPVS, "" ) - DEFINE_SCRIPTFUNC( AddRecipientsByPAS, "" ) - DEFINE_SCRIPTFUNC( AddAllPlayers, "" ) + + // TODO: multiplayer #else DEFINE_SCRIPTFUNC( DispatchUserMessage, "Dispatch a usermessage on client" ) #endif diff --git a/sp/src/game/shared/mapbase/vscript_singletons.h b/sp/src/game/shared/mapbase/vscript_singletons.h index 825320c0..e514f4d9 100644 --- a/sp/src/game/shared/mapbase/vscript_singletons.h +++ b/sp/src/game/shared/mapbase/vscript_singletons.h @@ -102,14 +102,6 @@ public: void DispatchUserMessage( const char *msg ); #endif -#ifdef GAME_DLL -public: - void AddRecipient( HSCRIPT player ); - void AddRecipientsByPVS( const Vector &pos ); - void AddRecipientsByPAS( const Vector &pos ); - void AddAllPlayers(); -#endif // GAME_DLL - public: void WriteInt( int iValue, int bits ); void WriteUInt( int iValue, int bits ); From 700ac4ed78a20c51de8435d6ff1cda75f658208a Mon Sep 17 00:00:00 2001 From: samisalreadytaken <46823719+samisalreadytaken@users.noreply.github.com> Date: Sat, 26 Feb 2022 19:15:00 +0300 Subject: [PATCH 315/378] Fixed memory leaks and unsafe code, reworked script CGameTrace --- sp/src/game/server/baseentity.cpp | 19 +-- .../shared/mapbase/vscript_funcs_shared.cpp | 137 ++++++++-------- .../shared/mapbase/vscript_funcs_shared.h | 154 ++++++++++-------- 3 files changed, 162 insertions(+), 148 deletions(-) diff --git a/sp/src/game/server/baseentity.cpp b/sp/src/game/server/baseentity.cpp index fd31f792..86070442 100644 --- a/sp/src/game/server/baseentity.cpp +++ b/sp/src/game/server/baseentity.cpp @@ -10213,13 +10213,10 @@ const Vector& CBaseEntity::ScriptGetBoundingMaxs(void) //----------------------------------------------------------------------------- int CBaseEntity::ScriptTakeDamage( HSCRIPT pInfo ) { - if (pInfo) + CTakeDamageInfo *info = HScriptToClass< CTakeDamageInfo >( pInfo ); + if ( info ) { - CTakeDamageInfo *info = HScriptToClass( pInfo ); //ToDamageInfo( pInfo ); - if (info) - { - return OnTakeDamage( *info ); - } + return OnTakeDamage( *info ); } return 0; @@ -10229,14 +10226,10 @@ int CBaseEntity::ScriptTakeDamage( HSCRIPT pInfo ) //----------------------------------------------------------------------------- void CBaseEntity::ScriptFireBullets( HSCRIPT pInfo ) { - if (pInfo) + FireBulletsInfo_t *info = HScriptToClass< FireBulletsInfo_t >( pInfo ); + if ( info ) { - extern FireBulletsInfo_t *GetFireBulletsInfoFromInfo( HSCRIPT hBulletsInfo ); - FireBulletsInfo_t *info = GetFireBulletsInfoFromInfo( pInfo ); - if (info) - { - FireBullets( *info ); - } + FireBullets( *info ); } } diff --git a/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp b/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp index ef410283..b0cbaf02 100644 --- a/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp +++ b/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp @@ -258,8 +258,8 @@ void ScriptDispatchSpawn( HSCRIPT hEntity ) 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, true ); + CTakeDamageInfo *damageInfo = new CTakeDamageInfo( ToEnt(hInflictor), ToEnt(hAttacker), flDamage, iDamageType ); + HSCRIPT hScript = g_pScriptVM->RegisterInstance( damageInfo ); damageInfo->SetDamagePosition( vecDamagePos ); damageInfo->SetDamageForce( vecForce ); @@ -269,28 +269,54 @@ static HSCRIPT CreateDamageInfo( HSCRIPT hInflictor, HSCRIPT hAttacker, const Ve static void DestroyDamageInfo( HSCRIPT hDamageInfo ) { - if (hDamageInfo) + CTakeDamageInfo *pInfo = HScriptToClass< CTakeDamageInfo >( hDamageInfo ); + if ( pInfo ) { - CTakeDamageInfo *pInfo = (CTakeDamageInfo*)g_pScriptVM->GetInstanceValue( hDamageInfo, GetScriptDescForClass( CTakeDamageInfo ) ); - if (pInfo) - { - g_pScriptVM->RemoveInstance( hDamageInfo ); - delete 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 ); } +void ScriptCalculateExplosiveDamageForce( HSCRIPT info, const Vector &vecDir, const Vector &vecForceOrigin, float flScale ) +{ + CTakeDamageInfo *pInfo = HScriptToClass< CTakeDamageInfo >( info ); + if ( pInfo ) + { + CalculateExplosiveDamageForce( pInfo, vecDir, vecForceOrigin, flScale ); + } +} + +void ScriptCalculateBulletDamageForce( HSCRIPT info, int iBulletType, const Vector &vecBulletDir, const Vector &vecForceOrigin, float flScale ) +{ + CTakeDamageInfo *pInfo = HScriptToClass< CTakeDamageInfo >( info ); + if ( pInfo ) + { + CalculateBulletDamageForce( pInfo, iBulletType, vecBulletDir, vecForceOrigin, flScale ); + } +} + +void ScriptCalculateMeleeDamageForce( HSCRIPT info, const Vector &vecMeleeDir, const Vector &vecForceOrigin, float flScale ) +{ + CTakeDamageInfo *pInfo = HScriptToClass< CTakeDamageInfo >( info ); + if ( pInfo ) + { + CalculateMeleeDamageForce( pInfo, vecMeleeDir, vecForceOrigin, flScale ); + } +} + +void ScriptGuessDamageForce( HSCRIPT info, const Vector &vecForceDir, const Vector &vecForceOrigin, float flScale ) +{ + CTakeDamageInfo *pInfo = HScriptToClass< CTakeDamageInfo >( info ); + if ( pInfo ) + { + GuessDamageForce( pInfo, vecForceDir, vecForceOrigin, flScale ); + } +} //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- -BEGIN_SCRIPTDESC_ROOT_NAMED( CTraceInfoAccessor, "CGameTrace", "Handle for accessing trace_t info." ) - DEFINE_SCRIPT_CONSTRUCTOR() - +BEGIN_SCRIPTDESC_ROOT_NAMED( CScriptGameTrace, "CGameTrace", "trace_t" ) 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." ) @@ -324,7 +350,7 @@ BEGIN_SCRIPTDESC_ROOT_NAMED( CTraceInfoAccessor, "CGameTrace", "Handle for acces DEFINE_SCRIPTFUNC( Destroy, "Deletes this instance. Important for preventing memory leaks." ) END_SCRIPTDESC(); -BEGIN_SCRIPTDESC_ROOT_NAMED( scriptsurfacedata_t, "surfacedata_t", "Handle for accessing surface data." ) +BEGIN_SCRIPTDESC_ROOT_NAMED( scriptsurfacedata_t, "surfacedata_t", "" ) DEFINE_SCRIPTFUNC( GetFriction, "The surface's friction." ) DEFINE_SCRIPTFUNC( GetThickness, "The surface's thickness." ) @@ -343,69 +369,44 @@ BEGIN_SCRIPTDESC_ROOT_NAMED( scriptsurfacedata_t, "surfacedata_t", "Handle for a DEFINE_SCRIPTFUNC( GetSoundStrain, "The surface's strain sound." ) END_SCRIPTDESC(); -const char* scriptsurfacedata_t::GetSoundStepLeft() { return physprops->GetString( sounds.stepleft ); } -const char* scriptsurfacedata_t::GetSoundStepRight() { return physprops->GetString( sounds.stepright ); } -const char* scriptsurfacedata_t::GetSoundImpactSoft() { return physprops->GetString( sounds.impactSoft ); } -const char* scriptsurfacedata_t::GetSoundImpactHard() { return physprops->GetString( sounds.impactHard ); } -const char* scriptsurfacedata_t::GetSoundScrapeSmooth() { return physprops->GetString( sounds.scrapeSmooth ); } -const char* scriptsurfacedata_t::GetSoundScrapeRough() { return physprops->GetString( sounds.scrapeRough ); } -const char* scriptsurfacedata_t::GetSoundBulletImpact() { return physprops->GetString( sounds.bulletImpact ); } -const char* scriptsurfacedata_t::GetSoundRolling() { return physprops->GetString( sounds.rolling ); } -const char* scriptsurfacedata_t::GetSoundBreak() { return physprops->GetString( sounds.breakSound ); } -const char* scriptsurfacedata_t::GetSoundStrain() { return physprops->GetString( sounds.strainSound ); } - -BEGIN_SCRIPTDESC_ROOT_NAMED( CSurfaceScriptAccessor, "csurface_t", "Handle for accessing csurface_t info." ) +BEGIN_SCRIPTDESC_ROOT_NAMED( CSurfaceScriptHelper, "csurface_t", "" ) DEFINE_SCRIPTFUNC( Name, "The surface's name." ) DEFINE_SCRIPTFUNC( SurfaceProps, "The surface's properties." ) - - DEFINE_SCRIPTFUNC( Destroy, "Deletes this instance. Important for preventing memory leaks." ) END_SCRIPTDESC(); CPlaneTInstanceHelper g_PlaneTInstanceHelper; -BEGIN_SCRIPTDESC_ROOT( cplane_t, "Handle for accessing cplane_t info." ) +BEGIN_SCRIPTDESC_ROOT( cplane_t, "" ) DEFINE_SCRIPT_INSTANCE_HELPER( &g_PlaneTInstanceHelper ) 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, true ); + CScriptGameTrace *tr = new CScriptGameTrace(); - CBaseEntity *pLooker = ToEnt(entIgnore); - UTIL_TraceLine( vecStart, vecEnd, iMask, pLooker, iCollisionGroup, &traceInfo->GetTrace()); + CBaseEntity *pIgnore = ToEnt( entIgnore ); + UTIL_TraceLine( vecStart, vecEnd, iMask, pIgnore, iCollisionGroup, tr ); - // The trace's destruction should destroy this automatically - CSurfaceScriptAccessor *surfaceInfo = new CSurfaceScriptAccessor( traceInfo->GetTrace().surface ); - HSCRIPT hSurface = g_pScriptVM->RegisterInstance( surfaceInfo ); - traceInfo->SetSurface( hSurface ); + tr->RegisterSurface(); + tr->RegisterPlane(); - HSCRIPT hPlane = g_pScriptVM->RegisterInstance( &(traceInfo->GetTrace().plane) ); - traceInfo->SetPlane( hPlane ); - - return hScript; + return tr->GetScriptInstance(); } 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, true ); + CScriptGameTrace *tr = new CScriptGameTrace(); - CBaseEntity *pLooker = ToEnt(entIgnore); - UTIL_TraceHull( vecStart, vecEnd, hullMin, hullMax, iMask, pLooker, iCollisionGroup, &traceInfo->GetTrace()); + CBaseEntity *pIgnore = ToEnt( entIgnore ); + UTIL_TraceHull( vecStart, vecEnd, hullMin, hullMax, iMask, pIgnore, iCollisionGroup, tr ); - // The trace's destruction should destroy this automatically - CSurfaceScriptAccessor *surfaceInfo = new CSurfaceScriptAccessor( traceInfo->GetTrace().surface ); - HSCRIPT hSurface = g_pScriptVM->RegisterInstance( surfaceInfo ); - traceInfo->SetSurface( hSurface ); + tr->RegisterSurface(); + tr->RegisterPlane(); - HSCRIPT hPlane = g_pScriptVM->RegisterInstance( &(traceInfo->GetTrace().plane) ); - traceInfo->SetPlane( hPlane ); - - return hScript; + return tr->GetScriptInstance(); } //----------------------------------------------------------------------------- @@ -451,8 +452,6 @@ BEGIN_SCRIPTDESC_ROOT( FireBulletsInfo_t, "Handle for accessing FireBulletsInfo_ DEFINE_SCRIPTFUNC( GetPrimaryAttack, "Gets whether the bullets came from a primary attack." ) DEFINE_SCRIPTFUNC( SetPrimaryAttack, "Sets whether the bullets came from a primary attack." ) - - //DEFINE_SCRIPTFUNC( Destroy, "Deletes this instance. Important for preventing memory leaks." ) END_SCRIPTDESC(); //----------------------------------------------------------------------------- @@ -483,7 +482,7 @@ static HSCRIPT CreateFireBulletsInfo( int cShots, const Vector &vecSrc, const Ve { // The script is responsible for deleting this via DestroyFireBulletsInfo(). FireBulletsInfo_t *info = new FireBulletsInfo_t(); - HSCRIPT hScript = g_pScriptVM->RegisterInstance( info, true ); + HSCRIPT hScript = g_pScriptVM->RegisterInstance( info ); info->SetShots( cShots ); info->SetSource( vecSrc ); @@ -497,13 +496,12 @@ static HSCRIPT CreateFireBulletsInfo( int cShots, const Vector &vecSrc, const Ve static void DestroyFireBulletsInfo( HSCRIPT hBulletsInfo ) { - g_pScriptVM->RemoveInstance( hBulletsInfo ); -} - -// For the function in baseentity.cpp -FireBulletsInfo_t *GetFireBulletsInfoFromInfo( HSCRIPT hBulletsInfo ) -{ - return HScriptToClass( hBulletsInfo ); + FireBulletsInfo_t *pInfo = HScriptToClass< FireBulletsInfo_t >( hBulletsInfo ); + if ( pInfo ) + { + g_pScriptVM->RemoveInstance( hBulletsInfo ); + delete pInfo; + } } //----------------------------------------------------------------------------- @@ -844,8 +842,11 @@ static void ScriptEntitiesInSphere( HSCRIPT hTable, int listMax, const Vector &c static void ScriptDecalTrace( HSCRIPT hTrace, const char *decalName ) { - CTraceInfoAccessor *traceInfo = HScriptToClass(hTrace); - UTIL_DecalTrace( &traceInfo->GetTrace(), decalName ); + CScriptGameTrace *tr = HScriptToClass< CScriptGameTrace >( hTrace ); + if ( tr ) + { + UTIL_DecalTrace( tr, decalName ); + } } static HSCRIPT ScriptCreateRope( HSCRIPT hStart, HSCRIPT hEnd, int iStartAttachment, int iEndAttachment, float ropeWidth, const char *pMaterialName, int numSegments, int ropeFlags ) diff --git a/sp/src/game/shared/mapbase/vscript_funcs_shared.h b/sp/src/game/shared/mapbase/vscript_funcs_shared.h index c7ad9ca7..bcf91741 100644 --- a/sp/src/game/shared/mapbase/vscript_funcs_shared.h +++ b/sp/src/game/shared/mapbase/vscript_funcs_shared.h @@ -21,42 +21,52 @@ //----------------------------------------------------------------------------- struct scriptsurfacedata_t : public surfacedata_t { - float GetFriction() { return physics.friction; } - float GetThickness() { return physics.thickness; } +public: + float GetFriction() const { return physics.friction; } + float GetThickness() const { return physics.thickness; } - float GetJumpFactor() { return game.jumpFactor; } - char GetMaterialChar() { return game.material; } + float GetJumpFactor() const { return game.jumpFactor; } + char GetMaterialChar() const { return game.material; } - const char* GetSoundStepLeft(); - const char* GetSoundStepRight(); - const char* GetSoundImpactSoft(); - const char* GetSoundImpactHard(); - const char* GetSoundScrapeSmooth(); - const char* GetSoundScrapeRough(); - const char* GetSoundBulletImpact(); - const char* GetSoundRolling(); - const char* GetSoundBreak(); - const char* GetSoundStrain(); + const char* GetSoundStepLeft() const { return physprops->GetString( sounds.stepleft ); } + const char* GetSoundStepRight() const { return physprops->GetString( sounds.stepright ); } + const char* GetSoundImpactSoft() const { return physprops->GetString( sounds.impactSoft ); } + const char* GetSoundImpactHard() const { return physprops->GetString( sounds.impactHard ); } + const char* GetSoundScrapeSmooth() const { return physprops->GetString( sounds.scrapeSmooth ); } + const char* GetSoundScrapeRough() const { return physprops->GetString( sounds.scrapeRough ); } + const char* GetSoundBulletImpact() const { return physprops->GetString( sounds.bulletImpact ); } + const char* GetSoundRolling() const { return physprops->GetString( sounds.rolling ); } + const char* GetSoundBreak() const { return physprops->GetString( sounds.breakSound ); } + const char* GetSoundStrain() const { return physprops->GetString( sounds.strainSound ); } }; //----------------------------------------------------------------------------- // Exposes csurface_t to VScript //----------------------------------------------------------------------------- -class CSurfaceScriptAccessor +class CSurfaceScriptHelper { public: - CSurfaceScriptAccessor( csurface_t &surf ) { m_surf = &surf; m_surfaceData = g_pScriptVM->RegisterInstance( reinterpret_cast(physprops->GetSurfaceData( m_surf->surfaceProps )) ); } - ~CSurfaceScriptAccessor() { delete m_surfaceData; } + // This class is owned by CScriptGameTrace, and cannot be accessed without being initialised in CScriptGameTrace::RegisterSurface() + //CSurfaceScriptHelper() : m_pSurface(NULL), m_hSurfaceData(NULL) {} - // cplane_t stuff - const char* Name() const { return m_surf->name; } - HSCRIPT SurfaceProps() const { return m_surfaceData; } + ~CSurfaceScriptHelper() + { + g_pScriptVM->RemoveInstance( m_hSurfaceData ); + } - void Destroy() { delete this; } + void Init( csurface_t *surf ) + { + m_pSurface = surf; + m_hSurfaceData = g_pScriptVM->RegisterInstance( + reinterpret_cast< scriptsurfacedata_t* >( physprops->GetSurfaceData( m_pSurface->surfaceProps ) ) ); + } + + const char* Name() const { return m_pSurface->name; } + HSCRIPT SurfaceProps() const { return m_hSurfaceData; } private: - csurface_t *m_surf; - HSCRIPT m_surfaceData; + csurface_t *m_pSurface; + HSCRIPT m_hSurfaceData; }; //----------------------------------------------------------------------------- @@ -83,70 +93,80 @@ class CPlaneTInstanceHelper : public IScriptInstanceHelper //----------------------------------------------------------------------------- // Exposes trace_t to VScript //----------------------------------------------------------------------------- -class CTraceInfoAccessor +class CScriptGameTrace : public CGameTrace { public: - ~CTraceInfoAccessor() + CScriptGameTrace() : m_surfaceAccessor(NULL), m_planeAccessor(NULL) { - if (m_surfaceAccessor) - { - CSurfaceScriptAccessor *pScriptSurface = HScriptToClass( m_surfaceAccessor ); - //g_pScriptVM->RemoveInstance( m_surfaceAccessor ); - delete pScriptSurface; - } - - //if (m_planeAccessor) - //{ - // g_pScriptVM->RemoveInstance( m_planeAccessor ); - //} + m_hScriptInstance = g_pScriptVM->RegisterInstance( this ); } - // 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(); } + ~CScriptGameTrace() + { + if ( m_hScriptInstance ) + { + g_pScriptVM->RemoveInstance( m_hScriptInstance ); + } - float FractionLeftSolid() const { return m_tr.fractionleftsolid; } - int HitGroup() const { return m_tr.hitgroup; } - int PhysicsBone() const { return m_tr.physicsbone; } + if ( m_surfaceAccessor ) + { + g_pScriptVM->RemoveInstance( m_surfaceAccessor ); + } - HSCRIPT Entity() const { return ToHScript(m_tr.m_pEnt); } + if ( m_planeAccessor ) + { + g_pScriptVM->RemoveInstance( m_planeAccessor ); + } + } - int HitBox() const { return m_tr.hitbox; } + void RegisterSurface() + { + m_surfaceHelper.Init( &surface ); + m_surfaceAccessor = g_pScriptVM->RegisterInstance( &m_surfaceHelper ); + } - // 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(); } + void RegisterPlane() + { + m_planeAccessor = g_pScriptVM->RegisterInstance( &plane ); + } - const Vector& StartPos() const { return m_tr.startpos; } - const Vector& EndPos() const { return m_tr.endpos; } + HSCRIPT GetScriptInstance() const + { + return m_hScriptInstance; + } - float Fraction() const { return m_tr.fraction; } +public: + float FractionLeftSolid() const { return fractionleftsolid; } + int HitGroup() const { return hitgroup; } + int PhysicsBone() const { return physicsbone; } - int Contents() const { return m_tr.contents; } - int DispFlags() const { return m_tr.dispFlags; } + HSCRIPT Entity() const { return ToHScript( m_pEnt ); } + int HitBox() const { return hitbox; } - bool AllSolid() const { return m_tr.allsolid; } - bool StartSolid() const { return m_tr.startsolid; } + const Vector& StartPos() const { return startpos; } + const Vector& EndPos() const { return endpos; } - HSCRIPT Surface() { return m_surfaceAccessor; } - void SetSurface( HSCRIPT hSurfAccessor ) { m_surfaceAccessor = hSurfAccessor; } + float Fraction() const { return fraction; } - HSCRIPT Plane() { return m_planeAccessor; } - void SetPlane( HSCRIPT hPlaneAccessor ) { m_planeAccessor = hPlaneAccessor; } + int Contents() const { return contents; } + int DispFlags() const { return dispFlags; } - trace_t &GetTrace() { return m_tr; } - void Destroy() { delete this; } + bool AllSolid() const { return allsolid; } + bool StartSolid() const { return startsolid; } + + HSCRIPT Surface() const { return m_surfaceAccessor; } + HSCRIPT Plane() const { return m_planeAccessor; } + + void Destroy() { delete this; } private: - trace_t m_tr; - HSCRIPT m_surfaceAccessor; HSCRIPT m_planeAccessor; + HSCRIPT m_hScriptInstance; + + CSurfaceScriptHelper m_surfaceHelper; + + CScriptGameTrace( const CScriptGameTrace& v ); }; //----------------------------------------------------------------------------- From 4af6d0cdaafcd4d26623b15b8bab54d47f339dc0 Mon Sep 17 00:00:00 2001 From: samisalreadytaken <46823719+samisalreadytaken@users.noreply.github.com> Date: Sat, 26 Feb 2022 19:20:00 +0300 Subject: [PATCH 316/378] Remove redundant script documentation --- .../shared/mapbase/vscript_funcs_shared.cpp | 150 +++++++++--------- 1 file changed, 75 insertions(+), 75 deletions(-) diff --git a/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp b/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp index b0cbaf02..fc9fa33e 100644 --- a/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp +++ b/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp @@ -344,33 +344,33 @@ BEGIN_SCRIPTDESC_ROOT_NAMED( CScriptGameTrace, "CGameTrace", "trace_t" ) 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( Surface, "Returns the trace's surface." ) - DEFINE_SCRIPTFUNC( Plane, "Returns the trace's plane." ) + DEFINE_SCRIPTFUNC( Surface, "" ) + DEFINE_SCRIPTFUNC( Plane, "" ) DEFINE_SCRIPTFUNC( Destroy, "Deletes this instance. Important for preventing memory leaks." ) END_SCRIPTDESC(); BEGIN_SCRIPTDESC_ROOT_NAMED( scriptsurfacedata_t, "surfacedata_t", "" ) - DEFINE_SCRIPTFUNC( GetFriction, "The surface's friction." ) - DEFINE_SCRIPTFUNC( GetThickness, "The surface's thickness." ) + DEFINE_SCRIPTFUNC( GetFriction, "" ) + DEFINE_SCRIPTFUNC( GetThickness, "" ) - DEFINE_SCRIPTFUNC( GetJumpFactor, "The surface's jump factor." ) - DEFINE_SCRIPTFUNC( GetMaterialChar, "The surface's material character." ) + DEFINE_SCRIPTFUNC( GetJumpFactor, "" ) + DEFINE_SCRIPTFUNC( GetMaterialChar, "" ) - DEFINE_SCRIPTFUNC( GetSoundStepLeft, "The surface's left step sound." ) - DEFINE_SCRIPTFUNC( GetSoundStepRight, "The surface's right step sound." ) - DEFINE_SCRIPTFUNC( GetSoundImpactSoft, "The surface's soft impact sound." ) - DEFINE_SCRIPTFUNC( GetSoundImpactHard, "The surface's hard impact sound." ) - DEFINE_SCRIPTFUNC( GetSoundScrapeSmooth, "The surface's smooth scrape sound." ) - DEFINE_SCRIPTFUNC( GetSoundScrapeRough, "The surface's rough scrape sound." ) - DEFINE_SCRIPTFUNC( GetSoundBulletImpact, "The surface's bullet impact sound." ) - DEFINE_SCRIPTFUNC( GetSoundRolling, "The surface's rolling sound." ) - DEFINE_SCRIPTFUNC( GetSoundBreak, "The surface's break sound." ) - DEFINE_SCRIPTFUNC( GetSoundStrain, "The surface's strain sound." ) + DEFINE_SCRIPTFUNC( GetSoundStepLeft, "" ) + DEFINE_SCRIPTFUNC( GetSoundStepRight, "" ) + DEFINE_SCRIPTFUNC( GetSoundImpactSoft, "" ) + DEFINE_SCRIPTFUNC( GetSoundImpactHard, "" ) + DEFINE_SCRIPTFUNC( GetSoundScrapeSmooth, "" ) + DEFINE_SCRIPTFUNC( GetSoundScrapeRough, "" ) + DEFINE_SCRIPTFUNC( GetSoundBulletImpact, "" ) + DEFINE_SCRIPTFUNC( GetSoundRolling, "" ) + DEFINE_SCRIPTFUNC( GetSoundBreak, "" ) + DEFINE_SCRIPTFUNC( GetSoundStrain, "" ) END_SCRIPTDESC(); BEGIN_SCRIPTDESC_ROOT_NAMED( CSurfaceScriptHelper, "csurface_t", "" ) - DEFINE_SCRIPTFUNC( Name, "The surface's name." ) + DEFINE_SCRIPTFUNC( Name, "" ) DEFINE_SCRIPTFUNC( SurfaceProps, "The surface's properties." ) END_SCRIPTDESC(); @@ -412,27 +412,27 @@ static HSCRIPT ScriptTraceHullComplex( const Vector &vecStart, const Vector &vec //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- -BEGIN_SCRIPTDESC_ROOT( FireBulletsInfo_t, "Handle for accessing FireBulletsInfo_t info." ) +BEGIN_SCRIPTDESC_ROOT( FireBulletsInfo_t, "" ) DEFINE_SCRIPT_CONSTRUCTOR() DEFINE_SCRIPTFUNC( GetShots, "Gets the number of shots which should be fired." ) DEFINE_SCRIPTFUNC( SetShots, "Sets the number of shots which should be fired." ) - DEFINE_SCRIPTFUNC( GetSource, "Gets the source of the bullets." ) - DEFINE_SCRIPTFUNC( SetSource, "Sets the source of the bullets." ) - DEFINE_SCRIPTFUNC( GetDirShooting, "Gets the direction of the bullets." ) - DEFINE_SCRIPTFUNC( SetDirShooting, "Sets the direction of the bullets." ) - DEFINE_SCRIPTFUNC( GetSpread, "Gets the spread of the bullets." ) - DEFINE_SCRIPTFUNC( SetSpread, "Sets the spread of the bullets." ) + DEFINE_SCRIPTFUNC( GetSource, "" ) + DEFINE_SCRIPTFUNC( SetSource, "" ) + DEFINE_SCRIPTFUNC( GetDirShooting, "" ) + DEFINE_SCRIPTFUNC( SetDirShooting, "" ) + DEFINE_SCRIPTFUNC( GetSpread, "" ) + DEFINE_SCRIPTFUNC( SetSpread, "" ) DEFINE_SCRIPTFUNC( GetDistance, "Gets the distance the bullets should travel." ) DEFINE_SCRIPTFUNC( SetDistance, "Sets the distance the bullets should travel." ) - DEFINE_SCRIPTFUNC( GetAmmoType, "Gets the ammo type the bullets should use." ) - DEFINE_SCRIPTFUNC( SetAmmoType, "Sets the ammo type the bullets should use." ) + DEFINE_SCRIPTFUNC( GetAmmoType, "" ) + DEFINE_SCRIPTFUNC( SetAmmoType, "" ) - DEFINE_SCRIPTFUNC( GetTracerFreq, "Gets the tracer frequency." ) - DEFINE_SCRIPTFUNC( SetTracerFreq, "Sets the tracer frequency." ) + DEFINE_SCRIPTFUNC( GetTracerFreq, "" ) + DEFINE_SCRIPTFUNC( SetTracerFreq, "" ) DEFINE_SCRIPTFUNC( GetDamage, "Gets the damage the bullets should deal. 0 = use ammo type" ) DEFINE_SCRIPTFUNC( SetDamage, "Sets the damage the bullets should deal. 0 = use ammo type" ) @@ -442,13 +442,13 @@ BEGIN_SCRIPTDESC_ROOT( FireBulletsInfo_t, "Handle for accessing FireBulletsInfo_ DEFINE_SCRIPTFUNC( GetFlags, "Gets the flags the bullets should use." ) DEFINE_SCRIPTFUNC( SetFlags, "Sets the flags the bullets should use." ) - DEFINE_SCRIPTFUNC( GetDamageForceScale, "Gets the scale of the damage force applied by the bullets." ) - DEFINE_SCRIPTFUNC( SetDamageForceScale, "Sets the scale of the damage force applied by the bullets." ) + DEFINE_SCRIPTFUNC( GetDamageForceScale, "" ) + DEFINE_SCRIPTFUNC( SetDamageForceScale, "" ) - DEFINE_SCRIPTFUNC_NAMED( ScriptGetAttacker, "GetAttacker", "Gets the entity considered to be the one who fired the bullets." ) - DEFINE_SCRIPTFUNC_NAMED( ScriptSetAttacker, "SetAttacker", "Sets the entity considered to be the one who fired the bullets." ) - DEFINE_SCRIPTFUNC_NAMED( ScriptGetAdditionalIgnoreEnt, "GetAdditionalIgnoreEnt", "Gets the optional entity which the bullets should ignore." ) - DEFINE_SCRIPTFUNC_NAMED( ScriptSetAdditionalIgnoreEnt, "SetAdditionalIgnoreEnt", "Sets the optional entity which the bullets should ignore." ) + DEFINE_SCRIPTFUNC_NAMED( ScriptGetAttacker, "GetAttacker", "" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptSetAttacker, "SetAttacker", "" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptGetAdditionalIgnoreEnt, "GetAdditionalIgnoreEnt", "" ) + DEFINE_SCRIPTFUNC_NAMED( ScriptSetAdditionalIgnoreEnt, "SetAdditionalIgnoreEnt", "" ) DEFINE_SCRIPTFUNC( GetPrimaryAttack, "Gets whether the bullets came from a primary attack." ) DEFINE_SCRIPTFUNC( SetPrimaryAttack, "Sets whether the bullets came from a primary attack." ) @@ -509,20 +509,20 @@ static void DestroyFireBulletsInfo( HSCRIPT hBulletsInfo ) //----------------------------------------------------------------------------- CAnimEventTInstanceHelper g_AnimEventTInstanceHelper; -BEGIN_SCRIPTDESC_ROOT( scriptanimevent_t, "Handle for accessing animevent_t info." ) +BEGIN_SCRIPTDESC_ROOT( scriptanimevent_t, "" ) DEFINE_SCRIPT_INSTANCE_HELPER( &g_AnimEventTInstanceHelper ) - DEFINE_SCRIPTFUNC( GetEvent, "Gets the event number." ) - DEFINE_SCRIPTFUNC( SetEvent, "Sets the event number." ) + DEFINE_SCRIPTFUNC( GetEvent, "" ) + DEFINE_SCRIPTFUNC( SetEvent, "" ) - DEFINE_SCRIPTFUNC( GetOptions, "Gets the event's options/parameters." ) - DEFINE_SCRIPTFUNC( SetOptions, "Sets the event's options/parameters." ) + DEFINE_SCRIPTFUNC( GetOptions, "" ) + DEFINE_SCRIPTFUNC( SetOptions, "" ) - DEFINE_SCRIPTFUNC( GetCycle, "Gets the cycle at which the event happens." ) - DEFINE_SCRIPTFUNC( SetCycle, "Sets the cycle at which the event happens." ) + DEFINE_SCRIPTFUNC( GetCycle, "" ) + DEFINE_SCRIPTFUNC( SetCycle, "" ) - DEFINE_SCRIPTFUNC( GetEventTime, "Gets the time the event plays." ) - DEFINE_SCRIPTFUNC( SetEventTime, "Sets the time the event plays." ) + DEFINE_SCRIPTFUNC( GetEventTime, "" ) + DEFINE_SCRIPTFUNC( SetEventTime, "" ) DEFINE_SCRIPTFUNC( GetType, "Gets the event's type flags. See the 'AE_TYPE_' set of constants for valid flags." ) DEFINE_SCRIPTFUNC( SetType, "Sets the event's type flags. See the 'AE_TYPE_' set of constants for valid flags." ) @@ -584,26 +584,26 @@ bool CAnimEventTInstanceHelper::Set( void *p, const char *pszKey, ScriptVariant_ //----------------------------------------------------------------------------- // EmitSound_t //----------------------------------------------------------------------------- -BEGIN_SCRIPTDESC_ROOT_NAMED( ScriptEmitSound_t, "EmitSound_t", "Handle for accessing EmitSound_t info." ) +BEGIN_SCRIPTDESC_ROOT_NAMED( ScriptEmitSound_t, "EmitSound_t", "" ) DEFINE_SCRIPT_CONSTRUCTOR() - DEFINE_SCRIPTFUNC( GetChannel, "Gets the sound's channel." ) - DEFINE_SCRIPTFUNC( SetChannel, "Gets the sound's channel." ) + DEFINE_SCRIPTFUNC( GetChannel, "" ) + DEFINE_SCRIPTFUNC( SetChannel, "" ) DEFINE_SCRIPTFUNC( GetSoundName, "Gets the sound's file path or soundscript name." ) DEFINE_SCRIPTFUNC( SetSoundName, "Sets the sound's file path or soundscript name." ) - DEFINE_SCRIPTFUNC( GetVolume, "Gets the sound's volume. (Note that this may not apply to soundscripts)" ) - DEFINE_SCRIPTFUNC( SetVolume, "Sets the sound's volume. (Note that this may not apply to soundscripts)" ) + DEFINE_SCRIPTFUNC( GetVolume, "(Note that this may not apply to soundscripts)" ) + DEFINE_SCRIPTFUNC( SetVolume, "(Note that this may not apply to soundscripts)" ) DEFINE_SCRIPTFUNC( GetSoundLevel, "Gets the sound's level in decibels. (Note that this may not apply to soundscripts)" ) DEFINE_SCRIPTFUNC( SetSoundLevel, "Sets the sound's level in decibels. (Note that this may not apply to soundscripts)" ) - DEFINE_SCRIPTFUNC( GetFlags, "Gets the sound's flags. See the 'SND_' set of constants for more information." ) - DEFINE_SCRIPTFUNC( SetFlags, "Sets the sound's flags. See the 'SND_' set of constants for more information." ) + DEFINE_SCRIPTFUNC( GetFlags, "Gets the sound's flags. See the 'SND_' set of constants." ) + DEFINE_SCRIPTFUNC( SetFlags, "Sets the sound's flags. See the 'SND_' set of constants." ) - DEFINE_SCRIPTFUNC( GetSpecialDSP, "Gets the sound's special DSP setting." ) - DEFINE_SCRIPTFUNC( SetSpecialDSP, "Sets the sound's special DSP setting." ) + DEFINE_SCRIPTFUNC( GetSpecialDSP, "" ) + DEFINE_SCRIPTFUNC( SetSpecialDSP, "" ) DEFINE_SCRIPTFUNC( HasOrigin, "Returns true if the sound has an origin override." ) DEFINE_SCRIPTFUNC( GetOrigin, "Gets the sound's origin override." ) @@ -625,14 +625,14 @@ BEGIN_SCRIPTDESC_ROOT_NAMED( ScriptEmitSound_t, "EmitSound_t", "Handle for acces DEFINE_SCRIPTFUNC( GetSpeakerEntity, "Gets the sound's original source if it is being transmitted by a microphone." ) DEFINE_SCRIPTFUNC( SetSpeakerEntity, "Sets the sound's original source if it is being transmitted by a microphone." ) - DEFINE_SCRIPTFUNC( GetSoundScriptHandle, "Gets the sound's script handle." ) - DEFINE_SCRIPTFUNC( SetSoundScriptHandle, "Sets the sound's script handle." ) + DEFINE_SCRIPTFUNC( GetSoundScriptHandle, "" ) + DEFINE_SCRIPTFUNC( SetSoundScriptHandle, "" ) END_SCRIPTDESC(); //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- -BEGIN_SCRIPTDESC_ROOT_NAMED( CScriptUserCmd, "CUserCmd", "Handle for accessing CUserCmd info." ) +BEGIN_SCRIPTDESC_ROOT_NAMED( CScriptUserCmd, "CUserCmd", "" ) DEFINE_SCRIPTFUNC( GetCommandNumber, "For matching server and client commands for debugging." ) DEFINE_SCRIPTFUNC_NAMED( ScriptGetTickCount, "GetTickCount", "The tick the client created this command." ) @@ -640,15 +640,15 @@ BEGIN_SCRIPTDESC_ROOT_NAMED( CScriptUserCmd, "CUserCmd", "Handle for accessing C DEFINE_SCRIPTFUNC( GetViewAngles, "Player instantaneous view angles." ) DEFINE_SCRIPTFUNC( SetViewAngles, "Sets player instantaneous view angles." ) - DEFINE_SCRIPTFUNC( GetForwardMove, "Forward velocity." ) - DEFINE_SCRIPTFUNC( SetForwardMove, "Sets forward velocity." ) - DEFINE_SCRIPTFUNC( GetSideMove, "Side velocity." ) - DEFINE_SCRIPTFUNC( SetSideMove, "Sets side velocity." ) - DEFINE_SCRIPTFUNC( GetUpMove, "Up velocity." ) - DEFINE_SCRIPTFUNC( SetUpMove, "Sets up velocity." ) + DEFINE_SCRIPTFUNC( GetForwardMove, "" ) + DEFINE_SCRIPTFUNC( SetForwardMove, "" ) + DEFINE_SCRIPTFUNC( GetSideMove, "" ) + DEFINE_SCRIPTFUNC( SetSideMove, "" ) + DEFINE_SCRIPTFUNC( GetUpMove, "" ) + DEFINE_SCRIPTFUNC( SetUpMove, "" ) - DEFINE_SCRIPTFUNC( GetButtons, "Attack button states." ) - DEFINE_SCRIPTFUNC( SetButtons, "Sets attack button states." ) + DEFINE_SCRIPTFUNC( GetButtons, "Input button state." ) + DEFINE_SCRIPTFUNC( SetButtons, "Sets input button state." ) DEFINE_SCRIPTFUNC( GetImpulse, "Impulse command issued." ) DEFINE_SCRIPTFUNC( SetImpulse, "Sets impulse command issued." ) @@ -674,19 +674,19 @@ END_SCRIPTDESC(); DEFINE_SCRIPTFUNC( Set##name, "Set " desc ) BEGIN_SCRIPTDESC_ROOT_NAMED( Script_AI_EnemyInfo_t, "AI_EnemyInfo_t", "Accessor for information about an enemy." ) - DEFINE_SCRIPTFUNC( Enemy, "Get the enemy." ) - DEFINE_SCRIPTFUNC( SetEnemy, "Set the enemy." ) - DEFINE_ENEMY_INFO_SCRIPTFUNCS( LastKnownLocation, "the enemy's last known location." ) - DEFINE_ENEMY_INFO_SCRIPTFUNCS( LastSeenLocation, "the enemy's last seen location." ) - DEFINE_ENEMY_INFO_SCRIPTFUNCS( TimeLastSeen, "the last time the enemy was seen." ) - DEFINE_ENEMY_INFO_SCRIPTFUNCS( TimeFirstSeen, "the first time the enemy was seen." ) - DEFINE_ENEMY_INFO_SCRIPTFUNCS( TimeLastReacquired, "the last time the enemy was reaquired." ) + DEFINE_SCRIPTFUNC( Enemy, "" ) + DEFINE_SCRIPTFUNC( SetEnemy, "" ) + DEFINE_ENEMY_INFO_SCRIPTFUNCS( LastKnownLocation, "" ) + DEFINE_ENEMY_INFO_SCRIPTFUNCS( LastSeenLocation, "" ) + DEFINE_ENEMY_INFO_SCRIPTFUNCS( TimeLastSeen, "" ) + DEFINE_ENEMY_INFO_SCRIPTFUNCS( TimeFirstSeen, "" ) + DEFINE_ENEMY_INFO_SCRIPTFUNCS( TimeLastReacquired, "" ) DEFINE_ENEMY_INFO_SCRIPTFUNCS( TimeValidEnemy, "the time at which the enemy can be selected (reaction delay)." ) DEFINE_ENEMY_INFO_SCRIPTFUNCS( TimeLastReceivedDamageFrom, "the last time damage was received from this enemy." ) DEFINE_ENEMY_INFO_SCRIPTFUNCS( TimeAtFirstHand, "the time at which the enemy was seen firsthand." ) DEFINE_ENEMY_INFO_SCRIPTFUNCS( DangerMemory, "the memory of danger position w/o enemy pointer." ) DEFINE_ENEMY_INFO_SCRIPTFUNCS( EludedMe, "whether the enemy is not at the last known location." ) - DEFINE_ENEMY_INFO_SCRIPTFUNCS( Unforgettable, "whether the enemy is unforgettable." ) + DEFINE_ENEMY_INFO_SCRIPTFUNCS( Unforgettable, "" ) DEFINE_ENEMY_INFO_SCRIPTFUNCS( MobbedMe, "whether the enemy was part of a mob at some point." ) END_SCRIPTDESC(); #endif @@ -994,15 +994,15 @@ void RegisterSharedScriptFunctions() 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, CreateDamageInfo, "" ); + ScriptRegisterFunction( g_pScriptVM, DestroyDamageInfo, "" ); 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." ); - ScriptRegisterFunction( g_pScriptVM, CreateFireBulletsInfo, "Creates FireBullets info." ); - ScriptRegisterFunction( g_pScriptVM, DestroyFireBulletsInfo, "Destroys FireBullets info." ); + ScriptRegisterFunction( g_pScriptVM, CreateFireBulletsInfo, "" ); + ScriptRegisterFunction( g_pScriptVM, DestroyFireBulletsInfo, "" ); 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." ); From f2f874939d53b9914ebeca1b7220f468fabc6484 Mon Sep 17 00:00:00 2001 From: samisalreadytaken <46823719+samisalreadytaken@users.noreply.github.com> Date: Fri, 4 Mar 2022 16:02:00 +0300 Subject: [PATCH 317/378] Fix vscript global hook calls --- sp/src/vscript/vscript_squirrel.nut | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/sp/src/vscript/vscript_squirrel.nut b/sp/src/vscript/vscript_squirrel.nut index b1700118..059f37f0 100644 --- a/sp/src/vscript/vscript_squirrel.nut +++ b/sp/src/vscript/vscript_squirrel.nut @@ -215,16 +215,17 @@ Hooks <- function Call( scope, event, ... ) { - local firstReturn = null + local firstReturn - if ( scope == null ) + // global hook; call all scopes + if ( !scope ) { - // null scope = global hook; call all scopes - vargv.insert(0,this) - foreach ( t in s_List ) + vargv.insert( 0, null ) + foreach( sc,t in s_List ) { if ( event in t ) { + vargv[0] = sc foreach( context, callback in t[event] ) { //printf( "(%.4f) Calling hook '%s' of context '%s' in static iteration\n", Time(), event, context ) @@ -241,7 +242,7 @@ Hooks <- local t = s_List[scope] if ( event in t ) { - vargv.insert(0,scope) + vargv.insert( 0, scope ) foreach( context, callback in t[event] ) { //printf( "(%.4f) Calling hook '%s' of context '%s'\n", Time(), event, context ) @@ -258,13 +259,7 @@ Hooks <- function ScopeHookedToEvent( scope, event ) { - if ( scope in s_List ) - { - if (event in s_List[scope]) - return true - } - - return false + return ( scope in s_List ) && ( event in s_List[scope] ) } } From 5e444b2db919f30f9ed79c6789dcaffc438b849c Mon Sep 17 00:00:00 2001 From: samisalreadytaken <46823719+samisalreadytaken@users.noreply.github.com> Date: Sun, 6 Mar 2022 18:46:00 +0300 Subject: [PATCH 318/378] Change CallClientScriptFunction UserMsg to EntityMsg --- .../shared/mapbase/logic_script_client.cpp | 42 +++++++++++++------ .../shared/mapbase/mapbase_usermessages.cpp | 31 -------------- 2 files changed, 30 insertions(+), 43 deletions(-) diff --git a/sp/src/game/shared/mapbase/logic_script_client.cpp b/sp/src/game/shared/mapbase/logic_script_client.cpp index 59f673dc..97edfe30 100644 --- a/sp/src/game/shared/mapbase/logic_script_client.cpp +++ b/sp/src/game/shared/mapbase/logic_script_client.cpp @@ -187,23 +187,41 @@ public: BaseClass::OnRestore(); } -#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) + void ReceiveMessage( int classID, bf_read &msg ) + { + if ( classID != GetClientClass()->m_ClassID ) { - Msg("%s CallScriptFunctionClient: \"%s\" is too long at %i characters, must be 64 or less\n", GetDebugName(), pszFunction, strlen(pszFunction)); + BaseClass::ReceiveMessage( classID, msg ); return; } - UserMessageBegin( filter, "CallClientScriptFunction" ); - WRITE_STRING( pszFunction ); // function - WRITE_SHORT( entindex() ); // entity + char szFunction[64]; + msg.ReadString( szFunction, sizeof( szFunction ) ); + + if ( m_ScriptScope.IsInitialized() ) + { + CallScriptFunction( szFunction, NULL ); + } + else + { + CGMsg( 0, CON_GROUP_VSCRIPT, "%s script scope not initialized!\n", GetDebugName() ); + } + } +#endif + +#ifdef GAME_DLL + void InputCallScriptFunctionClient( inputdata_t &inputdata ) + { + const char *pszFunction = inputdata.value.String(); + if ( V_strlen( pszFunction ) >= 64 ) + { + Msg( "%s CallScriptFunctionClient: \"%s\" is too long at %i characters, must be 64 or less\n", GetDebugName(), pszFunction, V_strlen(pszFunction)+1 ); + return; + } + + EntityMessageBegin( this, true ); + WRITE_STRING( pszFunction ); MessageEnd(); } #endif diff --git a/sp/src/game/shared/mapbase/mapbase_usermessages.cpp b/sp/src/game/shared/mapbase/mapbase_usermessages.cpp index 61cc4575..5af946e6 100644 --- a/sp/src/game/shared/mapbase/mapbase_usermessages.cpp +++ b/sp/src/game/shared/mapbase/mapbase_usermessages.cpp @@ -16,39 +16,9 @@ #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 ); //HOOK_MESSAGE( ScriptMsg ); // Hooked in CNetMsgScriptHelper } #endif @@ -56,7 +26,6 @@ void HookMapbaseUserMessages( void ) void RegisterMapbaseUserMessages( void ) { // VScript - usermessages->Register( "CallClientScriptFunction", -1 ); usermessages->Register( "ScriptMsg", -1 ); // CNetMsgScriptHelper #ifdef CLIENT_DLL From 4f7cac8178fccfab9b70e732e179367562dba3e9 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Tue, 8 Mar 2022 19:03:53 -0600 Subject: [PATCH 319/378] Added Mapbase version integer preprocessor --- sp/src/public/tier0/platform.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sp/src/public/tier0/platform.h b/sp/src/public/tier0/platform.h index 5afe5eea..7ed61545 100644 --- a/sp/src/public/tier0/platform.h +++ b/sp/src/public/tier0/platform.h @@ -1279,9 +1279,10 @@ PLATFORM_INTERFACE bool Is64BitOS(); #ifdef MAPBASE //----------------------------------------------------------------------------- -// General Mapbase version constant compiled into projects for versioning purposes +// General Mapbase version constants compiled into projects for versioning purposes //----------------------------------------------------------------------------- #define MAPBASE_VERSION "7.0" +#define MAPBASE_VER_INT 7000 // For use in #if in a similar fashion to macros like _MSC_VER #endif From 2aa17fff22440a681b6d795f8f7e97b1d36ca2b6 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Tue, 8 Mar 2022 19:14:53 -0600 Subject: [PATCH 320/378] Exposed Mapbase version integer to VScript --- sp/src/vscript/vscript_bindings_base.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/sp/src/vscript/vscript_bindings_base.cpp b/sp/src/vscript/vscript_bindings_base.cpp index e407af5e..69ca2187 100644 --- a/sp/src/vscript/vscript_bindings_base.cpp +++ b/sp/src/vscript/vscript_bindings_base.cpp @@ -460,6 +460,7 @@ void RegisterBaseBindings( IScriptVM *pVM ) //----------------------------------------------------------------------------- ScriptRegisterConstant( pVM, MAPBASE_VERSION, "The current Mapbase version according to when the VScript library was last compiled." ); + ScriptRegisterConstant( pVM, MAPBASE_VER_INT, "The current Mapbase version integer according to when the VScript library was last compiled." ); // // Math/world From 2282aedfa66ee76b0a4c0ff6f08bc5f1963feb21 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Tue, 8 Mar 2022 19:23:57 -0600 Subject: [PATCH 321/378] Added weapon script keyvalues for unique dropped model and whether or not to use the separate hands model --- sp/src/game/client/c_basecombatweapon.cpp | 10 ++++-- sp/src/game/server/basecombatweapon.cpp | 4 +++ .../game/shared/basecombatweapon_shared.cpp | 33 +++++++++++++++++++ sp/src/game/shared/basecombatweapon_shared.h | 5 +++ sp/src/game/shared/weapon_parse.cpp | 6 ++++ sp/src/game/shared/weapon_parse.h | 4 +++ 6 files changed, 60 insertions(+), 2 deletions(-) diff --git a/sp/src/game/client/c_basecombatweapon.cpp b/sp/src/game/client/c_basecombatweapon.cpp index b1973c51..3ae13cde 100644 --- a/sp/src/game/client/c_basecombatweapon.cpp +++ b/sp/src/game/client/c_basecombatweapon.cpp @@ -125,9 +125,15 @@ void C_BaseCombatWeapon::OnRestore() int C_BaseCombatWeapon::GetWorldModelIndex( void ) { +#ifdef MAPBASE + int iIndex = GetOwner() ? m_iWorldModelIndex.Get() : m_iDroppedModelIndex.Get(); +#else + int iIndex = m_iWorldModelIndex.Get(); +#endif + if ( GameRules() ) { - const char *pBaseName = modelinfo->GetModelName( modelinfo->GetModel( m_iWorldModelIndex ) ); + const char *pBaseName = modelinfo->GetModelName( modelinfo->GetModel( iIndex ) ); const char *pTranslatedName = GameRules()->TranslateEffectForVisionFilter( "weapons", pBaseName ); if ( pTranslatedName != pBaseName ) @@ -136,7 +142,7 @@ int C_BaseCombatWeapon::GetWorldModelIndex( void ) } } - return m_iWorldModelIndex; + return iIndex; } //----------------------------------------------------------------------------- diff --git a/sp/src/game/server/basecombatweapon.cpp b/sp/src/game/server/basecombatweapon.cpp index e49c1c1f..2863b747 100644 --- a/sp/src/game/server/basecombatweapon.cpp +++ b/sp/src/game/server/basecombatweapon.cpp @@ -487,7 +487,11 @@ void CBaseCombatWeapon::Kill( void ) //----------------------------------------------------------------------------- void CBaseCombatWeapon::FallInit( void ) { +#ifdef MAPBASE + SetModel( (GetDroppedModel() && GetDroppedModel()[0]) ? GetDroppedModel() : GetWorldModel() ); +#else SetModel( GetWorldModel() ); +#endif VPhysicsDestroyObject(); if ( !VPhysicsInitNormal( SOLID_BBOX, GetSolidFlags() | FSOLID_TRIGGER, false ) ) diff --git a/sp/src/game/shared/basecombatweapon_shared.cpp b/sp/src/game/shared/basecombatweapon_shared.cpp index 551fc52d..4b4d50c9 100644 --- a/sp/src/game/shared/basecombatweapon_shared.cpp +++ b/sp/src/game/shared/basecombatweapon_shared.cpp @@ -186,7 +186,11 @@ void CBaseCombatWeapon::Spawn( void ) if ( GetWorldModel() ) { +#ifdef MAPBASE + SetModel( (GetDroppedModel() && GetDroppedModel()[0]) ? GetDroppedModel() : GetWorldModel() ); +#else SetModel( GetWorldModel() ); +#endif } #if !defined( CLIENT_DLL ) @@ -291,6 +295,18 @@ void CBaseCombatWeapon::Precache( void ) { m_iWorldModelIndex = CBaseEntity::PrecacheModel( GetWorldModel() ); } +#ifdef MAPBASE + m_iDroppedModelIndex = 0; + if ( GetDroppedModel() && GetDroppedModel()[0] ) + { + m_iDroppedModelIndex = CBaseEntity::PrecacheModel( GetDroppedModel() ); + } + else + { + // Use the world model index + m_iDroppedModelIndex = m_iWorldModelIndex; + } +#endif // Precache sounds, too for ( int i = 0; i < NUM_SHOOT_SOUND_TYPES; ++i ) @@ -481,6 +497,16 @@ float CBaseCombatWeapon::GetSwaySpeedScale() const { return GetWpnData().m_flSwaySpeedScale; } + +const char *CBaseCombatWeapon::GetDroppedModel() const +{ + return GetWpnData().szDroppedModel; +} + +bool CBaseCombatWeapon::UsesHands() const +{ + return GetWpnData().m_bUsesHands; +} #endif //----------------------------------------------------------------------------- @@ -3008,6 +3034,7 @@ BEGIN_ENT_SCRIPTDESC( CBaseCombatWeapon, CBaseAnimating, "The base class for all DEFINE_SCRIPTFUNC( GetWorldModel, "Get the weapon's world model." ) DEFINE_SCRIPTFUNC( GetViewModel, "Get the weapon's view model." ) + DEFINE_SCRIPTFUNC( GetDroppedModel, "Get the weapon's unique dropped model if it has one." ) DEFINE_SCRIPTFUNC( GetWeight, "Get the weapon's weight." ) @@ -3302,6 +3329,9 @@ BEGIN_NETWORK_TABLE(CBaseCombatWeapon, DT_BaseCombatWeapon) SendPropDataTable("LocalActiveWeaponData", 0, &REFERENCE_SEND_TABLE(DT_LocalActiveWeaponData), SendProxy_SendActiveLocalWeaponDataTable ), SendPropModelIndex( SENDINFO(m_iViewModelIndex) ), SendPropModelIndex( SENDINFO(m_iWorldModelIndex) ), +#ifdef MAPBASE + SendPropModelIndex( SENDINFO(m_iDroppedModelIndex) ), +#endif SendPropInt( SENDINFO(m_iState ), 8, SPROP_UNSIGNED ), SendPropEHandle( SENDINFO(m_hOwner) ), @@ -3314,6 +3344,9 @@ BEGIN_NETWORK_TABLE(CBaseCombatWeapon, DT_BaseCombatWeapon) RecvPropDataTable("LocalActiveWeaponData", 0, 0, &REFERENCE_RECV_TABLE(DT_LocalActiveWeaponData)), RecvPropInt( RECVINFO(m_iViewModelIndex)), RecvPropInt( RECVINFO(m_iWorldModelIndex)), +#ifdef MAPBASE + RecvPropInt( RECVINFO(m_iDroppedModelIndex) ), +#endif RecvPropInt( RECVINFO(m_iState )), RecvPropEHandle( RECVINFO(m_hOwner ) ), diff --git a/sp/src/game/shared/basecombatweapon_shared.h b/sp/src/game/shared/basecombatweapon_shared.h index 88078e3e..9fda128a 100644 --- a/sp/src/game/shared/basecombatweapon_shared.h +++ b/sp/src/game/shared/basecombatweapon_shared.h @@ -422,6 +422,8 @@ public: float GetBobScale() const; float GetSwayScale() const; float GetSwaySpeedScale() const; + virtual const char *GetDroppedModel( void ) const; + bool UsesHands( void ) const; #endif // derive this function if you mod uses encrypted weapon info files @@ -681,6 +683,9 @@ public: // Weapon art CNetworkVar( int, m_iViewModelIndex ); CNetworkVar( int, m_iWorldModelIndex ); +#ifdef MAPBASE + CNetworkVar( int, m_iDroppedModelIndex ); +#endif // Sounds float m_flNextEmptySoundTime; // delay on empty sound playing diff --git a/sp/src/game/shared/weapon_parse.cpp b/sp/src/game/shared/weapon_parse.cpp index 54b9429a..d8844916 100644 --- a/sp/src/game/shared/weapon_parse.cpp +++ b/sp/src/game/shared/weapon_parse.cpp @@ -406,6 +406,8 @@ FileWeaponInfo_t::FileWeaponInfo_t() m_flBobScale = 1.0f; m_flSwayScale = 1.0f; m_flSwaySpeedScale = 1.0f; + szDroppedModel[0] = 0; + m_bUsesHands = false; #endif } @@ -477,6 +479,10 @@ void FileWeaponInfo_t::Parse( KeyValues *pKeyValuesData, const char *szWeaponNam m_flBobScale = pKeyValuesData->GetFloat( "bob_scale", 1.0f ); m_flSwayScale = pKeyValuesData->GetFloat( "sway_scale", 1.0f ); m_flSwaySpeedScale = pKeyValuesData->GetFloat( "sway_speed_scale", 1.0f ); + + Q_strncpy( szDroppedModel, pKeyValuesData->GetString( "droppedmodel" ), MAX_WEAPON_STRING ); + + m_bUsesHands = ( pKeyValuesData->GetInt( "uses_hands", 0 ) != 0 ) ? true : false; #endif #ifndef MAPBASE // Mapbase makes weapons in the same slot & position swap each other out, which is a feature mods can intentionally use. diff --git a/sp/src/game/shared/weapon_parse.h b/sp/src/game/shared/weapon_parse.h index d3995ee1..28032744 100644 --- a/sp/src/game/shared/weapon_parse.h +++ b/sp/src/game/shared/weapon_parse.h @@ -121,6 +121,10 @@ public: float m_flBobScale; float m_flSwayScale; float m_flSwaySpeedScale; + + char szDroppedModel[MAX_WEAPON_STRING]; // Model of this weapon when dropped on the ground + + bool m_bUsesHands; #endif // CLIENT DLL From dbb0ed6f469c95c4d541a9f076eafffe8cbd9d16 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Tue, 8 Mar 2022 19:25:55 -0600 Subject: [PATCH 322/378] Added gameinfo keyvalues for default hands models + code to hide custom hands on weapons which don't support them --- sp/src/game/server/player.cpp | 13 ++++ sp/src/game/shared/baseviewmodel_shared.cpp | 66 ++++++++++++++++--- sp/src/game/shared/mapbase/mapbase_shared.cpp | 8 +++ 3 files changed, 77 insertions(+), 10 deletions(-) diff --git a/sp/src/game/server/player.cpp b/sp/src/game/server/player.cpp index d713a8c3..6c78a3b5 100644 --- a/sp/src/game/server/player.cpp +++ b/sp/src/game/server/player.cpp @@ -632,6 +632,10 @@ void CBasePlayer::DestroyViewModels( void ) } #ifdef MAPBASE +extern char g_szDefaultHandsModel[MAX_PATH]; +extern int g_iDefaultHandsSkin; +extern int g_iDefaultHandsBody; + //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- @@ -648,6 +652,11 @@ void CBasePlayer::CreateHandModel(int index, int iOtherVm) vm->SetAbsOrigin(GetAbsOrigin()); vm->SetOwner(this); vm->SetIndex(index); + + vm->SetModel( g_szDefaultHandsModel ); + vm->m_nSkin = g_iDefaultHandsSkin; + vm->m_nBody = g_iDefaultHandsBody; + DispatchSpawn(vm); vm->FollowEntity(GetViewModel(iOtherVm), true); m_hViewModel.Set(index, vm); @@ -5418,6 +5427,10 @@ void CBasePlayer::Precache( void ) m_iTrain = TRAIN_NEW; #endif +#ifdef MAPBASE + PrecacheModel( g_szDefaultHandsModel ); +#endif + m_iClientBattery = -1; m_iUpdateTime = 5; // won't update for 1/2 a second diff --git a/sp/src/game/shared/baseviewmodel_shared.cpp b/sp/src/game/shared/baseviewmodel_shared.cpp index 7c4a4013..aa8ddbae 100644 --- a/sp/src/game/shared/baseviewmodel_shared.cpp +++ b/sp/src/game/shared/baseviewmodel_shared.cpp @@ -290,12 +290,15 @@ void CBaseViewModel::AddEffects( int nEffects ) } #ifdef MAPBASE - // Apply effect changes to any viewmodel children as well - // (fixes hand models) - for (CBaseEntity *pChild = FirstMoveChild(); pChild != NULL; pChild = pChild->NextMovePeer()) + if (GetOwningWeapon() && GetOwningWeapon()->UsesHands()) { - if (pChild->GetClassname()[0] == 'h') - pChild->AddEffects( nEffects ); + // If using hands, apply effect changes to any viewmodel children as well + // (fixes hand models) + for (CBaseEntity *pChild = FirstMoveChild(); pChild != NULL; pChild = pChild->NextMovePeer()) + { + if (pChild->GetClassname()[0] == 'h') + pChild->AddEffects( nEffects ); + } } #endif @@ -313,12 +316,15 @@ void CBaseViewModel::RemoveEffects( int nEffects ) } #ifdef MAPBASE - // Apply effect changes to any viewmodel children as well - // (fixes hand models) - for (CBaseEntity *pChild = FirstMoveChild(); pChild != NULL; pChild = pChild->NextMovePeer()) + if (GetOwningWeapon() && GetOwningWeapon()->UsesHands()) { - if (pChild->GetClassname()[0] == 'h') - pChild->RemoveEffects( nEffects ); + // If using hands, apply effect changes to any viewmodel children as well + // (fixes hand models) + for (CBaseEntity *pChild = FirstMoveChild(); pChild != NULL; pChild = pChild->NextMovePeer()) + { + if (pChild->GetClassname()[0] == 'h') + pChild->RemoveEffects( nEffects ); + } } #endif @@ -359,6 +365,18 @@ void CBaseViewModel::SetWeaponModel( const char *modelname, CBaseCombatWeapon *w SetControlPanelsActive( showControlPanels ); } #endif + +#ifdef MAPBASE + // If our owning weapon doesn't support hands, disable the hands viewmodel(s) + bool bSupportsHands = weapon->UsesHands(); + for (CBaseEntity *pChild = FirstMoveChild(); pChild != NULL; pChild = pChild->NextMovePeer()) + { + if (pChild->GetClassname()[0] == 'h') + { + bSupportsHands ? pChild->RemoveEffects( EF_NODRAW ) : pChild->AddEffects( EF_NODRAW ); + } + } +#endif } //----------------------------------------------------------------------------- @@ -754,7 +772,13 @@ class CHandViewModel : public CBaseViewModel DECLARE_CLASS( CHandViewModel, CBaseViewModel ); public: DECLARE_NETWORKCLASS(); + + CBaseViewModel *GetVMOwner(); + + CBaseCombatWeapon *GetOwningWeapon( void ); + private: + CHandle m_hVMOwner; }; LINK_ENTITY_TO_CLASS(hand_viewmodel, CHandViewModel); @@ -770,4 +794,26 @@ BEGIN_NETWORK_TABLE(CHandViewModel, DT_HandViewModel) RecvPropInt(RECVINFO_NAME(m_hNetworkMoveParent, moveparent), 0, RecvProxy_IntToMoveParent), #endif END_NETWORK_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CBaseViewModel *CHandViewModel::GetVMOwner() +{ + if (!m_hVMOwner) + m_hVMOwner = assert_cast(GetMoveParent()); + return m_hVMOwner; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CBaseCombatWeapon *CHandViewModel::GetOwningWeapon() +{ + CBaseViewModel *pVM = GetVMOwner(); + if (pVM) + return pVM->GetOwningWeapon(); + else + return NULL; +} #endif diff --git a/sp/src/game/shared/mapbase/mapbase_shared.cpp b/sp/src/game/shared/mapbase/mapbase_shared.cpp index 8550b6dc..fd4825de 100644 --- a/sp/src/game/shared/mapbase/mapbase_shared.cpp +++ b/sp/src/game/shared/mapbase/mapbase_shared.cpp @@ -86,6 +86,10 @@ char g_iszGameName[128]; // Default player configuration char g_szDefaultPlayerModel[MAX_PATH]; bool g_bDefaultPlayerDrawExternally; + +char g_szDefaultHandsModel[MAX_PATH]; +int g_iDefaultHandsSkin; +int g_iDefaultHandsBody; #endif enum @@ -226,6 +230,10 @@ public: #ifdef GAME_DLL Q_strncpy( g_szDefaultPlayerModel, gameinfo->GetString( "player_default_model", "models/player.mdl" ), sizeof( g_szDefaultPlayerModel ) ); g_bDefaultPlayerDrawExternally = gameinfo->GetBool( "player_default_draw_externally", false ); + + Q_strncpy( g_szDefaultHandsModel, gameinfo->GetString( "player_default_hands", "models/weapons/v_hands.mdl" ), sizeof( g_szDefaultHandsModel ) ); + g_iDefaultHandsSkin = gameinfo->GetInt( "player_default_hands_skin", 0 ); + g_iDefaultHandsBody = gameinfo->GetInt( "player_default_hands_body", 0 ); #endif } gameinfo->deleteThis(); From 670465dc5885e2cd098b592b5b2f7f6a38337031 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Tue, 8 Mar 2022 19:45:42 -0600 Subject: [PATCH 323/378] Fixed companion melee damage not saving/restoring --- sp/src/game/server/hl2/npc_playercompanion.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sp/src/game/server/hl2/npc_playercompanion.cpp b/sp/src/game/server/hl2/npc_playercompanion.cpp index 08def106..68568a72 100644 --- a/sp/src/game/server/hl2/npc_playercompanion.cpp +++ b/sp/src/game/server/hl2/npc_playercompanion.cpp @@ -156,6 +156,10 @@ BEGIN_DATADESC( CNPC_PlayerCompanion ) DEFINE_INPUT( m_iGrenadeDropCapabilities, FIELD_INTEGER, "SetGrenadeDropCapabilities" ), #endif +#ifdef COMPANION_MELEE_ATTACK + DEFINE_FIELD( m_nMeleeDamage, FIELD_INTEGER ), +#endif + END_DATADESC() //----------------------------------------------------------------------------- From f79515fc11452d36c154d39c0b1a501dd4925d80 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Wed, 9 Mar 2022 14:10:11 -0600 Subject: [PATCH 324/378] Redid parts of backup activity system to support weapon act table recursion --- sp/src/game/server/basecombatcharacter.cpp | 58 ++++++++++---- .../game/server/hl2/ai_behavior_actbusy.cpp | 18 ----- sp/src/game/server/hl2/ai_behavior_actbusy.h | 3 - sp/src/game/server/hl2/weapon_357.cpp | 11 +++ .../game/shared/basecombatweapon_shared.cpp | 80 +++++++++++++++++-- sp/src/game/shared/basecombatweapon_shared.h | 1 + 6 files changed, 127 insertions(+), 44 deletions(-) diff --git a/sp/src/game/server/basecombatcharacter.cpp b/sp/src/game/server/basecombatcharacter.cpp index c0bb5f1b..990b4214 100644 --- a/sp/src/game/server/basecombatcharacter.cpp +++ b/sp/src/game/server/basecombatcharacter.cpp @@ -2725,6 +2725,35 @@ bool CBaseCombatCharacter::Weapon_CanUse( CBaseCombatWeapon *pWeapon ) } #ifdef MAPBASE + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +static Activity Weapon_BackupActivityFromList( CBaseCombatCharacter *pBCC, acttable_t *pTable, int actCount, Activity activity, bool weaponTranslationWasRequired, CBaseCombatWeapon *pWeapon ) +{ + int i = 0; + for ( ; i < actCount; i++, pTable++ ) + { + if ( activity == pTable->baseAct ) + { + // Don't pick backup activities we don't actually have an animation for. + if (!pBCC->GetModelPtr()->HaveSequenceForActivity(pTable->weaponAct)) + break; + + return (Activity)pTable->weaponAct; + } + } + + // We didn't succeed in finding an activity. See if we can recurse + acttable_t *pBackupTable = CBaseCombatWeapon::GetDefaultBackupActivityList( pTable - i, actCount ); + if (pBackupTable) + { + return Weapon_BackupActivityFromList( pBCC, pBackupTable, actCount, activity, weaponTranslationWasRequired, pWeapon ); + } + + return activity; +} + //----------------------------------------------------------------------------- // Purpose: Uses an activity from a different weapon when the activity we were originally looking for does not exist on this character. // This gives NPCs and players the ability to use weapons they are otherwise unable to use. @@ -2739,30 +2768,27 @@ Activity CBaseCombatCharacter::Weapon_BackupActivity( Activity activity, bool we if (!pWeapon->SupportsBackupActivity(activity)) return activity; - // Sometimes, a NPC is supposed to use the default activity. Return that if the weapon translation was "not required" and we have an original activity. - // Don't do this with players. + // UNDONE: Sometimes, a NPC is supposed to use the default activity. Return that if the weapon translation was "not required" and we have an original activity. + /* if (!weaponTranslationWasRequired && GetModelPtr()->HaveSequenceForActivity(activity) && !IsPlayer()) { return activity; } + */ acttable_t *pTable = pWeapon->GetBackupActivityList(); - if (pTable) + int actCount = pWeapon->GetBackupActivityListCount(); + if (!pTable) + { + // Look for a default list + actCount = pWeapon->ActivityListCount(); + pTable = CBaseCombatWeapon::GetDefaultBackupActivityList( pWeapon->ActivityList(), actCount ); + } + + if (pTable && GetModelPtr()) { int actCount = pWeapon->GetBackupActivityListCount(); - for ( int i = 0; i < actCount; i++, pTable++ ) - { - if ( activity == pTable->baseAct ) - { - // Don't pick backup activities we don't actually have an animation for. - if (GetModelPtr() ? !GetModelPtr()->HaveSequenceForActivity(pTable->weaponAct) : false) - { - return activity; - } - - return (Activity)pTable->weaponAct; - } - } + return Weapon_BackupActivityFromList( this, pTable, actCount, activity, weaponTranslationWasRequired, pWeapon ); } return activity; diff --git a/sp/src/game/server/hl2/ai_behavior_actbusy.cpp b/sp/src/game/server/hl2/ai_behavior_actbusy.cpp index 069960f6..c5ad733d 100644 --- a/sp/src/game/server/hl2/ai_behavior_actbusy.cpp +++ b/sp/src/game/server/hl2/ai_behavior_actbusy.cpp @@ -1802,20 +1802,6 @@ bool CAI_ActBusyBehavior::PlayAnimForActBusy( busyanimparts_t AnimPart ) return false; } -#ifdef MAPBASE -//----------------------------------------------------------------------------- -// Purpose: Get the busy's move activity -//----------------------------------------------------------------------------- -Activity CAI_ActBusyBehavior::GetMoveActivityForActBusy() -{ - busyanim_t *pBusyAnim = g_ActBusyAnimDataSystem.GetBusyAnim( m_iCurrentBusyAnim ); - if ( !pBusyAnim ) - return m_ForcedActivity; - - return pBusyAnim->bTranslateActivity ? GetOuter()->TranslateActivity( m_ForcedActivity ) : m_ForcedActivity; -} -#endif - //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- @@ -2044,11 +2030,7 @@ void CAI_ActBusyBehavior::StartTask( const Task_t *pTask ) // If we have a forced activity, use that. Otherwise, walk. if ( m_ForcedActivity != ACT_INVALID && m_ForcedActivity != ACT_RESET ) { -#ifdef MAPBASE - GetNavigator()->SetMovementActivity( GetMoveActivityForActBusy() ); -#else GetNavigator()->SetMovementActivity( m_ForcedActivity ); -#endif // Cover is void once I move Forget( bits_MEMORY_INCOVER ); diff --git a/sp/src/game/server/hl2/ai_behavior_actbusy.h b/sp/src/game/server/hl2/ai_behavior_actbusy.h index 63ebecec..264fdb3d 100644 --- a/sp/src/game/server/hl2/ai_behavior_actbusy.h +++ b/sp/src/game/server/hl2/ai_behavior_actbusy.h @@ -167,9 +167,6 @@ private: void NotifyBusyEnding( void ); bool HasAnimForActBusy( int iActBusy, busyanimparts_t AnimPart ); bool PlayAnimForActBusy( busyanimparts_t AnimPart ); -#ifdef MAPBASE - Activity GetMoveActivityForActBusy(); -#endif void PlaySoundForActBusy( busyanimparts_t AnimPart ); private: diff --git a/sp/src/game/server/hl2/weapon_357.cpp b/sp/src/game/server/hl2/weapon_357.cpp index ac415c9e..a3c05371 100644 --- a/sp/src/game/server/hl2/weapon_357.cpp +++ b/sp/src/game/server/hl2/weapon_357.cpp @@ -225,6 +225,17 @@ acttable_t CWeapon357::m_acttable[] = IMPLEMENT_ACTTABLE( CWeapon357 ); + +// Allows Weapon_BackupActivity() to access the 357's activity table. +acttable_t *Get357Acttable() +{ + return CWeapon357::m_acttable; +} + +int Get357ActtableCount() +{ + return ARRAYSIZE(CWeapon357::m_acttable); +} #endif //----------------------------------------------------------------------------- diff --git a/sp/src/game/shared/basecombatweapon_shared.cpp b/sp/src/game/shared/basecombatweapon_shared.cpp index 4b4d50c9..22fe8b97 100644 --- a/sp/src/game/shared/basecombatweapon_shared.cpp +++ b/sp/src/game/shared/basecombatweapon_shared.cpp @@ -1100,6 +1100,11 @@ WeaponClass_t CBaseCombatWeapon::WeaponClassify() case ACT_IDLE_ANGRY_PISTOL: return WEPCLASS_HANDGUN; #if EXPANDED_HL2_WEAPON_ACTIVITIES case ACT_IDLE_ANGRY_CROSSBOW: // For now, crossbows are rifles +#endif +#if EXPANDED_HL2_UNUSED_WEAPON_ACTIVITIES + case ACT_IDLE_ANGRY_AR1: + case ACT_IDLE_ANGRY_SMG2: + case ACT_IDLE_ANGRY_SNIPER_RIFLE: #endif case ACT_IDLE_ANGRY_SMG1: case ACT_IDLE_ANGRY_AR2: return WEPCLASS_RIFLE; @@ -1134,6 +1139,18 @@ WeaponClass_t CBaseCombatWeapon::WeaponClassFromString(const char *str) #ifdef HL2_DLL extern acttable_t *GetSMG1Acttable(); extern int GetSMG1ActtableCount(); + +extern acttable_t *GetAR2Acttable(); +extern int GetAR2ActtableCount(); + +extern acttable_t *GetShotgunActtable(); +extern int GetShotgunActtableCount(); + +extern acttable_t *GetPistolActtable(); +extern int GetPistolActtableCount(); + +extern acttable_t *Get357Acttable(); +extern int Get357ActtableCount(); #endif //----------------------------------------------------------------------------- @@ -1154,20 +1171,69 @@ bool CBaseCombatWeapon::SupportsBackupActivity(Activity activity) acttable_t *CBaseCombatWeapon::GetBackupActivityList() { -#ifdef HL2_DLL - return GetSMG1Acttable(); -#else return NULL; -#endif } int CBaseCombatWeapon::GetBackupActivityListCount() { -#ifdef HL2_DLL - return GetSMG1ActtableCount(); -#else return 0; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +acttable_t *CBaseCombatWeapon::GetDefaultBackupActivityList( acttable_t *pTable, int &actCount ) +{ +#ifdef HL2_DLL + // Ensure this isn't already a default backup activity list + if (pTable == GetSMG1Acttable() || pTable == GetPistolActtable()) + return NULL; + + // Use a backup table based on what ACT_IDLE_ANGRY is translated to + Activity actTranslated = ACT_INVALID; + for ( int i = 0; i < actCount; i++, pTable++ ) + { + if ( pTable->baseAct == ACT_IDLE_ANGRY ) + { + actTranslated = (Activity)pTable->weaponAct; + break; + } + } + + if (actTranslated == ACT_INVALID) + return NULL; + + switch (actTranslated) + { +#if EXPANDED_HL2_WEAPON_ACTIVITIES + case ACT_IDLE_ANGRY_REVOLVER: #endif + case ACT_IDLE_ANGRY_PISTOL: + { + actCount = GetPistolActtableCount(); + return GetPistolActtable(); + } +#if EXPANDED_HL2_WEAPON_ACTIVITIES + case ACT_IDLE_ANGRY_CROSSBOW: // For now, crossbows are rifles +#endif +#if EXPANDED_HL2_UNUSED_WEAPON_ACTIVITIES + case ACT_IDLE_ANGRY_AR1: + case ACT_IDLE_ANGRY_SMG2: + case ACT_IDLE_ANGRY_SNIPER_RIFLE: +#endif + case ACT_IDLE_ANGRY_SMG1: + case ACT_IDLE_ANGRY_AR2: + case ACT_IDLE_ANGRY_SHOTGUN: + case ACT_IDLE_ANGRY_RPG: + { + actCount = GetSMG1ActtableCount(); + return GetSMG1Acttable(); + } + } +#endif + + actCount = 0; + return NULL; } #endif diff --git a/sp/src/game/shared/basecombatweapon_shared.h b/sp/src/game/shared/basecombatweapon_shared.h index 9fda128a..bd439b8c 100644 --- a/sp/src/game/shared/basecombatweapon_shared.h +++ b/sp/src/game/shared/basecombatweapon_shared.h @@ -232,6 +232,7 @@ public: virtual bool SupportsBackupActivity(Activity activity); virtual acttable_t *GetBackupActivityList(); virtual int GetBackupActivityListCount(); + static acttable_t *GetDefaultBackupActivityList( acttable_t *pTable, int &actCount ); #endif virtual void Equip( CBaseCombatCharacter *pOwner ); From bb2478f342036fb5f4d6bc4a0e11778f3522dd85 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Wed, 9 Mar 2022 14:12:28 -0600 Subject: [PATCH 325/378] Added VScript functions for giving/removing ammo --- sp/src/game/server/basecombatcharacter.cpp | 22 ++++++++++++++++++++++ sp/src/game/server/basecombatcharacter.h | 4 +++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/sp/src/game/server/basecombatcharacter.cpp b/sp/src/game/server/basecombatcharacter.cpp index 990b4214..f4b35392 100644 --- a/sp/src/game/server/basecombatcharacter.cpp +++ b/sp/src/game/server/basecombatcharacter.cpp @@ -163,6 +163,8 @@ BEGIN_ENT_SCRIPTDESC( CBaseCombatCharacter, CBaseFlex, "The base class shared by DEFINE_SCRIPTFUNC_NAMED( ScriptEquipWeapon, "EquipWeapon", "Make the character equip the specified weapon entity. If they don't already own the weapon, they will acquire it instantly." ) DEFINE_SCRIPTFUNC_NAMED( ScriptDropWeapon, "DropWeapon", "Make the character drop the specified weapon entity if they own it." ) + DEFINE_SCRIPTFUNC_NAMED( ScriptGiveAmmo, "GiveAmmo", "Gives the specified amount of the specified ammo type. The third parameter is whether or not to suppress the ammo pickup sound. Returns the amount of ammo actually given, which is 0 if the player's ammo for this type is already full." ) + DEFINE_SCRIPTFUNC_NAMED( ScriptRemoveAmmo, "RemoveAmmo", "Removes the specified amount of the specified ammo type." ) DEFINE_SCRIPTFUNC_NAMED( ScriptGetAmmoCount, "GetAmmoCount", "Get the ammo count of the specified ammo type." ) DEFINE_SCRIPTFUNC_NAMED( ScriptSetAmmoCount, "SetAmmoCount", "Set the ammo count of the specified ammo type." ) @@ -4541,6 +4543,26 @@ void CBaseCombatCharacter::ScriptEquipWeapon( HSCRIPT hWeapon ) } } +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +int CBaseCombatCharacter::ScriptGiveAmmo( int iCount, int iAmmoIndex, bool bSuppressSound ) +{ + return GiveAmmo( iCount, iAmmoIndex, bSuppressSound ); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CBaseCombatCharacter::ScriptRemoveAmmo( int iCount, int iAmmoIndex ) +{ + if (iAmmoIndex == -1) + { + Warning( "%i is not a valid ammo type\n", iAmmoIndex ); + return; + } + + RemoveAmmo( iCount, iAmmoIndex ); +} + //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- int CBaseCombatCharacter::ScriptGetAmmoCount( int iType ) const diff --git a/sp/src/game/server/basecombatcharacter.h b/sp/src/game/server/basecombatcharacter.h index ccdd16c8..bf07ee15 100644 --- a/sp/src/game/server/basecombatcharacter.h +++ b/sp/src/game/server/basecombatcharacter.h @@ -428,7 +428,9 @@ public: void ScriptDropWeapon( HSCRIPT hWeapon ); void ScriptEquipWeapon( HSCRIPT hWeapon ); - + + int ScriptGiveAmmo( int iCount, int iAmmoIndex, bool bSuppressSound = false ); + void ScriptRemoveAmmo( int iCount, int iAmmoIndex ); int ScriptGetAmmoCount( int iType ) const; void ScriptSetAmmoCount( int iType, int iCount ); From e4d5d946d296bfec5d1652546f544457713ddb8a Mon Sep 17 00:00:00 2001 From: Blixibon Date: Wed, 9 Mar 2022 14:14:12 -0600 Subject: [PATCH 326/378] Fixed activator, caller, etc. values not working within RunScriptCode and related inputs --- sp/src/game/server/baseentity.cpp | 17 +++++++++++++++-- sp/src/game/server/baseentity.h | 1 + 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/sp/src/game/server/baseentity.cpp b/sp/src/game/server/baseentity.cpp index fd31f792..42f857de 100644 --- a/sp/src/game/server/baseentity.cpp +++ b/sp/src/game/server/baseentity.cpp @@ -4674,6 +4674,11 @@ bool CBaseEntity::AcceptInput( const char *szInputName, CBaseEntity *pActivator, { (this->*pfnInput)( data ); } + + if ( m_ScriptScope.IsInitialized() ) + { + ScriptInputHookClearParams(); + } } else if ( dmap->dataDesc[i].flags & FTYPEDESC_KEY ) { @@ -4707,6 +4712,8 @@ bool CBaseEntity::AcceptInput( const char *szInputName, CBaseEntity *pActivator, if (functionReturn.m_bool) return true; } + + ScriptInputHookClearParams(); } #endif @@ -4750,13 +4757,19 @@ bool CBaseEntity::ScriptInputHook( const char *szInputName, CBaseEntity *pActiva bHandled = true; } + return bHandled; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CBaseEntity::ScriptInputHookClearParams() +{ g_pScriptVM->ClearValue( "activator" ); g_pScriptVM->ClearValue( "caller" ); #ifdef MAPBASE_VSCRIPT g_pScriptVM->ClearValue( "parameter" ); #endif - - return bHandled; } #ifdef MAPBASE_VSCRIPT diff --git a/sp/src/game/server/baseentity.h b/sp/src/game/server/baseentity.h index ab45b27a..1f2f75e1 100644 --- a/sp/src/game/server/baseentity.h +++ b/sp/src/game/server/baseentity.h @@ -693,6 +693,7 @@ public: #endif bool ScriptInputHook( const char *szInputName, CBaseEntity *pActivator, CBaseEntity *pCaller, variant_t Value, ScriptVariant_t &functionReturn ); + void ScriptInputHookClearParams(); #ifdef MAPBASE_VSCRIPT bool ScriptDeathHook( CTakeDamageInfo *info ); #endif From f8a8d49be7ba5269a4ad710cafe7d167c65d2c05 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Wed, 9 Mar 2022 14:14:50 -0600 Subject: [PATCH 327/378] Added GetViewModel function for VScript --- sp/src/game/server/player.cpp | 15 +++++++++++++++ sp/src/game/server/player.h | 2 ++ 2 files changed, 17 insertions(+) diff --git a/sp/src/game/server/player.cpp b/sp/src/game/server/player.cpp index 6c78a3b5..00aefbb8 100644 --- a/sp/src/game/server/player.cpp +++ b/sp/src/game/server/player.cpp @@ -551,6 +551,8 @@ BEGIN_ENT_SCRIPTDESC( CBasePlayer, CBaseCombatCharacter, "The player entity." ) DEFINE_SCRIPTFUNC_NAMED( ScriptGetEyeRight, "GetEyeRight", "Gets the player's right eye vector." ) DEFINE_SCRIPTFUNC_NAMED( ScriptGetEyeUp, "GetEyeUp", "Gets the player's up eye vector." ) + DEFINE_SCRIPTFUNC_NAMED( ScriptGetViewModel, "GetViewModel", "Returns the viewmodel of the specified index." ) + // // Hooks // @@ -7148,6 +7150,19 @@ HSCRIPT CBasePlayer::VScriptGetExpresser() return hScript; } + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +HSCRIPT CBasePlayer::ScriptGetViewModel( int viewmodelindex ) +{ + if (viewmodelindex < 0 || viewmodelindex >= MAX_VIEWMODELS) + { + Warning( "GetViewModel: Invalid index '%i'\n", viewmodelindex ); + return NULL; + } + + return ToHScript( GetViewModel( viewmodelindex ) ); +} #endif //----------------------------------------------------------------------------- diff --git a/sp/src/game/server/player.h b/sp/src/game/server/player.h index 05bf335b..0bfba8fb 100644 --- a/sp/src/game/server/player.h +++ b/sp/src/game/server/player.h @@ -412,6 +412,8 @@ public: const Vector& ScriptGetEyeForward() { static Vector vecForward; EyeVectors( &vecForward, NULL, NULL ); return vecForward; } const Vector& ScriptGetEyeRight() { static Vector vecRight; EyeVectors( NULL, &vecRight, NULL ); return vecRight; } const Vector& ScriptGetEyeUp() { static Vector vecUp; EyeVectors( NULL, NULL, &vecUp ); return vecUp; } + + HSCRIPT ScriptGetViewModel( int viewmodelindex ); #endif // View model prediction setup From f98445e33f2149b4dad3d02f765241b20c80436d Mon Sep 17 00:00:00 2001 From: samisalreadytaken <46823719+samisalreadytaken@users.noreply.github.com> Date: Fri, 18 Mar 2022 18:30:00 +0300 Subject: [PATCH 328/378] Restrict vscript concommands --- sp/src/game/shared/vscript_shared.cpp | 53 +++++++++++++++++++++++---- 1 file changed, 45 insertions(+), 8 deletions(-) diff --git a/sp/src/game/shared/vscript_shared.cpp b/sp/src/game/shared/vscript_shared.cpp index 86e220b4..088c19a7 100644 --- a/sp/src/game/shared/vscript_shared.cpp +++ b/sp/src/game/shared/vscript_shared.cpp @@ -170,12 +170,22 @@ bool VScriptRunScript( const char *pszScriptName, HSCRIPT hScope, bool bWarnMiss return bSuccess; } -#ifdef CLIENT_DLL -CON_COMMAND( script_client, "Run the text as a script" ) + +#ifdef GAME_DLL +#define IsCommandIssuedByServerAdmin() UTIL_IsCommandIssuedByServerAdmin() #else -CON_COMMAND( script, "Run the text as a script" ) +#define IsCommandIssuedByServerAdmin() true +#endif + +#ifdef CLIENT_DLL +CON_COMMAND_F( script_client, "Run the text as a script", FCVAR_CHEAT ) +#else +CON_COMMAND_F( script, "Run the text as a script", FCVAR_CHEAT ) #endif { + if ( !IsCommandIssuedByServerAdmin() ) + return; + if ( !*args[1] ) { CGWarning( 0, CON_GROUP_VSCRIPT, "No function name specified\n" ); @@ -228,9 +238,15 @@ CON_COMMAND( script, "Run the text as a script" ) } } - -CON_COMMAND_SHARED( script_execute, "Run a vscript file" ) +#ifdef CLIENT_DLL +CON_COMMAND_F( script_execute_client, "Run a vscript file", FCVAR_CHEAT ) +#else +CON_COMMAND_F( script_execute, "Run a vscript file", FCVAR_CHEAT ) +#endif { + if ( !IsCommandIssuedByServerAdmin() ) + return; + if ( !*args[1] ) { CGWarning( 0, CON_GROUP_VSCRIPT, "No script specified\n" ); @@ -246,8 +262,15 @@ CON_COMMAND_SHARED( script_execute, "Run a vscript file" ) VScriptRunScript( args[1], true ); } -CON_COMMAND_SHARED( script_debug, "Connect the vscript VM to the script debugger" ) +#ifdef CLIENT_DLL +CON_COMMAND_F( script_debug_client, "Connect the vscript VM to the script debugger", FCVAR_CHEAT ) +#else +CON_COMMAND_F( script_debug, "Connect the vscript VM to the script debugger", FCVAR_CHEAT ) +#endif { + if ( !IsCommandIssuedByServerAdmin() ) + return; + if ( !g_pScriptVM ) { CGWarning( 0, CON_GROUP_VSCRIPT, "Scripting disabled or no server running\n" ); @@ -256,8 +279,15 @@ CON_COMMAND_SHARED( script_debug, "Connect the vscript VM to the script debugger g_pScriptVM->ConnectDebugger(); } -CON_COMMAND_SHARED( script_help, "Output help for script functions, optionally with a search string" ) +#ifdef CLIENT_DLL +CON_COMMAND_F( script_help_client, "Output help for script functions, optionally with a search string", FCVAR_CHEAT ) +#else +CON_COMMAND_F( script_help, "Output help for script functions, optionally with a search string", FCVAR_CHEAT ) +#endif { + if ( !IsCommandIssuedByServerAdmin() ) + return; + if ( !g_pScriptVM ) { CGWarning( 0, CON_GROUP_VSCRIPT, "Scripting disabled or no server running\n" ); @@ -272,8 +302,15 @@ CON_COMMAND_SHARED( script_help, "Output help for script functions, optionally w g_pScriptVM->Run( CFmtStr( "__Documentation.PrintHelp( \"%s\" );", pszArg1 ) ); } -CON_COMMAND_SHARED( script_dump_all, "Dump the state of the VM to the console" ) +#ifdef CLIENT_DLL +CON_COMMAND_F( script_dump_all_client, "Dump the state of the VM to the console", FCVAR_CHEAT ) +#else +CON_COMMAND_F( script_dump_all, "Dump the state of the VM to the console", FCVAR_CHEAT ) +#endif { + if ( !IsCommandIssuedByServerAdmin() ) + return; + if ( !g_pScriptVM ) { CGWarning( 0, CON_GROUP_VSCRIPT, "Scripting disabled or no server running\n" ); From c28349daaf390c2b43f247ad5f5cfb9763bc08ce Mon Sep 17 00:00:00 2001 From: samisalreadytaken <46823719+samisalreadytaken@users.noreply.github.com> Date: Fri, 18 Mar 2022 18:32:00 +0300 Subject: [PATCH 329/378] Add script funcs: - CBaseAnimating::ResetSequenceInfo() - CBaseAnimating::StudioFrameAdvance() --- sp/src/game/server/baseanimating.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sp/src/game/server/baseanimating.cpp b/sp/src/game/server/baseanimating.cpp index 1db0693a..74a9343e 100644 --- a/sp/src/game/server/baseanimating.cpp +++ b/sp/src/game/server/baseanimating.cpp @@ -305,7 +305,7 @@ BEGIN_ENT_SCRIPTDESC( CBaseAnimating, CBaseEntity, "Animating models" ) DEFINE_SCRIPTFUNC( GetNumBones, "Get the number of bones" ) DEFINE_SCRIPTFUNC( GetSequence, "Gets the current sequence" ) DEFINE_SCRIPTFUNC( SetSequence, "Sets the current sequence" ) - DEFINE_SCRIPTFUNC( SequenceLoops, "Loops the current sequence" ) + DEFINE_SCRIPTFUNC( SequenceLoops, "Does the current sequence loop?" ) DEFINE_SCRIPTFUNC_NAMED( ScriptSequenceDuration, "SequenceDuration", "Get the specified sequence duration" ) DEFINE_SCRIPTFUNC( LookupSequence, "Gets the index of the specified sequence name" ) DEFINE_SCRIPTFUNC( LookupActivity, "Gets the ID of the specified activity name" ) @@ -318,6 +318,8 @@ BEGIN_ENT_SCRIPTDESC( CBaseAnimating, CBaseEntity, "Animating models" ) DEFINE_SCRIPTFUNC_NAMED( ScriptSelectWeightedSequence, "SelectWeightedSequence", "Selects a sequence for the specified activity ID" ) DEFINE_SCRIPTFUNC_NAMED( ScriptSelectHeaviestSequence, "SelectHeaviestSequence", "Selects the sequence with the heaviest weight for the specified activity ID" ) DEFINE_SCRIPTFUNC_NAMED( ScriptGetSequenceKeyValues, "GetSequenceKeyValues", "Get a KeyValue class instance on the specified sequence. WARNING: This uses the same KeyValue pointer as GetModelKeyValues!" ) + DEFINE_SCRIPTFUNC( ResetSequenceInfo, "" ) + DEFINE_SCRIPTFUNC( StudioFrameAdvance, "" ) DEFINE_SCRIPTFUNC( GetPlaybackRate, "" ) DEFINE_SCRIPTFUNC( SetPlaybackRate, "" ) DEFINE_SCRIPTFUNC( GetCycle, "" ) From 493ff43ffe494128b503b7f128d58053a01fcec8 Mon Sep 17 00:00:00 2001 From: samisalreadytaken <46823719+samisalreadytaken@users.noreply.github.com> Date: Fri, 18 Mar 2022 18:32:20 +0300 Subject: [PATCH 330/378] Add script consts: SERVER_DLL, CLIENT_DLL --- sp/src/game/shared/mapbase/vscript_consts_shared.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sp/src/game/shared/mapbase/vscript_consts_shared.cpp b/sp/src/game/shared/mapbase/vscript_consts_shared.cpp index 0bcdd8ae..2ced7086 100644 --- a/sp/src/game/shared/mapbase/vscript_consts_shared.cpp +++ b/sp/src/game/shared/mapbase/vscript_consts_shared.cpp @@ -126,6 +126,15 @@ extern void RegisterWeaponScriptConstants(); void RegisterSharedScriptConstants() { + // "SERVER_DLL" is used in Source 2. +#ifdef GAME_DLL + ScriptRegisterConstantNamed( g_pScriptVM, 1, "SERVER_DLL", "" ); + ScriptRegisterConstantNamed( g_pScriptVM, 0, "CLIENT_DLL", "" ); +#else + ScriptRegisterConstantNamed( g_pScriptVM, 0, "SERVER_DLL", "" ); + ScriptRegisterConstantNamed( g_pScriptVM, 1, "CLIENT_DLL", "" ); +#endif + // // Activities // From f9d88b15ac91f9b561983ba7bc8103116afdc623 Mon Sep 17 00:00:00 2001 From: Peter Covington Date: Fri, 15 Apr 2022 09:59:17 -0400 Subject: [PATCH 331/378] NPCs can load dynamic interactions from all animation MDLs --- sp/src/game/server/ai_basenpc.cpp | 471 ++++++++++++++++-------------- 1 file changed, 251 insertions(+), 220 deletions(-) diff --git a/sp/src/game/server/ai_basenpc.cpp b/sp/src/game/server/ai_basenpc.cpp index c5fa8c7b..f1f72307 100644 --- a/sp/src/game/server/ai_basenpc.cpp +++ b/sp/src/game/server/ai_basenpc.cpp @@ -14719,326 +14719,356 @@ bool CAI_BaseNPC::IsAllowedToDodge( void ) //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- -void CAI_BaseNPC::ParseScriptedNPCInteractions( void ) +void CAI_BaseNPC::ParseScriptedNPCInteractions(void) { // Already parsed them? - if ( m_ScriptedInteractions.Count() ) + if (m_ScriptedInteractions.Count()) return; // Parse the model's key values and find any dynamic interactions - KeyValues *modelKeyValues = new KeyValues(""); - CUtlBuffer buf( 1024, 0, CUtlBuffer::TEXT_BUFFER ); + KeyValues* modelKeyValues = new KeyValues(""); + CUtlBuffer buf(1024, 0, CUtlBuffer::TEXT_BUFFER); - if (! modelinfo->GetModelKeyValue( GetModel(), buf )) + if (!modelinfo->GetModelKeyValue(GetModel(), buf)) return; - - if ( modelKeyValues->LoadFromBuffer( modelinfo->GetModelName( GetModel() ), buf ) ) + + if (modelKeyValues->LoadFromBuffer(modelinfo->GetModelName(GetModel()), buf)) { - // Do we have a dynamic interactions section? - KeyValues *pkvInteractions = modelKeyValues->FindKey("dynamic_interactions"); - if ( pkvInteractions ) - { - KeyValues *pkvNode = pkvInteractions->GetFirstSubKey(); - while ( pkvNode ) - { - ScriptedNPCInteraction_t sInteraction; - sInteraction.iszInteractionName = AllocPooledString( pkvNode->GetName() ); - #ifdef MAPBASE - // The method for parsing dynamic interactions has been reworked. - // Unknown values are now stored as response contexts to test against response criteria. - - bool bValidInteraction = true; - - // Default values - UTIL_StringToVector( sInteraction.vecRelativeOrigin.Base(), "0 0 0" ); - sInteraction.flDelay = 10.0; - sInteraction.flDistSqr = (DSS_MAX_DIST * DSS_MAX_DIST); - - // Misc. response criteria - char *szCriteria = ""; - - KeyValues *pCurNode = pkvNode->GetFirstSubKey(); - const char *szName = NULL; - const char *szValue = NULL; - while (pCurNode) + CUtlVector iszUsedNames; + for (KeyValues* pkvModelBlock = modelKeyValues; pkvModelBlock != nullptr; pkvModelBlock = pkvModelBlock->GetNextKey()) + { + // Do we have a dynamic interactions section? + KeyValues* pkvInteractions = pkvModelBlock->FindKey("dynamic_interactions"); + if (pkvInteractions) + { + KeyValues* pkvNode = pkvInteractions->GetFirstSubKey(); + while (pkvNode) { - szName = pCurNode->GetName(); - szValue = pCurNode->GetString(); + ScriptedNPCInteraction_t sInteraction; + sInteraction.iszInteractionName = AllocPooledString(pkvNode->GetName()); - if (!szName || !szValue) + if (iszUsedNames.Find(sInteraction.iszInteractionName) != iszUsedNames.InvalidIndex()) { - DevWarning("ERROR: Invalid dynamic interaction string\n"); + DevMsg(2, "Scripted interaction %s already defined on %s\n", pkvNode->GetName(), GetClassname()); + pkvNode = pkvNode->GetNextKey(); + continue; + } + + // The method for parsing dynamic interactions has been reworked. + // Unknown values are now stored as response contexts to test against response criteria. + + bool bValidInteraction = true; + + // Default values + UTIL_StringToVector(sInteraction.vecRelativeOrigin.Base(), "0 0 0"); + sInteraction.flDelay = 10.0; + sInteraction.flDistSqr = (DSS_MAX_DIST * DSS_MAX_DIST); + + // Misc. response criteria + char* szCriteria = ""; + + KeyValues* pCurNode = pkvNode->GetFirstSubKey(); + const char* szName = NULL; + const char* szValue = NULL; + while (pCurNode) + { + szName = pCurNode->GetName(); + szValue = pCurNode->GetString(); + + if (!szName || !szValue) + { + DevWarning("ERROR: Invalid dynamic interaction string\n"); + pCurNode = pCurNode->GetNextKey(); + } + + if (!Q_strncmp(szName, "classname", 9)) + { + bool pass = false; + if (Q_strstr(szValue, "!=")) + { + szValue += 2; + pass = true; + } + + if (!FStrEq(GetClassname(), szValue)) + pass = !pass; + } + else if (!Q_strncmp(szName, "mapbase", 7)) + { + sInteraction.iFlags |= SCNPC_FLAG_MAPBASE_ADDITION; + } + else if (!Q_strncmp(szName, "trigger", 7)) + { + if (!Q_strncmp(szValue, "auto_in_combat", 14)) + sInteraction.iTriggerMethod = SNPCINT_AUTOMATIC_IN_COMBAT; + } + else if (!Q_strncmp(szValue, "loop_break_trigger", 18)) + { + char szTrigger[256]; + Q_strncpy(szTrigger, szValue, sizeof(szTrigger)); + char* pszParam = strtok(szTrigger, " "); + while (pszParam) + { + if (!Q_strncmp(pszParam, "on_damage", 9)) + { + sInteraction.iLoopBreakTriggerMethod |= SNPCINT_LOOPBREAK_ON_DAMAGE; + } + else if (!Q_strncmp(pszParam, "on_flashlight_illum", 19)) + { + sInteraction.iLoopBreakTriggerMethod |= SNPCINT_LOOPBREAK_ON_FLASHLIGHT_ILLUM; + } + + pszParam = strtok(NULL, " "); + } + } + else if (!Q_strncmp(szName, "origin_relative", 15)) + UTIL_StringToVector(sInteraction.vecRelativeOrigin.Base(), szValue); + else if (!Q_strncmp(szName, "angles_relative", 15)) + { + sInteraction.iFlags |= SCNPC_FLAG_TEST_OTHER_ANGLES; + UTIL_StringToVector(sInteraction.angRelativeAngles.Base(), szValue); + } + else if (!Q_strncmp(szName, "velocity_relative", 17)) + { + sInteraction.iFlags |= SCNPC_FLAG_TEST_OTHER_VELOCITY; + UTIL_StringToVector(sInteraction.vecRelativeVelocity.Base(), szValue); + } + else if (!Q_strncmp(szName, "end_position", 12)) + { + sInteraction.iFlags |= SCNPC_FLAG_TEST_END_POSITION; + UTIL_StringToVector(sInteraction.vecRelativeEndPos.Base(), szValue); + } + + else if (!Q_strncmp(szName, "entry_sequence", 14)) + sInteraction.sPhases[SNPCINT_ENTRY].iszSequence = AllocPooledString(szValue); + else if (!Q_strncmp(szName, "entry_activity", 14)) + sInteraction.sPhases[SNPCINT_ENTRY].iActivity = GetActivityID(szValue); + + else if (!Q_strncmp(szName, "sequence", 8)) + sInteraction.sPhases[SNPCINT_SEQUENCE].iszSequence = AllocPooledString(szValue); + else if (!Q_strncmp(szName, "activity", 8)) + sInteraction.sPhases[SNPCINT_SEQUENCE].iActivity = GetActivityID(szValue); + + else if (!Q_strncmp(szName, "exit_sequence", 13)) + sInteraction.sPhases[SNPCINT_EXIT].iszSequence = AllocPooledString(szValue); + else if (!Q_strncmp(szName, "exit_activity", 13)) + sInteraction.sPhases[SNPCINT_EXIT].iActivity = GetActivityID(szValue); + + else if (!Q_strncmp(szName, "delay", 5)) + sInteraction.flDelay = atof(szValue); + else if (!Q_strncmp(szName, "origin_max_delta", 16)) + sInteraction.flDistSqr = atof(szValue); + + else if (!Q_strncmp(szName, "loop_in_action", 14) && !FStrEq(szValue, "0")) + sInteraction.iFlags |= SCNPC_FLAG_LOOP_IN_ACTION; + + else if (!Q_strncmp(szName, "dont_teleport_at_end", 20)) + { + if (!Q_stricmp(szValue, "me") || !Q_stricmp(szValue, "both")) + sInteraction.iFlags |= SCNPC_FLAG_DONT_TELEPORT_AT_END_ME; + else if (!Q_stricmp(szValue, "them") || !Q_stricmp(szValue, "both")) + sInteraction.iFlags |= SCNPC_FLAG_DONT_TELEPORT_AT_END_THEM; + } + + else if (!Q_strncmp(szName, "needs_weapon", 12)) + { + if (!Q_strncmp(szValue, "ME", 2)) + sInteraction.iFlags |= SCNPC_FLAG_NEEDS_WEAPON_ME; + else if (!Q_strncmp(szValue, "THEM", 4)) + sInteraction.iFlags |= SCNPC_FLAG_NEEDS_WEAPON_THEM; + else if (!Q_strncmp(szValue, "BOTH", 4)) + { + sInteraction.iFlags |= SCNPC_FLAG_NEEDS_WEAPON_ME; + sInteraction.iFlags |= SCNPC_FLAG_NEEDS_WEAPON_THEM; + } + } + + else if (!Q_strncmp(szName, "weapon_mine", 11)) + { + sInteraction.iFlags |= SCNPC_FLAG_NEEDS_WEAPON_ME; + sInteraction.iszMyWeapon = AllocPooledString(szValue); + } + else if (!Q_strncmp(szName, "weapon_theirs", 13)) + { + sInteraction.iFlags |= SCNPC_FLAG_NEEDS_WEAPON_THEM; + sInteraction.iszTheirWeapon = AllocPooledString(szValue); + } + + // Add anything else to our miscellaneous criteria + else + { + szCriteria = UTIL_VarArgs("%s,%s:%s", szCriteria, szName, szValue); + } + pCurNode = pCurNode->GetNextKey(); } - if (!Q_strncmp(szName, "classname", 9)) + if (!bValidInteraction) { - bool pass = false; - if (Q_strstr(szValue, "!=")) - { - szValue += 2; - pass = true; - } - - if (!FStrEq(GetClassname(), szValue)) - pass = !pass; - } - else if (!Q_strncmp(szName, "mapbase", 7)) - { - sInteraction.iFlags |= SCNPC_FLAG_MAPBASE_ADDITION; - } - else if (!Q_strncmp(szName, "trigger", 7)) - { - if (!Q_strncmp(szValue, "auto_in_combat", 14)) - sInteraction.iTriggerMethod = SNPCINT_AUTOMATIC_IN_COMBAT; - } - else if (!Q_strncmp(szValue, "loop_break_trigger", 18)) - { - char szTrigger[256]; - Q_strncpy( szTrigger, szValue, sizeof(szTrigger) ); - char *pszParam = strtok( szTrigger, " " ); - while (pszParam) - { - if ( !Q_strncmp( pszParam, "on_damage", 9) ) - { - sInteraction.iLoopBreakTriggerMethod |= SNPCINT_LOOPBREAK_ON_DAMAGE; - } - else if ( !Q_strncmp( pszParam, "on_flashlight_illum", 19) ) - { - sInteraction.iLoopBreakTriggerMethod |= SNPCINT_LOOPBREAK_ON_FLASHLIGHT_ILLUM; - } - - pszParam = strtok(NULL," "); - } - } - else if (!Q_strncmp(szName, "origin_relative", 15)) - UTIL_StringToVector( sInteraction.vecRelativeOrigin.Base(), szValue ); - else if (!Q_strncmp(szName, "angles_relative", 15)) - { - sInteraction.iFlags |= SCNPC_FLAG_TEST_OTHER_ANGLES; - UTIL_StringToVector( sInteraction.angRelativeAngles.Base(), szValue ); - } - else if (!Q_strncmp(szName, "velocity_relative", 17)) - { - sInteraction.iFlags |= SCNPC_FLAG_TEST_OTHER_VELOCITY; - UTIL_StringToVector( sInteraction.vecRelativeVelocity.Base(), szValue ); - } -#ifdef MAPBASE - else if (!Q_strncmp(szName, "end_position", 12)) - { - sInteraction.iFlags |= SCNPC_FLAG_TEST_END_POSITION; - UTIL_StringToVector( sInteraction.vecRelativeEndPos.Base(), szValue ); - } -#endif - - else if (!Q_strncmp(szName, "entry_sequence", 14)) - sInteraction.sPhases[SNPCINT_ENTRY].iszSequence = AllocPooledString( szValue ); - else if (!Q_strncmp(szName, "entry_activity", 14)) - sInteraction.sPhases[SNPCINT_ENTRY].iActivity = GetActivityID( szValue ); - - else if (!Q_strncmp(szName, "sequence", 8)) - sInteraction.sPhases[SNPCINT_SEQUENCE].iszSequence = AllocPooledString( szValue ); - else if (!Q_strncmp(szName, "activity", 8)) - sInteraction.sPhases[SNPCINT_SEQUENCE].iActivity = GetActivityID( szValue ); - - else if (!Q_strncmp(szName, "exit_sequence", 13)) - sInteraction.sPhases[SNPCINT_EXIT].iszSequence = AllocPooledString( szValue ); - else if (!Q_strncmp(szName, "exit_activity", 13)) - sInteraction.sPhases[SNPCINT_EXIT].iActivity = GetActivityID(szValue); - - else if (!Q_strncmp(szName, "delay", 5)) - sInteraction.flDelay = atof(szValue); - else if (!Q_strncmp(szName, "origin_max_delta", 16)) - sInteraction.flDistSqr = atof(szValue); - - else if (!Q_strncmp(szName, "loop_in_action", 14) && !FStrEq(szValue, "0")) - sInteraction.iFlags |= SCNPC_FLAG_LOOP_IN_ACTION; - - else if (!Q_strncmp(szName, "dont_teleport_at_end", 20)) - { - if ( !Q_stricmp( szValue, "me" ) || !Q_stricmp( szValue, "both" ) ) - sInteraction.iFlags |= SCNPC_FLAG_DONT_TELEPORT_AT_END_ME; - else if ( !Q_stricmp( szValue, "them" ) || !Q_stricmp( szValue, "both" ) ) - sInteraction.iFlags |= SCNPC_FLAG_DONT_TELEPORT_AT_END_THEM; + DevMsg("Scripted interaction %s rejected by %s\n", pkvNode->GetName(), GetClassname()); + pkvNode = pkvNode->GetNextKey(); + continue; } - else if (!Q_strncmp(szName, "needs_weapon", 12)) + if (szCriteria[0] == ',') { - if ( !Q_strncmp( szValue, "ME", 2 ) ) - sInteraction.iFlags |= SCNPC_FLAG_NEEDS_WEAPON_ME; - else if ( !Q_strncmp( szValue, "THEM", 4 ) ) - sInteraction.iFlags |= SCNPC_FLAG_NEEDS_WEAPON_THEM; - else if ( !Q_strncmp( szValue, "BOTH", 4 ) ) - { - sInteraction.iFlags |= SCNPC_FLAG_NEEDS_WEAPON_ME; - sInteraction.iFlags |= SCNPC_FLAG_NEEDS_WEAPON_THEM; - } + szCriteria += 1; + sInteraction.MiscCriteria = AllocPooledString(szCriteria); } - else if (!Q_strncmp(szName, "weapon_mine", 11)) - { - sInteraction.iFlags |= SCNPC_FLAG_NEEDS_WEAPON_ME; - sInteraction.iszMyWeapon = AllocPooledString( szValue ); - } - else if (!Q_strncmp(szName, "weapon_theirs", 13)) - { - sInteraction.iFlags |= SCNPC_FLAG_NEEDS_WEAPON_THEM; - sInteraction.iszTheirWeapon = AllocPooledString( szValue ); - } - // Add anything else to our miscellaneous criteria - else - { - szCriteria = UTIL_VarArgs("%s,%s:%s", szCriteria, szName, szValue); - } + // Add it to the list + AddScriptedNPCInteraction(&sInteraction); + iszUsedNames.AddToTail(sInteraction.iszInteractionName); - pCurNode = pCurNode->GetNextKey(); - } - - if (!bValidInteraction) - { - DevMsg("Scripted interaction %s rejected by %s\n", pkvNode->GetName(), GetClassname()); + // Move to next interaction pkvNode = pkvNode->GetNextKey(); - continue; - } - - if (szCriteria[0] == ',') - { - szCriteria += 1; - sInteraction.MiscCriteria = AllocPooledString(szCriteria); } + } + } #else +// Do we have a dynamic interactions section? + KeyValues* pkvInteractions = modelKeyValues->FindKey("dynamic_interactions"); + if (pkvInteractions) + { + KeyValues* pkvNode = pkvInteractions->GetFirstSubKey(); + while (pkvNode) + { + ScriptedNPCInteraction_t sInteraction; + sInteraction.iszInteractionName = AllocPooledString(pkvNode->GetName()); + + // Trigger method - const char *pszTrigger = pkvNode->GetString( "trigger", NULL ); - if ( pszTrigger ) + const char* pszTrigger = pkvNode->GetString("trigger", NULL); + if (pszTrigger) { - if ( !Q_strncmp( pszTrigger, "auto_in_combat", 14) ) + if (!Q_strncmp(pszTrigger, "auto_in_combat", 14)) { sInteraction.iTriggerMethod = SNPCINT_AUTOMATIC_IN_COMBAT; } } // Loop Break trigger method - pszTrigger = pkvNode->GetString( "loop_break_trigger", NULL ); - if ( pszTrigger ) + pszTrigger = pkvNode->GetString("loop_break_trigger", NULL); + if (pszTrigger) { char szTrigger[256]; - Q_strncpy( szTrigger, pszTrigger, sizeof(szTrigger) ); - char *pszParam = strtok( szTrigger, " " ); + Q_strncpy(szTrigger, pszTrigger, sizeof(szTrigger)); + char* pszParam = strtok(szTrigger, " "); while (pszParam) { - if ( !Q_strncmp( pszParam, "on_damage", 9) ) + if (!Q_strncmp(pszParam, "on_damage", 9)) { sInteraction.iLoopBreakTriggerMethod |= SNPCINT_LOOPBREAK_ON_DAMAGE; } - if ( !Q_strncmp( pszParam, "on_flashlight_illum", 19) ) + if (!Q_strncmp(pszParam, "on_flashlight_illum", 19)) { sInteraction.iLoopBreakTriggerMethod |= SNPCINT_LOOPBREAK_ON_FLASHLIGHT_ILLUM; } - pszParam = strtok(NULL," "); + pszParam = strtok(NULL, " "); } } // Origin - const char *pszOrigin = pkvNode->GetString( "origin_relative", "0 0 0" ); - UTIL_StringToVector( sInteraction.vecRelativeOrigin.Base(), pszOrigin ); + const char* pszOrigin = pkvNode->GetString("origin_relative", "0 0 0"); + UTIL_StringToVector(sInteraction.vecRelativeOrigin.Base(), pszOrigin); // Angles - const char *pszAngles = pkvNode->GetString( "angles_relative", NULL ); - if ( pszAngles ) + const char* pszAngles = pkvNode->GetString("angles_relative", NULL); + if (pszAngles) { sInteraction.iFlags |= SCNPC_FLAG_TEST_OTHER_ANGLES; - UTIL_StringToVector( sInteraction.angRelativeAngles.Base(), pszAngles ); + UTIL_StringToVector(sInteraction.angRelativeAngles.Base(), pszAngles); } // Velocity - const char *pszVelocity = pkvNode->GetString( "velocity_relative", NULL ); - if ( pszVelocity ) + const char* pszVelocity = pkvNode->GetString("velocity_relative", NULL); + if (pszVelocity) { sInteraction.iFlags |= SCNPC_FLAG_TEST_OTHER_VELOCITY; - UTIL_StringToVector( sInteraction.vecRelativeVelocity.Base(), pszVelocity ); + UTIL_StringToVector(sInteraction.vecRelativeVelocity.Base(), pszVelocity); } // Entry Sequence - const char *pszSequence = pkvNode->GetString( "entry_sequence", NULL ); - if ( pszSequence ) + const char* pszSequence = pkvNode->GetString("entry_sequence", NULL); + if (pszSequence) { - sInteraction.sPhases[SNPCINT_ENTRY].iszSequence = AllocPooledString( pszSequence ); + sInteraction.sPhases[SNPCINT_ENTRY].iszSequence = AllocPooledString(pszSequence); } // Entry Activity - const char *pszActivity = pkvNode->GetString( "entry_activity", NULL ); - if ( pszActivity ) + const char* pszActivity = pkvNode->GetString("entry_activity", NULL); + if (pszActivity) { - sInteraction.sPhases[SNPCINT_ENTRY].iActivity = GetActivityID( pszActivity ); + sInteraction.sPhases[SNPCINT_ENTRY].iActivity = GetActivityID(pszActivity); } // Sequence - pszSequence = pkvNode->GetString( "sequence", NULL ); - if ( pszSequence ) + pszSequence = pkvNode->GetString("sequence", NULL); + if (pszSequence) { - sInteraction.sPhases[SNPCINT_SEQUENCE].iszSequence = AllocPooledString( pszSequence ); + sInteraction.sPhases[SNPCINT_SEQUENCE].iszSequence = AllocPooledString(pszSequence); } // Activity - pszActivity = pkvNode->GetString( "activity", NULL ); - if ( pszActivity ) + pszActivity = pkvNode->GetString("activity", NULL); + if (pszActivity) { - sInteraction.sPhases[SNPCINT_SEQUENCE].iActivity = GetActivityID( pszActivity ); + sInteraction.sPhases[SNPCINT_SEQUENCE].iActivity = GetActivityID(pszActivity); } // Exit Sequence - pszSequence = pkvNode->GetString( "exit_sequence", NULL ); - if ( pszSequence ) + pszSequence = pkvNode->GetString("exit_sequence", NULL); + if (pszSequence) { - sInteraction.sPhases[SNPCINT_EXIT].iszSequence = AllocPooledString( pszSequence ); + sInteraction.sPhases[SNPCINT_EXIT].iszSequence = AllocPooledString(pszSequence); } // Exit Activity - pszActivity = pkvNode->GetString( "exit_activity", NULL ); - if ( pszActivity ) + pszActivity = pkvNode->GetString("exit_activity", NULL); + if (pszActivity) { - sInteraction.sPhases[SNPCINT_EXIT].iActivity = GetActivityID( pszActivity ); + sInteraction.sPhases[SNPCINT_EXIT].iActivity = GetActivityID(pszActivity); } // Delay - sInteraction.flDelay = pkvNode->GetFloat( "delay", 10.0 ); + sInteraction.flDelay = pkvNode->GetFloat("delay", 10.0); // Delta - sInteraction.flDistSqr = pkvNode->GetFloat( "origin_max_delta", (DSS_MAX_DIST * DSS_MAX_DIST) ); + sInteraction.flDistSqr = pkvNode->GetFloat("origin_max_delta", (DSS_MAX_DIST * DSS_MAX_DIST)); // Loop? - if ( pkvNode->GetFloat( "loop_in_action", 0 ) ) + if (pkvNode->GetFloat("loop_in_action", 0)) { sInteraction.iFlags |= SCNPC_FLAG_LOOP_IN_ACTION; } // Fixup position? - const char *pszDontFixup = pkvNode->GetString( "dont_teleport_at_end", NULL ); - if ( pszDontFixup ) + const char* pszDontFixup = pkvNode->GetString("dont_teleport_at_end", NULL); + if (pszDontFixup) { - if ( !Q_stricmp( pszDontFixup, "me" ) || !Q_stricmp( pszDontFixup, "both" ) ) + if (!Q_stricmp(pszDontFixup, "me") || !Q_stricmp(pszDontFixup, "both")) { sInteraction.iFlags |= SCNPC_FLAG_DONT_TELEPORT_AT_END_ME; } - else if ( !Q_stricmp( pszDontFixup, "them" ) || !Q_stricmp( pszDontFixup, "both" ) ) + else if (!Q_stricmp(pszDontFixup, "them") || !Q_stricmp(pszDontFixup, "both")) { sInteraction.iFlags |= SCNPC_FLAG_DONT_TELEPORT_AT_END_THEM; } } // Needs a weapon? - const char *pszNeedsWeapon = pkvNode->GetString( "needs_weapon", NULL ); - if ( pszNeedsWeapon ) + const char* pszNeedsWeapon = pkvNode->GetString("needs_weapon", NULL); + if (pszNeedsWeapon) { - if ( !Q_strncmp( pszNeedsWeapon, "ME", 2 ) ) + if (!Q_strncmp(pszNeedsWeapon, "ME", 2)) { sInteraction.iFlags |= SCNPC_FLAG_NEEDS_WEAPON_ME; } - else if ( !Q_strncmp( pszNeedsWeapon, "THEM", 4 ) ) + else if (!Q_strncmp(pszNeedsWeapon, "THEM", 4)) { sInteraction.iFlags |= SCNPC_FLAG_NEEDS_WEAPON_THEM; } - else if ( !Q_strncmp( pszNeedsWeapon, "BOTH", 4 ) ) + else if (!Q_strncmp(pszNeedsWeapon, "BOTH", 4)) { sInteraction.iFlags |= SCNPC_FLAG_NEEDS_WEAPON_ME; sInteraction.iFlags |= SCNPC_FLAG_NEEDS_WEAPON_THEM; @@ -15046,27 +15076,28 @@ void CAI_BaseNPC::ParseScriptedNPCInteractions( void ) } // Specific weapon types - const char *pszWeaponName = pkvNode->GetString( "weapon_mine", NULL ); - if ( pszWeaponName ) + const char* pszWeaponName = pkvNode->GetString("weapon_mine", NULL); + if (pszWeaponName) { sInteraction.iFlags |= SCNPC_FLAG_NEEDS_WEAPON_ME; - sInteraction.iszMyWeapon = AllocPooledString( pszWeaponName ); + sInteraction.iszMyWeapon = AllocPooledString(pszWeaponName); } - pszWeaponName = pkvNode->GetString( "weapon_theirs", NULL ); - if ( pszWeaponName ) + pszWeaponName = pkvNode->GetString("weapon_theirs", NULL); + if (pszWeaponName) { sInteraction.iFlags |= SCNPC_FLAG_NEEDS_WEAPON_THEM; - sInteraction.iszTheirWeapon = AllocPooledString( pszWeaponName ); + sInteraction.iszTheirWeapon = AllocPooledString(pszWeaponName); } -#endif // Add it to the list - AddScriptedNPCInteraction( &sInteraction ); + AddScriptedNPCInteraction(&sInteraction); // Move to next interaction pkvNode = pkvNode->GetNextKey(); } } +#endif // MAPBASE + } modelKeyValues->deleteThis(); From a5ad82339e6defa21ce356616d6f418c51be4260 Mon Sep 17 00:00:00 2001 From: Peter Covington Date: Tue, 19 Apr 2022 21:07:58 -0400 Subject: [PATCH 332/378] Compute aspect ratios on shadow depth textures --- sp/src/game/client/clientshadowmgr.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/sp/src/game/client/clientshadowmgr.cpp b/sp/src/game/client/clientshadowmgr.cpp index 9dc2a5fe..2d016f48 100644 --- a/sp/src/game/client/clientshadowmgr.cpp +++ b/sp/src/game/client/clientshadowmgr.cpp @@ -4484,13 +4484,18 @@ void CClientShadowMgr::ComputeShadowDepthTextures( const CViewSetup &viewSetup ) } CViewSetup shadowView; +#ifndef MAPBASE shadowView.m_flAspectRatio = 1.0f; +#endif shadowView.x = shadowView.y = 0; shadowView.width = shadowDepthTexture->GetActualWidth(); shadowView.height = shadowDepthTexture->GetActualHeight(); #ifndef ASW_PROJECTED_TEXTURES shadowView.m_bOrtho = false; shadowView.m_bDoBloomAndToneMapping = false; +#ifdef MAPBASE + shadowView.m_flAspectRatio = (flashlightState.m_fHorizontalFOVDegrees / flashlightState.m_fVerticalFOVDegrees); +#endif // MAPBASE #endif // Copy flashlight parameters @@ -4498,6 +4503,10 @@ void CClientShadowMgr::ComputeShadowDepthTextures( const CViewSetup &viewSetup ) if ( !flashlightState.m_bOrtho ) { shadowView.m_bOrtho = false; + +#ifdef MAPBASE + shadowView.m_flAspectRatio = (flashlightState.m_fHorizontalFOVDegrees / flashlightState.m_fVerticalFOVDegrees); +#endif // MAPBASE } else { @@ -4506,6 +4515,10 @@ void CClientShadowMgr::ComputeShadowDepthTextures( const CViewSetup &viewSetup ) shadowView.m_OrthoTop = flashlightState.m_fOrthoTop; shadowView.m_OrthoRight = flashlightState.m_fOrthoRight; shadowView.m_OrthoBottom = flashlightState.m_fOrthoBottom; + +#ifdef MAPBASE + shadowView.m_flAspectRatio = 1.0f; +#endif } shadowView.m_bDoBloomAndToneMapping = false; From a6a8a04b1fb2aa6d94f77d1dced6da2f27fe6817 Mon Sep 17 00:00:00 2001 From: Peter Covington Date: Wed, 20 Apr 2022 09:41:26 -0400 Subject: [PATCH 333/378] Fixed enemyfinders becoming visible when they wake --- sp/src/game/server/hl2/npc_enemyfinder.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/sp/src/game/server/hl2/npc_enemyfinder.cpp b/sp/src/game/server/hl2/npc_enemyfinder.cpp index f8fc21bd..d9855815 100644 --- a/sp/src/game/server/hl2/npc_enemyfinder.cpp +++ b/sp/src/game/server/hl2/npc_enemyfinder.cpp @@ -59,6 +59,10 @@ public: void InputTurnOff( inputdata_t &inputdata ); virtual void Wake( bool bFireOutput = true ); +#ifdef MAPBASE + // A version of Wake() that takes an activator + virtual void Wake(CBaseEntity* pActivator); +#endif private: int m_nStartOn; @@ -234,6 +238,16 @@ void CNPC_EnemyFinder::Wake( bool bFireOutput ) AddEffects( EF_NODRAW ); } +#ifdef MAPBASE +void CNPC_EnemyFinder::Wake(CBaseEntity* pActivator) +{ + BaseClass::Wake(pActivator); + + //Enemy finder is not allowed to become visible. + AddEffects(EF_NODRAW); +} +#endif // MAPBASE + //------------------------------------------------------------------------------ // //------------------------------------------------------------------------------ From 655212ee62c3f2cfe71d25a957f0dcce2b692515 Mon Sep 17 00:00:00 2001 From: Peter Covington Date: Wed, 20 Apr 2022 16:58:45 -0400 Subject: [PATCH 334/378] Fix for brightly glowing teeth --- sp/src/materialsystem/stdshaders/teeth.cpp | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/sp/src/materialsystem/stdshaders/teeth.cpp b/sp/src/materialsystem/stdshaders/teeth.cpp index f6035048..e9b071ff 100644 --- a/sp/src/materialsystem/stdshaders/teeth.cpp +++ b/sp/src/materialsystem/stdshaders/teeth.cpp @@ -222,7 +222,10 @@ BEGIN_VS_SHADER( SDK_Teeth_DX9, "Help for SDK_Teeth_DX9" ) float vEyePos_SpecExponent[4]; pShaderAPI->GetWorldSpaceCameraPosition( vEyePos_SpecExponent ); - vEyePos_SpecExponent[3] = 0.0f; + if (g_pHardwareConfig->HasFastVertexTextures() || g_pHardwareConfig->SupportsPixelShaders_2_b()) + vEyePos_SpecExponent[3] = params[PHONGEXPONENT]->GetFloatValue(); + else + vEyePos_SpecExponent[3] = 0.0f; pShaderAPI->SetPixelShaderConstant( PSREG_EYEPOS_SPEC_EXPONENT, vEyePos_SpecExponent, 1 ); if ( hasBump ) @@ -244,11 +247,6 @@ BEGIN_VS_SHADER( SDK_Teeth_DX9, "Help for SDK_Teeth_DX9" ) // ps_2_b version which does Phong if ( g_pHardwareConfig->SupportsPixelShaders_2_b() ) { - Vector4D vSpecExponent; - vSpecExponent[3] = params[PHONGEXPONENT]->GetFloatValue(); - - pShaderAPI->SetPixelShaderConstant( PSREG_EYEPOS_SPEC_EXPONENT, vSpecExponent.Base(), 1 ); - DECLARE_DYNAMIC_PIXEL_SHADER( sdk_teeth_bump_ps20b ); SET_DYNAMIC_PIXEL_SHADER_COMBO( PIXELFOGTYPE, pShaderAPI->GetPixelFogCombo() ); SET_DYNAMIC_PIXEL_SHADER_COMBO( NUM_LIGHTS, lightState.m_nNumLights ); @@ -278,10 +276,6 @@ BEGIN_VS_SHADER( SDK_Teeth_DX9, "Help for SDK_Teeth_DX9" ) SET_DYNAMIC_VERTEX_SHADER_COMBO( COMPRESSED_VERTS, (int)vertexCompression ); SET_DYNAMIC_VERTEX_SHADER( sdk_teeth_bump_vs30 ); - Vector4D vSpecExponent; - vSpecExponent[3] = params[PHONGEXPONENT]->GetFloatValue(); - pShaderAPI->SetPixelShaderConstant( PSREG_EYEPOS_SPEC_EXPONENT, vSpecExponent.Base(), 1 ); - DECLARE_DYNAMIC_PIXEL_SHADER( sdk_teeth_bump_ps30 ); SET_DYNAMIC_PIXEL_SHADER_COMBO( PIXELFOGTYPE, pShaderAPI->GetPixelFogCombo() ); SET_DYNAMIC_PIXEL_SHADER_COMBO( NUM_LIGHTS, lightState.m_nNumLights ); From b04fb3c43f405eeaec6a0079bc2c6cef3c2c29c5 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Tue, 26 Apr 2022 07:55:35 -0500 Subject: [PATCH 335/378] Added commentary footnotes, misc. commentary fixes --- .../game/client/c_point_commentary_node.cpp | 337 ++++++++++++++---- sp/src/game/server/CommentarySystem.cpp | 14 + 2 files changed, 279 insertions(+), 72 deletions(-) diff --git a/sp/src/game/client/c_point_commentary_node.cpp b/sp/src/game/client/c_point_commentary_node.cpp index 3314330b..cd0c77eb 100644 --- a/sp/src/game/client/c_point_commentary_node.cpp +++ b/sp/src/game/client/c_point_commentary_node.cpp @@ -20,6 +20,7 @@ #include "in_buttons.h" #ifdef MAPBASE #include "vgui_controls/Label.h" +#include "vgui_controls/TextImage.h" #include "vgui_controls/ImagePanel.h" #include "vgui_controls/AnimationController.h" #include "filesystem.h" @@ -53,6 +54,8 @@ ConVar commentary_type_image_endtime( "commentary_type_image_endtime", "120" ); ConVar commentary_audio_element_below_cc( "commentary_audio_element_below_cc", "1", FCVAR_NONE, "Allows commentary audio elements to display even when CC is enabled (although this is done by inverting their Y axis)" ); ConVar commentary_audio_element_below_cc_margin( "commentary_audio_element_below_cc_margin", "4" ); ConVar commentary_combine_speaker_and_printname( "commentary_combine_speaker_and_printname", "1" ); +ConVar commentary_footnote_offset_x( "commentary_footnote_offset_x", "16" ); +ConVar commentary_footnote_offset_y( "commentary_footnote_offset_y", "8" ); #endif //----------------------------------------------------------------------------- @@ -79,8 +82,8 @@ public: bool IsTheActiveNode( C_PointCommentaryNode *pNode ) { return (pNode == m_hActiveNode); } #ifdef MAPBASE - void CombineSpeakerAndPrintName( const char *pszPrintName ); - void RepositionCloseCaption(); + void FixupCommentaryLabels( const char *pszPrintName, const char *pszSpeakers, const char *pszFootnote ); + void RepositionAndFollowCloseCaption( int yOffset = 0 ); #endif // vgui overrides @@ -89,6 +92,8 @@ public: #ifdef MAPBASE virtual void PerformLayout(); void ResolveBounds( int width, int height ); + + virtual void LevelShutdown(); #endif private: @@ -110,8 +115,13 @@ private: vgui::ImagePanel *m_pImage; vgui::HFont m_hFont; + vgui::Label *m_pFootnoteLabel; + vgui::HFont m_hSmallFont; + // HACKHACK: Needed as a failsafe to prevent desync int m_iCCDefaultY; + + bool m_bShouldRepositionSubtitles; #endif // Painting @@ -271,6 +281,8 @@ public: void SetSpeakers( const char *pszSpeakers ) { Q_strncpy( m_iszSpeakers, pszSpeakers, sizeof( m_iszSpeakers ) ); } const char *GetPrintName() { return m_iszPrintName; } void SetPrintName( const char *pszPrintName ) { Q_strncpy( m_iszPrintName, pszPrintName, sizeof( m_iszPrintName ) ); } + const char *GetFootnote() { return m_iszFootnote; } + void SetFootnote( const char *pszFootnote ) { Q_strncpy( m_iszFootnote, pszFootnote, sizeof( m_iszFootnote ) ); } #endif public: @@ -288,6 +300,7 @@ public: bool m_bRestartAfterRestore; #ifdef MAPBASE char m_iszPrintName[MAX_SPEAKER_NAME]; + char m_iszFootnote[MAX_SPEAKER_NAME]; int m_iCommentaryType; float m_flPanelScale; float m_flPanelX; @@ -314,6 +327,7 @@ IMPLEMENT_CLIENTCLASS_DT(C_PointCommentaryNode, DT_PointCommentaryNode, CPointCo RecvPropEHandle( RECVINFO(m_hViewPosition) ), #ifdef MAPBASE RecvPropString( RECVINFO( m_iszPrintName ) ), + RecvPropString( RECVINFO( m_iszFootnote ) ), RecvPropInt( RECVINFO( m_iCommentaryType ) ), RecvPropFloat( RECVINFO( m_flPanelScale ) ), RecvPropFloat( RECVINFO( m_flPanelX ) ), @@ -339,6 +353,8 @@ BEGIN_ENT_SCRIPTDESC( C_PointCommentaryNode, C_BaseAnimating, "Commentary nodes DEFINE_SCRIPTFUNC( SetSpeakers, "" ) DEFINE_SCRIPTFUNC( GetPrintName, "" ) DEFINE_SCRIPTFUNC( SetPrintName, "" ) + DEFINE_SCRIPTFUNC( GetFootnote, "" ) + DEFINE_SCRIPTFUNC( SetFootnote, "" ) DEFINE_SCRIPTFUNC( GetCommentaryType, "" ) DEFINE_SCRIPTFUNC( SetCommentaryType, "" ) @@ -712,14 +728,24 @@ void C_PointCommentaryNode::StartEvent( float currenttime, CChoreoScene *scene, { CSingleUserRecipientFilter filter( C_BasePlayer::GetLocalPlayer() ); - EmitSound_t es; - es.m_nChannel = CHAN_VOICE2; - es.m_flVolume = 1; + CSoundParameters soundParams; + bool bSoundscript = (g_pSoundEmitterSystem->GetParametersForSound( event->GetParameters(), soundParams, GENDER_NONE, false )); + EmitSound_t es( soundParams ); + if (bSoundscript) + { + } + else + { + es.m_pSoundName = event->GetParameters(); + es.m_flVolume = 1; + } + + // TODO: This is supposed to make sure actors don't interrupt each other, but it doesn't seem to work + es.m_nChannel = CHAN_USER_BASE + scene->FindActorIndex( event->GetActor() ); es.m_SoundLevel = SNDLVL_GUNFIRE; - //es.m_nFlags = SND_SHOULDPAUSE; + es.m_nFlags = SND_SHOULDPAUSE; es.m_bEmitCloseCaption = false; - es.m_pSoundName = event->GetParameters(); // Just in case if (!m_hSceneOrigin) @@ -804,13 +830,23 @@ void C_PointCommentaryNode::StopLoopingSounds( void ) #ifdef MAPBASE if ( m_pScene ) { + // Must do this to terminate audio + if (m_hSceneOrigin) + { + CSingleUserRecipientFilter filter( C_BasePlayer::GetLocalPlayer() ); + + for (int i = 0; i < m_pScene->GetNumActors(); i++) + { + EmitSound_t es; + es.m_nChannel = CHAN_USER_BASE + i; + es.m_pSoundName = "common/null.wav"; + + EmitSound( filter, m_hSceneOrigin->entindex(), es ); + } + } + delete m_pScene; m_pScene = NULL; - - // Must do this to terminate audio - // (TODO: This causes problems when players switch from a scene node immediately to a regular audio node) - if (m_hSceneOrigin) - m_hSceneOrigin->EmitSound( "AI_BaseNPC.SentenceStop" ); } #endif } @@ -871,6 +907,8 @@ CHudCommentary::CHudCommentary( const char *name ) : vgui::Panel( NULL, "HudComm m_pImage = new vgui::ImagePanel( this, "HudCommentaryImagePanel" ); m_pImage->SetShouldScaleImage( true ); + m_pFootnoteLabel = new vgui::Label( this, "HudCommentaryFootnoteLabel", L"Commentary footnote" ); + m_iCCDefaultY = 0; #endif } @@ -887,6 +925,9 @@ void CHudCommentary::ApplySchemeSettings( vgui::IScheme *pScheme ) #ifdef MAPBASE m_pLabel->SetPaintBackgroundType( 2 ); m_pLabel->SetSize( 0, GetTall() ); + + m_pFootnoteLabel->SetPaintBackgroundType( 2 ); + m_pFootnoteLabel->SetSize( 0, GetTall() ); #endif } @@ -914,12 +955,8 @@ void CHudCommentary::Paint() // Reset close caption element if needed if (pHudCloseCaption->IsUsingCommentaryDimensions()) { - int ccX, ccY; - pHudCloseCaption->GetPos( ccX, ccY ); - //pHudCloseCaption->SetPos( ccX, ccY + m_iTypeAudioT ); - // Run this animation command instead of setting the position directly - g_pClientMode->GetViewportAnimationController()->RunAnimationCommand( pHudCloseCaption, "YPos", ccY + m_iTypeAudioT, 0.0f, 0.4f, vgui::AnimationController::INTERPOLATOR_ACCEL ); + g_pClientMode->GetViewportAnimationController()->RunAnimationCommand( pHudCloseCaption, "YPos", m_iCCDefaultY, 0.0f, 0.4f, vgui::AnimationController::INTERPOLATOR_ACCEL ); pHudCloseCaption->SetUsingCommentaryDimensions( false ); } @@ -941,12 +978,8 @@ void CHudCommentary::Paint() CHudCloseCaption *pHudCloseCaption = (CHudCloseCaption *)GET_HUDELEMENT( CHudCloseCaption ); if (pHudCloseCaption && pHudCloseCaption->IsUsingCommentaryDimensions()) { - int ccX, ccY; - pHudCloseCaption->GetPos( ccX, ccY ); - //pHudCloseCaption->SetPos( ccX, ccY + m_iTypeAudioT ); - // Run this animation command instead of setting the position directly - g_pClientMode->GetViewportAnimationController()->RunAnimationCommand( pHudCloseCaption, "YPos", ccY + m_iTypeAudioT, 0.0f, 0.4f, vgui::AnimationController::INTERPOLATOR_ACCEL ); + g_pClientMode->GetViewportAnimationController()->RunAnimationCommand( pHudCloseCaption, "YPos", m_iCCDefaultY, 0.0f, 0.4f, vgui::AnimationController::INTERPOLATOR_ACCEL ); pHudCloseCaption->SetUsingCommentaryDimensions( false ); } @@ -1055,6 +1088,35 @@ void CHudCommentary::Paint() vgui::surface()->GetTextSize( m_hFont, m_szCount, iCountWide, iCountTall ); #ifdef MAPBASE + if (m_pFootnoteLabel->IsEnabled()) + { + // Raise the count's position so that it doesn't get in the way + //iCountTall *= 2; + + int x, y; + m_pFootnoteLabel->GetPos(x, y); + + // + // Draw a bullet next to each footnote + // + CUtlVector pLineCoords; + pLineCoords.AddToTail( 0 ); // First line + + m_pFootnoteLabel->GetTextImage()->GetNewlinePositions( &pLineCoords, true ); + + int iBulletX = x - commentary_footnote_offset_x.GetInt(); + int iBulletY = y; + + vgui::surface()->DrawSetTextFont( m_hFont ); + vgui::surface()->DrawSetTextColor( clr ); + + for (int i = 0; i < pLineCoords.Count(); i++) + { + vgui::surface()->DrawSetTextPos( iBulletX, iBulletY + pLineCoords[i] ); + vgui::surface()->DrawUnicodeChar( L'\u2022' ); + } + } + if (m_iCommentaryType != COMMENTARY_TYPE_AUDIO && m_iCommentaryType != COMMENTARY_TYPE_SCENE) vgui::surface()->DrawSetTextPos( wide - m_iTypeTextCountXFR - iCountWide, tall - m_iTypeTextCountYFB - iCountTall ); else @@ -1085,13 +1147,35 @@ void CHudCommentary::PerformLayout() { BaseClass::PerformLayout(); + // Don't do anything if we shouldn't draw + if (!m_hActiveNode) // !ShouldDraw() + return; + + int extraWidth = 0, extraHeight = 0; + + // The dimensions of a progress bar, text card, etc. + int contentWidth = 0, contentHeight = 0; + + int xOffset = m_iBarX; + int yOffset = m_iBarY; + + // Footnotes can add more space to the bottom if they have newlines. + if (m_pFootnoteLabel->IsEnabled()) + { + m_pFootnoteLabel->SetBounds( xOffset, yOffset, (float)(m_iBarWide * m_flPanelScale), GetTall() ); + + int iNoteWide, iNoteTall; + m_pFootnoteLabel->GetContentSize( iNoteWide, iNoteTall ); + + m_pFootnoteLabel->SetTall( iNoteTall ); + + extraHeight += iNoteTall; + } + switch (m_iCommentaryType) { case COMMENTARY_TYPE_TEXT: { - int xOffset = m_iBarX; - int yOffset = m_iBarY; - m_pLabel->SetBounds( xOffset + m_iTextBorderSpace, yOffset + m_iTextBorderSpace, (float)(m_iBarWide * m_flPanelScale) - m_iTextBorderSpace, GetTall() ); @@ -1104,17 +1188,19 @@ void CHudCommentary::PerformLayout() m_pLabel->SetTall( lT ); - lW += (float)((m_iTextBorderSpace * 2) + (xOffset * 2)); - lT += (float)((m_iTextBorderSpace * 2) + (yOffset * 2)); + lW += (m_iTextBorderSpace * 2); + lT += (m_iTextBorderSpace * 2); - ResolveBounds( lW, lT ); + contentWidth = lW, contentHeight = lT; + + lW += (xOffset * 2); + lT += (yOffset * 2); + + ResolveBounds( lW + extraWidth, lT + extraHeight ); } break; case COMMENTARY_TYPE_IMAGE: { - int xOffset = m_iBarX; - int yOffset = m_iBarY; - // Figure out the size before setting bounds int iW, iT; //m_pImage->GetImage()->GetSize( iW, iT ); @@ -1134,17 +1220,40 @@ void CHudCommentary::PerformLayout() yOffset + m_iTextBorderSpace, iW, iT ); - iW += (float)((m_iTextBorderSpace * 2) + (xOffset * 2)); - iT += (float)((m_iTextBorderSpace * 2) + (yOffset * 2)); + iW += (m_iTextBorderSpace * 2); + iT += (m_iTextBorderSpace * 2); - ResolveBounds( iW, iT ); + contentWidth = iW, contentHeight = iT; + + iW += (xOffset * 2); + iT += (yOffset * 2); + + ResolveBounds( iW + extraWidth, iT + extraHeight ); } break; default: case COMMENTARY_TYPE_SCENE: case COMMENTARY_TYPE_AUDIO: + + // Keep the box centered + SetBounds( m_iTypeAudioX, m_iTypeAudioY - extraHeight, m_iTypeAudioW + extraWidth, m_iTypeAudioT + extraHeight ); + + // Reposition the subtitles to be above the commentary dialog + if (m_bShouldRepositionSubtitles) + { + RepositionAndFollowCloseCaption( extraHeight ); + } + + contentWidth = (m_iBarWide * m_flPanelScale), contentHeight = m_iBarTall; + break; } + + // Move the footnote to be at the bottom + if (m_pFootnoteLabel->IsEnabled()) + { + m_pFootnoteLabel->SetPos( m_iSpeakersX + commentary_footnote_offset_x.GetInt(), yOffset+contentHeight+ commentary_footnote_offset_y.GetInt() ); + } } //----------------------------------------------------------------------------- @@ -1195,6 +1304,30 @@ void CHudCommentary::ResolveBounds( int width, int height ) SetBounds( xPos, yPos, width, height ); } + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CHudCommentary::LevelShutdown( void ) +{ + if (m_iCCDefaultY != 0) + { + CHudCloseCaption *pHudCloseCaption = (CHudCloseCaption *)GET_HUDELEMENT( CHudCloseCaption ); + if (pHudCloseCaption && pHudCloseCaption->IsUsingCommentaryDimensions()) + { + int ccX, ccY; + pHudCloseCaption->GetPos( ccX, ccY ); + + if (m_iCCDefaultY != ccY) + { + DevMsg( "CHudCommentary had to reset misaligned CC element Y (%i) to default Y (%i)\n", ccY, m_iCCDefaultY ); + pHudCloseCaption->SetPos( ccX, m_iCCDefaultY ); + } + + pHudCloseCaption->SetUsingCommentaryDimensions( false ); + } + } +} #endif //----------------------------------------------------------------------------- @@ -1249,6 +1382,8 @@ void CHudCommentary::StartCommentary( C_PointCommentaryNode *pNode, char *pszSpe m_pImage->SetPaintEnabled( false ); m_pImage->EvictImage(); + m_pFootnoteLabel->SetEnabled( false ); + // Get our scheme and font information vgui::HScheme scheme = GetScheme(); m_hFont = vgui::scheme()->GetIScheme(scheme)->GetFont( "CommentaryDefault" ); @@ -1256,6 +1391,12 @@ void CHudCommentary::StartCommentary( C_PointCommentaryNode *pNode, char *pszSpe { m_hFont = vgui::scheme()->GetIScheme(scheme)->GetFont( "Default" ); } + + m_hSmallFont = vgui::scheme()->GetIScheme(scheme)->GetFont( "CommentarySmall" ); + if ( !m_hSmallFont) + { + m_hSmallFont = m_hFont; + } #endif // Don't draw the element itself if closecaptions are on (and captions are always on in non-english mode) @@ -1273,13 +1414,12 @@ void CHudCommentary::StartCommentary( C_PointCommentaryNode *pNode, char *pszSpe if (!m_bShouldPaint && commentary_audio_element_below_cc.GetBool()) { m_bShouldPaint = true; - RepositionCloseCaption(); + m_bShouldRepositionSubtitles = true; } + else + m_bShouldRepositionSubtitles = false; - if (commentary_combine_speaker_and_printname.GetBool() && pNode && pNode->m_iszPrintName[0] != '\0') - { - CombineSpeakerAndPrintName( pNode->m_iszPrintName ); - } + FixupCommentaryLabels( pNode->m_iszPrintName, pNode->m_iszSpeakers, pNode->m_iszFootnote ); #endif SetPaintBackgroundEnabled( m_bShouldPaint ); @@ -1330,6 +1470,12 @@ void CHudCommentary::StartTextCommentary( C_PointCommentaryNode *pNode, const ch m_hFont = vgui::scheme()->GetIScheme(scheme)->GetFont( "Default" ); } + m_hSmallFont = vgui::scheme()->GetIScheme(scheme)->GetFont( "CommentarySmall" ); + if ( !m_hSmallFont) + { + m_hSmallFont = m_hFont; + } + m_pLabel->SetText( pszText ); m_pLabel->SetFont( m_hFont ); m_pLabel->SetWrap( true ); @@ -1343,12 +1489,11 @@ void CHudCommentary::StartTextCommentary( C_PointCommentaryNode *pNode, const ch m_pImage->SetPaintEnabled( false ); m_pImage->EvictImage(); + m_pFootnoteLabel->SetEnabled( false ); + m_bShouldPaint = true; - if (commentary_combine_speaker_and_printname.GetBool() && pNode && pNode->m_iszPrintName[0] != '\0') - { - CombineSpeakerAndPrintName( pNode->m_iszPrintName ); - } + FixupCommentaryLabels( pNode->m_iszPrintName, pNode->m_iszSpeakers, pNode->m_iszFootnote ); SetPaintBackgroundEnabled( m_bShouldPaint ); @@ -1395,6 +1540,8 @@ void CHudCommentary::StartImageCommentary( C_PointCommentaryNode *pNode, const c m_pImage->SetImage( pszImage ); m_pImage->SetWide( m_iBarWide - m_iTextBorderSpace ); + m_pFootnoteLabel->SetEnabled( false ); + // Get our scheme and font information vgui::HScheme scheme = GetScheme(); m_hFont = vgui::scheme()->GetIScheme(scheme)->GetFont( "CommentaryDefault" ); @@ -1403,12 +1550,15 @@ void CHudCommentary::StartImageCommentary( C_PointCommentaryNode *pNode, const c m_hFont = vgui::scheme()->GetIScheme(scheme)->GetFont( "Default" ); } + m_hSmallFont = vgui::scheme()->GetIScheme(scheme)->GetFont( "CommentarySmall" ); + if ( !m_hSmallFont) + { + m_hSmallFont = m_hFont; + } + m_bShouldPaint = true; - if (commentary_combine_speaker_and_printname.GetBool() && pNode && pNode->m_iszPrintName[0] != '\0') - { - CombineSpeakerAndPrintName( pNode->m_iszPrintName ); - } + FixupCommentaryLabels( pNode->m_iszPrintName, pNode->m_iszSpeakers, pNode->m_iszFootnote ); SetPaintBackgroundEnabled( m_bShouldPaint ); @@ -1453,6 +1603,8 @@ void CHudCommentary::StartSceneCommentary( C_PointCommentaryNode *pNode, char *p m_pImage->SetPaintEnabled( false ); m_pImage->EvictImage(); + m_pFootnoteLabel->SetEnabled( false ); + // Get our scheme and font information vgui::HScheme scheme = GetScheme(); m_hFont = vgui::scheme()->GetIScheme(scheme)->GetFont( "CommentaryDefault" ); @@ -1461,6 +1613,12 @@ void CHudCommentary::StartSceneCommentary( C_PointCommentaryNode *pNode, char *p m_hFont = vgui::scheme()->GetIScheme(scheme)->GetFont( "Default" ); } + m_hSmallFont = vgui::scheme()->GetIScheme(scheme)->GetFont( "CommentarySmall" ); + if ( !m_hSmallFont) + { + m_hSmallFont = m_hFont; + } + // Don't draw the element itself if closecaptions are on (and captions are always on in non-english mode) ConVarRef pCVar( "closecaption" ); if ( pCVar.IsValid() ) @@ -1475,13 +1633,12 @@ void CHudCommentary::StartSceneCommentary( C_PointCommentaryNode *pNode, char *p if (!m_bShouldPaint && commentary_audio_element_below_cc.GetBool()) { m_bShouldPaint = true; - RepositionCloseCaption(); + m_bShouldRepositionSubtitles = true; } + else + m_bShouldRepositionSubtitles = false; - if (commentary_combine_speaker_and_printname.GetBool() && pNode && pNode->m_iszPrintName[0] != '\0') - { - CombineSpeakerAndPrintName( pNode->m_iszPrintName ); - } + FixupCommentaryLabels( pNode->m_iszPrintName, pNode->m_iszSpeakers, pNode->m_iszFootnote ); SetPaintBackgroundEnabled( m_bShouldPaint ); @@ -1514,12 +1671,8 @@ void CHudCommentary::StopCommentary( void ) CHudCloseCaption *pHudCloseCaption = (CHudCloseCaption *)GET_HUDELEMENT( CHudCloseCaption ); if (pHudCloseCaption && pHudCloseCaption->IsUsingCommentaryDimensions()) { - int ccX, ccY; - pHudCloseCaption->GetPos( ccX, ccY ); - //pHudCloseCaption->SetPos( ccX, ccY + m_iTypeAudioT ); - // Run this animation command instead of setting the position directly - g_pClientMode->GetViewportAnimationController()->RunAnimationCommand( pHudCloseCaption, "YPos", ccY + m_iTypeAudioT, 0.0f, 0.4f, vgui::AnimationController::INTERPOLATOR_ACCEL ); + g_pClientMode->GetViewportAnimationController()->RunAnimationCommand( pHudCloseCaption, "YPos", m_iCCDefaultY, 0.0f, 0.4f, vgui::AnimationController::INTERPOLATOR_ACCEL ); pHudCloseCaption->SetUsingCommentaryDimensions( false ); } @@ -1530,33 +1683,73 @@ void CHudCommentary::StopCommentary( void ) //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- -void CHudCommentary::CombineSpeakerAndPrintName( const char *pszPrintName ) +void CHudCommentary::FixupCommentaryLabels( const char *pszPrintName, const char *pszSpeakers, const char *pszFootnote ) { - wchar_t *pszLocal = g_pVGuiLocalize->Find( pszPrintName ); - if (m_szSpeakers[0] == '\0' || !m_bShouldPaint) // Use m_bShouldPaint as an indicator of whether or not we use subtitles + if (commentary_combine_speaker_and_printname.GetBool() && pszPrintName[0] != '\0') { - if (pszPrintName[0] == '#' && pszLocal) - wcsncpy( m_szSpeakers, pszLocal, sizeof( m_szSpeakers ) / sizeof( wchar_t ) ); + wchar_t *pszLocal = g_pVGuiLocalize->Find( pszPrintName ); + if (m_szSpeakers[0] == '\0' || !m_bShouldPaint) // Use m_bShouldPaint as an indicator of whether or not we use subtitles + { + if (pszPrintName[0] == '#' && pszLocal) + wcsncpy( m_szSpeakers, pszLocal, sizeof( m_szSpeakers ) / sizeof( wchar_t ) ); + else + g_pVGuiLocalize->ConvertANSIToUnicode( pszPrintName, m_szSpeakers, sizeof( m_szSpeakers ) ); + } else - g_pVGuiLocalize->ConvertANSIToUnicode( pszPrintName, m_szSpeakers, sizeof( m_szSpeakers ) ); + { + static wchar_t iszPrintNameLocalized[MAX_SPEAKER_NAME]; + + if (m_szSpeakers[0] == '#') + { + wchar_t *pwszSpeakers = g_pVGuiLocalize->Find( pszSpeakers ); + if (pwszSpeakers) + wcsncpy( m_szSpeakers, pwszSpeakers, sizeof( m_szSpeakers ) / sizeof( wchar_t ) ); + } + + if (pszPrintName[0] == '#' && pszLocal) + wcsncpy( iszPrintNameLocalized, pszLocal, sizeof( iszPrintNameLocalized ) / sizeof( wchar_t ) ); + else + g_pVGuiLocalize->ConvertANSIToUnicode( pszPrintName, iszPrintNameLocalized, sizeof( iszPrintNameLocalized ) ); + + V_snwprintf( m_szSpeakers, sizeof( m_szSpeakers ), L"%ls ~ %ls", m_szSpeakers, iszPrintNameLocalized ); + } + } + + if (pszFootnote[0] != '\0' && m_bShouldPaint) + { + m_pFootnoteLabel->SetText( pszFootnote ); + m_pFootnoteLabel->SetFont( m_hSmallFont ); + m_pFootnoteLabel->SetWrap( true ); + m_pFootnoteLabel->SetEnabled( true ); + m_pFootnoteLabel->SetPaintEnabled( true ); + m_pFootnoteLabel->SetPaintBackgroundEnabled( false ); + m_pFootnoteLabel->SetPaintBorderEnabled( false ); + //m_pFootnoteLabel->SizeToContents(); + m_pFootnoteLabel->SetContentAlignment( vgui::Label::a_northwest ); + m_pFootnoteLabel->SetFgColor( m_ForegroundColor ); } else { - static wchar_t iszPrintNameLocalized[MAX_SPEAKER_NAME]; + m_pFootnoteLabel->SetPaintEnabled( false ); + m_pFootnoteLabel->SetEnabled( false ); + } - if (pszPrintName[0] == '#' && pszLocal) - wcsncpy( iszPrintNameLocalized, pszLocal, sizeof( iszPrintNameLocalized ) / sizeof( wchar_t ) ); - else - g_pVGuiLocalize->ConvertANSIToUnicode( pszPrintName, iszPrintNameLocalized, sizeof( iszPrintNameLocalized ) ); + // Reset close caption element if it's still using commentary dimensions + // (fixes problems with switching from node to node) + CHudCloseCaption *pHudCloseCaption = (CHudCloseCaption *)GET_HUDELEMENT( CHudCloseCaption ); + if (pHudCloseCaption && pHudCloseCaption->IsUsingCommentaryDimensions()) + { + // Run this animation command instead of setting the position directly + g_pClientMode->GetViewportAnimationController()->RunAnimationCommand( pHudCloseCaption, "YPos", m_iCCDefaultY, 0.0f, 0.4f, vgui::AnimationController::INTERPOLATOR_ACCEL ); - V_snwprintf( m_szSpeakers, sizeof( m_szSpeakers ), L"%ls ~ %ls", m_szSpeakers, iszPrintNameLocalized ); + pHudCloseCaption->SetUsingCommentaryDimensions( false ); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- -void CHudCommentary::RepositionCloseCaption() +void CHudCommentary::RepositionAndFollowCloseCaption( int yOffset ) { // Invert the Y axis //SetPos( m_iTypeAudioX, ScreenHeight() - m_iTypeAudioY ); @@ -1577,7 +1770,7 @@ void CHudCommentary::RepositionCloseCaption() if (!pHudCloseCaption->IsUsingCommentaryDimensions()) { - if (m_iCCDefaultY != ccY && !pHudCloseCaption->IsUsingCommentaryDimensions()) + if (m_iCCDefaultY != ccY /*&& !pHudCloseCaption->IsUsingCommentaryDimensions()*/) { DevMsg( "CHudCommentary had to reset misaligned CC element Y (%i) to default Y (%i)\n", ccY, m_iCCDefaultY ); ccY = m_iCCDefaultY; @@ -1586,7 +1779,7 @@ void CHudCommentary::RepositionCloseCaption() ccY -= m_iTypeAudioT; // Run this animation command instead of setting the position directly - g_pClientMode->GetViewportAnimationController()->RunAnimationCommand( pHudCloseCaption, "YPos", ccY, 0.0f, 0.2f, vgui::AnimationController::INTERPOLATOR_DEACCEL ); + g_pClientMode->GetViewportAnimationController()->RunAnimationCommand( pHudCloseCaption, "YPos", ccY - yOffset, 0.0f, 0.2f, vgui::AnimationController::INTERPOLATOR_DEACCEL ); //pHudCloseCaption->SetPos( ccX, ccY ); pHudCloseCaption->SetUsingCommentaryDimensions( true ); diff --git a/sp/src/game/server/CommentarySystem.cpp b/sp/src/game/server/CommentarySystem.cpp index 3b4ef12b..7ff8b33e 100644 --- a/sp/src/game/server/CommentarySystem.cpp +++ b/sp/src/game/server/CommentarySystem.cpp @@ -24,6 +24,8 @@ #include "Sprite.h" #ifdef MAPBASE #include "mapbase/SystemConvarMod.h" +#include +#include #endif // memdbgon must be the last include file in a .cpp file!!! @@ -130,6 +132,8 @@ public: void SetSpeakers( const char *pszSpeakers ) { m_iszSpeakers.Set( AllocPooledString( pszSpeakers ) ); } const char *GetPrintName() { return STRING( m_iszPrintName.Get() ); } void SetPrintName( const char *pszPrintName ) { m_iszPrintName.Set( AllocPooledString( pszPrintName ) ); } + const char *GetFootnote() { return STRING( m_iszFootnote.Get() ); } + void SetFootnote( const char *pszFootnote ) { m_iszFootnote.Set( AllocPooledString( pszFootnote ) ); } #endif // Inputs @@ -165,6 +169,7 @@ private: float m_flViewPositionSpeedScale; float m_flReturnSpeedScale; CNetworkVar( string_t, m_iszPrintName ); + CNetworkVar( string_t, m_iszFootnote ); float m_flViewPositionChangedTime; // View position now blends relative to this value. Mainly needed for when SetViewPosition is used #endif bool m_bPreventMovement; @@ -226,6 +231,7 @@ BEGIN_DATADESC( CPointCommentaryNode ) DEFINE_KEYFIELD( m_flViewPositionSpeedScale, FIELD_FLOAT, "viewposition_speed" ), DEFINE_KEYFIELD( m_flReturnSpeedScale, FIELD_FLOAT, "return_speed" ), DEFINE_KEYFIELD( m_iszPrintName, FIELD_STRING, "printname" ), + DEFINE_KEYFIELD( m_iszFootnote, FIELD_STRING, "footnote" ), DEFINE_FIELD( m_flViewPositionChangedTime, FIELD_TIME ), DEFINE_KEYFIELD( m_iCommentaryType, FIELD_INTEGER, "type" ), DEFINE_KEYFIELD( m_flPanelScale, FIELD_FLOAT, "panelscale" ), @@ -271,6 +277,8 @@ BEGIN_ENT_SCRIPTDESC( CPointCommentaryNode, CBaseAnimating, "Commentary nodes wh DEFINE_SCRIPTFUNC( SetSpeakers, "" ) DEFINE_SCRIPTFUNC( GetPrintName, "" ) DEFINE_SCRIPTFUNC( SetPrintName, "" ) + DEFINE_SCRIPTFUNC( GetFootnote, "" ) + DEFINE_SCRIPTFUNC( SetFootnote, "" ) DEFINE_SCRIPTFUNC( GetCommentaryType, "" ) DEFINE_SCRIPTFUNC( SetCommentaryType, "" ) @@ -296,6 +304,7 @@ IMPLEMENT_SERVERCLASS_ST( CPointCommentaryNode, DT_PointCommentaryNode ) SendPropEHandle( SENDINFO(m_hViewPosition) ), #ifdef MAPBASE SendPropStringT( SENDINFO( m_iszPrintName ) ), + SendPropStringT( SENDINFO( m_iszFootnote ) ), SendPropInt( SENDINFO( m_iCommentaryType ), 2, SPROP_UNSIGNED ), SendPropFloat( SENDINFO( m_flPanelScale ) ), SendPropFloat( SENDINFO( m_flPanelX ) ), @@ -782,6 +791,11 @@ public: #endif engine->LockNetworkStringTables( oldLock ); + +#ifdef MAPBASE + // Special commentary localization file (useful for things like text nodes or print names) + g_pVGuiLocalize->AddFile( "resource/commentary_%language%.txt", "MOD" ); +#endif } void ShutDownCommentary( void ) From daa4779978a1def63b5f781b11708e26bbf88b7d Mon Sep 17 00:00:00 2001 From: Blixibon Date: Tue, 26 Apr 2022 08:04:54 -0500 Subject: [PATCH 336/378] Small fixes for issues of various sizes --- sp/src/game/server/ai_motor.cpp | 1 + sp/src/game/server/basecombatcharacter.cpp | 1 - sp/src/game/server/baseentity.cpp | 2 +- sp/src/game/server/hl2/npc_combine.cpp | 2 +- sp/src/game/server/hl2/npc_metropolice.cpp | 2 +- sp/src/game/server/hl2/weapon_sniperrifle.cpp | 2 +- sp/src/game/server/player.cpp | 1 + sp/src/game/shared/baseviewmodel_shared.cpp | 2 +- sp/src/game/shared/takedamageinfo.h | 4 ++-- 9 files changed, 9 insertions(+), 8 deletions(-) diff --git a/sp/src/game/server/ai_motor.cpp b/sp/src/game/server/ai_motor.cpp index 87a8ec6e..43eb86a3 100644 --- a/sp/src/game/server/ai_motor.cpp +++ b/sp/src/game/server/ai_motor.cpp @@ -845,6 +845,7 @@ void CAI_Motor::MoveFacing( const AILocalMoveGoal_t &move ) { // Don't let the facing queue interfere with arrival direction in important cases dir = move.facing; + VectorNormalize( dir ); } else #endif diff --git a/sp/src/game/server/basecombatcharacter.cpp b/sp/src/game/server/basecombatcharacter.cpp index f4b35392..5ea5c65d 100644 --- a/sp/src/game/server/basecombatcharacter.cpp +++ b/sp/src/game/server/basecombatcharacter.cpp @@ -2789,7 +2789,6 @@ Activity CBaseCombatCharacter::Weapon_BackupActivity( Activity activity, bool we if (pTable && GetModelPtr()) { - int actCount = pWeapon->GetBackupActivityListCount(); return Weapon_BackupActivityFromList( this, pTable, actCount, activity, weaponTranslationWasRequired, pWeapon ); } diff --git a/sp/src/game/server/baseentity.cpp b/sp/src/game/server/baseentity.cpp index 42f857de..5e47d89e 100644 --- a/sp/src/game/server/baseentity.cpp +++ b/sp/src/game/server/baseentity.cpp @@ -7707,7 +7707,7 @@ bool CBaseEntity::HasContext( const char *name, const char *value ) const if (value == NULL) return true; else - return Matcher_Match(STRING(m_ResponseContexts[i].m_iszValue), value); + return Matcher_Match( value, STRING(m_ResponseContexts[i].m_iszValue) ); } } diff --git a/sp/src/game/server/hl2/npc_combine.cpp b/sp/src/game/server/hl2/npc_combine.cpp index 50d10982..73bac242 100644 --- a/sp/src/game/server/hl2/npc_combine.cpp +++ b/sp/src/game/server/hl2/npc_combine.cpp @@ -2719,7 +2719,7 @@ void CNPC_Combine::HandleAnimEvent( animevent_t *pEvent ) else if ( pEvent->event == COMBINE_AE_ALTFIRE ) { #ifdef MAPBASE - if ( IsAltFireCapable() ) + if ( IsAltFireCapable() && GetActiveWeapon() ) #else if ( IsElite() ) #endif diff --git a/sp/src/game/server/hl2/npc_metropolice.cpp b/sp/src/game/server/hl2/npc_metropolice.cpp index 229db7b0..5f6151c4 100644 --- a/sp/src/game/server/hl2/npc_metropolice.cpp +++ b/sp/src/game/server/hl2/npc_metropolice.cpp @@ -1539,7 +1539,7 @@ void CNPC_MetroPolice::OnUpdateShotRegulator( ) // FIXME: This code (except the burst interval) could be used for all weapon types #ifdef MAPBASE // Only if we actually have the pistol out - if ( EntIsClass( GetActiveWeapon(), gm_isz_class_Pistol ) ) + if ( GetActiveWeapon() && EntIsClass( GetActiveWeapon(), gm_isz_class_Pistol ) ) #else if( Weapon_OwnsThisType( "weapon_pistol" ) ) #endif diff --git a/sp/src/game/server/hl2/weapon_sniperrifle.cpp b/sp/src/game/server/hl2/weapon_sniperrifle.cpp index 10777f89..f2939fcc 100644 --- a/sp/src/game/server/hl2/weapon_sniperrifle.cpp +++ b/sp/src/game/server/hl2/weapon_sniperrifle.cpp @@ -107,7 +107,7 @@ END_DATADESC() //----------------------------------------------------------------------------- acttable_t CWeaponSniperRifle::m_acttable[] = { - { ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_SNIPER_RIFLE, true } + { ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_SNIPER_RIFLE, true }, #if EXPANDED_HL2_UNUSED_WEAPON_ACTIVITIES // Optional new NPC activities diff --git a/sp/src/game/server/player.cpp b/sp/src/game/server/player.cpp index 00aefbb8..6092dcd8 100644 --- a/sp/src/game/server/player.cpp +++ b/sp/src/game/server/player.cpp @@ -662,6 +662,7 @@ void CBasePlayer::CreateHandModel(int index, int iOtherVm) DispatchSpawn(vm); vm->FollowEntity(GetViewModel(iOtherVm), true); m_hViewModel.Set(index, vm); + vm->AddEffects( EF_NODRAW ); } } #endif diff --git a/sp/src/game/shared/baseviewmodel_shared.cpp b/sp/src/game/shared/baseviewmodel_shared.cpp index aa8ddbae..5f9c0f10 100644 --- a/sp/src/game/shared/baseviewmodel_shared.cpp +++ b/sp/src/game/shared/baseviewmodel_shared.cpp @@ -368,7 +368,7 @@ void CBaseViewModel::SetWeaponModel( const char *modelname, CBaseCombatWeapon *w #ifdef MAPBASE // If our owning weapon doesn't support hands, disable the hands viewmodel(s) - bool bSupportsHands = weapon->UsesHands(); + bool bSupportsHands = weapon != NULL ? weapon->UsesHands() : false; for (CBaseEntity *pChild = FirstMoveChild(); pChild != NULL; pChild = pChild->NextMovePeer()) { if (pChild->GetClassname()[0] == 'h') diff --git a/sp/src/game/shared/takedamageinfo.h b/sp/src/game/shared/takedamageinfo.h index 840432b1..046c8111 100644 --- a/sp/src/game/shared/takedamageinfo.h +++ b/sp/src/game/shared/takedamageinfo.h @@ -344,12 +344,12 @@ inline void CTakeDamageInfo::SetDamageCustom( int iDamageCustom ) inline int CTakeDamageInfo::GetDamageStats() const { - return m_iDamageCustom; + return m_iDamageStats; } inline void CTakeDamageInfo::SetDamageStats( int iDamageCustom ) { - m_iDamageCustom = iDamageCustom; + m_iDamageStats = iDamageCustom; } inline int CTakeDamageInfo::GetAmmoType() const From 633e90fe16353e9b0006ec9670e58022f82ff4b3 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Tue, 26 Apr 2022 08:05:47 -0500 Subject: [PATCH 337/378] Added GetNewlinePositions for vgui::TextImage --- sp/src/public/vgui_controls/TextImage.h | 5 + sp/src/vgui2/vgui_controls/TextImage.cpp | 114 +++++++++++++++++++++++ 2 files changed, 119 insertions(+) diff --git a/sp/src/public/vgui_controls/TextImage.h b/sp/src/public/vgui_controls/TextImage.h index 499785ff..a410cb95 100644 --- a/sp/src/public/vgui_controls/TextImage.h +++ b/sp/src/public/vgui_controls/TextImage.h @@ -105,6 +105,11 @@ public: void SetColorChangeStream( CUtlSortVector *pUtlVecStream ); void ClearColorChangeStream( void ) { m_ColorChangeStream.Purge(); } +#ifdef MAPBASE + // Gets the relative y coordinates of all new lines created by newline (\n) characters. + void GetNewlinePositions( CUtlVector *pOutCoords, bool bIgnoreEmptyLines = true ); +#endif + protected: // truncate the _text string to fit into the draw width void SizeText(wchar_t *tempText, int stringLength); diff --git a/sp/src/vgui2/vgui_controls/TextImage.cpp b/sp/src/vgui2/vgui_controls/TextImage.cpp index 61532126..b6b9ff29 100644 --- a/sp/src/vgui2/vgui_controls/TextImage.cpp +++ b/sp/src/vgui2/vgui_controls/TextImage.cpp @@ -983,3 +983,117 @@ void TextImage::SetColorChangeStream( CUtlSortVector *pOutCoords, bool bIgnoreEmptyLines ) +{ + HFont font = GetFont(); + if (!_utext || font == INVALID_FONT ) + return; + + // Early out if there's no newlines in our text + if (wcschr( _utext, L'\n' ) == NULL) + return; + + if (m_bRecalculateTruncation) + { + if ( m_bWrap || m_bWrapCenter ) + { + RecalculateNewLinePositions(); + } + + RecalculateEllipsesPosition(); + } + + int lineHeight = surface()->GetFontTall( GetFont() ); + float x = 0.0f; + int y = 0; + int iIndent = 0; + + int px, py; + GetPos(px, py); + + int currentLineBreak = 0; + + if ( m_bWrapCenter && m_LineXIndent.Count() ) + { + x = m_LineXIndent[0]; + } + + for (wchar_t *wsz = _utext; *wsz != 0; wsz++) + { + wchar_t ch = wsz[0]; + + if ( m_bAllCaps ) + { + ch = towupper( ch ); + } + + // check for special characters + if ( ch == '\r' || ch <= 8 ) + { + // ignore, just use \n for newlines + continue; + } + else if (ch == '\n') + { + // newline + iIndent++; + if ( m_bWrapCenter && iIndent < m_LineXIndent.Count() ) + { + x = m_LineXIndent[iIndent]; + } + else + { + x = 0; + } + y += lineHeight; + + if (!bIgnoreEmptyLines || (*(wsz + 1) != 0 && wsz[1] != '\n')) + { + pOutCoords->AddToTail( y ); + } + + continue; + } + else if (ch == '&') + { + // "&&" means draw a single ampersand, single one is a shortcut character + if (wsz[1] == '&') + { + // just move on and draw the second ampersand + wsz++; + } + } + + // see if we've hit the truncated portion of the string + if (wsz == m_pwszEllipsesPosition) + { + // do nothing + } + + if (currentLineBreak != m_LineBreaks.Count()) + { + if (wsz == m_LineBreaks[currentLineBreak]) + { + // newline + iIndent++; + if ( m_bWrapCenter && iIndent < m_LineXIndent.Count() ) + { + x = m_LineXIndent[iIndent]; + } + else + { + x = 0; + } + + y += lineHeight; + currentLineBreak++; + } + } + + // Underlined text wants to draw the spaces anyway + x += surface()->GetCharacterWidth(font, ch); + } +} +#endif From 4dbe8a7001d155ce363a339efb6796bd47fc1177 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Tue, 26 Apr 2022 08:08:56 -0500 Subject: [PATCH 338/378] Added FIRE_BULLETS_NO_AUTO_GIB_TYPE --- sp/src/game/shared/baseentity_shared.cpp | 4 ++++ sp/src/game/shared/shareddefs.h | 3 +++ 2 files changed, 7 insertions(+) diff --git a/sp/src/game/shared/baseentity_shared.cpp b/sp/src/game/shared/baseentity_shared.cpp index cd3854dd..af49c966 100644 --- a/sp/src/game/shared/baseentity_shared.cpp +++ b/sp/src/game/shared/baseentity_shared.cpp @@ -1931,7 +1931,11 @@ void CBaseEntity::FireBullets( const FireBulletsInfo_t &info ) { flActualDamage = g_pGameRules->GetAmmoDamage( pAttacker, tr.m_pEnt, info.m_iAmmoType ); } +#ifdef MAPBASE + else if ((info.m_nFlags & FIRE_BULLETS_NO_AUTO_GIB_TYPE) == 0) +#else else +#endif { nActualDamageType = nDamageType | ((flActualDamage > 16) ? DMG_ALWAYSGIB : DMG_NEVERGIB ); } diff --git a/sp/src/game/shared/shareddefs.h b/sp/src/game/shared/shareddefs.h index 7e533ceb..2f127c30 100644 --- a/sp/src/game/shared/shareddefs.h +++ b/sp/src/game/shared/shareddefs.h @@ -684,6 +684,9 @@ enum FireBulletsFlags_t FIRE_BULLETS_DONT_HIT_UNDERWATER = 0x2, // If the shot hits its target underwater, don't damage it FIRE_BULLETS_ALLOW_WATER_SURFACE_IMPACTS = 0x4, // If the shot hits water surface, still call DoImpactEffect FIRE_BULLETS_TEMPORARY_DANGER_SOUND = 0x8, // Danger sounds added from this impact can be stomped immediately if another is queued +#ifdef MAPBASE + FIRE_BULLETS_NO_AUTO_GIB_TYPE = 0x10, // Don't automatically add DMG_ALWAYSGIB or DMG_NEVERGIB if m_flDamage is set +#endif }; From 08727cc32217934a8fdac17d1e54895f98f9cc39 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Tue, 26 Apr 2022 08:30:55 -0500 Subject: [PATCH 339/378] Added custom model support and 'NoIdlePatrol' keyvalue to npc_hunter --- sp/src/game/server/episodic/npc_hunter.cpp | 23 ++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/sp/src/game/server/episodic/npc_hunter.cpp b/sp/src/game/server/episodic/npc_hunter.cpp index ac904b81..0699d890 100644 --- a/sp/src/game/server/episodic/npc_hunter.cpp +++ b/sp/src/game/server/episodic/npc_hunter.cpp @@ -1447,6 +1447,10 @@ private: string_t m_iszFollowTarget; // Name of the strider we should follow. CSimpleStopwatch m_BeginFollowDelay; +#ifdef MAPBASE + bool m_bNoIdlePatrol; +#endif + int m_nKillingDamageType; HunterEyeStates_t m_eEyeState; @@ -1549,6 +1553,10 @@ BEGIN_DATADESC( CNPC_Hunter ) DEFINE_KEYFIELD( m_iszFollowTarget, FIELD_STRING, "FollowTarget" ), +#ifdef MAPBASE + DEFINE_KEYFIELD( m_bNoIdlePatrol, FIELD_BOOLEAN, "NoIdlePatrol" ), +#endif + DEFINE_FIELD( m_aimYaw, FIELD_FLOAT ), DEFINE_FIELD( m_aimPitch, FIELD_FLOAT ), @@ -1686,8 +1694,16 @@ CNPC_Hunter::~CNPC_Hunter() //----------------------------------------------------------------------------- void CNPC_Hunter::Precache() { +#ifdef MAPBASE + if (GetModelName() == NULL_STRING) + SetModelName( AllocPooledString( "models/hunter.mdl" ) ); + + PrecacheModel( STRING( GetModelName() ) ); + PropBreakablePrecacheAll( GetModelName() ); +#else PrecacheModel( "models/hunter.mdl" ); PropBreakablePrecacheAll( MAKE_STRING("models/hunter.mdl") ); +#endif PrecacheScriptSound( "NPC_Hunter.Idle" ); PrecacheScriptSound( "NPC_Hunter.Scan" ); @@ -1748,7 +1764,11 @@ void CNPC_Hunter::Spawn() { Precache(); +#ifdef MAPBASE + SetModel( STRING( GetModelName() ) ); +#else SetModel( "models/hunter.mdl" ); +#endif BaseClass::Spawn(); //m_debugOverlays |= OVERLAY_NPC_ROUTE_BIT | OVERLAY_BBOX_BIT | OVERLAY_PIVOT_BIT; @@ -3123,6 +3143,9 @@ int CNPC_Hunter::SelectSchedule() { case NPC_STATE_IDLE: { +#ifdef MAPBASE + if (!m_bNoIdlePatrol) +#endif return SCHED_HUNTER_PATROL; } From 32bbb0c231c6b7b09548e012acb9c191961dc386 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Tue, 26 Apr 2022 08:31:41 -0500 Subject: [PATCH 340/378] Added missing parameters to function in new response code --- sp/src/game/server/ai_speech_new.cpp | 12 ++++++++++++ sp/src/game/server/ai_speech_new.h | 4 ++++ 2 files changed, 16 insertions(+) diff --git a/sp/src/game/server/ai_speech_new.cpp b/sp/src/game/server/ai_speech_new.cpp index 8d73911f..d29b6b39 100644 --- a/sp/src/game/server/ai_speech_new.cpp +++ b/sp/src/game/server/ai_speech_new.cpp @@ -851,7 +851,11 @@ bool CAI_Expresser::SpeakDispatchResponse( AIConcept_t concept, AI_Response *res if ( !result->ShouldntUseScene() ) { // This generates a fake CChoreoScene wrapping the sound.txt name +#ifdef MAPBASE + spoke = SpeakAutoGeneratedScene( response, delay, result, filter ); +#else spoke = SpeakAutoGeneratedScene( response, delay ); +#endif } else { @@ -1300,9 +1304,17 @@ bool CAI_Expresser::SpeakRawScene( const char *pszScene, float delay, AI_Respons } // This will create a fake .vcd/CChoreoScene to wrap the sound to be played +#ifdef MAPBASE +bool CAI_Expresser::SpeakAutoGeneratedScene( char const *soundname, float delay, AI_Response *response, IRecipientFilter *filter ) +#else bool CAI_Expresser::SpeakAutoGeneratedScene( char const *soundname, float delay ) +#endif { +#ifdef MAPBASE + float speakTime = GetOuter()->PlayAutoGeneratedSoundScene( soundname, delay, response, filter ); +#else float speakTime = GetOuter()->PlayAutoGeneratedSoundScene( soundname ); +#endif if ( speakTime > 0 ) { SpeechMsg( GetOuter(), "SpeakAutoGeneratedScene( %s, %f) %f\n", soundname, delay, speakTime ); diff --git a/sp/src/game/server/ai_speech_new.h b/sp/src/game/server/ai_speech_new.h index 70e73354..c61f6f03 100644 --- a/sp/src/game/server/ai_speech_new.h +++ b/sp/src/game/server/ai_speech_new.h @@ -249,7 +249,11 @@ protected: bool SpeakRawScene( const char *pszScene, float delay, AI_Response *response, IRecipientFilter *filter = NULL ); // This will create a fake .vcd/CChoreoScene to wrap the sound to be played +#ifdef MAPBASE + bool SpeakAutoGeneratedScene( char const *soundname, float delay, AI_Response *response = NULL, IRecipientFilter *filter = NULL ); +#else bool SpeakAutoGeneratedScene( char const *soundname, float delay ); +#endif void DumpHistories(); From 033fd9662bab05be7ccac5d3cf211728e6c9eb5e Mon Sep 17 00:00:00 2001 From: Blixibon Date: Tue, 26 Apr 2022 08:34:11 -0500 Subject: [PATCH 341/378] Added new optional weapon activities for AR3, SMG3, and HMG1 --- sp/src/game/server/ai_activity.cpp | 133 ++++++++++++++++++++++++++++ sp/src/game/shared/activitylist.cpp | 114 ++++++++++++++++++++++++ sp/src/game/shared/ai_activity.h | 118 ++++++++++++++++++++++++ 3 files changed, 365 insertions(+) diff --git a/sp/src/game/server/ai_activity.cpp b/sp/src/game/server/ai_activity.cpp index d2316857..5362249d 100644 --- a/sp/src/game/server/ai_activity.cpp +++ b/sp/src/game/server/ai_activity.cpp @@ -2332,6 +2332,32 @@ void CAI_BaseNPC::InitDefaultActivitySR(void) ADD_ACTIVITY_TO_SR( ACT_IDLE_AIM_AR1_STIMULATED ); ADD_ACTIVITY_TO_SR( ACT_WALK_AIM_AR1_STIMULATED ); ADD_ACTIVITY_TO_SR( ACT_RUN_AIM_AR1_STIMULATED ); + + ADD_ACTIVITY_TO_SR( ACT_IDLE_AR3 ); + ADD_ACTIVITY_TO_SR( ACT_IDLE_ANGRY_AR3 ); + ADD_ACTIVITY_TO_SR( ACT_WALK_AR3 ); + ADD_ACTIVITY_TO_SR( ACT_RUN_AR3 ); + ADD_ACTIVITY_TO_SR( ACT_WALK_AIM_AR3 ); + ADD_ACTIVITY_TO_SR( ACT_RUN_AIM_AR3 ); + ADD_ACTIVITY_TO_SR( ACT_RANGE_ATTACK_AR3 ); + ADD_ACTIVITY_TO_SR( ACT_RELOAD_AR3 ); + ADD_ACTIVITY_TO_SR( ACT_RANGE_ATTACK_AR3_LOW ); + ADD_ACTIVITY_TO_SR( ACT_RELOAD_AR3_LOW ); + ADD_ACTIVITY_TO_SR( ACT_COVER_AR3_LOW ); + ADD_ACTIVITY_TO_SR( ACT_RANGE_AIM_AR3_LOW ); + ADD_ACTIVITY_TO_SR( ACT_GESTURE_RANGE_ATTACK_AR3 ); + ADD_ACTIVITY_TO_SR( ACT_GESTURE_RELOAD_AR3 ); + + ADD_ACTIVITY_TO_SR( ACT_IDLE_AR3_RELAXED ); + ADD_ACTIVITY_TO_SR( ACT_IDLE_AR3_STIMULATED ); + ADD_ACTIVITY_TO_SR( ACT_WALK_AR3_RELAXED ); + ADD_ACTIVITY_TO_SR( ACT_RUN_AR3_RELAXED ); + ADD_ACTIVITY_TO_SR( ACT_WALK_AR3_STIMULATED ); + ADD_ACTIVITY_TO_SR( ACT_RUN_AR3_STIMULATED ); + + ADD_ACTIVITY_TO_SR( ACT_IDLE_AIM_AR3_STIMULATED ); + ADD_ACTIVITY_TO_SR( ACT_WALK_AIM_AR3_STIMULATED ); + ADD_ACTIVITY_TO_SR( ACT_RUN_AIM_AR3_STIMULATED ); ADD_ACTIVITY_TO_SR( ACT_IDLE_SMG2 ); ADD_ACTIVITY_TO_SR( ACT_IDLE_ANGRY_SMG2 ); @@ -2358,6 +2384,58 @@ void CAI_BaseNPC::InitDefaultActivitySR(void) ADD_ACTIVITY_TO_SR( ACT_IDLE_AIM_SMG2_STIMULATED ); ADD_ACTIVITY_TO_SR( ACT_WALK_AIM_SMG2_STIMULATED ); ADD_ACTIVITY_TO_SR( ACT_RUN_AIM_SMG2_STIMULATED ); + + ADD_ACTIVITY_TO_SR( ACT_IDLE_SMG3 ); + ADD_ACTIVITY_TO_SR( ACT_IDLE_ANGRY_SMG3 ); + ADD_ACTIVITY_TO_SR( ACT_WALK_SMG3 ); + ADD_ACTIVITY_TO_SR( ACT_RUN_SMG3 ); + ADD_ACTIVITY_TO_SR( ACT_WALK_AIM_SMG3 ); + ADD_ACTIVITY_TO_SR( ACT_RUN_AIM_SMG3 ); + //ADD_ACTIVITY_TO_SR( ACT_RANGE_ATTACK_SMG3 ); + ADD_ACTIVITY_TO_SR( ACT_RELOAD_SMG3 ); + ADD_ACTIVITY_TO_SR( ACT_RANGE_ATTACK_SMG3_LOW ); + ADD_ACTIVITY_TO_SR( ACT_RELOAD_SMG3_LOW ); + ADD_ACTIVITY_TO_SR( ACT_COVER_SMG3_LOW ); + ADD_ACTIVITY_TO_SR( ACT_RANGE_AIM_SMG3_LOW ); + //ADD_ACTIVITY_TO_SR( ACT_GESTURE_RANGE_ATTACK_SMG3 ); + ADD_ACTIVITY_TO_SR( ACT_GESTURE_RELOAD_SMG3 ); + + ADD_ACTIVITY_TO_SR( ACT_IDLE_SMG3_RELAXED ); + ADD_ACTIVITY_TO_SR( ACT_IDLE_SMG3_STIMULATED ); + ADD_ACTIVITY_TO_SR( ACT_WALK_SMG3_RELAXED ); + ADD_ACTIVITY_TO_SR( ACT_RUN_SMG3_RELAXED ); + ADD_ACTIVITY_TO_SR( ACT_WALK_SMG3_STIMULATED ); + ADD_ACTIVITY_TO_SR( ACT_RUN_SMG3_STIMULATED ); + + ADD_ACTIVITY_TO_SR( ACT_IDLE_AIM_SMG3_STIMULATED ); + ADD_ACTIVITY_TO_SR( ACT_WALK_AIM_SMG3_STIMULATED ); + ADD_ACTIVITY_TO_SR( ACT_RUN_AIM_SMG3_STIMULATED ); + + ADD_ACTIVITY_TO_SR( ACT_IDLE_HMG1 ); + ADD_ACTIVITY_TO_SR( ACT_IDLE_ANGRY_HMG1 ); + ADD_ACTIVITY_TO_SR( ACT_WALK_HMG1 ); + ADD_ACTIVITY_TO_SR( ACT_RUN_HMG1 ); + ADD_ACTIVITY_TO_SR( ACT_WALK_AIM_HMG1 ); + ADD_ACTIVITY_TO_SR( ACT_RUN_AIM_HMG1 ); + //ADD_ACTIVITY_TO_SR( ACT_RANGE_ATTACK_HMG1 ); + ADD_ACTIVITY_TO_SR( ACT_RELOAD_HMG1 ); + ADD_ACTIVITY_TO_SR( ACT_RANGE_ATTACK_HMG1_LOW ); + ADD_ACTIVITY_TO_SR( ACT_RELOAD_HMG1_LOW ); + ADD_ACTIVITY_TO_SR( ACT_COVER_HMG1_LOW ); + ADD_ACTIVITY_TO_SR( ACT_RANGE_AIM_HMG1_LOW ); + //ADD_ACTIVITY_TO_SR( ACT_GESTURE_RANGE_ATTACK_HMG1 ); + ADD_ACTIVITY_TO_SR( ACT_GESTURE_RELOAD_HMG1 ); + + ADD_ACTIVITY_TO_SR( ACT_IDLE_HMG1_RELAXED ); + ADD_ACTIVITY_TO_SR( ACT_IDLE_HMG1_STIMULATED ); + ADD_ACTIVITY_TO_SR( ACT_WALK_HMG1_RELAXED ); + ADD_ACTIVITY_TO_SR( ACT_RUN_HMG1_RELAXED ); + ADD_ACTIVITY_TO_SR( ACT_WALK_HMG1_STIMULATED ); + ADD_ACTIVITY_TO_SR( ACT_RUN_HMG1_STIMULATED ); + + ADD_ACTIVITY_TO_SR( ACT_IDLE_AIM_HMG1_STIMULATED ); + ADD_ACTIVITY_TO_SR( ACT_WALK_AIM_HMG1_STIMULATED ); + ADD_ACTIVITY_TO_SR( ACT_RUN_AIM_HMG1_STIMULATED ); ADD_ACTIVITY_TO_SR( ACT_IDLE_SNIPER_RIFLE ); ADD_ACTIVITY_TO_SR( ACT_IDLE_ANGRY_SNIPER_RIFLE ); @@ -2419,8 +2497,14 @@ void CAI_BaseNPC::InitDefaultActivitySR(void) #if EXPANDED_HL2_UNUSED_WEAPON_ACTIVITIES ADD_ACTIVITY_TO_SR( ACT_RANGE_AIM_AR1_MED ); ADD_ACTIVITY_TO_SR( ACT_RANGE_ATTACK_AR1_MED ); + ADD_ACTIVITY_TO_SR( ACT_RANGE_AIM_AR3_MED ); + ADD_ACTIVITY_TO_SR( ACT_RANGE_ATTACK_AR3_MED ); ADD_ACTIVITY_TO_SR( ACT_RANGE_AIM_SMG2_MED ); ADD_ACTIVITY_TO_SR( ACT_RANGE_ATTACK_SMG2_MED ); + ADD_ACTIVITY_TO_SR( ACT_RANGE_AIM_SMG3_MED ); + ADD_ACTIVITY_TO_SR( ACT_RANGE_ATTACK_SMG3_MED ); + ADD_ACTIVITY_TO_SR( ACT_RANGE_AIM_HMG1_MED ); + ADD_ACTIVITY_TO_SR( ACT_RANGE_ATTACK_HMG1_MED ); ADD_ACTIVITY_TO_SR( ACT_RANGE_AIM_SNIPER_RIFLE_MED ); ADD_ACTIVITY_TO_SR( ACT_RANGE_ATTACK_SNIPER_RIFLE_MED ); #endif @@ -2486,6 +2570,16 @@ void CAI_BaseNPC::InitDefaultActivitySR(void) ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RANGE_ATTACK2_AR1 ); ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RELOAD_AR1 ); ADD_ACTIVITY_TO_SR( ACT_HL2MP_JUMP_AR1 ); + + ADD_ACTIVITY_TO_SR( ACT_HL2MP_IDLE_AR3 ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_RUN_AR3 ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_WALK_AR3 ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_IDLE_CROUCH_AR3 ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_WALK_CROUCH_AR3 ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RANGE_ATTACK_AR3 ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RANGE_ATTACK2_AR3 ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RELOAD_AR3 ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_JUMP_AR3 ); ADD_ACTIVITY_TO_SR( ACT_HL2MP_IDLE_SMG2 ); ADD_ACTIVITY_TO_SR( ACT_HL2MP_RUN_SMG2 ); @@ -2496,6 +2590,26 @@ void CAI_BaseNPC::InitDefaultActivitySR(void) ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RANGE_ATTACK2_SMG2 ); ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RELOAD_SMG2 ); ADD_ACTIVITY_TO_SR( ACT_HL2MP_JUMP_SMG2 ); + + ADD_ACTIVITY_TO_SR( ACT_HL2MP_IDLE_SMG3 ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_RUN_SMG3 ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_WALK_SMG3 ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_IDLE_CROUCH_SMG3 ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_WALK_CROUCH_SMG3 ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RANGE_ATTACK_SMG3 ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RANGE_ATTACK2_SMG3 ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RELOAD_SMG3 ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_JUMP_SMG3 ); + + ADD_ACTIVITY_TO_SR( ACT_HL2MP_IDLE_HMG1 ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_RUN_HMG1 ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_WALK_HMG1 ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_IDLE_CROUCH_HMG1 ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_WALK_CROUCH_HMG1 ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RANGE_ATTACK_HMG1 ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RANGE_ATTACK2_HMG1 ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_GESTURE_RELOAD_HMG1 ); + ADD_ACTIVITY_TO_SR( ACT_HL2MP_JUMP_HMG1 ); ADD_ACTIVITY_TO_SR( ACT_HL2MP_IDLE_SNIPER_RIFLE ); ADD_ACTIVITY_TO_SR( ACT_HL2MP_RUN_SNIPER_RIFLE ); @@ -2614,11 +2728,16 @@ CAI_BaseNPC::actlink_t CAI_BaseNPC::gm_ActivityGestureLinks[] = #if EXPANDED_HL2_UNUSED_WEAPON_ACTIVITIES { ACT_RANGE_ATTACK_AR1, ACT_GESTURE_RANGE_ATTACK_AR1 }, { ACT_RANGE_ATTACK_AR1_LOW, ACT_GESTURE_RANGE_ATTACK_AR1 }, + { ACT_RANGE_ATTACK_AR3, ACT_GESTURE_RANGE_ATTACK_AR3 }, + { ACT_RANGE_ATTACK_AR3_LOW, ACT_GESTURE_RANGE_ATTACK_AR3 }, { ACT_RANGE_ATTACK_AR2_GRENADE, ACT_GESTURE_RANGE_ATTACK_AR2_GRENADE }, { ACT_RANGE_ATTACK_HMG1, ACT_GESTURE_RANGE_ATTACK_HMG1 }, + { ACT_RANGE_ATTACK_HMG1_LOW, ACT_GESTURE_RANGE_ATTACK_HMG1 }, { ACT_RANGE_ATTACK_ML, ACT_GESTURE_RANGE_ATTACK_ML }, { ACT_RANGE_ATTACK_SMG2, ACT_GESTURE_RANGE_ATTACK_SMG2 }, { ACT_RANGE_ATTACK_SMG2_LOW, ACT_GESTURE_RANGE_ATTACK_SMG2 }, + { ACT_RANGE_ATTACK_SMG3, ACT_GESTURE_RANGE_ATTACK_SMG3 }, + { ACT_RANGE_ATTACK_SMG3_LOW, ACT_GESTURE_RANGE_ATTACK_SMG3 }, { ACT_RANGE_ATTACK_SLAM, ACT_GESTURE_RANGE_ATTACK_SLAM }, { ACT_RANGE_ATTACK_TRIPWIRE, ACT_GESTURE_RANGE_ATTACK_TRIPWIRE }, { ACT_RANGE_ATTACK_THROW, ACT_GESTURE_RANGE_ATTACK_THROW }, @@ -2627,8 +2746,14 @@ CAI_BaseNPC::actlink_t CAI_BaseNPC::gm_ActivityGestureLinks[] = { ACT_RELOAD_AR1, ACT_GESTURE_RELOAD_AR1 }, { ACT_RELOAD_AR1_LOW, ACT_GESTURE_RELOAD_AR1 }, + { ACT_RELOAD_AR3, ACT_GESTURE_RELOAD_AR3 }, + { ACT_RELOAD_AR3_LOW, ACT_GESTURE_RELOAD_AR3 }, { ACT_RELOAD_SMG2, ACT_GESTURE_RELOAD_SMG2 }, { ACT_RELOAD_SMG2_LOW, ACT_GESTURE_RELOAD_SMG2 }, + { ACT_RELOAD_SMG3, ACT_GESTURE_RELOAD_SMG3 }, + { ACT_RELOAD_SMG3_LOW, ACT_GESTURE_RELOAD_SMG3 }, + { ACT_RELOAD_HMG1, ACT_GESTURE_RELOAD_HMG1 }, + { ACT_RELOAD_HMG1_LOW, ACT_GESTURE_RELOAD_HMG1 }, { ACT_RELOAD_SNIPER_RIFLE, ACT_GESTURE_RELOAD_SNIPER_RIFLE }, { ACT_RELOAD_SNIPER_RIFLE_LOW, ACT_GESTURE_RELOAD_SNIPER_RIFLE }, #endif @@ -2646,6 +2771,14 @@ CAI_BaseNPC::actlink_t CAI_BaseNPC::gm_ActivityGestureLinks[] = { ACT_RANGE_ATTACK_REVOLVER_MED, ACT_GESTURE_RANGE_ATTACK_REVOLVER }, { ACT_RANGE_ATTACK_CROSSBOW_MED, ACT_GESTURE_RANGE_ATTACK_CROSSBOW }, #endif +#if EXPANDED_HL2_UNUSED_WEAPON_ACTIVITIES + { ACT_RANGE_ATTACK_AR1_MED, ACT_GESTURE_RANGE_ATTACK_AR1 }, + { ACT_RANGE_ATTACK_AR3_MED, ACT_GESTURE_RANGE_ATTACK_AR3 }, + { ACT_RANGE_ATTACK_SMG2_MED, ACT_GESTURE_RANGE_ATTACK_SMG2 }, + { ACT_RANGE_ATTACK_SMG3_MED, ACT_GESTURE_RANGE_ATTACK_SMG3 }, + { ACT_RANGE_ATTACK_HMG1_MED, ACT_GESTURE_RANGE_ATTACK_HMG1 }, + { ACT_RANGE_ATTACK_SNIPER_RIFLE_MED, ACT_GESTURE_RANGE_ATTACK_SNIPER_RIFLE }, +#endif #endif }; diff --git a/sp/src/game/shared/activitylist.cpp b/sp/src/game/shared/activitylist.cpp index b8aea0bf..e8191ed0 100644 --- a/sp/src/game/shared/activitylist.cpp +++ b/sp/src/game/shared/activitylist.cpp @@ -2448,6 +2448,32 @@ void ActivityList_RegisterSharedActivities( void ) REGISTER_SHARED_ACTIVITY( ACT_IDLE_AIM_AR1_STIMULATED ); REGISTER_SHARED_ACTIVITY( ACT_WALK_AIM_AR1_STIMULATED ); REGISTER_SHARED_ACTIVITY( ACT_RUN_AIM_AR1_STIMULATED ); + + REGISTER_SHARED_ACTIVITY( ACT_IDLE_AR3 ); + REGISTER_SHARED_ACTIVITY( ACT_IDLE_ANGRY_AR3 ); + REGISTER_SHARED_ACTIVITY( ACT_WALK_AR3 ); + REGISTER_SHARED_ACTIVITY( ACT_RUN_AR3 ); + REGISTER_SHARED_ACTIVITY( ACT_WALK_AIM_AR3 ); + REGISTER_SHARED_ACTIVITY( ACT_RUN_AIM_AR3 ); + REGISTER_SHARED_ACTIVITY( ACT_RANGE_ATTACK_AR3 ); + REGISTER_SHARED_ACTIVITY( ACT_RELOAD_AR3 ); + REGISTER_SHARED_ACTIVITY( ACT_RANGE_ATTACK_AR3_LOW ); + REGISTER_SHARED_ACTIVITY( ACT_RELOAD_AR3_LOW ); + REGISTER_SHARED_ACTIVITY( ACT_COVER_AR3_LOW ); + REGISTER_SHARED_ACTIVITY( ACT_RANGE_AIM_AR3_LOW ); + REGISTER_SHARED_ACTIVITY( ACT_GESTURE_RANGE_ATTACK_AR3 ); + REGISTER_SHARED_ACTIVITY( ACT_GESTURE_RELOAD_AR3 ); + + REGISTER_SHARED_ACTIVITY( ACT_IDLE_AR3_RELAXED ); + REGISTER_SHARED_ACTIVITY( ACT_IDLE_AR3_STIMULATED ); + REGISTER_SHARED_ACTIVITY( ACT_WALK_AR3_RELAXED ); + REGISTER_SHARED_ACTIVITY( ACT_RUN_AR3_RELAXED ); + REGISTER_SHARED_ACTIVITY( ACT_WALK_AR3_STIMULATED ); + REGISTER_SHARED_ACTIVITY( ACT_RUN_AR3_STIMULATED ); + + REGISTER_SHARED_ACTIVITY( ACT_IDLE_AIM_AR3_STIMULATED ); + REGISTER_SHARED_ACTIVITY( ACT_WALK_AIM_AR3_STIMULATED ); + REGISTER_SHARED_ACTIVITY( ACT_RUN_AIM_AR3_STIMULATED ); REGISTER_SHARED_ACTIVITY( ACT_IDLE_SMG2 ); REGISTER_SHARED_ACTIVITY( ACT_IDLE_ANGRY_SMG2 ); @@ -2475,6 +2501,58 @@ void ActivityList_RegisterSharedActivities( void ) REGISTER_SHARED_ACTIVITY( ACT_WALK_AIM_SMG2_STIMULATED ); REGISTER_SHARED_ACTIVITY( ACT_RUN_AIM_SMG2_STIMULATED ); + REGISTER_SHARED_ACTIVITY( ACT_IDLE_SMG3 ); + REGISTER_SHARED_ACTIVITY( ACT_IDLE_ANGRY_SMG3 ); + REGISTER_SHARED_ACTIVITY( ACT_WALK_SMG3 ); + REGISTER_SHARED_ACTIVITY( ACT_RUN_SMG3 ); + REGISTER_SHARED_ACTIVITY( ACT_WALK_AIM_SMG3 ); + REGISTER_SHARED_ACTIVITY( ACT_RUN_AIM_SMG3 ); + REGISTER_SHARED_ACTIVITY( ACT_RANGE_ATTACK_SMG3 ); + REGISTER_SHARED_ACTIVITY( ACT_RELOAD_SMG3 ); + REGISTER_SHARED_ACTIVITY( ACT_RANGE_ATTACK_SMG3_LOW ); + REGISTER_SHARED_ACTIVITY( ACT_RELOAD_SMG3_LOW ); + REGISTER_SHARED_ACTIVITY( ACT_COVER_SMG3_LOW ); + REGISTER_SHARED_ACTIVITY( ACT_RANGE_AIM_SMG3_LOW ); + REGISTER_SHARED_ACTIVITY( ACT_GESTURE_RANGE_ATTACK_SMG3 ); + REGISTER_SHARED_ACTIVITY( ACT_GESTURE_RELOAD_SMG3 ); + + REGISTER_SHARED_ACTIVITY( ACT_IDLE_SMG3_RELAXED ); + REGISTER_SHARED_ACTIVITY( ACT_IDLE_SMG3_STIMULATED ); + REGISTER_SHARED_ACTIVITY( ACT_WALK_SMG3_RELAXED ); + REGISTER_SHARED_ACTIVITY( ACT_RUN_SMG3_RELAXED ); + REGISTER_SHARED_ACTIVITY( ACT_WALK_SMG3_STIMULATED ); + REGISTER_SHARED_ACTIVITY( ACT_RUN_SMG3_STIMULATED ); + + REGISTER_SHARED_ACTIVITY( ACT_IDLE_AIM_SMG3_STIMULATED ); + REGISTER_SHARED_ACTIVITY( ACT_WALK_AIM_SMG3_STIMULATED ); + REGISTER_SHARED_ACTIVITY( ACT_RUN_AIM_SMG3_STIMULATED ); + + REGISTER_SHARED_ACTIVITY( ACT_IDLE_HMG1 ); + REGISTER_SHARED_ACTIVITY( ACT_IDLE_ANGRY_HMG1 ); + REGISTER_SHARED_ACTIVITY( ACT_WALK_HMG1 ); + REGISTER_SHARED_ACTIVITY( ACT_RUN_HMG1 ); + REGISTER_SHARED_ACTIVITY( ACT_WALK_AIM_HMG1 ); + REGISTER_SHARED_ACTIVITY( ACT_RUN_AIM_HMG1 ); + //REGISTER_SHARED_ACTIVITY( ACT_RANGE_ATTACK_HMG1 ); + REGISTER_SHARED_ACTIVITY( ACT_RELOAD_HMG1 ); + REGISTER_SHARED_ACTIVITY( ACT_RANGE_ATTACK_HMG1_LOW ); + REGISTER_SHARED_ACTIVITY( ACT_RELOAD_HMG1_LOW ); + REGISTER_SHARED_ACTIVITY( ACT_COVER_HMG1_LOW ); + REGISTER_SHARED_ACTIVITY( ACT_RANGE_AIM_HMG1_LOW ); + //REGISTER_SHARED_ACTIVITY( ACT_GESTURE_RANGE_ATTACK_HMG1 ); + REGISTER_SHARED_ACTIVITY( ACT_GESTURE_RELOAD_HMG1 ); + + REGISTER_SHARED_ACTIVITY( ACT_IDLE_HMG1_RELAXED ); + REGISTER_SHARED_ACTIVITY( ACT_IDLE_HMG1_STIMULATED ); + REGISTER_SHARED_ACTIVITY( ACT_WALK_HMG1_RELAXED ); + REGISTER_SHARED_ACTIVITY( ACT_RUN_HMG1_RELAXED ); + REGISTER_SHARED_ACTIVITY( ACT_WALK_HMG1_STIMULATED ); + REGISTER_SHARED_ACTIVITY( ACT_RUN_HMG1_STIMULATED ); + + REGISTER_SHARED_ACTIVITY( ACT_IDLE_AIM_HMG1_STIMULATED ); + REGISTER_SHARED_ACTIVITY( ACT_WALK_AIM_HMG1_STIMULATED ); + REGISTER_SHARED_ACTIVITY( ACT_RUN_AIM_HMG1_STIMULATED ); + REGISTER_SHARED_ACTIVITY( ACT_IDLE_SNIPER_RIFLE ); REGISTER_SHARED_ACTIVITY( ACT_IDLE_ANGRY_SNIPER_RIFLE ); REGISTER_SHARED_ACTIVITY( ACT_WALK_SNIPER_RIFLE ); @@ -2535,8 +2613,14 @@ void ActivityList_RegisterSharedActivities( void ) #if EXPANDED_HL2_UNUSED_WEAPON_ACTIVITIES REGISTER_SHARED_ACTIVITY( ACT_RANGE_AIM_AR1_MED ); REGISTER_SHARED_ACTIVITY( ACT_RANGE_ATTACK_AR1_MED ); + REGISTER_SHARED_ACTIVITY( ACT_RANGE_AIM_AR3_MED ); + REGISTER_SHARED_ACTIVITY( ACT_RANGE_ATTACK_AR3_MED ); REGISTER_SHARED_ACTIVITY( ACT_RANGE_AIM_SMG2_MED ); REGISTER_SHARED_ACTIVITY( ACT_RANGE_ATTACK_SMG2_MED ); + REGISTER_SHARED_ACTIVITY( ACT_RANGE_AIM_SMG3_MED ); + REGISTER_SHARED_ACTIVITY( ACT_RANGE_ATTACK_SMG3_MED ); + REGISTER_SHARED_ACTIVITY( ACT_RANGE_AIM_HMG1_MED ); + REGISTER_SHARED_ACTIVITY( ACT_RANGE_ATTACK_HMG1_MED ); REGISTER_SHARED_ACTIVITY( ACT_RANGE_AIM_SNIPER_RIFLE_MED ); REGISTER_SHARED_ACTIVITY( ACT_RANGE_ATTACK_SNIPER_RIFLE_MED ); #endif @@ -2602,6 +2686,16 @@ void ActivityList_RegisterSharedActivities( void ) REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RANGE_ATTACK2_AR1 ); REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RELOAD_AR1 ); REGISTER_SHARED_ACTIVITY( ACT_HL2MP_JUMP_AR1 ); + + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_IDLE_AR3 ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_RUN_AR3 ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_WALK_AR3 ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_IDLE_CROUCH_AR3 ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_WALK_CROUCH_AR3 ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RANGE_ATTACK_AR3 ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RANGE_ATTACK2_AR3 ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RELOAD_AR3 ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_JUMP_AR3 ); REGISTER_SHARED_ACTIVITY( ACT_HL2MP_IDLE_SMG2 ); REGISTER_SHARED_ACTIVITY( ACT_HL2MP_RUN_SMG2 ); @@ -2612,6 +2706,26 @@ void ActivityList_RegisterSharedActivities( void ) REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RANGE_ATTACK2_SMG2 ); REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RELOAD_SMG2 ); REGISTER_SHARED_ACTIVITY( ACT_HL2MP_JUMP_SMG2 ); + + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_IDLE_SMG3 ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_RUN_SMG3 ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_WALK_SMG3 ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_IDLE_CROUCH_SMG3 ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_WALK_CROUCH_SMG3 ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RANGE_ATTACK_SMG3 ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RANGE_ATTACK2_SMG3 ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RELOAD_SMG3 ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_JUMP_SMG3 ); + + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_IDLE_HMG1 ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_RUN_HMG1 ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_WALK_HMG1 ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_IDLE_CROUCH_HMG1 ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_WALK_CROUCH_HMG1 ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RANGE_ATTACK_HMG1 ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RANGE_ATTACK2_HMG1 ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_GESTURE_RELOAD_HMG1 ); + REGISTER_SHARED_ACTIVITY( ACT_HL2MP_JUMP_HMG1 ); REGISTER_SHARED_ACTIVITY( ACT_HL2MP_IDLE_SNIPER_RIFLE ); REGISTER_SHARED_ACTIVITY( ACT_HL2MP_RUN_SNIPER_RIFLE ); diff --git a/sp/src/game/shared/ai_activity.h b/sp/src/game/shared/ai_activity.h index 2373f2f9..4cf3ca22 100644 --- a/sp/src/game/shared/ai_activity.h +++ b/sp/src/game/shared/ai_activity.h @@ -45,6 +45,7 @@ // This enables a bunch of new activities for unused Half-Life 2 weapons, particularly those which exist in the SDK, but are deactivated by default. // This essentially just means mods which restore those weapons have the option of using custom activities for them. // Mapbase's backup activity system would allow them to fall back to other weapons if the relevant activities do not exist. +// Also includes activity names for the "AR3" and "SMG3", which were never used in HL2, but may be useful when additional animation sets are needed. #define EXPANDED_HL2_UNUSED_WEAPON_ACTIVITIES 0 // EXPANDED NAVIGATION ACTIVITIES @@ -2343,6 +2344,33 @@ typedef enum ACT_WALK_AIM_AR1_STIMULATED, ACT_RUN_AIM_AR1_STIMULATED, + // AR3 (new) + ACT_IDLE_AR3, + ACT_IDLE_ANGRY_AR3, + ACT_WALK_AR3, + ACT_RUN_AR3, + ACT_WALK_AIM_AR3, + ACT_RUN_AIM_AR3, + ACT_RANGE_ATTACK_AR3, + ACT_RELOAD_AR3, + ACT_RANGE_ATTACK_AR3_LOW, + ACT_RELOAD_AR3_LOW, + ACT_COVER_AR3_LOW, + ACT_RANGE_AIM_AR3_LOW, + ACT_GESTURE_RANGE_ATTACK_AR3, + ACT_GESTURE_RELOAD_AR3, + + ACT_IDLE_AR3_RELAXED, + ACT_IDLE_AR3_STIMULATED, + ACT_WALK_AR3_RELAXED, + ACT_RUN_AR3_RELAXED, + ACT_WALK_AR3_STIMULATED, + ACT_RUN_AR3_STIMULATED, + + ACT_IDLE_AIM_AR3_STIMULATED, + ACT_WALK_AIM_AR3_STIMULATED, + ACT_RUN_AIM_AR3_STIMULATED, + // SMG2 ACT_IDLE_SMG2, ACT_IDLE_ANGRY_SMG2, @@ -2370,6 +2398,60 @@ typedef enum ACT_WALK_AIM_SMG2_STIMULATED, ACT_RUN_AIM_SMG2_STIMULATED, + // SMG3 (new) + ACT_IDLE_SMG3, + ACT_IDLE_ANGRY_SMG3, + ACT_WALK_SMG3, + ACT_RUN_SMG3, + ACT_WALK_AIM_SMG3, + ACT_RUN_AIM_SMG3, + ACT_RANGE_ATTACK_SMG3, + ACT_RELOAD_SMG3, + ACT_RANGE_ATTACK_SMG3_LOW, + ACT_RELOAD_SMG3_LOW, + ACT_COVER_SMG3_LOW, + ACT_RANGE_AIM_SMG3_LOW, + ACT_GESTURE_RANGE_ATTACK_SMG3, + ACT_GESTURE_RELOAD_SMG3, + + ACT_IDLE_SMG3_RELAXED, + ACT_IDLE_SMG3_STIMULATED, + ACT_WALK_SMG3_RELAXED, + ACT_RUN_SMG3_RELAXED, + ACT_WALK_SMG3_STIMULATED, + ACT_RUN_SMG3_STIMULATED, + + ACT_IDLE_AIM_SMG3_STIMULATED, + ACT_WALK_AIM_SMG3_STIMULATED, + ACT_RUN_AIM_SMG3_STIMULATED, + + // HMG1 + ACT_IDLE_HMG1, + ACT_IDLE_ANGRY_HMG1, + ACT_WALK_HMG1, + ACT_RUN_HMG1, + ACT_WALK_AIM_HMG1, + ACT_RUN_AIM_HMG1, + //ACT_RANGE_ATTACK_HMG1, + ACT_RELOAD_HMG1, + ACT_RANGE_ATTACK_HMG1_LOW, + ACT_RELOAD_HMG1_LOW, + ACT_COVER_HMG1_LOW, + ACT_RANGE_AIM_HMG1_LOW, + //ACT_GESTURE_RANGE_ATTACK_HMG1, + ACT_GESTURE_RELOAD_HMG1, + + ACT_IDLE_HMG1_RELAXED, + ACT_IDLE_HMG1_STIMULATED, + ACT_WALK_HMG1_RELAXED, + ACT_RUN_HMG1_RELAXED, + ACT_WALK_HMG1_STIMULATED, + ACT_RUN_HMG1_STIMULATED, + + ACT_IDLE_AIM_HMG1_STIMULATED, + ACT_WALK_AIM_HMG1_STIMULATED, + ACT_RUN_AIM_HMG1_STIMULATED, + // Sniper Rifle ACT_IDLE_SNIPER_RIFLE, ACT_IDLE_ANGRY_SNIPER_RIFLE, @@ -2433,8 +2515,14 @@ typedef enum // MED activities for unused weapons ACT_RANGE_AIM_AR1_MED, ACT_RANGE_ATTACK_AR1_MED, + ACT_RANGE_AIM_AR3_MED, + ACT_RANGE_ATTACK_AR3_MED, ACT_RANGE_AIM_SMG2_MED, ACT_RANGE_ATTACK_SMG2_MED, + ACT_RANGE_AIM_SMG3_MED, + ACT_RANGE_ATTACK_SMG3_MED, + ACT_RANGE_AIM_HMG1_MED, + ACT_RANGE_ATTACK_HMG1_MED, ACT_RANGE_AIM_SNIPER_RIFLE_MED, ACT_RANGE_ATTACK_SNIPER_RIFLE_MED, #endif @@ -2503,6 +2591,16 @@ typedef enum ACT_HL2MP_GESTURE_RELOAD_AR1, ACT_HL2MP_JUMP_AR1, + ACT_HL2MP_IDLE_AR3, + ACT_HL2MP_RUN_AR3, + ACT_HL2MP_WALK_AR3, + ACT_HL2MP_IDLE_CROUCH_AR3, + ACT_HL2MP_WALK_CROUCH_AR3, + ACT_HL2MP_GESTURE_RANGE_ATTACK_AR3, + ACT_HL2MP_GESTURE_RANGE_ATTACK2_AR3, + ACT_HL2MP_GESTURE_RELOAD_AR3, + ACT_HL2MP_JUMP_AR3, + ACT_HL2MP_IDLE_SMG2, ACT_HL2MP_RUN_SMG2, ACT_HL2MP_WALK_SMG2, @@ -2513,6 +2611,26 @@ typedef enum ACT_HL2MP_GESTURE_RELOAD_SMG2, ACT_HL2MP_JUMP_SMG2, + ACT_HL2MP_IDLE_SMG3, + ACT_HL2MP_RUN_SMG3, + ACT_HL2MP_WALK_SMG3, + ACT_HL2MP_IDLE_CROUCH_SMG3, + ACT_HL2MP_WALK_CROUCH_SMG3, + ACT_HL2MP_GESTURE_RANGE_ATTACK_SMG3, + ACT_HL2MP_GESTURE_RANGE_ATTACK2_SMG3, + ACT_HL2MP_GESTURE_RELOAD_SMG3, + ACT_HL2MP_JUMP_SMG3, + + ACT_HL2MP_IDLE_HMG1, + ACT_HL2MP_RUN_HMG1, + ACT_HL2MP_WALK_HMG1, + ACT_HL2MP_IDLE_CROUCH_HMG1, + ACT_HL2MP_WALK_CROUCH_HMG1, + ACT_HL2MP_GESTURE_RANGE_ATTACK_HMG1, + ACT_HL2MP_GESTURE_RANGE_ATTACK2_HMG1, + ACT_HL2MP_GESTURE_RELOAD_HMG1, + ACT_HL2MP_JUMP_HMG1, + ACT_HL2MP_IDLE_SNIPER_RIFLE, ACT_HL2MP_RUN_SNIPER_RIFLE, ACT_HL2MP_WALK_SNIPER_RIFLE, From 714c89cc4991f51d72f2c444192372a1335469e7 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Tue, 26 Apr 2022 08:38:22 -0500 Subject: [PATCH 342/378] Added Matcher_ContainsWildcard and fixed an issue with lazy wildcards --- sp/src/public/tier1/mapbase_matchers_base.h | 3 +++ sp/src/tier1/mapbase_matchers_base.cpp | 26 +++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/sp/src/public/tier1/mapbase_matchers_base.h b/sp/src/public/tier1/mapbase_matchers_base.h index 74b2cbc9..beb1d869 100644 --- a/sp/src/public/tier1/mapbase_matchers_base.h +++ b/sp/src/public/tier1/mapbase_matchers_base.h @@ -36,6 +36,9 @@ bool Matcher_NamesMatch_Classic( const char *pszQuery, const char *szValue ); // szValue = The value tested against the query. This value can use wildcards as well. bool Matcher_NamesMatch_MutualWildcard( const char *pszQuery, const char *szValue ); +// Returns true if the specified string contains a wildcard character. +bool Matcher_ContainsWildcard( const char *pszQuery ); + // Taken from the Response System. // Checks if the specified string appears to be a number of some sort. static bool AppearsToBeANumber( char const *token ) diff --git a/sp/src/tier1/mapbase_matchers_base.cpp b/sp/src/tier1/mapbase_matchers_base.cpp index 5f10814e..85cdb6e1 100644 --- a/sp/src/tier1/mapbase_matchers_base.cpp +++ b/sp/src/tier1/mapbase_matchers_base.cpp @@ -16,6 +16,7 @@ #include "minmax.h" ConVar mapbase_wildcards_enabled("mapbase_wildcards_enabled", "1", FCVAR_NONE, "Toggles Mapbase's '?' wildcard and true '*' features. Useful for maps that have '?' in their targetnames."); +ConVar mapbase_wildcards_lazy_hack("mapbase_wildcards_lazy_hack", "1", FCVAR_NONE, "Toggles a hack which prevents Mapbase's lazy '?' wildcards from picking up \"???\", the default instance parameter."); ConVar mapbase_regex_enabled("mapbase_regex_enabled", "1", FCVAR_NONE, "Toggles Mapbase's regex matching handover."); //============================================================================= @@ -121,6 +122,14 @@ bool Matcher_NamesMatch(const char *pszQuery, const char *szValue) return Matcher_Regex( pszQuery+2, szValue ); } } + else if (pszQuery[0] == '?' && pszQuery[1] == '?' && pszQuery[2] == '?' && mapbase_wildcards_lazy_hack.GetBool()) + { + // HACKHACK: There's a nasty issue where instances with blank parameters use "???", but Mapbase's lazy wildcard code + // recognizes this as essentially meaning "any name with 3 characters". This is a serious problem when the instance + // specifically expects the game to interpret "???" as a blank space, such as with damage filters, which crash when targeting + // a non-filter entity. + return false; + } return Matcher_RunCharCompare( pszQuery, szValue ); } @@ -200,6 +209,23 @@ bool Matcher_NamesMatch_MutualWildcard(const char *pszQuery, const char *szValue return false; } +// Returns true if a string contains a wildcard. +bool Matcher_ContainsWildcard(const char *pszQuery) +{ + if ( pszQuery == NULL ) + return false; + + while ( *pszQuery ) + { + unsigned char cQuery = *pszQuery; + if (cQuery == '*' || cQuery == '?') + return true; + ++pszQuery; + } + + return false; +} + // Matcher_Compare is a deprecated alias originally used when Matcher_Match didn't support wildcards. /* bool Matcher_Compare(const char *pszQuery, const char *szValue) From e22bbc97fbd38a9cf2541fe68d2af82630f2aeeb Mon Sep 17 00:00:00 2001 From: Blixibon Date: Tue, 26 Apr 2022 08:39:12 -0500 Subject: [PATCH 343/378] Fixed two issues in the response system --- sp/src/responserules/runtime/response_system.cpp | 14 ++++++++++++++ .../runtime/response_types_internal.cpp | 7 ++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/sp/src/responserules/runtime/response_system.cpp b/sp/src/responserules/runtime/response_system.cpp index d294316d..653c5cbf 100644 --- a/sp/src/responserules/runtime/response_system.cpp +++ b/sp/src/responserules/runtime/response_system.cpp @@ -1985,7 +1985,14 @@ void CResponseSystem::ParseResponse( void ) while ( 1 ) { +#ifdef MAPBASE + if ( !ParseToken() || !Q_stricmp( token, "}" ) ) + { + break; + } +#else ParseToken(); +#endif unsigned int hash = RR_HASH( token ); @@ -2048,7 +2055,14 @@ int CResponseSystem::ParseOneCriterion( const char *criterionName ) while ( TokenWaiting() || !gotbody ) { +#ifdef MAPBASE + if ( !ParseToken() ) + { + break; + } +#else ParseToken(); +#endif // Oops, part of next definition if( IsRootCommand() ) diff --git a/sp/src/responserules/runtime/response_types_internal.cpp b/sp/src/responserules/runtime/response_types_internal.cpp index 098801c4..873f8759 100644 --- a/sp/src/responserules/runtime/response_types_internal.cpp +++ b/sp/src/responserules/runtime/response_types_internal.cpp @@ -8,6 +8,7 @@ #include "rrbase.h" #ifdef MAPBASE #include "convar.h" +#include "mapbase_matchers_base.h" #endif // memdbgon must be the last include file in a .cpp file!!! @@ -117,7 +118,11 @@ static inline bool CanBucketBySubject( const char * RESTRICT pszSubject ) { return pszSubject && ( ( pszSubject[0] >= 'A' && pszSubject[0] <= 'Z' ) || - ( pszSubject[0] >= 'a' && pszSubject[0] <= 'z' ) ); + ( pszSubject[0] >= 'a' && pszSubject[0] <= 'z' ) ) +#ifdef MAPBASE + && !Matcher_ContainsWildcard( pszSubject ) +#endif + ; } ResponseRulePartition::tRuleDict &ResponseRulePartition::GetDictForRule( CResponseSystem *pSystem, Rule *pRule ) From 6413647d234ff1c4a6bcf07c5ddc9ce2b4a002b1 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Tue, 26 Apr 2022 08:40:52 -0500 Subject: [PATCH 344/378] Changed g_ai_ignore_graph_timestamps into a cvar which identifies maps from chapters.txt instead --- sp/src/game/server/ai_networkmanager.cpp | 25 +++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/sp/src/game/server/ai_networkmanager.cpp b/sp/src/game/server/ai_networkmanager.cpp index 2477ec67..10fb51ff 100644 --- a/sp/src/game/server/ai_networkmanager.cpp +++ b/sp/src/game/server/ai_networkmanager.cpp @@ -25,6 +25,9 @@ #include "ndebugoverlay.h" #include "ai_hint.h" #include "tier0/icommandline.h" +#ifdef MAPBASE +#include "gameinterface.h" +#endif // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -72,7 +75,10 @@ ConVar g_ai_norebuildgraph( "ai_norebuildgraph", "0" ); #ifdef MAPBASE ConVar g_ai_norebuildgraphmessage( "ai_norebuildgraphmessage", "0", FCVAR_ARCHIVE, "Stops the \"Node graph out of date\" message from appearing when rebuilding node graph" ); -ConVar g_ai_ignore_graph_timestamps( "g_ai_ignore_graph_timestamps", "1", FCVAR_NONE, "Ignores file timestamps when rebuilding nodegraphs, only relying on internal map version differences" ); +ConVar g_ai_norebuildgraph_if_in_chapters( "ai_norebuildgraph_if_in_chapters", "0", FCVAR_NONE, "Ignores rebuilding nodegraph if it's in chapters.txt. This allows for bypassing problems with Steam rebuilding nodegraphs in a mod's main maps without affecting custom maps." ); + +extern CUtlVector *Mapbase_GetChapterMaps(); +extern CUtlVector *Mapbase_GetChapterList(); #endif @@ -990,8 +996,21 @@ bool CAI_NetworkManager::IsAIFileCurrent ( const char *szMapName ) } #ifdef MAPBASE - if (g_ai_ignore_graph_timestamps.GetBool()) - return true; + if (g_ai_norebuildgraph_if_in_chapters.GetBool()) + { + // Look in the mod's chapter list. If this map is part of one of the chapters, consider it to have a good node graph + CUtlVector *ModChapterComments = Mapbase_GetChapterMaps(); + if (ModChapterComments->Count() > 0) + { + for ( int i = 0; i < ModChapterComments->Count(); i++ ) + { + if ( !Q_strnicmp( STRING(gpGlobals->mapname), ModChapterComments->Element(i).pBSPName, strlen(ModChapterComments->Element(i).pBSPName) ) ) + { + return true; + } + } + } + } #endif { From b0689150e5184269f617080690badc7d21582de2 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Tue, 26 Apr 2022 12:39:22 -0500 Subject: [PATCH 345/378] Added $envmapfresnel / $envmapfresnelminmaxexp without $phong + $allowdiffusemodulation, all from Alien Swarm SDK --- .../SDK_vertexlit_and_unlit_generic_ps20b.fxc | 28 ++++- .../SDK_vertexlit_and_unlit_generic_ps2x.fxc | 31 +++++- .../SDK_vertexlit_and_unlit_generic_ps20.inc | 31 +----- .../SDK_vertexlit_and_unlit_generic_ps20b.inc | 31 +----- .../SDK_vertexlit_and_unlit_generic_ps30.inc | 26 ++--- .../SDK_vertexlit_and_unlit_generic_ps20.inc | 31 +----- .../SDK_vertexlit_and_unlit_generic_ps20b.inc | 31 +----- .../SDK_vertexlit_and_unlit_generic_ps30.inc | 26 ++--- .../stdshaders/unlitgeneric_dx9.cpp | 14 +++ .../stdshaders/vertexlitgeneric_dx9.cpp | 10 ++ .../vertexlitgeneric_dx9_helper.cpp | 102 +++++++++++++++++- .../stdshaders/vertexlitgeneric_dx9_helper.h | 11 +- 12 files changed, 220 insertions(+), 152 deletions(-) diff --git a/sp/src/materialsystem/stdshaders/SDK_vertexlit_and_unlit_generic_ps20b.fxc b/sp/src/materialsystem/stdshaders/SDK_vertexlit_and_unlit_generic_ps20b.fxc index e78ed5d8..695faa2b 100644 --- a/sp/src/materialsystem/stdshaders/SDK_vertexlit_and_unlit_generic_ps20b.fxc +++ b/sp/src/materialsystem/stdshaders/SDK_vertexlit_and_unlit_generic_ps20b.fxc @@ -27,8 +27,8 @@ // STATIC: "FLASHLIGHTDEPTHFILTERMODE" "0..0" [ps20b] [XBOX] // STATIC: "DEPTHBLEND" "0..1" [ps20b] [ps30] // STATIC: "BLENDTINTBYBASEALPHA" "0..1" +// STATIC: "ENVMAPFRESNEL" "0..1" [ps30] // STATIC: "SRGB_INPUT_ADAPTER" "0..1" [ps20b] -// STATIC: "CUBEMAP_SPHERE_LEGACY" "0..1" // DYNAMIC: "PIXELFOGTYPE" "0..1" [ps20] // DYNAMIC: "LIGHTING_PREVIEW" "0..2" [PC] @@ -51,6 +51,10 @@ // SKIP: ($DISTANCEALPHA == 0) && ($DISTANCEALPHAFROMDETAIL || $SOFT_MASK || $OUTLINE || $OUTER_GLOW) // SKIP: ($DETAILTEXTURE == 0) && ($DISTANCEALPHAFROMDETAIL) +// envmap stuff is meaningless if we're not using a cubemap +// SKIP: ( $CUBEMAP == 0 ) && ( ( $ENVMAPFRESNEL == 1 ) || ( $BASEALPHAENVMAPMASK == 1 ) ) +// SKIP: ( $CUBEMAP == 0 ) && ( $ENVMAPMASK == 1 ) && ( $SELFILLUM_ENVMAPMASK_ALPHA == 0 ) + // We don't care about flashlight depth unless the flashlight is on // SKIP: ( $FLASHLIGHT == 0 ) && ( $FLASHLIGHTSHADOWS == 1 ) [ps20b] // SKIP: ( $FLASHLIGHT == 0 ) && ( $FLASHLIGHTSHADOWS == 1 ) [ps30] @@ -60,7 +64,7 @@ // SKIP: ( $FLASHLIGHT == 0 ) && ( $FLASHLIGHTDEPTHFILTERMODE != 0 ) [ps30] // DISTANCEALPHA-related skips -// SKIP: ($DISTANCEALPHA) && ($ENVMAPMASK || $BASEALPHAENVMAPMASK || $SELFILLUM || $SELFILLUM_ENVMAPMASK_ALPHA ) +// SKIP: ($DISTANCEALPHA) && ($ENVMAPMASK || $BASEALPHAENVMAPMASK || $SELFILLUM || $SELFILLUM_ENVMAPMASK_ALPHA || $ENVMAPFRESNEL) // SKIP: ($DISTANCEALPHA) && ($SEAMLESS_BASE || $SEAMLESS_DETAIL || $CUBEMAP || $LIGHTING_PREVIEW ) // SKIP: ($DISTANCEALPHA) && ($WRITEWATERFOGTODESTALPHA || $PIXELFOGTYPE || $FLASHLIGHT || $FLASHLIGHTSHADOWS || $SRGB_INPUT_ADAPTER ) @@ -87,6 +91,12 @@ const float4 g_SelfIllumTint_and_BlendFactor : register( c4 ); const float4 g_ShaderControls : register( c12 ); const float4 g_DepthFeatheringConstants : register( c13 ); +const float4 g_FresnelConstants : register( c14 ); +#define g_flFresnelBias g_FresnelConstants.x +#define g_flFresnelScale g_FresnelConstants.y +#define g_flFresnelExp g_FresnelConstants.z +#define g_flBaseAlphaEnvMapMaskExp g_FresnelConstants.w + const float4 g_EyePos_MinLight : register( c20 ); #define g_EyePos g_EyePos_MinLight.xyz #define g_fMinLighting g_EyePos_MinLight.w @@ -159,6 +169,8 @@ const float4 g_GlowColor : register( c6 ); const float4 g_DistanceAlphaParams : register( c7 ); #define SOFT_MASK_MAX g_DistanceAlphaParams.x #define SOFT_MASK_MIN g_DistanceAlphaParams.y +#define g_flBaseAlphaEnvMapMaskBias g_DistanceAlphaParams.z +#define g_flBaseAlphaEnvMapMaskScale g_DistanceAlphaParams.w const float4 g_OutlineColor : register( c8 ); #define OUTLINE_COLOR g_OutlineColor @@ -337,11 +349,19 @@ float4 main( PS_INPUT i ) : COLOR specularFactor *= envmapMaskTexel.xyz; } - if( bBaseAlphaEnvmapMask ) + if ( bBaseAlphaEnvmapMask ) { - specularFactor *= 1.0 - baseColor.a; // this blows! + specularFactor *= saturate( g_flBaseAlphaEnvMapMaskScale * pow( baseColor.a, g_flBaseAlphaEnvMapMaskExp ) + g_flBaseAlphaEnvMapMaskBias ); } + #if ( ENVMAPFRESNEL ) + { + float flFresnel = 1-saturate( dot( normalize( i.worldSpaceNormal.xyz ), normalize( i.worldVertToEyeVector.xyz ) ) ); + flFresnel = g_flFresnelScale * pow( flFresnel, g_flFresnelExp ) + g_flFresnelBias; + specularFactor *= flFresnel; + } + #endif + float3 diffuseLighting = float3( 1.0f, 1.0f, 1.0f ); if( bDiffuseLighting || bVertexColor && !( bVertexColor && bDiffuseLighting ) ) { diff --git a/sp/src/materialsystem/stdshaders/SDK_vertexlit_and_unlit_generic_ps2x.fxc b/sp/src/materialsystem/stdshaders/SDK_vertexlit_and_unlit_generic_ps2x.fxc index 9ed758b6..56685c11 100644 --- a/sp/src/materialsystem/stdshaders/SDK_vertexlit_and_unlit_generic_ps2x.fxc +++ b/sp/src/materialsystem/stdshaders/SDK_vertexlit_and_unlit_generic_ps2x.fxc @@ -23,8 +23,8 @@ // STATIC: "FLASHLIGHTDEPTHFILTERMODE" "0..0" [ps20b] [XBOX] // STATIC: "DEPTHBLEND" "0..1" [ps20b] [ps30] // STATIC: "BLENDTINTBYBASEALPHA" "0..1" +// STATIC: "ENVMAPFRESNEL" "0..1" [ps30] // STATIC: "SRGB_INPUT_ADAPTER" "0..1" [ps20b] -// STATIC: "CUBEMAP_SPHERE_LEGACY" "0..1" // DYNAMIC: "PIXELFOGTYPE" "0..1" [ps20] // DYNAMIC: "LIGHTING_PREVIEW" "0..2" [PC] @@ -47,6 +47,10 @@ // SKIP: ($DISTANCEALPHA == 0) && ($DISTANCEALPHAFROMDETAIL || $SOFT_MASK || $OUTLINE || $OUTER_GLOW) // SKIP: ($DETAILTEXTURE == 0) && ($DISTANCEALPHAFROMDETAIL) +// envmap stuff is meaningless if we're not using a cubemap +// SKIP: ( $CUBEMAP == 0 ) && ( ( $ENVMAPFRESNEL == 1 ) || ( $BASEALPHAENVMAPMASK == 1 ) ) +// SKIP: ( $CUBEMAP == 0 ) && ( $ENVMAPMASK == 1 ) && ( $SELFILLUM_ENVMAPMASK_ALPHA == 0 ) + // We don't care about flashlight depth unless the flashlight is on // SKIP: ( $FLASHLIGHT == 0 ) && ( $FLASHLIGHTSHADOWS == 1 ) [ps20b] // SKIP: ( $FLASHLIGHT == 0 ) && ( $FLASHLIGHTSHADOWS == 1 ) [ps30] @@ -56,7 +60,7 @@ // SKIP: ( $FLASHLIGHT == 0 ) && ( $FLASHLIGHTDEPTHFILTERMODE != 0 ) [ps30] // DISTANCEALPHA-related skips -// SKIP: ($DISTANCEALPHA) && ($ENVMAPMASK || $BASEALPHAENVMAPMASK || $SELFILLUM || $SELFILLUM_ENVMAPMASK_ALPHA ) +// SKIP: ($DISTANCEALPHA) && ($ENVMAPMASK || $BASEALPHAENVMAPMASK || $SELFILLUM || $SELFILLUM_ENVMAPMASK_ALPHA || $ENVMAPFRESNEL) // SKIP: ($DISTANCEALPHA) && ($SEAMLESS_BASE || $SEAMLESS_DETAIL || $CUBEMAP || $LIGHTING_PREVIEW ) // SKIP: ($DISTANCEALPHA) && ($WRITEWATERFOGTODESTALPHA || $PIXELFOGTYPE || $FLASHLIGHT || $FLASHLIGHTSHADOWS || $SRGB_INPUT_ADAPTER ) @@ -83,6 +87,12 @@ const float4 g_SelfIllumTint_and_BlendFactor : register( c4 ); const float4 g_ShaderControls : register( c12 ); const float4 g_DepthFeatheringConstants : register( c13 ); +const float4 g_FresnelConstants : register( c14 ); +#define g_flFresnelBias g_FresnelConstants.x +#define g_flFresnelScale g_FresnelConstants.y +#define g_flFresnelExp g_FresnelConstants.z +#define g_flBaseAlphaEnvMapMaskExp g_FresnelConstants.w + const float4 g_EyePos : register( c20 ); const float4 g_FogParams : register( c21 ); @@ -152,6 +162,8 @@ const float4 g_GlowColor : register( c6 ); const float4 g_DistanceAlphaParams : register( c7 ); #define SOFT_MASK_MAX g_DistanceAlphaParams.x #define SOFT_MASK_MIN g_DistanceAlphaParams.y +#define g_flBaseAlphaEnvMapMaskBias g_DistanceAlphaParams.z +#define g_flBaseAlphaEnvMapMaskScale g_DistanceAlphaParams.w const float4 g_OutlineColor : register( c8 ); #define OUTLINE_COLOR g_OutlineColor @@ -323,17 +335,26 @@ float4 main( PS_INPUT i ) : COLOR float3 specularFactor = 1.0f; float4 envmapMaskTexel; - if( bEnvmapMask ) + #if ( ENVMAPMASK ) { envmapMaskTexel = tex2D( EnvmapMaskSampler, i.baseTexCoord.xy ); specularFactor *= envmapMaskTexel.xyz; } + #endif - if( bBaseAlphaEnvmapMask ) + if ( bBaseAlphaEnvmapMask ) { - specularFactor *= 1.0 - baseColor.a; // this blows! + specularFactor *= saturate( g_flBaseAlphaEnvMapMaskScale * pow( baseColor.a, g_flBaseAlphaEnvMapMaskExp ) + g_flBaseAlphaEnvMapMaskBias ); } + #if ( ENVMAPFRESNEL ) + { + float flFresnel = 1-saturate( dot( normalize( i.worldSpaceNormal.xyz ), normalize( i.worldVertToEyeVector.xyz ) ) ); + flFresnel = g_flFresnelScale * pow( flFresnel, g_flFresnelExp ) + g_flFresnelBias; + specularFactor *= flFresnel; + } + #endif + float3 diffuseLighting = float3( 1.0f, 1.0f, 1.0f ); if( bDiffuseLighting || bVertexColor && !( bVertexColor && bDiffuseLighting ) ) { diff --git a/sp/src/materialsystem/stdshaders/fxctmp9/SDK_vertexlit_and_unlit_generic_ps20.inc b/sp/src/materialsystem/stdshaders/fxctmp9/SDK_vertexlit_and_unlit_generic_ps20.inc index 0bf098cd..8383989c 100644 --- a/sp/src/materialsystem/stdshaders/fxctmp9/SDK_vertexlit_and_unlit_generic_ps20.inc +++ b/sp/src/materialsystem/stdshaders/fxctmp9/SDK_vertexlit_and_unlit_generic_ps20.inc @@ -379,27 +379,6 @@ public: m_bBLENDTINTBYBASEALPHA = true; #endif } -private: - int m_nCUBEMAP_SPHERE_LEGACY; -#ifdef _DEBUG - bool m_bCUBEMAP_SPHERE_LEGACY; -#endif -public: - void SetCUBEMAP_SPHERE_LEGACY( int i ) - { - Assert( i >= 0 && i <= 1 ); - m_nCUBEMAP_SPHERE_LEGACY = i; -#ifdef _DEBUG - m_bCUBEMAP_SPHERE_LEGACY = true; -#endif - } - void SetCUBEMAP_SPHERE_LEGACY( bool i ) - { - m_nCUBEMAP_SPHERE_LEGACY = i ? 1 : 0; -#ifdef _DEBUG - m_bCUBEMAP_SPHERE_LEGACY = true; -#endif - } public: sdk_vertexlit_and_unlit_generic_ps20_Static_Index( ) { @@ -475,23 +454,19 @@ public: m_bBLENDTINTBYBASEALPHA = false; #endif // _DEBUG m_nBLENDTINTBYBASEALPHA = 0; -#ifdef _DEBUG - m_bCUBEMAP_SPHERE_LEGACY = false; -#endif // _DEBUG - m_nCUBEMAP_SPHERE_LEGACY = 0; } int GetIndex() { // Asserts to make sure that we aren't using any skipped combinations. // Asserts to make sure that we are setting all of the combination vars. #ifdef _DEBUG - bool bAllStaticVarsDefined = m_bDETAILTEXTURE && m_bCUBEMAP && m_bDIFFUSELIGHTING && m_bENVMAPMASK && m_bBASEALPHAENVMAPMASK && m_bSELFILLUM && m_bVERTEXCOLOR && m_bFLASHLIGHT && m_bSELFILLUM_ENVMAPMASK_ALPHA && m_bDETAIL_BLEND_MODE && m_bSEAMLESS_BASE && m_bSEAMLESS_DETAIL && m_bDISTANCEALPHA && m_bDISTANCEALPHAFROMDETAIL && m_bSOFT_MASK && m_bOUTLINE && m_bOUTER_GLOW && m_bBLENDTINTBYBASEALPHA && m_bCUBEMAP_SPHERE_LEGACY; + bool bAllStaticVarsDefined = m_bDETAILTEXTURE && m_bCUBEMAP && m_bDIFFUSELIGHTING && m_bENVMAPMASK && m_bBASEALPHAENVMAPMASK && m_bSELFILLUM && m_bVERTEXCOLOR && m_bFLASHLIGHT && m_bSELFILLUM_ENVMAPMASK_ALPHA && m_bDETAIL_BLEND_MODE && m_bSEAMLESS_BASE && m_bSEAMLESS_DETAIL && m_bDISTANCEALPHA && m_bDISTANCEALPHAFROMDETAIL && m_bSOFT_MASK && m_bOUTLINE && m_bOUTER_GLOW && m_bBLENDTINTBYBASEALPHA; Assert( bAllStaticVarsDefined ); #endif // _DEBUG - return ( 6 * m_nDETAILTEXTURE ) + ( 12 * m_nCUBEMAP ) + ( 24 * m_nDIFFUSELIGHTING ) + ( 48 * m_nENVMAPMASK ) + ( 96 * m_nBASEALPHAENVMAPMASK ) + ( 192 * m_nSELFILLUM ) + ( 384 * m_nVERTEXCOLOR ) + ( 768 * m_nFLASHLIGHT ) + ( 1536 * m_nSELFILLUM_ENVMAPMASK_ALPHA ) + ( 3072 * m_nDETAIL_BLEND_MODE ) + ( 30720 * m_nSEAMLESS_BASE ) + ( 61440 * m_nSEAMLESS_DETAIL ) + ( 122880 * m_nDISTANCEALPHA ) + ( 245760 * m_nDISTANCEALPHAFROMDETAIL ) + ( 491520 * m_nSOFT_MASK ) + ( 983040 * m_nOUTLINE ) + ( 1966080 * m_nOUTER_GLOW ) + ( 3932160 * m_nBLENDTINTBYBASEALPHA ) + ( 7864320 * m_nCUBEMAP_SPHERE_LEGACY ) + 0; + return ( 6 * m_nDETAILTEXTURE ) + ( 12 * m_nCUBEMAP ) + ( 24 * m_nDIFFUSELIGHTING ) + ( 48 * m_nENVMAPMASK ) + ( 96 * m_nBASEALPHAENVMAPMASK ) + ( 192 * m_nSELFILLUM ) + ( 384 * m_nVERTEXCOLOR ) + ( 768 * m_nFLASHLIGHT ) + ( 1536 * m_nSELFILLUM_ENVMAPMASK_ALPHA ) + ( 3072 * m_nDETAIL_BLEND_MODE ) + ( 30720 * m_nSEAMLESS_BASE ) + ( 61440 * m_nSEAMLESS_DETAIL ) + ( 122880 * m_nDISTANCEALPHA ) + ( 245760 * m_nDISTANCEALPHAFROMDETAIL ) + ( 491520 * m_nSOFT_MASK ) + ( 983040 * m_nOUTLINE ) + ( 1966080 * m_nOUTER_GLOW ) + ( 3932160 * m_nBLENDTINTBYBASEALPHA ) + 0; } }; -#define shaderStaticTest_sdk_vertexlit_and_unlit_generic_ps20 psh_forgot_to_set_static_DETAILTEXTURE + psh_forgot_to_set_static_CUBEMAP + psh_forgot_to_set_static_DIFFUSELIGHTING + psh_forgot_to_set_static_ENVMAPMASK + psh_forgot_to_set_static_BASEALPHAENVMAPMASK + psh_forgot_to_set_static_SELFILLUM + psh_forgot_to_set_static_VERTEXCOLOR + psh_forgot_to_set_static_FLASHLIGHT + psh_forgot_to_set_static_SELFILLUM_ENVMAPMASK_ALPHA + psh_forgot_to_set_static_DETAIL_BLEND_MODE + psh_forgot_to_set_static_SEAMLESS_BASE + psh_forgot_to_set_static_SEAMLESS_DETAIL + psh_forgot_to_set_static_DISTANCEALPHA + psh_forgot_to_set_static_DISTANCEALPHAFROMDETAIL + psh_forgot_to_set_static_SOFT_MASK + psh_forgot_to_set_static_OUTLINE + psh_forgot_to_set_static_OUTER_GLOW + psh_forgot_to_set_static_BLENDTINTBYBASEALPHA + psh_forgot_to_set_static_CUBEMAP_SPHERE_LEGACY + 0 +#define shaderStaticTest_sdk_vertexlit_and_unlit_generic_ps20 psh_forgot_to_set_static_DETAILTEXTURE + psh_forgot_to_set_static_CUBEMAP + psh_forgot_to_set_static_DIFFUSELIGHTING + psh_forgot_to_set_static_ENVMAPMASK + psh_forgot_to_set_static_BASEALPHAENVMAPMASK + psh_forgot_to_set_static_SELFILLUM + psh_forgot_to_set_static_VERTEXCOLOR + psh_forgot_to_set_static_FLASHLIGHT + psh_forgot_to_set_static_SELFILLUM_ENVMAPMASK_ALPHA + psh_forgot_to_set_static_DETAIL_BLEND_MODE + psh_forgot_to_set_static_SEAMLESS_BASE + psh_forgot_to_set_static_SEAMLESS_DETAIL + psh_forgot_to_set_static_DISTANCEALPHA + psh_forgot_to_set_static_DISTANCEALPHAFROMDETAIL + psh_forgot_to_set_static_SOFT_MASK + psh_forgot_to_set_static_OUTLINE + psh_forgot_to_set_static_OUTER_GLOW + psh_forgot_to_set_static_BLENDTINTBYBASEALPHA + 0 class sdk_vertexlit_and_unlit_generic_ps20_Dynamic_Index { private: diff --git a/sp/src/materialsystem/stdshaders/fxctmp9/SDK_vertexlit_and_unlit_generic_ps20b.inc b/sp/src/materialsystem/stdshaders/fxctmp9/SDK_vertexlit_and_unlit_generic_ps20b.inc index ee74372c..1106743f 100644 --- a/sp/src/materialsystem/stdshaders/fxctmp9/SDK_vertexlit_and_unlit_generic_ps20b.inc +++ b/sp/src/materialsystem/stdshaders/fxctmp9/SDK_vertexlit_and_unlit_generic_ps20b.inc @@ -442,27 +442,6 @@ public: m_bSRGB_INPUT_ADAPTER = true; #endif } -private: - int m_nCUBEMAP_SPHERE_LEGACY; -#ifdef _DEBUG - bool m_bCUBEMAP_SPHERE_LEGACY; -#endif -public: - void SetCUBEMAP_SPHERE_LEGACY( int i ) - { - Assert( i >= 0 && i <= 1 ); - m_nCUBEMAP_SPHERE_LEGACY = i; -#ifdef _DEBUG - m_bCUBEMAP_SPHERE_LEGACY = true; -#endif - } - void SetCUBEMAP_SPHERE_LEGACY( bool i ) - { - m_nCUBEMAP_SPHERE_LEGACY = i ? 1 : 0; -#ifdef _DEBUG - m_bCUBEMAP_SPHERE_LEGACY = true; -#endif - } public: sdk_vertexlit_and_unlit_generic_ps20b_Static_Index( ) { @@ -550,23 +529,19 @@ public: m_bSRGB_INPUT_ADAPTER = false; #endif // _DEBUG m_nSRGB_INPUT_ADAPTER = 0; -#ifdef _DEBUG - m_bCUBEMAP_SPHERE_LEGACY = false; -#endif // _DEBUG - m_nCUBEMAP_SPHERE_LEGACY = 0; } int GetIndex() { // Asserts to make sure that we aren't using any skipped combinations. // Asserts to make sure that we are setting all of the combination vars. #ifdef _DEBUG - bool bAllStaticVarsDefined = m_bDETAILTEXTURE && m_bCUBEMAP && m_bDIFFUSELIGHTING && m_bENVMAPMASK && m_bBASEALPHAENVMAPMASK && m_bSELFILLUM && m_bVERTEXCOLOR && m_bFLASHLIGHT && m_bSELFILLUM_ENVMAPMASK_ALPHA && m_bDETAIL_BLEND_MODE && m_bSEAMLESS_BASE && m_bSEAMLESS_DETAIL && m_bDISTANCEALPHA && m_bDISTANCEALPHAFROMDETAIL && m_bSOFT_MASK && m_bOUTLINE && m_bOUTER_GLOW && m_bFLASHLIGHTDEPTHFILTERMODE && m_bDEPTHBLEND && m_bBLENDTINTBYBASEALPHA && m_bSRGB_INPUT_ADAPTER && m_bCUBEMAP_SPHERE_LEGACY; + bool bAllStaticVarsDefined = m_bDETAILTEXTURE && m_bCUBEMAP && m_bDIFFUSELIGHTING && m_bENVMAPMASK && m_bBASEALPHAENVMAPMASK && m_bSELFILLUM && m_bVERTEXCOLOR && m_bFLASHLIGHT && m_bSELFILLUM_ENVMAPMASK_ALPHA && m_bDETAIL_BLEND_MODE && m_bSEAMLESS_BASE && m_bSEAMLESS_DETAIL && m_bDISTANCEALPHA && m_bDISTANCEALPHAFROMDETAIL && m_bSOFT_MASK && m_bOUTLINE && m_bOUTER_GLOW && m_bFLASHLIGHTDEPTHFILTERMODE && m_bDEPTHBLEND && m_bBLENDTINTBYBASEALPHA && m_bSRGB_INPUT_ADAPTER; Assert( bAllStaticVarsDefined ); #endif // _DEBUG - return ( 6 * m_nDETAILTEXTURE ) + ( 12 * m_nCUBEMAP ) + ( 24 * m_nDIFFUSELIGHTING ) + ( 48 * m_nENVMAPMASK ) + ( 96 * m_nBASEALPHAENVMAPMASK ) + ( 192 * m_nSELFILLUM ) + ( 384 * m_nVERTEXCOLOR ) + ( 768 * m_nFLASHLIGHT ) + ( 1536 * m_nSELFILLUM_ENVMAPMASK_ALPHA ) + ( 3072 * m_nDETAIL_BLEND_MODE ) + ( 30720 * m_nSEAMLESS_BASE ) + ( 61440 * m_nSEAMLESS_DETAIL ) + ( 122880 * m_nDISTANCEALPHA ) + ( 245760 * m_nDISTANCEALPHAFROMDETAIL ) + ( 491520 * m_nSOFT_MASK ) + ( 983040 * m_nOUTLINE ) + ( 1966080 * m_nOUTER_GLOW ) + ( 3932160 * m_nFLASHLIGHTDEPTHFILTERMODE ) + ( 11796480 * m_nDEPTHBLEND ) + ( 23592960 * m_nBLENDTINTBYBASEALPHA ) + ( 47185920 * m_nSRGB_INPUT_ADAPTER ) + ( 94371840 * m_nCUBEMAP_SPHERE_LEGACY ) + 0; + return ( 6 * m_nDETAILTEXTURE ) + ( 12 * m_nCUBEMAP ) + ( 24 * m_nDIFFUSELIGHTING ) + ( 48 * m_nENVMAPMASK ) + ( 96 * m_nBASEALPHAENVMAPMASK ) + ( 192 * m_nSELFILLUM ) + ( 384 * m_nVERTEXCOLOR ) + ( 768 * m_nFLASHLIGHT ) + ( 1536 * m_nSELFILLUM_ENVMAPMASK_ALPHA ) + ( 3072 * m_nDETAIL_BLEND_MODE ) + ( 30720 * m_nSEAMLESS_BASE ) + ( 61440 * m_nSEAMLESS_DETAIL ) + ( 122880 * m_nDISTANCEALPHA ) + ( 245760 * m_nDISTANCEALPHAFROMDETAIL ) + ( 491520 * m_nSOFT_MASK ) + ( 983040 * m_nOUTLINE ) + ( 1966080 * m_nOUTER_GLOW ) + ( 3932160 * m_nFLASHLIGHTDEPTHFILTERMODE ) + ( 11796480 * m_nDEPTHBLEND ) + ( 23592960 * m_nBLENDTINTBYBASEALPHA ) + ( 47185920 * m_nSRGB_INPUT_ADAPTER ) + 0; } }; -#define shaderStaticTest_sdk_vertexlit_and_unlit_generic_ps20b psh_forgot_to_set_static_DETAILTEXTURE + psh_forgot_to_set_static_CUBEMAP + psh_forgot_to_set_static_DIFFUSELIGHTING + psh_forgot_to_set_static_ENVMAPMASK + psh_forgot_to_set_static_BASEALPHAENVMAPMASK + psh_forgot_to_set_static_SELFILLUM + psh_forgot_to_set_static_VERTEXCOLOR + psh_forgot_to_set_static_FLASHLIGHT + psh_forgot_to_set_static_SELFILLUM_ENVMAPMASK_ALPHA + psh_forgot_to_set_static_DETAIL_BLEND_MODE + psh_forgot_to_set_static_SEAMLESS_BASE + psh_forgot_to_set_static_SEAMLESS_DETAIL + psh_forgot_to_set_static_DISTANCEALPHA + psh_forgot_to_set_static_DISTANCEALPHAFROMDETAIL + psh_forgot_to_set_static_SOFT_MASK + psh_forgot_to_set_static_OUTLINE + psh_forgot_to_set_static_OUTER_GLOW + psh_forgot_to_set_static_FLASHLIGHTDEPTHFILTERMODE + psh_forgot_to_set_static_DEPTHBLEND + psh_forgot_to_set_static_BLENDTINTBYBASEALPHA + psh_forgot_to_set_static_SRGB_INPUT_ADAPTER + psh_forgot_to_set_static_CUBEMAP_SPHERE_LEGACY + 0 +#define shaderStaticTest_sdk_vertexlit_and_unlit_generic_ps20b psh_forgot_to_set_static_DETAILTEXTURE + psh_forgot_to_set_static_CUBEMAP + psh_forgot_to_set_static_DIFFUSELIGHTING + psh_forgot_to_set_static_ENVMAPMASK + psh_forgot_to_set_static_BASEALPHAENVMAPMASK + psh_forgot_to_set_static_SELFILLUM + psh_forgot_to_set_static_VERTEXCOLOR + psh_forgot_to_set_static_FLASHLIGHT + psh_forgot_to_set_static_SELFILLUM_ENVMAPMASK_ALPHA + psh_forgot_to_set_static_DETAIL_BLEND_MODE + psh_forgot_to_set_static_SEAMLESS_BASE + psh_forgot_to_set_static_SEAMLESS_DETAIL + psh_forgot_to_set_static_DISTANCEALPHA + psh_forgot_to_set_static_DISTANCEALPHAFROMDETAIL + psh_forgot_to_set_static_SOFT_MASK + psh_forgot_to_set_static_OUTLINE + psh_forgot_to_set_static_OUTER_GLOW + psh_forgot_to_set_static_FLASHLIGHTDEPTHFILTERMODE + psh_forgot_to_set_static_DEPTHBLEND + psh_forgot_to_set_static_BLENDTINTBYBASEALPHA + psh_forgot_to_set_static_SRGB_INPUT_ADAPTER + 0 class sdk_vertexlit_and_unlit_generic_ps20b_Dynamic_Index { private: diff --git a/sp/src/materialsystem/stdshaders/fxctmp9/SDK_vertexlit_and_unlit_generic_ps30.inc b/sp/src/materialsystem/stdshaders/fxctmp9/SDK_vertexlit_and_unlit_generic_ps30.inc index c5a18611..27796cd6 100644 --- a/sp/src/materialsystem/stdshaders/fxctmp9/SDK_vertexlit_and_unlit_generic_ps30.inc +++ b/sp/src/materialsystem/stdshaders/fxctmp9/SDK_vertexlit_and_unlit_generic_ps30.inc @@ -422,24 +422,24 @@ public: #endif } private: - int m_nCUBEMAP_SPHERE_LEGACY; + int m_nENVMAPFRESNEL; #ifdef _DEBUG - bool m_bCUBEMAP_SPHERE_LEGACY; + bool m_bENVMAPFRESNEL; #endif public: - void SetCUBEMAP_SPHERE_LEGACY( int i ) + void SetENVMAPFRESNEL( int i ) { Assert( i >= 0 && i <= 1 ); - m_nCUBEMAP_SPHERE_LEGACY = i; + m_nENVMAPFRESNEL = i; #ifdef _DEBUG - m_bCUBEMAP_SPHERE_LEGACY = true; + m_bENVMAPFRESNEL = true; #endif } - void SetCUBEMAP_SPHERE_LEGACY( bool i ) + void SetENVMAPFRESNEL( bool i ) { - m_nCUBEMAP_SPHERE_LEGACY = i ? 1 : 0; + m_nENVMAPFRESNEL = i ? 1 : 0; #ifdef _DEBUG - m_bCUBEMAP_SPHERE_LEGACY = true; + m_bENVMAPFRESNEL = true; #endif } public: @@ -526,22 +526,22 @@ public: #endif // _DEBUG m_nBLENDTINTBYBASEALPHA = 0; #ifdef _DEBUG - m_bCUBEMAP_SPHERE_LEGACY = false; + m_bENVMAPFRESNEL = false; #endif // _DEBUG - m_nCUBEMAP_SPHERE_LEGACY = 0; + m_nENVMAPFRESNEL = 0; } int GetIndex() { // Asserts to make sure that we aren't using any skipped combinations. // Asserts to make sure that we are setting all of the combination vars. #ifdef _DEBUG - bool bAllStaticVarsDefined = m_bDETAILTEXTURE && m_bCUBEMAP && m_bDIFFUSELIGHTING && m_bENVMAPMASK && m_bBASEALPHAENVMAPMASK && m_bSELFILLUM && m_bVERTEXCOLOR && m_bFLASHLIGHT && m_bSELFILLUM_ENVMAPMASK_ALPHA && m_bDETAIL_BLEND_MODE && m_bSEAMLESS_BASE && m_bSEAMLESS_DETAIL && m_bDISTANCEALPHA && m_bDISTANCEALPHAFROMDETAIL && m_bSOFT_MASK && m_bOUTLINE && m_bOUTER_GLOW && m_bFLASHLIGHTDEPTHFILTERMODE && m_bDEPTHBLEND && m_bBLENDTINTBYBASEALPHA && m_bCUBEMAP_SPHERE_LEGACY; + bool bAllStaticVarsDefined = m_bDETAILTEXTURE && m_bCUBEMAP && m_bDIFFUSELIGHTING && m_bENVMAPMASK && m_bBASEALPHAENVMAPMASK && m_bSELFILLUM && m_bVERTEXCOLOR && m_bFLASHLIGHT && m_bSELFILLUM_ENVMAPMASK_ALPHA && m_bDETAIL_BLEND_MODE && m_bSEAMLESS_BASE && m_bSEAMLESS_DETAIL && m_bDISTANCEALPHA && m_bDISTANCEALPHAFROMDETAIL && m_bSOFT_MASK && m_bOUTLINE && m_bOUTER_GLOW && m_bFLASHLIGHTDEPTHFILTERMODE && m_bDEPTHBLEND && m_bBLENDTINTBYBASEALPHA && m_bENVMAPFRESNEL; Assert( bAllStaticVarsDefined ); #endif // _DEBUG - return ( 6 * m_nDETAILTEXTURE ) + ( 12 * m_nCUBEMAP ) + ( 24 * m_nDIFFUSELIGHTING ) + ( 48 * m_nENVMAPMASK ) + ( 96 * m_nBASEALPHAENVMAPMASK ) + ( 192 * m_nSELFILLUM ) + ( 384 * m_nVERTEXCOLOR ) + ( 768 * m_nFLASHLIGHT ) + ( 1536 * m_nSELFILLUM_ENVMAPMASK_ALPHA ) + ( 3072 * m_nDETAIL_BLEND_MODE ) + ( 30720 * m_nSEAMLESS_BASE ) + ( 61440 * m_nSEAMLESS_DETAIL ) + ( 122880 * m_nDISTANCEALPHA ) + ( 245760 * m_nDISTANCEALPHAFROMDETAIL ) + ( 491520 * m_nSOFT_MASK ) + ( 983040 * m_nOUTLINE ) + ( 1966080 * m_nOUTER_GLOW ) + ( 3932160 * m_nFLASHLIGHTDEPTHFILTERMODE ) + ( 11796480 * m_nDEPTHBLEND ) + ( 23592960 * m_nBLENDTINTBYBASEALPHA ) + ( 47185920 * m_nCUBEMAP_SPHERE_LEGACY ) + 0; + return ( 6 * m_nDETAILTEXTURE ) + ( 12 * m_nCUBEMAP ) + ( 24 * m_nDIFFUSELIGHTING ) + ( 48 * m_nENVMAPMASK ) + ( 96 * m_nBASEALPHAENVMAPMASK ) + ( 192 * m_nSELFILLUM ) + ( 384 * m_nVERTEXCOLOR ) + ( 768 * m_nFLASHLIGHT ) + ( 1536 * m_nSELFILLUM_ENVMAPMASK_ALPHA ) + ( 3072 * m_nDETAIL_BLEND_MODE ) + ( 30720 * m_nSEAMLESS_BASE ) + ( 61440 * m_nSEAMLESS_DETAIL ) + ( 122880 * m_nDISTANCEALPHA ) + ( 245760 * m_nDISTANCEALPHAFROMDETAIL ) + ( 491520 * m_nSOFT_MASK ) + ( 983040 * m_nOUTLINE ) + ( 1966080 * m_nOUTER_GLOW ) + ( 3932160 * m_nFLASHLIGHTDEPTHFILTERMODE ) + ( 11796480 * m_nDEPTHBLEND ) + ( 23592960 * m_nBLENDTINTBYBASEALPHA ) + ( 47185920 * m_nENVMAPFRESNEL ) + 0; } }; -#define shaderStaticTest_sdk_vertexlit_and_unlit_generic_ps30 psh_forgot_to_set_static_DETAILTEXTURE + psh_forgot_to_set_static_CUBEMAP + psh_forgot_to_set_static_DIFFUSELIGHTING + psh_forgot_to_set_static_ENVMAPMASK + psh_forgot_to_set_static_BASEALPHAENVMAPMASK + psh_forgot_to_set_static_SELFILLUM + psh_forgot_to_set_static_VERTEXCOLOR + psh_forgot_to_set_static_FLASHLIGHT + psh_forgot_to_set_static_SELFILLUM_ENVMAPMASK_ALPHA + psh_forgot_to_set_static_DETAIL_BLEND_MODE + psh_forgot_to_set_static_SEAMLESS_BASE + psh_forgot_to_set_static_SEAMLESS_DETAIL + psh_forgot_to_set_static_DISTANCEALPHA + psh_forgot_to_set_static_DISTANCEALPHAFROMDETAIL + psh_forgot_to_set_static_SOFT_MASK + psh_forgot_to_set_static_OUTLINE + psh_forgot_to_set_static_OUTER_GLOW + psh_forgot_to_set_static_FLASHLIGHTDEPTHFILTERMODE + psh_forgot_to_set_static_DEPTHBLEND + psh_forgot_to_set_static_BLENDTINTBYBASEALPHA + psh_forgot_to_set_static_CUBEMAP_SPHERE_LEGACY + 0 +#define shaderStaticTest_sdk_vertexlit_and_unlit_generic_ps30 psh_forgot_to_set_static_DETAILTEXTURE + psh_forgot_to_set_static_CUBEMAP + psh_forgot_to_set_static_DIFFUSELIGHTING + psh_forgot_to_set_static_ENVMAPMASK + psh_forgot_to_set_static_BASEALPHAENVMAPMASK + psh_forgot_to_set_static_SELFILLUM + psh_forgot_to_set_static_VERTEXCOLOR + psh_forgot_to_set_static_FLASHLIGHT + psh_forgot_to_set_static_SELFILLUM_ENVMAPMASK_ALPHA + psh_forgot_to_set_static_DETAIL_BLEND_MODE + psh_forgot_to_set_static_SEAMLESS_BASE + psh_forgot_to_set_static_SEAMLESS_DETAIL + psh_forgot_to_set_static_DISTANCEALPHA + psh_forgot_to_set_static_DISTANCEALPHAFROMDETAIL + psh_forgot_to_set_static_SOFT_MASK + psh_forgot_to_set_static_OUTLINE + psh_forgot_to_set_static_OUTER_GLOW + psh_forgot_to_set_static_FLASHLIGHTDEPTHFILTERMODE + psh_forgot_to_set_static_DEPTHBLEND + psh_forgot_to_set_static_BLENDTINTBYBASEALPHA + psh_forgot_to_set_static_ENVMAPFRESNEL + 0 class sdk_vertexlit_and_unlit_generic_ps30_Dynamic_Index { private: diff --git a/sp/src/materialsystem/stdshaders/fxctmp9_tmp/SDK_vertexlit_and_unlit_generic_ps20.inc b/sp/src/materialsystem/stdshaders/fxctmp9_tmp/SDK_vertexlit_and_unlit_generic_ps20.inc index 0bf098cd..8383989c 100644 --- a/sp/src/materialsystem/stdshaders/fxctmp9_tmp/SDK_vertexlit_and_unlit_generic_ps20.inc +++ b/sp/src/materialsystem/stdshaders/fxctmp9_tmp/SDK_vertexlit_and_unlit_generic_ps20.inc @@ -379,27 +379,6 @@ public: m_bBLENDTINTBYBASEALPHA = true; #endif } -private: - int m_nCUBEMAP_SPHERE_LEGACY; -#ifdef _DEBUG - bool m_bCUBEMAP_SPHERE_LEGACY; -#endif -public: - void SetCUBEMAP_SPHERE_LEGACY( int i ) - { - Assert( i >= 0 && i <= 1 ); - m_nCUBEMAP_SPHERE_LEGACY = i; -#ifdef _DEBUG - m_bCUBEMAP_SPHERE_LEGACY = true; -#endif - } - void SetCUBEMAP_SPHERE_LEGACY( bool i ) - { - m_nCUBEMAP_SPHERE_LEGACY = i ? 1 : 0; -#ifdef _DEBUG - m_bCUBEMAP_SPHERE_LEGACY = true; -#endif - } public: sdk_vertexlit_and_unlit_generic_ps20_Static_Index( ) { @@ -475,23 +454,19 @@ public: m_bBLENDTINTBYBASEALPHA = false; #endif // _DEBUG m_nBLENDTINTBYBASEALPHA = 0; -#ifdef _DEBUG - m_bCUBEMAP_SPHERE_LEGACY = false; -#endif // _DEBUG - m_nCUBEMAP_SPHERE_LEGACY = 0; } int GetIndex() { // Asserts to make sure that we aren't using any skipped combinations. // Asserts to make sure that we are setting all of the combination vars. #ifdef _DEBUG - bool bAllStaticVarsDefined = m_bDETAILTEXTURE && m_bCUBEMAP && m_bDIFFUSELIGHTING && m_bENVMAPMASK && m_bBASEALPHAENVMAPMASK && m_bSELFILLUM && m_bVERTEXCOLOR && m_bFLASHLIGHT && m_bSELFILLUM_ENVMAPMASK_ALPHA && m_bDETAIL_BLEND_MODE && m_bSEAMLESS_BASE && m_bSEAMLESS_DETAIL && m_bDISTANCEALPHA && m_bDISTANCEALPHAFROMDETAIL && m_bSOFT_MASK && m_bOUTLINE && m_bOUTER_GLOW && m_bBLENDTINTBYBASEALPHA && m_bCUBEMAP_SPHERE_LEGACY; + bool bAllStaticVarsDefined = m_bDETAILTEXTURE && m_bCUBEMAP && m_bDIFFUSELIGHTING && m_bENVMAPMASK && m_bBASEALPHAENVMAPMASK && m_bSELFILLUM && m_bVERTEXCOLOR && m_bFLASHLIGHT && m_bSELFILLUM_ENVMAPMASK_ALPHA && m_bDETAIL_BLEND_MODE && m_bSEAMLESS_BASE && m_bSEAMLESS_DETAIL && m_bDISTANCEALPHA && m_bDISTANCEALPHAFROMDETAIL && m_bSOFT_MASK && m_bOUTLINE && m_bOUTER_GLOW && m_bBLENDTINTBYBASEALPHA; Assert( bAllStaticVarsDefined ); #endif // _DEBUG - return ( 6 * m_nDETAILTEXTURE ) + ( 12 * m_nCUBEMAP ) + ( 24 * m_nDIFFUSELIGHTING ) + ( 48 * m_nENVMAPMASK ) + ( 96 * m_nBASEALPHAENVMAPMASK ) + ( 192 * m_nSELFILLUM ) + ( 384 * m_nVERTEXCOLOR ) + ( 768 * m_nFLASHLIGHT ) + ( 1536 * m_nSELFILLUM_ENVMAPMASK_ALPHA ) + ( 3072 * m_nDETAIL_BLEND_MODE ) + ( 30720 * m_nSEAMLESS_BASE ) + ( 61440 * m_nSEAMLESS_DETAIL ) + ( 122880 * m_nDISTANCEALPHA ) + ( 245760 * m_nDISTANCEALPHAFROMDETAIL ) + ( 491520 * m_nSOFT_MASK ) + ( 983040 * m_nOUTLINE ) + ( 1966080 * m_nOUTER_GLOW ) + ( 3932160 * m_nBLENDTINTBYBASEALPHA ) + ( 7864320 * m_nCUBEMAP_SPHERE_LEGACY ) + 0; + return ( 6 * m_nDETAILTEXTURE ) + ( 12 * m_nCUBEMAP ) + ( 24 * m_nDIFFUSELIGHTING ) + ( 48 * m_nENVMAPMASK ) + ( 96 * m_nBASEALPHAENVMAPMASK ) + ( 192 * m_nSELFILLUM ) + ( 384 * m_nVERTEXCOLOR ) + ( 768 * m_nFLASHLIGHT ) + ( 1536 * m_nSELFILLUM_ENVMAPMASK_ALPHA ) + ( 3072 * m_nDETAIL_BLEND_MODE ) + ( 30720 * m_nSEAMLESS_BASE ) + ( 61440 * m_nSEAMLESS_DETAIL ) + ( 122880 * m_nDISTANCEALPHA ) + ( 245760 * m_nDISTANCEALPHAFROMDETAIL ) + ( 491520 * m_nSOFT_MASK ) + ( 983040 * m_nOUTLINE ) + ( 1966080 * m_nOUTER_GLOW ) + ( 3932160 * m_nBLENDTINTBYBASEALPHA ) + 0; } }; -#define shaderStaticTest_sdk_vertexlit_and_unlit_generic_ps20 psh_forgot_to_set_static_DETAILTEXTURE + psh_forgot_to_set_static_CUBEMAP + psh_forgot_to_set_static_DIFFUSELIGHTING + psh_forgot_to_set_static_ENVMAPMASK + psh_forgot_to_set_static_BASEALPHAENVMAPMASK + psh_forgot_to_set_static_SELFILLUM + psh_forgot_to_set_static_VERTEXCOLOR + psh_forgot_to_set_static_FLASHLIGHT + psh_forgot_to_set_static_SELFILLUM_ENVMAPMASK_ALPHA + psh_forgot_to_set_static_DETAIL_BLEND_MODE + psh_forgot_to_set_static_SEAMLESS_BASE + psh_forgot_to_set_static_SEAMLESS_DETAIL + psh_forgot_to_set_static_DISTANCEALPHA + psh_forgot_to_set_static_DISTANCEALPHAFROMDETAIL + psh_forgot_to_set_static_SOFT_MASK + psh_forgot_to_set_static_OUTLINE + psh_forgot_to_set_static_OUTER_GLOW + psh_forgot_to_set_static_BLENDTINTBYBASEALPHA + psh_forgot_to_set_static_CUBEMAP_SPHERE_LEGACY + 0 +#define shaderStaticTest_sdk_vertexlit_and_unlit_generic_ps20 psh_forgot_to_set_static_DETAILTEXTURE + psh_forgot_to_set_static_CUBEMAP + psh_forgot_to_set_static_DIFFUSELIGHTING + psh_forgot_to_set_static_ENVMAPMASK + psh_forgot_to_set_static_BASEALPHAENVMAPMASK + psh_forgot_to_set_static_SELFILLUM + psh_forgot_to_set_static_VERTEXCOLOR + psh_forgot_to_set_static_FLASHLIGHT + psh_forgot_to_set_static_SELFILLUM_ENVMAPMASK_ALPHA + psh_forgot_to_set_static_DETAIL_BLEND_MODE + psh_forgot_to_set_static_SEAMLESS_BASE + psh_forgot_to_set_static_SEAMLESS_DETAIL + psh_forgot_to_set_static_DISTANCEALPHA + psh_forgot_to_set_static_DISTANCEALPHAFROMDETAIL + psh_forgot_to_set_static_SOFT_MASK + psh_forgot_to_set_static_OUTLINE + psh_forgot_to_set_static_OUTER_GLOW + psh_forgot_to_set_static_BLENDTINTBYBASEALPHA + 0 class sdk_vertexlit_and_unlit_generic_ps20_Dynamic_Index { private: diff --git a/sp/src/materialsystem/stdshaders/fxctmp9_tmp/SDK_vertexlit_and_unlit_generic_ps20b.inc b/sp/src/materialsystem/stdshaders/fxctmp9_tmp/SDK_vertexlit_and_unlit_generic_ps20b.inc index ee74372c..1106743f 100644 --- a/sp/src/materialsystem/stdshaders/fxctmp9_tmp/SDK_vertexlit_and_unlit_generic_ps20b.inc +++ b/sp/src/materialsystem/stdshaders/fxctmp9_tmp/SDK_vertexlit_and_unlit_generic_ps20b.inc @@ -442,27 +442,6 @@ public: m_bSRGB_INPUT_ADAPTER = true; #endif } -private: - int m_nCUBEMAP_SPHERE_LEGACY; -#ifdef _DEBUG - bool m_bCUBEMAP_SPHERE_LEGACY; -#endif -public: - void SetCUBEMAP_SPHERE_LEGACY( int i ) - { - Assert( i >= 0 && i <= 1 ); - m_nCUBEMAP_SPHERE_LEGACY = i; -#ifdef _DEBUG - m_bCUBEMAP_SPHERE_LEGACY = true; -#endif - } - void SetCUBEMAP_SPHERE_LEGACY( bool i ) - { - m_nCUBEMAP_SPHERE_LEGACY = i ? 1 : 0; -#ifdef _DEBUG - m_bCUBEMAP_SPHERE_LEGACY = true; -#endif - } public: sdk_vertexlit_and_unlit_generic_ps20b_Static_Index( ) { @@ -550,23 +529,19 @@ public: m_bSRGB_INPUT_ADAPTER = false; #endif // _DEBUG m_nSRGB_INPUT_ADAPTER = 0; -#ifdef _DEBUG - m_bCUBEMAP_SPHERE_LEGACY = false; -#endif // _DEBUG - m_nCUBEMAP_SPHERE_LEGACY = 0; } int GetIndex() { // Asserts to make sure that we aren't using any skipped combinations. // Asserts to make sure that we are setting all of the combination vars. #ifdef _DEBUG - bool bAllStaticVarsDefined = m_bDETAILTEXTURE && m_bCUBEMAP && m_bDIFFUSELIGHTING && m_bENVMAPMASK && m_bBASEALPHAENVMAPMASK && m_bSELFILLUM && m_bVERTEXCOLOR && m_bFLASHLIGHT && m_bSELFILLUM_ENVMAPMASK_ALPHA && m_bDETAIL_BLEND_MODE && m_bSEAMLESS_BASE && m_bSEAMLESS_DETAIL && m_bDISTANCEALPHA && m_bDISTANCEALPHAFROMDETAIL && m_bSOFT_MASK && m_bOUTLINE && m_bOUTER_GLOW && m_bFLASHLIGHTDEPTHFILTERMODE && m_bDEPTHBLEND && m_bBLENDTINTBYBASEALPHA && m_bSRGB_INPUT_ADAPTER && m_bCUBEMAP_SPHERE_LEGACY; + bool bAllStaticVarsDefined = m_bDETAILTEXTURE && m_bCUBEMAP && m_bDIFFUSELIGHTING && m_bENVMAPMASK && m_bBASEALPHAENVMAPMASK && m_bSELFILLUM && m_bVERTEXCOLOR && m_bFLASHLIGHT && m_bSELFILLUM_ENVMAPMASK_ALPHA && m_bDETAIL_BLEND_MODE && m_bSEAMLESS_BASE && m_bSEAMLESS_DETAIL && m_bDISTANCEALPHA && m_bDISTANCEALPHAFROMDETAIL && m_bSOFT_MASK && m_bOUTLINE && m_bOUTER_GLOW && m_bFLASHLIGHTDEPTHFILTERMODE && m_bDEPTHBLEND && m_bBLENDTINTBYBASEALPHA && m_bSRGB_INPUT_ADAPTER; Assert( bAllStaticVarsDefined ); #endif // _DEBUG - return ( 6 * m_nDETAILTEXTURE ) + ( 12 * m_nCUBEMAP ) + ( 24 * m_nDIFFUSELIGHTING ) + ( 48 * m_nENVMAPMASK ) + ( 96 * m_nBASEALPHAENVMAPMASK ) + ( 192 * m_nSELFILLUM ) + ( 384 * m_nVERTEXCOLOR ) + ( 768 * m_nFLASHLIGHT ) + ( 1536 * m_nSELFILLUM_ENVMAPMASK_ALPHA ) + ( 3072 * m_nDETAIL_BLEND_MODE ) + ( 30720 * m_nSEAMLESS_BASE ) + ( 61440 * m_nSEAMLESS_DETAIL ) + ( 122880 * m_nDISTANCEALPHA ) + ( 245760 * m_nDISTANCEALPHAFROMDETAIL ) + ( 491520 * m_nSOFT_MASK ) + ( 983040 * m_nOUTLINE ) + ( 1966080 * m_nOUTER_GLOW ) + ( 3932160 * m_nFLASHLIGHTDEPTHFILTERMODE ) + ( 11796480 * m_nDEPTHBLEND ) + ( 23592960 * m_nBLENDTINTBYBASEALPHA ) + ( 47185920 * m_nSRGB_INPUT_ADAPTER ) + ( 94371840 * m_nCUBEMAP_SPHERE_LEGACY ) + 0; + return ( 6 * m_nDETAILTEXTURE ) + ( 12 * m_nCUBEMAP ) + ( 24 * m_nDIFFUSELIGHTING ) + ( 48 * m_nENVMAPMASK ) + ( 96 * m_nBASEALPHAENVMAPMASK ) + ( 192 * m_nSELFILLUM ) + ( 384 * m_nVERTEXCOLOR ) + ( 768 * m_nFLASHLIGHT ) + ( 1536 * m_nSELFILLUM_ENVMAPMASK_ALPHA ) + ( 3072 * m_nDETAIL_BLEND_MODE ) + ( 30720 * m_nSEAMLESS_BASE ) + ( 61440 * m_nSEAMLESS_DETAIL ) + ( 122880 * m_nDISTANCEALPHA ) + ( 245760 * m_nDISTANCEALPHAFROMDETAIL ) + ( 491520 * m_nSOFT_MASK ) + ( 983040 * m_nOUTLINE ) + ( 1966080 * m_nOUTER_GLOW ) + ( 3932160 * m_nFLASHLIGHTDEPTHFILTERMODE ) + ( 11796480 * m_nDEPTHBLEND ) + ( 23592960 * m_nBLENDTINTBYBASEALPHA ) + ( 47185920 * m_nSRGB_INPUT_ADAPTER ) + 0; } }; -#define shaderStaticTest_sdk_vertexlit_and_unlit_generic_ps20b psh_forgot_to_set_static_DETAILTEXTURE + psh_forgot_to_set_static_CUBEMAP + psh_forgot_to_set_static_DIFFUSELIGHTING + psh_forgot_to_set_static_ENVMAPMASK + psh_forgot_to_set_static_BASEALPHAENVMAPMASK + psh_forgot_to_set_static_SELFILLUM + psh_forgot_to_set_static_VERTEXCOLOR + psh_forgot_to_set_static_FLASHLIGHT + psh_forgot_to_set_static_SELFILLUM_ENVMAPMASK_ALPHA + psh_forgot_to_set_static_DETAIL_BLEND_MODE + psh_forgot_to_set_static_SEAMLESS_BASE + psh_forgot_to_set_static_SEAMLESS_DETAIL + psh_forgot_to_set_static_DISTANCEALPHA + psh_forgot_to_set_static_DISTANCEALPHAFROMDETAIL + psh_forgot_to_set_static_SOFT_MASK + psh_forgot_to_set_static_OUTLINE + psh_forgot_to_set_static_OUTER_GLOW + psh_forgot_to_set_static_FLASHLIGHTDEPTHFILTERMODE + psh_forgot_to_set_static_DEPTHBLEND + psh_forgot_to_set_static_BLENDTINTBYBASEALPHA + psh_forgot_to_set_static_SRGB_INPUT_ADAPTER + psh_forgot_to_set_static_CUBEMAP_SPHERE_LEGACY + 0 +#define shaderStaticTest_sdk_vertexlit_and_unlit_generic_ps20b psh_forgot_to_set_static_DETAILTEXTURE + psh_forgot_to_set_static_CUBEMAP + psh_forgot_to_set_static_DIFFUSELIGHTING + psh_forgot_to_set_static_ENVMAPMASK + psh_forgot_to_set_static_BASEALPHAENVMAPMASK + psh_forgot_to_set_static_SELFILLUM + psh_forgot_to_set_static_VERTEXCOLOR + psh_forgot_to_set_static_FLASHLIGHT + psh_forgot_to_set_static_SELFILLUM_ENVMAPMASK_ALPHA + psh_forgot_to_set_static_DETAIL_BLEND_MODE + psh_forgot_to_set_static_SEAMLESS_BASE + psh_forgot_to_set_static_SEAMLESS_DETAIL + psh_forgot_to_set_static_DISTANCEALPHA + psh_forgot_to_set_static_DISTANCEALPHAFROMDETAIL + psh_forgot_to_set_static_SOFT_MASK + psh_forgot_to_set_static_OUTLINE + psh_forgot_to_set_static_OUTER_GLOW + psh_forgot_to_set_static_FLASHLIGHTDEPTHFILTERMODE + psh_forgot_to_set_static_DEPTHBLEND + psh_forgot_to_set_static_BLENDTINTBYBASEALPHA + psh_forgot_to_set_static_SRGB_INPUT_ADAPTER + 0 class sdk_vertexlit_and_unlit_generic_ps20b_Dynamic_Index { private: diff --git a/sp/src/materialsystem/stdshaders/fxctmp9_tmp/SDK_vertexlit_and_unlit_generic_ps30.inc b/sp/src/materialsystem/stdshaders/fxctmp9_tmp/SDK_vertexlit_and_unlit_generic_ps30.inc index c5a18611..27796cd6 100644 --- a/sp/src/materialsystem/stdshaders/fxctmp9_tmp/SDK_vertexlit_and_unlit_generic_ps30.inc +++ b/sp/src/materialsystem/stdshaders/fxctmp9_tmp/SDK_vertexlit_and_unlit_generic_ps30.inc @@ -422,24 +422,24 @@ public: #endif } private: - int m_nCUBEMAP_SPHERE_LEGACY; + int m_nENVMAPFRESNEL; #ifdef _DEBUG - bool m_bCUBEMAP_SPHERE_LEGACY; + bool m_bENVMAPFRESNEL; #endif public: - void SetCUBEMAP_SPHERE_LEGACY( int i ) + void SetENVMAPFRESNEL( int i ) { Assert( i >= 0 && i <= 1 ); - m_nCUBEMAP_SPHERE_LEGACY = i; + m_nENVMAPFRESNEL = i; #ifdef _DEBUG - m_bCUBEMAP_SPHERE_LEGACY = true; + m_bENVMAPFRESNEL = true; #endif } - void SetCUBEMAP_SPHERE_LEGACY( bool i ) + void SetENVMAPFRESNEL( bool i ) { - m_nCUBEMAP_SPHERE_LEGACY = i ? 1 : 0; + m_nENVMAPFRESNEL = i ? 1 : 0; #ifdef _DEBUG - m_bCUBEMAP_SPHERE_LEGACY = true; + m_bENVMAPFRESNEL = true; #endif } public: @@ -526,22 +526,22 @@ public: #endif // _DEBUG m_nBLENDTINTBYBASEALPHA = 0; #ifdef _DEBUG - m_bCUBEMAP_SPHERE_LEGACY = false; + m_bENVMAPFRESNEL = false; #endif // _DEBUG - m_nCUBEMAP_SPHERE_LEGACY = 0; + m_nENVMAPFRESNEL = 0; } int GetIndex() { // Asserts to make sure that we aren't using any skipped combinations. // Asserts to make sure that we are setting all of the combination vars. #ifdef _DEBUG - bool bAllStaticVarsDefined = m_bDETAILTEXTURE && m_bCUBEMAP && m_bDIFFUSELIGHTING && m_bENVMAPMASK && m_bBASEALPHAENVMAPMASK && m_bSELFILLUM && m_bVERTEXCOLOR && m_bFLASHLIGHT && m_bSELFILLUM_ENVMAPMASK_ALPHA && m_bDETAIL_BLEND_MODE && m_bSEAMLESS_BASE && m_bSEAMLESS_DETAIL && m_bDISTANCEALPHA && m_bDISTANCEALPHAFROMDETAIL && m_bSOFT_MASK && m_bOUTLINE && m_bOUTER_GLOW && m_bFLASHLIGHTDEPTHFILTERMODE && m_bDEPTHBLEND && m_bBLENDTINTBYBASEALPHA && m_bCUBEMAP_SPHERE_LEGACY; + bool bAllStaticVarsDefined = m_bDETAILTEXTURE && m_bCUBEMAP && m_bDIFFUSELIGHTING && m_bENVMAPMASK && m_bBASEALPHAENVMAPMASK && m_bSELFILLUM && m_bVERTEXCOLOR && m_bFLASHLIGHT && m_bSELFILLUM_ENVMAPMASK_ALPHA && m_bDETAIL_BLEND_MODE && m_bSEAMLESS_BASE && m_bSEAMLESS_DETAIL && m_bDISTANCEALPHA && m_bDISTANCEALPHAFROMDETAIL && m_bSOFT_MASK && m_bOUTLINE && m_bOUTER_GLOW && m_bFLASHLIGHTDEPTHFILTERMODE && m_bDEPTHBLEND && m_bBLENDTINTBYBASEALPHA && m_bENVMAPFRESNEL; Assert( bAllStaticVarsDefined ); #endif // _DEBUG - return ( 6 * m_nDETAILTEXTURE ) + ( 12 * m_nCUBEMAP ) + ( 24 * m_nDIFFUSELIGHTING ) + ( 48 * m_nENVMAPMASK ) + ( 96 * m_nBASEALPHAENVMAPMASK ) + ( 192 * m_nSELFILLUM ) + ( 384 * m_nVERTEXCOLOR ) + ( 768 * m_nFLASHLIGHT ) + ( 1536 * m_nSELFILLUM_ENVMAPMASK_ALPHA ) + ( 3072 * m_nDETAIL_BLEND_MODE ) + ( 30720 * m_nSEAMLESS_BASE ) + ( 61440 * m_nSEAMLESS_DETAIL ) + ( 122880 * m_nDISTANCEALPHA ) + ( 245760 * m_nDISTANCEALPHAFROMDETAIL ) + ( 491520 * m_nSOFT_MASK ) + ( 983040 * m_nOUTLINE ) + ( 1966080 * m_nOUTER_GLOW ) + ( 3932160 * m_nFLASHLIGHTDEPTHFILTERMODE ) + ( 11796480 * m_nDEPTHBLEND ) + ( 23592960 * m_nBLENDTINTBYBASEALPHA ) + ( 47185920 * m_nCUBEMAP_SPHERE_LEGACY ) + 0; + return ( 6 * m_nDETAILTEXTURE ) + ( 12 * m_nCUBEMAP ) + ( 24 * m_nDIFFUSELIGHTING ) + ( 48 * m_nENVMAPMASK ) + ( 96 * m_nBASEALPHAENVMAPMASK ) + ( 192 * m_nSELFILLUM ) + ( 384 * m_nVERTEXCOLOR ) + ( 768 * m_nFLASHLIGHT ) + ( 1536 * m_nSELFILLUM_ENVMAPMASK_ALPHA ) + ( 3072 * m_nDETAIL_BLEND_MODE ) + ( 30720 * m_nSEAMLESS_BASE ) + ( 61440 * m_nSEAMLESS_DETAIL ) + ( 122880 * m_nDISTANCEALPHA ) + ( 245760 * m_nDISTANCEALPHAFROMDETAIL ) + ( 491520 * m_nSOFT_MASK ) + ( 983040 * m_nOUTLINE ) + ( 1966080 * m_nOUTER_GLOW ) + ( 3932160 * m_nFLASHLIGHTDEPTHFILTERMODE ) + ( 11796480 * m_nDEPTHBLEND ) + ( 23592960 * m_nBLENDTINTBYBASEALPHA ) + ( 47185920 * m_nENVMAPFRESNEL ) + 0; } }; -#define shaderStaticTest_sdk_vertexlit_and_unlit_generic_ps30 psh_forgot_to_set_static_DETAILTEXTURE + psh_forgot_to_set_static_CUBEMAP + psh_forgot_to_set_static_DIFFUSELIGHTING + psh_forgot_to_set_static_ENVMAPMASK + psh_forgot_to_set_static_BASEALPHAENVMAPMASK + psh_forgot_to_set_static_SELFILLUM + psh_forgot_to_set_static_VERTEXCOLOR + psh_forgot_to_set_static_FLASHLIGHT + psh_forgot_to_set_static_SELFILLUM_ENVMAPMASK_ALPHA + psh_forgot_to_set_static_DETAIL_BLEND_MODE + psh_forgot_to_set_static_SEAMLESS_BASE + psh_forgot_to_set_static_SEAMLESS_DETAIL + psh_forgot_to_set_static_DISTANCEALPHA + psh_forgot_to_set_static_DISTANCEALPHAFROMDETAIL + psh_forgot_to_set_static_SOFT_MASK + psh_forgot_to_set_static_OUTLINE + psh_forgot_to_set_static_OUTER_GLOW + psh_forgot_to_set_static_FLASHLIGHTDEPTHFILTERMODE + psh_forgot_to_set_static_DEPTHBLEND + psh_forgot_to_set_static_BLENDTINTBYBASEALPHA + psh_forgot_to_set_static_CUBEMAP_SPHERE_LEGACY + 0 +#define shaderStaticTest_sdk_vertexlit_and_unlit_generic_ps30 psh_forgot_to_set_static_DETAILTEXTURE + psh_forgot_to_set_static_CUBEMAP + psh_forgot_to_set_static_DIFFUSELIGHTING + psh_forgot_to_set_static_ENVMAPMASK + psh_forgot_to_set_static_BASEALPHAENVMAPMASK + psh_forgot_to_set_static_SELFILLUM + psh_forgot_to_set_static_VERTEXCOLOR + psh_forgot_to_set_static_FLASHLIGHT + psh_forgot_to_set_static_SELFILLUM_ENVMAPMASK_ALPHA + psh_forgot_to_set_static_DETAIL_BLEND_MODE + psh_forgot_to_set_static_SEAMLESS_BASE + psh_forgot_to_set_static_SEAMLESS_DETAIL + psh_forgot_to_set_static_DISTANCEALPHA + psh_forgot_to_set_static_DISTANCEALPHAFROMDETAIL + psh_forgot_to_set_static_SOFT_MASK + psh_forgot_to_set_static_OUTLINE + psh_forgot_to_set_static_OUTER_GLOW + psh_forgot_to_set_static_FLASHLIGHTDEPTHFILTERMODE + psh_forgot_to_set_static_DEPTHBLEND + psh_forgot_to_set_static_BLENDTINTBYBASEALPHA + psh_forgot_to_set_static_ENVMAPFRESNEL + 0 class sdk_vertexlit_and_unlit_generic_ps30_Dynamic_Index { private: diff --git a/sp/src/materialsystem/stdshaders/unlitgeneric_dx9.cpp b/sp/src/materialsystem/stdshaders/unlitgeneric_dx9.cpp index f0c30116..23854678 100644 --- a/sp/src/materialsystem/stdshaders/unlitgeneric_dx9.cpp +++ b/sp/src/materialsystem/stdshaders/unlitgeneric_dx9.cpp @@ -78,6 +78,13 @@ BEGIN_VS_SHADER( SDK_UnlitGeneric, "Help for SDK_UnlitGeneric" ) SHADER_PARAM( DEPTHBLENDSCALE, SHADER_PARAM_TYPE_FLOAT, "50.0", "Amplify or reduce DEPTHBLEND fading. Lower values make harder edges." ) SHADER_PARAM( RECEIVEFLASHLIGHT, SHADER_PARAM_TYPE_INTEGER, "0", "Forces this material to receive flashlights." ) +#ifdef MAPBASE + SHADER_PARAM( ALLOWDIFFUSEMODULATION, SHADER_PARAM_TYPE_BOOL, "1", "Allow per-instance color modulation" ) + + SHADER_PARAM( ENVMAPFRESNELMINMAXEXP, SHADER_PARAM_TYPE_VEC3, "[0.0 1.0 2.0]", "Min/max fresnel range and exponent for vertexlitgeneric" ) + SHADER_PARAM( BASEALPHAENVMAPMASKMINMAXEXP, SHADER_PARAM_TYPE_VEC3, "[1.0 0.0 1.0]", "" ) +#endif + // vertexlitgeneric tree sway animation control (on unlitgeneric) SHADER_PARAM( TREESWAY, SHADER_PARAM_TYPE_INTEGER, "0", "" ) SHADER_PARAM( TREESWAYHEIGHT, SHADER_PARAM_TYPE_FLOAT, "1000", "" ) @@ -177,6 +184,13 @@ BEGIN_VS_SHADER( SDK_UnlitGeneric, "Help for SDK_UnlitGeneric" ) info.m_nDepthBlendScale = DEPTHBLENDSCALE; info.m_nReceiveFlashlight = RECEIVEFLASHLIGHT; +#ifdef MAPBASE + info.m_nAllowDiffuseModulation = ALLOWDIFFUSEMODULATION; + + info.m_nEnvMapFresnelMinMaxExp = ENVMAPFRESNELMINMAXEXP; + info.m_nBaseAlphaEnvMapMaskMinMaxExp = BASEALPHAENVMAPMASKMINMAXEXP; +#endif + info.m_nTreeSway = TREESWAY; info.m_nTreeSwayHeight = TREESWAYHEIGHT; info.m_nTreeSwayStartHeight = TREESWAYSTARTHEIGHT; diff --git a/sp/src/materialsystem/stdshaders/vertexlitgeneric_dx9.cpp b/sp/src/materialsystem/stdshaders/vertexlitgeneric_dx9.cpp index 73918971..378c39be 100644 --- a/sp/src/materialsystem/stdshaders/vertexlitgeneric_dx9.cpp +++ b/sp/src/materialsystem/stdshaders/vertexlitgeneric_dx9.cpp @@ -141,6 +141,11 @@ BEGIN_VS_SHADER( SDK_VertexLitGeneric, "Help for SDK_VertexLitGeneric" ) SHADER_PARAM( BLENDTINTCOLOROVERBASE, SHADER_PARAM_TYPE_FLOAT, "0", "blend between tint acting as a multiplication versus a replace" ) #ifdef MAPBASE + SHADER_PARAM( ALLOWDIFFUSEMODULATION, SHADER_PARAM_TYPE_BOOL, "1", "Allow per-instance color modulation" ) + + SHADER_PARAM( ENVMAPFRESNELMINMAXEXP, SHADER_PARAM_TYPE_VEC3, "[0.0 1.0 2.0]", "Min/max fresnel range and exponent for vertexlitgeneric" ) + SHADER_PARAM( BASEALPHAENVMAPMASKMINMAXEXP, SHADER_PARAM_TYPE_VEC3, "[1.0 0.0 1.0]", "" ) + SHADER_PARAM( PHONGDISABLEHALFLAMBERT, SHADER_PARAM_TYPE_BOOL, "0", "Disable half lambert for phong" ) #endif @@ -239,6 +244,11 @@ BEGIN_VS_SHADER( SDK_VertexLitGeneric, "Help for SDK_VertexLitGeneric" ) info.m_nTintReplacesBaseColor = BLENDTINTCOLOROVERBASE; #ifdef MAPBASE + info.m_nAllowDiffuseModulation = ALLOWDIFFUSEMODULATION; + + info.m_nEnvMapFresnelMinMaxExp = ENVMAPFRESNELMINMAXEXP; + info.m_nBaseAlphaEnvMapMaskMinMaxExp = BASEALPHAENVMAPMASKMINMAXEXP; + info.m_nPhongDisableHalfLambert = PHONGDISABLEHALFLAMBERT; #endif diff --git a/sp/src/materialsystem/stdshaders/vertexlitgeneric_dx9_helper.cpp b/sp/src/materialsystem/stdshaders/vertexlitgeneric_dx9_helper.cpp index 21202a4e..14890a22 100644 --- a/sp/src/materialsystem/stdshaders/vertexlitgeneric_dx9_helper.cpp +++ b/sp/src/materialsystem/stdshaders/vertexlitgeneric_dx9_helper.cpp @@ -225,6 +225,21 @@ void InitParamsVertexLitGeneric_DX9( CBaseVSShader *pShader, IMaterialVar** para InitIntParam( info.m_nDepthBlend, params, 0 ); InitFloatParam( info.m_nDepthBlendScale, params, 50.0f ); + +#ifdef MAPBASE + InitIntParam( info.m_nAllowDiffuseModulation, params, 1 ); + + if ( ( info.m_nEnvMapFresnelMinMaxExp != -1 ) && !params[info.m_nEnvMapFresnelMinMaxExp]->IsDefined() ) + { + params[info.m_nEnvMapFresnelMinMaxExp]->SetVecValue( 0.0f, 1.0f, 2.0f, 0.0f ); + } + if ( ( info.m_nBaseAlphaEnvMapMaskMinMaxExp != -1 ) && !params[info.m_nBaseAlphaEnvMapMaskMinMaxExp]->IsDefined() ) + { + // Default to min: 1 max: 0 exp: 1 so that we default to the legacy behavior for basealphaenvmapmask, which is 1-baseColor.a + // These default values translate to a scale of -1, bias of 1 and exponent 1 in the shader. + params[info.m_nBaseAlphaEnvMapMaskMinMaxExp]->SetVecValue( 1.0f, 0.0f, 1.0f, 0.0f ); + } +#endif InitIntParam( info.m_nTreeSway, params, 0 ); InitFloatParam( info.m_nTreeSwayHeight, params, 1000.0f ); @@ -458,18 +473,33 @@ static void DrawVertexLitGeneric_DX9_Internal( CBaseVSShader *pShader, IMaterial bool bHasSelfIllum = (!bHasFlashlight || IsX360() ) && IS_FLAG_SET( MATERIAL_VAR_SELFILLUM ); bool bHasEnvmapMask = (!bHasFlashlight || IsX360() ) && info.m_nEnvmapMask != -1 && params[info.m_nEnvmapMask]->IsTexture(); bool bHasSelfIllumFresnel = ( !IsTextureSet( info.m_nDetail, params ) ) && ( bHasSelfIllum ) && ( info.m_nSelfIllumFresnel != -1 ) && ( params[info.m_nSelfIllumFresnel]->GetIntValue() != 0 ); +#ifdef MAPBASE + bool bHasEnvMapFresnel = bHasEnvmap && IsBoolSet( info.m_nEnvmapFresnel, params ); +#endif bool bHasSelfIllumMask = bHasSelfIllum && IsTextureSet( info.m_nSelfIllumMask, params ); bool hasSelfIllumInEnvMapMask = ( info.m_nSelfIllumEnvMapMask_Alpha != -1 ) && ( params[info.m_nSelfIllumEnvMapMask_Alpha]->GetFloatValue() != 0.0 ) ; +#ifdef MAPBASE + if (!bHasEnvmap) + { + bHasEnvmapMask = hasSelfIllumInEnvMapMask; + } +#endif + if ( pShader->IsSnapshotting() ) { /*^*/ // printf("\t\t[2] snapshotting...\n"); +#ifdef MAPBASE + bool hasBaseAlphaEnvmapMask = bHasEnvmap && IS_FLAG_SET( MATERIAL_VAR_BASEALPHAENVMAPMASK ); + bool hasNormalMapAlphaEnvmapMask = bHasEnvmap && IS_FLAG_SET( MATERIAL_VAR_NORMALMAPALPHAENVMAPMASK ); +#else bool hasBaseAlphaEnvmapMask = IS_FLAG_SET( MATERIAL_VAR_BASEALPHAENVMAPMASK ); bool hasNormalMapAlphaEnvmapMask = IS_FLAG_SET( MATERIAL_VAR_NORMALMAPALPHAENVMAPMASK ); +#endif if ( info.m_nVertexAlphaTest != -1 && params[info.m_nVertexAlphaTest]->GetIntValue() > 0 ) @@ -486,7 +516,9 @@ static void DrawVertexLitGeneric_DX9_Internal( CBaseVSShader *pShader, IMaterial } bool bHasEnvmap = (!bHasFlashlight || IsX360() ) && ( info.m_nEnvmap != -1 ) && params[info.m_nEnvmap]->IsTexture(); +#ifndef MAPBASE bool bHasLegacyEnvSphereMap = bHasEnvmap && IS_FLAG_SET(MATERIAL_VAR_ENVMAPSPHERE); +#endif bool bHasNormal = bVertexLitGeneric || bHasEnvmap || bHasFlashlight || bSeamlessBase || bSeamlessDetail; if ( IsPC() ) { @@ -805,7 +837,9 @@ static void DrawVertexLitGeneric_DX9_Internal( CBaseVSShader *pShader, IMaterial DECLARE_STATIC_PIXEL_SHADER( sdk_vertexlit_and_unlit_generic_ps20b ); SET_STATIC_PIXEL_SHADER_COMBO( SELFILLUM_ENVMAPMASK_ALPHA, ( hasSelfIllumInEnvMapMask && ( bHasEnvmapMask ) ) ); SET_STATIC_PIXEL_SHADER_COMBO( CUBEMAP, bHasEnvmap ); +#ifndef MAPBASE SET_STATIC_PIXEL_SHADER_COMBO( CUBEMAP_SPHERE_LEGACY, bHasLegacyEnvSphereMap ); +#endif SET_STATIC_PIXEL_SHADER_COMBO( DIFFUSELIGHTING, hasDiffuseLighting ); SET_STATIC_PIXEL_SHADER_COMBO( ENVMAPMASK, bHasEnvmapMask ); SET_STATIC_PIXEL_SHADER_COMBO( BASEALPHAENVMAPMASK, hasBaseAlphaEnvmapMask ); @@ -878,7 +912,9 @@ static void DrawVertexLitGeneric_DX9_Internal( CBaseVSShader *pShader, IMaterial DECLARE_STATIC_PIXEL_SHADER( sdk_vertexlit_and_unlit_generic_ps30 ); SET_STATIC_PIXEL_SHADER_COMBO( SELFILLUM_ENVMAPMASK_ALPHA, ( hasSelfIllumInEnvMapMask && ( bHasEnvmapMask ) ) ); SET_STATIC_PIXEL_SHADER_COMBO( CUBEMAP, bHasEnvmap ); - SET_STATIC_PIXEL_SHADER_COMBO( CUBEMAP_SPHERE_LEGACY, bHasLegacyEnvSphereMap ); +#ifndef MAPBASE + SET_STATIC_PIXEL_SHADER_COMBO( CUBEMAP_SPHERE_LEGACY, bHasLegacyEnvSphereMap ); +#endif SET_STATIC_PIXEL_SHADER_COMBO( DIFFUSELIGHTING, hasDiffuseLighting ); SET_STATIC_PIXEL_SHADER_COMBO( ENVMAPMASK, bHasEnvmapMask ); SET_STATIC_PIXEL_SHADER_COMBO( BASEALPHAENVMAPMASK, hasBaseAlphaEnvmapMask ); @@ -897,6 +933,9 @@ static void DrawVertexLitGeneric_DX9_Internal( CBaseVSShader *pShader, IMaterial SET_STATIC_PIXEL_SHADER_COMBO( FLASHLIGHTDEPTHFILTERMODE, nShadowFilterMode ); SET_STATIC_PIXEL_SHADER_COMBO( DEPTHBLEND, bDoDepthBlend ); SET_STATIC_PIXEL_SHADER_COMBO( BLENDTINTBYBASEALPHA, bBlendTintByBaseAlpha ); +#ifdef MAPBASE + SET_STATIC_PIXEL_SHADER_COMBO( ENVMAPFRESNEL, bHasEnvMapFresnel ); +#endif SET_STATIC_PIXEL_SHADER( sdk_vertexlit_and_unlit_generic_ps30 ); } #endif @@ -1076,9 +1115,26 @@ static void DrawVertexLitGeneric_DX9_Internal( CBaseVSShader *pShader, IMaterial { params[info.m_nOutlineColor]->GetVecValue( flConsts+12, 3 ); } +#ifdef MAPBASE + if ( info.m_nBaseAlphaEnvMapMaskMinMaxExp != -1 ) + { + flConsts[10] = params[ info.m_nBaseAlphaEnvMapMaskMinMaxExp ]->GetVecValue()[0]; + flConsts[11] = params[ info.m_nBaseAlphaEnvMapMaskMinMaxExp ]->GetVecValue()[1] - flConsts[10]; + } +#endif pContextData->m_SemiStaticCmdsOut.SetPixelShaderConstant( 5, flConsts, 5 ); } +#ifdef MAPBASE + else if ( info.m_nBaseAlphaEnvMapMaskMinMaxExp != -1 ) + { + float flConsts[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; + + flConsts[2] = params[ info.m_nBaseAlphaEnvMapMaskMinMaxExp ]->GetVecValue()[0]; + flConsts[3] = params[ info.m_nBaseAlphaEnvMapMaskMinMaxExp ]->GetVecValue()[1] - flConsts[2]; + pContextData->m_SemiStaticCmdsOut.SetPixelShaderConstant( 7, flConsts, 1 ); + } +#endif if ( !g_pConfig->m_bFastNoBump ) { if ( bHasBump ) @@ -1118,6 +1174,29 @@ static void DrawVertexLitGeneric_DX9_Internal( CBaseVSShader *pShader, IMaterial pContextData->m_SemiStaticCmdsOut.BindTexture( pShader, SHADER_SAMPLER4, info.m_nEnvmapMask, info.m_nEnvmapMaskFrame ); } +#ifdef MAPBASE + if ( bHasEnvMapFresnel ) + { + float flConsts[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; + params[ info.m_nEnvMapFresnelMinMaxExp ]->GetVecValue( flConsts, 3 ); + flConsts[1] -= flConsts[0]; // convert max fresnel into scale factor + + if ( info.m_nBaseAlphaEnvMapMaskMinMaxExp != -1 ) + { + flConsts[3] = params[ info.m_nBaseAlphaEnvMapMaskMinMaxExp ]->GetVecValue()[2]; // basealphaenvmapmask exponent in w + } + + pContextData->m_SemiStaticCmdsOut.SetPixelShaderConstant( 14, flConsts, 1 ); + } + else if ( info.m_nBaseAlphaEnvMapMaskMinMaxExp != -1 ) + { + // still need to set exponent for basealphaenvmapmask + float flConsts[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; + flConsts[3] = params[ info.m_nBaseAlphaEnvMapMaskMinMaxExp ]->GetVecValue()[2]; // basealphaenvmapmask exponent in w + pContextData->m_SemiStaticCmdsOut.SetPixelShaderConstant( 14, flConsts, 1 ); + } +#endif + if ( bHasSelfIllumFresnel && (!bHasFlashlight || IsX360() ) ) { float vConstScaleBiasExp[4] = { 1.0f, 0.0f, 1.0f, 0.0f }; @@ -1436,14 +1515,29 @@ static void DrawVertexLitGeneric_DX9_Internal( CBaseVSShader *pShader, IMaterial #endif } - if ( ( info.m_nHDRColorScale != -1 ) && pShader->IsHDREnabled() ) +#ifdef MAPBASE + // material can choose to support per-instance modulation via $allowdiffusemodulation + bool bAllowDiffuseModulation = (info.m_nAllowDiffuseModulation == -1) ? true : (params[info.m_nAllowDiffuseModulation]->GetIntValue() != 0); + + if (bAllowDiffuseModulation) +#endif { - pShader->SetModulationPixelShaderDynamicState_LinearColorSpace_LinearScale( 1, params[info.m_nHDRColorScale]->GetFloatValue() ); + if ( ( info.m_nHDRColorScale != -1 ) && pShader->IsHDREnabled() ) + { + pShader->SetModulationPixelShaderDynamicState_LinearColorSpace_LinearScale( 1, params[info.m_nHDRColorScale]->GetFloatValue() ); + } + else + { + pShader->SetModulationPixelShaderDynamicState_LinearColorSpace( 1 ); + } } +#ifdef MAPBASE else { - pShader->SetModulationPixelShaderDynamicState_LinearColorSpace( 1 ); + float color[4] = { 1.0, 1.0, 1.0, 1.0 }; + pShaderAPI->SetPixelShaderConstant( 1, color ); } +#endif float eyePos[4]; pShaderAPI->GetWorldSpaceCameraPosition( eyePos ); diff --git a/sp/src/materialsystem/stdshaders/vertexlitgeneric_dx9_helper.h b/sp/src/materialsystem/stdshaders/vertexlitgeneric_dx9_helper.h index 94a16ebc..5df1ab93 100644 --- a/sp/src/materialsystem/stdshaders/vertexlitgeneric_dx9_helper.h +++ b/sp/src/materialsystem/stdshaders/vertexlitgeneric_dx9_helper.h @@ -132,7 +132,16 @@ struct VertexLitGeneric_DX9_Vars_t int m_nTintReplacesBaseColor; #ifdef MAPBASE - // Parameter ported from Alien Swarm. See bPhongHalfLambert in DrawSkin_DX9_Internal() for more info. + // Parameters ported from Alien Swarm SDK shaders. + + // Utility param for disabling tinting on certain materials. + int m_nAllowDiffuseModulation; + + // $envmapfresnel on non-phong materials. + int m_nEnvMapFresnelMinMaxExp; + int m_nBaseAlphaEnvMapMaskMinMaxExp; + + // Disables $halflambert on phong materials. See bPhongHalfLambert in DrawSkin_DX9_Internal() for more info. int m_nPhongDisableHalfLambert; #endif From e0821e404fd2abcb3342aedcd8979927404f5f17 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Tue, 26 Apr 2022 13:53:04 -0500 Subject: [PATCH 346/378] Disabled NPC door activities by default and allowed mappers to enable them at their own discretion --- sp/src/game/server/BasePropDoor.h | 2 + sp/src/game/server/props.cpp | 65 ++++++++++++++++++++++--------- 2 files changed, 49 insertions(+), 18 deletions(-) diff --git a/sp/src/game/server/BasePropDoor.h b/sp/src/game/server/BasePropDoor.h index 2557bec3..7e8400d2 100644 --- a/sp/src/game/server/BasePropDoor.h +++ b/sp/src/game/server/BasePropDoor.h @@ -77,6 +77,8 @@ public: #ifdef MAPBASE virtual bool PassesDoorFilter(CBaseEntity *pEntity) { return true; } + + virtual bool KeyValue( const char *szKeyName, const char *szValue ); #endif protected: diff --git a/sp/src/game/server/props.cpp b/sp/src/game/server/props.cpp index 56428e73..4aed7c57 100644 --- a/sp/src/game/server/props.cpp +++ b/sp/src/game/server/props.cpp @@ -4290,6 +4290,32 @@ void CBasePropDoor::Precache(void) } +#ifdef MAPBASE +//----------------------------------------------------------------------------- +// Purpose: Handles keyvalues from the BSP. Called before spawning. +//----------------------------------------------------------------------------- +bool CBasePropDoor::KeyValue( const char *szKeyName, const char *szValue ) +{ + if ( FStrEq(szKeyName, "openfrontactivityoverride") ) + { + m_eNPCOpenFrontActivity = (Activity)CAI_BaseNPC::GetActivityID( szValue ); + if (m_eNPCOpenFrontActivity == ACT_INVALID) + m_eNPCOpenFrontActivity = ActivityList_RegisterPrivateActivity( szValue ); + } + else if ( FStrEq(szKeyName, "openbackactivityoverride") ) + { + m_eNPCOpenBackActivity = (Activity)CAI_BaseNPC::GetActivityID( szValue ); + if (m_eNPCOpenBackActivity == ACT_INVALID) + m_eNPCOpenBackActivity = ActivityList_RegisterPrivateActivity( szValue ); + } + else + return BaseClass::KeyValue( szKeyName, szValue ); + + return true; +} +#endif + + //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- @@ -4418,29 +4444,32 @@ void CBasePropDoor::CalcDoorSounds() strSoundUnlocked = AllocPooledString( pkvHardwareData->GetString( "unlocked" ) ); #ifdef MAPBASE - if (m_eNPCOpenFrontActivity == ACT_INVALID) + if (ai_door_enable_acts.GetBool()) { - const char *pszActivity = pkvHardwareData->GetString( "activity_front" ); - if (pszActivity[0] != '\0') + if (m_eNPCOpenFrontActivity == ACT_INVALID) { - m_eNPCOpenFrontActivity = (Activity)CAI_BaseNPC::GetActivityID( pszActivity ); - if (m_eNPCOpenFrontActivity == ACT_INVALID) - m_eNPCOpenFrontActivity = ActivityList_RegisterPrivateActivity( pszActivity ); + const char *pszActivity = pkvHardwareData->GetString( "activity_front" ); + if (pszActivity[0] != '\0') + { + m_eNPCOpenFrontActivity = (Activity)CAI_BaseNPC::GetActivityID( pszActivity ); + if (m_eNPCOpenFrontActivity == ACT_INVALID) + m_eNPCOpenFrontActivity = ActivityList_RegisterPrivateActivity( pszActivity ); + } } - } - if (m_eNPCOpenBackActivity == ACT_INVALID) - { - const char *pszActivity = pkvHardwareData->GetString( "activity_back" ); - if (pszActivity[0] != '\0') + if (m_eNPCOpenBackActivity == ACT_INVALID) { - m_eNPCOpenBackActivity = (Activity)CAI_BaseNPC::GetActivityID( pszActivity ); - if (m_eNPCOpenBackActivity == ACT_INVALID) - m_eNPCOpenBackActivity = ActivityList_RegisterPrivateActivity( pszActivity ); + const char *pszActivity = pkvHardwareData->GetString( "activity_back" ); + if (pszActivity[0] != '\0') + { + m_eNPCOpenBackActivity = (Activity)CAI_BaseNPC::GetActivityID( pszActivity ); + if (m_eNPCOpenBackActivity == ACT_INVALID) + m_eNPCOpenBackActivity = ActivityList_RegisterPrivateActivity( pszActivity ); + } } } if (m_flNPCOpenDistance == -1) - m_flNPCOpenDistance = pkvHardwareData->GetFloat( "npc_distance", 32.0 ); + m_flNPCOpenDistance = pkvHardwareData->GetFloat( "npc_distance", ai_door_enable_acts.GetBool() ? 32.0 : 64.0 ); #endif } @@ -6043,7 +6072,7 @@ void CPropDoorRotating::DoorResume( void ) } #ifdef MAPBASE -ConVar ai_door_enable_acts( "ai_door_enable_acts", "1", FCVAR_NONE, "Enables the new door-opening activities." ); +ConVar ai_door_enable_acts( "ai_door_enable_acts", "0", FCVAR_NONE, "Enables the new door-opening activities by default. Override keyvalues will override this cvar." ); ConVar ai_door_open_dist_override( "ai_door_open_dist_override", "-1", FCVAR_NONE, "Overrides the distance from a door a NPC has to navigate to in order to open a door." ); #endif @@ -6080,7 +6109,7 @@ void CPropDoorRotating::GetNPCOpenData(CAI_BaseNPC *pNPC, opendata_t &opendata) opendata.vecStandPos += vecForward * flPosOffset; opendata.vecFaceDir = -vecForward; #ifdef MAPBASE - opendata.eActivity = !ai_door_enable_acts.GetBool() ? ACT_INVALID : GetNPCOpenFrontActivity(); + opendata.eActivity = GetNPCOpenFrontActivity(); #endif } else @@ -6089,7 +6118,7 @@ void CPropDoorRotating::GetNPCOpenData(CAI_BaseNPC *pNPC, opendata_t &opendata) opendata.vecStandPos -= vecForward * flPosOffset; opendata.vecFaceDir = vecForward; #ifdef MAPBASE - opendata.eActivity = !ai_door_enable_acts.GetBool() ? ACT_INVALID : GetNPCOpenBackActivity(); + opendata.eActivity = GetNPCOpenBackActivity(); #endif } From e7c61320a54ef324e95d9300df021647aaf82a48 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Wed, 27 Apr 2022 00:09:34 -0500 Subject: [PATCH 347/378] Fixed misplaced cvars --- sp/src/game/server/props.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sp/src/game/server/props.cpp b/sp/src/game/server/props.cpp index 4aed7c57..c643dd68 100644 --- a/sp/src/game/server/props.cpp +++ b/sp/src/game/server/props.cpp @@ -4139,6 +4139,11 @@ enum void PlayLockSounds(CBaseEntity *pEdict, locksound_t *pls, int flocked, int fbutton); +#ifdef MAPBASE +ConVar ai_door_enable_acts( "ai_door_enable_acts", "0", FCVAR_NONE, "Enables the new door-opening activities by default. Override keyvalues will override this cvar." ); +ConVar ai_door_open_dist_override( "ai_door_open_dist_override", "-1", FCVAR_NONE, "Overrides the distance from a door a NPC has to navigate to in order to open a door." ); +#endif + BEGIN_DATADESC_NO_BASE(locksound_t) DEFINE_FIELD( sLockedSound, FIELD_STRING), @@ -6071,11 +6076,6 @@ void CPropDoorRotating::DoorResume( void ) AngularMove( m_angGoal, m_flSpeed ); } -#ifdef MAPBASE -ConVar ai_door_enable_acts( "ai_door_enable_acts", "0", FCVAR_NONE, "Enables the new door-opening activities by default. Override keyvalues will override this cvar." ); -ConVar ai_door_open_dist_override( "ai_door_open_dist_override", "-1", FCVAR_NONE, "Overrides the distance from a door a NPC has to navigate to in order to open a door." ); -#endif - //----------------------------------------------------------------------------- // Purpose: // Input : vecMoveDir - From ad4adf90ca438c4b1adbc53526aa7f88881c31b2 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Wed, 4 May 2022 20:50:44 -0500 Subject: [PATCH 348/378] Fixed a typo --- sp/src/game/server/hl2/weapon_ar1.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sp/src/game/server/hl2/weapon_ar1.cpp b/sp/src/game/server/hl2/weapon_ar1.cpp index c6e49239..0d9c0240 100644 --- a/sp/src/game/server/hl2/weapon_ar1.cpp +++ b/sp/src/game/server/hl2/weapon_ar1.cpp @@ -98,7 +98,7 @@ public: } } -#ifdef MAPBSAE +#ifdef MAPBASE virtual acttable_t *GetBackupActivityList() { return GetAR2Acttable(); } virtual int GetBackupActivityListCount() { return GetAR2ActtableCount(); } #endif From 39ec4ee704bf683e58e499e9dbcc1cbe95943078 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Wed, 4 May 2022 20:52:21 -0500 Subject: [PATCH 349/378] Fixed zombie serverside ragdoll gibs crashing when one of the models isn't valid --- sp/src/game/server/hl2/npc_BaseZombie.cpp | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/sp/src/game/server/hl2/npc_BaseZombie.cpp b/sp/src/game/server/hl2/npc_BaseZombie.cpp index 5d13c5e6..fee51dd7 100644 --- a/sp/src/game/server/hl2/npc_BaseZombie.cpp +++ b/sp/src/game/server/hl2/npc_BaseZombie.cpp @@ -2354,11 +2354,14 @@ void CNPC_BaseZombie::BecomeTorso( const Vector &vecTorsoForce, const Vector &ve if ( m_bForceServerRagdoll ) { pGib = CreateServerRagdollSubmodel( this, GetLegsModel(), GetAbsOrigin() - Vector(0, 0, 40), GetAbsAngles(), COLLISION_GROUP_INTERACTIVE_DEBRIS ); - pGib->VPhysicsGetObject()->AddVelocity( &vecLegsForce, NULL ); - - if (flFadeTime > 0.0) + if (pGib && pGib->VPhysicsGetObject()) { - pGib->SUB_StartFadeOut( flFadeTime, false ); + pGib->VPhysicsGetObject()->AddVelocity( &vecLegsForce, NULL ); + + if (flFadeTime > 0.0) + { + pGib->SUB_StartFadeOut( flFadeTime, false ); + } } } else @@ -2506,11 +2509,14 @@ void CNPC_BaseZombie::ReleaseHeadcrab( const Vector &vecOrigin, const Vector &ve if ( m_bForceServerRagdoll ) { pGib = CreateServerRagdollSubmodel( this, GetHeadcrabModel(), vecOrigin, GetLocalAngles(), COLLISION_GROUP_INTERACTIVE_DEBRIS ); - pGib->VPhysicsGetObject()->AddVelocity(&vecVelocity, NULL); - if (ShouldIgniteZombieGib()) - static_cast(pGib)->Ignite( random->RandomFloat( 8.0, 12.0 ), false ); + if (pGib && pGib->VPhysicsGetObject()) + { + pGib->VPhysicsGetObject()->AddVelocity(&vecVelocity, NULL); + if (ShouldIgniteZombieGib()) + static_cast(pGib)->Ignite( random->RandomFloat( 8.0, 12.0 ), false ); - pGib->SUB_StartFadeOut( 15, false ); + pGib->SUB_StartFadeOut( 15, false ); + } } else pGib = CreateRagGib( GetHeadcrabModel(), vecOrigin, GetLocalAngles(), vecVelocity, 15, ShouldIgniteZombieGib() ); From dc1eb02322b8c4739f845881d0915009917b0a83 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Wed, 4 May 2022 20:59:18 -0500 Subject: [PATCH 350/378] Clarified clientside SequenceLoops VScript function description --- sp/src/game/client/c_baseanimating.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sp/src/game/client/c_baseanimating.cpp b/sp/src/game/client/c_baseanimating.cpp index 1c867472..7bd1c737 100644 --- a/sp/src/game/client/c_baseanimating.cpp +++ b/sp/src/game/client/c_baseanimating.cpp @@ -332,7 +332,7 @@ BEGIN_ENT_SCRIPTDESC( C_BaseAnimating, C_BaseEntity, "Animating models client-si DEFINE_SCRIPTFUNC( GetSequence, "Gets the current sequence" ) DEFINE_SCRIPTFUNC( SetSequence, "Sets the current sequence" ) - DEFINE_SCRIPTFUNC( SequenceLoops, "Loops the current sequence" ) + DEFINE_SCRIPTFUNC( SequenceLoops, "Does the current sequence loop?" ) DEFINE_SCRIPTFUNC( LookupSequence, "Gets the index of the specified sequence name" ) DEFINE_SCRIPTFUNC( LookupActivity, "Gets the ID of the specified activity name" ) DEFINE_SCRIPTFUNC( GetSequenceName, "Gets the name of the specified sequence index" ) From fca05c8be92ae0b68fb63ea46f24662e6b6af91a Mon Sep 17 00:00:00 2001 From: Blixibon Date: Wed, 4 May 2022 21:00:01 -0500 Subject: [PATCH 351/378] Updated README --- README | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README b/README index 924b32fe..00242852 100644 --- a/README +++ b/README @@ -127,6 +127,7 @@ Direct contributions: =-- https://github.com/mapbase-source/source-sdk-2013/pull/167 (Security fixes) =-- https://github.com/mapbase-source/source-sdk-2013/pull/168 (Squirrel update) =-- https://github.com/mapbase-source/source-sdk-2013/pull/171 (VScript documentation sorting) +=-- https://github.com/mapbase-source/source-sdk-2013/pull/173 (VScript fixes and optimizations) == Contributions from z33ky: =-- https://github.com/mapbase-source/source-sdk-2013/pull/21 (Various GCC/Linux compilation fixes) @@ -141,6 +142,12 @@ Direct contributions: =-- https://github.com/mapbase-source/source-sdk-2013/pull/162 (VS2019 exception specification fix) =-- https://github.com/mapbase-source/source-sdk-2013/pull/170 (HL2 non-Episodic build fix) +== Contributions from Petercov: +=-- https://github.com/mapbase-source/source-sdk-2013/pull/182 (NPCs load dynamic interactions from all animation MDLs) +=-- https://github.com/mapbase-source/source-sdk-2013/pull/184 (Projected texture horizontal FOV shadow fix) +=-- https://github.com/mapbase-source/source-sdk-2013/pull/185 (Fix enemyfinders becoming visible when they wake) +=-- https://github.com/mapbase-source/source-sdk-2013/pull/186 (Fix for brightly glowing teeth) + //--------------------------------------------------------------------------------------------------------------------------------------------------- Other sources: From b6b0583550d1e431fd6eecd88ad6d11e39941e62 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Fri, 15 Jul 2022 23:27:19 -0500 Subject: [PATCH 352/378] Added precaching + logo colors to env_credits --- sp/src/game/client/hl2/hud_credits.cpp | 84 +++++++++++++++++++++++++- sp/src/game/server/EnvMessage.cpp | 32 ++++++++++ 2 files changed, 115 insertions(+), 1 deletion(-) diff --git a/sp/src/game/client/hl2/hud_credits.cpp b/sp/src/game/client/hl2/hud_credits.cpp index 6520e6b4..fb4354f5 100644 --- a/sp/src/game/client/hl2/hud_credits.cpp +++ b/sp/src/game/client/hl2/hud_credits.cpp @@ -57,6 +57,9 @@ enum #define CREDITS_LOGO 1 #define CREDITS_INTRO 2 #define CREDITS_OUTRO 3 +#ifdef MAPBASE +#define CREDITS_PRECACHE 4 +#endif bool g_bRollingCredits = false; @@ -112,6 +115,10 @@ private: void PrepareOutroCredits( void ); void PrepareIntroCredits( void ); +#ifdef MAPBASE + void PrecacheCredits(); +#endif + float FadeBlend( float fadein, float fadeout, float hold, float localTime ); void PrepareLine( vgui::HFont hFont, char const *pchLine ); @@ -162,6 +169,9 @@ private: char m_szCreditsFile[MAX_PATH]; char m_szLogoFont[64]; + char m_szLogo2Font[64]; + Color m_cLogoColor; + Color m_cLogo2Color; #endif }; @@ -309,6 +319,10 @@ void CHudCredits::ReadParams( KeyValues *pKeyValue ) #ifdef MAPBASE Q_strncpy( m_szLogoFont, pKeyValue->GetString( "logofont", "" ), sizeof( m_szLogoFont ) ); + Q_strncpy( m_szLogo2Font, pKeyValue->GetString( "logo2font", "" ), sizeof( m_szLogo2Font ) ); + + m_cLogoColor = pKeyValue->GetColor( "logocolor" ); + m_cLogo2Color = pKeyValue->GetColor( "logo2color" ); #endif } @@ -650,6 +664,11 @@ void CHudCredits::DrawLogo( void ) Color cColor = m_TextColor; cColor[3] = m_Alpha; + +#ifdef MAPBASE + if (m_cLogoColor.a() > 0) + cColor = m_cLogoColor; +#endif surface()->DrawSetTextFont( m_hTFont ); surface()->DrawSetTextColor( cColor[0], cColor[1], cColor[2], cColor[3] ); @@ -664,6 +683,19 @@ void CHudCredits::DrawLogo( void ) if ( Q_strlen( m_szLogo2 ) > 0 ) { +#ifdef MAPBASE + if (m_szLogo2Font[0] != '\0') + { + m_hTFont = vgui::scheme()->GetIScheme( scheme )->GetFont( m_szLogo2Font ); + iFontTall = surface()->GetFontTall( m_hTFont ); + surface()->DrawSetTextFont( m_hTFont ); + } + if (m_cLogo2Color.a() > 0) + { + surface()->DrawSetTextColor( m_cLogo2Color[0], m_cLogo2Color[1], m_cLogo2Color[2], m_cLogo2Color[3] ); + } +#endif + g_pVGuiLocalize->ConvertANSIToUnicode( m_szLogo2, unicode, sizeof( unicode ) ); iStringWidth = GetStringPixelWidth( unicode, m_hTFont ); @@ -946,7 +978,7 @@ void CHudCredits::PrepareOutroCredits( void ) iHeight += ((float)iFontTall * pCredit->flImageScale * ((float)GetTall() / 900.0f)) + m_flSeparation; - Msg( "'%s' is image type (image scale is %f)\n", pCredit->szCreditName, pCredit->flImageScale ); + //Msg( "'%s' is image type (image scale is %f)\n", pCredit->szCreditName, pCredit->flImageScale ); } else { @@ -1070,6 +1102,49 @@ void CHudCredits::PrepareIntroCredits( void ) } #ifdef MAPBASE +void CHudCredits::PrecacheCredits() +{ + PrepareCredits( "OutroCreditsNames" ); + + if ( m_CreditsList.Count() == 0 ) + return; + + for ( int i = 0; i < m_CreditsList.Count(); i++ ) + { + creditname_t *pCredit = &m_CreditsList[i]; + + if ( pCredit == NULL ) + continue; + + if (pCredit->szFontName[0] == '$') + { + if (V_strncmp( pCredit->szFontName + 1, "Image", 5 ) == 0) + { + if (m_bAllowColumns && V_strstr( pCredit->szCreditName, "\t" )) + { + CUtlStringList outStrings; + V_SplitString( pCredit->szCreditName, "\t", outStrings ); + FOR_EACH_VEC( outStrings, i ) + { + GetOrAllocateImageID( outStrings[i] ); + } + outStrings.PurgeAndDeleteElements(); + } + else + { + GetOrAllocateImageID( pCredit->szCreditName ); + } + } + else + { + //Msg( "'%s' is not an image type\n", pCredit->szFontName + 1 ); + } + } + } + + m_CreditsList.RemoveAll(); +} + int CHudCredits::GetOrAllocateImageID( const char *szFileName ) { int iIndex = m_ImageDict.Find( szFileName ); @@ -1112,6 +1187,13 @@ void CHudCredits::MsgFunc_CreditsMsg( bf_read &msg ) PrepareOutroCredits(); break; } +#ifdef MAPBASE + case CREDITS_PRECACHE: + { + PrecacheCredits(); + break; + } +#endif } } diff --git a/sp/src/game/server/EnvMessage.cpp b/sp/src/game/server/EnvMessage.cpp index 6de81783..7725b67d 100644 --- a/sp/src/game/server/EnvMessage.cpp +++ b/sp/src/game/server/EnvMessage.cpp @@ -154,6 +154,9 @@ public: DECLARE_DATADESC(); void Spawn( void ); +#ifdef MAPBASE + void PrecacheCreditsThink(); +#endif void InputRollCredits( inputdata_t &inputdata ); void InputRollOutroCredits( inputdata_t &inputdata ); void InputShowLogo( inputdata_t &inputdata ); @@ -186,6 +189,8 @@ BEGIN_DATADESC( CCredits ) #ifdef MAPBASE DEFINE_KEYFIELD( m_iszCreditsFile, FIELD_STRING, "CreditsFile" ), + + DEFINE_THINKFUNC( PrecacheCreditsThink ), #endif DEFINE_FIELD( m_bRolledOutroCredits, FIELD_BOOLEAN ), @@ -196,8 +201,35 @@ void CCredits::Spawn( void ) { SetSolid( SOLID_NONE ); SetMoveType( MOVETYPE_NONE ); + +#ifdef MAPBASE + // Ensures the player has time to spawn + SetContextThink( &CCredits::PrecacheCreditsThink, gpGlobals->curtime + 0.5f, "PrecacheCreditsContext" ); +#endif } +#ifdef MAPBASE +void CCredits::PrecacheCreditsThink() +{ + CBasePlayer *pPlayer = UTIL_GetLocalPlayer(); + if (!pPlayer) + { + Warning( "%s: No player\n", GetDebugName() ); + return; + } + + CSingleUserRecipientFilter user( pPlayer ); + user.MakeReliable(); + + UserMessageBegin( user, "CreditsMsg" ); + WRITE_BYTE( 4 ); + WRITE_STRING( STRING(m_iszCreditsFile) ); + MessageEnd(); + + SetContextThink( NULL, TICK_NEVER_THINK, "PrecacheCreditsContext" ); +} +#endif + static void CreditsDone_f( void ) { CCredits *pCredits = (CCredits*)gEntList.FindEntityByClassname( NULL, "env_credits" ); From f965afde16ca4adaf317742f89651cffba389fb4 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Fri, 15 Jul 2022 23:33:23 -0500 Subject: [PATCH 353/378] Added support for directory-specific Mapbase manifests when using the "ADDON" path ID (disabled by default) --- sp/src/game/shared/mapbase/mapbase_shared.cpp | 53 +++++++++++++++++-- 1 file changed, 49 insertions(+), 4 deletions(-) diff --git a/sp/src/game/shared/mapbase/mapbase_shared.cpp b/sp/src/game/shared/mapbase/mapbase_shared.cpp index fd4825de..47e83ada 100644 --- a/sp/src/game/shared/mapbase/mapbase_shared.cpp +++ b/sp/src/game/shared/mapbase/mapbase_shared.cpp @@ -35,6 +35,7 @@ #include "tier0/memdbgon.h" #define GENERIC_MANIFEST_FILE "scripts/mapbase_default_manifest.txt" +#define GENERIC_MANIFEST_FILE_ADDON "scripts/mapbase_default_manifest_addon.txt" #ifdef CLIENT_DLL #define AUTOLOADED_MANIFEST_FILE VarArgs("maps/%s_manifest.txt", g_MapName) @@ -52,6 +53,8 @@ ConVar mapbase_load_default_manifest("mapbase_load_default_manifest", "1", FCVAR // This constant should change with each Mapbase update ConVar mapbase_version( "mapbase_version", MAPBASE_VERSION, FCVAR_NONE, "The version of Mapbase currently being used in this mod's server.dll" ); +ConVar mapbase_load_addon_manifest( "mapbase_load_addon_manifest", "0", FCVAR_NONE, "Allows manifests from \"addon\" path IDs to be loaded." ); + ConVar mapbase_flush_talker("mapbase_flush_talker", "1", FCVAR_NONE, "Normally, when a map with custom talker files is unloaded, the response system resets to rid itself of the custom file(s). Turn this convar off to prevent that from happening."); extern void MapbaseGameLog_Init(); @@ -67,6 +70,8 @@ static bool g_bMapContainsCustomTalker; // This constant should change with each Mapbase update ConVar mapbase_version_client( "mapbase_version_client", MAPBASE_VERSION, FCVAR_NONE, "The version of Mapbase currently being used in this mod's client.dll" ); +ConVar mapbase_load_addon_manifest( "mapbase_load_addon_manifest_client", "0", FCVAR_NONE, "Allows manifests from \"addon\" path IDs to be loaded on the client." ); + // This is from the vgui_controls library extern vgui::HScheme g_iCustomClientSchemeOverride; @@ -110,6 +115,9 @@ enum //MANIFEST_SENTENCES, MANIFEST_ACTBUSY, #endif +#ifdef MAPBASE_VSCRIPT + MANIFEST_VSCRIPT, +#endif // Must always be kept below MANIFEST_NUM_TYPES, @@ -147,6 +155,9 @@ static const ManifestType_t gm_szManifestFileStrings[MANIFEST_NUM_TYPES] = { //{ "sentences", "mapbase_load_sentences", "Should we load map-specific sentences? e.g. \"maps/_sentences.txt\"" }, { "actbusy", "mapbase_load_actbusy", "Should we load map-specific actbusy files? e.g. \"maps/_actbusy.txt\"" }, #endif +#ifdef MAPBASE_VSCRIPT + { "vscript", "mapbase_load_vscript", "Should we load map-specific VScript map spawn files? e.g. \"maps/_mapspawn.nut\"" }, +#endif }; //----------------------------------------------------------------------------- @@ -265,6 +276,37 @@ public: ParseGenericManifest(); } + // Load addon manifests if we should + if (mapbase_load_addon_manifest.GetBool()) + { + char searchPaths[4096]; + filesystem->GetSearchPath( "ADDON", true, searchPaths, sizeof( searchPaths ) ); + + for ( char *path = strtok( searchPaths, ";" ); path; path = strtok( NULL, ";" ) ) + { + char pathName[MAX_PATH]; + V_StripTrailingSlash( path ); + V_FileBase( path, pathName, sizeof( pathName ) ); + + KeyValues *pKV = new KeyValues( "DefaultAddonManifest" ); + + char manifestName[MAX_PATH]; + V_snprintf( manifestName, sizeof( manifestName ), "%s_mapbase_manifest.txt", pathName ); + if (filesystem->FileExists( manifestName, "ADDON" )) + { + if (pKV->LoadFromFile( filesystem, manifestName )) + AddManifestFile( pKV, pathName, false ); + } + else + { + if (pKV->LoadFromFile( filesystem, GENERIC_MANIFEST_FILE_ADDON )) + AddManifestFile( pKV, pathName, true ); + } + + pKV->deleteThis(); + } + } + #ifdef GAME_DLL MapbaseGameLog_Init(); #endif @@ -405,7 +447,7 @@ public: KeyValues *pKV = new KeyValues("DefaultManifest"); pKV->LoadFromFile(filesystem, GENERIC_MANIFEST_FILE); - AddManifestFile(pKV/*, true*/); + AddManifestFile(pKV, g_MapName/*, true*/); pKV->deleteThis(); } @@ -422,7 +464,7 @@ public: CGMsg( 1, CON_GROUP_MAPBASE_MISC, "===== Mapbase Manifest: Loading manifest file %s =====\n", file ); - AddManifestFile(pKV, false); + AddManifestFile(pKV, g_MapName, false); CGMsg( 1, CON_GROUP_MAPBASE_MISC, "==============================================================================\n" ); @@ -461,12 +503,15 @@ public: //case MANIFEST_SOUNDSCAPES: { g_SoundscapeSystem.AddSoundscapeFile(value); } break; //case MANIFEST_SENTENCES: { engine->PrecacheSentenceFile(value); } break; case MANIFEST_ACTBUSY: { ParseCustomActbusyFile(value); } break; +#endif +#ifdef MAPBASE_VSCRIPT + case MANIFEST_VSCRIPT: { VScriptRunScript(value, false); } break; #endif } } // This doesn't call deleteThis()! - void AddManifestFile(KeyValues *pKV, bool bDontWarn = false) + void AddManifestFile(KeyValues *pKV, const char *pszMapName, bool bDontWarn = false) { char value[MAX_PATH]; const char *name; @@ -485,7 +530,7 @@ public: { if (FStrEq( outStrings[i], "mapname" )) { - Q_strncat( value, g_MapName, sizeof( value ) ); + Q_strncat( value, pszMapName, sizeof( value ) ); } else if (FStrEq( outStrings[i], "language" )) { From ebf24e98e3c1e35746c193378f03c4c308ffb566 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Fri, 15 Jul 2022 23:33:51 -0500 Subject: [PATCH 354/378] Fixed VS2013 compile error --- sp/src/game/server/player.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sp/src/game/server/player.cpp b/sp/src/game/server/player.cpp index 6092dcd8..c53cb6ad 100644 --- a/sp/src/game/server/player.cpp +++ b/sp/src/game/server/player.cpp @@ -7856,7 +7856,7 @@ Activity CBasePlayer::Weapon_TranslateActivity( Activity baseAct, bool *pRequire if ( GetModelPtr() && (!GetModelPtr()->HaveSequenceForActivity(weaponTranslation) || baseAct == weaponTranslation) ) { // This is used so players can fall back to backup activities in the same way NPCs in Mapbase can - Activity backupActivity = Weapon_BackupActivity(baseAct, pRequired); + Activity backupActivity = Weapon_BackupActivity(baseAct, pRequired ? *pRequired : false); if ( baseAct != backupActivity && GetModelPtr()->HaveSequenceForActivity(backupActivity) ) return backupActivity; From 5536021e4f61b8e94056fa209a68df9611243fba Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sat, 16 Jul 2022 00:04:46 -0500 Subject: [PATCH 355/378] Added SetSpeechTarget() for citizen heal/ammo concepts --- sp/src/game/server/hl2/npc_citizen17.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sp/src/game/server/hl2/npc_citizen17.cpp b/sp/src/game/server/hl2/npc_citizen17.cpp index 42822d2f..be80179a 100644 --- a/sp/src/game/server/hl2/npc_citizen17.cpp +++ b/sp/src/game/server/hl2/npc_citizen17.cpp @@ -1800,10 +1800,16 @@ void CNPC_Citizen::StartTask( const Task_t *pTask ) break; } +#ifdef MAPBASE + SetSpeechTarget( GetTarget() ); +#endif Speak( TLK_HEAL ); } else if ( IsAmmoResupplier() ) { +#ifdef MAPBASE + SetSpeechTarget( GetTarget() ); +#endif Speak( TLK_GIVEAMMO ); } SetIdealActivity( (Activity)ACT_CIT_HEAL ); From 0615b367ca68facb57d2ce57b3ee8b8f13c81518 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sat, 16 Jul 2022 00:05:28 -0500 Subject: [PATCH 356/378] Two misc. fixes --- sp/src/game/server/hl2/hl2_player.cpp | 4 ++++ sp/src/game/server/hl2/weapon_crossbow.cpp | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/sp/src/game/server/hl2/hl2_player.cpp b/sp/src/game/server/hl2/hl2_player.cpp index d44849e7..3fa00df0 100644 --- a/sp/src/game/server/hl2/hl2_player.cpp +++ b/sp/src/game/server/hl2/hl2_player.cpp @@ -1263,6 +1263,10 @@ Class_T CHL2_Player::Classify ( void ) if(IsInAVehicle()) { IServerVehicle *pVehicle = GetVehicle(); +#ifdef MAPBASE + if (!pVehicle) + return CLASS_PLAYER; +#endif return pVehicle->ClassifyPassenger( this, CLASS_PLAYER ); } else diff --git a/sp/src/game/server/hl2/weapon_crossbow.cpp b/sp/src/game/server/hl2/weapon_crossbow.cpp index 8a0f306b..b55fa441 100644 --- a/sp/src/game/server/hl2/weapon_crossbow.cpp +++ b/sp/src/game/server/hl2/weapon_crossbow.cpp @@ -1003,7 +1003,7 @@ void CWeaponCrossbow::FireBolt( void ) inline void CWeaponCrossbow::SetBolt( int iSetting ) { int iBody = FindBodygroupByName( "bolt" ); - if (iBody != -1 || (GetOwner() && GetOwner()->IsPlayer())) // HACKHACK: Player models check the viewmodel instead of the worldmodel, so we have to do this manually + if (iBody != -1 /*|| (GetOwner() && GetOwner()->IsPlayer())*/) // TODO: Player models check the viewmodel instead of the worldmodel, but setting the bodygroup regardless can cause a crash, so we need a better solution SetBodygroup( iBody, iSetting ); else m_nSkin = iSetting; From fe518c9859c5680165e69ade1e58831737e80744 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sat, 16 Jul 2022 12:03:56 -0500 Subject: [PATCH 357/378] Fixed an oversight in CAI_BaseNPC::TranslateActivity --- sp/src/game/server/ai_basenpc.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sp/src/game/server/ai_basenpc.cpp b/sp/src/game/server/ai_basenpc.cpp index f1f72307..6f8b7bcd 100644 --- a/sp/src/game/server/ai_basenpc.cpp +++ b/sp/src/game/server/ai_basenpc.cpp @@ -6827,7 +6827,11 @@ Activity CAI_BaseNPC::TranslateActivity( Activity idealActivity, Activity *pIdea return baseTranslation; if ( idealWeaponActivity != baseTranslation && HaveSequenceForActivity( idealWeaponActivity ) ) +#ifdef MAPBASE + return idealWeaponActivity; +#else return idealActivity; +#endif if ( idealActivity != idealWeaponActivity && HaveSequenceForActivity( idealActivity ) ) return idealActivity; From a4657d0cf1ead6d395bbf08cace125914486a3f2 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sat, 16 Jul 2022 13:16:45 -0500 Subject: [PATCH 358/378] Fixed a crash involving player +USE anims --- sp/src/game/server/hl2/hl2_player.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sp/src/game/server/hl2/hl2_player.cpp b/sp/src/game/server/hl2/hl2_player.cpp index 3fa00df0..6720ff10 100644 --- a/sp/src/game/server/hl2/hl2_player.cpp +++ b/sp/src/game/server/hl2/hl2_player.cpp @@ -1397,7 +1397,7 @@ Activity CHL2_Player::Weapon_TranslateActivity( Activity baseAct, bool *pRequire { CBaseEntity* pHeldEnt = GetPlayerHeldEntity( this ); float flMass = pHeldEnt ? - PlayerPickupGetHeldObjectMass( m_hUseEntity, pHeldEnt->VPhysicsGetObject() ) : + (pHeldEnt->VPhysicsGetObject() ? PlayerPickupGetHeldObjectMass( m_hUseEntity, pHeldEnt->VPhysicsGetObject() ) : player_use_anim_heavy_mass.GetFloat()) : (m_hUseEntity->VPhysicsGetObject() ? m_hUseEntity->GetMass() : player_use_anim_heavy_mass.GetFloat()); if ( flMass >= player_use_anim_heavy_mass.GetFloat() ) { From a9bd90f681afb6bd9cb9599ac58f84ea06a48784 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sun, 17 Jul 2022 18:32:30 -0500 Subject: [PATCH 359/378] Fixed invalid look targets invalidating models --- sp/src/game/server/ai_baseactor.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/sp/src/game/server/ai_baseactor.cpp b/sp/src/game/server/ai_baseactor.cpp index 248c0841..ddf3da70 100644 --- a/sp/src/game/server/ai_baseactor.cpp +++ b/sp/src/game/server/ai_baseactor.cpp @@ -1142,6 +1142,18 @@ void CAI_BaseActor::UpdateHeadControl( const Vector &vHeadTarget, float flHeadIn ConcatTransforms( worldToForward, targetXform, headXform ); MatrixAngles( headXform, vTargetAngles ); +#ifdef MAPBASE + // This is here to cover an edge case where pose parameters set to NaN invalidate the model. + if (!vTargetAngles.IsValid()) + { + Warning( "================================================================================\n" + "!!!!! %s tried to set a NaN head angle (can happen when look targets have >1 importance) !!!!!\n" + "================================================================================\n", GetDebugName() ); + vTargetAngles.x = 0; + vTargetAngles.y = 0; + } +#endif + // partially debounce head goal float s0 = 1.0 - flHeadInfluence + GetHeadDebounce() * flHeadInfluence; float s1 = (1.0 - s0); From 197a9be59c4814533e25e4e8e04a7da6bc1f1dfc Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sun, 17 Jul 2022 20:17:48 -0500 Subject: [PATCH 360/378] Fixed response system support for escaped quotes causing backslashes to stop working --- sp/src/game/shared/ai_responsesystem_new.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sp/src/game/shared/ai_responsesystem_new.cpp b/sp/src/game/shared/ai_responsesystem_new.cpp index 9b519902..b639f270 100644 --- a/sp/src/game/shared/ai_responsesystem_new.cpp +++ b/sp/src/game/shared/ai_responsesystem_new.cpp @@ -188,6 +188,12 @@ skipwhite: token[len] = 0; return data; } + else if (c != '\"' && escaped) + { + // Not an escape character, just a back slash + token[len] = '\\'; + len++; + } escaped = (c == '\\'); if (!escaped) From 04cff632a3f723d94969acc741718c74589fd031 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Tue, 19 Jul 2022 13:44:03 -0500 Subject: [PATCH 361/378] Fixed leftover code causing issues in debug --- sp/src/game/server/entitylist.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/sp/src/game/server/entitylist.cpp b/sp/src/game/server/entitylist.cpp index dd886ab3..55d5614b 100644 --- a/sp/src/game/server/entitylist.cpp +++ b/sp/src/game/server/entitylist.cpp @@ -402,14 +402,6 @@ void CGlobalEntityList::Clear( void ) // free the memory g_DeleteList.Purge(); -#ifdef _DEBUG // From Alien Swarm SDK - for ( UtlHashHandle_t handle = g_EntsByClassname.GetFirstHandle(); g_EntsByClassname.IsValidHandle(handle); handle = g_EntsByClassname.GetNextHandle(handle) ) - { - EntsByStringList_t &element = g_EntsByClassname[handle]; - Assert( element.pHead == NULL ); - } -#endif - #ifdef MAPBASE_VSCRIPT g_CustomProcedurals.Purge(); #endif From 22f0b2c3ccdbb322f1e3fd41784f6fbe3b77965b Mon Sep 17 00:00:00 2001 From: samisalreadytaken <46823719+samisalreadytaken@users.noreply.github.com> Date: Mon, 18 Jul 2022 22:37:05 +0300 Subject: [PATCH 362/378] Refactor script hook system --- sp/src/game/client/c_baseentity.cpp | 2 +- sp/src/game/server/baseentity.cpp | 2 +- sp/src/game/server/filters.cpp | 10 +- sp/src/game/shared/baseentity_shared.cpp | 2 +- .../shared/mapbase/weapon_custom_scripted.cpp | 9 +- sp/src/public/vscript/ivscript.h | 89 ++++----- sp/src/vscript/vscript_squirrel.cpp | 92 ++++------ sp/src/vscript/vscript_squirrel.nut | 170 ++++++++++-------- 8 files changed, 201 insertions(+), 175 deletions(-) diff --git a/sp/src/game/client/c_baseentity.cpp b/sp/src/game/client/c_baseentity.cpp index b7ded40f..43471e9d 100644 --- a/sp/src/game/client/c_baseentity.cpp +++ b/sp/src/game/client/c_baseentity.cpp @@ -1353,7 +1353,7 @@ void C_BaseEntity::Term() if ( m_hScriptInstance ) { #ifdef MAPBASE_VSCRIPT - if ( m_ScriptScope.IsInitialized() ) + if ( m_ScriptScope.IsInitialized() && g_Hook_UpdateOnRemove.CanRunInScope( m_ScriptScope ) ) { g_Hook_UpdateOnRemove.Call( m_ScriptScope, NULL, NULL ); } diff --git a/sp/src/game/server/baseentity.cpp b/sp/src/game/server/baseentity.cpp index 147dfc39..67c3b17e 100644 --- a/sp/src/game/server/baseentity.cpp +++ b/sp/src/game/server/baseentity.cpp @@ -2646,7 +2646,7 @@ void CBaseEntity::UpdateOnRemove( void ) if ( m_hScriptInstance ) { #ifdef MAPBASE_VSCRIPT - if (m_ScriptScope.IsInitialized()) + if ( m_ScriptScope.IsInitialized() && g_Hook_UpdateOnRemove.CanRunInScope( m_ScriptScope ) ) { g_Hook_UpdateOnRemove.Call( m_ScriptScope, NULL, NULL ); } diff --git a/sp/src/game/server/filters.cpp b/sp/src/game/server/filters.cpp index 84021a95..da5dd61f 100644 --- a/sp/src/game/server/filters.cpp +++ b/sp/src/game/server/filters.cpp @@ -2157,7 +2157,7 @@ class CFilterScript : public CBaseFilter public: bool PassesFilterImpl( CBaseEntity *pCaller, CBaseEntity *pEntity ) { - if (m_ScriptScope.IsInitialized()) + if ( m_ScriptScope.IsInitialized() && g_Hook_PassesFilter.CanRunInScope( m_ScriptScope ) ) { // caller, activator ScriptVariant_t functionReturn; @@ -2176,7 +2176,7 @@ public: bool PassesDamageFilterImpl( CBaseEntity *pCaller, const CTakeDamageInfo &info ) { - if (m_ScriptScope.IsInitialized()) + if ( m_ScriptScope.IsInitialized() && g_Hook_PassesDamageFilter.CanRunInScope( m_ScriptScope ) ) { HSCRIPT pInfo = g_pScriptVM->RegisterInstance( const_cast(&info) ); @@ -2201,7 +2201,7 @@ public: bool PassesFinalDamageFilter( CBaseEntity *pCaller, const CTakeDamageInfo &info ) { - if (m_ScriptScope.IsInitialized()) + if ( m_ScriptScope.IsInitialized() && g_Hook_PassesFinalDamageFilter.CanRunInScope( m_ScriptScope ) ) { HSCRIPT pInfo = g_pScriptVM->RegisterInstance( const_cast(&info) ); @@ -2225,7 +2225,7 @@ public: bool BloodAllowed( CBaseEntity *pCaller, const CTakeDamageInfo &info ) { - if (m_ScriptScope.IsInitialized()) + if ( m_ScriptScope.IsInitialized() && g_Hook_BloodAllowed.CanRunInScope( m_ScriptScope ) ) { HSCRIPT pInfo = g_pScriptVM->RegisterInstance( const_cast(&info) ); @@ -2249,7 +2249,7 @@ public: bool DamageMod( CBaseEntity *pCaller, CTakeDamageInfo &info ) { - if (m_ScriptScope.IsInitialized()) + if ( m_ScriptScope.IsInitialized() && g_Hook_DamageMod.CanRunInScope( m_ScriptScope ) ) { HSCRIPT pInfo = g_pScriptVM->RegisterInstance( &info ); diff --git a/sp/src/game/shared/baseentity_shared.cpp b/sp/src/game/shared/baseentity_shared.cpp index af49c966..3393afa8 100644 --- a/sp/src/game/shared/baseentity_shared.cpp +++ b/sp/src/game/shared/baseentity_shared.cpp @@ -1613,7 +1613,7 @@ typedef CTraceFilterSimpleList CBulletsTraceFilter; void CBaseEntity::FireBullets( const FireBulletsInfo_t &info ) { #if defined(MAPBASE_VSCRIPT) && defined(GAME_DLL) - if (m_ScriptScope.IsInitialized()) + if ( m_ScriptScope.IsInitialized() && g_Hook_FireBullets.CanRunInScope( m_ScriptScope ) ) { HSCRIPT hInfo = g_pScriptVM->RegisterInstance( const_cast(&info) ); diff --git a/sp/src/game/shared/mapbase/weapon_custom_scripted.cpp b/sp/src/game/shared/mapbase/weapon_custom_scripted.cpp index d9155f32..4d5c744d 100644 --- a/sp/src/game/shared/mapbase/weapon_custom_scripted.cpp +++ b/sp/src/game/shared/mapbase/weapon_custom_scripted.cpp @@ -177,8 +177,13 @@ CWeaponCustomScripted::CWeaponCustomScripted() bool CWeaponCustomScripted::RunWeaponHook( ScriptHook_t &hook, HSCRIPT &cached, ScriptVariant_t *retVal, ScriptVariant_t *pArgs ) { - if (!hook.CheckFuncValid(cached)) - cached = hook.CanRunInScope(m_ScriptScope); + if ( !cached ) + { + if ( hook.CanRunInScope( m_ScriptScope ) ) + { + cached = hook.m_hFunc; + } + } if (cached) { diff --git a/sp/src/public/vscript/ivscript.h b/sp/src/public/vscript/ivscript.h index 001e1c24..fc16a143 100644 --- a/sp/src/public/vscript/ivscript.h +++ b/sp/src/public/vscript/ivscript.h @@ -885,9 +885,8 @@ public: //-------------------------------------------------------- // Hooks //-------------------------------------------------------- - virtual bool ScopeIsHooked( HSCRIPT hScope, const char *pszEventName ) = 0; - virtual HSCRIPT LookupHookFunction( const char *pszEventName, HSCRIPT hScope, bool &bLegacy ) = 0; - virtual ScriptStatus_t ExecuteHookFunction( const char *pszEventName, HSCRIPT hFunction, ScriptVariant_t *pArgs, int nArgs, ScriptVariant_t *pReturn, HSCRIPT hScope, bool bWait ) = 0; + virtual HSCRIPT LookupHookFunction( const char *pszEventName, HSCRIPT hScope ) = 0; + virtual ScriptStatus_t ExecuteHookFunction( HSCRIPT hFunction, const char *pszEventName, ScriptVariant_t *pArgs, int nArgs, ScriptVariant_t *pReturn, HSCRIPT hScope, bool bWait ) = 0; #endif //-------------------------------------------------------- @@ -1593,17 +1592,6 @@ typedef CScriptScopeT<> CScriptScope; // // This was previously done with raw function lookups, but Mapbase adds more and // it's hard to keep track of them without proper standards or documentation. -// -// At the moment, this simply plugs hook documentation into VScript and maintains -// the same function lookup method on the inside, but it's intended to be open for -// more complex hook mechanisms with proper parameters in the future. -// -// For example: -// -// if (m_hFunc) -// { -// g_pScriptVM->ExecuteFunction( m_Func, pArgs, m_desc.m_Parameters.Count(), pReturn, m_ScriptScope, true ); -// } //----------------------------------------------------------------------------- struct ScriptHook_t { @@ -1620,51 +1608,72 @@ struct ScriptHook_t // ----------------------------------------------------------------- - // Cached for when CanRunInScope() is called before Call() + // Only valid between CanRunInScope() and Call() HSCRIPT m_hFunc; bool m_bLegacy; - // Checks if there's a function of this name which would run in this scope - HSCRIPT CanRunInScope( HSCRIPT hScope ) + ScriptHook_t() : + m_bLegacy(false), + m_hFunc(NULL) { - extern IScriptVM *g_pScriptVM; - m_hFunc = g_pScriptVM->LookupHookFunction( m_desc.m_pszScriptName, hScope, m_bLegacy ); - return m_hFunc; } - // Checks if an existing func can be used - bool CheckFuncValid( HSCRIPT hFunc ) +#ifdef _DEBUG + // + // An uninitialised script scope will pass as null scope which is considered a valid hook scope (global hook) + // This should catch CanRunInScope() calls without CScriptScope::IsInitalised() checks first. + // + bool CanRunInScope( CScriptScope &hScope ) { - // TODO: Better crtieria for this? - if (hFunc) + Assert( hScope.IsInitialized() ); + return hScope.IsInitialized() && CanRunInScope( (HSCRIPT)hScope ); + } +#endif + + // Checks if there's a function of this name which would run in this scope + bool CanRunInScope( HSCRIPT hScope ) + { + extern IScriptVM *g_pScriptVM; + + // Check the hook system first to make sure an unintended function in the script scope does not cancel out all script hooks. + m_hFunc = g_pScriptVM->LookupHookFunction( m_desc.m_pszScriptName, hScope ); + if ( !m_hFunc ) { - m_hFunc = hFunc; - return true; + // Legacy support if the new system is not being used + m_hFunc = g_pScriptVM->LookupFunction( m_desc.m_pszScriptName, hScope ); + m_bLegacy = true; } - return false; + else + { + m_bLegacy = false; + } + + return !!m_hFunc; } // Call the function + // NOTE: `bRelease` only exists for weapon_custom_scripted legacy script func caching bool Call( HSCRIPT hScope, ScriptVariant_t *pReturn, ScriptVariant_t *pArgs, bool bRelease = true ) { extern IScriptVM *g_pScriptVM; - // Make sure we have a function in this scope - if (!m_hFunc && !CanRunInScope(hScope)) - return false; + // Call() should not be called without CanRunInScope() check first, it caches m_hFunc for legacy support + Assert( CanRunInScope( hScope ) ); + // Legacy - else if (m_bLegacy) + if ( m_bLegacy ) { + Assert( m_hFunc ); + for (int i = 0; i < m_desc.m_Parameters.Count(); i++) { g_pScriptVM->SetValue( m_pszParameterNames[i], pArgs[i] ); } - g_pScriptVM->ExecuteFunction( m_hFunc, NULL, 0, pReturn, hScope, true ); + ScriptStatus_t status = g_pScriptVM->ExecuteFunction( m_hFunc, NULL, 0, pReturn, hScope, true ); - if (bRelease) + if ( bRelease ) g_pScriptVM->ReleaseFunction( m_hFunc ); - m_hFunc = NULL; for (int i = 0; i < m_desc.m_Parameters.Count(); i++) @@ -1672,19 +1681,19 @@ struct ScriptHook_t g_pScriptVM->ClearValue( m_pszParameterNames[i] ); } - return true; + return status == SCRIPT_DONE; } // New Hook System else { - g_pScriptVM->ExecuteHookFunction( m_desc.m_pszScriptName, m_hFunc, pArgs, m_desc.m_Parameters.Count(), pReturn, hScope, true ); - if (bRelease) + ScriptStatus_t status = g_pScriptVM->ExecuteHookFunction( m_hFunc, m_desc.m_pszScriptName, pArgs, m_desc.m_Parameters.Count(), pReturn, hScope, true ); + + if ( bRelease ) g_pScriptVM->ReleaseFunction( m_hFunc ); m_hFunc = NULL; - return true; - } - return false; + return status == SCRIPT_DONE; + } } }; #endif diff --git a/sp/src/vscript/vscript_squirrel.cpp b/sp/src/vscript/vscript_squirrel.cpp index 15d8c1ff..932ab26f 100644 --- a/sp/src/vscript/vscript_squirrel.cpp +++ b/sp/src/vscript/vscript_squirrel.cpp @@ -188,9 +188,8 @@ public: //-------------------------------------------------------- // Hooks //-------------------------------------------------------- - virtual bool ScopeIsHooked( HSCRIPT hScope, const char *pszEventName ) override; - virtual HSCRIPT LookupHookFunction( const char *pszEventName, HSCRIPT hScope, bool &bLegacy ) override; - virtual ScriptStatus_t ExecuteHookFunction( const char *pszEventName, HSCRIPT hFunction, ScriptVariant_t *pArgs, int nArgs, ScriptVariant_t *pReturn, HSCRIPT hScope, bool bWait ) override; + virtual HSCRIPT LookupHookFunction( const char *pszEventName, HSCRIPT hScope ) override; + virtual ScriptStatus_t ExecuteHookFunction( HSCRIPT hFunction, const char *pszEventName, ScriptVariant_t *pArgs, int nArgs, ScriptVariant_t *pReturn, HSCRIPT hScope, bool bWait ) override; //-------------------------------------------------------- // External functions @@ -2348,55 +2347,38 @@ ScriptStatus_t SquirrelVM::ExecuteFunction(HSCRIPT hFunction, ScriptVariant_t* p return SCRIPT_DONE; } -bool SquirrelVM::ScopeIsHooked( HSCRIPT hScope, const char *pszEventName ) +HSCRIPT SquirrelVM::LookupHookFunction(const char *pszEventName, HSCRIPT hScope) { + SquirrelSafeCheck safeCheck(vm_); + // For now, assume null scope (which is used for global hooks) is always hooked - if (!hScope) - return true; - - SquirrelSafeCheck safeCheck(vm_); - - Assert(hScope != INVALID_HSCRIPT); - - sq_pushroottable(vm_); - sq_pushstring(vm_, "Hooks", -1); - sq_get(vm_, -2); - sq_pushstring(vm_, "ScopeHookedToEvent", -1); - sq_get(vm_, -2); - sq_push(vm_, -2); - sq_pushobject(vm_, *((HSQOBJECT*)hScope)); - sq_pushstring(vm_, pszEventName, -1); - sq_call(vm_, 3, SQTrue, SQTrue); - - SQBool val; - if (SQ_FAILED(sq_getbool(vm_, -1, &val))) + if ( hScope ) { - sq_pop(vm_, 3); - return false; + Assert( hScope != INVALID_HSCRIPT ); + + sq_pushroottable(vm_); + sq_pushstring(vm_, "Hooks", -1); + sq_get(vm_, -2); + sq_pushstring(vm_, "IsEventHookedInScope", -1); + sq_get(vm_, -2); + sq_push(vm_, -2); + sq_pushstring(vm_, pszEventName, -1); + sq_pushobject(vm_, *((HSQOBJECT*)hScope)); + sq_call(vm_, 3, SQTrue, SQTrue); + + SQBool val; + if (SQ_FAILED(sq_getbool(vm_, -1, &val))) + { + sq_pop(vm_, 3); + return nullptr; + } + + sq_pop(vm_, 4); + + if (!val) + return nullptr; } - sq_pop(vm_, 4); - return val ? true : false; -} - -HSCRIPT SquirrelVM::LookupHookFunction(const char *pszEventName, HSCRIPT hScope, bool &bLegacy) -{ - HSCRIPT hFunc = hScope ? LookupFunction( pszEventName, hScope ) : nullptr; - if (hFunc) - { - bLegacy = true; - return hFunc; - } - else - { - bLegacy = false; - } - - if (!ScopeIsHooked(hScope, pszEventName)) - return nullptr; - - SquirrelSafeCheck safeCheck(vm_); - sq_pushroottable(vm_); sq_pushstring(vm_, "Hooks", -1); sq_get(vm_, -2); @@ -2411,31 +2393,31 @@ HSCRIPT SquirrelVM::LookupHookFunction(const char *pszEventName, HSCRIPT hScope, HSQOBJECT* pObj = new HSQOBJECT; *pObj = obj; + return (HSCRIPT)pObj; } -ScriptStatus_t SquirrelVM::ExecuteHookFunction(const char *pszEventName, HSCRIPT hFunction, ScriptVariant_t* pArgs, int nArgs, ScriptVariant_t* pReturn, HSCRIPT hScope, bool bWait) +ScriptStatus_t SquirrelVM::ExecuteHookFunction(HSCRIPT hFunction, const char *pszEventName, ScriptVariant_t* pArgs, int nArgs, ScriptVariant_t* pReturn, HSCRIPT hScope, bool bWait) { - SquirrelSafeCheck safeCheck(vm_); - if (!hFunction) + if ( !hFunction ) return SCRIPT_ERROR; - if (hFunction == INVALID_HSCRIPT) - return SCRIPT_ERROR; + SquirrelSafeCheck safeCheck(vm_); HSQOBJECT* pFunc = (HSQOBJECT*)hFunction; sq_pushobject(vm_, *pFunc); - // TODO: Run in hook scope + // The call environment of the Hooks::Call function does not matter + // as the function does not access any member variables. sq_pushroottable(vm_); + sq_pushstring(vm_, pszEventName, -1); + if (hScope) sq_pushobject(vm_, *((HSQOBJECT*)hScope)); else sq_pushnull(vm_); // global hook - sq_pushstring(vm_, pszEventName, -1); - for (int i = 0; i < nArgs; ++i) { PushVariant(vm_, pArgs[i]); diff --git a/sp/src/vscript/vscript_squirrel.nut b/sp/src/vscript/vscript_squirrel.nut index bafd55b7..1c1bd4e7 100644 --- a/sp/src/vscript/vscript_squirrel.nut +++ b/sp/src/vscript/vscript_squirrel.nut @@ -152,114 +152,144 @@ Hooks <- // table, string, closure, string function Add( scope, event, callback, context ) { + switch ( typeof scope ) + { + case "table": + case "instance": + case "class": + break; + default: + throw "invalid scope param"; + } + + if ( typeof event != "string" ) + throw "invalid event param"; + if ( typeof callback != "function" ) - throw "invalid callback param" + throw "invalid callback param"; - if ( !(scope in s_List) ) - s_List[scope] <- {} + if ( typeof context != "string" ) + throw "invalid context param"; - local t = s_List[scope] + if ( !(event in s_List) ) + s_List[event] <- {}; - if ( !(event in t) ) - t[event] <- {} + local t = s_List[event]; - t[event][context] <- callback + if ( !(scope in t) ) + t[scope] <- {}; + + t[scope][context] <- callback; } - function Remove( context, event = null ) + function Remove( event, context ) { + local rem; + if ( event ) { - foreach( k,scope in s_List ) + if ( event in s_List ) { - if ( event in scope ) + foreach ( scope, ctx in s_List[event] ) { - local t = scope[event] - if ( context in t ) + if ( context in ctx ) { - delete t[context] + delete ctx[context]; } - // cleanup? - if ( !t.len() ) - delete scope[event] + if ( !ctx.len() ) + { + if ( !rem ) + rem = []; + rem.append( event ); + rem.append( scope ); + } } - - // cleanup? - if ( !scope.len() ) - delete s_List[k] } } else { - foreach( k,scope in s_List ) + foreach ( ev, t in s_List ) { - foreach( kk,ev in scope ) + foreach ( scope, ctx in t ) { - if ( context in ev ) + if ( context in ctx ) { - delete ev[context] + delete ctx[context]; } - // cleanup? - if ( !ev.len() ) - delete scope[kk] - } - - // cleanup? - if ( !scope.len() ) - delete s_List[k] - } - } - } - - function Call( scope, event, ... ) - { - local firstReturn - - // global hook; call all scopes - if ( !scope ) - { - vargv.insert( 0, null ) - foreach( sc,t in s_List ) - { - if ( event in t ) - { - vargv[0] = sc - foreach( context, callback in t[event] ) + if ( !ctx.len() ) { - //printf( "(%.4f) Calling hook '%s' of context '%s' in static iteration\n", Time(), event, context ) - - local curReturn = callback.acall(vargv) - if (firstReturn == null) - firstReturn = curReturn + if ( !rem ) + rem = []; + rem.append( ev ); + rem.append( scope ); } } } } - else if ( scope in s_List ) - { - local t = s_List[scope] - if ( event in t ) - { - vargv.insert( 0, scope ) - foreach( context, callback in t[event] ) - { - //printf( "(%.4f) Calling hook '%s' of context '%s'\n", Time(), event, context ) - local curReturn = callback.acall(vargv) - if (firstReturn == null) - firstReturn = curReturn + if ( rem ) + { + local c = rem.len() - 1; + for ( local i = 0; i < c; i += 2 ) + { + local ev = rem[i]; + local scope = rem[i+1]; + + if ( !s_List[ev][scope].len() ) + delete s_List[ev][scope]; + + if ( !s_List[ev].len() ) + delete s_List[ev]; + } + } + } + + function Call( event, scope, ... ) + { + local firstReturn; + + if ( event in s_List ) + { + vargv.insert( 0, scope ); + + local t = s_List[event]; + if ( scope in t ) + { + foreach ( fn in t[scope] ) + { + //printf( "(%.4f) Calling hook %s:%s\n", Time(), event, context ); + + local r = fn.acall( vargv ); + if ( firstReturn == null ) + firstReturn = r; + } + } + else if ( !scope ) // global hook + { + foreach ( sc, ctx in t ) + { + vargv[0] = sc; + + foreach ( context, fn in ctx ) + { + //printf( "(%.4f) Calling hook (g) %s:%s\n", Time(), event, context ); + + local r = fn.acall( vargv ); + if ( firstReturn == null ) + firstReturn = r; + } } } } - return firstReturn + return firstReturn; } - function ScopeHookedToEvent( scope, event ) + function IsEventHookedInScope( event, scope ) { - return ( scope in s_List ) && ( event in s_List[scope] ) + return ( event in s_List ) && ( scope in s_List[event] ) } } From 6e6bb4d639b9a93ed2ca656057ab7ea871265328 Mon Sep 17 00:00:00 2001 From: samisalreadytaken <46823719+samisalreadytaken@users.noreply.github.com> Date: Mon, 18 Jul 2022 23:58:29 +0300 Subject: [PATCH 363/378] Implement CScriptHookManager --- sp/src/game/client/vscript_client.cpp | 11 +- sp/src/game/server/vscript_server.cpp | 12 +- .../shared/mapbase/vscript_singletons.cpp | 6 +- sp/src/game/shared/vscript_shared.cpp | 4 + sp/src/public/vscript/ivscript.h | 329 ++++++++++++++++-- sp/src/vscript/vscript_squirrel.cpp | 66 +--- sp/src/vscript/vscript_squirrel.nut | 8 +- 7 files changed, 349 insertions(+), 87 deletions(-) diff --git a/sp/src/game/client/vscript_client.cpp b/sp/src/game/client/vscript_client.cpp index 1b2891ab..1a5c59be 100644 --- a/sp/src/game/client/vscript_client.cpp +++ b/sp/src/game/client/vscript_client.cpp @@ -114,7 +114,7 @@ public: void OnEntityCreated( CBaseEntity *pEntity ) { - if ( g_pScriptVM ) + if ( g_pScriptVM && GetScriptHookManager().IsEventHooked( "OnEntityCreated" ) ) { // entity ScriptVariant_t args[] = { ScriptVariant_t( pEntity->GetScriptInstance() ) }; @@ -124,7 +124,7 @@ public: void OnEntityDeleted( CBaseEntity *pEntity ) { - if ( g_pScriptVM ) + if ( g_pScriptVM && GetScriptHookManager().IsEventHooked( "OnEntityDeleted" ) ) { // entity ScriptVariant_t args[] = { ScriptVariant_t( pEntity->GetScriptInstance() ) }; @@ -645,6 +645,11 @@ bool VScriptClientInit() #else Log( "VSCRIPT: Started VScript virtual machine using script language '%s'\n", g_pScriptVM->GetLanguageName() ); #endif + +#ifdef MAPBASE_VSCRIPT + GetScriptHookManager().OnInit(); +#endif + ScriptRegisterFunction( g_pScriptVM, GetMapName, "Get the name of the map."); ScriptRegisterFunction( g_pScriptVM, Time, "Get the current server time" ); ScriptRegisterFunction( g_pScriptVM, DoUniqueString, SCRIPT_ALIAS( "UniqueString", "Generate a string guaranteed to be unique across the life of the script VM, with an optional root string." ) ); @@ -770,6 +775,8 @@ public: { #ifdef MAPBASE_VSCRIPT g_ScriptNetMsg->LevelShutdownPreVM(); + + GetScriptHookManager().OnShutdown(); #endif VScriptClientTerm(); } diff --git a/sp/src/game/server/vscript_server.cpp b/sp/src/game/server/vscript_server.cpp index 559c57e3..25c8281a 100644 --- a/sp/src/game/server/vscript_server.cpp +++ b/sp/src/game/server/vscript_server.cpp @@ -154,7 +154,7 @@ public: void OnEntityCreated( CBaseEntity *pEntity ) { - if ( g_pScriptVM ) + if ( g_pScriptVM && GetScriptHookManager().IsEventHooked( "OnEntityCreated" ) ) { // entity ScriptVariant_t args[] = { ScriptVariant_t( pEntity->GetScriptInstance() ) }; @@ -164,7 +164,7 @@ public: void OnEntitySpawned( CBaseEntity *pEntity ) { - if ( g_pScriptVM ) + if ( g_pScriptVM && GetScriptHookManager().IsEventHooked( "OnEntitySpawned" ) ) { // entity ScriptVariant_t args[] = { ScriptVariant_t( pEntity->GetScriptInstance() ) }; @@ -174,7 +174,7 @@ public: void OnEntityDeleted( CBaseEntity *pEntity ) { - if ( g_pScriptVM ) + if ( g_pScriptVM && GetScriptHookManager().IsEventHooked( "OnEntityDeleted" ) ) { // entity ScriptVariant_t args[] = { ScriptVariant_t( pEntity->GetScriptInstance() ) }; @@ -600,6 +600,10 @@ bool VScriptServerInit() Log( "VSCRIPT: Started VScript virtual machine using script language '%s'\n", g_pScriptVM->GetLanguageName() ); #endif +#ifdef MAPBASE_VSCRIPT + GetScriptHookManager().OnInit(); +#endif + #ifdef MAPBASE_VSCRIPT // MULTIPLAYER // ScriptRegisterFunctionNamed( g_pScriptVM, UTIL_PlayerByIndex, "GetPlayerByIndex", "PlayerInstanceFromIndex" ); @@ -836,6 +840,8 @@ public: { #ifdef MAPBASE_VSCRIPT g_ScriptNetMsg->LevelShutdownPreVM(); + + GetScriptHookManager().OnShutdown(); #endif VScriptServerTerm(); } diff --git a/sp/src/game/shared/mapbase/vscript_singletons.cpp b/sp/src/game/shared/mapbase/vscript_singletons.cpp index 64212d44..8f821e6c 100644 --- a/sp/src/game/shared/mapbase/vscript_singletons.cpp +++ b/sp/src/game/shared/mapbase/vscript_singletons.cpp @@ -872,7 +872,8 @@ public: // IGameSystem { if ( g_pScriptVM ) { - g_Hook_OnSave.Call( NULL, NULL, NULL ); + if ( GetScriptHookManager().IsEventHooked( "OnSave" ) ) + g_Hook_OnSave.Call( NULL, NULL, NULL ); // Legacy hook HSCRIPT hFunc = g_pScriptVM->LookupFunction( "OnSave" ); @@ -893,7 +894,8 @@ public: // IGameSystem { if ( g_pScriptVM ) { - g_Hook_OnRestore.Call( NULL, NULL, NULL ); + if ( GetScriptHookManager().IsEventHooked( "OnRestore" ) ) + g_Hook_OnRestore.Call( NULL, NULL, NULL ); // Legacy hook HSCRIPT hFunc = g_pScriptVM->LookupFunction( "OnRestore" ); diff --git a/sp/src/game/shared/vscript_shared.cpp b/sp/src/game/shared/vscript_shared.cpp index 088c19a7..4f20b7c6 100644 --- a/sp/src/game/shared/vscript_shared.cpp +++ b/sp/src/game/shared/vscript_shared.cpp @@ -451,6 +451,10 @@ public: } m_InstanceMap.Purge(); +#ifdef MAPBASE_VSCRIPT + GetScriptHookManager().OnRestore(); +#endif + #if defined(MAPBASE_VSCRIPT) && defined(CLIENT_DLL) VScriptSaveRestoreUtil_OnVMRestore(); #endif diff --git a/sp/src/public/vscript/ivscript.h b/sp/src/public/vscript/ivscript.h index fc16a143..0d105d55 100644 --- a/sp/src/public/vscript/ivscript.h +++ b/sp/src/public/vscript/ivscript.h @@ -98,6 +98,9 @@ #include #include +#include "utlmap.h" +#include "utlvector.h" + #include "platform.h" #include "datamap.h" #include "appframework/IAppSystem.h" @@ -137,6 +140,8 @@ class KeyValues; // This has been moved up a bit for IScriptManager DECLARE_POINTER_HANDLE( HSCRIPT ); #define INVALID_HSCRIPT ((HSCRIPT)-1) + +typedef unsigned int HScriptRaw; #endif enum ScriptLanguage_t @@ -885,8 +890,9 @@ public: //-------------------------------------------------------- // Hooks //-------------------------------------------------------- - virtual HSCRIPT LookupHookFunction( const char *pszEventName, HSCRIPT hScope ) = 0; - virtual ScriptStatus_t ExecuteHookFunction( HSCRIPT hFunction, const char *pszEventName, ScriptVariant_t *pArgs, int nArgs, ScriptVariant_t *pReturn, HSCRIPT hScope, bool bWait ) = 0; + // Persistent unique identifier for an HSCRIPT variable + virtual HScriptRaw HScriptToRaw( HSCRIPT val ) = 0; + virtual ScriptStatus_t ExecuteHookFunction( const char *pszEventName, ScriptVariant_t *pArgs, int nArgs, ScriptVariant_t *pReturn, HSCRIPT hScope, bool bWait ) = 0; #endif //-------------------------------------------------------- @@ -1586,6 +1592,291 @@ typedef CScriptScopeT<> CScriptScope; #define VScriptAddEnumToRoot( enumVal ) g_pScriptVM->SetValue( #enumVal, (int)enumVal ) #ifdef MAPBASE_VSCRIPT + +// +// Map pointer iteration +// +#define FOR_EACH_MAP_PTR( mapName, iteratorName ) \ + for ( int iteratorName = (mapName)->FirstInorder(); (mapName)->IsUtlMap && iteratorName != (mapName)->InvalidIndex(); iteratorName = (mapName)->NextInorder( iteratorName ) ) + +#define FOR_EACH_MAP_PTR_FAST( mapName, iteratorName ) \ + for ( int iteratorName = 0; (mapName)->IsUtlMap && iteratorName < (mapName)->MaxElement(); ++iteratorName ) if ( !(mapName)->IsValidIndex( iteratorName ) ) continue; else + +#define FOR_EACH_VEC_PTR( vecName, iteratorName ) \ + for ( int iteratorName = 0; iteratorName < (vecName)->Count(); iteratorName++ ) + +//----------------------------------------------------------------------------- +// +// Keeps track of which events and scopes are hooked without polling this from the script VM on each request. +// Local cache is updated each time there is a change to script hooks: on Add, on Remove, on game restore +// +//----------------------------------------------------------------------------- +class CScriptHookManager +{ +private: + typedef CUtlVector< char* > contextmap_t; + typedef CUtlMap< HScriptRaw, contextmap_t* > scopemap_t; + typedef CUtlMap< char*, scopemap_t* > hookmap_t; + + HSCRIPT m_hfnHookFunc; + + // { [string event], { [HSCRIPT scope], { [string context], [HSCRIPT callback] } } } + hookmap_t m_HookList; + +public: + + CScriptHookManager() : m_HookList( DefLessFunc(char*) ), m_hfnHookFunc(NULL) + { + } + + HSCRIPT GetHookFunction() + { + return m_hfnHookFunc; + } + + // For global hooks + bool IsEventHooked( const char *szEvent ) + { + return m_HookList.Find( const_cast< char* >( szEvent ) ) != m_HookList.InvalidIndex(); + } + + bool IsEventHookedInScope( const char *szEvent, HSCRIPT hScope ) + { + extern IScriptVM *g_pScriptVM; + + Assert( hScope ); + + int eventIdx = m_HookList.Find( const_cast< char* >( szEvent ) ); + if ( eventIdx == m_HookList.InvalidIndex() ) + return false; + + scopemap_t *scopeMap = m_HookList.Element( eventIdx ); + return scopeMap->Find( g_pScriptVM->HScriptToRaw( hScope ) ) != scopeMap->InvalidIndex(); + } + + static void __UpdateScriptHooks( HSCRIPT hooksList ) + { + extern CScriptHookManager &GetScriptHookManager(); + GetScriptHookManager().Update( hooksList ); + } + + // + // On VM init, registers script func and caches the hook func. + // + void OnInit() + { + extern IScriptVM *g_pScriptVM; + + ScriptRegisterFunctionNamed( g_pScriptVM, __UpdateScriptHooks, "__UpdateScriptHooks", SCRIPT_HIDE ); + + ScriptVariant_t hHooks; + g_pScriptVM->GetValue( "Hooks", &hHooks ); + + Assert( hHooks.m_type == FIELD_HSCRIPT ); + + if ( hHooks.m_type == FIELD_HSCRIPT ) + { + m_hfnHookFunc = g_pScriptVM->LookupFunction( "Call", hHooks ); + } + + Clear(); + } + + // + // On VM shutdown, clear the cache. + // Not exactly necessary, as the cache will be cleared on VM init next time. + // + void OnShutdown() + { + extern IScriptVM *g_pScriptVM; + + if ( m_hfnHookFunc ) + g_pScriptVM->ReleaseFunction( m_hfnHookFunc ); + + m_hfnHookFunc = NULL; + + Clear(); + } + + // + // On VM restore, update local cache. + // + void OnRestore() + { + extern IScriptVM *g_pScriptVM; + + ScriptVariant_t hHooks; + g_pScriptVM->GetValue( "Hooks", &hHooks ); + + if ( hHooks.m_type == FIELD_HSCRIPT ) + { + // Existing m_hfnHookFunc is invalid + m_hfnHookFunc = g_pScriptVM->LookupFunction( "Call", hHooks ); + + HSCRIPT func = g_pScriptVM->LookupFunction( "__UpdateHooks", hHooks ); + g_pScriptVM->Call( func ); + g_pScriptVM->ReleaseFunction( func ); + g_pScriptVM->ReleaseValue( hHooks ); + } + } + + // + // Clear local cache. + // + void Clear() + { + if ( m_HookList.Count() ) + { + FOR_EACH_MAP_FAST( m_HookList, i ) + { + scopemap_t *scopeMap = m_HookList.Element(i); + + FOR_EACH_MAP_PTR_FAST( scopeMap, j ) + { + contextmap_t *contextMap = scopeMap->Element(j); + contextMap->PurgeAndDeleteElements(); + } + + char *szEvent = m_HookList.Key(i); + free( szEvent ); + + scopeMap->PurgeAndDeleteElements(); + } + + m_HookList.PurgeAndDeleteElements(); + } + } + + // + // Called from script, update local cache. + // + void Update( HSCRIPT hooksList ) + { + extern IScriptVM *g_pScriptVM; + + // Rebuild from scratch + Clear(); + { + ScriptVariant_t varEvent, varScopeMap; + int it = -1; + while ( ( it = g_pScriptVM->GetKeyValue( hooksList, it, &varEvent, &varScopeMap ) ) != -1 ) + { + // types are checked in script + Assert( varEvent.m_type == FIELD_CSTRING ); + Assert( varScopeMap.m_type == FIELD_HSCRIPT ); + + scopemap_t *scopeMap; + + int eventIdx = m_HookList.Find( const_cast< char* >( varEvent.m_pszString ) ); + if ( eventIdx != m_HookList.InvalidIndex() ) + { + scopeMap = m_HookList.Element( eventIdx ); + } + else + { + scopeMap = new scopemap_t( DefLessFunc(HScriptRaw) ); + m_HookList.Insert( strdup( varEvent.m_pszString ), scopeMap ); + } + + ScriptVariant_t varScope, varContextMap; + int it2 = -1; + while ( ( it2 = g_pScriptVM->GetKeyValue( varScopeMap, it2, &varScope, &varContextMap ) ) != -1 ) + { + Assert( varScope.m_type == FIELD_HSCRIPT ); + Assert( varContextMap.m_type == FIELD_HSCRIPT); + + contextmap_t *contextMap; + + int scopeIdx = scopeMap->Find( g_pScriptVM->HScriptToRaw( varScope.m_hScript ) ); + if ( scopeIdx != scopeMap->InvalidIndex() ) + { + contextMap = scopeMap->Element( scopeIdx ); + } + else + { + contextMap = new contextmap_t(); + scopeMap->Insert( g_pScriptVM->HScriptToRaw( varScope.m_hScript ), contextMap ); + } + + ScriptVariant_t varContext, varCallback; + int it3 = -1; + while ( ( it3 = g_pScriptVM->GetKeyValue( varContextMap, it3, &varContext, &varCallback ) ) != -1 ) + { + Assert( varContext.m_type == FIELD_CSTRING ); + Assert( varCallback.m_type == FIELD_HSCRIPT ); + + bool skip = false; + + FOR_EACH_VEC_PTR( contextMap, k ) + { + char *szContext = contextMap->Element(k); + if ( V_strcmp( szContext, varContext.m_pszString ) == 0 ) + { + skip = true; + break; + } + } + + if ( !skip ) + contextMap->AddToTail( strdup( varContext.m_pszString ) ); + + g_pScriptVM->ReleaseValue( varContext ); + g_pScriptVM->ReleaseValue( varCallback ); + } + + g_pScriptVM->ReleaseValue( varScope ); + g_pScriptVM->ReleaseValue( varContextMap ); + } + + g_pScriptVM->ReleaseValue( varEvent ); + g_pScriptVM->ReleaseValue( varScopeMap ); + } + } + } +#ifdef _DEBUG + void Dump() + { + extern IScriptVM *g_pScriptVM; + + FOR_EACH_MAP( m_HookList, i ) + { + scopemap_t *scopeMap = m_HookList.Element(i); + char *szEvent = m_HookList.Key(i); + + Msg( "%s [%x]\n", szEvent, (void*)scopeMap ); + Msg( "{\n" ); + + FOR_EACH_MAP_PTR( scopeMap, j ) + { + HScriptRaw hScope = scopeMap->Key(j); + contextmap_t *contextMap = scopeMap->Element(j); + + Msg( "\t(0x%X) [%x]\n", hScope, (void*)contextMap ); + Msg( "\t{\n" ); + + FOR_EACH_VEC_PTR( contextMap, k ) + { + char *szContext = contextMap->Element(k); + + Msg( "\t\t%-.50s\n", szContext ); + } + + Msg( "\t}\n" ); + } + + Msg( "}\n" ); + } + } +#endif +}; + +inline CScriptHookManager &GetScriptHookManager() +{ + static CScriptHookManager g_ScriptHookManager; + return g_ScriptHookManager; +} + + //----------------------------------------------------------------------------- // Function bindings allow script functions to run C++ functions. // Hooks allow C++ functions to run script functions. @@ -1610,10 +1901,8 @@ struct ScriptHook_t // Only valid between CanRunInScope() and Call() HSCRIPT m_hFunc; - bool m_bLegacy; ScriptHook_t() : - m_bLegacy(false), m_hFunc(NULL) { } @@ -1633,20 +1922,17 @@ struct ScriptHook_t // Checks if there's a function of this name which would run in this scope bool CanRunInScope( HSCRIPT hScope ) { + // For now, assume null scope (which is used for global hooks) is always hooked + if ( !hScope || GetScriptHookManager().IsEventHookedInScope( m_desc.m_pszScriptName, hScope ) ) + { + m_hFunc = NULL; + return true; + } + extern IScriptVM *g_pScriptVM; - // Check the hook system first to make sure an unintended function in the script scope does not cancel out all script hooks. - m_hFunc = g_pScriptVM->LookupHookFunction( m_desc.m_pszScriptName, hScope ); - if ( !m_hFunc ) - { - // Legacy support if the new system is not being used - m_hFunc = g_pScriptVM->LookupFunction( m_desc.m_pszScriptName, hScope ); - m_bLegacy = true; - } - else - { - m_bLegacy = false; - } + // Legacy support if the new system is not being used + m_hFunc = g_pScriptVM->LookupFunction( m_desc.m_pszScriptName, hScope ); return !!m_hFunc; } @@ -1661,10 +1947,8 @@ struct ScriptHook_t Assert( CanRunInScope( hScope ) ); // Legacy - if ( m_bLegacy ) + if ( m_hFunc ) { - Assert( m_hFunc ); - for (int i = 0; i < m_desc.m_Parameters.Count(); i++) { g_pScriptVM->SetValue( m_pszParameterNames[i], pArgs[i] ); @@ -1686,12 +1970,7 @@ struct ScriptHook_t // New Hook System else { - ScriptStatus_t status = g_pScriptVM->ExecuteHookFunction( m_hFunc, m_desc.m_pszScriptName, pArgs, m_desc.m_Parameters.Count(), pReturn, hScope, true ); - - if ( bRelease ) - g_pScriptVM->ReleaseFunction( m_hFunc ); - m_hFunc = NULL; - + ScriptStatus_t status = g_pScriptVM->ExecuteHookFunction( m_desc.m_pszScriptName, pArgs, m_desc.m_Parameters.Count(), pReturn, hScope, true ); return status == SCRIPT_DONE; } } diff --git a/sp/src/vscript/vscript_squirrel.cpp b/sp/src/vscript/vscript_squirrel.cpp index 932ab26f..3b1e87ab 100644 --- a/sp/src/vscript/vscript_squirrel.cpp +++ b/sp/src/vscript/vscript_squirrel.cpp @@ -188,8 +188,8 @@ public: //-------------------------------------------------------- // Hooks //-------------------------------------------------------- - virtual HSCRIPT LookupHookFunction( const char *pszEventName, HSCRIPT hScope ) override; - virtual ScriptStatus_t ExecuteHookFunction( HSCRIPT hFunction, const char *pszEventName, ScriptVariant_t *pArgs, int nArgs, ScriptVariant_t *pReturn, HSCRIPT hScope, bool bWait ) override; + virtual HScriptRaw HScriptToRaw( HSCRIPT val ) override; + virtual ScriptStatus_t ExecuteHookFunction( const char *pszEventName, ScriptVariant_t *pArgs, int nArgs, ScriptVariant_t *pReturn, HSCRIPT hScope, bool bWait ) override; //-------------------------------------------------------- // External functions @@ -2347,64 +2347,24 @@ ScriptStatus_t SquirrelVM::ExecuteFunction(HSCRIPT hFunction, ScriptVariant_t* p return SCRIPT_DONE; } -HSCRIPT SquirrelVM::LookupHookFunction(const char *pszEventName, HSCRIPT hScope) +HScriptRaw SquirrelVM::HScriptToRaw( HSCRIPT val ) { - SquirrelSafeCheck safeCheck(vm_); + Assert( val ); + Assert( val != INVALID_HSCRIPT ); - // For now, assume null scope (which is used for global hooks) is always hooked - if ( hScope ) - { - Assert( hScope != INVALID_HSCRIPT ); - - sq_pushroottable(vm_); - sq_pushstring(vm_, "Hooks", -1); - sq_get(vm_, -2); - sq_pushstring(vm_, "IsEventHookedInScope", -1); - sq_get(vm_, -2); - sq_push(vm_, -2); - sq_pushstring(vm_, pszEventName, -1); - sq_pushobject(vm_, *((HSQOBJECT*)hScope)); - sq_call(vm_, 3, SQTrue, SQTrue); - - SQBool val; - if (SQ_FAILED(sq_getbool(vm_, -1, &val))) - { - sq_pop(vm_, 3); - return nullptr; - } - - sq_pop(vm_, 4); - - if (!val) - return nullptr; - } - - sq_pushroottable(vm_); - sq_pushstring(vm_, "Hooks", -1); - sq_get(vm_, -2); - sq_pushstring(vm_, "Call", -1); - sq_get(vm_, -2); - - HSQOBJECT obj; - sq_resetobject(&obj); - sq_getstackobj(vm_, -1, &obj); - sq_addref(vm_, &obj); - sq_pop(vm_, 3); - - HSQOBJECT* pObj = new HSQOBJECT; - *pObj = obj; - - return (HSCRIPT)pObj; + HSQOBJECT *obj = (HSQOBJECT*)val; +#if 0 + if ( sq_isweakref(*obj) ) + return obj->_unVal.pWeakRef->_obj._unVal.raw; +#endif + return obj->_unVal.raw; } -ScriptStatus_t SquirrelVM::ExecuteHookFunction(HSCRIPT hFunction, const char *pszEventName, ScriptVariant_t* pArgs, int nArgs, ScriptVariant_t* pReturn, HSCRIPT hScope, bool bWait) +ScriptStatus_t SquirrelVM::ExecuteHookFunction(const char *pszEventName, ScriptVariant_t* pArgs, int nArgs, ScriptVariant_t* pReturn, HSCRIPT hScope, bool bWait) { - if ( !hFunction ) - return SCRIPT_ERROR; - SquirrelSafeCheck safeCheck(vm_); - HSQOBJECT* pFunc = (HSQOBJECT*)hFunction; + HSQOBJECT* pFunc = (HSQOBJECT*)GetScriptHookManager().GetHookFunction(); sq_pushobject(vm_, *pFunc); // The call environment of the Hooks::Call function does not matter diff --git a/sp/src/vscript/vscript_squirrel.nut b/sp/src/vscript/vscript_squirrel.nut index 1c1bd4e7..5b76bbe3 100644 --- a/sp/src/vscript/vscript_squirrel.nut +++ b/sp/src/vscript/vscript_squirrel.nut @@ -180,6 +180,8 @@ Hooks <- t[scope] <- {}; t[scope][context] <- callback; + + return __UpdateHooks(); } function Remove( event, context ) @@ -244,6 +246,8 @@ Hooks <- delete s_List[ev]; } } + + return __UpdateHooks(); } function Call( event, scope, ... ) @@ -287,9 +291,9 @@ Hooks <- return firstReturn; } - function IsEventHookedInScope( event, scope ) + function __UpdateHooks() { - return ( event in s_List ) && ( scope in s_List[event] ) + return __UpdateScriptHooks( s_List ); } } From f43c4607f79e9d3f60da5543aa80b7f271b85b1d Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sat, 23 Jul 2022 00:30:29 -0500 Subject: [PATCH 364/378] Removed BuildTransformations VScript hook for now --- sp/src/game/client/c_baseanimating.cpp | 36 +++++++++++++------------- sp/src/game/client/c_baseanimating.h | 2 +- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/sp/src/game/client/c_baseanimating.cpp b/sp/src/game/client/c_baseanimating.cpp index 7bd1c737..7afc4d22 100644 --- a/sp/src/game/client/c_baseanimating.cpp +++ b/sp/src/game/client/c_baseanimating.cpp @@ -297,7 +297,7 @@ END_SCRIPTDESC(); ScriptHook_t C_BaseAnimating::g_Hook_OnClientRagdoll; ScriptHook_t C_BaseAnimating::g_Hook_FireEvent; -ScriptHook_t C_BaseAnimating::g_Hook_BuildTransformations; +//ScriptHook_t C_BaseAnimating::g_Hook_BuildTransformations; #endif BEGIN_ENT_SCRIPTDESC( C_BaseAnimating, C_BaseEntity, "Animating models client-side" ) @@ -367,8 +367,8 @@ BEGIN_ENT_SCRIPTDESC( C_BaseAnimating, C_BaseEntity, "Animating models client-si DEFINE_SCRIPTHOOK_PARAM( "options", FIELD_CSTRING ) END_SCRIPTHOOK() - BEGIN_SCRIPTHOOK( C_BaseAnimating::g_Hook_BuildTransformations, "BuildTransformations", FIELD_VOID, "Called when building bone transformations. Allows VScript to read/write any bone with Get/SetBoneTransform." ) - END_SCRIPTHOOK() + //BEGIN_SCRIPTHOOK( C_BaseAnimating::g_Hook_BuildTransformations, "BuildTransformations", FIELD_VOID, "Called when building bone transformations. Allows VScript to read/write any bone with Get/SetBoneTransform." ) + //END_SCRIPTHOOK() #endif END_SCRIPTDESC(); @@ -1779,21 +1779,21 @@ void C_BaseAnimating::BuildTransformations( CStudioHdr *hdr, Vector *pos, Quater } #ifdef MAPBASE_VSCRIPT - if (m_ScriptScope.IsInitialized() && g_Hook_BuildTransformations.CanRunInScope(m_ScriptScope)) - { - int oldWritableBones = m_BoneAccessor.GetWritableBones(); - int oldReadableBones = m_BoneAccessor.GetReadableBones(); - m_BoneAccessor.SetWritableBones( BONE_USED_BY_ANYTHING ); - m_BoneAccessor.SetReadableBones( BONE_USED_BY_ANYTHING ); - - // No parameters - //ScriptVariant_t args[] = {}; - //ScriptVariant_t returnValue; - g_Hook_BuildTransformations.Call( m_ScriptScope, NULL, NULL /*&returnValue, args*/ ); - - m_BoneAccessor.SetWritableBones( oldWritableBones ); - m_BoneAccessor.SetReadableBones( oldReadableBones ); - } + //if (m_ScriptScope.IsInitialized() && g_Hook_BuildTransformations.CanRunInScope(m_ScriptScope)) + //{ + // int oldWritableBones = m_BoneAccessor.GetWritableBones(); + // int oldReadableBones = m_BoneAccessor.GetReadableBones(); + // m_BoneAccessor.SetWritableBones( BONE_USED_BY_ANYTHING ); + // m_BoneAccessor.SetReadableBones( BONE_USED_BY_ANYTHING ); + // + // // No parameters + // //ScriptVariant_t args[] = {}; + // //ScriptVariant_t returnValue; + // g_Hook_BuildTransformations.Call( m_ScriptScope, NULL, NULL /*&returnValue, args*/ ); + // + // m_BoneAccessor.SetWritableBones( oldWritableBones ); + // m_BoneAccessor.SetReadableBones( oldReadableBones ); + //} #endif } diff --git a/sp/src/game/client/c_baseanimating.h b/sp/src/game/client/c_baseanimating.h index 0f2f57df..24e33a3b 100644 --- a/sp/src/game/client/c_baseanimating.h +++ b/sp/src/game/client/c_baseanimating.h @@ -491,7 +491,7 @@ public: static ScriptHook_t g_Hook_OnClientRagdoll; static ScriptHook_t g_Hook_FireEvent; - static ScriptHook_t g_Hook_BuildTransformations; + //static ScriptHook_t g_Hook_BuildTransformations; // UNDONE: Thread access issues float ScriptGetPoseParameter(const char* szName); #endif From 636898fd79783fbbe107a82cdd44ed583bd9e222 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sat, 23 Jul 2022 00:31:07 -0500 Subject: [PATCH 365/378] Updated README --- README | 1 + 1 file changed, 1 insertion(+) diff --git a/README b/README index 00242852..efa04881 100644 --- a/README +++ b/README @@ -128,6 +128,7 @@ Direct contributions: =-- https://github.com/mapbase-source/source-sdk-2013/pull/168 (Squirrel update) =-- https://github.com/mapbase-source/source-sdk-2013/pull/171 (VScript documentation sorting) =-- https://github.com/mapbase-source/source-sdk-2013/pull/173 (VScript fixes and optimizations) +=-- https://github.com/mapbase-source/source-sdk-2013/pull/192 (VScript hook manager and fixes) == Contributions from z33ky: =-- https://github.com/mapbase-source/source-sdk-2013/pull/21 (Various GCC/Linux compilation fixes) From 0cf49fbfa0f7b2cdaf6f1ee4548a5c2ac11739d4 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sun, 24 Jul 2022 19:21:05 -0500 Subject: [PATCH 366/378] Fixed filter_script not functioning properly --- sp/src/game/server/filters.cpp | 85 ++++++++++++++++++---------------- 1 file changed, 46 insertions(+), 39 deletions(-) diff --git a/sp/src/game/server/filters.cpp b/sp/src/game/server/filters.cpp index da5dd61f..704cf054 100644 --- a/sp/src/game/server/filters.cpp +++ b/sp/src/game/server/filters.cpp @@ -2157,118 +2157,125 @@ class CFilterScript : public CBaseFilter public: bool PassesFilterImpl( CBaseEntity *pCaller, CBaseEntity *pEntity ) { - if ( m_ScriptScope.IsInitialized() && g_Hook_PassesFilter.CanRunInScope( m_ScriptScope ) ) + if ( !m_ScriptScope.IsInitialized() ) + { + Warning( "%s: No script scope, cannot filter\n", GetDebugName() ); + return false; + } + + if ( g_Hook_PassesFilter.CanRunInScope( m_ScriptScope ) ) { // caller, activator ScriptVariant_t functionReturn; ScriptVariant_t args[] = { ToHScript( pCaller ), ToHScript( pEntity ) }; - if ( !g_Hook_PassesFilter.Call( m_ScriptScope, &functionReturn, args ) ) - { - Warning( "%s: No PassesFilter function\n", GetDebugName() ); - } + g_Hook_PassesFilter.Call( m_ScriptScope, &functionReturn, args ); return functionReturn.m_bool; } - Warning("%s: No script scope, cannot filter\n", GetDebugName()); + Warning( "%s: No PassesFilter function\n", GetDebugName() ); return false; } bool PassesDamageFilterImpl( CBaseEntity *pCaller, const CTakeDamageInfo &info ) { - if ( m_ScriptScope.IsInitialized() && g_Hook_PassesDamageFilter.CanRunInScope( m_ScriptScope ) ) + if ( !m_ScriptScope.IsInitialized() ) + { + Warning( "%s: No script scope, cannot filter\n", GetDebugName() ); + return false; + } + + if ( g_Hook_PassesDamageFilter.CanRunInScope( m_ScriptScope ) ) { HSCRIPT pInfo = g_pScriptVM->RegisterInstance( const_cast(&info) ); // caller, info ScriptVariant_t functionReturn; ScriptVariant_t args[] = { ToHScript( pCaller ), pInfo }; - if ( !g_Hook_PassesDamageFilter.Call( m_ScriptScope, &functionReturn, args ) ) - { - // Fall back to main filter function - g_pScriptVM->RemoveInstance( pInfo ); - return PassesFilterImpl( pCaller, info.GetAttacker() ); - } + g_Hook_PassesDamageFilter.Call( m_ScriptScope, &functionReturn, args ); g_pScriptVM->RemoveInstance( pInfo ); return functionReturn.m_bool; } - Warning("%s: No script scope, cannot filter\n", GetDebugName()); - return false; + // Fall back to main filter function + return PassesFilterImpl( pCaller, info.GetAttacker() ); } bool PassesFinalDamageFilter( CBaseEntity *pCaller, const CTakeDamageInfo &info ) { - if ( m_ScriptScope.IsInitialized() && g_Hook_PassesFinalDamageFilter.CanRunInScope( m_ScriptScope ) ) + if ( !m_ScriptScope.IsInitialized() ) + { + Warning( "%s: No script scope, cannot filter\n", GetDebugName() ); + return false; + } + + if ( g_Hook_PassesFinalDamageFilter.CanRunInScope( m_ScriptScope ) ) { HSCRIPT pInfo = g_pScriptVM->RegisterInstance( const_cast(&info) ); // caller, info ScriptVariant_t functionReturn; ScriptVariant_t args[] = { ToHScript( pCaller ), pInfo }; - if ( !g_Hook_PassesFinalDamageFilter.Call( m_ScriptScope, &functionReturn, args ) ) - { - g_pScriptVM->RemoveInstance( pInfo ); - return BaseClass::PassesFinalDamageFilter( pCaller, info ); - } + g_Hook_PassesFinalDamageFilter.Call( m_ScriptScope, &functionReturn, args ); g_pScriptVM->RemoveInstance( pInfo ); return functionReturn.m_bool; } - Warning("%s: No script scope, cannot filter\n", GetDebugName()); - return false; + return BaseClass::PassesFinalDamageFilter( pCaller, info ); } bool BloodAllowed( CBaseEntity *pCaller, const CTakeDamageInfo &info ) { - if ( m_ScriptScope.IsInitialized() && g_Hook_BloodAllowed.CanRunInScope( m_ScriptScope ) ) + if ( !m_ScriptScope.IsInitialized() ) + { + Warning( "%s: No script scope, cannot filter\n", GetDebugName() ); + return false; + } + + if ( g_Hook_BloodAllowed.CanRunInScope( m_ScriptScope ) ) { HSCRIPT pInfo = g_pScriptVM->RegisterInstance( const_cast(&info) ); // caller, info ScriptVariant_t functionReturn; ScriptVariant_t args[] = { ToHScript( pCaller ), pInfo }; - if ( !g_Hook_BloodAllowed.Call( m_ScriptScope, &functionReturn, args ) ) - { - g_pScriptVM->RemoveInstance( pInfo ); - return BaseClass::BloodAllowed( pCaller, info ); - } + g_Hook_BloodAllowed.Call( m_ScriptScope, &functionReturn, args ); g_pScriptVM->RemoveInstance( pInfo ); return functionReturn.m_bool; } - Warning("%s: No script scope, cannot filter\n", GetDebugName()); - return false; + return BaseClass::BloodAllowed( pCaller, info ); } bool DamageMod( CBaseEntity *pCaller, CTakeDamageInfo &info ) { - if ( m_ScriptScope.IsInitialized() && g_Hook_DamageMod.CanRunInScope( m_ScriptScope ) ) + if ( !m_ScriptScope.IsInitialized() ) + { + Warning( "%s: No script scope, cannot filter\n", GetDebugName() ); + return false; + } + + if ( g_Hook_DamageMod.CanRunInScope( m_ScriptScope ) ) { HSCRIPT pInfo = g_pScriptVM->RegisterInstance( &info ); // caller, info ScriptVariant_t functionReturn; ScriptVariant_t args[] = { ToHScript( pCaller ), pInfo }; - if ( !g_Hook_DamageMod.Call( m_ScriptScope, &functionReturn, args ) ) - { - g_pScriptVM->RemoveInstance( pInfo ); - return BaseClass::DamageMod( pCaller, info ); - } + g_Hook_DamageMod.Call( m_ScriptScope, &functionReturn, args ); g_pScriptVM->RemoveInstance( pInfo ); return functionReturn.m_bool; } - Warning("%s: No script scope, cannot filter\n", GetDebugName()); - return false; + return BaseClass::DamageMod( pCaller, info ); } }; From 9a939547c05daba34e64299324ee7e54a71fd99c Mon Sep 17 00:00:00 2001 From: Blixibon Date: Tue, 26 Jul 2022 12:54:01 -0500 Subject: [PATCH 367/378] Fixed rare activity translation recursion case --- sp/src/game/server/ai_basenpc.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sp/src/game/server/ai_basenpc.cpp b/sp/src/game/server/ai_basenpc.cpp index 6f8b7bcd..c503a09c 100644 --- a/sp/src/game/server/ai_basenpc.cpp +++ b/sp/src/game/server/ai_basenpc.cpp @@ -2598,11 +2598,7 @@ bool CAI_BaseNPC::FValidateHintType ( CAI_Hint *pHint ) Activity CAI_BaseNPC::GetHintActivity( short sHintType, Activity HintsActivity ) { if ( HintsActivity != ACT_INVALID ) -#ifdef MAPBASE - return TranslateActivity( HintsActivity ); // Always translate the activity -#else return HintsActivity; -#endif return ACT_IDLE; } From 8e90e6df58de6ba9ae5ab809443df79397adfd8c Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sat, 6 Aug 2022 13:08:32 -0500 Subject: [PATCH 368/378] Fixed commentary localization file not loading properly --- sp/src/game/client/c_point_commentary_node.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sp/src/game/client/c_point_commentary_node.cpp b/sp/src/game/client/c_point_commentary_node.cpp index cd0c77eb..7ff47f24 100644 --- a/sp/src/game/client/c_point_commentary_node.cpp +++ b/sp/src/game/client/c_point_commentary_node.cpp @@ -248,7 +248,7 @@ public: #ifdef MAPBASE // Special commentary localization file (useful for things like text nodes or print names) - g_pVGuiLocalize->AddFile( "resource/commentary_%language%.txt" ); + g_pVGuiLocalize->AddFile( "resource/commentary_%language%.txt", "MOD", true ); #endif } From 5369953d6019e7e49069fe92f365b86d84e968e5 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sat, 6 Aug 2022 13:11:01 -0500 Subject: [PATCH 369/378] Fixed NPCs being unable to open doors with hardware not defined in the QC --- sp/src/game/server/props.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sp/src/game/server/props.cpp b/sp/src/game/server/props.cpp index c643dd68..78675b7a 100644 --- a/sp/src/game/server/props.cpp +++ b/sp/src/game/server/props.cpp @@ -4478,6 +4478,13 @@ void CBasePropDoor::CalcDoorSounds() #endif } +#ifdef MAPBASE + // This would still be -1 if the hardware wasn't valid + if (m_flNPCOpenDistance == -1) + m_flNPCOpenDistance = ai_door_enable_acts.GetBool() ? 32.0 : 64.0; +#endif + + // If any sounds were missing, try the "defaults" block. if ( ( strSoundOpen == NULL_STRING ) || ( strSoundClose == NULL_STRING ) || ( strSoundMoving == NULL_STRING ) || ( strSoundLocked == NULL_STRING ) || ( strSoundUnlocked == NULL_STRING ) ) From 1cff3a2cd0a9f91e25f4e677bdb2af492d292c0e Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sat, 6 Aug 2022 14:46:34 -0500 Subject: [PATCH 370/378] Fixed RPG readiness activities being marked as required --- sp/src/game/server/hl2/weapon_rpg.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sp/src/game/server/hl2/weapon_rpg.cpp b/sp/src/game/server/hl2/weapon_rpg.cpp index 645ca8e6..1ffc0326 100644 --- a/sp/src/game/server/hl2/weapon_rpg.cpp +++ b/sp/src/game/server/hl2/weapon_rpg.cpp @@ -1405,9 +1405,16 @@ acttable_t CWeaponRPG::m_acttable[] = { ACT_GESTURE_RANGE_ATTACK1, ACT_GESTURE_RANGE_ATTACK_RPG, false }, #endif +#ifdef MAPBASE + // Readiness activities should not be required + { ACT_IDLE_RELAXED, ACT_IDLE_RPG_RELAXED, false }, + { ACT_IDLE_STIMULATED, ACT_IDLE_ANGRY_RPG, false }, + { ACT_IDLE_AGITATED, ACT_IDLE_ANGRY_RPG, false }, +#else { ACT_IDLE_RELAXED, ACT_IDLE_RPG_RELAXED, true }, { ACT_IDLE_STIMULATED, ACT_IDLE_ANGRY_RPG, true }, { ACT_IDLE_AGITATED, ACT_IDLE_ANGRY_RPG, true }, +#endif { ACT_IDLE, ACT_IDLE_RPG, true }, { ACT_IDLE_ANGRY, ACT_IDLE_ANGRY_RPG, true }, From 392746f725fdced9c393c3916435ac3d68843a1f Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sun, 28 Aug 2022 13:03:59 -0500 Subject: [PATCH 371/378] Fixed typo in vscript_server.nut --- sp/src/game/server/vscript_server.nut | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sp/src/game/server/vscript_server.nut b/sp/src/game/server/vscript_server.nut index 0a2d75d7..ad48da19 100644 --- a/sp/src/game/server/vscript_server.nut +++ b/sp/src/game/server/vscript_server.nut @@ -93,7 +93,7 @@ function __ReplaceClosures( script, scope ) local tempParent = { getroottable = function() { return null; } }; local temp = { runscript = script }; - temp.set_delegate(tempParent); + temp.setdelegate(tempParent); temp.runscript() foreach( key,val in temp ) From deacb7df619d567ca0eb7fea1e5407205d6c12c8 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sun, 28 Aug 2022 13:06:08 -0500 Subject: [PATCH 372/378] Fixed VScript files from Mapbase manifests not being loaded properly --- sp/src/game/shared/mapbase/mapbase_shared.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sp/src/game/shared/mapbase/mapbase_shared.cpp b/sp/src/game/shared/mapbase/mapbase_shared.cpp index 47e83ada..43790ca5 100644 --- a/sp/src/game/shared/mapbase/mapbase_shared.cpp +++ b/sp/src/game/shared/mapbase/mapbase_shared.cpp @@ -473,7 +473,7 @@ public: void LoadFromValue( const char *value, int type, bool bDontWarn ) { - if (!filesystem->FileExists(value, "MOD")) + if (type != MANIFEST_VSCRIPT && !filesystem->FileExists(value, "MOD")) { if (!bDontWarn) { From 3c7d0f86b390d1d969f3d08299d4d114539e7e66 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sun, 28 Aug 2022 13:06:55 -0500 Subject: [PATCH 373/378] Fixed global state counters not being initialized --- sp/src/game/server/globalstate.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sp/src/game/server/globalstate.cpp b/sp/src/game/server/globalstate.cpp index 7ade7762..720e8906 100644 --- a/sp/src/game/server/globalstate.cpp +++ b/sp/src/game/server/globalstate.cpp @@ -131,6 +131,9 @@ public: entity.name = m_nameList.AddString( pGlobalname ); entity.levelName = m_nameList.AddString( pMapName ); entity.state = state; +#ifdef MAPBASE + entity.counter = 0; +#endif int index = GetIndex( m_nameList.String( entity.name ) ); if ( index >= 0 ) From 1426eccc68fb254bd8a3883f84aedc030a036441 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sun, 28 Aug 2022 13:08:28 -0500 Subject: [PATCH 374/378] Strengthened NaN head angle brute force workaround --- sp/src/game/server/ai_baseactor.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/sp/src/game/server/ai_baseactor.cpp b/sp/src/game/server/ai_baseactor.cpp index ddf3da70..df0a5aaa 100644 --- a/sp/src/game/server/ai_baseactor.cpp +++ b/sp/src/game/server/ai_baseactor.cpp @@ -1149,8 +1149,14 @@ void CAI_BaseActor::UpdateHeadControl( const Vector &vHeadTarget, float flHeadIn Warning( "================================================================================\n" "!!!!! %s tried to set a NaN head angle (can happen when look targets have >1 importance) !!!!!\n" "================================================================================\n", GetDebugName() ); - vTargetAngles.x = 0; - vTargetAngles.y = 0; + m_goalHeadCorrection.Init(); + Set( m_FlexweightHeadRightLeft, 0.0f ); + Set( m_FlexweightHeadUpDown, 0.0f ); + Set( m_FlexweightHeadTilt, 0.0f ); + Set( m_ParameterHeadYaw, 0.0f ); + Set( m_ParameterHeadPitch, 0.0f ); + Set( m_ParameterHeadRoll, 0.0f ); + return; } #endif From daf55037fe4f1ab04ff4db2367e8917628d3a08c Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sun, 28 Aug 2022 13:10:23 -0500 Subject: [PATCH 375/378] Added support for "mapspawn_addon" scripts in addon paths (inspired by L4D2) --- sp/src/game/client/vscript_client.cpp | 4 + sp/src/game/server/vscript_server.cpp | 2 + sp/src/game/shared/vscript_shared.cpp | 193 ++++++++++++++++++++++++-- sp/src/game/shared/vscript_shared.h | 2 + 4 files changed, 192 insertions(+), 9 deletions(-) diff --git a/sp/src/game/client/vscript_client.cpp b/sp/src/game/client/vscript_client.cpp index 1a5c59be..faf35c16 100644 --- a/sp/src/game/client/vscript_client.cpp +++ b/sp/src/game/client/vscript_client.cpp @@ -707,6 +707,10 @@ bool VScriptClientInit() VScriptRunScript( "vscript_client", true ); VScriptRunScript( "mapspawn", false ); +#ifdef MAPBASE_VSCRIPT + RunAddonScripts(); +#endif + VMPROF_SHOW( pszScriptLanguage, "virtual machine startup" ); return true; diff --git a/sp/src/game/server/vscript_server.cpp b/sp/src/game/server/vscript_server.cpp index 25c8281a..40e35f00 100644 --- a/sp/src/game/server/vscript_server.cpp +++ b/sp/src/game/server/vscript_server.cpp @@ -672,6 +672,8 @@ bool VScriptServerInit() VScriptRunScript( "mapspawn", false ); #ifdef MAPBASE_VSCRIPT + RunAddonScripts(); + // Since the world entity spawns before VScript is initted, RunVScripts() is called before the VM has started, so no scripts are run. // This gets around that by calling the same function right after the VM is initted. GetWorldEntity()->RunVScripts(); diff --git a/sp/src/game/shared/vscript_shared.cpp b/sp/src/game/shared/vscript_shared.cpp index 4f20b7c6..ec41c566 100644 --- a/sp/src/game/shared/vscript_shared.cpp +++ b/sp/src/game/shared/vscript_shared.cpp @@ -40,6 +40,15 @@ extern int vscript_token; int vscript_token_hack = vscript_token; #endif +static const char *pszExtensions[] = +{ + "", // SL_NONE + ".gm", // SL_GAMEMONKEY + ".nut", // SL_SQUIRREL + ".lua", // SL_LUA + ".py", // SL_PYTHON +}; + HSCRIPT VScriptCompileScript( const char *pszScriptName, bool bWarnMissing ) @@ -49,15 +58,6 @@ HSCRIPT VScriptCompileScript( const char *pszScriptName, bool bWarnMissing ) return NULL; } - static const char *pszExtensions[] = - { - "", // SL_NONE - ".gm", // SL_GAMEMONKEY - ".nut", // SL_SQUIRREL - ".lua", // SL_LUA - ".py", // SL_PYTHON - }; - const char *pszVMExtension = pszExtensions[g_pScriptVM->GetLanguage()]; const char *pszIncomingExtension = V_strrchr( pszScriptName , '.' ); if ( pszIncomingExtension && V_strcmp( pszIncomingExtension, pszVMExtension ) != 0 ) @@ -171,6 +171,113 @@ bool VScriptRunScript( const char *pszScriptName, HSCRIPT hScope, bool bWarnMiss } +#ifdef MAPBASE_VSCRIPT + +// +// These functions are currently only used for "mapspawn_addon" scripts. +// +HSCRIPT VScriptCompileScriptAbsolute( const char *pszScriptName, bool bWarnMissing, const char *pszRootFolderName ) +{ + if ( !g_pScriptVM ) + { + return NULL; + } + + const char *pszVMExtension = pszExtensions[g_pScriptVM->GetLanguage()]; + const char *pszIncomingExtension = V_strrchr( pszScriptName , '.' ); + if ( pszIncomingExtension && V_strcmp( pszIncomingExtension, pszVMExtension ) != 0 ) + { + CGWarning( 0, CON_GROUP_VSCRIPT, "Script file type does not match VM type\n" ); + return NULL; + } + + CFmtStr scriptPath; + if ( pszIncomingExtension ) + { + scriptPath = pszScriptName; + } + else + { + scriptPath.sprintf( "%s%s", pszScriptName, pszVMExtension ); + } + + const char *pBase; + CUtlBuffer bufferScript; + + if ( g_pScriptVM->GetLanguage() == SL_PYTHON ) + { + // python auto-loads raw or precompiled modules - don't load data here + pBase = NULL; + } + else + { + bool bResult = filesystem->ReadFile( scriptPath, NULL, bufferScript ); + + if ( !bResult && bWarnMissing ) + { + CGWarning( 0, CON_GROUP_VSCRIPT, "Script not found (%s) \n", scriptPath.operator const char *() ); + Assert( "Error running script" ); + } + + pBase = (const char *) bufferScript.Base(); + + if ( !pBase || !*pBase ) + { + return NULL; + } + } + + // Attach the folder to the script ID + const char *pszFilename = V_strrchr( scriptPath, '/' ); + scriptPath.sprintf( "%s%s", pszRootFolderName, pszFilename ); + + HSCRIPT hScript = g_pScriptVM->CompileScript( pBase, scriptPath ); + if ( !hScript ) + { + CGWarning( 0, CON_GROUP_VSCRIPT, "FAILED to compile and execute script file named %s\n", scriptPath.operator const char *() ); + Assert( "Error running script" ); + } + return hScript; +} + +bool VScriptRunScriptAbsolute( const char *pszScriptName, HSCRIPT hScope, bool bWarnMissing, const char *pszRootFolderName ) +{ + if ( !g_pScriptVM ) + { + return false; + } + + if ( !pszScriptName || !*pszScriptName ) + { + CGWarning( 0, CON_GROUP_VSCRIPT, "Cannot run script: NULL script name\n" ); + return false; + } + + // Prevent infinite recursion in VM + if ( g_ScriptServerRunScriptDepth > 16 ) + { + CGWarning( 0, CON_GROUP_VSCRIPT, "IncludeScript stack overflow\n" ); + return false; + } + + g_ScriptServerRunScriptDepth++; + HSCRIPT hScript = VScriptCompileScriptAbsolute( pszScriptName, bWarnMissing, pszRootFolderName ); + bool bSuccess = false; + if ( hScript ) + { + bSuccess = ( g_pScriptVM->Run( hScript, hScope ) != SCRIPT_ERROR ); + if ( !bSuccess ) + { + Warning( "Error running script named %s\n", pszScriptName ); + Assert( "Error running script" ); + } + } + g_ScriptServerRunScriptDepth--; + return bSuccess; +} +#endif + + #ifdef GAME_DLL #define IsCommandIssuedByServerAdmin() UTIL_IsCommandIssuedByServerAdmin() #else @@ -321,6 +428,74 @@ CON_COMMAND_F( script_dump_all, "Dump the state of the VM to the console", FCVAR //----------------------------------------------------------------------------- +#ifdef MAPBASE_VSCRIPT +void RunAddonScripts() +{ + char searchPaths[4096]; + filesystem->GetSearchPath( "ADDON", true, searchPaths, sizeof( searchPaths ) ); + + for ( char *path = strtok( searchPaths, ";" ); path; path = strtok( NULL, ";" ) ) + { + char folderName[MAX_PATH]; + Q_FileBase( path, folderName, sizeof( folderName ) ); + + // mapspawn_addon + char fullpath[MAX_PATH]; + Q_snprintf( fullpath, sizeof( fullpath ), "%sscripts/vscripts/mapspawn_addon", path ); + Q_FixSlashes( fullpath ); + + VScriptRunScriptAbsolute( fullpath, NULL, false, folderName ); + } +} + +// UNDONE: "autorun" folder +/* +void RunAutorunScripts() +{ + FileFindHandle_t fileHandle; + char szDirectory[MAX_PATH]; + char szFileName[MAX_PATH]; + char szPartialScriptPath[MAX_PATH]; + + // TODO: Scanning for VM extension would make this more efficient + Q_strncpy( szDirectory, "scripts/vscripts/autorun/*", sizeof( szDirectory ) ); + + const char *pszScriptFile = filesystem->FindFirst( szDirectory, &fileHandle ); + while (pszScriptFile && fileHandle != FILESYSTEM_INVALID_FIND_HANDLE) + { + Q_FileBase( pszScriptFile, szFileName, sizeof( szFileName ) ); + Q_snprintf( szPartialScriptPath, sizeof( szPartialScriptPath ), "autorun/%s", szFileName ); + VScriptRunScript( szPartialScriptPath ); + + pszScriptFile = filesystem->FindNext( fileHandle ); + } + + // Non-shared scripts +#ifdef CLIENT_DLL + Q_strncpy( szDirectory, "scripts/vscripts/autorun/client/*", sizeof( szDirectory ) ); +#else + Q_strncpy( szDirectory, "scripts/vscripts/autorun/server/*", sizeof( szDirectory ) ); +#endif + + pszScriptFile = filesystem->FindFirst( szDirectory, &fileHandle ); + while (pszScriptFile && fileHandle != FILESYSTEM_INVALID_FIND_HANDLE) + { + Q_FileBase( pszScriptFile, szFileName, sizeof( szFileName ) ); +#ifdef CLIENT_DLL + Q_snprintf( szPartialScriptPath, sizeof( szPartialScriptPath ), "autorun/client/%s", szFileName ); +#else + Q_snprintf( szPartialScriptPath, sizeof( szPartialScriptPath ), "autorun/server/%s", szFileName ); +#endif + VScriptRunScript( szPartialScriptPath ); + + pszScriptFile = filesystem->FindNext( fileHandle ); + } +} +*/ +#endif + +//----------------------------------------------------------------------------- + static short VSCRIPT_SERVER_SAVE_RESTORE_VERSION = 2; //----------------------------------------------------------------------------- diff --git a/sp/src/game/shared/vscript_shared.h b/sp/src/game/shared/vscript_shared.h index 8bf23d54..50834220 100644 --- a/sp/src/game/shared/vscript_shared.h +++ b/sp/src/game/shared/vscript_shared.h @@ -45,6 +45,8 @@ extern CBaseEntityScriptInstanceHelper g_BaseEntityScriptInstanceHelper; #ifdef MAPBASE_VSCRIPT void RegisterSharedScriptConstants(); void RegisterSharedScriptFunctions(); + +void RunAddonScripts(); #endif #endif // VSCRIPT_SHARED_H From be6277c2c8553aa0f22a52cc7ef080a0ad8f3d20 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sun, 2 Oct 2022 19:11:24 -0500 Subject: [PATCH 376/378] Fixed commentary node HUD alignment issues --- sp/src/game/client/c_point_commentary_node.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/sp/src/game/client/c_point_commentary_node.cpp b/sp/src/game/client/c_point_commentary_node.cpp index 7ff47f24..d8d9ad4c 100644 --- a/sp/src/game/client/c_point_commentary_node.cpp +++ b/sp/src/game/client/c_point_commentary_node.cpp @@ -120,6 +120,7 @@ private: // HACKHACK: Needed as a failsafe to prevent desync int m_iCCDefaultY; + float m_flCCAnimTime; bool m_bShouldRepositionSubtitles; #endif @@ -910,6 +911,7 @@ CHudCommentary::CHudCommentary( const char *name ) : vgui::Panel( NULL, "HudComm m_pFootnoteLabel = new vgui::Label( this, "HudCommentaryFootnoteLabel", L"Commentary footnote" ); m_iCCDefaultY = 0; + m_flCCAnimTime = 0.0f; #endif } @@ -1415,6 +1417,9 @@ void CHudCommentary::StartCommentary( C_PointCommentaryNode *pNode, char *pszSpe { m_bShouldPaint = true; m_bShouldRepositionSubtitles = true; + + // Ensure we perform layout later + InvalidateLayout(); } else m_bShouldRepositionSubtitles = false; @@ -1634,6 +1639,9 @@ void CHudCommentary::StartSceneCommentary( C_PointCommentaryNode *pNode, char *p { m_bShouldPaint = true; m_bShouldRepositionSubtitles = true; + + // Ensure we perform layout later + InvalidateLayout(); } else m_bShouldRepositionSubtitles = false; @@ -1781,9 +1789,17 @@ void CHudCommentary::RepositionAndFollowCloseCaption( int yOffset ) // Run this animation command instead of setting the position directly g_pClientMode->GetViewportAnimationController()->RunAnimationCommand( pHudCloseCaption, "YPos", ccY - yOffset, 0.0f, 0.2f, vgui::AnimationController::INTERPOLATOR_DEACCEL ); //pHudCloseCaption->SetPos( ccX, ccY ); + m_flCCAnimTime = gpGlobals->curtime + 0.2f; pHudCloseCaption->SetUsingCommentaryDimensions( true ); } + else if (gpGlobals->curtime > m_flCCAnimTime && ccY != m_iCCDefaultY - m_iTypeAudioT - yOffset) + { + DevMsg( "CHudCommentary had to correct misaligned CC element offset (%i != %i)\n", m_iCCDefaultY - ccY, yOffset ); + + g_pClientMode->GetViewportAnimationController()->RunAnimationCommand( pHudCloseCaption, "YPos", m_iCCDefaultY - m_iTypeAudioT - yOffset, 0.0f, 0.2f, vgui::AnimationController::INTERPOLATOR_DEACCEL ); + m_flCCAnimTime = gpGlobals->curtime + 0.2f; + } SetPos( ccX, ccY + pHudCloseCaption->GetTall() + commentary_audio_element_below_cc_margin.GetInt() ); From c31e48591f7ffd7289b7e30019825ee4fead3055 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sun, 2 Oct 2022 19:12:42 -0500 Subject: [PATCH 377/378] Fixed crash from TestEntity on filters --- sp/src/game/server/filters.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sp/src/game/server/filters.cpp b/sp/src/game/server/filters.cpp index 704cf054..c15f8eee 100644 --- a/sp/src/game/server/filters.cpp +++ b/sp/src/game/server/filters.cpp @@ -134,6 +134,12 @@ void CBaseFilter::InputTestActivator( inputdata_t &inputdata ) //----------------------------------------------------------------------------- void CBaseFilter::InputTestEntity( inputdata_t &inputdata ) { + if ( !inputdata.value.Entity() ) + { + // HACKHACK: Not firing OnFail in this case is intentional for the time being (activator shouldn't be null) + return; + } + if ( PassesFilter( inputdata.pCaller, inputdata.value.Entity() ) ) { m_OnPass.FireOutput( inputdata.value.Entity(), m_bPassCallerWhenTested ? inputdata.pCaller : this ); From f5633dcc756d960b7fd6456dd9936def655030b1 Mon Sep 17 00:00:00 2001 From: Blixibon Date: Sun, 2 Oct 2022 19:23:22 -0500 Subject: [PATCH 378/378] Updated README --- README | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README b/README index efa04881..d5ca32ee 100644 --- a/README +++ b/README @@ -101,8 +101,8 @@ interchangeable arms; this may change in the future) Direct contributions: +- https://github.com/mapbase-source/source-sdk-2013/pull/3 ("playvideo" command playback fix from Avanate) - https://github.com/mapbase-source/source-sdk-2013/pull/5 (Custom VScript implementation by ReDucTor; was placed into feature branch before being merged in a subsequent PR) -- https://github.com/mapbase-source/source-sdk-2013/pull/3 ("playvideo" command playback fix from Avantate) - https://github.com/mapbase-source/source-sdk-2013/pull/60 (Adjustment by RoyaleNoir to one of Saul's VDC changes) - https://github.com/mapbase-source/source-sdk-2013/pull/84 (CS:S viewmodel chirality from 1upD) - https://github.com/mapbase-source/source-sdk-2013/pull/116 (vgui_movie_display mute keyvalue from Alivebyte/rzkid) @@ -180,6 +180,10 @@ Other relevant articles: * https://github.com/mapbase-source/source-sdk-2013/wiki/Mapbase-Disclaimers * https://github.com/mapbase-source/source-sdk-2013/wiki/Frequently-Asked-Questions-(FAQ) +//--------------------------------------------------------------------------------------------------------------------------------------------------- + +In memory of Holly Liberatore (moofemp) + //=================================================================================================================================================== Please see the Source SDK 2013 license below: