aboutsummaryrefslogtreecommitdiff
path: root/sp/src/game/server/hl2/npc_BaseZombie.h
blob: d4800f3c6917595278a095f382eb67fee7c17c46 (plain) (blame)
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
290
291
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: 
//
// $NoKeywords: $
//=============================================================================//

#ifndef NPC_BASEZOMBIE_H
#define NPC_BASEZOMBIE_H
#ifdef _WIN32
#pragma once
#endif

#include "ai_basenpc.h"
#include "ai_blended_movement.h"
#include "soundenvelope.h"
#include "ai_behavior_actbusy.h"

#define ZOM_ATTN_FOOTSTEP ATTN_IDLE

#define	ENVELOPE_CONTROLLER		(CSoundEnvelopeController::GetController())

#define ZOMBIE_MELEE_REACH	55

extern int AE_ZOMBIE_ATTACK_RIGHT;
extern int AE_ZOMBIE_ATTACK_LEFT;
extern int AE_ZOMBIE_ATTACK_BOTH;
extern int AE_ZOMBIE_SWATITEM;
extern int AE_ZOMBIE_STARTSWAT;
extern int AE_ZOMBIE_STEP_LEFT;
extern int AE_ZOMBIE_STEP_RIGHT;
extern int AE_ZOMBIE_SCUFF_LEFT;
extern int AE_ZOMBIE_SCUFF_RIGHT;
extern int AE_ZOMBIE_ATTACK_SCREAM;
extern int AE_ZOMBIE_GET_UP;
extern int AE_ZOMBIE_POUND;

#define ZOMBIE_BODYGROUP_HEADCRAB	1	// The crab on our head

// Pass these to claw attack so we know where to draw the blood.
#define ZOMBIE_BLOOD_LEFT_HAND		0
#define ZOMBIE_BLOOD_RIGHT_HAND		1
#define ZOMBIE_BLOOD_BOTH_HANDS		2
#define ZOMBIE_BLOOD_BITE			3
	

enum HeadcrabRelease_t
{
	RELEASE_NO,
	RELEASE_IMMEDIATE,		// release the headcrab right now!
	RELEASE_SCHEDULED,		// release the headcrab through the AI schedule.
	RELEASE_VAPORIZE,		// just destroy the crab.	
	RELEASE_RAGDOLL,		// release a dead crab
	RELEASE_RAGDOLL_SLICED_OFF	// toss the crab up a bit
};


//=========================================================
// schedules
//=========================================================
enum
{
	SCHED_ZOMBIE_CHASE_ENEMY = LAST_SHARED_SCHEDULE,
	SCHED_ZOMBIE_MOVE_SWATITEM,
	SCHED_ZOMBIE_SWATITEM,
	SCHED_ZOMBIE_ATTACKITEM,
	SCHED_ZOMBIE_RELEASECRAB,
	SCHED_ZOMBIE_MOVE_TO_AMBUSH,
	SCHED_ZOMBIE_WAIT_AMBUSH,
	SCHED_ZOMBIE_WANDER_MEDIUM,	// medium range wandering behavior.
	SCHED_ZOMBIE_WANDER_FAIL,
	SCHED_ZOMBIE_WANDER_STANDOFF,
	SCHED_ZOMBIE_MELEE_ATTACK1,
	SCHED_ZOMBIE_POST_MELEE_WAIT,

	LAST_BASE_ZOMBIE_SCHEDULE,
};

//=========================================================
// tasks
//=========================================================
enum 
{
	TASK_ZOMBIE_DELAY_SWAT = LAST_SHARED_TASK,
	TASK_ZOMBIE_GET_PATH_TO_PHYSOBJ,
	TASK_ZOMBIE_SWAT_ITEM,
	TASK_ZOMBIE_DIE,
	TASK_ZOMBIE_RELEASE_HEADCRAB,
	TASK_ZOMBIE_WAIT_POST_MELEE,

	LAST_BASE_ZOMBIE_TASK,
};


