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