2 * $Logfile: /Freespace2/code/Weapon/Shockwave.cpp $
7 * C file for creating and managing shockwaves
10 * Revision 1.1 2002/05/03 03:28:11 root
14 * 7 9/01/99 10:15a Dave
16 * 6 7/18/99 12:32p Dave
17 * Randomly oriented shockwaves.
19 * 5 3/23/99 2:29p Andsager
20 * Fix shockwaves for kamikazi and Fred defined. Collect together
21 * shockwave_create_info struct.
23 * 4 2/26/99 4:14p Dave
24 * Put in the ability to have multiple shockwaves for ships.
26 * 3 11/05/98 5:55p Dave
27 * Big pass at reducing #includes
29 * 2 10/07/98 10:54a Dave
32 * 1 10/07/98 10:51a Dave
34 * 49 5/18/98 3:04p Lawrance
35 * Play shockwave impact sound
37 * 48 5/18/98 12:59a Lawrance
38 * Replace shockwave impact sound with a new "whoosh" sound that
39 * originates from the shockwave center
41 * 47 4/15/98 10:17p Mike
42 * Training mission #5.
43 * Fix application of subsystem damage.
45 * 46 4/09/98 7:58p John
46 * Cleaned up tmapper code a bit. Put NDEBUG around some ndebug stuff.
47 * Took out XPARENT flag settings in all the alpha-blended texture stuff.
49 * 45 3/31/98 5:19p John
50 * Removed demo/save/restore. Made NDEBUG defined compile. Removed a
51 * bunch of debug stuff out of player file. Made model code be able to
52 * unload models and malloc out only however many models are needed.
55 * 44 3/30/98 4:02p John
56 * Made machines with < 32 MB of RAM use every other frame of certain
57 * bitmaps. Put in code to keep track of how much RAM we've malloc'd.
59 * 43 3/26/98 5:26p John
60 * added new paging code. nonfunctional.
62 * 42 3/04/98 4:11p Lawrance
63 * Have area effects affect asteroids, have asteroids cast an area effect,
66 * 41 2/26/98 10:08p Hoffoss
67 * Rewrote state saving and restoring to fix bugs and simplify the code.
69 * 40 2/22/98 12:19p John
70 * Externalized some strings
72 * 39 2/20/98 8:32p Lawrance
73 * Make shockwaves affect subsystems more realistically.
75 * 38 2/16/98 11:26a Lawrance
76 * ensure shockwave lasts full duration
78 * 37 2/16/98 10:04a Lawrance
79 * Fix broken shockwave damage.
81 * 36 2/14/98 4:42p Lawrance
82 * pass shockwave object (not parent) to ship_apply_global_damage()
84 * 35 2/12/98 11:54p Lawrance
85 * restructure rendering code to use an animation
87 * 34 2/11/98 5:38p Dave
88 * Put in a global inited flag for shockwaves.
90 * 33 2/02/98 8:47a Andsager
91 * Ship death area damage applied as instantaneous damage for small ships
92 * and shockwaves for large (>50 radius) ships.
94 * 32 1/26/98 11:54a Lawrance
95 * Don't allow Navbuoys to be affected by area-effect damage and blasts.
97 * 31 1/22/98 11:43p Lawrance
98 * Play sound effect when player is hit by shockwave.
100 * 30 1/14/98 4:31p Dave
101 * Made shockwaves apply damage correctly.
103 * 29 1/14/98 2:59p Allender
104 * if shockwave came from a weapon, make the shockwave's parent be the
107 * 28 12/30/97 6:44p John
108 * Made g3_Draw_bitmap functions account for aspect of bitmap.
110 * 27 12/02/97 4:00p John
111 * Added first rev of thruster glow, along with variable levels of
112 * translucency, which retquired some restructing of palman.
114 * 26 11/29/97 2:06p John
115 * made g3_draw_bitmap and g3_draw_rotated bitmap take w&h, not w/2 & h/2,
116 * like they used to incorrectly assume. Added code to model to read in
119 * 25 11/19/97 10:20p Lawrance
120 * remove ship_shockwave from ship struct, handled in physics now
122 * 24 11/16/97 8:52p Andsager
123 * For shockwaves, update physics damping info in physics code.
125 * 23 9/18/97 10:48p Lawrance
126 * comment out unused struct member
128 * 22 9/18/97 4:08p John
129 * Cleaned up & restructured ship damage stuff.
131 * 21 9/17/97 5:12p John
132 * Restructured collision routines. Probably broke a lot of stuff.
134 * 20 9/04/97 5:10p Andsager
135 * implement physics using moment of inertia and mass (from BSPgen).
136 * Added to phys_info struct. Updated ship_info, polymodel structs.
137 * Updated weapon ($Mass and $Force) and ship ($Mass -> $Density) tables
139 * 19 9/03/97 4:33p John
140 * changed bmpman to only accept ani and pcx's. made passing .pcx or .ani
141 * to bm_load functions not needed. Made bmpman keep track of palettes
142 * for bitmaps not mapped into game palettes.
144 * 18 8/26/97 3:31p Andsager
145 * scaled shockwave shake duration according to damage
147 * 17 8/05/97 1:25a Mike
148 * Make ship death roll be shortened by more damage.
150 * 16 7/31/97 5:55p John
151 * made so you pass flags to obj_create.
152 * Added new collision code that ignores any pairs that will never
155 * 15 7/25/97 4:30p Andsager
156 * Save shockwave info
158 * 14 7/25/97 1:04p Andsager
159 * Modified physics flag PF_REDUCED_DAMP for damping when object is hit.
160 * Flag is now set in physics_apply_whack/shock and turned off in
161 * physics_sim_vel. Weapons should not directly set this flag.
163 * 13 7/22/97 2:40p Andsager
164 * shockwaves now cause proper rotation of ships
166 * 12 7/20/97 7:01p Lawrance
167 * changed names of anim_ files to be more consistent
169 * 11 7/18/97 10:52a Lawrance
170 * let player have some control when shockwave hits
172 * 10 7/17/97 8:02p Lawrance
173 * tweaking shockwave effect
175 * 9 7/16/97 5:51p Lawrance
176 * make shockwaves translucent
178 * 8 7/16/97 4:00p Lawrance
179 * render shockwaves by default
181 * 7 7/16/97 3:50p Lawrance
182 * render shockwaves first, to fake transparency
184 * 6 7/16/97 2:52p Lawrance
185 * make shockwaves objects
187 * 5 7/15/97 7:26p Lawrance
188 * make shockwave blast persist over time
190 * 4 7/09/97 1:56p Lawrance
191 * add savegame support for shockwaves
193 * 3 7/09/97 10:33a Lawrance
194 * make area-effect spheres translucent
196 * 2 7/08/97 6:00p Lawrance
197 * implementing shockwaves
199 * 1 7/08/97 1:30p Lawrance
208 #include "freespace.h" // for colors
209 #include "shockwave.h"
211 #include "animplay.h"
213 #include "linklist.h"
216 #include "asteroid.h"
218 // -----------------------------------------------------------
220 // -----------------------------------------------------------
222 // -----------------------------------------------------------
223 // Module-wide globals
224 // -----------------------------------------------------------
226 static char *Shockwave_filenames[MAX_SHOCKWAVE_TYPES] =
233 shockwave Shockwaves[MAX_SHOCKWAVES];
234 shockwave_info Shockwave_info[MAX_SHOCKWAVE_TYPES];
236 shockwave Shockwave_list;
237 int Shockwave_inited = 0;
239 // -----------------------------------------------------------
241 // -----------------------------------------------------------
242 #define SW_INDEX(sw) (sw-Shockwaves)
244 // -----------------------------------------------------------
246 // -----------------------------------------------------------
247 extern int Show_area_effect;
249 // ------------------------------------------------------------------------------------
250 // shockwave_create()
252 // Call to create a shockwave
254 // input: parent_objnum => object number of object spawning the shockwave
255 // pos => vector specifing global position of shockwave center
256 // speed => speed at which shockwave expands (m/s)
257 // inner_radius => radius at which damage applied is at maximum
258 // outer_radius => damage decreases linearly to zero from inner_radius to
259 // outer_radius. Outside outer_radius, damage is 0.
260 // damage => the maximum damage (ie within inner_radius)
261 // blast => the maximux blast (within inner_radius)
262 // sw_flag => indicates whether shockwave is from weapon or ship explosion
263 // delay => delay in ms before the shockwave actually starts
265 // return: success => object number of shockwave
268 int shockwave_create(int parent_objnum, vector *pos, shockwave_create_info *sci, int flag, int delay)
270 int i, objnum, real_parent;
275 for ( i = 0; i < MAX_SHOCKWAVES; i++ ) {
276 if ( !(Shockwaves[i].flags & SW_USED) ){
281 if ( i == MAX_SHOCKWAVES ) {
285 // real_parent is the guy who caused this shockwave to happen
286 if ( Objects[parent_objnum].type == OBJ_WEAPON ){
287 real_parent = Objects[parent_objnum].parent;
289 real_parent = parent_objnum;
293 sw->flags = (SW_USED | flag);
294 sw->speed = sci->speed;
295 sw->inner_radius = sci->inner_rad;
296 sw->outer_radius = sci->outer_rad;
297 sw->damage = sci->damage;
298 sw->blast = sci->blast;
301 sw->num_objs_hit = 0;
302 sw->shockwave_info_index=0; // only one type for now... type could be passed is as a parameter
303 sw->current_bitmap=-1;
305 sw->time_elapsed=0.0f;
306 sw->delay_stamp = delay;
308 sw->rot_angle = sci->rot_angle;
310 si = &Shockwave_info[sw->shockwave_info_index];
311 // sw->total_time = i2fl(si->num_frames) / si->fps; // in seconds
312 sw->total_time = sw->outer_radius / sw->speed;
314 if ( Objects[parent_objnum].type == OBJ_WEAPON ) {
315 sw->weapon_info_index = Weapons[Objects[parent_objnum].instance].weapon_info_index;
318 sw->weapon_info_index = -1;
321 orient = vmd_identity_matrix;
323 objnum = obj_create( OBJ_SHOCKWAVE, real_parent, i, &orient, &sw->pos, sw->outer_radius, OF_RENDERS );
331 list_append(&Shockwave_list, sw);
336 // ------------------------------------------------------------------------------------
337 // shockwave_delete()
339 // Delete a shockwave
341 // input: object *objp => pointer to shockwave object
343 void shockwave_delete(object *objp)
345 Assert(objp->type == OBJ_SHOCKWAVE);
346 Assert(objp->instance >= 0 && objp->instance < MAX_SHOCKWAVES);
348 Shockwaves[objp->instance].flags = 0;
349 Shockwaves[objp->instance].objnum = -1;
350 list_remove(&Shockwave_list, &Shockwaves[objp->instance]);
353 // ------------------------------------------------------------------------------------
354 // shockwave_delete_all()
357 void shockwave_delete_all()
359 shockwave *sw, *next;
361 sw = GET_FIRST(&Shockwave_list);
362 while ( sw != &Shockwave_list ) {
364 Assert(sw->objnum != -1);
365 Objects[sw->objnum].flags |= OF_SHOULD_BE_DEAD;
370 // Set the correct frame of animation for the shockwave
371 void shockwave_set_framenum(int index)
377 sw = &Shockwaves[index];
378 si = &Shockwave_info[sw->shockwave_info_index];
380 framenum = fl2i(sw->time_elapsed / sw->total_time * si->num_frames + 0.5);
382 // ensure we don't go past the number of frames of animation
383 if ( framenum > (si->num_frames-1) ) {
384 framenum = (si->num_frames-1);
385 Objects[sw->objnum].flags |= OF_SHOULD_BE_DEAD;
388 if ( framenum < 0 ) {
392 sw->current_bitmap = si->bitmap_id + framenum;
395 // ------------------------------------------------------------------------------------
398 // Simulate a single shockwave. If the shockwave radius exceeds outer_radius, then
399 // delete the shockwave.
401 // input: ojbp => object pointer that points to shockwave object
402 // frametime => time to simulate shockwave
404 void shockwave_move(object *shockwave_objp, float frametime)
411 Assert(shockwave_objp->type == OBJ_SHOCKWAVE);
412 Assert(shockwave_objp->instance >= 0 && shockwave_objp->instance < MAX_SHOCKWAVES);
413 sw = &Shockwaves[shockwave_objp->instance];
415 // if the shockwave has a delay on it
416 if(sw->delay_stamp != -1){
417 if(timestamp_elapsed(sw->delay_stamp)){
418 sw->delay_stamp = -1;
424 sw->time_elapsed += frametime;
426 if ( sw->time_elapsed > sw->total_time ) {
427 shockwave_objp->flags |= OF_SHOULD_BE_DEAD;
431 shockwave_set_framenum(shockwave_objp->instance);
433 sw->radius += (frametime * sw->speed);
434 if ( sw->radius > sw->outer_radius ) {
435 sw->radius = sw->outer_radius;
436 shockwave_objp->flags |= OF_SHOULD_BE_DEAD;
440 // blast ships and asteroids
441 for ( objp = GET_FIRST(&obj_used_list); objp !=END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) {
442 if ( (objp->type != OBJ_SHIP) && (objp->type != OBJ_ASTEROID) ) {
446 if ( objp->type == OBJ_SHIP ) {
447 // don't blast navbuoys
448 if ( ship_get_SIF(objp->instance) & SIF_NAVBUOY ) {
453 // only apply damage to a ship once from a shockwave
454 for ( i = 0; i < sw->num_objs_hit; i++ ) {
455 if ( objp->signature == sw->obj_sig_hitlist[i] ){
459 if ( i < sw->num_objs_hit ){
463 if ( weapon_area_calc_damage(objp, &sw->pos, sw->inner_radius, sw->outer_radius, sw->blast, sw->damage, &blast, &damage, sw->radius) == -1 ){
467 // okay, we have damage applied, record the object signature so we don't repeatedly apply damage
468 Assert(sw->num_objs_hit < SW_MAX_OBJS_HIT);
469 if ( sw->num_objs_hit >= SW_MAX_OBJS_HIT) {
475 sw->obj_sig_hitlist[sw->num_objs_hit++] = objp->signature;
476 ship_apply_global_damage(objp, shockwave_objp, &sw->pos, damage );
477 weapon_area_apply_blast(NULL, objp, &sw->pos, blast, 1);
480 asteroid_hit(objp, NULL, NULL, damage);
488 // If this shockwave hit the player, play shockwave impact sound
489 if ( objp == Player_obj ) {
490 snd_play( &Snds[SND_SHOCKWAVE_IMPACT], 0.0f, max(0.4f, damage/Weapon_info[sw->weapon_info_index].damage) );
496 // ------------------------------------------------------------------------------------
497 // shockwave_render()
499 // Draw the shockwave identified by handle
501 // input: objp => pointer to shockwave object
503 void shockwave_render(object *objp)
509 Assert(objp->type == OBJ_SHOCKWAVE);
510 Assert(objp->instance >= 0 && objp->instance < MAX_SHOCKWAVES);
512 sw = &Shockwaves[objp->instance];
513 si = &Shockwave_info[sw->shockwave_info_index];
515 if( (sw->delay_stamp != -1) && !timestamp_elapsed(sw->delay_stamp)){
519 if ( sw->current_bitmap < 0 ){
524 if(The_mission.flags & MISSION_FLAG_FULLNEB){
525 gr_fog_set(GR_FOGMODE_NONE, 0, 0, 0);
528 g3_rotate_vertex(&p, &sw->pos );
530 gr_set_bitmap(sw->current_bitmap, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, 1.3f );
531 g3_draw_rotated_bitmap(&p, fl_radian(sw->rot_angle), sw->radius, TMAP_FLAG_TEXTURED);
534 // ------------------------------------------------------------------------------------
537 // Call once at the start of each level (mission)
539 void shockwave_level_init()
544 // load in shockwaves
545 for ( i=0; i<MAX_SHOCKWAVE_TYPES; i++ ) {
546 si = &Shockwave_info[i];
547 si->bitmap_id = bm_load_animation( Shockwave_filenames[i], &si->num_frames, &si->fps, 1 );
548 if ( si->bitmap_id < 0 ) {
549 Error(LOCATION, "Could not load %s anim file\n", Shockwave_filenames[i]);
553 list_init(&Shockwave_list);
555 for ( i = 0; i < MAX_SHOCKWAVES; i++ ) {
556 Shockwaves[i].flags = 0;
557 Shockwaves[i].objnum = -1;
560 Shockwave_inited = 1;
563 // ------------------------------------------------------------------------------------
564 // shockwave_level_close()
566 // Call at the close of each level (mission)
567 void shockwave_level_close()
569 if(Shockwave_inited){
570 shockwave_delete_all();
572 Shockwave_inited = 0;
575 // ------------------------------------------------------------------------------------
578 // Called at game-shutdown to
580 void shockwave_close()
584 // ------------------------------------------------------------------------------------
585 // shockwave_move_all()
587 // Simulate all shockwaves in Shockwave_list
589 // input: frametime => time for last frame in ms
591 void shockwave_move_all(float frametime)
593 shockwave *sw, *next;
595 sw = GET_FIRST(&Shockwave_list);
596 while ( sw != &Shockwave_list ) {
598 Assert(sw->objnum != -1);
599 shockwave_move(&Objects[sw->objnum], frametime);
604 // ------------------------------------------------------------------------------------
605 // shockwave_render_all()
608 void shockwave_render_all()
610 shockwave *sw, *next;
612 sw = GET_FIRST(&Shockwave_list);
613 while ( sw != &Shockwave_list ) {
615 Assert(sw->objnum != -1);
616 shockwave_render(&Objects[sw->objnum]);
621 // return the weapon_info_index field for a shockwave
622 int shockwave_weapon_index(int index)
624 return Shockwaves[index].weapon_info_index;
627 // return the maximum radius for specified shockwave
628 float shockwave_max_radius(int index)
630 return Shockwaves[index].outer_radius;
633 void shockwave_page_in()
638 // load in shockwaves
639 for ( i=0; i<MAX_SHOCKWAVE_TYPES; i++ ) {
640 si = &Shockwave_info[i];
641 bm_page_in_texture( si->bitmap_id, si->num_frames );