Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions sp/src/game/server/ai_basenpc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -671,13 +671,27 @@ void CAI_BaseNPC::Ignite( float flFlameLifetime, bool bNPCOnly, float flSize, bo
{
BaseClass::Ignite( flFlameLifetime, bNPCOnly, flSize, bCalledByLevelDesigner );

#ifdef MAPBASE
// Alyx's enemy ignited code from below can now be run on any NPC as long as
// it's our current enemy.
if ( GetEnemy() && GetEnemy()->IsNPC() )
{
GetEnemy()->MyNPCPointer()->EnemyIgnited( this );
}
#endif

#ifdef HL2_EPISODIC
CBasePlayer *pPlayer = AI_GetSinglePlayer();
if ( pPlayer && pPlayer->IRelationType( this ) != D_LI )
{
CNPC_Alyx *alyx = CNPC_Alyx::GetAlyx();

#ifdef MAPBASE
// Alyx's code continues to run if Alyx was not this NPC's enemy.
if ( alyx && alyx != GetEnemy() )
#else
if ( alyx )
#endif
{
alyx->EnemyIgnited( this );
}
Expand Down Expand Up @@ -16213,6 +16227,21 @@ void CAI_BaseNPC::ModifyOrAppendEnemyCriteria( AI_CriteriaSet& set, CBaseEntity
set.AppendCriteria( "enemyclass", g_pGameRules->AIClassText( pEnemy->Classify() ) ); // UTIL_VarArgs("%i", pEnemy->Classify())
set.AppendCriteria( "distancetoenemy", UTIL_VarArgs( "%f", EnemyDistance(pEnemy) ) );
set.AppendCriteria( "timesincecombat", "-1" );

CAI_BaseNPC *pNPC = pEnemy->MyNPCPointer();
if (pNPC)
{
set.AppendCriteria("enemy_is_npc", "1");

set.AppendCriteria( "enemy_activity", CAI_BaseNPC::GetActivityName( pNPC->GetActivity() ) );
set.AppendCriteria( "enemy_weapon", pNPC->GetActiveWeapon() ? pNPC->GetActiveWeapon()->GetClassname() : "0" );
}
else
{
set.AppendCriteria("enemy_is_npc", "0");
}

pEnemy->AppendContextToCriteria( set, "enemy_" );
}
else
{
Expand Down
3 changes: 3 additions & 0 deletions sp/src/game/server/ai_basenpc.h
Original file line number Diff line number Diff line change
Expand Up @@ -1974,6 +1974,9 @@ class CAI_BaseNPC : public CBaseCombatCharacter,
//---------------------------------

virtual void Ignite( float flFlameLifetime, bool bNPCOnly = true, float flSize = 0.0f, bool bCalledByLevelDesigner = false );
#ifdef MAPBASE
virtual void EnemyIgnited( CAI_BaseNPC *pVictim ) {}
#endif
virtual bool PassesDamageFilter( const CTakeDamageInfo &info );

//---------------------------------
Expand Down
38 changes: 38 additions & 0 deletions sp/src/game/server/ai_playerally.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,12 @@ ConceptInfo_t g_ConceptInfos[] =

// Passenger behaviour
{ TLK_PASSENGER_NEW_RADAR_CONTACT, SPEECH_IMPORTANT, -1, -1, -1, -1, -1, -1, AICF_DEFAULT, },

#ifdef MAPBASE
{ TLK_TAKING_FIRE, SPEECH_IMPORTANT,-1, -1, -1, -1, -1, -1, AICF_DEFAULT, },
{ TLK_NEW_ENEMY, SPEECH_IMPORTANT,-1, -1, -1, -1, -1, -1, AICF_DEFAULT, },
{ TLK_COMBAT_IDLE, SPEECH_IMPORTANT,-1, -1, -1, -1, -1, -1, AICF_DEFAULT, },
#endif
};

//-----------------------------------------------------------------------------
Expand Down Expand Up @@ -1259,6 +1265,38 @@ void CAI_PlayerAlly::OnKilledNPC( CBaseCombatCharacter *pKilled )
}
}

#ifdef MAPBASE
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CAI_PlayerAlly::OnEnemyRangeAttackedMe( CBaseEntity *pEnemy, const Vector &vecDir, const Vector &vecEnd )
{
BaseClass::OnEnemyRangeAttackedMe( pEnemy, vecDir, vecEnd );

if ( IRelationType( pEnemy ) <= D_FR )
{
AI_CriteriaSet modifiers;
ModifyOrAppendEnemyCriteria( modifiers, pEnemy );

Vector vecEntDir = (pEnemy->EyePosition() - EyePosition());
float flDot = DotProduct( vecEntDir.Normalized(), vecDir );
modifiers.AppendCriteria( "shot_dot", CNumStr( flDot ) );

if (GetLastDamageTime() == gpGlobals->curtime)
modifiers.AppendCriteria( "missed", "0" );
else
modifiers.AppendCriteria( "missed", "1" );

// Check if they're out of ammo
if ( pEnemy->IsCombatCharacter() && pEnemy->MyCombatCharacterPointer()->GetActiveWeapon() && pEnemy->MyCombatCharacterPointer()->GetActiveWeapon()->Clip1() <= 0 )
modifiers.AppendCriteria( "last_attack", "1" );
else
modifiers.AppendCriteria( "last_attack", "0" );

SpeakIfAllowed( TLK_TAKING_FIRE, modifiers );
}
}
#endif

//-----------------------------------------------------------------------------
void CAI_PlayerAlly::TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator )
{
Expand Down
11 changes: 11 additions & 0 deletions sp/src/game/server/ai_playerally.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,13 @@
#define TLK_TGCATCHUP "TLK_TGCATCHUP"
#define TLK_TGENDTOUR "TLK_TGENDTOUR"

#ifdef MAPBASE
// Additional concepts for companions in mods
#define TLK_TAKING_FIRE "TLK_TAKING_FIRE" // Someone fired at me (regardless of whether I was hit)
#define TLK_NEW_ENEMY "TLK_NEW_ENEMY" // A new enemy appeared while combat was already in progress
#define TLK_COMBAT_IDLE "TLK_COMBAT_IDLE" // Similar to TLK_ATTACKING, but specifically for when *not* currently attacking (e.g. when in cover or reloading)
#endif

//-----------------------------------------------------------------------------

#define TALKRANGE_MIN 500.0 // don't talk to anyone farther away than this
Expand Down Expand Up @@ -315,6 +322,10 @@ class CAI_PlayerAlly : public CAI_BaseActor
//---------------------------------
void OnKilledNPC( CBaseCombatCharacter *pKilled );

#ifdef MAPBASE
void OnEnemyRangeAttackedMe( CBaseEntity *pEnemy, const Vector &vecDir, const Vector &vecEnd );
#endif

//---------------------------------
// Damage handling
//---------------------------------
Expand Down
4 changes: 4 additions & 0 deletions sp/src/game/server/basecombatcharacter.h
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,10 @@ class CBaseCombatCharacter : public CBaseFlex

virtual bool CanBecomeServerRagdoll( void ) { return true; }

#ifdef MAPBASE
virtual void OnEnemyRangeAttackedMe( CBaseEntity *pEnemy, const Vector &vecDir, const Vector &vecEnd ) {}
#endif

// -----------------------
// Damage
// -----------------------
Expand Down
18 changes: 18 additions & 0 deletions sp/src/game/server/hl2/ai_behavior_functank.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,24 @@ int CAI_FuncTankBehavior::SelectSchedule()
return SCHED_IDLE_STAND;
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CAI_FuncTankBehavior::ModifyOrAppendCriteria( AI_CriteriaSet &set )
{
BaseClass::ModifyOrAppendCriteria( set );

#ifdef MAPBASE
set.AppendCriteria( "ft_mounted", m_bMounted ? "1" : "0" );

if (m_hFuncTank)
{
set.AppendCriteria( "ft_classname", m_hFuncTank->GetClassname() );
m_hFuncTank->AppendContextToCriteria( set, "ft_" );
}
#endif
}

//-----------------------------------------------------------------------------
// Purpose:
// Input : activity -
Expand Down
2 changes: 2 additions & 0 deletions sp/src/game/server/hl2/ai_behavior_functank.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ class CAI_FuncTankBehavior : public CAI_SimpleBehavior
bool CanManTank( CFuncTank *pTank, bool bForced );
#endif

void ModifyOrAppendCriteria( AI_CriteriaSet &set );

Activity NPC_TranslateActivity( Activity activity );

// Conditions:
Expand Down
3 changes: 3 additions & 0 deletions sp/src/game/server/hl2/npc_BaseZombie.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2590,6 +2590,9 @@ void CNPC_BaseZombie::ReleaseHeadcrab( const Vector &vecOrigin, const Vector &ve
// Inherit some misc. properties
pCrab->m_bForceServerRagdoll = m_bForceServerRagdoll;
pCrab->m_iViewHideFlags = m_iViewHideFlags;

// Add response context for companion response (more reliable than checking for post-death zombie entity)
pCrab->AddContext( "from_zombie", "1", 2.0f );
#endif

// make me the crab's owner to avoid collision issues
Expand Down
8 changes: 8 additions & 0 deletions sp/src/game/server/hl2/npc_alyx_episodic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1092,10 +1092,14 @@ void CNPC_Alyx::Event_KilledOther( CBaseEntity *pVictim, const CTakeDamageInfo &
//-----------------------------------------------------------------------------
void CNPC_Alyx::EnemyIgnited( CAI_BaseNPC *pVictim )
{
#ifdef MAPBASE
BaseClass::EnemyIgnited( pVictim );
#else
if ( FVisible( pVictim ) )
{
SpeakIfAllowed( TLK_ENEMY_BURNING );
}
#endif
}

//-----------------------------------------------------------------------------
Expand Down Expand Up @@ -1252,6 +1256,7 @@ void CNPC_Alyx::DoCustomSpeechAI( void )

CBasePlayer *pPlayer = AI_GetSinglePlayer();

#ifndef MAPBASE // Ported to CNPC_PlayerCompanion
if ( HasCondition(COND_NEW_ENEMY) && GetEnemy() )
{
if ( GetEnemy()->Classify() == CLASS_HEADCRAB )
Expand All @@ -1278,6 +1283,7 @@ void CNPC_Alyx::DoCustomSpeechAI( void )
}
}
}
#endif

// Darkness mode speech
ClearCondition( COND_ALYX_IN_DARK );
Expand Down Expand Up @@ -1917,6 +1923,7 @@ int CNPC_Alyx::SelectSchedule( void )
//-----------------------------------------------------------------------------
int CNPC_Alyx::SelectScheduleDanger( void )
{
#ifndef MAPBASE
if( HasCondition( COND_HEAR_DANGER ) )
{
CSound *pSound;
Expand All @@ -1929,6 +1936,7 @@ int CNPC_Alyx::SelectScheduleDanger( void )
SpeakIfAllowed( TLK_DANGER_ZOMBINE_GRENADE );
}
}
#endif

return BaseClass::SelectScheduleDanger();
}
Expand Down
93 changes: 93 additions & 0 deletions sp/src/game/server/hl2/npc_playercompanion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@
#include "mapbase/GlobalStrings.h"
#include "world.h"
#include "vehicle_base.h"
#include "npc_headcrab.h"
#include "npc_BaseZombie.h"
#endif

ConVar ai_debug_readiness("ai_debug_readiness", "0" );
Expand Down Expand Up @@ -640,6 +642,55 @@ void CNPC_PlayerCompanion::DoCustomSpeechAI( void )
{
SpeakIfAllowed( TLK_PLDEAD );
}

#ifdef MAPBASE
// Unique new enemy concepts ported from Alyx
// The casts have been changed to dynamic_cast due to the risk of non-CBaseHeadcrab/CNPC_BaseZombie enemies using those classes
if ( HasCondition(COND_NEW_ENEMY) && GetEnemy() )
{
int nClass = GetEnemy()->Classify();
if ( nClass == CLASS_HEADCRAB )
{
CBaseHeadcrab *pHC = dynamic_cast<CBaseHeadcrab*>(GetEnemy());
if ( pHC )
{
// If we see a headcrab for the first time as he's jumping at me, freak out!
if ( ( GetEnemy()->GetEnemy() == this ) && pHC->IsJumping() && gpGlobals->curtime - GetEnemies()->FirstTimeSeen(GetEnemy()) < 0.5 )
{
SpeakIfAllowed( "TLK_SPOTTED_INCOMING_HEADCRAB" );
}
else
{
// If we see a headcrab leaving a zombie that just died, mention it
// (Note that this is now a response context since some death types remove the zombie instantly)
int nContext = pHC->FindContextByName( "from_zombie" );
if ( nContext > -1 && !ContextExpired( nContext ) ) // pHC->GetOwnerEntity() && ( pHC->GetOwnerEntity()->Classify() == CLASS_ZOMBIE ) && !pHC->GetOwnerEntity()->IsAlive()
{
SpeakIfAllowed( "TLK_SPOTTED_HEADCRAB_LEAVING_ZOMBIE" );
}
}
}
}
else if ( nClass == CLASS_ZOMBIE )
{
CNPC_BaseZombie *pZombie = dynamic_cast<CNPC_BaseZombie*>(GetEnemy());
// If we see a zombie getting up, mention it
if ( pZombie && pZombie->IsGettingUp() )
{
SpeakIfAllowed( "TLK_SPOTTED_ZOMBIE_WAKEUP" );
}
}

if ( gpGlobals->curtime - GetEnemies()->TimeAtFirstHand( GetEnemy() ) <= 1.0f && nClass != CLASS_BULLSEYE )
{
// New concept which did not originate from Alyx, but is in the same category as the above concepts.
// This is meant to be used when a new enemy enters the arena while combat is already in progress.
// (Note that this can still trigger when combat begins, but unlike TLK_STARTCOMBAT, it has no delay
// between combat engagements.)
SpeakIfAllowed( TLK_NEW_ENEMY );
}
}
#endif
}

