aboutsummaryrefslogtreecommitdiff
path: root/sp/src/game/server/soundent.h
blob: 4de733f4340185c76aa13c8dc9ac975c081c6297 (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
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: 
//
// $NoKeywords: $
//
//=============================================================================//
// Soundent.h - the entity that spawns when the world 
// spawns, and handles the world's active and free sound
// lists.

#ifndef SOUNDENT_H
#define SOUNDENT_H

#ifdef _WIN32
#pragma once
#endif

enum
{
	MAX_WORLD_SOUNDS_SP	= 64,	// Maximum number of sounds handled by the world at one time in single player.
	// This is also the number of entries saved in a savegame file (for b/w compatibility).

	MAX_WORLD_SOUNDS_MP	= 128	// The sound array size is set this large but we'll only use gpGlobals->maxPlayers+32 entries in mp.
};

enum
{
	SOUND_NONE				= 0,
	SOUND_COMBAT			= 0x00000001,
	SOUND_WORLD				= 0x00000002,
	SOUND_PLAYER			= 0x00000004,
	SOUND_DANGER			= 0x00000008,
	SOUND_BULLET_IMPACT		= 0x00000010,
	SOUND_CARCASS			= 0x00000020,
	SOUND_MEAT				= 0x00000040,
	SOUND_GARBAGE			= 0x00000080,
	SOUND_THUMPER			= 0x00000100, // keeps certain creatures at bay
	SOUND_BUGBAIT			= 0x00000200, // gets the antlion's attention
	SOUND_PHYSICS_DANGER	= 0x00000400,
	SOUND_DANGER_SNIPERONLY	= 0x00000800, // only scares the sniper NPC.
	SOUND_MOVE_AWAY			= 0x00001000,
	SOUND_PLAYER_VEHICLE	= 0x00002000,
	SOUND_READINESS_LOW		= 0x00004000, // Changes listener's readiness (Player Companion only)
	SOUND_READINESS_MEDIUM	= 0x00008000,
	SOUND_READINESS_HIGH	= 0x00010000,

	// Contexts begin here.
	SOUND_CONTEXT_FROM_SNIPER		= 0x00100000, // additional context for SOUND_DANGER
	SOUND_CONTEXT_GUNFIRE			= 0x00200000, // Added to SOUND_COMBAT
	SOUND_CONTEXT_MORTAR			= 0x00400000, // Explosion going to happen here.
	SOUND_CONTEXT_COMBINE_ONLY		= 0x00800000, // Only combine can hear sounds marked this way
	SOUND_CONTEXT_REACT_TO_SOURCE	= 0x01000000, // React to sound source's origin, not sound's location
	SOUND_CONTEXT_EXPLOSION			= 0x02000000, // Context added to SOUND_COMBAT, usually.
	SOUND_CONTEXT_EXCLUDE_COMBINE	= 0x04000000, // Combine do NOT hear this
	SOUND_CONTEXT_DANGER_APPROACH   = 0x08000000, // Treat as a normal danger sound if you see the source, otherwise turn to face source.
	SOUND_CONTEXT_ALLIES_ONLY		= 0x10000000, // Only player allies can hear this sound
	SOUND_CONTEXT_PLAYER_VEHICLE	= 0x20000000, // HACK: need this because we're not treating the SOUND_xxx values as true bit values! See switch in OnListened.

	ALL_CONTEXTS			= 0xFFF00000,

	ALL_SCENTS				= SOUND_CARCASS | SOUND_MEAT | SOUND_GARBAGE,

	ALL_SOUNDS				= 0x000FFFFF & ~ALL_SCENTS,

};

// Make as many of these as you want. 
enum
{
	SOUNDENT_CHANNEL_UNSPECIFIED = 0,
	SOUNDENT_CHANNEL_REPEATING,
	SOUNDENT_CHANNEL_REPEATED_DANGER,	// for things that make danger sounds frequently.
	SOUNDENT_CHANNEL_REPEATED_PHYSICS_DANGER,
	SOUNDENT_CHANNEL_WEAPON,
	SOUNDENT_CHANNEL_INJURY,
	SOUNDENT_CHANNEL_BULLET_IMPACT,
	SOUNDENT_CHANNEL_NPC_FOOTSTEP,
	SOUNDENT_CHANNEL_SPOOKY_NOISE,		// made by zombies in darkness
	SOUNDENT_CHANNEL_ZOMBINE_GRENADE,
};

enum
{
	SOUNDLIST_EMPTY = -1
};

#define SOUNDENT_VOLUME_MACHINEGUN	1500.0
#define SOUNDENT_VOLUME_SHOTGUN		1500.0
#define SOUNDENT_VOLUME_PISTOL		1500.0
#define SOUNDENT_VOLUME_EMPTY		 500.0 // volume of the "CLICK" when you have no bullets

enum
{
	SOUND_PRIORITY_VERY_LOW = -2,
	SOUND_PRIORITY_LOW,
	SOUND_PRIORITY_NORMAL = 0,
	SOUND_PRIORITY_HIGH,
	SOUND_PRIORITY_VERY_HIGH,
	SOUND_PRIORITY_HIGHEST,
};

//=========================================================
// CSound - an instance of a sound in the world.
//=========================================================
class CSound
{
	DECLARE_SIMPLE_DATADESC();

public:
	bool	DoesSoundExpire() const;
	float	SoundExpirationTime() const;
	void	SetSoundOrigin( const Vector &vecOrigin ) { m_vecOrigin = vecOrigin; }
	const	Vector& GetSoundOrigin( void ) { return m_vecOrigin; }
	const	Vector& GetSoundReactOrigin( void );
	bool	FIsSound( void );
	bool	FIsScent( void );
	bool	IsSoundType( int nSoundFlags ) const;
	int		SoundType( ) const;
	int		SoundContext() const;
	int		SoundTypeNoContext( ) const;
	int		Volume( ) const;
	float	OccludedVolume() { return m_iVolume * m_flOcclusionScale; }
	int		NextSound() const;
	void	Reset ( void );
	int		SoundChannel( void ) const;
	bool	ValidateOwner() const;

	EHANDLE	m_hOwner;				// sound's owner
	EHANDLE	m_hTarget;				// Sounds's target - an odd concept. For a gunfire sound, the target is the entity being fired at
	int		m_iVolume;				// how loud the sound is
	float	m_flOcclusionScale;		// How loud the sound is when occluded by the world. (volume * occlusionscale)
	int		m_iType;				// what type of sound this is
	int		m_iNextAudible;			// temporary link that NPCs use to build a list of audible sounds

private:
	void	Clear ( void );

	float	m_flExpireTime;	// when the sound should be purged from the list
	short	m_iNext;		// index of next sound in this list ( Active or Free )
	bool	m_bNoExpirationTime;
	int		m_ownerChannelIndex;

	Vector	m_vecOrigin;	// sound's location in space

	bool	m_bHasOwner;	// Lets us know if this sound was created with an owner. In case the owner goes null.

#ifdef DEBUG
	int		m_iMyIndex;		// debugging
#endif

	friend class CSoundEnt;
};

inline bool CSound::DoesSoundExpire() const
{
	return m_bNoExpirationTime == false;
}

inline float CSound::SoundExpirationTime() const
{
	return m_bNoExpirationTime ? FLT_MAX : m_flExpireTime;
}

inline bool CSound::IsSoundType( int nSoundFlags ) const
{
	return (m_iType & nSoundFlags) != 0;
}

inline int CSound::SoundType( ) const
{
	return m_iType;
}

inline int CSound::SoundContext( ) const
{
	return m_iType & ALL_CONTEXTS;
}

inline int CSound::SoundTypeNoContext( ) const
{
	return m_iType & ~ALL_CONTEXTS;
}

inline int CSound::Volume( ) const
{
	return m_iVolume;
}

inline int CSound::NextSound() const
{
	return m_iNext;
}

inline int CSound::SoundChannel( void ) const
{
	return m_ownerChannelIndex;
}

// The owner is considered valid if:
//		-The sound never had an assigned owner (quite common)
//		-The sound was assigned an owner and that owner still exists
inline bool CSound::ValidateOwner( void ) const
{
	return ( !m_bHasOwner || (m_hOwner.Get() != NULL) );
}

//=========================================================
// CSoundEnt - a single instance of this entity spawns when
// the world spawns. The SoundEnt's job is to update the 
// world's Free and Active sound lists.
//=========================================================
class CSoundEnt : public CPointEntity
{
	DECLARE_DATADESC();

public:
	DECLARE_CLASS( CSoundEnt, CPointEntity );

	// Construction, destruction
	static bool InitSoundEnt();
	static void ShutdownSoundEnt();

	CSoundEnt();
	virtual ~CSoundEnt();

	virtual void OnRestore();
	void Precache ( void );
	void Spawn( void );
	void Think( void );
	void Initialize ( void );
	int ObjectCaps( void ) { return BaseClass::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; }

	static void		InsertSound ( int iType, const Vector &vecOrigin, int iVolume, float flDuration, CBaseEntity *pOwner = NULL, int soundChannelIndex = SOUNDENT_CHANNEL_UNSPECIFIED, CBaseEntity *pSoundTarget = NULL );
	static void		FreeSound ( int iSound, int iPrevious );
	static int		ActiveList( void );// return the head of the active list
	static int		FreeList( void );// return the head of the free list
	static CSound*	SoundPointerForIndex( int iIndex );// return a pointer for this index in the sound list
	static CSound*	GetLoudestSoundOfType( int iType, const Vector &vecEarPosition );
	static int		ClientSoundIndex ( edict_t *pClient );

	bool	IsEmpty( void );
	int		ISoundsInList ( int iListType );
	int		IAllocSound ( void );
	int		FindOrAllocateSound( CBaseEntity *pOwner, int soundChannelIndex );
	
private:
	int		m_iFreeSound;	// index of the first sound in the free sound list
	int		m_iActiveSound; // indes of the first sound in the active sound list
	int		m_cLastActiveSounds; // keeps track of the number of active sounds at the last update. (for diagnostic work)
	CSound	m_SoundPool[ MAX_WORLD_SOUNDS_MP ];
};


//-----------------------------------------------------------------------------
// Inline methods
//-----------------------------------------------------------------------------
inline bool CSoundEnt::IsEmpty( void ) 
{ 
	return m_iActiveSound == SOUNDLIST_EMPTY; 
}


#endif //SOUNDENT_H