2 * Copyright (C) Volition, Inc. 1999. All rights reserved.
4 * All source code herein is the property of Volition, Inc. You may not sell
5 * or otherwise commercially exploit the source or things you created based on
10 * $Logfile: /Freespace2/code/Weapon/Shockwave.cpp $
15 * C file for creating and managing shockwaves
18 * Revision 1.4 2004/09/20 01:31:45 theoddone33
21 * Revision 1.3 2002/06/09 04:41:29 relnev
22 * added copyright header
24 * Revision 1.2 2002/05/07 03:16:53 theoddone33
25 * The Great Newline Fix
27 * Revision 1.1.1.1 2002/05/03 03:28:11 root
31 * 7 9/01/99 10:15a Dave
33 * 6 7/18/99 12:32p Dave
34 * Randomly oriented shockwaves.
36 * 5 3/23/99 2:29p Andsager
37 * Fix shockwaves for kamikazi and Fred defined. Collect together
38 * shockwave_create_info struct.
40 * 4 2/26/99 4:14p Dave
41 * Put in the ability to have multiple shockwaves for ships.
43 * 3 11/05/98 5:55p Dave
44 * Big pass at reducing #includes
46 * 2 10/07/98 10:54a Dave
49 * 1 10/07/98 10:51a Dave
51 * 49 5/18/98 3:04p Lawrance
52 * Play shockwave impact sound
54 * 48 5/18/98 12:59a Lawrance
55 * Replace shockwave impact sound with a new "whoosh" sound that
56 * originates from the shockwave center
58 * 47 4/15/98 10:17p Mike
59 * Training mission #5.
60 * Fix application of subsystem damage.
62 * 46 4/09/98 7:58p John
63 * Cleaned up tmapper code a bit. Put NDEBUG around some ndebug stuff.
64 * Took out XPARENT flag settings in all the alpha-blended texture stuff.
66 * 45 3/31/98 5:19p John
67 * Removed demo/save/restore. Made NDEBUG defined compile. Removed a
68 * bunch of debug stuff out of player file. Made model code be able to
69 * unload models and malloc out only however many models are needed.
72 * 44 3/30/98 4:02p John
73 * Made machines with < 32 MB of RAM use every other frame of certain
74 * bitmaps. Put in code to keep track of how much RAM we've malloc'd.
76 * 43 3/26/98 5:26p John
77 * added new paging code. nonfunctional.
79 * 42 3/04/98 4:11p Lawrance
80 * Have area effects affect asteroids, have asteroids cast an area effect,
83 * 41 2/26/98 10:08p Hoffoss
84 * Rewrote state saving and restoring to fix bugs and simplify the code.
86 * 40 2/22/98 12:19p John
87 * Externalized some strings
89 * 39 2/20/98 8:32p Lawrance
90 * Make shockwaves affect subsystems more realistically.
92 * 38 2/16/98 11:26a Lawrance
93 * ensure shockwave lasts full duration
95 * 37 2/16/98 10:04a Lawrance
96 * Fix broken shockwave damage.
98 * 36 2/14/98 4:42p Lawrance
99 * pass shockwave object (not parent) to ship_apply_global_damage()
101 * 35 2/12/98 11:54p Lawrance
102 * restructure rendering code to use an animation
104 * 34 2/11/98 5:38p Dave
105 * Put in a global inited flag for shockwaves.
107 * 33 2/02/98 8:47a Andsager
108 * Ship death area damage applied as instantaneous damage for small ships
109 * and shockwaves for large (>50 radius) ships.
111 * 32 1/26/98 11:54a Lawrance
112 * Don't allow Navbuoys to be affected by area-effect damage and blasts.
114 * 31 1/22/98 11:43p Lawrance
115 * Play sound effect when player is hit by shockwave.
117 * 30 1/14/98 4:31p Dave
118 * Made shockwaves apply damage correctly.
120 * 29 1/14/98 2:59p Allender
121 * if shockwave came from a weapon, make the shockwave's parent be the
124 * 28 12/30/97 6:44p John
125 * Made g3_Draw_bitmap functions account for aspect of bitmap.
127 * 27 12/02/97 4:00p John
128 * Added first rev of thruster glow, along with variable levels of
129 * translucency, which retquired some restructing of palman.
131 * 26 11/29/97 2:06p John
132 * made g3_draw_bitmap and g3_draw_rotated bitmap take w&h, not w/2 & h/2,
133 * like they used to incorrectly assume. Added code to model to read in
136 * 25 11/19/97 10:20p Lawrance
137 * remove ship_shockwave from ship struct, handled in physics now
139 * 24 11/16/97 8:52p Andsager
140 * For shockwaves, update physics damping info in physics code.
142 * 23 9/18/97 10:48p Lawrance
143 * comment out unused struct member
145 * 22 9/18/97 4:08p John
146 * Cleaned up & restructured ship damage stuff.
148 * 21 9/17/97 5:12p John
149 * Restructured collision routines. Probably broke a lot of stuff.
151 * 20 9/04/97 5:10p Andsager
152 * implement physics using moment of inertia and mass (from BSPgen).
153 * Added to phys_info struct. Updated ship_info, polymodel structs.
154 * Updated weapon ($Mass and $Force) and ship ($Mass -> $Density) tables
156 * 19 9/03/97 4:33p John
157 * changed bmpman to only accept ani and pcx's. made passing .pcx or .ani
158 * to bm_load functions not needed. Made bmpman keep track of palettes
159 * for bitmaps not mapped into game palettes.
161 * 18 8/26/97 3:31p Andsager
162 * scaled shockwave shake duration according to damage
164 * 17 8/05/97 1:25a Mike
165 * Make ship death roll be shortened by more damage.
167 * 16 7/31/97 5:55p John
168 * made so you pass flags to obj_create.
169 * Added new collision code that ignores any pairs that will never
172 * 15 7/25/97 4:30p Andsager
173 * Save shockwave info
175 * 14 7/25/97 1:04p Andsager
176 * Modified physics flag PF_REDUCED_DAMP for damping when object is hit.
177 * Flag is now set in physics_apply_whack/shock and turned off in
178 * physics_sim_vel. Weapons should not directly set this flag.
180 * 13 7/22/97 2:40p Andsager
181 * shockwaves now cause proper rotation of ships
183 * 12 7/20/97 7:01p Lawrance
184 * changed names of anim_ files to be more consistent
186 * 11 7/18/97 10:52a Lawrance
187 * let player have some control when shockwave hits
189 * 10 7/17/97 8:02p Lawrance
190 * tweaking shockwave effect
192 * 9 7/16/97 5:51p Lawrance
193 * make shockwaves translucent
195 * 8 7/16/97 4:00p Lawrance
196 * render shockwaves by default
198 * 7 7/16/97 3:50p Lawrance
199 * render shockwaves first, to fake transparency
201 * 6 7/16/97 2:52p Lawrance
202 * make shockwaves objects
204 * 5 7/15/97 7:26p Lawrance
205 * make shockwave blast persist over time
207 * 4 7/09/97 1:56p Lawrance
208 * add savegame support for shockwaves
210 * 3 7/09/97 10:33a Lawrance
211 * make area-effect spheres translucent
213 * 2 7/08/97 6:00p Lawrance
214 * implementing shockwaves
216 * 1 7/08/97 1:30p Lawrance
225 #include "freespace.h" // for colors
226 #include "shockwave.h"
228 #include "animplay.h"
230 #include "linklist.h"
233 #include "asteroid.h"
235 // -----------------------------------------------------------
237 // -----------------------------------------------------------
239 // -----------------------------------------------------------
240 // Module-wide globals
241 // -----------------------------------------------------------
243 static const char *Shockwave_filenames[MAX_SHOCKWAVE_TYPES] =
250 shockwave Shockwaves[MAX_SHOCKWAVES];
251 shockwave_info Shockwave_info[MAX_SHOCKWAVE_TYPES];
253 shockwave Shockwave_list;
254 int Shockwave_inited = 0;
256 // -----------------------------------------------------------
258 // -----------------------------------------------------------
259 #define SW_INDEX(sw) (sw-Shockwaves)
261 // -----------------------------------------------------------
263 // -----------------------------------------------------------
264 extern int Show_area_effect;
266 // ------------------------------------------------------------------------------------
267 // shockwave_create()
269 // Call to create a shockwave
271 // input: parent_objnum => object number of object spawning the shockwave
272 // pos => vector specifing global position of shockwave center
273 // speed => speed at which shockwave expands (m/s)
274 // inner_radius => radius at which damage applied is at maximum
275 // outer_radius => damage decreases linearly to zero from inner_radius to
276 // outer_radius. Outside outer_radius, damage is 0.
277 // damage => the maximum damage (ie within inner_radius)
278 // blast => the maximux blast (within inner_radius)
279 // sw_flag => indicates whether shockwave is from weapon or ship explosion
280 // delay => delay in ms before the shockwave actually starts
282 // return: success => object number of shockwave
285 int shockwave_create(int parent_objnum, vector *pos, shockwave_create_info *sci, int flag, int delay)
287 int i, objnum, real_parent;
289 // shockwave_info *si;
292 for ( i = 0; i < MAX_SHOCKWAVES; i++ ) {
293 if ( !(Shockwaves[i].flags & SW_USED) ){
298 if ( i == MAX_SHOCKWAVES ) {
302 // real_parent is the guy who caused this shockwave to happen
303 if ( Objects[parent_objnum].type == OBJ_WEAPON ){
304 real_parent = Objects[parent_objnum].parent;
306 real_parent = parent_objnum;
310 sw->flags = (SW_USED | flag);
311 sw->speed = sci->speed;
312 sw->inner_radius = sci->inner_rad;
313 sw->outer_radius = sci->outer_rad;
314 sw->damage = sci->damage;
315 sw->blast = sci->blast;
318 sw->num_objs_hit = 0;
319 sw->shockwave_info_index=0; // only one type for now... type could be passed is as a parameter
320 sw->current_bitmap=-1;
322 sw->time_elapsed=0.0f;
323 sw->delay_stamp = delay;
325 sw->rot_angle = sci->rot_angle;
327 // si = &Shockwave_info[sw->shockwave_info_index];
328 // sw->total_time = i2fl(si->num_frames) / si->fps; // in seconds
329 sw->total_time = sw->outer_radius / sw->speed;
331 if ( Objects[parent_objnum].type == OBJ_WEAPON ) {
332 sw->weapon_info_index = Weapons[Objects[parent_objnum].instance].weapon_info_index;
335 sw->weapon_info_index = -1;
338 orient = vmd_identity_matrix;
340 objnum = obj_create( OBJ_SHOCKWAVE, real_parent, i, &orient, &sw->pos, sw->outer_radius, OF_RENDERS );
348 list_append(&Shockwave_list, sw);
353 // ------------------------------------------------------------------------------------
354 // shockwave_delete()
356 // Delete a shockwave
358 // input: object *objp => pointer to shockwave object
360 void shockwave_delete(object *objp)
362 SDL_assert(objp->type == OBJ_SHOCKWAVE);
363 SDL_assert(objp->instance >= 0 && objp->instance < MAX_SHOCKWAVES);
365 Shockwaves[objp->instance].flags = 0;
366 Shockwaves[objp->instance].objnum = -1;
367 list_remove(&Shockwave_list, &Shockwaves[objp->instance]);
370 // ------------------------------------------------------------------------------------
371 // shockwave_delete_all()
374 void shockwave_delete_all()
376 shockwave *sw, *next;
378 sw = GET_FIRST(&Shockwave_list);
379 while ( sw != &Shockwave_list ) {
381 SDL_assert(sw->objnum != -1);
382 Objects[sw->objnum].flags |= OF_SHOULD_BE_DEAD;
387 // Set the correct frame of animation for the shockwave
388 void shockwave_set_framenum(int index)
394 sw = &Shockwaves[index];
395 si = &Shockwave_info[sw->shockwave_info_index];
397 framenum = fl2i(sw->time_elapsed / sw->total_time * si->num_frames + 0.5);
399 // ensure we don't go past the number of frames of animation
400 if ( framenum > (si->num_frames-1) ) {
401 framenum = (si->num_frames-1);
402 Objects[sw->objnum].flags |= OF_SHOULD_BE_DEAD;
405 if ( framenum < 0 ) {
409 sw->current_bitmap = si->bitmap_id + framenum;
412 // ------------------------------------------------------------------------------------
415 // Simulate a single shockwave. If the shockwave radius exceeds outer_radius, then
416 // delete the shockwave.
418 // input: ojbp => object pointer that points to shockwave object
419 // frametime => time to simulate shockwave
421 void shockwave_move(object *shockwave_objp, float frametime)
428 SDL_assert(shockwave_objp->type == OBJ_SHOCKWAVE);
429 SDL_assert(shockwave_objp->instance >= 0 && shockwave_objp->instance < MAX_SHOCKWAVES);
430 sw = &Shockwaves[shockwave_objp->instance];
432 // if the shockwave has a delay on it
433 if(sw->delay_stamp != -1){
434 if(timestamp_elapsed(sw->delay_stamp)){
435 sw->delay_stamp = -1;
441 sw->time_elapsed += frametime;
443 if ( sw->time_elapsed > sw->total_time ) {
444 shockwave_objp->flags |= OF_SHOULD_BE_DEAD;
448 shockwave_set_framenum(shockwave_objp->instance);
450 sw->radius += (frametime * sw->speed);
451 if ( sw->radius > sw->outer_radius ) {
452 sw->radius = sw->outer_radius;
453 shockwave_objp->flags |= OF_SHOULD_BE_DEAD;
457 // blast ships and asteroids
458 for ( objp = GET_FIRST(&obj_used_list); objp !=END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) {
459 if ( (objp->type != OBJ_SHIP) && (objp->type != OBJ_ASTEROID) ) {
463 if ( objp->type == OBJ_SHIP ) {
464 // don't blast navbuoys
465 if ( ship_get_SIF(objp->instance) & SIF_NAVBUOY ) {
470 // only apply damage to a ship once from a shockwave
471 for ( i = 0; i < sw->num_objs_hit; i++ ) {
472 if ( objp->signature == sw->obj_sig_hitlist[i] ){
476 if ( i < sw->num_objs_hit ){
480 if ( weapon_area_calc_damage(objp, &sw->pos, sw->inner_radius, sw->outer_radius, sw->blast, sw->damage, &blast, &damage, sw->radius) == -1 ){
484 // okay, we have damage applied, record the object signature so we don't repeatedly apply damage
485 SDL_assert(sw->num_objs_hit < SW_MAX_OBJS_HIT);
486 if ( sw->num_objs_hit >= SW_MAX_OBJS_HIT) {
492 sw->obj_sig_hitlist[sw->num_objs_hit++] = objp->signature;
493 ship_apply_global_damage(objp, shockwave_objp, &sw->pos, damage );
494 weapon_area_apply_blast(NULL, objp, &sw->pos, blast, 1);
497 asteroid_hit(objp, NULL, NULL, damage);
505 // If this shockwave hit the player, play shockwave impact sound
506 if ( objp == Player_obj ) {
507 snd_play( &Snds[SND_SHOCKWAVE_IMPACT], 0.0f, max(0.4f, damage/Weapon_info[sw->weapon_info_index].damage) );
513 // ------------------------------------------------------------------------------------
514 // shockwave_render()
516 // Draw the shockwave identified by handle
518 // input: objp => pointer to shockwave object
520 void shockwave_render(object *objp)
525 SDL_assert(objp->type == OBJ_SHOCKWAVE);
526 SDL_assert(objp->instance >= 0 && objp->instance < MAX_SHOCKWAVES);
528 sw = &Shockwaves[objp->instance];
530 if( (sw->delay_stamp != -1) && !timestamp_elapsed(sw->delay_stamp)){
534 if ( sw->current_bitmap < 0 ){
539 if(The_mission.flags & MISSION_FLAG_FULLNEB){
540 gr_fog_set(GR_FOGMODE_NONE, 0, 0, 0, -1.0f, -1.0f);
543 g3_rotate_vertex(&p, &sw->pos );
545 gr_set_bitmap(sw->current_bitmap, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, 1.3f, -1, -1);
546 g3_draw_rotated_bitmap(&p, fl_radian(sw->rot_angle), sw->radius, TMAP_FLAG_TEXTURED);
549 // ------------------------------------------------------------------------------------
552 // Call once at the start of each level (mission)
554 void shockwave_level_init()
559 // load in shockwaves
560 for ( i=0; i<MAX_SHOCKWAVE_TYPES; i++ ) {
561 si = &Shockwave_info[i];
562 si->bitmap_id = bm_load_animation( Shockwave_filenames[i], &si->num_frames, &si->fps, 1 );
563 if ( si->bitmap_id < 0 ) {
564 Error(LOCATION, "Could not load %s anim file\n", Shockwave_filenames[i]);
568 list_init(&Shockwave_list);
570 for ( i = 0; i < MAX_SHOCKWAVES; i++ ) {
571 Shockwaves[i].flags = 0;
572 Shockwaves[i].objnum = -1;
575 Shockwave_inited = 1;
578 // ------------------------------------------------------------------------------------
579 // shockwave_level_close()
581 // Call at the close of each level (mission)
582 void shockwave_level_close()
584 if(Shockwave_inited){
585 shockwave_delete_all();
587 Shockwave_inited = 0;
590 // ------------------------------------------------------------------------------------
593 // Called at game-shutdown to
595 void shockwave_close()
599 // ------------------------------------------------------------------------------------
600 // shockwave_move_all()
602 // Simulate all shockwaves in Shockwave_list
604 // input: frametime => time for last frame in ms
606 void shockwave_move_all(float frametime)
608 shockwave *sw, *next;
610 sw = GET_FIRST(&Shockwave_list);
611 while ( sw != &Shockwave_list ) {
613 SDL_assert(sw->objnum != -1);
614 shockwave_move(&Objects[sw->objnum], frametime);
619 // ------------------------------------------------------------------------------------
620 // shockwave_render_all()
623 void shockwave_render_all()
625 shockwave *sw, *next;
627 sw = GET_FIRST(&Shockwave_list);
628 while ( sw != &Shockwave_list ) {
630 SDL_assert(sw->objnum != -1);
631 shockwave_render(&Objects[sw->objnum]);
636 // return the weapon_info_index field for a shockwave
637 int shockwave_weapon_index(int index)
639 return Shockwaves[index].weapon_info_index;
642 // return the maximum radius for specified shockwave
643 float shockwave_max_radius(int index)
645 return Shockwaves[index].outer_radius;
648 void shockwave_page_in()
653 // load in shockwaves
654 for ( i=0; i<MAX_SHOCKWAVE_TYPES; i++ ) {
655 si = &Shockwave_info[i];
656 bm_page_in_texture( si->bitmap_id, si->num_frames );