//-----------------------------------------------------------------------------
Expand Down Expand Up @@ -910,8 +961,21 @@ int CNPC_PlayerCompanion::SelectScheduleDanger()

if ( pSound && (pSound->m_iType & SOUND_DANGER) )
{
#ifdef MAPBASE
if ( pSound->SoundChannel() == SOUNDENT_CHANNEL_ZOMBINE_GRENADE )
{
SetSpeechTarget( pSound->m_hOwner );
SpeakIfAllowed( TLK_DANGER_ZOMBINE_GRENADE );
}
else if (!(pSound->SoundContext() & (SOUND_CONTEXT_MORTAR | SOUND_CONTEXT_FROM_SNIPER)) || IsOkToCombatSpeak())
{
SetSpeechTarget( pSound->m_hOwner );
SpeakIfAllowed( TLK_DANGER );
}
#else
if ( !(pSound->SoundContext() & (SOUND_CONTEXT_MORTAR|SOUND_CONTEXT_FROM_SNIPER)) || IsOkToCombatSpeak() )
SpeakIfAllowed( TLK_DANGER );
#endif

if ( HasCondition( COND_PC_SAFE_FROM_MORTAR ) )
{
Expand Down Expand Up @@ -4309,6 +4373,20 @@ void CNPC_PlayerCompanion::Event_KilledOther( CBaseEntity *pVictim, const CTakeD
}
}

//-----------------------------------------------------------------------------
// Purpose: Called by enemy NPC's when they are ignited
// Input : pVictim - entity that was ignited
//-----------------------------------------------------------------------------
void CNPC_PlayerCompanion::EnemyIgnited( CAI_BaseNPC *pVictim )
{
BaseClass::EnemyIgnited( pVictim );

if ( FVisible( pVictim ) )
{
SpeakIfAllowed( TLK_ENEMY_BURNING );
}
}

//-----------------------------------------------------------------------------
// Purpose: Handles custom combat speech stuff ported from Alyx.
//-----------------------------------------------------------------------------
Expand Down Expand Up @@ -4376,6 +4454,21 @@ void CNPC_PlayerCompanion::DoCustomCombatAI( void )
{
SpeakIfAllowed( TLK_MANY_ENEMIES );
}

// If we're not currently attacking or vulnerable, try speaking
else if ( gpGlobals->curtime - GetLastAttackTime() > 1.0f && (!HasCondition( COND_SEE_ENEMY ) || IsCurSchedule( SCHED_RELOAD ) || IsCurSchedule( SCHED_HIDE_AND_RELOAD )) )
{
int chance = ( IsMoving() ) ? 20 : 3;
if ( ShouldSpeakRandom( TLK_COMBAT_IDLE, chance ) )
{
AI_CriteriaSet modifiers;

modifiers.AppendCriteria( "in_cover", HasMemory( bits_MEMORY_INCOVER ) ? "1" : "0" );
modifiers.AppendCriteria( "lastseenenemy", UTIL_VarArgs( "%f", gpGlobals->curtime - GetEnemyLastTimeSeen() ) );

SpeakIfAllowed( TLK_COMBAT_IDLE, modifiers );
}
}
}
#endif

Expand Down
1 change: 1 addition & 0 deletions sp/src/game/server/hl2/npc_playercompanion.h
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,7 @@ class CNPC_PlayerCompanion : public CAI_PlayerAlly

virtual void Event_Killed( const CTakeDamageInfo &info );
virtual void Event_KilledOther( CBaseEntity *pVictim, const CTakeDamageInfo &info );
virtual void EnemyIgnited( CAI_BaseNPC *pVictim );
virtual void DoCustomCombatAI( void );
#endif

Expand Down
Loading