1 /*
2 EFFECTS.C
3
4 Copyright (C) 1991-2001 and beyond by Bungie Studios, Inc.
5 and the "Aleph One" developers.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (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 This license is contained in the file "COPYING",
18 which is included with this source code; it is available online at
19 http://www.gnu.org/licenses/gpl.html
20
21 Friday, May 27, 1994 10:40:13 AM
22
23 Saturday, May 28, 1994 2:13:08 AM
24 hopefully effects can be used for sparks. most effects disappear when their animations
25 terminate.
26 Friday, September 30, 1994 5:48:25 PM (Jason)
27 hopefully. ha. added sound-only effects.
28 Wednesday, February 1, 1995 12:58:17 AM (Jason')
29 teleporting item effects.
30
31 Feb 6, 2000 (Loren Petrich):
32 Added access to size of effect-definition structure
33
34 Aug 30, 2000 (Loren Petrich):
35 Added stuff for unpacking and packing
36 */
37
38 #include "cseries.h"
39 #include "map.h"
40 #include "interface.h"
41 #include "effects.h"
42 #include "SoundManager.h"
43 #include "lua_script.h"
44
45 #include "Packing.h"
46
47 /*
48 ryan reports get_object_data() failing on effect->data after a teleport effect terminates
49 */
50
51 /* ---------- macros */
52
53 /* ---------- structures */
54
55 /* ---------- private prototypes */
56
57 /* ---------- globals */
58
59 /* import effect definition constants, structures and globals */
60 #include "effect_definitions.h"
61
62 // Moved the definition over to map.cpp
63
64 // struct effect_data *effects = NULL;
65
66 static effect_definition *get_effect_definition(const short type);
67
68 /* ---------- code */
69
get_effect_data(const short effect_index)70 effect_data *get_effect_data(
71 const short effect_index)
72 {
73 struct effect_data *effect = GetMemberWithBounds(effects,effect_index,MAXIMUM_EFFECTS_PER_MAP);
74
75 vassert(effect, csprintf(temporary, "effect index #%d is out of range", effect_index));
76 vassert(SLOT_IS_USED(effect), csprintf(temporary, "effect index #%d (%p) is unused", effect_index, (void*)effect));
77
78 return effect;
79 }
80
81 // LP change: moved down here because it refers to effect definitions
get_effect_definition(const short type)82 effect_definition *get_effect_definition(const short type)
83 {
84 return GetMemberWithBounds(effect_definitions,type,NUMBER_OF_EFFECT_TYPES);
85 }
86
87
new_effect(world_point3d * origin,short polygon_index,short type,angle facing)88 short new_effect(
89 world_point3d *origin,
90 short polygon_index,
91 short type,
92 angle facing)
93 {
94 short effect_index= NONE;
95
96 if (polygon_index!=NONE)
97 {
98 struct effect_data *effect;
99 struct effect_definition *definition;
100
101 definition= get_effect_definition(type);
102 // LP change: idiot-proofing
103 if (!definition) return NONE;
104
105 if (definition->flags&_sound_only)
106 {
107 struct shape_animation_data *animation= get_shape_animation_data(BUILD_DESCRIPTOR(definition->collection, definition->shape));
108 if (!animation) return NONE;
109
110 play_world_sound(polygon_index, origin, animation->first_frame_sound);
111 }
112 else
113 {
114 for (effect_index= 0,effect= effects; effect_index<MAXIMUM_EFFECTS_PER_MAP; ++effect_index, ++effect)
115 {
116 if (SLOT_IS_FREE(effect))
117 {
118 short object_index= new_map_object3d(origin, polygon_index, BUILD_DESCRIPTOR(definition->collection, definition->shape), facing);
119
120 if (object_index!=NONE)
121 {
122 struct object_data *object= get_object_data(object_index);
123
124 effect->type= type;
125 effect->flags= 0;
126 effect->object_index= object_index;
127 effect->data= 0;
128 effect->delay= definition->delay ? global_random()%definition->delay : 0;
129 MARK_SLOT_AS_USED(effect);
130
131 SET_OBJECT_OWNER(object, _object_is_effect);
132 object->sound_pitch= definition->sound_pitch;
133 if (effect->delay) SET_OBJECT_INVISIBILITY(object, true);
134 if (definition->flags&_media_effect) SET_OBJECT_IS_MEDIA_EFFECT(object);
135 }
136 else
137 {
138 effect_index= NONE;
139 }
140
141 break;
142 }
143 }
144 if (effect_index==MAXIMUM_EFFECTS_PER_MAP) effect_index= NONE;
145 }
146 }
147
148 return effect_index;
149 }
150
151 /* assumes �t==1 tick */
update_effects(void)152 void update_effects(
153 void)
154 {
155 struct effect_data *effect;
156 short effect_index;
157
158 for (effect_index= 0, effect= effects; effect_index<MAXIMUM_EFFECTS_PER_MAP; ++effect_index, ++effect)
159 {
160 if (SLOT_IS_USED(effect))
161 {
162 struct object_data *object= get_object_data(effect->object_index);
163 struct effect_definition *definition= get_effect_definition(effect->type);
164 // LP change: idiot-proofing
165 if (!definition) continue;
166
167 if (effect->delay)
168 {
169 /* handle invisible, delayed effects */
170 if (!(effect->delay-= 1))
171 {
172 SET_OBJECT_INVISIBILITY(object, false);
173 play_object_sound(effect->object_index, definition->delay_sound);
174 }
175 }
176 else
177 {
178 /* update our object�s animation */
179 animate_object(effect->object_index);
180
181 /* if the effect�s animation has terminated and we�re supposed to deactive it, do so */
182 if (((GET_OBJECT_ANIMATION_FLAGS(object)&_obj_last_frame_animated)&&(definition->flags&_end_when_animation_loops)) ||
183 ((GET_OBJECT_ANIMATION_FLAGS(object)&_obj_transfer_mode_finished)&&(definition->flags&_end_when_transfer_animation_loops)))
184 {
185 remove_effect(effect_index);
186
187 /* if we�re supposed to make another item visible, do so */
188 if (definition->flags&_make_twin_visible)
189 {
190 struct object_data *object= get_object_data(effect->data);
191
192 SET_OBJECT_INVISIBILITY(object, false);
193 }
194 }
195 }
196 }
197 }
198 }
199
remove_effect(short effect_index)200 void remove_effect(
201 short effect_index)
202 {
203 struct effect_data *effect;
204
205 effect= get_effect_data(effect_index);
206 remove_map_object(effect->object_index);
207 L_Invalidate_Effect(effect_index);
208 MARK_SLOT_AS_FREE(effect);
209 }
210
remove_all_nonpersistent_effects(void)211 void remove_all_nonpersistent_effects(
212 void)
213 {
214 struct effect_data *effect;
215 short effect_index;
216
217 for (effect_index= 0, effect= effects; effect_index<MAXIMUM_EFFECTS_PER_MAP; ++effect_index, ++effect)
218 {
219 if (SLOT_IS_USED(effect))
220 {
221 struct effect_definition *definition= get_effect_definition(effect->type);
222 // LP change: idiot-proofing
223 if (!definition) continue;
224
225 if (definition->flags&(_end_when_animation_loops|_end_when_transfer_animation_loops))
226 {
227 remove_effect(effect_index);
228 }
229 }
230 }
231 }
232
mark_effect_collections(short effect_type,bool loading)233 void mark_effect_collections(
234 short effect_type,
235 bool loading)
236 {
237 if (effect_type!=NONE)
238 {
239 struct effect_definition *definition= get_effect_definition(effect_type);
240 // LP change: idiot-proofing
241 if (!definition) return;
242
243 /* mark the effect collection */
244 loading ? mark_collection_for_loading(definition->collection) : mark_collection_for_unloading(definition->collection);
245 }
246 }
247
teleport_object_out(short object_index)248 void teleport_object_out(
249 short object_index)
250 {
251 struct object_data *object= get_object_data(object_index);
252
253 if (!OBJECT_IS_INVISIBLE(object))
254 {
255 short effect_index= new_effect(&object->location, object->polygon, _effect_teleport_object_out, object->facing);
256
257 if (effect_index!=NONE)
258 {
259 struct effect_data *effect= get_effect_data(effect_index);
260 struct object_data *effect_object= get_object_data(effect->object_index);
261
262 // make the effect look like the object
263 effect_object->shape= object->shape;
264 effect_object->sequence= object->sequence;
265 effect_object->transfer_mode= _xfer_fold_out;
266 effect_object->transfer_period= TELEPORTING_MIDPOINT;
267 effect_object->transfer_phase= 0;
268 effect_object->flags|= object->flags&(_object_is_enlarged|_object_is_tiny);
269
270 // make the object invisible
271 SET_OBJECT_INVISIBILITY(object, true);
272
273 play_object_sound(effect->object_index, Sound_TeleportOut()); /* teleport in sound, at destination */
274 }
275 }
276 }
277
278 // if the given object isn�t already teleporting in, do so
teleport_object_in(short object_index)279 void teleport_object_in(
280 short object_index)
281 {
282 struct effect_data *effect;
283 short effect_index;
284
285 for (effect_index= 0, effect= effects; effect_index<MAXIMUM_EFFECTS_PER_MAP; ++effect_index, ++effect)
286 {
287 if (SLOT_IS_USED(effect))
288 {
289 if (effect->type==_effect_teleport_object_in && effect->data==object_index)
290 {
291 object_index= NONE;
292 break;
293 }
294 }
295 }
296
297 if (object_index!=NONE)
298 {
299 struct object_data *object= get_object_data(object_index);
300
301 effect_index= new_effect(&object->location, object->polygon, _effect_teleport_object_in, object->facing);
302 if (effect_index!=NONE)
303 {
304 struct object_data *effect_object;
305
306 effect= get_effect_data(effect_index);
307 effect->data= object_index;
308
309 effect_object= get_object_data(effect->object_index);
310 effect_object->shape= object->shape;
311 effect_object->transfer_mode= _xfer_fold_in;
312 effect_object->transfer_period= TELEPORTING_MIDPOINT;
313 effect_object->transfer_phase= 0;
314 effect_object->flags|= object->flags&(_object_is_enlarged|_object_is_tiny);
315 }
316 }
317 }
318
319
320 /* ---------- private code */
321
322
unpack_effect_data(uint8 * Stream,effect_data * Objects,size_t Count)323 uint8 *unpack_effect_data(uint8 *Stream, effect_data* Objects, size_t Count)
324 {
325 uint8* S = Stream;
326 effect_data* ObjPtr = Objects;
327
328 for (size_t k = 0; k < Count; k++, ObjPtr++)
329 {
330 StreamToValue(S,ObjPtr->type);
331 StreamToValue(S,ObjPtr->object_index);
332
333 StreamToValue(S,ObjPtr->flags);
334
335 StreamToValue(S,ObjPtr->data);
336 StreamToValue(S,ObjPtr->delay);
337
338 S += 11*2;
339 }
340
341 assert((S - Stream) == static_cast<ptrdiff_t>(Count*SIZEOF_effect_data));
342 return S;
343 }
344
pack_effect_data(uint8 * Stream,effect_data * Objects,size_t Count)345 uint8 *pack_effect_data(uint8 *Stream, effect_data* Objects, size_t Count)
346 {
347 uint8* S = Stream;
348 effect_data* ObjPtr = Objects;
349
350 for (size_t k = 0; k < Count; k++, ObjPtr++)
351 {
352 ValueToStream(S,ObjPtr->type);
353 ValueToStream(S,ObjPtr->object_index);
354
355 ValueToStream(S,ObjPtr->flags);
356
357 ValueToStream(S,ObjPtr->data);
358 ValueToStream(S,ObjPtr->delay);
359
360 S += 11*2;
361 }
362
363 assert((S - Stream) == static_cast<ptrdiff_t>(Count*SIZEOF_effect_data));
364 return S;
365 }
366
367
unpack_effect_definition(uint8 * Stream,size_t Count)368 uint8 *unpack_effect_definition(uint8 *Stream, size_t Count)
369 {
370 return unpack_effect_definition(Stream,effect_definitions,Count);
371 }
372
unpack_effect_definition(uint8 * Stream,effect_definition * Objects,size_t Count)373 uint8 *unpack_effect_definition(uint8 *Stream, effect_definition *Objects, size_t Count)
374 {
375 uint8* S = Stream;
376 effect_definition* ObjPtr = Objects;
377
378 for (size_t k = 0; k < Count; k++, ObjPtr++)
379 {
380 StreamToValue(S,ObjPtr->collection);
381 StreamToValue(S,ObjPtr->shape);
382
383 StreamToValue(S,ObjPtr->sound_pitch);
384
385 StreamToValue(S,ObjPtr->flags);
386 StreamToValue(S,ObjPtr->delay);
387 StreamToValue(S,ObjPtr->delay_sound);
388 }
389
390 assert((S - Stream) == static_cast<ptrdiff_t>(Count*SIZEOF_effect_definition));
391 return S;
392 }
393
unpack_m1_effect_definition(uint8 * Stream,size_t Count)394 uint8* unpack_m1_effect_definition(uint8* Stream, size_t Count)
395 {
396 uint8* S = Stream;
397 effect_definition* ObjPtr = effect_definitions;
398
399 for (size_t k = 0; k < Count; k++, ObjPtr++)
400 {
401 StreamToValue(S, ObjPtr->collection);
402 StreamToValue(S, ObjPtr->shape);
403 ObjPtr->sound_pitch = FIXED_ONE;
404 StreamToValue(S, ObjPtr->flags);
405 ObjPtr->delay = 0;
406 ObjPtr->delay_sound = NONE;
407 }
408
409 return S;
410 }
411
412
pack_effect_definition(uint8 * Stream,size_t Count)413 uint8 *pack_effect_definition(uint8 *Stream, size_t Count)
414 {
415 return pack_effect_definition(Stream,effect_definitions,Count);
416 }
417
pack_effect_definition(uint8 * Stream,effect_definition * Objects,size_t Count)418 uint8 *pack_effect_definition(uint8 *Stream, effect_definition *Objects, size_t Count)
419 {
420 uint8* S = Stream;
421 effect_definition* ObjPtr = Objects;
422
423 for (size_t k = 0; k < Count; k++, ObjPtr++)
424 {
425 ValueToStream(S,ObjPtr->collection);
426 ValueToStream(S,ObjPtr->shape);
427
428 ValueToStream(S,ObjPtr->sound_pitch);
429
430 ValueToStream(S,ObjPtr->flags);
431 ValueToStream(S,ObjPtr->delay);
432 ValueToStream(S,ObjPtr->delay_sound);
433 }
434
435 assert((S - Stream) == static_cast<ptrdiff_t>(Count*SIZEOF_effect_definition));
436 return S;
437 }
438
init_effect_definitions()439 void init_effect_definitions()
440 {
441 memcpy(effect_definitions, original_effect_definitions, sizeof(effect_definitions));
442 }
443