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
|