//=========================================================
// Zombie conditions
//=========================================================
enum Zombie_Conds
{
	COND_ZOMBIE_CAN_SWAT_ATTACK = LAST_SHARED_CONDITION,
	COND_ZOMBIE_RELEASECRAB,
	COND_ZOMBIE_LOCAL_MELEE_OBSTRUCTION,

	LAST_BASE_ZOMBIE_CONDITION,
};



typedef CAI_BlendingHost< CAI_BehaviorHost<CAI_BaseNPC> > CAI_BaseZombieBase;

//=========================================================
//=========================================================
abstract_class CNPC_BaseZombie : public CAI_BaseZombieBase
{
	DECLARE_CLASS( CNPC_BaseZombie, CAI_BaseZombieBase );

public:
	CNPC_BaseZombie( void );
	~CNPC_BaseZombie( void );

	void Spawn( void );
	void Precache( void );
	void StartTouch( CBaseEntity *pOther );
	bool CreateBehaviors();
	float MaxYawSpeed( void );
	bool OverrideMoveFacing( const AILocalMoveGoal_t &move, float flInterval );
	Class_T Classify( void );
	Disposition_t IRelationType( CBaseEntity *pTarget );
	void HandleAnimEvent( animevent_t *pEvent );

	void OnStateChange( NPC_STATE OldState, NPC_STATE NewState );

	void KillMe( void )
	{
		m_iHealth = 5;
		OnTakeDamage( CTakeDamageInfo( this, this, m_iHealth * 2, DMG_GENERIC ) );
	}

	int MeleeAttack1Conditions ( float flDot, float flDist );
	virtual float GetClawAttackRange() const { return ZOMBIE_MELEE_REACH; }

	// No range attacks
	int RangeAttack1Conditions ( float flDot, float flDist ) { return( 0 ); }
	
	virtual float GetHitgroupDamageMultiplier( int iHitGroup, const CTakeDamageInfo &info );
	void TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator );
	int OnTakeDamage_Alive( const CTakeDamageInfo &info );
	virtual float	GetReactionDelay( CBaseEntity *pEnemy ) { return 0.0; }

	virtual int SelectSchedule ( void );
	virtual int	SelectFailSchedule( int failedSchedule, int failedTask, AI_TaskFailureCode_t taskFailCode );
	virtual void BuildScheduleTestBits( void );

	virtual int TranslateSchedule( int scheduleType );
	virtual Activity NPC_TranslateActivity( Activity baseAct );

	void StartTask( const Task_t *pTask );
	void RunTask( const Task_t *pTask );

	void GatherConditions( void );
	void PrescheduleThink( void );

	virtual void Event_Killed( const CTakeDamageInfo &info );
	virtual bool BecomeRagdoll( const CTakeDamageInfo &info, const Vector &forceVector );
	void StopLoopingSounds();
	virtual void OnScheduleChange( void );

	virtual void PoundSound();

	// Custom damage/death 
	bool ShouldIgnite( const CTakeDamageInfo &info );
	bool ShouldIgniteZombieGib( void );
	virtual bool IsChopped( const CTakeDamageInfo &info );
	virtual bool IsSquashed( const CTakeDamageInfo &info ) { return false; }
	virtual void DieChopped( const CTakeDamageInfo &info );
	virtual void Ignite( float flFlameLifetime, bool bNPCOnly = true, float flSize = 0.0f, bool bCalledByLevelDesigner = false );
	void CopyRenderColorTo( CBaseEntity *pOther );

	virtual bool ShouldBecomeTorso( const CTakeDamageInfo &info, float flDamageThreshold );
	virtual HeadcrabRelease_t ShouldReleaseHeadcrab( const CTakeDamageInfo &info, float flDamageThreshold );

	// Headcrab releasing/breaking apart
	void RemoveHead( void );
	virtual void SetZombieModel( void ) { };
	virtual void BecomeTorso( const Vector &vecTorsoForce, const Vector &vecLegsForce );
	virtual bool CanBecomeLiveTorso() { return false; }
	virtual bool HeadcrabFits( CBaseAnimating *pCrab );
	void ReleaseHeadcrab( const Vector &vecOrigin, const Vector &vecVelocity, bool fRemoveHead, bool fRagdollBody, bool fRagdollCrab = false );
	void SetHeadcrabSpawnLocation( int iCrabAttachment, CBaseAnimating *pCrab );

	// Slumping/sleeping
	bool IsSlumped( void );
	bool IsGettingUp( void );

	// Swatting physics objects
	int GetSwatActivity( void );
	bool FindNearestPhysicsObject( int iMaxMass );
	float DistToPhysicsEnt( void );
	virtual bool CanSwatPhysicsObjects( void ) { return true; }

	// Returns whether we must be very near our enemy to attack them.
	virtual bool MustCloseToAttack(void) { return true; }

	virtual CBaseEntity *ClawAttack( float flDist, int iDamage, QAngle &qaViewPunch, Vector &vecVelocityPunch, int BloodOrigin );

	// Sounds & sound envelope
	virtual bool ShouldPlayFootstepMoan( void );
	virtual void PainSound( const CTakeDamageInfo &info ) = 0;
	virtual void AlertSound( void ) = 0;
	virtual void IdleSound( void ) = 0;
	virtual void AttackSound( void ) = 0;
	virtual void AttackHitSound( void ) = 0;
	virtual void AttackMissSound( void ) = 0;
	virtual void FootstepSound( bool fRightFoot ) = 0;
	virtual void FootscuffSound( bool fRightFoot ) = 0;

	// make a sound Alyx can hear when in darkness mode
	void		 MakeAISpookySound( float volume, float duration = 0.5 );

	virtual bool CanPlayMoanSound();
	virtual void MoanSound( envelopePoint_t *pEnvelope, int iEnvelopeSize );
	bool ShouldPlayIdleSound( void ) { return false; }

	virtual const char *GetMoanSound( int nSound ) = 0;
	virtual const char *GetHeadcrabClassname( void ) = 0;
	virtual const char *GetLegsModel( void ) = 0;
	virtual const char *GetTorsoModel( void ) = 0;
	virtual const char *GetHeadcrabModel( void ) = 0;

	virtual Vector BodyTarget( const Vector &posSrc, bool bNoisy );
	virtual Vector HeadTarget( const Vector &posSrc );
	virtual float  GetAutoAimRadius();
	virtual void TranslateNavGoal( CBaseEntity *pEnemy, Vector &chasePosition );

	bool OnInsufficientStopDist( AILocalMoveGoal_t *pMoveGoal, float distClear, AIMoveResult_t *pResult );

	virtual	bool		AllowedToIgnite( void ) { return true; }

public:
	CAI_ActBusyBehavior		m_ActBusyBehavior;



protected:

	CSoundPatch	*m_pMoanSound;

	bool	m_fIsTorso;			// is this is a half-zombie?
	bool	m_fIsHeadless;		// is this zombie headless

	float	m_flNextFlinch;

	bool m_bHeadShot;			// Used to determine the survival of our crab beyond our death.

	//
	// Zombies catch on fire if they take too much burn damage in a given time period.
	//
	float	m_flBurnDamage;				// Keeps track of how much burn damage we've incurred in the last few seconds.
	float	m_flBurnDamageResetTime;	// Time at which we reset the burn damage.

	EHANDLE m_hPhysicsEnt;

	float m_flNextMoanSound;
	float m_flNextSwat;
	float m_flNextSwatScan;
	float m_crabHealth;
	float m_flMoanPitch;

	EHANDLE	m_hObstructor;

	static int g_numZombies;	// counts total number of existing zombies.

	int m_iMoanSound; // each zombie picks one of the 4 and keeps it.

	static int ACT_ZOM_SWATLEFTMID;
	static int ACT_ZOM_SWATRIGHTMID;
	static int ACT_ZOM_SWATLEFTLOW;
	static int ACT_ZOM_SWATRIGHTLOW;
	static int ACT_ZOM_RELEASECRAB;
	static int ACT_ZOM_FALL;

	DECLARE_DATADESC();

	DEFINE_CUSTOM_AI;

private:
	bool m_bIsSlumped;

};

#endif // NPC_BASEZOMBIE_H