1414#include " ai_scriptconditions.h"
1515#include " saverestore_utlvector.h"
1616
17+ #ifdef MAPBASE_MP
18+ #include " filters.h"
19+ #endif
20+
1721// memdbgon must be the last include file in a .cpp file!!!
1822#include " tier0/memdbgon.h"
1923
2024#define SF_ACTOR_AS_ACTIVATOR ( 1 << 0 )
25+ #ifdef MAPBASE
26+ #define SF_PLAYER_AS_ACTIVATOR ( 1 << 1 ) // Mainly useful in MP
27+ #endif
2128
2229ConVar debugscriptconditions ( " ai_debugscriptconditions" , " 0" );
2330
@@ -55,6 +62,9 @@ BEGIN_DATADESC( CAI_ScriptConditions )
5562#ifdef MAPBASE
5663 DEFINE_INPUTFUNC ( FIELD_EHANDLE , " SatisfyConditions" , InputSatisfyConditions ),
5764#endif
65+ #ifdef MAPBASE_MP
66+ DEFINE_INPUTFUNC ( FIELD_STRING , " SetPlayerFilter" , InputSetPlayerFilter ),
67+ #endif
5868
5969 // ---------------------------------
6070
@@ -111,6 +121,11 @@ BEGIN_DATADESC( CAI_ScriptConditions )
111121 DEFINE_UTLVECTOR( m_ElementList, FIELD_EMBEDDED ),
112122 DEFINE_FIELD( m_bLeaveAsleep, FIELD_BOOLEAN ),
113123
124+ #ifdef MAPBASE_MP
125+ DEFINE_KEYFIELD ( m_iszPlayerFilterName, FIELD_STRING , " PlayerFilter" ),
126+ DEFINE_FIELD( m_hPlayerFilter, FIELD_EHANDLE ),
127+ #endif
128+
114129END_DATADESC ()
115130
116131BEGIN_SIMPLE_DATADESC ( CAI_ProxTester )
@@ -129,6 +144,42 @@ END_DATADESC()
129144
130145#define EVALUATOR ( name ) { &CAI_ScriptConditions::Eval##name, #name }
131146
147+ #ifdef MAPBASE_MP
148+
149+ CAI_ScriptConditions::EvaluatorInfo_t CAI_ScriptConditions::gm_PlayerEvaluators[] =
150+ {
151+ EVALUATOR ( ActorSeePlayer ),
152+ EVALUATOR ( PlayerActorProximity ),
153+ EVALUATOR ( PlayerTargetProximity ),
154+ EVALUATOR ( PlayerBlockingActor ),
155+ EVALUATOR ( PlayerActorLook ),
156+ EVALUATOR ( PlayerTargetLook ),
157+ EVALUATOR ( PlayerActorLOS ),
158+ EVALUATOR ( PlayerTargetLOS ),
159+
160+ #ifdef HL2_EPISODIC
161+ EVALUATOR ( PlayerInVehicle ),
162+ #endif
163+
164+ };
165+
166+ // !!! In MP, this is only used for evaluators that don't use players.
167+ // Use gm_PlayerEvaluators for evaluators that require a player.
168+ CAI_ScriptConditions::EvaluatorInfo_t CAI_ScriptConditions::gm_Evaluators[] =
169+ {
170+ EVALUATOR ( State ),
171+ EVALUATOR ( ActorTargetProximity ),
172+ EVALUATOR ( ActorSeeTarget),
173+
174+ #ifdef HL2_EPISODIC
175+ EVALUATOR ( ActorInPVS ),
176+ EVALUATOR ( ActorInVehicle ),
177+ #endif
178+
179+ };
180+
181+ #else
182+
132183CAI_ScriptConditions::EvaluatorInfo_t CAI_ScriptConditions::gm_Evaluators[] =
133184{
134185 EVALUATOR ( ActorSeePlayer ),
@@ -151,6 +202,8 @@ CAI_ScriptConditions::EvaluatorInfo_t CAI_ScriptConditions::gm_Evaluators[] =
151202
152203};
153204
205+ #endif
206+
154207void CAI_ScriptConditions::OnRestore ( void )
155208{
156209 BaseClass::OnRestore ();
@@ -537,7 +590,7 @@ void CAI_ScriptConditions::EvaluationThink()
537590 m_OnConditionsTimeout.FireOutput ( pActivator, this );
538591 continue ;
539592 }
540-
593+
541594 bool result = true ;
542595 const int nEvaluators = sizeof ( gm_Evaluators ) / sizeof ( gm_Evaluators[0 ] );
543596
@@ -561,6 +614,47 @@ void CAI_ScriptConditions::EvaluationThink()
561614 }
562615 }
563616
617+ #ifdef MAPBASE_MP
618+ if ( result )
619+ {
620+ // Loop through all of the players until one of them passes. If we've been given a filter, use it to determine which players to evaluate.
621+ //
622+ // You may notice this ignores GetPlayer() and is implemented more primitively than how ai_script_conditions handles multiple actors.
623+ // ai_script_conditions was designed to evaluate conditions on multiple actors simultaneously, but it was only designed with one player in mind.
624+ // Having the existing element list account for multiple players is theoretically possible, but each element is designed to time out and fire outputs separately.
625+ // Since existing instances of the entity were not designed for that functionality and it would make the entity much more complex to manage even under new cases,
626+ // I've elected to go for a simpler implementation that just loops through all of the players every time an actor's condition needs to be evaluated.
627+ const int nPlayerEvaluators = sizeof ( gm_PlayerEvaluators ) / sizeof ( gm_PlayerEvaluators[0 ] );
628+ for ( int playerIdx = 1 ; playerIdx <= gpGlobals->maxClients ; playerIdx++ )
629+ {
630+ CBasePlayer *pPlayer = UTIL_PlayerByIndex ( playerIdx );
631+ if ( !pPlayer || ( m_hPlayerFilter && !m_hPlayerFilter->PassesFilter ( this , pPlayer ) ) )
632+ continue ;
633+
634+ result = true ;
635+ args.pPlayer = pPlayer;
636+
637+ ScrCondDbgMsg ( (" %s evaluating player: %s [%i]\n " , GetDebugName (), pPlayer->GetPlayerName (), playerIdx) );
638+
639+ for ( int i = 0 ; i < nPlayerEvaluators; ++i )
640+ {
641+ if ( !(this ->*gm_PlayerEvaluators[i].pfnEvaluator )( args ) )
642+ {
643+ pConditionElement->GetTimer ()->Reset ();
644+ result = false ;
645+
646+ ScrCondDbgMsg ( ( " \t %s failed on: %s\n " , GetDebugName (), gm_PlayerEvaluators[ i ].pszName ) );
647+
648+ break ;
649+ }
650+ }
651+
652+ if ( result )
653+ break ;
654+ }
655+ }
656+ #endif
657+
564658 if ( result )
565659 {
566660 ScrCondDbgMsg ( ( " %s waiting... %f\n " , GetDebugName (), pConditionElement->GetTimer ()->GetRemaining () ) );
@@ -656,6 +750,13 @@ void CAI_ScriptConditions::Enable( void )
656750 }
657751 }
658752
753+ #ifdef MAPBASE_MP
754+ if ( m_iszPlayerFilterName != NULL_STRING )
755+ {
756+ m_hPlayerFilter = dynamic_cast <CBaseFilter *>(gEntList .FindEntityByName ( NULL , m_iszPlayerFilterName, this ));
757+ }
758+ #endif
759+
659760 m_fDisabled = false ;
660761
661762 SetThink ( &CAI_ScriptConditions::EvaluationThink );
@@ -706,6 +807,23 @@ void CAI_ScriptConditions::InputSatisfyConditions( inputdata_t &inputdata )
706807}
707808#endif
708809
810+ #ifdef MAPBASE_MP
811+ // -----------------------------------------------------------------------------
812+
813+ void CAI_ScriptConditions::InputSetPlayerFilter ( inputdata_t &inputdata )
814+ {
815+ m_iszPlayerFilterName = inputdata.value .StringID ();
816+ if ( m_iszPlayerFilterName != NULL_STRING )
817+ {
818+ m_hPlayerFilter = dynamic_cast <CBaseFilter *>(gEntList .FindEntityByName ( NULL , m_iszPlayerFilterName, this ));
819+ }
820+ else
821+ {
822+ m_hPlayerFilter = NULL ;
823+ }
824+ }
825+ #endif
826+
709827// -----------------------------------------------------------------------------
710828
711829bool CAI_ScriptConditions::IsInFOV ( CBaseEntity *pViewer, CBaseEntity *pViewed, float fov, bool bTrueCone )
0 commit comments