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 a1c1e85613..e3744752bd 100644 --- a/sp/src/public/vscript/ivscript.h +++ b/sp/src/public/vscript/ivscript.h @@ -863,6 +863,15 @@ class IScriptVM //-------------------------------------------------------- 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 2c80041b21..e671f5ff0a 100644 --- a/sp/src/vscript/vscript_squirrel.cpp +++ b/sp/src/vscript/vscript_squirrel.cpp @@ -161,6 +161,13 @@ class SquirrelVM : public IScriptVM //-------------------------------------------------------- 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 cb929807fe..bae6bd0da9 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 | 135 +- 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, 11052 insertions(+), 59 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 29e5acc675..daf5bf4181 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 243324f12a..a6d7fe29b1 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 81ddc16959..5327785810 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 @@ class AI_Response }; #endif // AI_CRITERIA_H +#endif diff --git a/sp/src/game/server/ai_baseactor.cpp b/sp/src/game/server/ai_baseactor.cpp index 2ddc60f722..0994082951 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 6333ed86ea..ad17477857 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 c37ba2fc35..284a315ae2 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 2104b1f2ca..ef4bb0253a 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 0000000000..ff49d535f4 --- /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 25673612ce..43b82ed4f8 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 dc9948ce96..93448ec790 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 5ed1225550..99f2862470 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 0000000000..f6cfaaaabd --- /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 0000000000..02501c180c --- /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 0000000000..46779ad64b --- /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 0000000000..15101b70b3 --- /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 7284d0d208..dff5ee7fbc 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 ); +#endif m_ResponseContexts[iIndex].m_fExpirationTime = duration; - return; } + else + { + ResponseContext_t newContext; + newContext.m_iszName = AllocPooledString( name ); - ResponseContext_t newContext; - newContext.m_iszName = AllocPooledString( name ); - newContext.m_iszValue = AllocPooledString( value ); - newContext.m_fExpirationTime = duration; +#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 ); + m_ResponseContexts.AddToTail( newContext ); + } } -#endif //----------------------------------------------------------------------------- // 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 a9c69ca329..358f2037c9 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 @@ class CBaseEntity : public IServerEntity 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 @@ class CBaseEntity : public IServerEntity #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 215b13f55a..ec809534af 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 b6ecd44c46..d5a99514a7 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 06a0e00ded..9550a86ac9 100644 --- a/sp/src/game/server/basemultiplayerplayer.h +++ b/sp/src/game/server/basemultiplayerplayer.h @@ -28,7 +28,7 @@ class CBaseMultiplayerPlayer : public CAI_ExpresserHost 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 9a4f09e6d9..288e93a075 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 ffb8dd9648..8dc5ec4008 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 7b193a9b7d..25a65017c6 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 7599a6ac33..d4ce19ac33 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 8588c04370..3efb974125 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 382e2dd2ec..2191b39436 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 6914fd1904..92914d05d3 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 6e005a60bf..a004c3e1e1 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 df35da1e6d..64558734d2 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 3714623806..b4672f196b 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 0000000000..31a5b1eff0 --- /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 0000000000..b5d2c4fd67 --- /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 0000000000..80cbcca60b --- /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 0000000000..a558f79e70 --- /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 0000000000..c0ae8e36b0 --- /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 0000000000..41a3cc60b8 --- /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 34a1caf898..b25bb1724a 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 0000000000..fa39bd88cc --- /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 0000000000..2e7472c25b --- /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 0000000000..65b1bb6e60 --- /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 e8387b56b8..a6d1a1a671 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 0e5a34284e..422a006f42 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 0000000000..3dc5cb2002 --- /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 0000000000..9ab73afaa1 --- /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 0000000000..afdc40ef74 --- /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 0000000000..5fec10ded1 --- /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 0000000000..f18d02f356 --- /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 0000000000..2d11bdd2c4 --- /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 0000000000..99e766fe1f --- /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 0000000000..986ae0cd41 --- /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 0000000000..a1ff5a8b96 --- /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 0000000000..7e1e04abf3 --- /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 0000000000..e7af74deef --- /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 0000000000..0d2c49fd7c --- /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 0000000000..4199359f20 --- /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 d7012f3ee5..1715831740 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 7354a28ef3..2ab187faaf 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 17f0440e78..fdfcc57e79 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 acf7c9b85f..66530a33b7 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 a34255b26a..0b0b633405 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 ff49d535f4..84db4773e5 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 ); + +#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 gEntList.FindEntityByName( NULL, subject ); + 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 f6cfaaaabd..a7c4ac729e 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 02501c180c..e3c895beb1 100644 --- a/sp/src/game/server/ai_speech_new.h +++ b/sp/src/game/server/ai_speech_new.h @@ -178,6 +178,11 @@ class CAI_Expresser : public ResponseRules::IResponseFilter 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 @@ class CAI_Expresser : public ResponseRules::IResponseFilter 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 @@ class CAI_Expresser : public ResponseRules::IResponseFilter // 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 46779ad64b..79794d4bdc 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 2e7472c25b..821b0c5737 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 afdc40ef74..f517c5a6db 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 5fec10ded1..9849b5a9f3 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 @@ namespace ResponseRules 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 a1ff5a8b96..6124805c0f 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 f517c5a6db..94660c5890 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 80cbcca60b..efa6d27c9e 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 @@ class CDefaultResponseSystem : public CGameResponseSystem, public CAutoGameSyste 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 @@ class CDefaultResponseSystemSaveRestoreBlockHandler : public CDefSaveRestoreBloc 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 @@ class CDefaultResponseSystemSaveRestoreBlockHandler : public CDefSaveRestoreBloc 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 94660c5890..37d5f0d976 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 2d11bdd2c4..72e7eca567 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 99e766fe1f..5222c80d7b 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 efa6d27c9e..e703775ffa 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 821b0c5737..4ec62cee85 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 5222c80d7b..20cc9d5412 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 a7c4ac729e..f04e6d2b5e 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 e3c895beb1..fec4f8c2f4 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 dff5ee7fbc..5302ee6ab6 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 25a65017c6..ad46a25c85 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 d5a99514a7..d75ec6279e 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 f1f1d26b17..b8b915f490 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 52e8cc1a28..7d86ad636a 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 0000000000..74b2cbc919 --- /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 37d5f0d976..60fedddba7 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 0000000000..5f10814e77 --- /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 1715831740..3d47526acf 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 60fedddba7..15950b079c 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 9849b5a9f3..b675e8167a 100644 --- a/sp/src/responserules/runtime/response_system.h +++ b/sp/src/responserules/runtime/response_system.h @@ -241,6 +241,10 @@ namespace ResponseRules 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 15950b079c..7867bda0cf 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 e703775ffa..4dbf822289 100644 --- a/sp/src/game/shared/ai_responsesystem_new.cpp +++ b/sp/src/game/shared/ai_responsesystem_new.cpp @@ -1078,7 +1078,6 @@ class CDefaultResponseSystemSaveRestoreBlockHandler : public CDefSaveRestoreBloc 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 4ec62cee85..a3e8fea3a4 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 6124805c0f..3be0710ec1 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 a3b4037812..a7bb37a4f0 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 aac399d734..111328620d 100644 --- a/sp/src/game/client/glow_outline_effect.h +++ b/sp/src/game/client/glow_outline_effect.h @@ -150,6 +150,10 @@ class CGlowObjectManager 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 1b71f9fd3b..63c964394d 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 c5e514996d..412723b1a8 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 @@ class CScriptConCommand : public ICommandCallback, public ICommandCompletionCall ~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 @@ class CScriptConCommand : public ICommandCallback, public ICommandCompletionCall { 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 @@ class CScriptConCommand : public ICommandCallback, public ICommandCompletionCall 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 @@ class CScriptConCommand : public ICommandCallback, public ICommandCompletionCall { if (fn) { - if ( !m_cmd->IsRegistered() ) + if ( !m_pBase->IsRegistered() ) Register(); if ( m_hCallback ) @@ -2283,8 +2293,8 @@ class CScriptConCommand : public ICommandCallback, public ICommandCompletionCall 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 @@ class CScriptConCommand : public ICommandCallback, public ICommandCompletionCall 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 @@ class CScriptConVar ~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 @@ class CScriptConvarAccessor : public CAutoGameSystem 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 @@ class CScriptConvarAccessor : public CAutoGameSystem 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 @@ class CScriptConvarAccessor : public CAutoGameSystem 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 @@ class CScriptConvarAccessor : public CAutoGameSystem } 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 @@ class CEffectsScriptHelper 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 c49a6efbc4..fc27eb74e0 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 dabfbbd9d6..f2170be4b0 100644 --- a/sp/src/game/client/c_baseentity.h +++ b/sp/src/game/client/c_baseentity.h @@ -400,7 +400,7 @@ class C_BaseEntity : public IClientEntity #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 8a2d961722..ec01575bb8 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 2cad41ca88..b413d282ea 100644 --- a/sp/src/game/client/c_baselesson.h +++ b/sp/src/game/client/c_baselesson.h @@ -426,7 +426,7 @@ class CScriptedIconLesson : public CIconLesson 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 00c97c66e4..14ae908caa 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 8f0d4c0c0a..8479b07e92 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 06799325b5..69939dbb84 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 0f47432381..135ad7f98e 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 84ae23b9b2..0ffc68f5c4 100644 --- a/sp/src/game/server/hl2/hl2_player.h +++ b/sp/src/game/server/hl2/hl2_player.h @@ -303,7 +303,7 @@ class CHL2_Player : public CBasePlayer 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 b28189f74a..c13117f56c 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 31341fb9be..edd304091a 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 314ee011c2..37268cc474 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 4b3388df76..b2750f5c6b 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 @@ class IScriptManager : public IAppSystem // //----------------------------------------------------------------------------- -#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 @@ class IScriptVM #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 cb01280e69..08ca8fc703 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 af605ea112..0ec23b9760 100644 --- a/sp/src/vscript/vscript_squirrel.cpp +++ b/sp/src/vscript/vscript_squirrel.cpp @@ -241,7 +241,7 @@ class SquirrelVM : public IScriptVM 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 559ee2beb6..6eda689086 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 6eda689086..21147f214f 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 7ba162147a..9b13fc8142 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 cceb804354..406c3e1385 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 99ac791488..d24ac04b0e 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 e23a9fe9d5..2d7058a3dd 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 84db4773e5..838be4ee06 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 f04e6d2b5e..1edffdb7a6 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 7867bda0cf..968f856ddd 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 72e7eca567..fe6d7fd023 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 20cc9d5412..25b6f2d12e 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 838be4ee06..759f5c46ac 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 79794d4bdc..7e8bf05548 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 92914d05d3..1ff2b18e8a 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 af605ea112..e24abb9bfa 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 | 160 ++++++++++------------- 3 files changed, 79 insertions(+), 101 deletions(-) diff --git a/sp/src/game/client/c_baseentity.h b/sp/src/game/client/c_baseentity.h index dabfbbd9d6..396cd3f0da 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 @@ class C_BaseEntity : public IClientEntity 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 a96d443bdd..fc8d232e24 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 @@ class CBaseEntity : public IServerEntity 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 cae3f5d92f..207f454411 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 + { + // 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 0f4e6a3543..52147fb3aa 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 2a2ad03c65..9eaf233266 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 290e3b25aa..2b00af39ed 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 7e299fc59b..d5c8b41636 100644 --- a/sp/src/game/server/hl2/item_battery.cpp +++ b/sp/src/game/server/hl2/item_battery.cpp @@ -23,12 +23,12 @@ class CItemBattery : public CItem 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 @@ class CItemBattery : public CItem 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 628f873e68..54f961c75d 100644 --- a/sp/src/game/server/hl2/item_healthkit.cpp +++ b/sp/src/game/server/hl2/item_healthkit.cpp @@ -30,11 +30,29 @@ class CHealthKit : public CItem 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 @@ class CHealthVial : public CItem 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 @@ class CHealthVial : public CItem 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 2089fa1fb3..53f440e8be 100644 --- a/sp/src/game/server/items.h +++ b/sp/src/game/server/items.h @@ -90,9 +90,12 @@ class CItem : public CBaseAnimating, public CDefaultPlayerPickupVPhysics #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 d3902db3b3..b3134460ab 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 0000000000..3db01c242e --- /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 0000000000..9b7c965289 --- /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 0000000000..ceff056355 --- /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 0000000000..d6701fc738 --- /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 0000000000..9b9a843d09 --- /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 0000000000..ef6a680c63 --- /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 0000000000..d6701fc738 --- /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 0000000000..9b9a843d09 --- /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 0000000000..ef6a680c63 --- /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 40d641439e..d6a8480d06 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 50c66a923a..dccaf2a507 100644 --- a/sp/src/game/client/vscript_client.cpp +++ b/sp/src/game/client/vscript_client.cpp @@ -165,6 +165,8 @@ class CScriptMaterialProxy : public IMaterialProxy, public IClientScriptPersista 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 0ec23b9760..afb466f6d2 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 c5e514996d..47e26bb021 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 @@ class CScriptReadWriteFile : public CAutoGameSystem } 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 450faf7877..636b7c6e2d 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 3d82108148..204b412b1c 100644 --- a/sp/src/game/client/c_rope.h +++ b/sp/src/game/client/c_rope.h @@ -33,6 +33,9 @@ class C_RopeKeyframe : public C_BaseEntity DECLARE_CLASS( C_RopeKeyframe, C_BaseEntity ); DECLARE_CLIENTCLASS(); +#ifdef MAPBASE_VSCRIPT + DECLARE_ENT_SCRIPTDESC(); +#endif private: @@ -142,6 +145,11 @@ class C_RopeKeyframe : public C_BaseEntity 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 @@ class C_RopeKeyframe : public C_BaseEntity 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 edd304091a..5d4675c5d5 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 fed3ea1ba8..9fb186c22e 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 b2a8ddcc63..6f64a15d83 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 0f26c2522e..7efac5261d 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. + // 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()) + { + // Unused Weighting + case 2: + bShouldSwitch = g_pGameRules->FShouldSwitchWeapon( this, pWeapon ); + break; - if ( !PlayerHasMegaPhysCannon() ) - { - Weapon_Switch( pWeapon ); + // 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 76166b1ba4..b6aa50623e 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 1edffdb7a6..76735a9def 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 5aff896f64..e93add3c9f 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 @@ class CMapbaseSystem : public CAutoGameSystem 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 cdd955c970..7346092e8d 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 08ca8fc703..65bcd21ddb 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" ); + + pGroupRoot->LoadFromFile( filesystem, pszFileName, pathID ); + + 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() ); + } + } -ConVar con_group_include_name( "con_group_include_name", "0", FCVAR_NONE, "Includes groups when printing." ); + pGroupRoot->deleteThis(); +} + +void InitConsoleGroups( IBaseFileSystem *filesystem ) +{ + LoadConsoleGroupsFromFile( filesystem, "scripts/mapbase_con_groups.txt", "MOD" ); + LoadConsoleGroupsFromFile( filesystem, "scripts/mod_con_groups.txt", "MOD" ); +} -CON_COMMAND( con_group_list, "Prints a list of all console groups." ) +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 SetConsoleGroupIncludeNames( bool bToggle ) +{ + g_bIncludeConGroupNames = bToggle; } -*/ -void CGMsg( int level, int nGroup, const tchar* pMsg, ... ) +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- + +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 3dc5cb2002..6d53e95455 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 968f856ddd..156bd45f85 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 f18d02f356..1d8f6b311d 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 3be0710ec1..b652e8b377 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 44f559b0c2..263325515a 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 336ff622cd..13c4775a6f 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 a6d1a1a671..9bcaf90eca 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 fe6d7fd023..098801c452 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 bbe1f9d013..5d13c5e6c3 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 afb466f6d2..a2de0a96c0 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 76735a9def..e886ab8f1b 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 d908b15cc5..8da332cd0e 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 310083536d..30e1f69783 100644 --- a/sp/src/game/server/episodic/npc_magnusson.cpp +++ b/sp/src/game/server/episodic/npc_magnusson.cpp @@ -37,6 +37,11 @@ class CNPC_Magnusson : public CAI_BaseActor 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 551460b296..266dca6d8e 100644 --- a/sp/src/game/server/hl2/npc_alyx.h +++ b/sp/src/game/server/hl2/npc_alyx.h @@ -36,6 +36,9 @@ class CNPC_Alyx : public CNPC_PlayerCompanion // 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 9e72fd8de5..6d4eb67b17 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 @@ class CNPC_Alyx : public CNPC_PlayerCompanion #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 02afce18cf..93ca92f048 100644 --- a/sp/src/game/server/hl2/npc_barney.cpp +++ b/sp/src/game/server/hl2/npc_barney.cpp @@ -81,6 +81,11 @@ class CNPC_Barney : public CNPC_PlayerCompanion 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 e12bab0c2b..e1409c80cc 100644 --- a/sp/src/game/server/hl2/npc_breen.cpp +++ b/sp/src/game/server/hl2/npc_breen.cpp @@ -34,6 +34,11 @@ class CNPC_Breen : public CAI_BaseActor 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 4b42c6c0a7..c66e927310 100644 --- a/sp/src/game/server/hl2/npc_eli.cpp +++ b/sp/src/game/server/hl2/npc_eli.cpp @@ -37,6 +37,11 @@ class CNPC_Eli : public CAI_BaseActor 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 e808176205..4e5e5cf8ed 100644 --- a/sp/src/game/server/hl2/npc_kleiner.cpp +++ b/sp/src/game/server/hl2/npc_kleiner.cpp @@ -35,6 +35,11 @@ class CNPC_Kleiner : public CAI_BaseActor 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 ff924cd256..f92a8f51d9 100644 --- a/sp/src/game/server/hl2/npc_mossman.cpp +++ b/sp/src/game/server/hl2/npc_mossman.cpp @@ -41,6 +41,11 @@ class CNPC_Mossman : public CAI_PlayerAlly 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 e0da23d3f3..5c281d59fa 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 @@ class CNPC_Vortigaunt : public CNPC_PlayerCompanion // 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 c48803aefa..4bbb96d2c9 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 c78cddb2bc..a74bb46ea3 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 4ac6f31ed6..81aa16bc63 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 6733fc56e4..9a4af817fd 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 c3e39af82b..fcefa3f965 100644 --- a/sp/src/game/shared/beam_shared.cpp +++ b/sp/src/game/shared/beam_shared.cpp @@ -42,6 +42,9 @@ class CInfoTarget : public CPointEntity 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 65bcd21ddb..5f23b3f8b2 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 47e26bb021..ba2f484a58 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 39998e4ba4..bfd4f5a2e7 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 | 6 +++--- .../stdshaders/SDK_windowimposter_vs20.fxc | 6 +++--- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/sp/src/materialsystem/stdshaders/SDK_teeth_bump_vs20.fxc b/sp/src/materialsystem/stdshaders/SDK_teeth_bump_vs20.fxc index 1dd834b524..ddca526a8f 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 fc3ea25a63..8863683eba 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; + float4 worldPos_projPosZ : TEXCOORD1; // Necessary for pixel fog + #if PARALLAXCORRECT - float3 worldSpaceNormal : TEXCOORD1; + float3 worldSpaceNormal : TEXCOORD2; #endif - - float4 worldPos_projPosZ : TEXCOORD2; // Necessary for pixel fog }; 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 f67676ee37..3a6a933484 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; + float4 worldPos_projPosZ : TEXCOORD1; // Necessary for pixel fog + #if PARALLAXCORRECT - float3 worldNormal : TEXCOORD1; + float3 worldNormal : TEXCOORD2; #endif - - float4 worldPos_projPosZ : TEXCOORD2; // Necessary for pixel fog }; 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 12ecc545af..bf8b01e1dc 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 e93add3c9f..05872b4e6d 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 874645e16e..a39ac5701a 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 3efb974125..bf56dc78a3 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 f417175fcd..3295c1b985 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 3457b05420..0fc3d0e016 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 3295c1b985..93efddc79a 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 f230e99f1c..758f4719e2 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 288e93a075..c5ad733d8b 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 a33dd438ff..264fdb3d20 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 @@ class CAI_ActBusyBehavior : public CAI_SimpleBehavior 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 66488b11a4..29e383a71f 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 65a13ea76c..b621ce1f11 100644 --- a/sp/src/game/client/worldlight.h +++ b/sp/src/game/client/worldlight.h @@ -27,7 +27,9 @@ class CWorldLights : public CAutoGameSystem // 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 @@ class CWorldLights : public CAutoGameSystem 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 79160a4923..b1e250b1f5 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 81aa16bc63..9dc2a5fe11 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 2285b97ed8..2732740390 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 d133e82e40..55d0211fd3 100644 --- a/sp/src/game/client/c_movie_display.h +++ b/sp/src/game/client/c_movie_display.h @@ -20,6 +20,7 @@ class C_MovieDisplay : public C_BaseEntity 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 @@ class C_MovieDisplay : public C_BaseEntity 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 0f47432381..8524a3381c 100644 --- a/sp/src/game/client/vgui_movie_display.cpp +++ b/sp/src/game/client/vgui_movie_display.cpp @@ -81,7 +81,7 @@ class CMovieDisplayScreen : public CVGuiScreenPanel 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 8524a3381c..8cc2c0db77 100644 --- a/sp/src/game/client/vgui_movie_display.cpp +++ b/sp/src/game/client/vgui_movie_display.cpp @@ -81,7 +81,6 @@ class CMovieDisplayScreen : public CVGuiScreenPanel 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 5c31fb233a..01236f1c09 100644 --- a/sp/src/game/server/movie_display.cpp +++ b/sp/src/game/server/movie_display.cpp @@ -53,6 +53,7 @@ class CMovieDisplay : public CBaseEntity 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 01236f1c09..b5a4476c57 100644 --- a/sp/src/game/server/movie_display.cpp +++ b/sp/src/game/server/movie_display.cpp @@ -21,6 +21,8 @@ class CMovieDisplay : public CBaseEntity 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 759f5c46ac..6557570925 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 43b82ed4f8..f7594febaf 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 e886ab8f1b..41fe618276 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 fec4f8c2f4..1882e66e9b 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 @@ class CAI_Expresser : public ResponseRules::IResponseFilter // -------------------------------- - 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 @@ class CAI_Expresser : public ResponseRules::IResponseFilter // 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 @@ class CAI_Expresser : public ResponseRules::IResponseFilter // -------------------------------- - 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 @@ class CAI_Expresser : public ResponseRules::IResponseFilter 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 @@ class CAI_Expresser : public ResponseRules::IResponseFilter 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 @@ class CAI_ExpresserHost : public BASE_NPC, protected CAI_ExpresserSink // 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 @@ class CAI_ExpresserHostWithData : public CAI_ExpresserHost 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 @@ class CAI_ExpresserWithFollowup : public CAI_Expresser 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 bb0dfe0bc7..8f60651996 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 2191b39436..83a6ed9e3b 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 31a5b1eff0..837c61aad7 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 4dbf822289..6c3301bb76 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 a558f79e70..9d2fff6b0c 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 41a3cc60b8..3e375a0ad0 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 d3f1c65ba4..0872539dc3 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 25b6f2d12e..08f311855b 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 fc27eb74e0..9d60652073 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 | 126 +++++++++---------- 1 file changed, 63 insertions(+), 63 deletions(-) diff --git a/sp/src/public/responserules/response_types.h b/sp/src/public/responserules/response_types.h index a3e8fea3a4..2e80cc5aae 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 ); - } + criterianame( UTL_INVAL_SYMBOL ), + weight( 0.0f ) + { + value[ 0 ] = 0; + } - CritEntry_t& operator=( const CritEntry_t& src ) - { - if ( this == &src ) - return *this; + CritEntry_t( const CritEntry_t& src ) + { + criterianame = src.criterianame; + value[ 0 ] = 0; + weight = src.weight; + SetValue( src.value ); + } - criterianame = src.criterianame; - weight = src.weight; - SetValue( src.value ); + CritEntry_t& operator=( const CritEntry_t& src ) + { + if ( this == &src ) + return *this; - return *this; - } + criterianame = src.criterianame; + weight = src.weight; + SetValue( src.value ); - static bool LessFunc( const CritEntry_t& lhs, const CritEntry_t& rhs ) - { - return lhs.criterianame < rhs.criterianame; - } + return *this; + } - void SetValue( char const *str ) - { - if ( !str ) + static bool LessFunc( const CritEntry_t& lhs, const CritEntry_t& rhs ) { - value[ 0 ] = 0; + return lhs.criterianame < rhs.criterianame; } - else + + void SetValue( char const *str ) { - Q_strncpy( value, str, sizeof( value ) ); + if ( !str ) + { + value[ 0 ] = 0; + } + else + { + Q_strncpy( value, str, sizeof( value ) ); + } } - } - CritSymbol_t criterianame; - char value[ 64 ]; - float weight; + 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 dafad41e4a..10e7fcfecb 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 7b07e15709..a07ae1bd95 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); + + free(iszTemplate); - return strdup(szModel); + 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 754ff56d9b..fa11a20398 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 326599648a..9ff1db6045 100644 --- a/sp/src/game/shared/mapbase/MapEdit.cpp +++ b/sp/src/game/shared/mapbase/MapEdit.cpp @@ -464,7 +464,7 @@ class CMapEdit : public CAutoGameSystemPerFrame { 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 @@ class CMapEdit : public CAutoGameSystemPerFrame { // Input name case 0: - pInputName = inputparams; break; + pInputName = AllocPooledString(inputparams); break; // Input parameter case 1: varInputParam.SetString(AllocPooledString(inputparams)); break; @@ -500,9 +500,10 @@ class CMapEdit : public CAutoGameSystemPerFrame 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 a07ae1bd95..cbe0519083 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 fe52380617..a43cfe32ae 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 | 112 ++++++++++++++++++---- sp/src/game/server/envmicrophone.h | 15 +++ sp/src/game/shared/SoundEmitterSystem.cpp | 39 ++++++++ 5 files changed, 154 insertions(+), 20 deletions(-) diff --git a/sp/src/game/server/baseentity.cpp b/sp/src/game/server/baseentity.cpp index d23ba924f5..95adce8e4e 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 05858b6abb..4b5449d664 100644 --- a/sp/src/game/server/baseentity.h +++ b/sp/src/game/server/baseentity.h @@ -1563,7 +1563,11 @@ class CBaseEntity : public IServerEntity 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 29a59ead9a..23b1758cdd 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; + 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 - 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; + 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_nPitch = iPitch; - ep.m_pOrigin = &m_hSpeaker->GetAbsOrigin(); + ep.m_nChannel = CHAN_STATIC; + ep.m_flVolume = flVolume; + ep.m_nPitch = iPitch; + ep.m_pOrigin = &m_hSpeaker->GetAbsOrigin(); #endif - ep.m_flSoundTime = soundtime; - ep.m_nSpeakerEntity = entindex; + 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 ); + 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 11527d584b..e330099c10 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 @@ class CEnvMicrophone : public CPointEntity 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 @@ class CEnvMicrophone : public CPointEntity 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 @@ class CEnvMicrophone : public CPointEntity 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 e1072b78b2..76a855d924 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 48256d92fa..77fa8112e9 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 bf8b01e1dc..33cdd01053 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 212947357c..c78c76fdeb 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 505395da74..7b4f281088 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 deeacf5dce..1846cfddb8 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 207f454411..6b802a25cb 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 9fb186c22e..e564d2b420 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 a39ac5701a..6aba49afa5 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 @@ class CScriptGameEventListener : public IGameEventListener2, public CAutoGameSys //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 @@ class CScriptConCommand : public ICommandCallback, public ICommandCompletionCall 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 @@ class CScriptConCommand : public ICommandCallback, public ICommandCompletionCall { if (fn) { - if ( !m_pBase->IsRegistered() ) + if ( !BaseClass::IsRegistered() ) Register(); if ( m_hCallback ) @@ -2306,8 +2301,8 @@ class CScriptConCommand : public ICommandCallback, public ICommandCompletionCall 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 @@ class CScriptConCommand : public ICommandCallback, public ICommandCompletionCall 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 @@ class CScriptConVar 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 @@ class CScriptConVar } 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 b1e250b1f5..f710b5539c 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 | 148 ++++++++++++++++------------ 3 files changed, 106 insertions(+), 67 deletions(-) diff --git a/sp/src/public/vscript/ivscript.h b/sp/src/public/vscript/ivscript.h index a1f24ce620..9db7c1066e 100644 --- a/sp/src/public/vscript/ivscript.h +++ b/sp/src/public/vscript/ivscript.h @@ -889,6 +889,11 @@ class IScriptVM // 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 cde074f081..a1ba928baa 100644 --- a/sp/src/vscript/vscript_squirrel.cpp +++ b/sp/src/vscript/vscript_squirrel.cpp @@ -187,6 +187,11 @@ class SquirrelVM : public IScriptVM // 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 0c48bb8734..8fa8fb58ad 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]; -} + // table, string, closure, string + function Add( scope, event, callback, context ) + { + if ( typeof callback != "function" ) + throw "invalid callback param" -function Hooks::Remove( name ) -{ - Hooks.Registered.rawdelete(name); -} + if ( !(scope in s_List) ) + s_List[scope] <- {} -function Hooks::ScopeHookedToEvent( scope, event ) -{ - //printl("Running ScopeHookedToEvent()") - foreach (elem in Hooks.Registered) - { - if (elem[1] == scope && elem[0] == event) - return true + 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]() + if ( event in scope ) + { + local t = scope[event] + if ( context in t ) + { + delete t[context] + } + + // cleanup? + if ( !t.len() ) + delete scope[event] + } + + // cleanup? + if ( !scope.len() ) + delete s_List[k] } - break; - - case 1: - foreach (elem in Hooks.Registered) + } + else + { + foreach( k,scope in s_List ) { - if (elem[0] == event && elem[1] == scope) - return elem[2](vargv[0]) + foreach( kk,ev in scope ) + { + if ( context in ev ) + { + delete ev[context] + } + + // cleanup? + if ( !ev.len() ) + delete scope[kk] + } + + // cleanup? + if ( !scope.len() ) + delete s_List[k] } - break; + } + } - case 2: - foreach (elem in Hooks.Registered) - { - if (elem[0] == event && elem[1] == scope) - return elem[2](vargv[0], vargv[1]) - } - break; + function Call( scope, event, ... ) + { + local firstReturn = null - case 3: - 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]) + 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; + } - 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; + return firstReturn + } - 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 ScopeHookedToEvent( scope, event ) + { + if ( scope in s_List ) + { + if (event in s_List[scope]) + return true + } - 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; + 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 f710b5539c..59326ce991 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 f12d385b97..f87aad96a6 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 25fd4fdb2c..60052ded90 100644 --- a/sp/src/game/server/ai_hint.h +++ b/sp/src/game/server/ai_hint.h @@ -289,6 +289,11 @@ class CAI_Hint : public CServerOnlyEntity 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 @@ class CAI_Hint : public CServerOnlyEntity 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 8c4767197e..62d5c6ec2f 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 8f470a47fb..0d1f71e477 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 d3a1be102e..80217efb17 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 d4ce19ac33..15c12c768b 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 640459e516..6378e10990 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 50b3659b9e..53372e8d5d 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 @@ class C_BaseAnimating : public C_BaseEntity, private IModelLoadCallback 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 @@ class C_BaseAnimating : public C_BaseEntity, private IModelLoadCallback 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 e032e99041..dd326d8047 100644 --- a/sp/src/game/server/ai_basenpc.h +++ b/sp/src/game/server/ai_basenpc.h @@ -667,6 +667,7 @@ class CAI_BaseNPC : public CBaseCombatCharacter, 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 @@ class CAI_BaseNPC : public CBaseCombatCharacter, 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 788edc2779..cc578df0f3 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 8f0e0aa82e..b45f96b69a 100644 --- a/sp/src/game/server/baseanimating.h +++ b/sp/src/game/server/baseanimating.h @@ -84,6 +84,7 @@ class CBaseAnimating : public CBaseEntity 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 6378e10990..c8208e6a34 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, *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; - GetBoneTransform( iBone, *HScriptToClass( hTransform ) ); + 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 53372e8d5d..30b69ea759 100644 --- a/sp/src/game/client/c_baseanimating.h +++ b/sp/src/game/client/c_baseanimating.h @@ -468,6 +468,11 @@ class C_BaseAnimating : public C_BaseEntity, private IModelLoadCallback 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 @@ class C_BaseAnimating : public C_BaseEntity, private IModelLoadCallback 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 b740e3f0bb..6facbb2bd5 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 95adce8e4e..8492f2999b 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 4b5449d664..e3388e87bd 100644 --- a/sp/src/game/server/baseentity.h +++ b/sp/src/game/server/baseentity.h @@ -693,6 +693,9 @@ class CBaseEntity : public IServerEntity #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 fa40fd7630..b39dad9fb7 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 80c4291f7d..63d5e3ed8a 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 f68531bb05..6f2aa4b819 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 9b1bfa842f..62d31c159e 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 9ff1db6045..0891c29ef1 100644 --- a/sp/src/game/shared/mapbase/MapEdit.cpp +++ b/sp/src/game/shared/mapbase/MapEdit.cpp @@ -409,7 +409,6 @@ class CMapEdit : public CAutoGameSystemPerFrame pkvClassname = pkvClassname->GetNextKey(); } - pkvClassname->deleteThis(); } else if (FStrEq(pNodeName, "edit")) { @@ -432,7 +431,6 @@ class CMapEdit : public CAutoGameSystemPerFrame pName = pName->GetNextKey(); } - pName->deleteThis(); } else if (FStrEq(pNodeName, "delete")) { @@ -455,7 +453,6 @@ class CMapEdit : public CAutoGameSystemPerFrame pName = pName->GetNextKey(); } - pName->deleteThis(); } else if (FStrEq(pNodeName, "fire")) { @@ -525,12 +522,10 @@ class CMapEdit : public CAutoGameSystemPerFrame 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 2c5b606a0e..903822f515 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 0000000000..b3670281ae --- /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 10bf02e549..0d715bf48c 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 19fc67842e..37b4584484 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 1b7398a4b7..7b1d825441 100644 --- a/sp/src/game/server/scripted.h +++ b/sp/src/game/server/scripted.h @@ -97,6 +97,8 @@ class CAI_ScriptedSequence : public CBaseEntity 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 @@ class CAI_ScriptedSequence : public CBaseEntity 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 2f189265fc..cb1567d549 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 516015fee1..23f44c3976 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 740378001c..44fc7102d5 100644 --- a/sp/src/game/server/rope.h +++ b/sp/src/game/server/rope.h @@ -102,6 +102,11 @@ class CRopeKeyframe : public CBaseEntity, public IPositionWatcher 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 4bbb96d2c9..b143a79dd0 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 f87aad96a6..7c6a421e4c 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 0d1f71e477..f366ee571a 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 59326ce991..af8ad7d4a1 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 cd05139f49..85c895ac8b 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 33cdd01053..d6609449a4 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 32b7504142..20b2379cfd 100644 --- a/sp/src/game/server/env_instructor_hint.cpp +++ b/sp/src/game/server/env_instructor_hint.cpp @@ -26,6 +26,15 @@ class CEnvInstructorHint : public CPointEntity 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 @@ class CEnvInstructorHint : public CPointEntity #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 a74bb46ea3..7bd15a1742 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 fc33224997..67ca064ae5 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 05872b4e6d..e9527f7287 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 49aafc10e2..98e6d6c2ab 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 422a006f42..f463847bee 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 7b80a59cd6..7bc5bb6238 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 6facbb2bd5..6c59d88a67 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 8b7dcfc94e..84021a952c 100644 --- a/sp/src/game/server/filters.cpp +++ b/sp/src/game/server/filters.cpp @@ -1522,6 +1522,7 @@ class CFilterSurfaceData : public CBaseFilter 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 c13117f56c..588bb6c7c2 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 5d4675c5d5..dd14ddafc6 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 | 396 +++++++++--------- 5 files changed, 241 insertions(+), 200 deletions(-) diff --git a/sp/src/game/shared/mapbase/vscript_singletons.cpp b/sp/src/game/shared/mapbase/vscript_singletons.cpp index 6aba49afa5..b2f829a5fd 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 @@ class CScriptSaveRestoreUtil : public CAutoGameSystem { if ( g_pScriptVM ) { + g_Hook_OnSave.Call( NULL, NULL, NULL ); + + // Legacy hook HSCRIPT hFunc = g_pScriptVM->LookupFunction( "OnSave" ); if ( hFunc ) { @@ -870,6 +876,9 @@ class CScriptSaveRestoreUtil : public CAutoGameSystem { 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 a0c2bdcf91..5fe1d5702e 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 c8295e0205..abaa2d66c6 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 f14618e58d..fa4c15d2f0 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 85c895ac8b..79cfb6c426 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 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 DocumentedFuncs = {} + local DocumentedClasses = {} + local DocumentedEnums = {} + local DocumentedConsts = {} + local DocumentedHooks = {} + local DocumentedMembers = {} + + 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]; + if (description.len() && description[0] == '#') + { + AddAliasedToTable(name, signature, description, DocumentedFuncs) + } + else + { + 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] == '#') + function __Documentation::RegisterClassHelp(name, baseclass, description) { - AddAliasedToTable(name, signature, description, DocumentedConsts) + DocumentedClasses[name] <- [baseclass, description]; } - else + + function __Documentation::RegisterEnumHelp(name, num_elements, description) { - DocumentedConsts[name] <- [signature, description]; + DocumentedEnums[name] <- [num_elements, 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) + function __Documentation::RegisterConstHelp(name, signature, description) { - // Is an aliased function - text += ("Signature: function " + name + "("); - foreach(k,v in this[name].getinfos().parameters) + if (description.len() && description[0] == '#') + { + AddAliasedToTable(name, signature, description, DocumentedConsts) + } + else { - if (k == 0 && v == "this") continue; - if (k > 1) text += (", "); - text += (v); + DocumentedConsts[name] <- [signature, description]; } - text += (")\n"); } - else + + function __Documentation::RegisterHookHelp(name, signature, description) { - text += ("Signature: " + doc[0] + "\n"); + DocumentedHooks[name] <- [signature, description]; } - 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); -} + function __Documentation::RegisterMemberHelp(name, signature, description) + { + DocumentedMembers[name] <- [signature, description]; + } -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 printdoc( text ) + { + return ::printc(200,224,255,text); + } -local function PrintConst(name, doc) -{ - local text = ("Constant: " + name + "\n"); - if (doc[0] == null) + local function printdocl( text ) { - text += ("Value: null\n"); + return printdoc(text + "\n"); } - else + + local function PrintClass(name, doc) { - text += ("Value: " + doc[0] + "\n"); + 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); } - 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 PrintFunc(name, doc) { - // Is an aliased function - text += ("Signature: function " + name + "("); - foreach(k,v in this[name].getinfos().parameters) + local text = "Function: " + name + "\n" + + if (doc[0] == null) { - if (k == 0 && v == "this") continue; - if (k > 1) text += (", "); - text += (v); + // 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"); } - text += (")\n"); + if (doc[1].len()) + text += ("Description: " + doc[1] + "\n"); + printdocl(text); } - else + + 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 PrintMatchesInDocList(pattern, list, printfunc) -{ - local foundMatches = 0; + 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); + } - foreach(name, doc in list) + local function PrintConst(name, doc) { - if (pattern == "*" || name.tolower().find(pattern) != null || (doc[1].len() && doc[1].tolower().find(pattern) != null)) + local text = ("Constant: " + name + "\n"); + if (doc[0] == null) + { + text += ("Value: null\n"); + } + else { - foundMatches = 1; - printfunc(name, doc) + text += ("Value: " + doc[0] + "\n"); } + if (doc[1].len()) + text += ("Description: " + doc[1] + "\n"); + printdocl(text); } - return foundMatches; -} + 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); + } -function __Documentation::PrintHelp(pattern = "*") -{ - if ( !developer ) + local function PrintMatchesInDocList(pattern, list, printfunc) { - printdocl("Documentation is not enabled. To enable documentation, restart the server with the 'developer' cvar set to 1 or higher."); - return + 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; } - 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 = "*") + { + 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"); + } + } +} +else +{ + __Documentation.RegisterHelp <- + __Documentation.RegisterClassHelp <- + __Documentation.RegisterEnumHelp <- + __Documentation.RegisterConstHelp <- + __Documentation.RegisterHookHelp <- + __Documentation.RegisterMemberHelp <- dummy + + 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 6c59d88a67..08d119dcb8 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 6d971ca3bb..d2d7639425 100644 --- a/sp/src/game/server/basecombatcharacter.h +++ b/sp/src/game/server/basecombatcharacter.h @@ -445,6 +445,9 @@ class CBaseCombatCharacter : public CBaseFlex 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 8492f2999b..0a9640585d 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 e3388e87bd..8577749d7e 100644 --- a/sp/src/game/server/baseentity.h +++ b/sp/src/game/server/baseentity.h @@ -1093,7 +1093,7 @@ class CBaseEntity : public IServerEntity 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 @@ class CBaseEntity : public IServerEntity 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 19616e10ab..42c2eb3fee 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 b6aa50623e..8eec2e6d06 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 6146013075..64f11d2a2a 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 dd14ddafc6..db6942015e 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 9511efa408..e407af5ec9 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 e9527f7287..0f3db5b8a0 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 @@ class CMapbaseSystem : public CAutoGameSystem 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 67ca064ae5..5cef9cc042 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 bb7dff50fe..fd4839aec3 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 b5b94c72a2..563d96e36f 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 66fd83674e..2d59c9a05f 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 30b69ea759..900f5ab890 100644 --- a/sp/src/game/client/c_baseanimating.h +++ b/sp/src/game/client/c_baseanimating.h @@ -80,7 +80,7 @@ class CAttachmentData 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 a7bb37a4f0..4942cc65de 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 80d892617d..f5e0523dac 100644 --- a/sp/src/game/client/c_baseentity.h +++ b/sp/src/game/client/c_baseentity.h @@ -1263,7 +1263,7 @@ class C_BaseEntity : public IClientEntity #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 0f0609d669..d0425d6b80 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 612a18d7e3..56ac16f4d5 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 71d03a0806..a2f73ee54e 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 3214a55fd8..ee86e515c3 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 b1af5b23a9..ebc392e2b3 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 2251556ba3..33bef81fe9 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 4d01015127..39742467d2 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 8577749d7e..8f92ba6095 100644 --- a/sp/src/game/server/baseentity.h +++ b/sp/src/game/server/baseentity.h @@ -1272,7 +1272,7 @@ class CBaseEntity : public IServerEntity #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 @@ class CBaseEntity : public IServerEntity 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 @@ class CBaseEntity : public IServerEntity 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 5032ca0406..8b76e88883 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 d03213567a..d9031dd424 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 653bf1dd47..1b390e834d 100644 --- a/sp/src/game/server/hltvdirector.h +++ b/sp/src/game/server/hltvdirector.h @@ -67,7 +67,7 @@ class CHLTVDirector : public CGameEventListener, public CBaseGameSystemPerFrame, 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 d62764ab59..1d5330ca5c 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 b0b2d867a1..eb6ceee6b5 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 42d2ebaa31..9378257d79 100644 --- a/sp/src/game/shared/GameEventListener.h +++ b/sp/src/game/shared/GameEventListener.h @@ -25,7 +25,7 @@ class CGameEventListener : public IGameEventListener2 { } - ~CGameEventListener() + virtual ~CGameEventListener() { StopListeningForAllEvents(); } diff --git a/sp/src/game/shared/util_shared.cpp b/sp/src/game/shared/util_shared.cpp index f1dd7e0022..be44201d54 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 dc8523e302..98f6ba4ebb 100644 --- a/sp/src/game/shared/util_shared.h +++ b/sp/src/game/shared/util_shared.h @@ -606,7 +606,7 @@ class CountdownTimer 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 5a858f194f..5c57671a49 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 dfb93b0d4a..6e020aaf75 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 1a35cab158..4a6a8ce007 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 250133d5c0..0f1f5c47ff 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 b10170ded0..06f78c64cc 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 f2ba68c360..3684d5b500 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 b9c72b2fb7..70fe86c49e 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 1e08b0a305..425a172ece 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 @@ class CPositionInterpolator_Rope : public IPositionInterpolator 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 b2cfd27c4c..4ee0482439 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 3f22e918c7..ddabcd220b 100644 --- a/sp/src/public/materialsystem/MaterialSystemUtil.h +++ b/sp/src/public/materialsystem/MaterialSystemUtil.h @@ -72,6 +72,10 @@ class CTextureReference 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 142b35e9e3..46a92de081 100644 --- a/sp/src/public/networkvar.h +++ b/sp/src/public/networkvar.h @@ -744,9 +744,9 @@ class CNetworkQuaternionBase : public CNetworkVarBase< Type, Changer > 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 b92a77c72a..96e5cf5d28 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 @@ class CGameSaveRestoreInfo 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 @@ class CGameSaveRestoreInfo 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 @@ class CGameSaveRestoreInfo { #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 @@ class CGameSaveRestoreInfo 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 7e9aad66ea..30b2455cf5 100644 --- a/sp/src/public/scratchpad3d.h +++ b/sp/src/public/scratchpad3d.h @@ -51,7 +51,7 @@ class CScratchPad3D : public IScratchPad3D m_pCachedRenderData = NULL; } - ~CBaseCommand() + virtual ~CBaseCommand() { ReleaseCachedRenderData(); } diff --git a/sp/src/public/sentence.cpp b/sp/src/public/sentence.cpp index 49c24c3c54..1b8efd646a 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 9bf97018d2..127840dcbf 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 bcc38d5d52..384f4732c3 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 @@ class CStudioHdr 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 9fd38d0a9b..fab7165090 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 e0f9c16ab9..34e1ccb91e 100644 --- a/sp/src/public/tier0/memalloc.h +++ b/sp/src/public/tier0/memalloc.h @@ -382,7 +382,12 @@ class CMemAllocAttributeAlloction #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 7fd6e9ca18..4e46839fc2 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 5c679e4571..269d44ecdd 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 f463847bee..5afe5eea80 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 b5bfef5338..53989db497 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 9b082541be..9c866639cb 100644 --- a/sp/src/public/tier1/byteswap.h +++ b/sp/src/public/tier1/byteswap.h @@ -186,7 +186,7 @@ class CByteswap 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 07b63d8de9..99f8e22390 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 @@ class CSortedPanelYLess 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 5fe1d5702e..001e1c24dd 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 9816560dbc..6def3bab93 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 4b1d19f613..d2e50557dd 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 52a25e4db3..e723bae916 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 ec5d10189e..7db8b931f1 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 da5a3b4e2e..020855fbb5 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 499296d94e..6054fd290b 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 32df2fae66..6f127558c8 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 e18427eb96..7f9738d2ae 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 b7ad4d3b84..c244edebdd 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 66530a33b7..d3d0c73d96 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 4b2a2852e1..4e73892086 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 47ce40fdad..e756073f31 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 02caa80060..ee62e53990 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 245366f499..7dd289edc1 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 f59305badd..dcb9aea5c8 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 47ea96efb0..a24973a8ba 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 @@ class CHudCommentary : public CHudElement, public vgui::Panel 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 @@ class CHudCommentary : public CHudElement, public vgui::Panel 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 @@ class CHudCommentary : public CHudElement, public vgui::Panel 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 @@ class C_PointCommentaryNode : public C_BaseAnimating 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 @@ class C_PointCommentaryNode : public C_BaseAnimating 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 4d01015127..23a8a5b87a 100644 --- a/sp/src/game/server/CommentarySystem.cpp +++ b/sp/src/game/server/CommentarySystem.cpp @@ -138,6 +138,10 @@ class CPointCommentaryNode : public CBaseAnimating 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 a24973a8ba..b59cf253c7 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 @@ class CHudCommentary : public CHudElement, public vgui::Panel 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 23a8a5b87a..6c435d3f31 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 b59cf253c7..bfef3c0a48 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 @@ class CHudCommentary : public CHudElement, public vgui::Panel 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 @@ class CHudCommentary : public CHudElement, public vgui::Panel // 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 @@ class CHudCommentary : public CHudElement, public vgui::Panel 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 @@ class CHudCommentary : public CHudElement, public vgui::Panel 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 @@ class C_PointCommentaryNode : public C_BaseAnimating 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 @@ class C_PointCommentaryNode : public C_BaseAnimating 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 6c435d3f31..906c9daf43 100644 --- a/sp/src/game/server/CommentarySystem.cpp +++ b/sp/src/game/server/CommentarySystem.cpp @@ -74,6 +74,15 @@ class CPointCommentaryNode : public CBaseAnimating 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 @@ class CPointCommentaryNode : public CBaseAnimating 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 d30843dcdf..0ddb6e1da4 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 906c9daf43..ba5aaba8cd 100644 --- a/sp/src/game/server/CommentarySystem.cpp +++ b/sp/src/game/server/CommentarySystem.cpp @@ -77,6 +77,8 @@ class CPointCommentaryNode : public CBaseAnimating 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 @@ class CPointCommentaryNode : public CBaseAnimating 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 c78c76fdeb..17988d183e 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 5cef9cc042..ce2a1bc65b 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 3fa3fab842..59237c842f 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 270a503cd1..9c093be62f 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 80bb509091..9a571bf5cf 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 8a5ddd551c..110f8b32e4 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 180afe9d53..f89dffb3c8 100644 --- a/sp/src/game/client/hud_closecaption.h +++ b/sp/src/game/client/hud_closecaption.h @@ -111,6 +111,11 @@ class CHudCloseCaption : public CHudElement, public vgui::Panel 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 0f3db5b8a0..49d914f702 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 @@ class CMapbaseSystem : public CAutoGameSystem 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 @@ class CMapbaseSystem : public CAutoGameSystem } #ifdef CLIENT_DLL - bool m_bInitializedRTs = false; - CUtlVector m_CameraTextures; - //----------------------------------------------------------------------------- // Initialize custom RT textures if necessary //----------------------------------------------------------------------------- @@ -389,7 +384,10 @@ class CMapbaseSystem : public CAutoGameSystem 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 @@ class CMapbaseSystem : public CAutoGameSystem 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 @@ class CMapbaseSystem : public CAutoGameSystem { 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 @@ class CMapbaseSystem : public CAutoGameSystem 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 d304f5c9e7..71780093c5 100644 --- a/sp/src/game/client/c_vguiscreen.h +++ b/sp/src/game/client/c_vguiscreen.h @@ -112,6 +112,15 @@ class C_VGuiScreen : public C_BaseEntity 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 c3847ac057..f0d2032da9 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 bfef3c0a48..cdee8adeef 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 @@ class CHudCommentary : public CHudElement, public vgui::Panel 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 ba5aaba8cd..959798e5b0 100644 --- a/sp/src/game/server/CommentarySystem.cpp +++ b/sp/src/game/server/CommentarySystem.cpp @@ -79,6 +79,7 @@ class CPointCommentaryNode : public CBaseAnimating #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 @@ class CPointCommentaryNode : public CBaseAnimating #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 03e23cb7ba..7a5bce80e3 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 7a5bce80e3..37f5c19bae 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 4aacad13b9..47bf82be39 100644 --- a/sp/src/game/server/triggers.h +++ b/sp/src/game/server/triggers.h @@ -300,6 +300,10 @@ class CTriggerCamera : public CBaseEntity #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 @@ class CTriggerCamera : public CBaseEntity #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 6c3301bb76..9b519902f3 100644 --- a/sp/src/game/shared/ai_responsesystem_new.cpp +++ b/sp/src/game/shared/ai_responsesystem_new.cpp @@ -531,6 +531,9 @@ class CInstancedResponseSystem : public CGameResponseSystem virtual void LevelInitPostEntity() { +#ifdef MAPBASE + if (!rr_enhanced_saverestore.GetBool() || gpGlobals->eLoadType != MapLoad_Transition) +#endif ResetResponseGroups(); } @@ -567,6 +570,16 @@ class CDefaultResponseSystem : public CGameResponseSystem, public CAutoGameSyste 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 156bd45f85..d294316d19 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 b675e8167a..a862d76143 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 0000000000..e7ed2b71c4 --- /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 e7ed2b71c4..648cf2feba 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 648cf2feba..d1e9b96c3e 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 d1e9b96c3e..7c7d153b90 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 cdee8adeef..f9e447c6e0 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 @@ class CHudCommentary : public CHudElement, public vgui::Panel #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 @@ class CHudCommentary : public CHudElement, public vgui::Panel //----------------------------------------------------------------------------- // 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 @@ class C_PointCommentaryNode : public C_BaseAnimating #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 @@ class C_PointCommentaryNode : public C_BaseAnimating 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,7 +464,253 @@ 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 959798e5b0..0ddb48b4ff 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 0ddb6e1da4..11f8e8aaf6 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 280e8a44de..b976071214 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 @@ class CHudCredits : public CHudElement, public vgui::Panel 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 @@ class CHudCredits : public CHudElement, public vgui::Panel 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 @@ class CHudCredits : public CHudElement, public vgui::Panel 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 = 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 ); + } - int iFontTall = surface()->GetFontTall ( m_hTFont ); + 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; + + // 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(); + } - iHeight += surface()->GetFontTall ( m_hTFont ) + m_flSeparation; + // 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] ); - PrepareLine( m_hTFont, pCredit->szCreditName ); + 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 f9e447c6e0..fa5f8eacee 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 f89dffb3c8..b3bdae06fd 100644 --- a/sp/src/game/client/hud_closecaption.h +++ b/sp/src/game/client/hud_closecaption.h @@ -138,6 +138,11 @@ class CHudCloseCaption : public CHudElement, public vgui::Panel 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 @@ class CHudCloseCaption : public CHudElement, public vgui::Panel 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 6c643413fd..a08ab4e27f 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 21b9db8479..75722bfee2 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 3e9f44c022..27dd955382 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 fa5f8eacee..68516ba3b1 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 @@ class CHudCommentary : public CHudElement, public vgui::Panel 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 @@ class C_PointCommentaryNode : public C_BaseAnimating, public IChoreoEventCallbac { 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 @@ class C_PointCommentaryNode : public C_BaseAnimating, public IChoreoEventCallbac 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 0ddb48b4ff..378ccc043f 100644 --- a/sp/src/game/server/CommentarySystem.cpp +++ b/sp/src/game/server/CommentarySystem.cpp @@ -135,6 +135,7 @@ class CPointCommentaryNode : public CBaseAnimating 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 110f8b32e4..9b9c0c112c 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() ) - { - font = params.GetFontNumber(); - } - else + vgui::HFont useF = params.font; +#ifdef MAPBASE + if (params.customFont == false) +#endif { - font = streamlen >= cc_smallfontlength.GetInt() ? CCFONT_SMALL : CCFONT_NORMAL; + int font; + if ( IsPC() ) + { + font = params.GetFontNumber(); + } + else + { + font = streamlen >= cc_smallfontlength.GetInt() ? CCFONT_SMALL : CCFONT_NORMAL; + } + useF = m_hFonts[font]; + params.font = useF; } - 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 68516ba3b1..76e753d755 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 b976071214..6520e6b4f8 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 49d914f702..3e776861ab 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 @@ class CMapbaseSystem : public CAutoGameSystem { 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 @@ class CMapbaseSystem : public CAutoGameSystem 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 @@ class CMapbaseSystem : public CAutoGameSystem (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 499296d94e..18526ac712 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 + { + iScheme = ipanel()->GetScheme(GetVParent()); + } + else + { + iScheme = 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 ipanel()->GetScheme(GetVParent()); + return g_iCustomClientSchemeOverride; } +#endif - return scheme()->GetDefaultScheme(); + 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 0792df23cf..bc5244efb2 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 bf56dc78a3..8f708b6e03 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 07ba67da42..e0f3957731 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 0a9640585d..75c1d799a1 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 8577749d7e..13d645034e 100644 --- a/sp/src/game/server/baseentity.h +++ b/sp/src/game/server/baseentity.h @@ -2148,6 +2148,8 @@ class CBaseEntity : public IServerEntity 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 a7bb37a4f0..2f10b2ae8d 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 80d892617d..29d04ea026 100644 --- a/sp/src/game/client/c_baseentity.h +++ b/sp/src/game/client/c_baseentity.h @@ -296,6 +296,7 @@ class C_BaseEntity : public IClientEntity 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 75c1d799a1..90b5199972 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 13d645034e..2645e476be 100644 --- a/sp/src/game/server/baseentity.h +++ b/sp/src/game/server/baseentity.h @@ -1537,6 +1537,12 @@ class CBaseEntity : public IServerEntity 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 @@ class CBaseEntity : public IServerEntity 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 76a855d924..06f73b725c 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 db6942015e..e8efdee4dd 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 e564d2b420..a2af7d7124 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 0a38e5a15a..ae3def47e8 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 a2af7d7124..26c0c1b8a7 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 ae3def47e8..40055a88ce 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 90b5199972..5598ba6993 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 2645e476be..c55c8c2b61 100644 --- a/sp/src/game/server/baseentity.h +++ b/sp/src/game/server/baseentity.h @@ -610,7 +610,7 @@ class CBaseEntity : public IServerEntity #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 5598ba6993..fd31f79285 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 fa4c15d2f0..cd5fe6f6ae 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_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_newtableex(vm_, pEnumDesc->m_ConstantBindings.Count()); - sq_pop(vm_, 1); + sq_pushconsttable(vm_); - // 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_pushstring(vm_, pEnumDesc->m_pszScriptName, -1); + 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 6b802a25cb..cd3854ddc4 100644 --- a/sp/src/game/shared/baseentity_shared.cpp +++ b/sp/src/game/shared/baseentity_shared.cpp @@ -2393,7 +2393,66 @@ 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 bcd254a555..a2ab0caeab 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 84cb0109ac..097588c616 100644 --- a/sp/src/game/server/ai_behavior_follow.h +++ b/sp/src/game/server/ai_behavior_follow.h @@ -71,6 +71,10 @@ class CAI_FollowGoal : public CAI_GoalEntity 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 | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/sp/src/game/server/triggers.cpp b/sp/src/game/server/triggers.cpp index 37f5c19bae..2361f8facd 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 ( HasSpawnFlags( SF_CAMERA_PLAYER_TAKECONTROL ) ) + { + pBasePlayer->EnableControl( TRUE ); + } + if (!m_bDontSetPlayerView) + { pBasePlayer->SetViewEntity( NULL ); - - pBasePlayer->EnableControl(TRUE); - pBasePlayer->m_Local.m_bDrawViewmodel = true; + 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 5496d45303..a31258829d 100644 --- a/sp/src/game/client/c_env_screenoverlay.cpp +++ b/sp/src/game/client/c_env_screenoverlay.cpp @@ -48,6 +48,9 @@ class C_EnvScreenOverlay : public C_BaseEntity 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 c66061aed9..8d797dea53 100644 --- a/sp/src/game/client/iviewrender.h +++ b/sp/src/game/client/iviewrender.h @@ -115,6 +115,13 @@ abstract_class IViewRender 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 619993fa8f..a653734992 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 29f9c65147..9ebc261ab1 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 2312c4d532..5e99096a19 100644 --- a/sp/src/game/client/viewrender.h +++ b/sp/src/game/client/viewrender.h @@ -468,6 +468,13 @@ class CViewRender : public IViewRender, 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 @@ class CViewRender : public IViewRender, 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 07bbf08df4..259a6fdcc2 100644 --- a/sp/src/game/server/env_screenoverlay.cpp +++ b/sp/src/game/server/env_screenoverlay.cpp @@ -39,6 +39,9 @@ class CEnvScreenOverlay : public CPointEntity 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 06f73b725c..6b10c6fead 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 0b99ef6348..a098662094 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 4e4c64e804..cbc602a0ed 100644 --- a/sp/src/game/client/game_controls/baseviewport.h +++ b/sp/src/game/client/game_controls/baseviewport.h @@ -73,6 +73,10 @@ class CBaseViewport : public vgui::EditablePanel, public IViewPort, public IGame 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 3e776861ab..6701e0befc 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 @@ class CMapbaseSystem : public CAutoGameSystem { 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 @@ class CMapbaseSystem : public CAutoGameSystem 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 @@ class CMapbaseSystem : public CAutoGameSystem } 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 6da33a38d8..886b4291a4 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 | 133 +++++++++--------- sp/src/game/client/viewrender.h | 2 +- .../server/mapbase/func_fake_worldportal.cpp | 2 +- 5 files changed, 73 insertions(+), 75 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 9d92675e1d..1cae8ebe56 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 3fc4418b61..1bae2de004 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 @@ class C_FuncFakeWorldPortal : public C_BaseEntity //----------------------------------------------------------------------------- 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 9ebc261ab1..e3889d74b3 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; + // + // 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 vOurForward, vOurRight, vOurUp; + AngleVectors( pCameraEnt->GetAbsAngles(), &vOurForward, &vOurRight, &vOurUp ); + + Quaternion quat; + BasisToQuaternion( ourPlane.normal, vOurRight, vOurUp, quat ); + QuaternionAngles( quat, angFakePortalAngles ); - // RED - First 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 ); - // Make sure the origin and angles are relative to the target plane - monitorView.origin -= pCameraEnt->GetAbsOrigin(); + // YELLOW - Portal origin + debugoverlay->AddBoxOverlay( pCameraEnt->GetAbsOrigin(), Vector(-32,-32,-32), Vector(32,32,32), angFakePortalAngles, 255, 224, 0, 128, 10.0f ); + } - // scale origin by sky scale + // + // 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 ) { - float scale = 1.0f / pCameraEnt->m_flScale; - VectorScale( monitorView.origin, scale, monitorView.origin ); + Vector vecTranslation; + MatrixGetColumn( matPlayerToPortal, 3, vecTranslation ); + vecTranslation /= pCameraEnt->m_flScale; + MatrixSetColumn( vecTranslation, 3, matPlayerToPortal ); } - // 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; - - // 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 ); + matrix3x4_t matTarget; + AngleMatrix( angTargetAngles, pCameraEnt->m_hTargetPlane->GetAbsOrigin(), matTarget ); - Quaternion quat; - BasisToQuaternion( vecSkyForward, vecSkyRight, vecSkyUp, quat ); - QuaternionAngles( quat, monitorView.angles ); + // Now apply the new matrix to the new reference point + matrix3x4_t matPortalToPlayer, matNewPlayerPosition; + MatrixInvert( matPlayerToPortal, matPortalToPlayer ); - // End of code mostly lifted from projected texture screenspace stuff - // ---------------------------------------------------------------------- + ConcatTransforms( matTarget, matPortalToPlayer, matNewPlayerPosition ); - // 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); + MatrixAngles( matNewPlayerPosition, monitorView.angles, 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) { + // 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() ); + + // The portal plane's distance from the actual brush's origin + float flPlaneDist = vecPlaneOrigin.Length(); - // TODO: How do we get a good value for this!?!? - //plane.w = m_OurPlane.dist + 0.1f; - plane.w = -32.0f + 0.1f; + // 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 5e99096a19..936a282b5b 100644 --- a/sp/src/game/client/viewrender.h +++ b/sp/src/game/client/viewrender.h @@ -454,7 +454,7 @@ class CViewRender : public IViewRender, #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 3184d2fa3c..de951b6ad6 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 c8208e6a34..c5b54eefcf 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 30b69ea759..342579ddc7 100644 --- a/sp/src/game/client/c_baseanimating.h +++ b/sp/src/game/client/c_baseanimating.h @@ -531,6 +531,10 @@ class C_BaseAnimating : public C_BaseEntity, private IModelLoadCallback 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 0fc3d0e016..1e044a1d76 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 682d5435d2..41893f7b06 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 ad57f7e7cb..9c6cb875fc 100644 --- a/sp/src/game/client/fx_impact.h +++ b/sp/src/game/client/fx_impact.h @@ -58,12 +58,21 @@ class CRagdollEnumerator : public IPartitionEnumerator // 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 e62f7f66a0..09257b0d4a 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 0af73a8957..7ac69311a2 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 faa482a267..d348c53e02 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 cc578df0f3..5d27044a43 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 e8efdee4dd..54273d6a16 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 26c0c1b8a7..aab303d869 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 40055a88ce..c7ad9ca718 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 @@ class CTraceInfoAccessor //----------------------------------------------------------------------------- // 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 6b87f888d6..04ff44ed03 100644 --- a/sp/src/game/shared/usercmd.h +++ b/sp/src/game/shared/usercmd.h @@ -127,39 +127,6 @@ class CUserCmd 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 d6e619353f..1852ab8ccc 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 09257b0d4a..f1ee3dbe2c 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 dd326d8047..1a00cb8754 100644 --- a/sp/src/game/server/ai_basenpc.h +++ b/sp/src/game/server/ai_basenpc.h @@ -2119,6 +2119,7 @@ class CAI_BaseNPC : public CBaseCombatCharacter, 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 08d119dcb8..5f61ae37b7 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 7efac5261d..e2465cc70d 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 b7fef9b773..708c17bb65 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 9c943105a6..523ba8270a 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 15c12c768b..3076347df2 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 ec541cca2f..c9af801063 100644 --- a/sp/src/game/server/hl2/npc_combine.h +++ b/sp/src/game/server/hl2/npc_combine.h @@ -59,7 +59,7 @@ class CNPC_Combine : public CAI_BaseActor // 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 @@ class CNPC_Combine : public CAI_BaseActor 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 @@ class CNPC_Combine : public CAI_BaseActor 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 @@ class CNPC_Combine : public CAI_BaseActor private: int m_nKickDamage; -#ifndef MAPBASE +#ifndef MAPBASE // CAI_GrenadeUser Vector m_vecTossVelocity; EHANDLE m_hForcedGrenadeTarget; #else @@ -334,12 +334,12 @@ class CNPC_Combine : public CAI_BaseActor // 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 @@ class CNPC_Combine : public CAI_BaseActor 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 @@ class CNPC_Combine : public CAI_BaseActor #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 8f708b6e03..cf94fdbf23 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 1f3f9517c3..742de7e3a7 100644 --- a/sp/src/game/server/hl2/npc_metropolice.h +++ b/sp/src/game/server/hl2/npc_metropolice.h @@ -67,8 +67,12 @@ class CNPC_MetroPolice : public CAI_BaseActor 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 @@ class CNPC_MetroPolice : public CAI_BaseActor // 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 8eec2e6d06..6ee991e10a 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 81ba080c84..2fe0b843ac 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 @@ class CNPC_PlayerCompanion : public CAI_PlayerAlly // 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 @@ class CNPC_PlayerCompanion : public CAI_PlayerAlly 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 e14b47a3fe..a9ff5302e4 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 7f1ea8c13a..69031d740b 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 @@ class CAI_GrenadeUser : public BASE_NPC, public CAI_GrenadeUserSink 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 @@ class CAI_GrenadeUser : public BASE_NPC, public CAI_GrenadeUserSink 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 @@ class CAI_GrenadeUser : public BASE_NPC, public CAI_GrenadeUserSink // 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 @@ class CAI_GrenadeUser : public BASE_NPC, public CAI_GrenadeUserSink 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 f1ee3dbe2c..1aa07ac7de 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 a653734992..0204a0ab23 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 53f440e8be..6209c15ee0 100644 --- a/sp/src/game/server/items.h +++ b/sp/src/game/server/items.h @@ -89,9 +89,9 @@ class CItem : public CBaseAnimating, public CDefaultPlayerPickupVPhysics #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 76e753d755..006451e4b5 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 @@ class CHudCommentary : public CHudElement, public vgui::Panel 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 378ccc043f..8269c61289 100644 --- a/sp/src/game/server/CommentarySystem.cpp +++ b/sp/src/game/server/CommentarySystem.cpp @@ -136,6 +136,7 @@ class CPointCommentaryNode : public CBaseAnimating 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 006451e4b5..3314330bd3 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 @@ class C_PointCommentaryNode : public C_BaseAnimating, public IChoreoEventCallbac } } +#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 @@ class C_PointCommentaryNode : public C_BaseAnimating, public IChoreoEventCallbac //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 8269c61289..437ed08636 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 @@ class CPointCommentaryNode : public CBaseAnimating 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 de951b6ad6..6430d5df2f 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 @@ class CFuncFakeWorldPortal : public CFuncBrush 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 6701e0befc..877cf9ff9f 100644 --- a/sp/src/game/shared/mapbase/mapbase_shared.cpp +++ b/sp/src/game/shared/mapbase/mapbase_shared.cpp @@ -375,55 +375,6 @@ class CMapbaseSystem : public CAutoGameSystem 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 @@ class CMapbaseSystem : public CAutoGameSystem 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 @@ class CMapbaseSystem : public CAutoGameSystem } } -#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 b2f829a5fd..009aa48c80 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 a94c77b6a9..fdae50dafc 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 ec9be919cd..fc803f1f67 100644 --- a/sp/src/game/server/hl2/npc_rollermine.cpp +++ b/sp/src/game/server/hl2/npc_rollermine.cpp @@ -310,6 +310,16 @@ class CNPC_RollerMine : public CNPCBaseInteractive, public CDefault 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 aac717c56e..0323afcc0c 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 9f3b9be452..a48aa41355 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 2d19727df5..b0a3e33077 100644 --- a/sp/src/game/shared/basecombatweapon_shared.h +++ b/sp/src/game/shared/basecombatweapon_shared.h @@ -319,7 +319,7 @@ class CBaseCombatWeapon : public BASECOMBATWEAPON_DERIVED_FROM 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 aab303d869..e57a714df5 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 b2f829a5fd..2f492f8886 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 @@ class CScriptGameEventListener : public IGameEventListener2, public CAutoGameSys 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 @@ class CScriptConvarAccessor : public CAutoGameSystem 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 @@ class CScriptConvarAccessor : public CAutoGameSystem 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 | 127 ++++++++++++++++++---------- 1 file changed, 80 insertions(+), 47 deletions(-) diff --git a/sp/src/vscript/vscript_squirrel.nut b/sp/src/vscript/vscript_squirrel.nut index 79cfb6c426..b17001189c 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." ); - -__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.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." ); - +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::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.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 a43cfe32ae..6f4a8ef24b 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 ced6ced984..0b2422faba 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 fac6c0dd8f..84ccffb5ab 100644 --- a/sp/src/game/client/c_baseplayer.h +++ b/sp/src/game/client/c_baseplayer.h @@ -458,6 +458,8 @@ class C_BasePlayer : public C_BaseCombatCharacter, public CGameEventListener // 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 e2465cc70d..5280b60a3f 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 03709ade75..85c92c673a 100644 --- a/sp/src/game/server/player.h +++ b/sp/src/game/server/player.h @@ -943,7 +943,7 @@ class CBasePlayer : public CBaseCombatCharacter #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 d77d0c8926..46afe4f238 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 afd5bcf995..135b564500 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 6012dff724..5f7e02a58f 100644 --- a/sp/src/game/client/c_effects.h +++ b/sp/src/game/client/c_effects.h @@ -130,6 +130,10 @@ friend class CClient_Precipitation::CPrecipitationEffect; 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 a43cfe32ae..e52ffcb0bf 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 85c92c673a..bda4a5fea6 100644 --- a/sp/src/game/server/player.h +++ b/sp/src/game/server/player.h @@ -1147,7 +1147,8 @@ class CBasePlayer : public CBaseCombatCharacter 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 @@ class CBasePlayer : public CBaseCombatCharacter // 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 4cd9dd7bd2..12dc248f5c 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 e52ffcb0bf..3e70f4fa1d 100644 --- a/sp/src/game/server/hl2/hl2_player.cpp +++ b/sp/src/game/server/hl2/hl2_player.cpp @@ -259,6 +259,7 @@ class CLogicPlayerProxy : public CLogicalEntity 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 708c17bb65..47acecd64f 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 dccaf2a507..405b208322 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 @@ class CScriptClientEntityIterator 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 6927b0f106..76d66a8384 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 @@ class CScriptEntityIterator { 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 | 46 ++++++++++++++++------------- 2 files changed, 34 insertions(+), 20 deletions(-) diff --git a/sp/src/game/server/ai_baseactor.cpp b/sp/src/game/server/ai_baseactor.cpp index 0994082951..99f6b24431 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 1aa07ac7de..513f6dc2d7 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 ); + if( info.GetAttacker()->IsPlayer() ) + { + 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 ) + // This also counts as being harmed by player's squad. + m_OnDamagedByPlayerSquad.FireOutput( info.GetAttacker(), this ); + } + else { - if( pAttacker->GetSquad() != NULL && pAttacker->IsInPlayerSquad() ) + // 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 c1d7b88341..d04ff89d7d 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 ac112cbd0c..d7b882f86c 100644 --- a/sp/src/game/server/BaseAnimatingOverlay.h +++ b/sp/src/game/server/BaseAnimatingOverlay.h @@ -43,6 +43,9 @@ class CAnimationLayer #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 @@ class CAnimationLayer 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 @@ class CBaseAnimatingOverlay : public CBaseAnimating 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 @@ class CBaseAnimatingOverlay : public CBaseAnimating 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 99f6b24431..248c0841f2 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 8da332cd0e..3c660a8836 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 93ca92f048..cfb80afc0c 100644 --- a/sp/src/game/server/hl2/npc_barney.cpp +++ b/sp/src/game/server/hl2/npc_barney.cpp @@ -51,8 +51,10 @@ class CNPC_Barney : public CNPC_PlayerCompanion 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 e0f3957731..d14fc7021c 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 35f39a057f..6828a664fd 100644 --- a/sp/src/game/server/hl2/npc_citizen17.h +++ b/sp/src/game/server/hl2/npc_citizen17.h @@ -277,6 +277,11 @@ class CNPC_Citizen : public CNPC_PlayerCompanion 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 @@ class CNPC_Citizen : public CNPC_PlayerCompanion //----------------------------------------------------- +#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 4530f26133..967c57953a 100644 --- a/sp/src/game/server/hl2/npc_fisherman.cpp +++ b/sp/src/game/server/hl2/npc_fisherman.cpp @@ -64,8 +64,10 @@ class CNPC_Fisherman : public CNPC_PlayerCompanion 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 6ee991e10a..597f4c7f81 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 54273d6a16..0bcdd8ae23 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 513f6dc2d7..d2ec72bf7e 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 0d715bf48c..cf425fd077 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 b45f96b69a..4fb3c47c3b 100644 --- a/sp/src/game/server/baseanimating.h +++ b/sp/src/game/server/baseanimating.h @@ -388,6 +388,8 @@ class CBaseAnimating : public CBaseEntity 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 1135aa8263..e49c1c1f09 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 2ffca3bc07..d26f702a1a 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 cf94fdbf23..b3b0e5d1b8 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 8dffd6dbac..7fdd89f24b 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 5f61ae37b7..c39271569a 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 59237c842f..b012811f78 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 @@ class CWeapon357 : public CBaseHLCombatWeapon 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 cc3e862cb2..4dd95532ac 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 @@ class CWeaponAlyxGun : public CHLSelectFireMachineGun 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 89a16700c5..dcd0009c15 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 1890ef6e05..26bb961fc4 100644 --- a/sp/src/game/server/hl2/weapon_crowbar.h +++ b/sp/src/game/server/hl2/weapon_crowbar.h @@ -46,6 +46,12 @@ class CWeaponCrowbar : public CBaseHLBludgeonWeapon // 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 9a571bf5cf..da78654bb5 100644 --- a/sp/src/game/server/hl2/weapon_pistol.cpp +++ b/sp/src/game/server/hl2/weapon_pistol.cpp @@ -108,6 +108,12 @@ class CWeaponPistol : public CBaseHLCombatWeapon 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 a48aa41355..d807e559cd 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 b0a3e33077..0f2fe433aa 100644 --- a/sp/src/game/shared/basecombatweapon_shared.h +++ b/sp/src/game/shared/basecombatweapon_shared.h @@ -230,6 +230,8 @@ class CBaseCombatWeapon : public BASECOMBATWEAPON_DERIVED_FROM 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 da25999c33..93688915d9 100644 --- a/sp/src/game/shared/hl2mp/weapon_stunstick.h +++ b/sp/src/game/shared/hl2mp/weapon_stunstick.h @@ -83,6 +83,12 @@ class CWeaponStunStick : public CBaseHL2MPBludgeonWeapon 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 b88c114289..7e5f13f9b2 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 9e986cb7ad..ede1485b10 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 44b8f62ddf..bfe3eb0502 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 42c2eb3fee..cdeb8f6b78 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 6d4eb67b17..2f95099be7 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 @@ class CNPC_Alyx : public CNPC_PlayerCompanion 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 d14fc7021c..62cd9ab22c 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 3076347df2..3a643ff7da 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 b012811f78..dc8e44835d 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 9c093be62f..538f63120f 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 b86b4c05eb..eb492e97d3 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 da78654bb5..417d1ee5a3 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 d807e559cd..1036259e60 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 cdb9378a12..3d82e46c96 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 fdbc7943f6..e95c2dbb74 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 3ae41e288d..808b6e901d 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 1d68b52924..0884153e1e 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 3a643ff7da..73f58af55c 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)) + { + 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 ) ) ) { - eNewActivity = ACT_WALK_EASY; + 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 597f4c7f81..7ed8553eaa 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 dcd0009c15..6279c34d93 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 97b0e89eac..8e88985121 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 69031d740b..bfcbd4de2d 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 @@ class CAI_GrenadeUser : public BASE_NPC, public CAI_GrenadeUserSink 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 7e5f13f9b2..c467ddc400 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 d2ec72bf7e..170b5454d1 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 cf425fd077..7fc1c13b90 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 49f3d5f462..0db2c6c585 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 d7f14293b6..b5f5d2972b 100644 --- a/sp/src/game/server/ai_motor.h +++ b/sp/src/game/server/ai_motor.h @@ -62,6 +62,10 @@ class CAI_Motor : public CAI_Component, 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 d136c92325..9d6ae06a03 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 0e15e2a839..be53f34497 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 ede1485b10..6d3f3cf612 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 bfe3eb0502..36d07ed33a 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 170b5454d1..e11d6452ee 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 1a00cb8754..675412af6f 100644 --- a/sp/src/game/server/ai_basenpc.h +++ b/sp/src/game/server/ai_basenpc.h @@ -1731,8 +1731,8 @@ class CAI_BaseNPC : public CBaseCombatCharacter, 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 b3b0e5d1b8..31e86f37a4 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 6279c34d93..5e12856cc3 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 eb492e97d3..87f45fce1b 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 808b6e901d..2efbd40956 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 fb9ec21561..44406dee3d 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 8e88985121..b0c75a149a 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 b053ac1b67..6e73e1556f 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 41893f7b06..0ef81cc568 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 0204a0ab23..94988d9f84 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 5d27044a43..1db0693a8d 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 69031d740b..5f014fec26 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 @@ class CAI_GrenadeUser : public BASE_NPC, public CAI_GrenadeUserSink } // 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 0db2c6c585..c9c6fb8e45 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 cdeb8f6b78..01a64dea18 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 31e86f37a4..9d8e0b96ab 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 c3734147af..2460ffa086 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 aab303d869..34729186d0 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 9b9c0c112c..e2d718c987 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 b3bdae06fd..8688e60e04 100644 --- a/sp/src/game/client/hud_closecaption.h +++ b/sp/src/game/client/hud_closecaption.h @@ -179,7 +179,7 @@ class CHudCloseCaption : public CHudElement, public vgui::Panel 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 f0a3260171..89f7922872 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 a9f1949697..75d5b8dfb7 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 @@ class CAI_FuncTankBehavior : public CAI_SimpleBehavior 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 963a0e54a3..c446257597 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 01a64dea18..9df7a3ee26 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 2f95099be7..f24ddf6768 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 @@ class CNPC_Alyx : public CNPC_PlayerCompanion 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 62cd9ab22c..ab7647c67f 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 6828a664fd..5d23429d97 100644 --- a/sp/src/game/server/hl2/npc_citizen17.h +++ b/sp/src/game/server/hl2/npc_citizen17.h @@ -370,7 +370,6 @@ class CNPC_Citizen : public CNPC_PlayerCompanion #endif //----------------------------------------------------- - CAI_FuncTankBehavior m_FuncTankBehavior; #ifdef MAPBASE CAI_RappelBehavior m_RappelBehavior; CAI_PolicingBehavior m_PolicingBehavior; @@ -378,6 +377,8 @@ class CNPC_Citizen : public CNPC_PlayerCompanion // 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 7ed8553eaa..ed782f1b69 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 2fe0b843ac..ce23058b9b 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 @@ class CNPC_PlayerCompanion : public CAI_PlayerAlly 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 7fdd89f24b..839c18d943 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 c5b54eefcf..13abe166da 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 7fc1c13b90..bcb54c816d 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 d1b32d1432..0a11c915dd 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 c467ddc400..f62e38db44 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 dc8e44835d..16c57991f2 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 5e12856cc3..35305f5979 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 87f45fce1b..f1b5009a78 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 e95c2dbb74..1a6488c280 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 417d1ee5a3..eff09cfef1 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 2efbd40956..72ee96f9fc 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 44406dee3d..a1a228c840 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 b0c75a149a..3589358e11 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 6d3f3cf612..95ff21448f 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 36d07ed33a..118457873f 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 | 81 +++++++++++-- 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, 283 insertions(+), 51 deletions(-) diff --git a/sp/src/game/server/ai_basenpc.cpp b/sp/src/game/server/ai_basenpc.cpp index e11d6452ee..61cba40aae 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 + // 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()) ); - else -#endif - nCoverActivity = ACT_COVER_LOW; + 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 675412af6f..d666a33d90 100644 --- a/sp/src/game/server/ai_basenpc.h +++ b/sp/src/game/server/ai_basenpc.h @@ -998,6 +998,7 @@ class CAI_BaseNPC : public CBaseCombatCharacter, 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 @@ class CAI_BaseNPC : public CBaseCombatCharacter, 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 8822f75075..4730e122f3 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 ce26ca61ae..f4df0640a1 100644 --- a/sp/src/game/server/ai_behavior.h +++ b/sp/src/game/server/ai_behavior.h @@ -132,6 +132,8 @@ abstract_class CAI_BehaviorBase : public CAI_Component void BridgeHandleAnimEvent( animevent_t *pEvent ); #ifdef MAPBASE bool BridgeCanUnholsterWeapon( void ); + bool BridgeShouldPickADeathPose( void ); + bool BridgeCanTranslateCrouchActivity( void ); #endif virtual void GatherConditions(); @@ -220,6 +222,8 @@ abstract_class CAI_BehaviorBase : public CAI_Component 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 @@ abstract_class IBehaviorBackBridge #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 @@ class CAI_BehaviorHost : public BASE_NPC, void HandleAnimEvent( animevent_t *pEvent ); #ifdef MAPBASE bool CanUnholsterWeapon( void ); + bool ShouldPickADeathPose( void ); + bool CanTranslateCrouchActivity( void ); #endif bool ShouldAlwaysThink(); @@ -534,6 +543,9 @@ class CAI_BehaviorHost : public BASE_NPC, #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 bc5244efb2..8574087643 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 c08059e84a..2de2a0729c 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 @@ class CAI_StandoffBehavior : public CAI_MappedActivityBehavior_Temporary // 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 9d8e0b96ab..b107b9713a 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 61cba40aae..16faea3ac0 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 d666a33d90..fe63f36e8e 100644 --- a/sp/src/game/server/ai_basenpc.h +++ b/sp/src/game/server/ai_basenpc.h @@ -1021,6 +1021,25 @@ class CAI_BaseNPC : public CBaseCombatCharacter, 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 @@ class CAI_BaseNPC : public CBaseCombatCharacter, 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 @@ class CAI_BaseNPC : public CBaseCombatCharacter, #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 @@ class CAI_BaseNPC : public CBaseCombatCharacter, 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 @@ class CAI_BaseNPC : public CBaseCombatCharacter, 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 @@ class CAI_BaseNPC : public CBaseCombatCharacter, 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 d04ff89d7d..06bf690e0a 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 d7b882f86c..38ee7ed15c 100644 --- a/sp/src/game/server/BaseAnimatingOverlay.h +++ b/sp/src/game/server/BaseAnimatingOverlay.h @@ -181,8 +181,10 @@ class CBaseAnimatingOverlay : public CBaseAnimating 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 16faea3ac0..02a8b72599 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 bcb54c816d..e0c9feef4a 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 c9c6fb8e45..f54432ffb7 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 b5f5d2972b..29c05f8464 100644 --- a/sp/src/game/server/ai_motor.h +++ b/sp/src/game/server/ai_motor.h @@ -87,6 +87,9 @@ class CAI_Motor : public CAI_Component, 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 9d6ae06a03..59c06822b8 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 87399c4f22..8bcdcc0826 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 1f8ec4d142..2e8e90af85 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 60052ded90..570f85ef91 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 @@ class CHintCriteria 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 @@ class CHintCriteria 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 @@ class CAI_Hint : public CServerOnlyEntity 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 62d5c6ec2f..cd79279881 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 22aaf5f3af..70bd019c00 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 16d8a7fa58..818324f04f 100644 --- a/sp/src/game/server/ai_network.cpp +++ b/sp/src/game/server/ai_network.cpp @@ -144,6 +144,31 @@ class CNodeFilter : public INodeListFilter 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 16c57991f2..8b4fe93feb 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 35305f5979..e6a32e933c 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 f1b5009a78..20ec1cc988 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 eff09cfef1..a04d30b658 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 72ee96f9fc..2d20211d2c 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 a1a228c840..e0b2e336d9 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 3589358e11..04f7e39010 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 ed782f1b69..97bc54bebf 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 97bc54bebf..97901f93ac 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 73f58af55c..ebeccf2b27 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 d96c75c5b6..2557bec360 100644 --- a/sp/src/game/server/BasePropDoor.h +++ b/sp/src/game/server/BasePropDoor.h @@ -103,6 +103,12 @@ abstract_class CBasePropDoor : public CDynamicProp 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 @@ abstract_class CBasePropDoor : public CDynamicProp 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 02a8b72599..225d8096c0 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 59c06822b8..c58471d0dc 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 9263628b44..2affea8ac8 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 225d8096c0..fc8cd28729 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 20ec1cc988..1ce3329cab 100644 --- a/sp/src/game/server/hl2/weapon_crossbow.cpp +++ b/sp/src/game/server/hl2/weapon_crossbow.cpp @@ -542,7 +542,7 @@ class CWeaponCrossbow : public CBaseHLCombatWeapon 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 1036259e60..3e23ab0f0e 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 0f2fe433aa..abfdb3b05d 100644 --- a/sp/src/game/shared/basecombatweapon_shared.h +++ b/sp/src/game/shared/basecombatweapon_shared.h @@ -321,7 +321,7 @@ class CBaseCombatWeapon : public BASECOMBATWEAPON_DERIVED_FROM 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 7bd4862c44..d9155f3219 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 f1493ce019..924f10310b 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 @@ class CWeaponCustomScripted : public SCRIPTED_WEAPON_DERIVED_FROM 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 13abe166da..0dd620d761 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 fc8cd28729..7167b2c871 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 e0c9feef4a..61fefb3ff0 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 818324f04f..1323b7ce21 100644 --- a/sp/src/game/server/ai_network.cpp +++ b/sp/src/game/server/ai_network.cpp @@ -157,7 +157,7 @@ class CNodeHintFilter : public CNodeFilter 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 f62e38db44..02afb3b7aa 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 1a6488c280..8a0daacf2c 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 95ff21448f..ecee2eee33 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 118457873f..ad39c548c7 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 0884153e1e..992bd0367b 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 b107b9713a..a8579647d1 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 64f11d2a2a..84eba6df84 100644 --- a/sp/src/game/server/hl2/proto_sniper.cpp +++ b/sp/src/game/server/hl2/proto_sniper.cpp @@ -250,6 +250,10 @@ class CProtoSniper : public CAI_BaseNPC 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 d2ec72bf7e..8f758e1279 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 9263628b44..e29b0e235a 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 121dd5c315..ebd87c4da1 100644 --- a/sp/src/game/server/props.h +++ b/sp/src/game/server/props.h @@ -329,6 +329,9 @@ class CDynamicProp : public CBreakableProp, public IPositionWatcher // 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 @@ class CDynamicProp : public CBreakableProp, public IPositionWatcher 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 @@ class CDynamicProp : public CBreakableProp, public IPositionWatcher 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 f366ee571a..2477ec6744 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 135b564500..a273cb286b 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 d14fc7021c..ec49e5a465 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 3076347df2..79b3091211 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 fcf7429107..714f62f400 100644 --- a/sp/src/game/server/hl2/cbasehelicopter.h +++ b/sp/src/game/server/hl2/cbasehelicopter.h @@ -267,6 +267,10 @@ class CAvoidSphere : public CBaseEntity 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 ddb9752ab7..ac6efb1cbe 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 | 308 +++++++++--------- 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, 1664 insertions(+), 256 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 0b2422faba..57a9c7eb34 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 84ccffb5ab..5b5695957f 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 @@ class C_BasePlayer : public C_BaseCombatCharacter, public CGameEventListener 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 @@ class C_BasePlayer : public C_BaseCombatCharacter, public CGameEventListener // 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 6960031d5f..12e29768e8 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 0000000000..63149a0a02 --- /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 4bbcea9472..f7e337087e 100644 --- a/sp/src/game/client/c_colorcorrectionvolume.cpp +++ b/sp/src/game/client/c_colorcorrectionvolume.cpp @@ -36,9 +36,26 @@ class C_ColorCorrectionVolume : public C_BaseEntity 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 @@ class C_ColorCorrectionVolume : public C_BaseEntity }; 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 6f2aa4b819..f2e6e31dc5 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 a1389f9612..20288db8f7 100644 --- a/sp/src/game/client/clientmode_shared.h +++ b/sp/src/game/client/clientmode_shared.h @@ -91,6 +91,11 @@ class ClientModeShared : public IClientMode, public CGameEventListener 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 @@ class ClientModeShared : public IClientMode, public CGameEventListener 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 770354b0fc..cf1210ac7f 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 3d5271db6c..3eba0f8cb7 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 @@ class CColorCorrectionMgr : public CBaseGameSystem 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 @@ class CColorCorrectionMgr : public CBaseGameSystem 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 2b74f62538..38b60047aa 100644 --- a/sp/src/game/client/iclientmode.h +++ b/sp/src/game/client/iclientmode.h @@ -112,6 +112,11 @@ abstract_class IClientMode 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 e3889d74b3..c88858d583 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 16d0122240..69e6db8580 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 0000000000..2e96eb7c56 --- /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 a56cd533e3..abc55d75ff 100644 --- a/sp/src/game/server/colorcorrectionvolume.cpp +++ b/sp/src/game/server/colorcorrectionvolume.cpp @@ -48,7 +48,11 @@ class CColorCorrectionVolume : public CBaseTrigger 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 @@ class CColorCorrectionVolume : public CBaseTrigger 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 bfd4f5a2e7..492b204670 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: Set the tonemap scale to the specified value +// Purpose: //----------------------------------------------------------------------------- -void CEnvTonemapController::InputSetTonemapScale( inputdata_t &inputdata ) +bool CEnvTonemapController::KeyValue( const char *szKeyName, const char *szValue ) { - //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 ( FStrEq( szKeyName, "TonemapScale" ) ) + { + float flTonemapScale = atof( szValue ); + if (flTonemapScale != -1.0f) + { + mat_hdr_tonemapscale.SetValue( flTonemapScale ); + } + } + else if (FStrEq( szKeyName, "TonemapRate" )) { - if ( inputdata.pActivator != NULL && inputdata.pActivator->IsPlayer() ) + float flTonemapRate = atof( szValue ); + if (flTonemapRate != -1.0f) { -// DevMsg("activator is a player: InputSetTonemapScale\n"); - CBasePlayer *pPlayer = ToBasePlayer(inputdata.pActivator); - if (pPlayer) + ConVarRef mat_hdr_manual_tonemap_rate( "mat_hdr_manual_tonemap_rate" ); + if ( mat_hdr_manual_tonemap_rate.IsValid() ) { - pPlayer->InputSetTonemapScale( inputdata ); - return; + 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 ) +{ 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 ) ) + 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 { - if ( inputdata.pActivator != NULL && inputdata.pActivator->IsPlayer() ) + pTonemapController = static_cast( gEntList.FindEntityByClassname( pTonemapController, "env_tonemap_controller" ) ); + if ( pTonemapController ) { -// DevMsg("activator is a player: InputUseDefaultBloomScale\n"); - CBasePlayer *pPlayer = ToBasePlayer(inputdata.pActivator); - if (pPlayer) + if ( m_hMasterController == NULL ) + { + m_hMasterController = pTonemapController; + } + else { - pPlayer->InputUseDefaultBloomScale( inputdata ); - return; + if ( pTonemapController->IsMaster() ) + { + m_hMasterController = pTonemapController; + } } } - } + } while ( pTonemapController ); - m_bUseCustomBloomScale = false; + } + + +//-------------------------------------------------------------------------------------------------------- +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 0000000000..94e3e0f424 --- /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 0000000000..f2f9a718b4 --- /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 0000000000..6bd5880ae1 --- /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 5280b60a3f..524b1e75b8 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 bda4a5fea6..05bf335b20 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 @@ class CBasePlayer : public CBaseCombatCharacter #ifdef MAPBASE bool ShouldUseVisibilityCache( CBaseEntity *pEntity ); + + void UpdateFXVolume( void ); // From Alien Swarm SDK #endif public: @@ -884,9 +890,18 @@ class CBasePlayer : public CBaseCombatCharacter 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 @@ class CBasePlayer : public CBaseCombatCharacter 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 587dbd1a4c..f9ceef70e6 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 523ba8270a..80ece7cf5e 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 daf5bf4181..8238a0b708 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 4e73892086..2bda187c19 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 70fe86c49e..e6d3288a5c 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 fdfcc57e79..e4955ef7d6 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 d3d0c73d96..3322bcdc6d 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 efcaedfb3f..e08fa89408 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 3322bcdc6d..fac51e1d45 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 405b208322..a01ba4d290 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 d6521cc90b..5fa7f1bcc9 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 dcb9aea5c8..bca929c9dd 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 3e9f44c022..e12d63d29d 100644 --- a/sp/src/utils/vbsp/vbsp.h +++ b/sp/src/utils/vbsp/vbsp.h @@ -347,6 +347,8 @@ class CMapFile #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 abaa2d66c6..bcb94845e7 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 bca929c9dd..c479b27949 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 3c660a8836..921e3fe64c 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 797325a0b7..000de791ed 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 0000000000..03602ef2b4 --- /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 4e86eb8541..e8e401a4e7 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 4495afb358..097968dbe7 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 @@ class CBounceBomb : public CBaseAnimating, public CDefaultPlayerPickupVPhysics 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 @@ class CBounceBomb : public CBaseAnimating, public CDefaultPlayerPickupVPhysics #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 e57a714df5..dd02b2ba53 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 b3670281ae..6b08bafc4c 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 3592733370..14ec4a9ace 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 18df0f7b82..56428e73ca 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 1846cfddb8..0a2d75d79a 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 e8e401a4e7..aa9bdf2961 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 d6609449a4..ce19b772a3 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 8238a0b708..b631f9ab7a 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 020855fbb5..b3502e589d 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 e08fa89408..76e1ac12ec 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 e4955ef7d6..f37b4970eb 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 2bda187c19..4428c2c1bc 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 e756073f31..437a16cd23 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 ee62e53990..cdd5d1b872 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 7dd289edc1..007e22c185 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 b631f9ab7a..2fda4762ff 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 b3502e589d..3d1e24adfb 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 f37b4970eb..8ea011478b 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 4428c2c1bc..e69456ea77 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 437a16cd23..a6d812bae1 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 cdd5d1b872..bea9d867b8 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 007e22c185..d57d7d4933 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 76e1ac12ec..efcaedfb3f 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 0000000000..447b3cec77 --- /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 d57d7d4933..e94ebd7649 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 839c18d943..218da1a552 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 5c281d59fa..91e6a3c639 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 @@ class CNPC_Vortigaunt : public CNPC_PlayerCompanion #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 1ce3329cab..2287ce849b 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 ecee2eee33..5b13c7505e 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 ad39c548c7..8663ce3ab2 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 4cf69736ea..8c736cabda 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 8c736cabda..dd6c5b6f0f 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 02afb3b7aa..7a64a9638c 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 0ef81cc568..236e39b4dd 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 dd6c5b6f0f..d9ad0e600c 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 dd02b2ba53..ef410283aa 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 269d44ecdd..5ff4dbb425 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 57a9c7eb34..c02a54a8f0 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 639fd4c581..0545d0a318 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 492b204670..95cf61358f 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 c02a54a8f0..acb398f02e 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 4d593fc59c..97a2217d3c 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 cb9c1fc8ff..57683a19a0 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 46e80cc5f5..e3dc3f03b4 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 0ffc68f5c4..a4886730f4 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 @@ class CHL2_Player : public CBasePlayer 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 8b4fe93feb..a73a97ba1e 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 e6a32e933c..6b634de07b 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 2287ce849b..b8d9db711d 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 8a0daacf2c..46c935a85d 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 b0e188aa53..c248c74e12 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 87fddf4e9d..3dfe86c3a5 100644 --- a/sp/src/game/server/hl2/weapon_physcannon.cpp +++ b/sp/src/game/server/hl2/weapon_physcannon.cpp @@ -1238,6 +1238,9 @@ class CWeaponPhysCannon : public CBaseHLCombatWeapon 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 a04d30b658..6608479716 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 2d20211d2c..3a8be2192a 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 e0b2e336d9..50752e8ce1 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 04f7e39010..96cfdd2c75 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 80ece7cf5e..b04706d48d 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 0000000000..3936040f9b --- /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 0000000000..7609237a56 --- /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 | 623 +++++++++++------- .../shared/mapbase/singleplayer_animstate.h | 104 +-- 5 files changed, 478 insertions(+), 476 deletions(-) diff --git a/sp/src/game/server/hl2/hl2_player.cpp b/sp/src/game/server/hl2/hl2_player.cpp index e3dc3f03b4..02e1d9e0a3 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 a4886730f4..b493f78a70 100644 --- a/sp/src/game/server/hl2/hl2_player.h +++ b/sp/src/game/server/hl2/hl2_player.h @@ -132,8 +132,9 @@ class CHL2_Player : public CBasePlayer // 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 d90655ac53..82cb75aae2 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 3936040f9b..8f184c7a12 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,259 +68,392 @@ 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()); + if ( HandleJumping() ) + { + return ACT_HL2MP_JUMP; + } + else + { + Activity idealActivity = ACT_HL2MP_IDLE; - ComputePlaybackRate(); -} + if ( GetOuter()->GetFlags() & ( FL_FROZEN | FL_ATCONTROLS ) ) + { + speed = 0; + } + else + { + 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; + } + } + } -void CSinglePlayerAnimState::Release() -{ - delete this; + return idealActivity; + } + + //return m_pPlayer->GetActivity(); +#endif } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- -void CSinglePlayerAnimState::ComputePlaybackRate() +void CSinglePlayerAnimState::SetPlayerAnimation( PLAYER_ANIM playerAnim ) { - // 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 ) ) + if ( playerAnim == PLAYER_ATTACK1 ) { - 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 + m_iFireSequence = SelectWeightedSequence( TranslateActivity( ACT_HL2MP_GESTURE_RANGE_ATTACK ) ); + m_bFiring = m_iFireSequence != -1; + m_flFireCycle = 0; } - else + else if ( playerAnim == PLAYER_JUMP ) { - GetBasePlayer()->SetPlaybackRate( 1.0f ); + // 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: -// Output : CBasePlayer //----------------------------------------------------------------------------- -CBasePlayer *CSinglePlayerAnimState::GetBasePlayer() +Activity CSinglePlayerAnimState::TranslateActivity( Activity actDesired ) { - return m_pPlayer; +#ifdef CLIENT_DLL + return actDesired; +#else + return m_pPlayer->Weapon_TranslateActivity( actDesired ); +#endif } //----------------------------------------------------------------------------- // Purpose: -// Input : dt - //----------------------------------------------------------------------------- -void CSinglePlayerAnimState::EstimateYaw( void ) +bool CSinglePlayerAnimState::HandleJumping() { - 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; - } + 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: Override for backpeddling -// Input : dt - +// Purpose: //----------------------------------------------------------------------------- -void CSinglePlayerAnimState::ComputePoseParam_BodyYaw( void ) +void CSinglePlayerAnimState::ComputeSequences( CStudioHdr *pStudioHdr ) { - int iYaw = GetBasePlayer()->LookupPoseParameter( "move_yaw" ); - if ( iYaw < 0 ) - return; + CBasePlayerAnimState::ComputeSequences(pStudioHdr); - // view direction relative to movement - float flYaw; + ComputeFireSequence(); + ComputeMiscSequence(); + ComputeReloadSequence(); + ComputeWeaponSwitchSequence(); +} - EstimateYaw(); +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CSinglePlayerAnimState::ClearAnimationState() +{ + m_bJumping = false; + m_bFiring = false; + m_bReloading = false; + m_bWeaponSwitching = false; + m_bPlayingMisc = false; + CBasePlayerAnimState::ClearAnimationState(); +} - QAngle angles = GetBasePlayer()->GetLocalAngles(); - float ang = angles[ YAW ]; - if ( ang > 180.0f ) - { - ang -= 360.0f; - } - else if ( ang < -180.0f ) - { - ang += 360.0f; - } +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 + } +} - // calc side to side turning - flYaw = ang - m_flGaitYaw; - // Invert for mapping into 8way blend - flYaw = -flYaw; - flYaw = flYaw - (int)(flYaw / 360) * 360; +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int CSinglePlayerAnimState::CalcAimLayerSequence( float *flCycle, float *flAimSequenceWeight, bool bForceIdle ) +{ + // TODO? + return m_pOuter->LookupSequence( "soldier_Aim_9_directions" ); +} - if (flYaw < -180) - { - flYaw = flYaw + 360; - } - else if (flYaw > 180) - { - flYaw = flYaw - 360; - } - - GetBasePlayer()->SetPoseParameter( iYaw, flYaw ); +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 - //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 ) ); + pLayer->m_fFlags |= ANIM_LAYER_ACTIVE; #endif + pLayer->SetOrder( iLayer ); } -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -void CSinglePlayerAnimState::ComputePoseParam_BodyPitch( CStudioHdr *pStudioHdr ) +void CSinglePlayerAnimState::ComputeFireSequence() { - // Get pitch from v_angle - float flPitch = GetBasePlayer()->GetLocalAngles()[ PITCH ]; + UpdateLayerSequenceGeneric( FIRESEQUENCE_LAYER, m_bFiring, m_flFireCycle, m_iFireSequence, false ); +} - if ( flPitch > 180.0f ) - { - flPitch -= 360.0f; - } - flPitch = clamp( flPitch, -90, 90 ); +void CSinglePlayerAnimState::ComputeReloadSequence() +{ + UpdateLayerSequenceGeneric( RELOADSEQUENCE_LAYER, m_bReloading, m_flReloadCycle, m_iReloadSequence, false, m_flReloadBlendIn, m_flReloadBlendOut, false, m_fReloadPlaybackRate ); +} - QAngle absangles = GetBasePlayer()->GetAbsAngles(); - absangles.x = 0.0f; - m_angRender = absangles; +void CSinglePlayerAnimState::ComputeWeaponSwitchSequence() +{ + UpdateLayerSequenceGeneric( RELOADSEQUENCE_LAYER, m_bWeaponSwitching, m_flWeaponSwitchCycle, m_iWeaponSwitchSequence, false, 0, 0.5f ); +} - // See if we have a blender for pitch - GetBasePlayer()->SetPoseParameter( pStudioHdr, "aim_pitch", flPitch ); +// 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 : goal - -// maxrate - -// dt - -// current - -// Output : int +// Purpose: +// Input : - +// Output : float //----------------------------------------------------------------------------- -int CSinglePlayerAnimState::ConvergeAngles( float goal,float maxrate, float dt, float& current ) +float CSinglePlayerAnimState::GetCurrentMaxGroundSpeed() { - int direction = TURN_NONE; + CStudioHdr *pStudioHdr = GetOuter()->GetModelPtr(); - float anglediff = goal - current; - float anglediffabs = fabs( anglediff ); + if ( pStudioHdr == NULL ) + return 1.0f; - anglediff = AngleNormalize( anglediff ); + int iMoveX = GetOuter()->LookupPoseParameter( "move_x" ); + int iMoveY = GetOuter()->LookupPoseParameter( "move_y" ); - 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 prevX = GetOuter()->GetPoseParameter( iMoveX ); + float prevY = GetOuter()->GetPoseParameter( iMoveY ); - float maxmove = maxrate * dt * scale; + 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; + } - if ( fabs( anglediff ) < maxmove ) - { - current = goal; - } - else - { - if ( anglediff > 0 ) - { - current += maxmove; - direction = TURN_LEFT; - } - else - { - current -= maxmove; - direction = TURN_RIGHT; - } - } + GetOuter()->SetPoseParameter( pStudioHdr, iMoveX, newX ); + GetOuter()->SetPoseParameter( pStudioHdr, iMoveY, newY ); - current = AngleNormalize( current ); + float speed = GetOuter()->GetSequenceGroundSpeed(GetOuter()->GetSequence() ); - return direction; + GetOuter()->SetPoseParameter( pStudioHdr, iMoveX, prevX ); + GetOuter()->SetPoseParameter( pStudioHdr, iMoveY, prevY ); + + return speed; } +//----------------------------------------------------------------------------- +// Purpose: Override for backpeddling +// Input : dt - +//----------------------------------------------------------------------------- +void CSinglePlayerAnimState::ComputePoseParam_BodyYaw( void ) +{ + CBasePlayerAnimState::ComputePoseParam_BodyYaw(); + + //ComputePoseParam_BodyLookYaw(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- 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,19 +571,19 @@ 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 ); } */ @@ -436,12 +592,10 @@ void CSinglePlayerAnimState::ComputePoseParam_BodyLookYaw( void ) //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- -void CSinglePlayerAnimState::ComputePoseParam_HeadPitch( CStudioHdr *pStudioHdr ) +void CSinglePlayerAnimState::ComputePoseParam_BodyPitch( CStudioHdr *pStudioHdr ) { // Get pitch from v_angle - int iHeadPitch = GetBasePlayer()->LookupPoseParameter("head_pitch"); - - float flPitch = GetBasePlayer()->EyeAngles()[PITCH]; + float flPitch = m_flEyePitch; if ( flPitch > 180.0f ) { @@ -449,56 +603,35 @@ 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 ); + // See if we have a blender for pitch + GetOuter()->SetPoseParameter( pStudioHdr, "aim_pitch", flPitch ); + + ComputePoseParam_HeadPitch( pStudioHdr ); } - //----------------------------------------------------------------------------- // Purpose: -// Input : activity - -// Output : Activity //----------------------------------------------------------------------------- -Activity CSinglePlayerAnimState::BodyYawTranslateActivity( Activity activity ) +void CSinglePlayerAnimState::ComputePoseParam_HeadPitch( CStudioHdr *pStudioHdr ) { - // Not even standing still, sigh - if ( activity != ACT_IDLE ) - return activity; + // Get pitch from v_angle + int iHeadPitch = GetOuter()->LookupPoseParameter("head_pitch"); - // Not turning - switch ( m_nTurningInPlace ) + float flPitch = m_flEyePitch; + + if ( flPitch > 180.0f ) { - 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; + flPitch -= 360.0f; } + flPitch = clamp( flPitch, -90, 90 ); - Assert( 0 ); - return activity; -} - -const QAngle& CSinglePlayerAnimState::GetRenderAngles() -{ - return m_angRender; -} + QAngle absangles = GetOuter()->GetAbsAngles(); + absangles.x = 0.0f; + m_angRender = absangles; -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 7609237a56..460e6e12f2 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 ); - - Activity BodyYawTranslateActivity( Activity activity ); + void SetPlayerAnimation( PLAYER_ANIM playerAnim ); + Activity TranslateActivity( Activity actDesired ); - void Update(); + void ComputeSequences( CStudioHdr *pStudioHdr ); - const QAngle& GetRenderAngles(); - - void GetPoseParameters( CStudioHdr *pStudioHdr, float poseParameter[MAXSTUDIOPOSEPARAM] ); + void ClearAnimationState(); + void ClearAnimationLayers(); - CBasePlayer *GetBasePlayer(); +private: - void Release(); + bool HandleJumping(); -private: - void GetOuterAbsVelocity( Vector& vel ); + void ComputeFireSequence(); + void ComputeReloadSequence(); + void ComputeWeaponSwitchSequence(); + void ComputeMiscSequence(); - int ConvergeAngles( float goal,float maxrate, float dt, float& current ); + 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; - - 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; + CBasePlayer* m_pPlayer; + + // Current state variables. + bool m_bJumping; // Set on a jump event. + float m_flJumpStartTime; + bool m_bFirstJumpFrame; + + // 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; + + bool m_bWeaponSwitching; + float m_flWeaponSwitchCycle; + int m_iWeaponSwitchSequence; + + 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 | 40 ++++++---------------- 2 files changed, 15 insertions(+), 35 deletions(-) diff --git a/sp/src/game/server/basecombatcharacter.cpp b/sp/src/game/server/basecombatcharacter.cpp index c39271569a..c11eb9fa78 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 524b1e75b8..1f52ea4ffb 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); - - 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; + // 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; + + 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 7a64a9638c..1468711836 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 a73a97ba1e..4c180932af 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 6b634de07b..54576eb195 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 612fe142c3..f8fcabf3da 100644 --- a/sp/src/game/server/hl2/weapon_bugbait.cpp +++ b/sp/src/game/server/hl2/weapon_bugbait.cpp @@ -58,6 +58,9 @@ class CWeaponBugBait : public CBaseHLCombatWeapon 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 50752e8ce1..539cceed65 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 96cfdd2c75..bfafeb5831 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 5b13c7505e..3c888c6f0c 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 8663ce3ab2..5b5f34686a 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 1468711836..f1a36cf822 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 4c180932af..b0ae2131b1 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 538f63120f..dbd57cec88 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 47ee9e3970..23b0c1961a 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 54576eb195..c9c2738817 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 f8fcabf3da..330cf2c676 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 b8d9db711d..7766ff9890 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 46c935a85d..cee8d0f957 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 c248c74e12..01a9b17a18 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 3dfe86c3a5..a08dc22099 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 6608479716..dce9326266 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 3a8be2192a..9f49684f76 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 539cceed65..9724408aa3 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 bfafeb5831..4097f2aeda 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 3c888c6f0c..4493a50cc7 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 5b5f34686a..e73c571a7d 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 5bdea44f06..36dd9825d0 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 992bd0367b..b936b19465 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 8f184c7a12..e3b84b4dfe 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 33a700fc8f..894c290b22 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 02e1d9e0a3..be1ecf1138 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 b493f78a70..49f41deb1c 100644 --- a/sp/src/game/server/hl2/hl2_player.h +++ b/sp/src/game/server/hl2/hl2_player.h @@ -134,6 +134,8 @@ class CHL2_Player : public CBasePlayer #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 c9c2738817..6bb1f1207c 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 01a9b17a18..aeba27851f 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 a08dc22099..6585a59c12 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 9f49684f76..750dbf8abc 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 9724408aa3..746560587b 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 4097f2aeda..280d8e08a3 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 3e23ab0f0e..50c2ea2526 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 e3b84b4dfe..380dbd8936 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 460e6e12f2..a805dffc2d 100644 --- a/sp/src/game/shared/mapbase/singleplayer_animstate.h +++ b/sp/src/game/shared/mapbase/singleplayer_animstate.h @@ -48,6 +48,8 @@ class CSinglePlayerAnimState : public CBasePlayerAnimState 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 @@ class CSinglePlayerAnimState : public CBasePlayerAnimState 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 11f8e8aaf6..7e533ceb74 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 1f52ea4ffb..659eb74873 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 0545d0a318..b1973c51d5 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 acb398f02e..6e06834155 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 5b5695957f..bc8ca65419 100644 --- a/sp/src/game/client/c_baseplayer.h +++ b/sp/src/game/client/c_baseplayer.h @@ -207,6 +207,11 @@ class C_BasePlayer : public C_BaseCombatCharacter, public CGameEventListener 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 @@ class C_BasePlayer : public C_BaseCombatCharacter, public CGameEventListener { 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 be1ecf1138..903033ee5f 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 49f41deb1c..0f0087c4a5 100644 --- a/sp/src/game/server/hl2/hl2_player.h +++ b/sp/src/game/server/hl2/hl2_player.h @@ -138,6 +138,8 @@ class CHL2_Player : public CBasePlayer 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 7766ff9890..71df75f359 100644 --- a/sp/src/game/server/hl2/weapon_crossbow.cpp +++ b/sp/src/game/server/hl2/weapon_crossbow.cpp @@ -591,6 +591,7 @@ class CWeaponCrossbow : public CBaseHLCombatWeapon 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 6585a59c12..8a52143c6a 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 17b3cf537e..15a33ea8c2 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 fe838cad76..368c9bb12c 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 @@ class C_BaseHLPlayer : public C_BasePlayer 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 @@ class C_BaseHLPlayer : public C_BasePlayer 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 903033ee5f..5668ee7a0b 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 0f0087c4a5..9f41826900 100644 --- a/sp/src/game/server/hl2/hl2_player.h +++ b/sp/src/game/server/hl2/hl2_player.h @@ -442,7 +442,10 @@ class CHL2_Player : public CBasePlayer #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 380dbd8936..251681dac0 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 251681dac0..53f4e28461 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 71df75f359..2dc487dafc 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 8a52143c6a..842d6a5f93 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 f1a36cf822..4fd0300b21 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 b0ae2131b1..38a152461d 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 4493a50cc7..e7326e64c9 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 e73c571a7d..39cc48fc0a 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 447b3cec77..950e16772f 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 ce19b772a3..f51ed14468 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 f51ed14468..a8b0244fb0 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 4fd0300b21..a2ac4c14a1 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 d2d7639425..ccdd16c815 100644 --- a/sp/src/game/server/basecombatcharacter.h +++ b/sp/src/game/server/basecombatcharacter.h @@ -412,6 +412,9 @@ class CBaseCombatCharacter : public CBaseFlex } 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 a8579647d1..229db7b048 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 63a4ee6d63..e517a6fe69 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 23b0c1961a..ae499a49ea 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 @@ class CWeaponAnnabelle : public CBaseHLCombatWeapon 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 @@ class CWeaponAnnabelle : public CBaseHLCombatWeapon 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 746560587b..71df2695d2 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 e7326e64c9..8c7d24ae95 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 39cc48fc0a..7177c5cd23 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 97901f93ac..08def106c5 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 ce23058b9b..8dcf1aa167 100644 --- a/sp/src/game/server/hl2/npc_playercompanion.h +++ b/sp/src/game/server/hl2/npc_playercompanion.h @@ -282,6 +282,9 @@ class CNPC_PlayerCompanion : public CAI_PlayerAlly 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 750dbf8abc..36a60dd1fe 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 3c9dae5f61..a536d1c22f 100644 --- a/sp/src/game/server/hl2/weapon_rpg.h +++ b/sp/src/game/server/hl2/weapon_rpg.h @@ -216,6 +216,9 @@ class CWeaponRPG : public CBaseHLCombatWeapon 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 53f4e28461..8cc9337e18 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 a2ac4c14a1..530f27a78b 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 5668ee7a0b..b79396077c 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 9f41826900..12c0386c85 100644 --- a/sp/src/game/server/hl2/hl2_player.h +++ b/sp/src/game/server/hl2/hl2_player.h @@ -132,6 +132,8 @@ class CHL2_Player : public CBasePlayer // 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 8c7d24ae95..98fe580b72 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 7177c5cd23..c13df83fbb 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 330cf2c676..72967d7d29 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 50c2ea2526..e6b61249a0 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 b79396077c..00fdbcfdef 100644 --- a/sp/src/game/server/hl2/hl2_player.cpp +++ b/sp/src/game/server/hl2/hl2_player.cpp @@ -331,39 +331,41 @@ class CCommandRedirect : public CBaseTrigger } // 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 00fdbcfdef..afb2c1cb77 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 530f27a78b..dc090f7ec4 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 d9ad0e600c..8c3fbc61a4 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 8574087643..29c89e3990 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 2de2a0729c..9141e87434 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 f54432ffb7..87a8ec6e7e 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 c58471d0dc..dacab2aa94 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 afb2c1cb77..c148ba3e85 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 9df7a3ee26..ee8b197ceb 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 79ff9a0e67..42822d2ff3 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 aedf23ac42..50d109825b 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 be53f34497..6e5ec1362a 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 38a152461d..ac415c9e10 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 dbd57cec88..5bf20eb6d9 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 ae499a49ea..6b7ecdd9ce 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 6bb1f1207c..0437c15d36 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 72967d7d29..d9e6f94ca4 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 3d82e46c96..95a0229633 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 2dc487dafc..8a0f306bfa 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 cee8d0f957..7cc34b9cb3 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 aeba27851f..91eddcd3c5 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 842d6a5f93..2e9854608d 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 dce9326266..9819f7481a 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 36a60dd1fe..645ca8e603 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 71df2695d2..5348e08a96 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 280d8e08a3..b11fbedc38 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 14ec4a9ace..543969c23e 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 98fe580b72..1a2c1955c8 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 c13df83fbb..99d0931299 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 e6b61249a0..c95a01891e 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 36dd9825d0..c4eb714064 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 b936b19465..1d6ae161a0 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 8cc9337e18..7c8b92c98a 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 dc090f7ec4..2627f0812b 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 994cdabbb0..c6e492398c 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 @@ class CWeaponAR1 : public CHLMachineGun 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 0437c15d36..1a3a1633f5 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 d5376a834c..5a855f2c8a 100644 --- a/sp/src/game/server/hl2/weapon_ar2.h +++ b/sp/src/game/server/hl2/weapon_ar2.h @@ -71,6 +71,9 @@ class CWeaponAR2 : public CHLMachineGun 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 498faddd0e..9c5037b959 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 901a73aea5..10777f89ad 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 @@ class CWeaponSniperRifle : public CBaseHLCombatWeapon 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 1a2c1955c8..0b17d272ac 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 99d0931299..2373f2f93e 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 29c89e3990..00e1565b53 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 921e3fe64c..49f3c189fe 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 2627f0812b..1f7245abcf 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 0b17d272ac..b8aea0bf06 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 1f7245abcf..d23168577d 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 659eb74873..d713a8c370 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 c5ad733d8b..069960f6a7 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 264fdb3d20..63ebececbc 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 @@ class CAI_ActBusyBehavior : public CAI_SimpleBehavior 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 20b2379cfd..3ee20fb2c2 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 0dd620d761..1c86747248 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 6082be1f34..0f2f57df23 100644 --- a/sp/src/game/client/c_baseanimating.h +++ b/sp/src/game/client/c_baseanimating.h @@ -737,6 +737,10 @@ class C_ClientRagdoll : public C_BaseAnimating, public IPVSNotify 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 3dd2d7b5ba..3db90618a3 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 ded9377371..86938039a6 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 758f4719e2..5f4f705808 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 @@ class CRagdollLRURetirement : public CAutoGameSystemPerFrame 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 @@ class CRagdollLRURetirement : public CAutoGameSystemPerFrame 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 c148ba3e85..d44849e7f0 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 877cf9ff9f..8550b6dc00 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 @@ class CMapbaseSystem : public CAutoGameSystem 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 1a3a1633f5..6e7d4cac27 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 19c18d7a93..dd92934607 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 261b938bf5..776a96807e 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 919bd9e924..5747d8edfe 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 fb6545f921..5c03e8393b 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 fc619616c0..53a297630f 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 7d4021721b..60d3d21b1e 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 59db331796..8ca3ae7cf4 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 dc3092f1de..4b1a834415 100644 --- a/sp/src/game/shared/mapbase/vscript_singletons.cpp +++ b/sp/src/game/shared/mapbase/vscript_singletons.cpp @@ -2290,9 +2290,18 @@ class CScriptConCommand : public ConCommand, public ICommandCallback, public ICo { 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 86938039a6..a9da261302 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 a01ba4d290..1b2891ab1d 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 17988d183e..8cd5293d40 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 c95a01891e..551fc52d00 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 abfdb3b05d..88078e3eee 100644 --- a/sp/src/game/shared/basecombatweapon_shared.h +++ b/sp/src/game/shared/basecombatweapon_shared.h @@ -417,6 +417,12 @@ class CBaseCombatWeapon : public BASECOMBATWEAPON_DERIVED_FROM 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 47acecd64f..7c4a401330 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 8d64f4a5f8..06c69df7c8 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 51dcff107e..54b9429aee 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 56803dfa69..d3995ee1e5 100644 --- a/sp/src/game/shared/weapon_parse.h +++ b/sp/src/game/shared/weapon_parse.h @@ -116,6 +116,13 @@ class FileWeaponInfo_t 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 0ab9733023..93ca871e1e 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 e1c41c1238..7a71e270bb 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 fe63f36e8e..878a6f817f 100644 --- a/sp/src/game/server/ai_basenpc.h +++ b/sp/src/game/server/ai_basenpc.h @@ -1005,6 +1005,10 @@ class CAI_BaseNPC : public CBaseCombatCharacter, 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 b17001189c..334ae92ca7 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 77fa8112e9..c51715cf09 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 a8b0244fb0..924b32fe50 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 c11eb9fa78..c0bb5f1b0f 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 d98ea9cdda..abee7a5d85 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) - { - // 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(); - } - } - - 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; - } + // 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 { - const CEntInfo *pInfo = gEntList.FirstEntInfo(); - - for ( ;pInfo; pInfo = pInfo->m_pNext ) + CBaseEntity *target = NULL; + while ( 1 ) { - CBaseEntity *ent = (CBaseEntity *)pInfo->m_pEntity; - if ( !ent ) - { - DevWarning( "NULL entity in global entity list!\n" ); - continue; - } - - if ( !ent->GetEntityName() ) - continue; + target = gEntList.FindEntityByName( target, pe->m_iTarget, pSearchingEntity, pe->m_pActivator, pe->m_pCaller ); + if ( !target ) + break; - 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; - } + // 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 - 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 bb555a1faf..dd886ab315 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 @@ class CAimTargetManager : public IEntityListener // 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 @@ class CAimTargetManager : public IEntityListener 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 505b196820..e2339ada1e 100644 --- a/sp/src/game/server/entitylist.h +++ b/sp/src/game/server/entitylist.h @@ -74,6 +74,26 @@ class CNullEntityFilter : public IEntityFindFilter 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 @@ class CGlobalEntityList : public CBaseEntityList 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 @@ class CGlobalEntityList : public CBaseEntityList 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 76d66a8384..559c57e3d0 100644 --- a/sp/src/game/server/vscript_server.cpp +++ b/sp/src/game/server/vscript_server.cpp @@ -122,6 +122,24 @@ class CScriptEntityIterator : public IEntityListener 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 492a4939ef..9f3d78b773 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 8c3fbc61a4..c5fa8c7bbc 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 dafad41e4a..1bc7caf8c0 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 5ed1225550..69406fa5bc 100644 --- a/sp/src/game/server/ai_speech.h +++ b/sp/src/game/server/ai_speech.h @@ -192,6 +192,10 @@ class CAI_Expresser : public IResponseFilter 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 0437c28086..9f0f30108b 100644 --- a/sp/src/game/server/sceneentity.cpp +++ b/sp/src/game/server/sceneentity.cpp @@ -159,6 +159,7 @@ class CSceneManager : public CBaseEntity #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 @@ class CSceneEntity : public CPointEntity, public IChoreoEventCallback 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 6e005a60bf..8f22154049 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 69406fa5bc..72c704b864 100644 --- a/sp/src/game/server/ai_speech.h +++ b/sp/src/game/server/ai_speech.h @@ -184,6 +184,10 @@ class CAI_Expresser : public IResponseFilter 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 41fe618276..8d73911f6b 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 1882e66e9b..70e73354ee 100644 --- a/sp/src/game/server/ai_speech_new.h +++ b/sp/src/game/server/ai_speech_new.h @@ -211,6 +211,10 @@ class CAI_Expresser : public ResponseRules::IResponseFilter 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 72c704b864..a0a82318a5 100644 --- a/sp/src/game/server/ai_speech.h +++ b/sp/src/game/server/ai_speech.h @@ -185,7 +185,7 @@ class CAI_Expresser : public IResponseFilter 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 cd5fe6f6ae..101a52524b 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 101a52524b..b84654196a 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 b84654196a..15d8c1ffef 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 4b1a834415..535e1d1d87 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 @@ class CScriptSteamAPI return steamapicontext->SteamUtils()->GetCurrentBatteryPower(); } - +#if 0 const char *GetIPCountry() { if ( !steamapicontext || !steamapicontext->SteamUtils() ) @@ -3047,7 +3066,7 @@ class CScriptSteamAPI return ret; } - +#endif const char *GetCurrentGameLanguage() { if ( !steamapicontext || !steamapicontext->SteamApps() ) @@ -3066,6 +3085,7 @@ class CScriptSteamAPI } 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 535e1d1d87..bf28a31bd6 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 fee631181b..1656f5672f 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 1d84e4ce7a..f580fe46b1 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 @@ class C_BaseCombatCharacter : public C_BaseFlex 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 c11eb9fa78..53c2802aaf 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 ccdd16c815..b9bb748117 100644 --- a/sp/src/game/server/basecombatcharacter.h +++ b/sp/src/game/server/basecombatcharacter.h @@ -420,10 +420,10 @@ class CBaseCombatCharacter : public CBaseFlex 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 @@ class CBaseCombatCharacter : public CBaseFlex 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 c95a01891e..e4adfc627b 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 | 188 +++++++++++++++--- .../game/shared/mapbase/vscript_singletons.h | 25 ++- 2 files changed, 177 insertions(+), 36 deletions(-) diff --git a/sp/src/game/shared/mapbase/vscript_singletons.cpp b/sp/src/game/shared/mapbase/vscript_singletons.cpp index bf28a31bd6..f1b72c1d3a 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 + int count = m_MsgIn_()ReadUBitLong( SCRIPT_NETMSG_QUEUE_BITS ); + DebugNetMsg( 2, " msg count %d\n", count ); + while ( count-- ) +#endif { + 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 ) + 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 ) + 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 ) ); + DevWarning( 1, DLL_LOC_STR " NetMsg: invalid callback '%s'\n", GetNetMsgName( hash ) ); #else - DevWarning( 1, DLL_LOC_STR " NetMsg: invalid callback [%d]\n", hash ); + DevWarning( 1, DLL_LOC_STR " NetMsg: invalid callback [%d]\n", hash ); #endif + } + g_pScriptVM->ReleaseValue( hfn ); } - g_pScriptVM->ReleaseValue( hfn ); - } - else - { - DevWarning( 1, DLL_LOC_STR " NetMsg hook not found [%d]\n", hash ); + 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 ( func ) + if ( !msg || !msg[0] ) { + g_pScriptVM->RaiseException( DLL_LOC_STR "NetMsg: invalid message name" ); + return; + } + #ifdef _DEBUG - NetMsgHook_t &hook = g_NetMsgHooks[ g_NetMsgHooks.AddToTail() ]; - hook.Set( msg ); + 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 - g_pScriptVM->SetValue( m_Hooks, int( HashStringCaseless(msg) ), func ); + + if ( 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 a18d4a38ff..825320c0b2 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 @@ class CNetMsgScriptHelper 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 ) ]; +#ifdef CLIENT_DLL + int m_iLastBit; +#endif + public: + CNetMsgScriptHelper() : m_Hooks(NULL) + #ifdef CLIENT_DLL - CNetMsgScriptHelper() : m_Hooks(NULL), m_bWriteReady(false) {} + , m_bWriteReady(0), m_bWriteIgnore(0), m_nQueueCount(0), m_iLastBit(0) #else - CNetMsgScriptHelper() : m_Hooks(NULL) {} + , m_MsgIn(0) #endif + {} + public: #ifdef CLIENT_DLL bool Init(); // IGameSystem @@ -135,6 +150,8 @@ class CNetMsgScriptHelper //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 f1b72c1d3a..64212d44aa 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 825320c0b2..e514f4d990 100644 --- a/sp/src/game/shared/mapbase/vscript_singletons.h +++ b/sp/src/game/shared/mapbase/vscript_singletons.h @@ -102,14 +102,6 @@ class CNetMsgScriptHelper 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 fd31f79285..86070442a9 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 ef410283aa..b0cbaf02c9 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 ); - - CBaseEntity *pLooker = ToEnt(entIgnore); - UTIL_TraceLine( vecStart, vecEnd, iMask, pLooker, iCollisionGroup, &traceInfo->GetTrace()); + CScriptGameTrace *tr = new CScriptGameTrace(); - // The trace's destruction should destroy this automatically - CSurfaceScriptAccessor *surfaceInfo = new CSurfaceScriptAccessor( traceInfo->GetTrace().surface ); - HSCRIPT hSurface = g_pScriptVM->RegisterInstance( surfaceInfo ); - traceInfo->SetSurface( hSurface ); + CBaseEntity *pIgnore = ToEnt( entIgnore ); + UTIL_TraceLine( vecStart, vecEnd, iMask, pIgnore, iCollisionGroup, tr ); - HSCRIPT hPlane = g_pScriptVM->RegisterInstance( &(traceInfo->GetTrace().plane) ); - traceInfo->SetPlane( hPlane ); + tr->RegisterSurface(); + tr->RegisterPlane(); - 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 ); - - CBaseEntity *pLooker = ToEnt(entIgnore); - UTIL_TraceHull( vecStart, vecEnd, hullMin, hullMax, iMask, pLooker, iCollisionGroup, &traceInfo->GetTrace()); + CScriptGameTrace *tr = new CScriptGameTrace(); - // The trace's destruction should destroy this automatically - CSurfaceScriptAccessor *surfaceInfo = new CSurfaceScriptAccessor( traceInfo->GetTrace().surface ); - HSCRIPT hSurface = g_pScriptVM->RegisterInstance( surfaceInfo ); - traceInfo->SetSurface( hSurface ); + CBaseEntity *pIgnore = ToEnt( entIgnore ); + UTIL_TraceHull( vecStart, vecEnd, hullMin, hullMax, iMask, pIgnore, iCollisionGroup, tr ); - HSCRIPT hPlane = g_pScriptVM->RegisterInstance( &(traceInfo->GetTrace().plane) ); - traceInfo->SetPlane( hPlane ); + tr->RegisterSurface(); + tr->RegisterPlane(); - 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 c7ad9ca718..bcf9174125 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; } - - 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(); +public: + float GetFriction() const { return physics.friction; } + float GetThickness() const { return physics.thickness; } + + float GetJumpFactor() const { return game.jumpFactor; } + char GetMaterialChar() const { return game.material; } + + 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) + m_hScriptInstance = g_pScriptVM->RegisterInstance( this ); + } + + ~CScriptGameTrace() + { + if ( m_hScriptInstance ) { - CSurfaceScriptAccessor *pScriptSurface = HScriptToClass( m_surfaceAccessor ); - //g_pScriptVM->RemoveInstance( m_surfaceAccessor ); - delete pScriptSurface; + g_pScriptVM->RemoveInstance( m_hScriptInstance ); } - //if (m_planeAccessor) - //{ - // g_pScriptVM->RemoveInstance( m_planeAccessor ); - //} - } + if ( m_surfaceAccessor ) + { + g_pScriptVM->RemoveInstance( m_surfaceAccessor ); + } - // 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(); } + if ( m_planeAccessor ) + { + g_pScriptVM->RemoveInstance( m_planeAccessor ); + } + } - float FractionLeftSolid() const { return m_tr.fractionleftsolid; } - int HitGroup() const { return m_tr.hitgroup; } - int PhysicsBone() const { return m_tr.physicsbone; } + void RegisterSurface() + { + m_surfaceHelper.Init( &surface ); + m_surfaceAccessor = g_pScriptVM->RegisterInstance( &m_surfaceHelper ); + } - HSCRIPT Entity() const { return ToHScript(m_tr.m_pEnt); } + void RegisterPlane() + { + m_planeAccessor = g_pScriptVM->RegisterInstance( &plane ); + } - int HitBox() const { return m_tr.hitbox; } + HSCRIPT GetScriptInstance() const + { + return m_hScriptInstance; + } - // 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(); } +public: + float FractionLeftSolid() const { return fractionleftsolid; } + int HitGroup() const { return hitgroup; } + int PhysicsBone() const { return physicsbone; } - const Vector& StartPos() const { return m_tr.startpos; } - const Vector& EndPos() const { return m_tr.endpos; } + HSCRIPT Entity() const { return ToHScript( m_pEnt ); } + int HitBox() const { return hitbox; } - float Fraction() const { return m_tr.fraction; } + const Vector& StartPos() const { return startpos; } + const Vector& EndPos() const { return endpos; } - int Contents() const { return m_tr.contents; } - int DispFlags() const { return m_tr.dispFlags; } + float Fraction() const { return fraction; } - bool AllSolid() const { return m_tr.allsolid; } - bool StartSolid() const { return m_tr.startsolid; } + int Contents() const { return contents; } + int DispFlags() const { return dispFlags; } - HSCRIPT Surface() { return m_surfaceAccessor; } - void SetSurface( HSCRIPT hSurfAccessor ) { m_surfaceAccessor = hSurfAccessor; } + bool AllSolid() const { return allsolid; } + bool StartSolid() const { return startsolid; } - HSCRIPT Plane() { return m_planeAccessor; } - void SetPlane( HSCRIPT hPlaneAccessor ) { m_planeAccessor = hPlaneAccessor; } + HSCRIPT Surface() const { return m_surfaceAccessor; } + HSCRIPT Plane() const { return m_planeAccessor; } - trace_t &GetTrace() { return m_tr; } - void Destroy() { delete this; } + 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 | 154 +++++++++--------- 1 file changed, 77 insertions(+), 77 deletions(-) diff --git a/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp b/sp/src/game/shared/mapbase/vscript_funcs_shared.cpp index b0cbaf02c9..fc9fa33ec0 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( GetJumpFactor, "The surface's jump factor." ) - DEFINE_SCRIPTFUNC( GetMaterialChar, "The surface's material character." ) - - 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( GetFriction, "" ) + DEFINE_SCRIPTFUNC( GetThickness, "" ) + + DEFINE_SCRIPTFUNC( GetJumpFactor, "" ) + DEFINE_SCRIPTFUNC( GetMaterialChar, "" ) + + 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 b17001189c..059f37f03f 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 | 38 ++++++++++++++----- .../shared/mapbase/mapbase_usermessages.cpp | 31 --------------- 2 files changed, 28 insertions(+), 41 deletions(-) diff --git a/sp/src/game/shared/mapbase/logic_script_client.cpp b/sp/src/game/shared/mapbase/logic_script_client.cpp index 59f673dc1f..97edfe304a 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 @@ class CLogicScriptClient : public CBaseEntity BaseClass::OnRestore(); } -#else - void InputCallScriptFunctionClient( inputdata_t &inputdata ) + + void ReceiveMessage( int classID, bf_read &msg ) { - // TODO: Support for specific players? - CBroadcastRecipientFilter filter; - filter.MakeReliable(); + if ( classID != GetClientClass()->m_ClassID ) + { + BaseClass::ReceiveMessage( classID, msg ); + return; + } + + 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 (strlen( pszFunction ) > 64) + if ( V_strlen( pszFunction ) >= 64 ) { - Msg("%s CallScriptFunctionClient: \"%s\" is too long at %i characters, must be 64 or less\n", GetDebugName(), pszFunction, strlen(pszFunction)); + Msg( "%s CallScriptFunctionClient: \"%s\" is too long at %i characters, must be 64 or less\n", GetDebugName(), pszFunction, V_strlen(pszFunction)+1 ); return; } - UserMessageBegin( filter, "CallClientScriptFunction" ); - WRITE_STRING( pszFunction ); // function - WRITE_SHORT( entindex() ); // entity + 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 61cc457572..5af946e6e9 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 5afe5eea80..7ed6154590 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 e407af5ec9..69ca218725 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 b1973c51d5..3ae13cdee8 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 e49c1c1f09..2863b747fd 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 551fc52d00..4b4d50c91a 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 88078e3eee..9fda128a48 100644 --- a/sp/src/game/shared/basecombatweapon_shared.h +++ b/sp/src/game/shared/basecombatweapon_shared.h @@ -422,6 +422,8 @@ class CBaseCombatWeapon : public BASECOMBATWEAPON_DERIVED_FROM 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 @@ class CBaseCombatWeapon : public BASECOMBATWEAPON_DERIVED_FROM // 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 54b9429aee..d8844916e4 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 d3995ee1e5..280327447d 100644 --- a/sp/src/game/shared/weapon_parse.h +++ b/sp/src/game/shared/weapon_parse.h @@ -121,6 +121,10 @@ class FileWeaponInfo_t 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 d713a8c370..6c78a3b518 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 7c4a401330..aa8ddbae1d 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 8550b6dc00..fd4825de13 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 @@ class CMapbaseSystem : public CAutoGameSystem #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 08def106c5..68568a7283 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 c0bb5f1b0f..990b421441 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) { - 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; - } + // Look for a default list + actCount = pWeapon->ActivityListCount(); + pTable = CBaseCombatWeapon::GetDefaultBackupActivityList( pWeapon->ActivityList(), actCount ); + } - return (Activity)pTable->weaponAct; - } - } + if (pTable && GetModelPtr()) + { + int actCount = pWeapon->GetBackupActivityListCount(); + 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 069960f6a7..c5ad733d8b 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 63ebececbc..264fdb3d20 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 @@ class CAI_ActBusyBehavior : public CAI_SimpleBehavior 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 ac415c9e10..a3c053719e 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 4b4d50c91a..22fe8b977c 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 9fda128a48..bd439b8c3f 100644 --- a/sp/src/game/shared/basecombatweapon_shared.h +++ b/sp/src/game/shared/basecombatweapon_shared.h @@ -232,6 +232,7 @@ class CBaseCombatWeapon : public BASECOMBATWEAPON_DERIVED_FROM 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 990b421441..f4b3539204 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 ccdd16c815..bf07ee1510 100644 --- a/sp/src/game/server/basecombatcharacter.h +++ b/sp/src/game/server/basecombatcharacter.h @@ -428,7 +428,9 @@ class CBaseCombatCharacter : public CBaseFlex 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 fd31f79285..42f857de8a 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 ab45b27a1e..1f2f75e15b 100644 --- a/sp/src/game/server/baseentity.h +++ b/sp/src/game/server/baseentity.h @@ -693,6 +693,7 @@ class CBaseEntity : public IServerEntity #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 6c78a3b518..00aefbb813 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 05bf335b20..0bfba8fbfa 100644 --- a/sp/src/game/server/player.h +++ b/sp/src/game/server/player.h @@ -412,6 +412,8 @@ class CBasePlayer : public CBaseCombatCharacter 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 | 51 +++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 7 deletions(-) diff --git a/sp/src/game/shared/vscript_shared.cpp b/sp/src/game/shared/vscript_shared.cpp index 86e220b47d..088c19a710 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 GAME_DLL +#define IsCommandIssuedByServerAdmin() UTIL_IsCommandIssuedByServerAdmin() +#else +#define IsCommandIssuedByServerAdmin() true +#endif + #ifdef CLIENT_DLL -CON_COMMAND( script_client, "Run the text as a script" ) +CON_COMMAND_F( script_client, "Run the text as a script", FCVAR_CHEAT ) #else -CON_COMMAND( script, "Run the text as a script" ) +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 1db0693a8d..74a9343e8e 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 0bcdd8ae23..2ced70863e 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 | 423 ++++++++++++++++-------------- 1 file changed, 227 insertions(+), 196 deletions(-) diff --git a/sp/src/game/server/ai_basenpc.cpp b/sp/src/game/server/ai_basenpc.cpp index c5fa8c7bbc..f1f72307c6 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 ) +#ifdef MAPBASE + CUtlVector iszUsedNames; + for (KeyValues* pkvModelBlock = modelKeyValues; pkvModelBlock != nullptr; pkvModelBlock = pkvModelBlock->GetNextKey()) { - KeyValues *pkvNode = pkvInteractions->GetFirstSubKey(); - while ( pkvNode ) + // Do we have a dynamic interactions section? + KeyValues* pkvInteractions = pkvModelBlock->FindKey("dynamic_interactions"); + if (pkvInteractions) { - ScriptedNPCInteraction_t sInteraction; - sInteraction.iszInteractionName = AllocPooledString( pkvNode->GetName() ); + 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. + if (iszUsedNames.Find(sInteraction.iszInteractionName) != iszUsedNames.InvalidIndex()) + { + DevMsg(2, "Scripted interaction %s already defined on %s\n", pkvNode->GetName(), GetClassname()); + pkvNode = pkvNode->GetNextKey(); + continue; + } - bool bValidInteraction = true; + // The method for parsing dynamic interactions has been reworked. + // Unknown values are now stored as response contexts to test against response criteria. - // Default values - UTIL_StringToVector( sInteraction.vecRelativeOrigin.Base(), "0 0 0" ); - sInteraction.flDelay = 10.0; - sInteraction.flDistSqr = (DSS_MAX_DIST * DSS_MAX_DIST); + bool bValidInteraction = true; - // Misc. response criteria - char *szCriteria = ""; + // Default values + UTIL_StringToVector(sInteraction.vecRelativeOrigin.Base(), "0 0 0"); + sInteraction.flDelay = 10.0; + sInteraction.flDistSqr = (DSS_MAX_DIST * DSS_MAX_DIST); - KeyValues *pCurNode = pkvNode->GetFirstSubKey(); - const char *szName = NULL; - const char *szValue = NULL; - while (pCurNode) - { - szName = pCurNode->GetName(); - szValue = pCurNode->GetString(); + // Misc. response criteria + char* szCriteria = ""; - if (!szName || !szValue) + KeyValues* pCurNode = pkvNode->GetFirstSubKey(); + const char* szName = NULL; + const char* szValue = NULL; + while (pCurNode) { - DevWarning("ERROR: Invalid dynamic interaction string\n"); - pCurNode = pCurNode->GetNextKey(); - } + szName = pCurNode->GetName(); + szValue = pCurNode->GetString(); - if (!Q_strncmp(szName, "classname", 9)) - { - bool pass = false; - if (Q_strstr(szValue, "!=")) + if (!szName || !szValue) { - szValue += 2; - pass = true; + DevWarning("ERROR: Invalid dynamic interaction string\n"); + pCurNode = pCurNode->GetNextKey(); } - 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(szName, "classname", 9)) { - if ( !Q_strncmp( pszParam, "on_damage", 9) ) + bool pass = false; + if (Q_strstr(szValue, "!=")) { - sInteraction.iLoopBreakTriggerMethod |= SNPCINT_LOOPBREAK_ON_DAMAGE; + szValue += 2; + pass = true; } - else if ( !Q_strncmp( pszParam, "on_flashlight_illum", 19) ) + + 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) { - sInteraction.iLoopBreakTriggerMethod |= SNPCINT_LOOPBREAK_ON_FLASHLIGHT_ILLUM; - } + 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," "); + 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, "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, "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, "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, "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, "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, "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, "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 ) ) + 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); } - } - else if (!Q_strncmp(szName, "weapon_mine", 11)) - { - sInteraction.iFlags |= SCNPC_FLAG_NEEDS_WEAPON_ME; - sInteraction.iszMyWeapon = AllocPooledString( szValue ); + // Add anything else to our miscellaneous criteria + else + { + szCriteria = UTIL_VarArgs("%s,%s:%s", szCriteria, szName, szValue); + } + + pCurNode = pCurNode->GetNextKey(); } - else if (!Q_strncmp(szName, "weapon_theirs", 13)) + + if (!bValidInteraction) { - sInteraction.iFlags |= SCNPC_FLAG_NEEDS_WEAPON_THEM; - sInteraction.iszTheirWeapon = AllocPooledString( szValue ); + DevMsg("Scripted interaction %s rejected by %s\n", pkvNode->GetName(), GetClassname()); + pkvNode = pkvNode->GetNextKey(); + continue; } - // Add anything else to our miscellaneous criteria - else + if (szCriteria[0] == ',') { - szCriteria = UTIL_VarArgs("%s,%s:%s", szCriteria, szName, szValue); + szCriteria += 1; + sInteraction.MiscCriteria = AllocPooledString(szCriteria); } - pCurNode = pCurNode->GetNextKey(); - } - if (!bValidInteraction) - { - DevMsg("Scripted interaction %s rejected by %s\n", pkvNode->GetName(), GetClassname()); - pkvNode = pkvNode->GetNextKey(); - continue; - } + // Add it to the list + AddScriptedNPCInteraction(&sInteraction); + iszUsedNames.AddToTail(sInteraction.iszInteractionName); - if (szCriteria[0] == ',') - { - szCriteria += 1; - sInteraction.MiscCriteria = AllocPooledString(szCriteria); + // Move to next interaction + pkvNode = pkvNode->GetNextKey(); } + } + } #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 9dc2a5fe11..2d016f489d 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 f8fc21bdbb..d9855815df 100644 --- a/sp/src/game/server/hl2/npc_enemyfinder.cpp +++ b/sp/src/game/server/hl2/npc_enemyfinder.cpp @@ -59,6 +59,10 @@ class CNPC_EnemyFinder : public CAI_BaseNPC 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 f60350485b..e9b071ffcb 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 3314330bd3..cd0c77eb61 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 @@ class CHudCommentary : public CHudElement, public vgui::Panel 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 @@ class CHudCommentary : public CHudElement, public vgui::Panel #ifdef MAPBASE virtual void PerformLayout(); void ResolveBounds( int width, int height ); + + virtual void LevelShutdown(); #endif private: @@ -110,8 +115,13 @@ class CHudCommentary : public CHudElement, public vgui::Panel 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 @@ class C_PointCommentaryNode : public C_BaseAnimating, public IChoreoEventCallbac 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 @@ class C_PointCommentaryNode : public C_BaseAnimating, public IChoreoEventCallbac 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 ) { - 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" ); + { + 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; } #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); + + contentWidth = lW, contentHeight = lT; + + lW += (xOffset * 2); + lT += (yOffset * 2); - ResolveBounds( lW, lT ); + 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); + + contentWidth = iW, contentHeight = iT; - ResolveBounds( iW, 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,13 +1550,16 @@ void CHudCommentary::StartImageCommentary( C_PointCommentaryNode *pNode, const c m_hFont = vgui::scheme()->GetIScheme(scheme)->GetFont( "Default" ); } - m_bShouldPaint = true; - - if (commentary_combine_speaker_and_printname.GetBool() && pNode && pNode->m_iszPrintName[0] != '\0') + m_hSmallFont = vgui::scheme()->GetIScheme(scheme)->GetFont( "CommentarySmall" ); + if ( !m_hSmallFont) { - CombineSpeakerAndPrintName( pNode->m_iszPrintName ); + m_hSmallFont = m_hFont; } + m_bShouldPaint = true; + + FixupCommentaryLabels( pNode->m_iszPrintName, pNode->m_iszSpeakers, pNode->m_iszFootnote ); + SetPaintBackgroundEnabled( m_bShouldPaint ); char sz[MAX_COUNT_STRING]; @@ -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 3b4ef12ba5..7ff8b33e3c 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 @@ class CPointCommentaryNode : public CBaseAnimating 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 @@ class CPointCommentaryNode : public CBaseAnimating 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 @@ class CCommentarySystem : public CAutoGameSystemPerFrame #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 87a8ec6e7e..43eb86a34f 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 f4b3539204..5ea5c65d21 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 42f857de8a..5e47d89e09 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 50d109825b..73bac24282 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 229db7b048..5f6151c4a7 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 10777f89ad..f2939fccc1 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 00aefbb813..6092dcd8cc 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 aa8ddbae1d..5f9c0f10c6 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 840432b1c8..046c8111b7 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 499785ff1c..a410cb9508 100644 --- a/sp/src/public/vgui_controls/TextImage.h +++ b/sp/src/public/vgui_controls/TextImage.h @@ -105,6 +105,11 @@ class TextImage : public Image 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 6153212628..b6b9ff29cf 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 cd3854ddc4..af49c966d4 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 7e533ceb74..2f127c30e7 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 ac904b81b9..0699d89061 100644 --- a/sp/src/game/server/episodic/npc_hunter.cpp +++ b/sp/src/game/server/episodic/npc_hunter.cpp @@ -1447,6 +1447,10 @@ class CNPC_Hunter : public CAI_BaseActor 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 8d73911f6b..d29b6b39f8 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 70e73354ee..c61f6f0325 100644 --- a/sp/src/game/server/ai_speech_new.h +++ b/sp/src/game/server/ai_speech_new.h @@ -249,7 +249,11 @@ class CAI_Expresser : public ResponseRules::IResponseFilter 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 d23168577d..5362249dcf 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 b8aea0bf06..e8191ed0fd 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 2373f2f93e..4cf3ca2265 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 74b2cbc919..beb1d869c9 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 5f10814e77..85cdb6e122 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 d294316d19..653c5cbf7d 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 098801c452..873f875928 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 2477ec6744..10fb51ffe1 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 e78ed5d80e..695faa2b88 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,10 +349,18 @@ float4 main( PS_INPUT i ) : COLOR specularFactor *= envmapMaskTexel.xyz; } - if( bBaseAlphaEnvmapMask ) + if ( bBaseAlphaEnvmapMask ) + { + specularFactor *= saturate( g_flBaseAlphaEnvMapMaskScale * pow( baseColor.a, g_flBaseAlphaEnvMapMaskExp ) + g_flBaseAlphaEnvMapMaskBias ); + } + + #if ( ENVMAPFRESNEL ) { - specularFactor *= 1.0 - baseColor.a; // this blows! + 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 9ed758b6fb..56685c1112 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 0bf098cdb4..8383989c4e 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 ee74372c5a..1106743ff7 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 c5a1861197..27796cd6e2 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 0bf098cdb4..8383989c4e 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 ee74372c5a..1106743ff7 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 c5a1861197..27796cd6e2 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 f0c3011660..2385467859 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 73918971f5..378c39be00 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 21202a4ec6..14890a22fc 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 94a16ebcb4..5df1ab93ba 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 2557bec360..7e8400d22c 100644 --- a/sp/src/game/server/BasePropDoor.h +++ b/sp/src/game/server/BasePropDoor.h @@ -77,6 +77,8 @@ abstract_class CBasePropDoor : public CDynamicProp #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 56428e73ca..4aed7c5742 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 4aed7c5742..c643dd6825 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 c6e492398c..0d9c0240e7 100644 --- a/sp/src/game/server/hl2/weapon_ar1.cpp +++ b/sp/src/game/server/hl2/weapon_ar1.cpp @@ -98,7 +98,7 @@ class CWeaponAR1 : public CHLMachineGun } } -#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 5d13c5e6c3..fee51dd763 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 1c86747248..7bd1c73716 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 924b32fe50..0024285296 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 6520e6b4f8..fb4354f549 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 @@ class CHudCredits : public CHudElement, public vgui::Panel 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 @@ class CHudCredits : public CHudElement, public vgui::Panel 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 6de8178308..7725b67dbe 100644 --- a/sp/src/game/server/EnvMessage.cpp +++ b/sp/src/game/server/EnvMessage.cpp @@ -154,6 +154,9 @@ class CCredits : public CPointEntity 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,7 +201,34 @@ 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 ) { 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 fd4825de13..47e83adaaf 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 @@ class CMapbaseSystem : public CAutoGameSystem 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 @@ class CMapbaseSystem : public CAutoGameSystem 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 @@ class CMapbaseSystem : public CAutoGameSystem 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 @@ class CMapbaseSystem : public CAutoGameSystem //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 @@ class CMapbaseSystem : public CAutoGameSystem { 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 6092dcd8cc..c53cb6ad0a 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 42822d2ff3..be80179a5a 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 d44849e7f0..3fa00df0a0 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 8a0f306bfa..b55fa441cf 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 f1f72307c6..6f8b7bcdb2 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 3fa00df0a0..6720ff10b7 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 248c0841f2..ddf3da7058 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 9b519902f3..b639f270eb 100644 --- a/sp/src/game/shared/ai_responsesystem_new.cpp +++ b/sp/src/game/shared/ai_responsesystem_new.cpp @@ -188,6 +188,12 @@ inline const char *RR_Parse_Preserve(const char *data, char *token ) 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 dd886ab315..55d5614bd1 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 | 84 ++++------ sp/src/vscript/vscript_squirrel.nut | 148 +++++++++++------- 8 files changed, 186 insertions(+), 160 deletions(-) diff --git a/sp/src/game/client/c_baseentity.cpp b/sp/src/game/client/c_baseentity.cpp index b7ded40fca..43471e9dbc 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 147dfc3919..67c3b17e5a 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 84021a952c..da5dd61ffd 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 @@ class CFilterScript : public CBaseFilter 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 @@ class CFilterScript : public CBaseFilter 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 @@ class CFilterScript : public CBaseFilter 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 @@ class CFilterScript : public CBaseFilter 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 af49c966d4..3393afa89f 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 d9155f3219..4d5c744d33 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 001e1c24dd..fc16a14383 100644 --- a/sp/src/public/vscript/ivscript.h +++ b/sp/src/public/vscript/ivscript.h @@ -885,9 +885,8 @@ class IScriptVM //-------------------------------------------------------- // 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 15d8c1ffef..932ab26f55 100644 --- a/sp/src/vscript/vscript_squirrel.cpp +++ b/sp/src/vscript/vscript_squirrel.cpp @@ -188,9 +188,8 @@ class SquirrelVM : public IScriptVM //-------------------------------------------------------- // 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,54 +2347,37 @@ 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) { - // 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))) + // For now, assume null scope (which is used for global hooks) is always hooked + if ( hScope ) { - sq_pop(vm_, 3); - return false; - } + Assert( hScope != INVALID_HSCRIPT ); - sq_pop(vm_, 4); - return val ? true : false; -} + 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); -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; - } + SQBool val; + if (SQ_FAILED(sq_getbool(vm_, -1, &val))) + { + sq_pop(vm_, 3); + return nullptr; + } - if (!ScopeIsHooked(hScope, pszEventName)) - return nullptr; + sq_pop(vm_, 4); - SquirrelSafeCheck safeCheck(vm_); + if (!val) + return nullptr; + } sq_pushroottable(vm_); sq_pushstring(vm_, "Hooks", -1); @@ -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 bafd55b7df..1c1bd4e7f7 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] + if ( !ctx.len() ) + { + if ( !rem ) + rem = []; + rem.append( ev ); + rem.append( scope ); + } } + } + } - // cleanup? - if ( !scope.len() ) - delete s_List[k] + 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( scope, event, ... ) + function Call( event, scope, ... ) { - local firstReturn + local firstReturn; - // global hook; call all scopes - if ( !scope ) + if ( event in s_List ) { - vargv.insert( 0, null ) - foreach( sc,t in s_List ) + vargv.insert( 0, scope ); + + local t = s_List[event]; + if ( scope in t ) { - if ( event in t ) + foreach ( fn in t[scope] ) { - vargv[0] = sc - foreach( context, callback in t[event] ) - { - //printf( "(%.4f) Calling hook '%s' of context '%s' in static iteration\n", Time(), event, context ) + //printf( "(%.4f) Calling hook %s:%s\n", Time(), event, context ); - local curReturn = callback.acall(vargv) - if (firstReturn == null) - firstReturn = curReturn - } + local r = fn.acall( vargv ); + if ( firstReturn == null ) + firstReturn = r; } } - } - else if ( scope in s_List ) - { - local t = s_List[scope] - if ( event in t ) + else if ( !scope ) // global hook { - vargv.insert( 0, scope ) - foreach( context, callback in t[event] ) + foreach ( sc, ctx in t ) { - //printf( "(%.4f) Calling hook '%s' of context '%s'\n", Time(), event, context ) + vargv[0] = sc; - local curReturn = callback.acall(vargv) - if (firstReturn == null) - firstReturn = curReturn + 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 1b2891ab1d..1a5c59be2c 100644 --- a/sp/src/game/client/vscript_client.cpp +++ b/sp/src/game/client/vscript_client.cpp @@ -114,7 +114,7 @@ class CScriptClientEntityIterator : public IClientEntityListener 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 @@ class CScriptClientEntityIterator : public IClientEntityListener 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 @@ class CVScriptGameSystem : public CAutoGameSystemPerFrame { #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 559c57e3d0..25c8281abf 100644 --- a/sp/src/game/server/vscript_server.cpp +++ b/sp/src/game/server/vscript_server.cpp @@ -154,7 +154,7 @@ class CScriptEntityIterator : public IEntityListener 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 @@ class CScriptEntityIterator : public IEntityListener 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 @@ class CScriptEntityIterator : public IEntityListener 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 @@ class CVScriptGameSystem : public CAutoGameSystemPerFrame { #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 64212d44aa..8f821e6c66 100644 --- a/sp/src/game/shared/mapbase/vscript_singletons.cpp +++ b/sp/src/game/shared/mapbase/vscript_singletons.cpp @@ -872,7 +872,8 @@ class CScriptSaveRestoreUtil : public CAutoGameSystem { 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 @@ class CScriptSaveRestoreUtil : public CAutoGameSystem { 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 088c19a710..4f20b7c625 100644 --- a/sp/src/game/shared/vscript_shared.cpp +++ b/sp/src/game/shared/vscript_shared.cpp @@ -451,6 +451,10 @@ class CVScriptSaveRestoreBlockHandler : public CDefSaveRestoreBlockHandler } 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 fc16a14383..0d105d5531 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 @@ class IScriptVM //-------------------------------------------------------- // 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,21 +1922,18 @@ struct ScriptHook_t // 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 ) + // For now, assume null scope (which is used for global hooks) is always hooked + if ( !hScope || GetScriptHookManager().IsEventHookedInScope( m_desc.m_pszScriptName, hScope ) ) { - // 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; + m_hFunc = NULL; + return true; } + extern IScriptVM *g_pScriptVM; + + // 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 932ab26f55..3b1e87ab13 100644 --- a/sp/src/vscript/vscript_squirrel.cpp +++ b/sp/src/vscript/vscript_squirrel.cpp @@ -188,8 +188,8 @@ class SquirrelVM : public IScriptVM //-------------------------------------------------------- // 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_); - - // 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); + Assert( val ); + Assert( val != INVALID_HSCRIPT ); - 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 1c1bd4e7f7..5b76bbe3a7 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 7bd1c73716..7afc4d2255 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 0f2f57df23..24e33a3be1 100644 --- a/sp/src/game/client/c_baseanimating.h +++ b/sp/src/game/client/c_baseanimating.h @@ -491,7 +491,7 @@ class C_BaseAnimating : public C_BaseEntity, private IModelLoadCallback 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 0024285296..efa04881a6 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 da5dd61ffd..704cf05492 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 6f8b7bcdb2..c503a09c1c 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 cd0c77eb61..7ff47f2459 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 @@ class C_PointCommentaryNode : public C_BaseAnimating, public IChoreoEventCallbac #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 c643dd6825..78675b7ab4 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 645ca8e603..1ffc032609 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 0a2d75d79a..ad48da19ae 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 47e83adaaf..43790ca53f 100644 --- a/sp/src/game/shared/mapbase/mapbase_shared.cpp +++ b/sp/src/game/shared/mapbase/mapbase_shared.cpp @@ -473,7 +473,7 @@ class CMapbaseSystem : public CAutoGameSystem 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 7ade776277..720e890608 100644 --- a/sp/src/game/server/globalstate.cpp +++ b/sp/src/game/server/globalstate.cpp @@ -131,6 +131,9 @@ class CGlobalState : public CAutoGameSystem 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 ddf3da7058..df0a5aaa4b 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 1a5c59be2c..faf35c16d3 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 25c8281abf..40e35f00a7 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 4f20b7c625..ec41c5663b 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 8bf23d54d1..508342208d 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 7ff47f2459..d8d9ad4c54 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 @@ class CHudCommentary : public CHudElement, public vgui::Panel // 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 704cf05492..c15f8eee29 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 efa04881a6..d5ca32ee97 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: