|
35 | 35 | #include "mapbase/GlobalStrings.h"
|
36 | 36 | #include "world.h"
|
37 | 37 | #include "vehicle_base.h"
|
| 38 | +#include "npc_headcrab.h" |
| 39 | +#include "npc_BaseZombie.h" |
38 | 40 | #endif
|
39 | 41 |
|
40 | 42 | ConVar ai_debug_readiness("ai_debug_readiness", "0" );
|
@@ -640,6 +642,55 @@ void CNPC_PlayerCompanion::DoCustomSpeechAI( void )
|
640 | 642 | {
|
641 | 643 | SpeakIfAllowed( TLK_PLDEAD );
|
642 | 644 | }
|
| 645 | + |
| 646 | +#ifdef MAPBASE |
| 647 | + // Unique new enemy concepts ported from Alyx |
| 648 | + // The casts have been changed to dynamic_cast due to the risk of non-CBaseHeadcrab/CNPC_BaseZombie enemies using those classes |
| 649 | + if ( HasCondition(COND_NEW_ENEMY) && GetEnemy() ) |
| 650 | + { |
| 651 | + int nClass = GetEnemy()->Classify(); |
| 652 | + if ( nClass == CLASS_HEADCRAB ) |
| 653 | + { |
| 654 | + CBaseHeadcrab *pHC = dynamic_cast<CBaseHeadcrab*>(GetEnemy()); |
| 655 | + if ( pHC ) |
| 656 | + { |
| 657 | + // If we see a headcrab for the first time as he's jumping at me, freak out! |
| 658 | + if ( ( GetEnemy()->GetEnemy() == this ) && pHC->IsJumping() && gpGlobals->curtime - GetEnemies()->FirstTimeSeen(GetEnemy()) < 0.5 ) |
| 659 | + { |
| 660 | + SpeakIfAllowed( "TLK_SPOTTED_INCOMING_HEADCRAB" ); |
| 661 | + } |
| 662 | + else |
| 663 | + { |
| 664 | + // If we see a headcrab leaving a zombie that just died, mention it |
| 665 | + // (Note that this is now a response context since some death types remove the zombie instantly) |
| 666 | + int nContext = pHC->FindContextByName( "from_zombie" ); |
| 667 | + if ( nContext > -1 && !ContextExpired( nContext ) ) // pHC->GetOwnerEntity() && ( pHC->GetOwnerEntity()->Classify() == CLASS_ZOMBIE ) && !pHC->GetOwnerEntity()->IsAlive() |
| 668 | + { |
| 669 | + SpeakIfAllowed( "TLK_SPOTTED_HEADCRAB_LEAVING_ZOMBIE" ); |
| 670 | + } |
| 671 | + } |
| 672 | + } |
| 673 | + } |
| 674 | + else if ( nClass == CLASS_ZOMBIE ) |
| 675 | + { |
| 676 | + CNPC_BaseZombie *pZombie = dynamic_cast<CNPC_BaseZombie*>(GetEnemy()); |
| 677 | + // If we see a zombie getting up, mention it |
| 678 | + if ( pZombie && pZombie->IsGettingUp() ) |
| 679 | + { |
| 680 | + SpeakIfAllowed( "TLK_SPOTTED_ZOMBIE_WAKEUP" ); |
| 681 | + } |
| 682 | + } |
| 683 | + |
| 684 | + if ( gpGlobals->curtime - GetEnemies()->TimeAtFirstHand( GetEnemy() ) <= 1.0f && nClass != CLASS_BULLSEYE ) |
| 685 | + { |
| 686 | + // New concept which did not originate from Alyx, but is in the same category as the above concepts. |
| 687 | + // This is meant to be used when a new enemy enters the arena while combat is already in progress. |
| 688 | + // (Note that this can still trigger when combat begins, but unlike TLK_STARTCOMBAT, it has no delay |
| 689 | + // between combat engagements.) |
| 690 | + SpeakIfAllowed( TLK_NEW_ENEMY ); |
| 691 | + } |
| 692 | + } |
| 693 | +#endif |
643 | 694 | }
|
644 | 695 |
|
645 | 696 | //-----------------------------------------------------------------------------
|
@@ -910,8 +961,21 @@ int CNPC_PlayerCompanion::SelectScheduleDanger()
|
910 | 961 |
|
911 | 962 | if ( pSound && (pSound->m_iType & SOUND_DANGER) )
|
912 | 963 | {
|
| 964 | +#ifdef MAPBASE |
| 965 | + if ( pSound->SoundChannel() == SOUNDENT_CHANNEL_ZOMBINE_GRENADE ) |
| 966 | + { |
| 967 | + SetSpeechTarget( pSound->m_hOwner ); |
| 968 | + SpeakIfAllowed( TLK_DANGER_ZOMBINE_GRENADE ); |
| 969 | + } |
| 970 | + else if (!(pSound->SoundContext() & (SOUND_CONTEXT_MORTAR | SOUND_CONTEXT_FROM_SNIPER)) || IsOkToCombatSpeak()) |
| 971 | + { |
| 972 | + SetSpeechTarget( pSound->m_hOwner ); |
| 973 | + SpeakIfAllowed( TLK_DANGER ); |
| 974 | + } |
| 975 | +#else |
913 | 976 | if ( !(pSound->SoundContext() & (SOUND_CONTEXT_MORTAR|SOUND_CONTEXT_FROM_SNIPER)) || IsOkToCombatSpeak() )
|
914 | 977 | SpeakIfAllowed( TLK_DANGER );
|
| 978 | +#endif |
915 | 979 |
|
916 | 980 | if ( HasCondition( COND_PC_SAFE_FROM_MORTAR ) )
|
917 | 981 | {
|
@@ -4309,6 +4373,20 @@ void CNPC_PlayerCompanion::Event_KilledOther( CBaseEntity *pVictim, const CTakeD
|
4309 | 4373 | }
|
4310 | 4374 | }
|
4311 | 4375 |
|
| 4376 | +//----------------------------------------------------------------------------- |
| 4377 | +// Purpose: Called by enemy NPC's when they are ignited |
| 4378 | +// Input : pVictim - entity that was ignited |
| 4379 | +//----------------------------------------------------------------------------- |
| 4380 | +void CNPC_PlayerCompanion::EnemyIgnited( CAI_BaseNPC *pVictim ) |
| 4381 | +{ |
| 4382 | + BaseClass::EnemyIgnited( pVictim ); |
| 4383 | + |
| 4384 | + if ( FVisible( pVictim ) ) |
| 4385 | + { |
| 4386 | + SpeakIfAllowed( TLK_ENEMY_BURNING ); |
| 4387 | + } |
| 4388 | +} |
| 4389 | + |
4312 | 4390 | //-----------------------------------------------------------------------------
|
4313 | 4391 | // Purpose: Handles custom combat speech stuff ported from Alyx.
|
4314 | 4392 | //-----------------------------------------------------------------------------
|
@@ -4376,6 +4454,21 @@ void CNPC_PlayerCompanion::DoCustomCombatAI( void )
|
4376 | 4454 | {
|
4377 | 4455 | SpeakIfAllowed( TLK_MANY_ENEMIES );
|
4378 | 4456 | }
|
| 4457 | + |
| 4458 | + // If we're not currently attacking or vulnerable, try speaking |
| 4459 | + else if ( gpGlobals->curtime - GetLastAttackTime() > 1.0f && (!HasCondition( COND_SEE_ENEMY ) || IsCurSchedule( SCHED_RELOAD ) || IsCurSchedule( SCHED_HIDE_AND_RELOAD )) ) |
| 4460 | + { |
| 4461 | + int chance = ( IsMoving() ) ? 20 : 3; |
| 4462 | + if ( ShouldSpeakRandom( TLK_COMBAT_IDLE, chance ) ) |
| 4463 | + { |
| 4464 | + AI_CriteriaSet modifiers; |
| 4465 | + |
| 4466 | + modifiers.AppendCriteria( "in_cover", HasMemory( bits_MEMORY_INCOVER ) ? "1" : "0" ); |
| 4467 | + modifiers.AppendCriteria( "lastseenenemy", UTIL_VarArgs( "%f", gpGlobals->curtime - GetEnemyLastTimeSeen() ) ); |
| 4468 | + |
| 4469 | + SpeakIfAllowed( TLK_COMBAT_IDLE, modifiers ); |
| 4470 | + } |
| 4471 | + } |
4379 | 4472 | }
|
4380 | 4473 | #endif
|
4381 | 4474 |
|
|
0 commit comments