mirror of
https://github.com/mapbase-source/source-sdk-2013.git
synced 2024-12-25 14:25:32 +03:00
Add new dynamic interaction keyvalues and utilities
This commit is contained in:
parent
e34e0d3b10
commit
fd149ff161
@ -76,6 +76,23 @@ int CAI_BaseNPC::GetActivityID(const char* actName)
|
||||
return m_pActivitySR->GetStringID(actName);
|
||||
}
|
||||
|
||||
#ifdef MAPBASE
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Gets an activity ID or registers a new private one if it doesn't exist
|
||||
//-----------------------------------------------------------------------------
|
||||
int CAI_BaseNPC::GetOrRegisterActivity( const char *actName )
|
||||
{
|
||||
int actID = GetActivityID( actName );
|
||||
if (actID == ACT_INVALID)
|
||||
{
|
||||
actID = ActivityList_RegisterPrivateActivity( actName );
|
||||
AddActivityToSR( actName, actID );
|
||||
}
|
||||
|
||||
return actID;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define ADD_ACTIVITY_TO_SR(activityname) AddActivityToSR(#activityname,activityname)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -12443,7 +12443,11 @@ BEGIN_SIMPLE_DATADESC( ScriptedNPCInteraction_t )
|
||||
DEFINE_FIELD( bValidOnCurrentEnemy, FIELD_BOOLEAN ),
|
||||
DEFINE_FIELD( flNextAttemptTime, FIELD_TIME ),
|
||||
#ifdef MAPBASE
|
||||
DEFINE_FIELD( MiscCriteria, FIELD_STRING ),//DEFINE_UTLVECTOR( MiscCriteria, FIELD_EMBEDDED ),
|
||||
DEFINE_EMBEDDED_ARRAY( sTheirPhases, SNPCINT_NUM_PHASES ),
|
||||
DEFINE_FIELD( bHasSeparateSequenceNames, FIELD_BOOLEAN ),
|
||||
DEFINE_FIELD( flMaxAngleDiff, FIELD_FLOAT ),
|
||||
DEFINE_FIELD( iszRelatedInteractions, FIELD_STRING ),
|
||||
DEFINE_FIELD( MiscCriteria, FIELD_STRING ),
|
||||
#endif
|
||||
END_DATADESC()
|
||||
|
||||
@ -14847,32 +14851,60 @@ void CAI_BaseNPC::ParseScriptedNPCInteractions(void)
|
||||
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);
|
||||
sInteraction.sPhases[SNPCINT_ENTRY].iActivity = GetOrRegisterActivity(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);
|
||||
sInteraction.sPhases[SNPCINT_SEQUENCE].iActivity = GetOrRegisterActivity(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);
|
||||
sInteraction.sPhases[SNPCINT_EXIT].iActivity = GetOrRegisterActivity(szValue);
|
||||
|
||||
else if (!Q_strncmp(szName, "their_", 6))
|
||||
{
|
||||
szName += 6;
|
||||
sInteraction.bHasSeparateSequenceNames = true;
|
||||
|
||||
if (!Q_strncmp(szName, "entry_sequence", 14))
|
||||
sInteraction.sTheirPhases[SNPCINT_ENTRY].iszSequence = AllocPooledString(szValue);
|
||||
else if (!Q_strncmp(szName, "entry_activity", 14))
|
||||
sInteraction.sTheirPhases[SNPCINT_ENTRY].iActivity = GetOrRegisterActivity(szValue);
|
||||
|
||||
else if (!Q_strncmp(szName, "sequence", 8))
|
||||
sInteraction.sTheirPhases[SNPCINT_SEQUENCE].iszSequence = AllocPooledString(szValue);
|
||||
else if (!Q_strncmp(szName, "activity", 8))
|
||||
sInteraction.sTheirPhases[SNPCINT_SEQUENCE].iActivity = GetOrRegisterActivity(szValue);
|
||||
|
||||
else if (!Q_strncmp(szName, "exit_sequence", 13))
|
||||
sInteraction.sTheirPhases[SNPCINT_EXIT].iszSequence = AllocPooledString(szValue);
|
||||
else if (!Q_strncmp(szName, "exit_activity", 13))
|
||||
sInteraction.sTheirPhases[SNPCINT_EXIT].iActivity = GetOrRegisterActivity(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, "angles_max_diff", 15))
|
||||
sInteraction.flMaxAngleDiff = atof(szValue);
|
||||
|
||||
else if (!Q_strncmp(szName, "loop_in_action", 14) && !FStrEq(szValue, "0"))
|
||||
sInteraction.iFlags |= SCNPC_FLAG_LOOP_IN_ACTION;
|
||||
|
||||
else if (!Q_strncmp(szName, "dont_teleport_at_end", 20))
|
||||
{
|
||||
if (!Q_stricmp(szValue, "me") || !Q_stricmp(szValue, "both"))
|
||||
if (!Q_stricmp(szValue, "me"))
|
||||
sInteraction.iFlags |= SCNPC_FLAG_DONT_TELEPORT_AT_END_ME;
|
||||
else if (!Q_stricmp(szValue, "them") || !Q_stricmp(szValue, "both"))
|
||||
else if (!Q_stricmp(szValue, "them"))
|
||||
sInteraction.iFlags |= SCNPC_FLAG_DONT_TELEPORT_AT_END_THEM;
|
||||
else if (!Q_stricmp( szValue, "both" ))
|
||||
{
|
||||
sInteraction.iFlags |= SCNPC_FLAG_DONT_TELEPORT_AT_END_ME;
|
||||
sInteraction.iFlags |= SCNPC_FLAG_DONT_TELEPORT_AT_END_THEM;
|
||||
}
|
||||
}
|
||||
|
||||
else if (!Q_strncmp(szName, "needs_weapon", 12))
|
||||
@ -14899,6 +14931,11 @@ void CAI_BaseNPC::ParseScriptedNPCInteractions(void)
|
||||
sInteraction.iszTheirWeapon = AllocPooledString(szValue);
|
||||
}
|
||||
|
||||
else if (!Q_strncmp(szName, "related_interactions", 20))
|
||||
{
|
||||
sInteraction.iszRelatedInteractions = AllocPooledString(szValue);
|
||||
}
|
||||
|
||||
// Add anything else to our miscellaneous criteria
|
||||
else
|
||||
{
|
||||
@ -15130,8 +15167,23 @@ void CAI_BaseNPC::AddScriptedNPCInteraction( ScriptedNPCInteraction_t *pInteract
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
const char *CAI_BaseNPC::GetScriptedNPCInteractionSequence( ScriptedNPCInteraction_t *pInteraction, int iPhase )
|
||||
const char *CAI_BaseNPC::GetScriptedNPCInteractionSequence( ScriptedNPCInteraction_t *pInteraction, int iPhase, bool bOtherNPC )
|
||||
{
|
||||
#ifdef MAPBASE
|
||||
if (bOtherNPC && pInteraction->bHasSeparateSequenceNames)
|
||||
{
|
||||
// Check unique phases
|
||||
if ( pInteraction->sTheirPhases[iPhase].iActivity != ACT_INVALID )
|
||||
{
|
||||
int iSequence = SelectWeightedSequence( (Activity)pInteraction->sTheirPhases[iPhase].iActivity );
|
||||
return GetSequenceName( iSequence );
|
||||
}
|
||||
|
||||
if ( pInteraction->sTheirPhases[iPhase].iszSequence != NULL_STRING )
|
||||
return STRING(pInteraction->sTheirPhases[iPhase].iszSequence);
|
||||
}
|
||||
#endif
|
||||
|
||||
if ( pInteraction->sPhases[iPhase].iActivity != ACT_INVALID )
|
||||
{
|
||||
int iSequence = SelectWeightedSequence( (Activity)pInteraction->sPhases[iPhase].iActivity );
|
||||
@ -15225,6 +15277,36 @@ void CAI_BaseNPC::StartScriptedNPCInteraction( CAI_BaseNPC *pOtherNPC, ScriptedN
|
||||
|
||||
// Setup next attempt
|
||||
pInteraction->flNextAttemptTime = gpGlobals->curtime + pInteraction->flDelay + RandomFloat(-2,2);
|
||||
#ifdef MAPBASE
|
||||
if (pInteraction->iszRelatedInteractions != NULL_STRING)
|
||||
{
|
||||
// Delay related interactions as well
|
||||
char szRelatedInteractions[256];
|
||||
Q_strncpy( szRelatedInteractions, STRING( pInteraction->iszRelatedInteractions ), sizeof( szRelatedInteractions ) );
|
||||
|
||||
char *pszInteraction = strtok( szRelatedInteractions, "," );
|
||||
while (pszInteraction)
|
||||
{
|
||||
bool bWildCard = Matcher_ContainsWildcard( pszInteraction );
|
||||
|
||||
for ( int i = 0; i < m_ScriptedInteractions.Count(); i++ )
|
||||
{
|
||||
ScriptedNPCInteraction_t *pOtherInteraction = &m_ScriptedInteractions[i];
|
||||
|
||||
if ( Matcher_NamesMatch( pszInteraction, STRING( pOtherInteraction->iszInteractionName ) ) && pOtherInteraction != pInteraction )
|
||||
{
|
||||
pOtherInteraction->flNextAttemptTime = pInteraction->flNextAttemptTime;
|
||||
|
||||
// Not looking for multiple
|
||||
if (!bWildCard)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pszInteraction = strtok( NULL, "," );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Spawn a scripted sequence for this NPC to play the interaction anim
|
||||
CAI_ScriptedSequence *pMySequence = (CAI_ScriptedSequence*)CreateEntityByName( "scripted_sequence" );
|
||||
@ -15256,6 +15338,15 @@ void CAI_BaseNPC::StartScriptedNPCInteraction( CAI_BaseNPC *pOtherNPC, ScriptedN
|
||||
CAI_ScriptedSequence *pTheirSequence = NULL;
|
||||
if ( pOtherNPC )
|
||||
{
|
||||
#ifdef MAPBASE
|
||||
if (pInteraction->bHasSeparateSequenceNames)
|
||||
{
|
||||
pszEntrySequence = GetScriptedNPCInteractionSequence( pInteraction, SNPCINT_ENTRY, true );
|
||||
pszSequence = GetScriptedNPCInteractionSequence( pInteraction, SNPCINT_SEQUENCE, true );
|
||||
pszExitSequence = GetScriptedNPCInteractionSequence( pInteraction, SNPCINT_EXIT, true );
|
||||
}
|
||||
#endif
|
||||
|
||||
pTheirSequence = (CAI_ScriptedSequence*)CreateEntityByName( "scripted_sequence" );
|
||||
pTheirSequence->KeyValue( "m_iszEntry", pszEntrySequence );
|
||||
pTheirSequence->KeyValue( "m_iszPlay", pszSequence );
|
||||
@ -15367,7 +15458,7 @@ bool CAI_BaseNPC::CanRunAScriptedNPCInteraction( bool bForced )
|
||||
return false;
|
||||
|
||||
// Default AI prevents interactions while melee attacking, but not ranged attacking
|
||||
if ( IsCurSchedule( SCHED_MELEE_ATTACK1 ) || IsCurSchedule( SCHED_MELEE_ATTACK2 ) )
|
||||
if ( ( IsCurSchedule( SCHED_MELEE_ATTACK1 ) || IsCurSchedule( SCHED_MELEE_ATTACK2 ) ) && !CanStartDynamicInteractionDuringMelee() )
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -15556,8 +15647,14 @@ void CAI_BaseNPC::CalculateValidEnemyInteractions( void )
|
||||
|
||||
if (bSame)
|
||||
continue;
|
||||
#endif
|
||||
|
||||
// Resolve the activity or sequence, and make sure our enemy has it
|
||||
const char *pszSequence = GetScriptedNPCInteractionSequence( pInteraction, SNPCINT_SEQUENCE, true );
|
||||
if ( !pszSequence )
|
||||
continue;
|
||||
if ( pNPC->LookupSequence( pszSequence ) == -1 )
|
||||
continue;
|
||||
#else
|
||||
// Use sequence? or activity?
|
||||
if ( pInteraction->sPhases[SNPCINT_SEQUENCE].iActivity != ACT_INVALID )
|
||||
{
|
||||
@ -15573,53 +15670,6 @@ void CAI_BaseNPC::CalculateValidEnemyInteractions( void )
|
||||
if ( pNPC->LookupSequence( STRING(pInteraction->sPhases[SNPCINT_SEQUENCE].iszSequence) ) == -1 )
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifdef MAPBASE
|
||||
if (pInteraction->MiscCriteria != NULL_STRING)
|
||||
{
|
||||
// Test against response system criteria
|
||||
AI_CriteriaSet set;
|
||||
ModifyOrAppendCriteria( set );
|
||||
CBasePlayer *pPlayer = UTIL_GetLocalPlayer();
|
||||
if( pPlayer )
|
||||
pPlayer->ModifyOrAppendPlayerCriteria( set );
|
||||
ReAppendContextCriteria( set );
|
||||
|
||||
DevMsg("Testing %s misc criteria\n", STRING(pInteraction->MiscCriteria));
|
||||
|
||||
int index;
|
||||
const char *criteriavalue;
|
||||
char key[128];
|
||||
char value[128];
|
||||
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)
|
||||
{
|
||||
criteriavalue = set.GetValue(index);
|
||||
if (!Matcher_Match(value, criteriavalue))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Test with empty string in case our criteria is != or something
|
||||
criteriavalue = "";
|
||||
if (!Matcher_Match(value, criteriavalue))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
pInteraction->bValidOnCurrentEnemy = true;
|
||||
@ -15789,7 +15839,95 @@ bool CAI_BaseNPC::InteractionIsAllowed( CAI_BaseNPC *pOtherNPC, ScriptedNPCInter
|
||||
return true;
|
||||
|
||||
// m_iDynamicInteractionsAllowed == TRS_FALSE case is already handled in CanRunAScriptedNPCInteraction().
|
||||
return !(pInteraction->iFlags & SCNPC_FLAG_MAPBASE_ADDITION && m_iDynamicInteractionsAllowed == TRS_NONE);
|
||||
if (pInteraction->iFlags & SCNPC_FLAG_MAPBASE_ADDITION && m_iDynamicInteractionsAllowed == TRS_NONE)
|
||||
return false;
|
||||
|
||||
// Test misc. criteria here since some of it may not have been valid on initial calculation, but could be now
|
||||
if (pInteraction->MiscCriteria != NULL_STRING)
|
||||
{
|
||||
// Test against response system criteria
|
||||
AI_CriteriaSet set;
|
||||
ModifyOrAppendCriteria( set );
|
||||
CBasePlayer *pPlayer = UTIL_GetLocalPlayer();
|
||||
if (pPlayer)
|
||||
pPlayer->ModifyOrAppendPlayerCriteria( set );
|
||||
|
||||
// Get criteria from target if we want it
|
||||
if ( V_strstr( STRING( pInteraction->MiscCriteria ), "their_" ) )
|
||||
{
|
||||
// Currently, in order to get everything which might be desired, we call the other NPC's ModifyOrAppendCriteria.
|
||||
// We put it in a separate criteria set, then assign a prefix and append it to the main set, similar to how contexts are appended.
|
||||
// This includes a few global criterions which we might not need, so we throw them out before they're merged.
|
||||
// This isn't a very efficient solution, but there are no better options available without rewriting parts of the response criteria system.
|
||||
AI_CriteriaSet theirSet;
|
||||
pOtherNPC->ModifyOrAppendCriteria( theirSet );
|
||||
|
||||
set.EnsureCapacity( (theirSet.GetCount()-2) + set.GetCount() ); // We know we'll be throwing out 2 global criterions
|
||||
|
||||
char sz[ 128 ];
|
||||
for ( int i = 0; i < theirSet.GetCount(); i++ )
|
||||
{
|
||||
const char *name = theirSet.GetName( i );
|
||||
const char *value = theirSet.GetValue( i );
|
||||
|
||||
if (FStrEq( name, "map" ) || FStrEq( name, "episodic" ) || FStrEq( name, "is_console" )
|
||||
|| FStrEq( name, "month" ) || FStrEq( name, "day" )
|
||||
|| FStrEq( name, "is_console" ) || FStrEq( name, "is_pc" )
|
||||
|| V_strnicmp( name, "world", 5 ) == 0)
|
||||
{
|
||||
// Global criterion, ignore
|
||||
continue;
|
||||
}
|
||||
|
||||
Q_snprintf( sz, sizeof( sz ), "their_%s", name );
|
||||
|
||||
if (ai_debug_dyninteractions.GetInt() == 3)
|
||||
Msg( "%i: %s -> %s:%s\n", i, name, sz, value );
|
||||
|
||||
set.AppendCriteria( sz, value );
|
||||
}
|
||||
|
||||
// Append this afterwards because it has its own prefix system
|
||||
pOtherNPC->AppendContextToCriteria( set, "their_" );
|
||||
}
|
||||
|
||||
ReAppendContextCriteria( set );
|
||||
|
||||
int index;
|
||||
const char *criteriavalue;
|
||||
char key[128];
|
||||
char value[128];
|
||||
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)
|
||||
{
|
||||
criteriavalue = set.GetValue( index );
|
||||
if (!Matcher_Match( value, criteriavalue ))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Test with empty string in case our criteria is != or something
|
||||
criteriavalue = "";
|
||||
if (!Matcher_Match( value, criteriavalue ))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -15855,14 +15993,28 @@ bool CAI_BaseNPC::InteractionCouldStart( CAI_BaseNPC *pOtherNPC, ScriptedNPCInte
|
||||
for ( int ang = 0; ang < 3; ang++ )
|
||||
{
|
||||
float flAngDiff = AngleDiff( angEnemyAngles[ang], angAngles[ang] );
|
||||
#ifdef MAPBASE
|
||||
if ( fabs(flAngDiff) > pInteraction->flMaxAngleDiff )
|
||||
#else
|
||||
if ( fabs(flAngDiff) > DSS_MAX_ANGLE_DIFF )
|
||||
#endif
|
||||
{
|
||||
bMatches = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( !bMatches )
|
||||
{
|
||||
#ifdef MAPBASE
|
||||
if ( bDebug )
|
||||
{
|
||||
Msg(" %s angle not matched: (%0.2f %0.2f %0.2f), desired (%0.2f, %0.2f, %0.2f)\n", GetDebugName(),
|
||||
anglemod(angEnemyAngles.x), anglemod(angEnemyAngles.y), anglemod(angEnemyAngles.z), anglemod(angAngles.x), anglemod(angAngles.y), anglemod(angAngles.z) );
|
||||
Msg(" diff: (%0.2f, %0.2f, %0.2f)\n", AngleDiff( angEnemyAngles.x, angAngles.x ), AngleDiff( angEnemyAngles.y, angAngles.y ), AngleDiff( angEnemyAngles.z, angAngles.z ) );
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( bDebug )
|
||||
{
|
||||
@ -15980,6 +16132,25 @@ bool CAI_BaseNPC::HasInteractionCantDie( void )
|
||||
return ( m_bCannotDieDuringInteraction && IsRunningDynamicInteraction() );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Return true if this NPC has valid interactions on the current enemy.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CAI_BaseNPC::HasValidInteractionsOnCurrentEnemy( void )
|
||||
{
|
||||
if ( !GetEnemy() || !GetEnemy()->IsNPC() )
|
||||
return false;
|
||||
|
||||
for ( int i = 0; i < m_ScriptedInteractions.Count(); i++ )
|
||||
{
|
||||
ScriptedNPCInteraction_t *pInteraction = &m_ScriptedInteractions[i];
|
||||
|
||||
if ( pInteraction->bValidOnCurrentEnemy )
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : &inputdata -
|
||||
|
@ -425,6 +425,9 @@ struct ScriptedNPCInteraction_t
|
||||
iszTheirWeapon = NULL_STRING;
|
||||
#ifdef MAPBASE
|
||||
vecRelativeEndPos = vec3_origin;
|
||||
bHasSeparateSequenceNames = false;
|
||||
flMaxAngleDiff = DSS_MAX_ANGLE_DIFF;
|
||||
iszRelatedInteractions = NULL_STRING;
|
||||
MiscCriteria = NULL_STRING;
|
||||
#endif
|
||||
|
||||
@ -432,6 +435,10 @@ struct ScriptedNPCInteraction_t
|
||||
{
|
||||
sPhases[i].iszSequence = NULL_STRING;
|
||||
sPhases[i].iActivity = ACT_INVALID;
|
||||
#ifdef MAPBASE
|
||||
sTheirPhases[i].iszSequence = NULL_STRING;
|
||||
sTheirPhases[i].iActivity = ACT_INVALID;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@ -459,10 +466,14 @@ struct ScriptedNPCInteraction_t
|
||||
float flNextAttemptTime;
|
||||
|
||||
#ifdef MAPBASE
|
||||
// Unrecognized keyvalues are tested against response criteria later.
|
||||
// This was originally a CUtlVector that carries response contexts, but I couldn't get it working due to some CUtlVector-struct shenanigans.
|
||||
// It works when we use a single string_t that's split and read each time the code runs, but feel free to improve on this.
|
||||
string_t MiscCriteria; // CUtlVector<ResponseContext_t>
|
||||
ScriptedNPCInteraction_Phases_t sTheirPhases[SNPCINT_NUM_PHASES]; // The animations played by the target NPC, if they are different
|
||||
bool bHasSeparateSequenceNames;
|
||||
|
||||
float flMaxAngleDiff;
|
||||
string_t iszRelatedInteractions; // These interactions will be delayed as well when this interaction is used.
|
||||
|
||||
// Unrecognized keyvalues which are tested against response criteria later.
|
||||
string_t MiscCriteria;
|
||||
#endif
|
||||
|
||||
DECLARE_SIMPLE_DATADESC();
|
||||
@ -1304,10 +1315,14 @@ private:
|
||||
public:
|
||||
float GetInteractionYaw( void ) const { return m_flInteractionYaw; }
|
||||
|
||||
bool IsRunningDynamicInteraction( void ) { return (m_iInteractionState != NPCINT_NOT_RUNNING && (m_hCine != NULL)); }
|
||||
bool IsActiveDynamicInteraction( void ) { return (m_iInteractionState == NPCINT_RUNNING_ACTIVE && (m_hCine != NULL)); }
|
||||
CAI_BaseNPC *GetInteractionPartner( void );
|
||||
|
||||
protected:
|
||||
void ParseScriptedNPCInteractions( void );
|
||||
void AddScriptedNPCInteraction( ScriptedNPCInteraction_t *pInteraction );
|
||||
const char *GetScriptedNPCInteractionSequence( ScriptedNPCInteraction_t *pInteraction, int iPhase );
|
||||
const char *GetScriptedNPCInteractionSequence( ScriptedNPCInteraction_t *pInteraction, int iPhase, bool bOtherNPC = false );
|
||||
void StartRunningInteraction( CAI_BaseNPC *pOtherNPC, bool bActive );
|
||||
void StartScriptedNPCInteraction( CAI_BaseNPC *pOtherNPC, ScriptedNPCInteraction_t *pInteraction, Vector vecOtherOrigin, QAngle angOtherAngles );
|
||||
void CheckForScriptedNPCInteractions( void );
|
||||
@ -1320,17 +1335,16 @@ protected:
|
||||
#endif
|
||||
bool InteractionCouldStart( CAI_BaseNPC *pOtherNPC, ScriptedNPCInteraction_t *pInteraction, Vector &vecOrigin, QAngle &angAngles );
|
||||
virtual bool CanRunAScriptedNPCInteraction( bool bForced = false );
|
||||
bool IsRunningDynamicInteraction( void ) { return (m_iInteractionState != NPCINT_NOT_RUNNING && (m_hCine != NULL)); }
|
||||
bool IsActiveDynamicInteraction( void ) { return (m_iInteractionState == NPCINT_RUNNING_ACTIVE && (m_hCine != NULL)); }
|
||||
ScriptedNPCInteraction_t *GetRunningDynamicInteraction( void ) { return &(m_ScriptedInteractions[m_iInteractionPlaying]); }
|
||||
void SetInteractionCantDie( bool bCantDie ) { m_bCannotDieDuringInteraction = bCantDie; }
|
||||
bool HasInteractionCantDie( void );
|
||||
bool HasValidInteractionsOnCurrentEnemy( void );
|
||||
virtual bool CanStartDynamicInteractionDuringMelee() { return false; }
|
||||
|
||||
void InputForceInteractionWithNPC( inputdata_t &inputdata );
|
||||
void StartForcedInteraction( CAI_BaseNPC *pNPC, int iInteraction );
|
||||
void CleanupForcedInteraction( void );
|
||||
void CalculateForcedInteractionPosition( void );
|
||||
CAI_BaseNPC *GetInteractionPartner( void );
|
||||
|
||||
private:
|
||||
// Forced interactions
|
||||
@ -2228,6 +2242,9 @@ public:
|
||||
static const char* GetActivityName (int actID);
|
||||
|
||||
static void AddActivityToSR(const char *actName, int conID);
|
||||
#ifdef MAPBASE
|
||||
static int GetOrRegisterActivity( const char *actName );
|
||||
#endif
|
||||
|
||||
static void AddEventToSR(const char *eventName, int conID);
|
||||
static const char* GetEventName (int actID);
|
||||
|
Loading…
Reference in New Issue
Block a user