2 * $Logfile: /Freespace2/code/Weapon/Shockwave.cpp $
7 * C file for creating and managing shockwaves
10 * Revision 1.2 2002/05/07 03:16:53 theoddone33
11 * The Great Newline Fix
13 * Revision 1.1.1.1 2002/05/03 03:28:11 root
17 * 7 9/01/99 10:15a Dave
19 * 6 7/18/99 12:32p Dave
20 * Randomly oriented shockwaves.
22 * 5 3/23/99 2:29p Andsager
23 * Fix shockwaves for kamikazi and Fred defined. Collect together
24 * shockwave_create_info struct.
26 * 4 2/26/99 4:14p Dave
27 * Put in the ability to have multiple shockwaves for ships.
29 * 3 11/05/98 5:55p Dave
30 * Big pass at reducing #includes
32 * 2 10/07/98 10:54a Dave
35 * 1 10/07/98 10:51a Dave
37 * 49 5/18/98 3:04p Lawrance
38 * Play shockwave impact sound
40 * 48 5/18/98 12:59a Lawrance
41 * Replace shockwave impact sound with a new "whoosh" sound that
42 * originates from the shockwave center
44 * 47 4/15/98 10:17p Mike
45 * Training mission #5.
46 * Fix application of subsystem damage.
48 * 46 4/09/98 7:58p John
49 * Cleaned up tmapper code a bit. Put NDEBUG around some ndebug stuff.
50 * Took out XPARENT flag settings in all the alpha-blended texture stuff.
52 * 45 3/31/98 5:19p John
53 * Removed demo/save/restore. Made NDEBUG defined compile. Removed a
54 * bunch of debug stuff out of player file. Made model code be able to
55 * unload models and malloc out only however many models are needed.
58 * 44 3/30/98 4:02p John
59 * Made machines with < 32 MB of RAM use every other frame of certain
60 * bitmaps. Put in code to keep track of how much RAM we've malloc'd.
62 * 43 3/26/98 5:26p John
63 * added new paging code. nonfunctional.
65 * 42 3/04/98 4:11p Lawrance
66 * Have area effects affect asteroids, have asteroids cast an area effect,
69 * 41 2/26/98 10:08p Hoffoss
70 * Rewrote state saving and restoring to fix bugs and simplify the code.
72 * 40 2/22/98 12:19p John
73 * Externalized some strings
75 * 39 2/20/98 8:32p Lawrance
76 * Make shockwaves affect subsystems more realistically.
78 * 38 2/16/98 11:26a Lawrance
79 * ensure shockwave lasts full duration
81 * 37 2/16/98 10:04a Lawrance
82 * Fix broken shockwave damage.
84 * 36 2/14/98 4:42p Lawrance
85 * pass shockwave object (not parent) to ship_apply_global_damage()
87 * 35 2/12/98 11:54p Lawrance
88 * restructure rendering code to use an animation
90 * 34 2/11/98 5:38p Dave
91 * Put in a global inited flag for shockwaves.
93 * 33 2/02/98 8:47a Andsager
94 * Ship death area damage applied as instantaneous damage for small ships
95 * and shockwaves for large (>50 radius) ships.
97 * 32 1/26/98 11:54a Lawrance
98 * Don't allow Navbuoys to be affected by area-effect damage and blasts.
100 * 31 1/22/98 11:43p Lawrance
101 * Play sound effect when player is hit by shockwave.
103 * 30 1/14/98 4:31p Dave
104 * Made shockwaves apply damage correctly.
106 * 29 1/14/98 2:59p Allender
107 * if shockwave came from a weapon, make the shockwave's parent be the
110 * 28 12/30/97 6:44p John
111 * Made g3_Draw_bitmap functions account for aspect of bitmap.
113 * 27 12/02/97 4:00p John
114 * Added first rev of thruster glow, along with variable levels of
115 * translucency, which retquired some restructing of palman.
117 * 26 11/29/97 2:06p John
118 * made g3_draw_bitmap and g3_draw_rotated bitmap take w&h, not w/2 & h/2,
119 * like they used to incorrectly assume. Added code to model to read in
122 * 25 11/19/97 10:20p Lawrance
123 * remove ship_shockwave from ship struct, handled in physics now
125 * 24 11/16/97 8:52p Andsager
126 * For shockwaves, update physics damping info in physics code.
128 * 23 9/18/97 10:48p Lawrance
129 * comment out unused struct member
131 * 22 9/18/97 4:08p John
132 * Cleaned up & restructured ship damage stuff.
134 * 21 9/17/97 5:12p John
135 * Restructured collision routines. Probably broke a lot of stuff.
137 * 20 9/04/97 5:10p Andsager
138 * implement physics using moment of inertia and mass (from BSPgen).
139 * Added to phys_info struct. Updated ship_info, polymodel structs.
140 * Updated weapon ($Mass and $Force) and ship ($Mass -> $Density) tables
142 * 19 9/03/97 4:33p John
143 * changed bmpman to only accept ani and pcx's. made passing .pcx or .ani
144 * to bm_load functions not needed. Made bmpman keep track of palettes
145 * for bitmaps not mapped into game palettes.
147 * 18 8/26/97 3:31p Andsager
148 * scaled shockwave shake duration according to damage
150 * 17 8/05/97 1:25a Mike
151 * Make ship death roll be shortened by more damage.
153 * 16 7/31/97 5:55p John
154 * made so you pass flags to obj_create.
155 * Added new collision code that ignores any pairs that will never
158 * 15 7/25/97 4:30p Andsager
159 * Save shockwave info
161 * 14 7/25/97 1:04p Andsager
162 * Modified physics flag PF_REDUCED_DAMP for damping when object is hit.
163 * Flag is now set in physics_apply_whack/shock and turned off in
164 * physics_sim_vel. Weapons should not directly set this flag.
166 * 13 7/22/97 2:40p Andsager
167 * shockwaves now cause proper rotation of ships
169 * 12 7/20/97 7:01p Lawrance
170 * changed names of anim_ files to be more consistent
172 * 11 7/18/97 10:52a Lawrance
173 * let player have some control when shockwave hits
175 * 10 7/17/97 8:02p Lawrance
176 * tweaking shockwave effect
178 * 9 7/16/97 5:51p Lawrance
179 * make shockwaves translucent
181 * 8 7/16/97 4:00p Lawrance
182 * render shockwaves by default
184 * 7 7/16/97 3:50p Lawrance
185 * render shockwaves first, to fake transparency
187 * 6 7/16/97 2:52p Lawrance
188 * make shockwaves objects
190 * 5 7/15/97 7:26p Lawrance
191 * make shockwave blast persist over time
193 * 4 7/09/97 1:56p Lawrance
194 * add savegame support for shockwaves
196 * 3 7/09/97 10:33a Lawrance
197 * make area-effect spheres translucent
199 * 2 7/08/97 6:00p Lawrance
200 * implementing shockwaves
202 * 1 7/08/97 1:30p Lawrance
211 #include "freespace.h" // for colors
212 #include "shockwave.h"
214 #include "animplay.h"
216 #include "linklist.h"
219 #include "asteroid.h"
221 // -----------------------------------------------------------
223 // -----------------------------------------------------------
225 // -----------------------------------------------------------
226 // Module-wide globals
227 // -----------------------------------------------------------
229 static char *Shockwave_filenames[MAX_SHOCKWAVE_TYPES] =
236 shockwave Shockwaves[MAX_SHOCKWAVES];
237 shockwave_info Shockwave_info[MAX_SHOCKWAVE_TYPES];
239 shockwave Shockwave_list;
240 int Shockwave_inited = 0;
242 // -----------------------------------------------------------
244 // -----------------------------------------------------------
245 #define SW_INDEX(sw) (sw-Shockwaves)
247 // -----------------------------------------------------------
249 // -----------------------------------------------------------
250 extern int Show_area_effect;
252 // ------------------------------------------------------------------------------------
253 // shockwave_create()
255 // Call to create a shockwave
257 // input: parent_objnum => object number of object spawning the shockwave
258 // pos => vector specifing global position of shockwave center
259 // speed => speed at which shockwave expands (m/s)
260 // inner_radius => radius at which damage applied is at maximum
261 // outer_radius => damage decreases linearly to zero from inner_radius to
262 // outer_radius. Outside outer_radius, damage is 0.
263 // damage => the maximum damage (ie within inner_radius)
264 // blast => the maximux blast (within inner_radius)
265 // sw_flag => indicates whether shockwave is from weapon or ship explosion
266 // delay => delay in ms before the shockwave actually starts
268 // return: success => object number of shockwave
271 int shockwave_create(int parent_objnum, vector *pos, shockwave_create_info *sci, int flag, int delay)
273 int i, objnum, real_parent;
278 for ( i = 0; i < MAX_SHOCKWAVES; i++ ) {
279 if ( !(Shockwaves[i].flags & SW_USED) ){
284 if ( i == MAX_SHOCKWAVES ) {
288 // real_parent is the guy who caused this shockwave to happen
289 if ( Objects[parent_objnum].type == OBJ_WEAPON ){
290 real_parent = Objects[parent_objnum].parent;
292 real_parent = parent_objnum;
296 sw->flags = (SW_USED | flag);
297 sw->speed = sci->speed;
298 sw->inner_radius = sci->inner_rad;
299 sw->outer_radius = sci->outer_rad;
300 sw->damage = sci->damage;
301 sw->blast = sci->blast;
304 sw->num_objs_hit = 0;
305 sw->shockwave_info_index=0; // only one type for now... type could be passed is as a parameter
306 sw->current_bitmap=-1;
308 sw->time_elapsed=0.0f;
309 sw->delay_stamp = delay;
311 sw->rot_angle = sci->rot_angle;
313 si = &Shockwave_info[sw->shockwave_info_index];
314 // sw->total_time = i2fl(si->num_frames) / si->fps; // in seconds
315 sw->total_time = sw->outer_radius / sw->speed;
317 if ( Objects[parent_objnum].type == OBJ_WEAPON ) {
318 sw->weapon_info_index = Weapons[Objects[parent_objnum].instance].weapon_info_index;
321 sw->weapon_info_index = -1;
324 orient = vmd_identity_matrix;
326 objnum = obj_create( OBJ_SHOCKWAVE, real_parent, i, &orient, &sw->pos, sw->outer_radius, OF_RENDERS );
334 list_append(&Shockwave_list, sw);
339 // ------------------------------------------------------------------------------------
340 // shockwave_delete()
342 // Delete a shockwave
344 // input: object *objp => pointer to shockwave object
346 void shockwave_delete(object *objp)
348 Assert(objp->type == OBJ_SHOCKWAVE);
349 Assert(objp->instance >= 0 && objp->instance < MAX_SHOCKWAVES);
351 Shockwaves[objp->instance].flags = 0;
352 Shockwaves[objp->instance].objnum = -1;
353 list_remove(&Shockwave_list, &Shockwaves[objp->instance]);
356 // ------------------------------------------------------------------------------------
357 // shockwave_delete_all()
360 void shockwave_delete_all()
362 shockwave *sw, *next;
364 sw = GET_FIRST(&Shockwave_list);
365 while ( sw != &Shockwave_list ) {
367 Assert(sw->objnum != -1);
368 Objects[sw->objnum].flags |= OF_SHOULD_BE_DEAD;
373 // Set the correct frame of animation for the shockwave
374 void shockwave_set_framenum(int index)
380 sw = &Shockwaves[index];
381 si = &Shockwave_info[sw->shockwave_info_index];
383 framenum = fl2i(sw->time_elapsed / sw->total_time * si->num_frames + 0.5);
385 // ensure we don't go past the number of frames of animation
386 if ( framenum > (si->num_frames-1) ) {
387 framenum = (si->num_frames-1);
388 Objects[sw->objnum].flags |= OF_SHOULD_BE_DEAD;
391 if ( framenum < 0 ) {
395 sw->current_bitmap = si->bitmap_id + framenum;
398 // ------------------------------------------------------------------------------------
401 // Simulate a single shockwave. If the shockwave radius exceeds outer_radius, then
402 // delete the shockwave.
404 // input: ojbp => object pointer that points to shockwave object
405 // frametime => time to simulate shockwave
407 void shockwave_move(object *shockwave_objp, float frametime)
414 Assert(shockwave_objp->type == OBJ_SHOCKWAVE);
415 Assert(shockwave_objp->instance >= 0 && shockwave_objp->instance < MAX_SHOCKWAVES);
416 sw = &Shockwaves[shockwave_objp->instance];
418 // if the shockwave has a delay on it
419 if(sw->delay_stamp != -1){
420 if(timestamp_elapsed(sw->delay_stamp)){
421 sw->delay_stamp = -1;
427 sw->time_elapsed += frametime;
429 if ( sw->time_elapsed > sw->total_time ) {
430 shockwave_objp->flags |= OF_SHOULD_BE_DEAD;
434 shockwave_set_framenum(shockwave_objp->instance);
436 sw->radius += (frametime * sw->speed);
437 if ( sw->radius > sw->outer_radius ) {
438 sw->radius = sw->outer_radius;
439 shockwave_objp->flags |= OF_SHOULD_BE_DEAD;
443 // blast ships and asteroids
444 for ( objp = GET_FIRST(&obj_used_list); objp !=END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) {
445 if ( (objp->type != OBJ_SHIP) && (objp->type != OBJ_ASTEROID) ) {
449 if ( objp->type == OBJ_SHIP ) {
450 // don't blast navbuoys
451 if ( ship_get_SIF(objp->instance) & SIF_NAVBUOY ) {
456 // only apply damage to a ship once from a shockwave
457 for ( i = 0; i < sw->num_objs_hit; i++ ) {
458 if ( objp->signature == sw->obj_sig_hitlist[i] ){
462 if ( i < sw->num_objs_hit ){
466 if ( weapon_area_calc_damage(objp, &sw->pos, sw->inner_radius, sw->outer_radius, sw->blast, sw->damage, &blast, &damage, sw->radius) == -1 ){
470 // okay, we have damage applied, record the object signature so we don't repeatedly apply damage
471 Assert(sw->num_objs_hit < SW_MAX_OBJS_HIT);
472 if ( sw->num_objs_hit >= SW_MAX_OBJS_HIT) {
478 sw->obj_sig_hitlist[sw->num_objs_hit++] = objp->signature;
479 ship_apply_global_damage(objp, shockwave_objp, &sw->pos, damage );
480 weapon_area_apply_blast(NULL, objp, &sw->pos, blast, 1);
483 asteroid_hit(objp, NULL, NULL, damage);
491 // If this shockwave hit the player, play shockwave impact sound
492 if ( objp == Player_obj ) {
493 snd_play( &Snds[SND_SHOCKWAVE_IMPACT], 0.0f, max(0.4f, damage/Weapon_info[sw->weapon_info_index].damage) );
499 // ------------------------------------------------------------------------------------
500 // shockwave_render()
502 // Draw the shockwave identified by handle
504 // input: objp => pointer to shockwave object
506 void shockwave_render(object *objp)
512 Assert(objp->type == OBJ_SHOCKWAVE);
513 Assert(objp->instance >= 0 && objp->instance < MAX_SHOCKWAVES);
515 sw = &Shockwaves[objp->instance];
516 si = &Shockwave_info[sw->shockwave_info_index];
518 if( (sw->delay_stamp != -1) && !timestamp_elapsed(sw->delay_stamp)){
522 if ( sw->current_bitmap < 0 ){
527 if(The_mission.flags & MISSION_FLAG_FULLNEB){
528 gr_fog_set(GR_FOGMODE_NONE, 0, 0, 0);
531 g3_rotate_vertex(&p, &sw->pos );
533 gr_set_bitmap(sw->current_bitmap, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, 1.3f );
534 g3_draw_rotated_bitmap(&p, fl_radian(sw->rot_angle), sw->radius, TMAP_FLAG_TEXTURED);
537 // ------------------------------------------------------------------------------------
540 // Call once at the start of each level (mission)
542 void shockwave_level_init()
547 // load in shockwaves
548 for ( i=0; i<MAX_SHOCKWAVE_TYPES; i++ ) {
549 si = &Shockwave_info[i];
550 si->bitmap_id = bm_load_animation( Shockwave_filenames[i], &si->num_frames, &si->fps, 1 );
551 if ( si->bitmap_id < 0 ) {
552 Error(LOCATION, "Could not load %s anim file\n", Shockwave_filenames[i]);
556 list_init(&Shockwave_list);
558 for ( i = 0; i < MAX_SHOCKWAVES; i++ ) {
559 Shockwaves[i].flags = 0;
560 Shockwaves[i].objnum = -1;
563 Shockwave_inited = 1;
566 // ------------------------------------------------------------------------------------
567 // shockwave_level_close()
569 // Call at the close of each level (mission)
570 void shockwave_level_close()
572 if(Shockwave_inited){
573 shockwave_delete_all();
575 Shockwave_inited = 0;
578 // ------------------------------------------------------------------------------------
581 // Called at game-shutdown to
583 void shockwave_close()
587 // ------------------------------------------------------------------------------------
588 // shockwave_move_all()
590 // Simulate all shockwaves in Shockwave_list
592 // input: frametime => time for last frame in ms
594 void shockwave_move_all(float frametime)
596 shockwave *sw, *next;
598 sw = GET_FIRST(&Shockwave_list);
599 while ( sw != &Shockwave_list ) {
601 Assert(sw->objnum != -1);
602 shockwave_move(&Objects[sw->objnum], frametime);
607 // ------------------------------------------------------------------------------------
608 // shockwave_render_all()
611 void shockwave_render_all()
613 shockwave *sw, *next;
615 sw = GET_FIRST(&Shockwave_list);
616 while ( sw != &Shockwave_list ) {
618 Assert(sw->objnum != -1);
619 shockwave_render(&Objects[sw->objnum]);
624 // return the weapon_info_index field for a shockwave
625 int shockwave_weapon_index(int index)
627 return Shockwaves[index].weapon_info_index;
630 // return the maximum radius for specified shockwave
631 float shockwave_max_radius(int index)
633 return Shockwaves[index].outer_radius;
636 void shockwave_page_in()
641 // load in shockwaves
642 for ( i=0; i<MAX_SHOCKWAVE_TYPES; i++ ) {
643 si = &Shockwave_info[i];
644 bm_page_in_texture( si->bitmap_id, si->num_frames );