1 /*
2 ===========================================================================
3
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
6
7 This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code").
8
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
21
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
23
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25
26 ===========================================================================
27 */
28
29 #include "sys/platform.h"
30 #include "Entity.h"
31
32 #include "Sound.h"
33
34 /*
35 ===============================================================================
36
37 SOUND
38
39 ===============================================================================
40 */
41
42 const idEventDef EV_Speaker_On( "On", NULL );
43 const idEventDef EV_Speaker_Off( "Off", NULL );
44 const idEventDef EV_Speaker_Timer( "<timer>", NULL );
45
CLASS_DECLARATION(idEntity,idSound)46 CLASS_DECLARATION( idEntity, idSound )
47 EVENT( EV_Activate, idSound::Event_Trigger )
48 EVENT( EV_Speaker_On, idSound::Event_On )
49 EVENT( EV_Speaker_Off, idSound::Event_Off )
50 EVENT( EV_Speaker_Timer, idSound::Event_Timer )
51 END_CLASS
52
53
54 /*
55 ================
56 idSound::idSound
57 ================
58 */
59 idSound::idSound( void ) {
60 lastSoundVol = 0.0f;
61 soundVol = 0.0f;
62 shakeTranslate.Zero();
63 shakeRotate.Zero();
64 random = 0.0f;
65 wait = 0.0f;
66 timerOn = false;
67 playingUntilTime = 0;
68 }
69
70 /*
71 ================
72 idSound::Save
73 ================
74 */
Save(idSaveGame * savefile) const75 void idSound::Save( idSaveGame *savefile ) const {
76 savefile->WriteFloat( lastSoundVol );
77 savefile->WriteFloat( soundVol );
78 savefile->WriteFloat( random );
79 savefile->WriteFloat( wait );
80 savefile->WriteBool( timerOn );
81 savefile->WriteVec3( shakeTranslate );
82 savefile->WriteAngles( shakeRotate );
83 savefile->WriteInt( playingUntilTime );
84 }
85
86 /*
87 ================
88 idSound::Restore
89 ================
90 */
Restore(idRestoreGame * savefile)91 void idSound::Restore( idRestoreGame *savefile ) {
92 savefile->ReadFloat( lastSoundVol );
93 savefile->ReadFloat( soundVol );
94 savefile->ReadFloat( random );
95 savefile->ReadFloat( wait );
96 savefile->ReadBool( timerOn );
97 savefile->ReadVec3( shakeTranslate );
98 savefile->ReadAngles( shakeRotate );
99 savefile->ReadInt( playingUntilTime );
100 }
101
102 /*
103 ================
104 idSound::Spawn
105 ================
106 */
Spawn(void)107 void idSound::Spawn( void ) {
108 spawnArgs.GetVector( "move", "0 0 0", shakeTranslate );
109 spawnArgs.GetAngles( "rotate", "0 0 0", shakeRotate );
110 spawnArgs.GetFloat( "random", "0", random );
111 spawnArgs.GetFloat( "wait", "0", wait );
112
113 if ( ( wait > 0.0f ) && ( random >= wait ) ) {
114 random = wait - 0.001;
115 gameLocal.Warning( "speaker '%s' at (%s) has random >= wait", name.c_str(), GetPhysics()->GetOrigin().ToString(0) );
116 }
117
118 soundVol = 0.0f;
119 lastSoundVol = 0.0f;
120
121 if ( ( shakeRotate != ang_zero ) || ( shakeTranslate != vec3_zero ) ) {
122 BecomeActive( TH_THINK );
123 }
124
125 if ( !refSound.waitfortrigger && ( wait > 0.0f ) ) {
126 timerOn = true;
127 PostEventSec( &EV_Speaker_Timer, wait + gameLocal.random.CRandomFloat() * random );
128 } else {
129 timerOn = false;
130 }
131 }
132
133 /*
134 ================
135 idSound::Event_Trigger
136
137 this will toggle the idle idSound on and off
138 ================
139 */
Event_Trigger(idEntity * activator)140 void idSound::Event_Trigger( idEntity *activator ) {
141 if ( wait > 0.0f ) {
142 if ( timerOn ) {
143 timerOn = false;
144 CancelEvents( &EV_Speaker_Timer );
145 } else {
146 timerOn = true;
147 DoSound( true );
148 PostEventSec( &EV_Speaker_Timer, wait + gameLocal.random.CRandomFloat() * random );
149 }
150 } else {
151 if ( gameLocal.isMultiplayer ) {
152 if ( refSound.referenceSound && ( gameLocal.time < playingUntilTime ) ) {
153 DoSound( false );
154 } else {
155 DoSound( true );
156 }
157 } else {
158 if ( refSound.referenceSound && refSound.referenceSound->CurrentlyPlaying() ) {
159 DoSound( false );
160 } else {
161 DoSound( true );
162 }
163 }
164 }
165 }
166
167 /*
168 ================
169 idSound::Event_Timer
170 ================
171 */
Event_Timer(void)172 void idSound::Event_Timer( void ) {
173 DoSound( true );
174 PostEventSec( &EV_Speaker_Timer, wait + gameLocal.random.CRandomFloat() * random );
175 }
176
177 /*
178 ================
179 idSound::Think
180 ================
181 */
Think(void)182 void idSound::Think( void ) {
183 idAngles ang;
184
185 // run physics
186 RunPhysics();
187
188 // clear out our update visuals think flag since we never call Present
189 BecomeInactive( TH_UPDATEVISUALS );
190 }
191
192 /*
193 ===============
194 idSound::UpdateChangableSpawnArgs
195 ===============
196 */
UpdateChangeableSpawnArgs(const idDict * source)197 void idSound::UpdateChangeableSpawnArgs( const idDict *source ) {
198
199 idEntity::UpdateChangeableSpawnArgs( source );
200
201 if ( source ) {
202 FreeSoundEmitter( true );
203 spawnArgs.Copy( *source );
204 idSoundEmitter *saveRef = refSound.referenceSound;
205 gameEdit->ParseSpawnArgsToRefSound( &spawnArgs, &refSound );
206 refSound.referenceSound = saveRef;
207
208 idVec3 origin;
209 idMat3 axis;
210
211 if ( GetPhysicsToSoundTransform( origin, axis ) ) {
212 refSound.origin = GetPhysics()->GetOrigin() + origin * axis;
213 } else {
214 refSound.origin = GetPhysics()->GetOrigin();
215 }
216
217 spawnArgs.GetFloat( "random", "0", random );
218 spawnArgs.GetFloat( "wait", "0", wait );
219
220 if ( ( wait > 0.0f ) && ( random >= wait ) ) {
221 random = wait - 0.001;
222 gameLocal.Warning( "speaker '%s' at (%s) has random >= wait", name.c_str(), GetPhysics()->GetOrigin().ToString(0) );
223 }
224
225 if ( !refSound.waitfortrigger && ( wait > 0.0f ) ) {
226 timerOn = true;
227 DoSound( false );
228 CancelEvents( &EV_Speaker_Timer );
229 PostEventSec( &EV_Speaker_Timer, wait + gameLocal.random.CRandomFloat() * random );
230 } else if ( !refSound.waitfortrigger && !(refSound.referenceSound && refSound.referenceSound->CurrentlyPlaying() ) ) {
231 // start it if it isn't already playing, and we aren't waitForTrigger
232 DoSound( true );
233 timerOn = false;
234 }
235 }
236 }
237
238 /*
239 ===============
240 idSound::SetSound
241 ===============
242 */
SetSound(const char * sound,int channel)243 void idSound::SetSound( const char *sound, int channel ) {
244 const idSoundShader *shader = declManager->FindSound( sound );
245 if ( shader != refSound.shader ) {
246 FreeSoundEmitter( true );
247 }
248 gameEdit->ParseSpawnArgsToRefSound(&spawnArgs, &refSound);
249 refSound.shader = shader;
250 // start it if it isn't already playing, and we aren't waitForTrigger
251 if ( !refSound.waitfortrigger && !(refSound.referenceSound && refSound.referenceSound->CurrentlyPlaying() ) ) {
252 DoSound( true );
253 }
254 }
255
256 /*
257 ================
258 idSound::DoSound
259 ================
260 */
DoSound(bool play)261 void idSound::DoSound( bool play ) {
262 if ( play ) {
263 StartSoundShader( refSound.shader, SND_CHANNEL_ANY, refSound.parms.soundShaderFlags, true, &playingUntilTime );
264 playingUntilTime += gameLocal.time;
265 } else {
266 StopSound( SND_CHANNEL_ANY, true );
267 playingUntilTime = 0;
268 }
269 }
270
271 /*
272 ================
273 idSound::Event_On
274 ================
275 */
Event_On(void)276 void idSound::Event_On( void ) {
277 if ( wait > 0.0f ) {
278 timerOn = true;
279 PostEventSec( &EV_Speaker_Timer, wait + gameLocal.random.CRandomFloat() * random );
280 }
281 DoSound( true );
282 }
283
284 /*
285 ================
286 idSound::Event_Off
287 ================
288 */
Event_Off(void)289 void idSound::Event_Off( void ) {
290 if ( timerOn ) {
291 timerOn = false;
292 CancelEvents( &EV_Speaker_Timer );
293 }
294 DoSound( false );
295 }
296
297 /*
298 ===============
299 idSound::ShowEditingDialog
300 ===============
301 */
ShowEditingDialog(void)302 void idSound::ShowEditingDialog( void ) {
303 common->InitTool( EDITOR_SOUND, &spawnArgs );
304 }
305