1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
|
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Base combat character with no AI
//
//=====================================================================================//
#include "ai_baseactor.h"
#include "npc_playercompanion.h"
#include "ai_behavior_holster.h"
#include "ai_behavior_functank.h"
#include "soundenvelope.h"
extern ConVar npc_alyx_readiness;
class CNPC_Alyx : public CNPC_PlayerCompanion
{
public:
DECLARE_CLASS( CNPC_Alyx, CNPC_PlayerCompanion );
// fast class list
CNPC_Alyx *m_pNext;
virtual void ModifyOrAppendCriteria( AI_CriteriaSet &set );
bool ForceVehicleInteraction( const char *lpszInteractionName, CBaseCombatCharacter *pOther );
CNPC_Alyx( );
~CNPC_Alyx( );
static CNPC_Alyx *GetAlyx( void );
bool CreateBehaviors();
void Spawn( void );
void Activate( void );
void StopLoopingSounds( void );
void SelectModel();
void Precache( void );
void SetupAlyxWithoutParent( void );
void CreateEmpTool( void );
void PrescheduleThink( void );
void GatherConditions();
bool ShouldPlayerAvoid( void );
void AnalyzeGunfireSound( CSound *pSound );
bool IsValidEnemy( CBaseEntity *pEnemy );
void Event_KilledOther( CBaseEntity *pVictim, const CTakeDamageInfo &info );
void Event_Killed( const CTakeDamageInfo &info );
void EnemyIgnited( CAI_BaseNPC *pVictim );
void CombineBallSocketed( int iNumBounces );
void AimGun( void );
Vector GetActualShootPosition( const Vector &shootOrigin );
float MaxYawSpeed( void );
void OnUpdateShotRegulator();
bool IsCrouchedActivity( Activity activity );
bool OnBeginMoveAndShoot();
void SpeakAttacking( void );
virtual float GetJumpGravity() const { return 1.8f; }
// Crouching
Vector GetCrouchEyeOffset( void ) { return Vector(0,0,50); }
Vector GetCrouchGunOffset( void ) { return Vector(0,0,40); }
bool EnemyIsValidCrouchTarget( CBaseEntity *pEnemy );
bool Stand( void );
bool Crouch( void );
void DesireCrouch( void );
// Custom AI
void DoCustomCombatAI( void );
void DoMobbedCombatAI( void );
void DoCustomSpeechAI( void );
Disposition_t IRelationType( CBaseEntity *pTarget );
int IRelationPriority( CBaseEntity *pTarget );
CAI_FollowBehavior &GetFollowBehavior( void );
Class_T Classify ( void );
bool FValidateHintType( CAI_Hint *pHint );
int ObjectCaps();
void HandleAnimEvent( animevent_t *pEvent );
bool FInViewCone( CBaseEntity *pEntity );
bool QuerySeeEntity( CBaseEntity *pEntity, bool bOnlyHateOrFearIfNPC = false );
bool CanSeeEntityInDarkness( CBaseEntity *pEntity );
bool IsCoverPosition( const Vector &vecThreat, const Vector &vecPosition );
Activity NPC_TranslateActivity ( Activity activity );
bool ShouldDeferToFollowBehavior();
void BuildScheduleTestBits();
bool ShouldBehaviorSelectSchedule( CAI_BehaviorBase *pBehavior );
int SelectSchedule( void );
int SelectScheduleDanger( void );
int TranslateSchedule( int scheduleType );
void StartTask( const Task_t *pTask );
void RunTask( const Task_t *pTask );
void OnStateChange( NPC_STATE OldState, NPC_STATE NewState );
float LengthOfLastCombat( void ) const;
// bool IsNavigationUrgent();
void TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator );
bool CanBeHitByMeleeAttack( CBaseEntity *pAttacker );
int OnTakeDamage_Alive( const CTakeDamageInfo &info );
bool FCanCheckAttacks();
float GetAttackDamageScale( CBaseEntity *pVictim );
bool HandleInteraction(int interactionType, void *data, CBaseCombatCharacter* sourceEnt);
virtual bool SpeakIfAllowed( AIConcept_t concept, const char *modifiers = NULL, bool bRespondingToPlayer = false, char *pszOutResponseChosen = NULL, size_t bufsize = 0 );
void HolsterPistol();
void DrawPistol();
void Weapon_Drop( CBaseCombatWeapon *pWeapon, const Vector *pvecTarget = NULL, const Vector *pVelocity = NULL );
void SetEMPHolstered( bool bHolstered ) { m_bIsEMPHolstered = bHolstered; }
bool IsEMPHolstered() { return (!m_hEmpTool || m_hEmpTool->GetParent() != this || m_bIsEMPHolstered); }
float GetReadinessDecay() { return 60.0f; }
virtual bool IsAllowedToAim();
virtual void PainSound( const CTakeDamageInfo &info );
virtual void DeathSound( const CTakeDamageInfo &info );
// Hacking and object interaction
void SearchForInteractTargets();
bool IsValidInteractTarget( CBaseEntity *pTarget );
bool CanInteractWithTarget( CBaseEntity *pTarget );
void SetInteractTarget( CBaseEntity *pTarget );
bool HasInteractTarget() { return m_hHackTarget != NULL; }
CBaseEntity *GetInteractTarget() { return m_hHackTarget; }
void EmpZapTarget( CBaseEntity *pTarget );
virtual void OnSeeEntity( CBaseEntity *pEntity );
void InputAllowInteraction( inputdata_t &inputdata )
{
m_bInteractionAllowed = true;
}
void InputDisallowInteraction( inputdata_t &inputdata )
{
m_bInteractionAllowed = false;
}
void InputAllowDarknessSpeech( inputdata_t &inputdata )
{
m_bDarknessSpeechAllowed = inputdata.value.Bool();
}
void InputGiveEMP( inputdata_t &inputdata );
void InputVehiclePunted( inputdata_t &inputdata );
void InputOutsideTransition( inputdata_t &inputdata );
virtual void OnGivenWeapon( CBaseCombatWeapon *pNewWeapon );
virtual void OnChangeActiveWeapon( CBaseCombatWeapon *pOldWeapon, CBaseCombatWeapon *pNewWeapon );
virtual void Weapon_Equip( CBaseCombatWeapon *pWeapon );
virtual bool Weapon_CanUse( CBaseCombatWeapon *pWeapon );
// Blinding
virtual void PlayerHasIlluminatedNPC( CBasePlayer *pPlayer, float flDot );
void CheckBlindedByFlare( void );
bool CanBeBlindedByFlashlight( bool bCheckLightSources );
bool PlayerFlashlightOnMyEyes( CBasePlayer *pPlayer );
bool BlindedByFlare( void );
bool CanReload( void );
virtual bool PickTacticalLookTarget( AILookTargetArgs_t *pArgs );
virtual void OnSelectedLookTarget( AILookTargetArgs_t *pArgs );
virtual bool IsReadinessCapable( void );
virtual void ReadinessLevelChanged( int iPriorLevel );
bool IsAllowedToInteract();
virtual void BarnacleDeathSound( void );
virtual const char *GetDeathMessageText( void ) { return "GAMEOVER_ALYXDEAD"; }
PassengerState_e GetPassengerState( void );
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
bool PlayerInSpread( const Vector &sourcePos, const Vector &targetPos, float flSpread, float maxDistOffCenter, bool ignoreHatedPlayers );
private:
EHANDLE m_hEmpTool;
EHANDLE m_hHackTarget;
CHandle<CAI_Hint> m_hStealthLookTarget;
bool m_bInteractionAllowed;
float m_fTimeNextSearchForInteractTargets;
bool m_bDarknessSpeechAllowed;
bool m_bIsEMPHolstered;
bool m_bIsFlashlightBlind;
float m_fStayBlindUntil;
float m_flDontBlindUntil;
bool m_bSpokeLostPlayerInDarkness;
bool m_bPlayerFlashlightState;
bool m_bHadCondSeeEnemy;
string_t m_iszCurrentBlindScene;
float m_fTimeUntilNextDarknessFoundPlayer;
float m_fCombatStartTime;
float m_fCombatEndTime;
float m_flNextCrouchTime;
CSoundPatch *m_sndDarknessBreathing;
// Speech timers
// Theoretically, these shouldn't be needed. Instead, each response
// should prevent the concept being spoken for the desired time. But
// until the responses exists, Alyx will spam the response rules forever,
// so these timers stop that.
CRandStopwatch m_SpeechWatch_LostPlayer;
CSimpleSimTimer m_SpeechTimer_HeardSound;
CRandStopwatch m_SpeechWatch_SoundDelay;
CRandStopwatch m_SpeechWatch_BreathingRamp;
CRandStopwatch m_SpeechWatch_FoundPlayer;
CAI_MoveMonitor m_MoveMonitor;
enum WeaponType_t
{
WT_NONE,
WT_ALYXGUN,
WT_SMG1,
WT_SHOTGUN,
WT_AR2,
WT_OTHER,
};
int m_WeaponType;
bool m_bShouldHaveEMP;
CAI_FuncTankBehavior m_FuncTankBehavior;
COutputEvent m_OnFinishInteractWithObject;
COutputEvent m_OnPlayerUse;
bool RunningPassengerBehavior( void );
WeaponType_t ComputeWeaponType( CBaseEntity *pWeapon = NULL );
WeaponType_t GetWeaponType() { return (WeaponType_t)m_WeaponType; }
bool HasShotgun() { Assert( m_WeaponType == ComputeWeaponType() ); return ( m_WeaponType == WT_SHOTGUN ); }
bool HasAlyxgun() { Assert( m_WeaponType == ComputeWeaponType() ); return ( m_WeaponType == WT_ALYXGUN ); }
bool HasAR2() { Assert( m_WeaponType == ComputeWeaponType() ); return ( m_WeaponType == WT_AR2 ); }
private:
enum
{
COND_ALYX_HAS_INTERACT_TARGET = BaseClass::NEXT_CONDITION,
COND_ALYX_NO_INTERACT_TARGET,
COND_ALYX_CAN_INTERACT_WITH_TARGET, // Hack target is in a suitable state and location to hack
COND_ALYX_CAN_NOT_INTERACT_WITH_TARGET,
COND_ALYX_PLAYER_TURNED_ON_FLASHLIGHT,
COND_ALYX_PLAYER_TURNED_OFF_FLASHLIGHT,
COND_ALYX_PLAYER_FLASHLIGHT_EXPIRED,
COND_ALYX_IN_DARK, // lights are out and she can't see
};
enum
{
SCHED_ALYX_PREPARE_TO_INTERACT_WITH_TARGET = BaseClass::NEXT_SCHEDULE,
SCHED_ALYX_WAIT_TO_INTERACT_WITH_TARGET,
SCHED_ALYX_INTERACT_WITH_TARGET,
SCHED_ALYX_INTERACTION_INTERRUPTED,
SCHED_ALYX_FINISH_INTERACTING_WITH_TARGET,
SCHED_ALYX_HOLSTER_EMP,
SCHED_ALYX_ALERT_FACE_AWAYFROM_BESTSOUND,
SCHED_ALYX_RANGE_ATTACK1,
SCHED_ALYX_ALERT_REACT_TO_COMBAT_SOUND,
SCHED_ALYX_COMBAT_FACE,
SCHED_ALYX_WAKE_ANGRY,
SCHED_ALYX_NEW_WEAPON,
SCHED_ALYX_IDLE_STAND,
SCHED_ALYX_ALERT_FACE_BESTSOUND,
SCHED_ALYX_FALL_TO_GROUND,
};
enum
{
TASK_ALYX_BEGIN_INTERACTION = BaseClass::NEXT_TASK,
TASK_ALYX_COMPLETE_INTERACTION,
TASK_ALYX_ANNOUNCE_HACK,
TASK_ALYX_GET_PATH_TO_INTERACT_TARGET,
TASK_ALYX_WAIT_HACKING,
TASK_ALYX_HOLSTER_PISTOL,
TASK_ALYX_DRAW_PISTOL,
TASK_ALYX_HOLSTER_AND_DESTROY_PISTOL,
TASK_ALYX_BUILD_COMBAT_FACE_PATH,
TASK_ALYX_SET_IDLE_ACTIVITY,
TASK_ALYX_FALL_TO_GROUND,
};
DECLARE_DATADESC();
DEFINE_CUSTOM_AI;
};
|