1 //----------------------------------------------------------------------------
2 // EDGE Data Definition File Code (Sounds)
3 //----------------------------------------------------------------------------
4 //
5 // Copyright (c) 1999-2008 The EDGE Team.
6 //
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License
9 // as published by the Free Software Foundation; either version 2
10 // of the License, or (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
16 //
17 //----------------------------------------------------------------------------
18 //
19 // -KM- 1998/09/27 Finished :-)
20 //
21
22 #include "local.h"
23
24 #include "sfx.h"
25
26 static sfxdef_c *dynamic_sfx;
27
28 sfxdef_container_c sfxdefs;
29
30 #define DDF_CMD_BASE dummy_sfx
31 static sfxdef_c dummy_sfx;
32
33 static const commandlist_t sfx_commands[] =
34 {
35 DDF_FIELD("LUMP_NAME", lump_name, DDF_MainGetLumpName),
36 DDF_FIELD("FILE_NAME", file_name, DDF_MainGetString),
37 DDF_FIELD("SINGULAR", singularity, DDF_MainGetNumeric),
38 DDF_FIELD("PRIORITY", priority, DDF_MainGetNumeric),
39 DDF_FIELD("VOLUME", volume, DDF_MainGetPercent),
40 DDF_FIELD("LOOP", looping, DDF_MainGetBoolean),
41 DDF_FIELD("PRECIOUS", precious, DDF_MainGetBoolean),
42 DDF_FIELD("MAX_DISTANCE", max_distance, DDF_MainGetFloat),
43
44 DDF_CMD_END
45 };
46
47
48 //
49 // DDF PARSE ROUTINES
50 //
51
SoundStartEntry(const char * name,bool extend)52 static void SoundStartEntry(const char *name, bool extend)
53 {
54 if (!name || !name[0])
55 {
56 DDF_WarnError("New sound entry is missing a name!");
57 name = "SOUND_WITH_NO_NAME";
58 }
59
60 dynamic_sfx = sfxdefs.Lookup(name);
61
62 if (extend)
63 {
64 if (! dynamic_sfx)
65 DDF_Error("Unknown sound to extend: %s\n", name);
66 return;
67 }
68
69 // replaces an existing entry?
70 if (dynamic_sfx)
71 {
72 // maintain the internal ID
73 int id = dynamic_sfx->normal.sounds[0];
74
75 dynamic_sfx->Default();
76
77 dynamic_sfx->normal.num = 1;
78 dynamic_sfx->normal.sounds[0] = id;
79 return;
80 }
81
82 // not found, create a new one
83 dynamic_sfx = new sfxdef_c;
84
85 dynamic_sfx->name = name;
86
87 sfxdefs.Insert(dynamic_sfx);
88
89 // give it a self-referencing ID number
90 dynamic_sfx->normal.sounds[0] = sfxdefs.GetSize()-1;
91 dynamic_sfx->normal.num = 1;
92 }
93
94
SoundParseField(const char * field,const char * contents,int index,bool is_last)95 static void SoundParseField(const char *field, const char *contents,
96 int index, bool is_last)
97 {
98 #if (DEBUG_DDF)
99 I_Debugf("SOUND_PARSE: %s = %s;\n", field, contents);
100 #endif
101
102 // -AJA- ignore these for backwards compatibility
103 if (DDF_CompareName(field, "BITS") == 0 ||
104 DDF_CompareName(field, "STEREO") == 0)
105 return;
106
107 if (DDF_MainParseField(sfx_commands, field, contents, (byte *)dynamic_sfx))
108 return; // OK
109
110 DDF_WarnError("Unknown sounds.ddf command: %s\n", field);
111 }
112
113
SoundFinishEntry(void)114 static void SoundFinishEntry(void)
115 {
116 if (!dynamic_sfx->lump_name[0] &&
117 !(dynamic_sfx->file_name && dynamic_sfx->file_name[0]))
118 {
119 DDF_Error("Missing LUMP_NAME or FILE_NAME for sound.\n");
120 }
121 }
122
123
SoundClearAll(void)124 static void SoundClearAll(void)
125 {
126 I_Warning("Ignoring #CLEARALL in sounds.ddf\n");
127 }
128
129
DDF_ReadSFX(void * data,int size)130 bool DDF_ReadSFX(void *data, int size)
131 {
132 readinfo_t sfx_r;
133
134 sfx_r.memfile = (char*)data;
135 sfx_r.memsize = size;
136 sfx_r.tag = "SOUNDS";
137 sfx_r.entries_per_dot = 8;
138
139 if (sfx_r.memfile)
140 {
141 sfx_r.message = NULL;
142 sfx_r.filename = NULL;
143 sfx_r.lumpname = "DDFSFX";
144 }
145 else
146 {
147 sfx_r.message = "DDF_InitSounds";
148 sfx_r.filename = "sounds.ddf";
149 sfx_r.lumpname = NULL;
150 }
151
152 sfx_r.start_entry = SoundStartEntry;
153 sfx_r.parse_field = SoundParseField;
154 sfx_r.finish_entry = SoundFinishEntry;
155 sfx_r.clear_all = SoundClearAll;
156
157 return DDF_MainReadFile(&sfx_r);
158 }
159
DDF_SFXInit(void)160 void DDF_SFXInit(void)
161 {
162 sfxdefs.Clear();
163 }
164
DDF_SFXCleanUp(void)165 void DDF_SFXCleanUp(void)
166 {
167 sfxdefs.Trim();
168 }
169
170 //
171 // DDF_MainLookupSound
172 //
173 // Lookup the sound specified.
174 //
175 // -ACB- 1998/07/08 Checked the S_sfx table for sfx names.
176 // -ACB- 1998/07/18 Removed to the need set *currentcmdlist[commandref].data to -1
177 // -KM- 1998/09/27 Fixed this func because of sounds.ddf
178 // -KM- 1998/10/29 sfx_t finished
179 //
DDF_MainLookupSound(const char * info,void * storage)180 void DDF_MainLookupSound(const char *info, void *storage)
181 {
182 sfx_t **dest = (sfx_t **)storage;
183
184 SYS_ASSERT(info && storage);
185
186 *dest = sfxdefs.GetEffect(info);
187 }
188
189 // --> Sound Effect Definition Class
190
191 //
192 // sfxdef_c Constructor
193 //
sfxdef_c()194 sfxdef_c::sfxdef_c() : name()
195 {
196 Default();
197 }
198
199 //
200 // sfxdef_c Destructor
201 //
~sfxdef_c()202 sfxdef_c::~sfxdef_c()
203 {
204 }
205
206 //
207 // sfxdef_c::CopyDetail()
208 //
CopyDetail(sfxdef_c & src)209 void sfxdef_c::CopyDetail(sfxdef_c &src)
210 {
211 lump_name = src.lump_name;
212 file_name = src.file_name;
213
214 // clear the internal sfx_t (ID would be wrong)
215 normal.sounds[0] = 0;
216 normal.num = 0;
217
218 singularity = src.singularity; // singularity
219 priority = src.priority; // priority (lower is more important)
220 volume = src.volume; // volume
221 looping = src.looping; // looping
222 precious = src.precious; // precious
223 max_distance = src.max_distance; // max_distance
224 }
225
226 //
227 // sfxdef_c::Default()
228 //
Default()229 void sfxdef_c::Default()
230 {
231 lump_name.clear();
232 file_name.clear();
233
234 normal.sounds[0] = 0;
235 normal.num = 0;
236
237 singularity = 0; // singularity
238 priority = 999; // priority (lower is more important)
239 volume = PERCENT_MAKE(100); // volume
240 looping = false; // looping
241 precious = false; // precious
242 max_distance = S_CLIPPING_DIST; // max_distance
243 }
244
245
246 // --> Sound Effect Definition Containter Class
247
248 //
249 // sfxdef_container_c::CleanupObject()
250 //
CleanupObject(void * obj)251 void sfxdef_container_c::CleanupObject(void *obj)
252 {
253 sfxdef_c *s = *(sfxdef_c**)obj;
254
255 if (s)
256 delete s;
257
258 return;
259 }
260
strncasecmpwild(const char * s1,const char * s2,int n)261 static int strncasecmpwild(const char *s1, const char *s2, int n)
262 {
263 int i = 0;
264
265 for (i = 0; s1[i] && s2[i] && i < n; i++)
266 {
267 if ((toupper(s1[i]) != toupper(s2[i])) && (s1[i] != '?') && (s2[i] != '?'))
268 break;
269 }
270 // -KM- 1999/01/29 If strings are equal return equal.
271 if (i == n)
272 return 0;
273
274 if (s1[i] == '?' || s2[i] == '?')
275 return 0;
276
277 return s1[i] - s2[i];
278 }
279
280
281 //
282 // sfxdef_container_c::GetEffect()
283 //
284 // FIXME!! Remove error param hack
285 // FIXME!! Cache results for those we create
286 //
GetEffect(const char * name,bool error)287 sfx_t* sfxdef_container_c::GetEffect(const char *name, bool error)
288 {
289 epi::array_iterator_c it, last;
290 int count;
291
292 sfxdef_c *si;
293 sfx_t *r;
294
295 // NULL Sound
296 if (!name || !name[0] || DDF_CompareName(name, "NULL")==0)
297 return NULL;
298
299 // count them
300 for (count=0, it=GetTailIterator();
301 it.IsValid() && it.GetPos() >= 0;
302 it--)
303 {
304 si = ITERATOR_TO_TYPE(it, sfxdef_c*);
305
306 if (strncasecmpwild(name, si->name.c_str(), 8) == 0)
307 {
308 count++;
309 last = it;
310 }
311 }
312
313 if (count == 0)
314 {
315 if (error)
316 DDF_WarnError("Unknown SFX: '%.8s'\n", name);
317
318 return NULL;
319 }
320
321 // -AJA- optimisation to save some memory
322 if (count == 1)
323 {
324 si = ITERATOR_TO_TYPE(last, sfxdef_c*);
325 r = &si->normal;
326
327 SYS_ASSERT(r->num == 1);
328
329 return r;
330 }
331
332 //
333 // allocate elements. Uses (count-1) since sfx_t already includes
334 // the first integer.
335 //
336 r = (sfx_t*) new byte[sizeof(sfx_t) + ((count-1) * sizeof(int))];
337
338 // now store them
339 for (r->num=0, it=GetTailIterator();
340 it.IsValid() && it.GetPos() >= 0;
341 it--)
342 {
343 si = ITERATOR_TO_TYPE(it, sfxdef_c*);
344
345 if (strncasecmpwild(name, si->name.c_str(), 8) == 0)
346 r->sounds[r->num++] = it.GetPos();
347 }
348
349 SYS_ASSERT(r->num == count);
350
351 return r;
352 }
353
354 //
355 // sfxdef_container_c::Lookup()
356 //
Lookup(const char * name)357 sfxdef_c* sfxdef_container_c::Lookup(const char *name)
358 {
359 epi::array_iterator_c it;
360
361 for (it=GetIterator(0); it.IsValid(); it++)
362 {
363 sfxdef_c *s = ITERATOR_TO_TYPE(it, sfxdef_c*);
364
365 if (DDF_CompareName(s->name.c_str(), name) == 0)
366 return s;
367 }
368
369 return NULL;
370 }
371
372 //--- editor settings ---
373 // vi:ts=4:sw=4:noexpandtab
374