]> icculus.org git repositories - taylor/freespace2.git/blob - src/weapon/shockwave.cpp
Initial revision
[taylor/freespace2.git] / src / weapon / shockwave.cpp
1 /*
2  * $Logfile: /Freespace2/code/Weapon/Shockwave.cpp $
3  * $Revision$
4  * $Date$
5  * $Author$
6  *
7  * C file for creating and managing shockwaves
8  *
9  * $Log$
10  * Revision 1.1  2002/05/03 03:28:11  root
11  * Initial revision
12  *
13  * 
14  * 7     9/01/99 10:15a Dave
15  * 
16  * 6     7/18/99 12:32p Dave
17  * Randomly oriented shockwaves.
18  * 
19  * 5     3/23/99 2:29p Andsager
20  * Fix shockwaves for kamikazi and Fred defined.  Collect together
21  * shockwave_create_info struct.
22  * 
23  * 4     2/26/99 4:14p Dave
24  * Put in the ability to have multiple shockwaves for ships.
25  * 
26  * 3     11/05/98 5:55p Dave
27  * Big pass at reducing #includes
28  * 
29  * 2     10/07/98 10:54a Dave
30  * Initial checkin.
31  * 
32  * 1     10/07/98 10:51a Dave
33  * 
34  * 49    5/18/98 3:04p Lawrance
35  * Play shockwave impact sound
36  * 
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
40  * 
41  * 47    4/15/98 10:17p Mike
42  * Training mission #5.
43  * Fix application of subsystem damage.
44  * 
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.
48  * 
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.
53  *  
54  * 
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.
58  * 
59  * 43    3/26/98 5:26p John
60  * added new paging code. nonfunctional.
61  * 
62  * 42    3/04/98 4:11p Lawrance
63  * Have area effects affect asteroids, have asteroids cast an area effect,
64  * fix ship shockwaves
65  * 
66  * 41    2/26/98 10:08p Hoffoss
67  * Rewrote state saving and restoring to fix bugs and simplify the code.
68  * 
69  * 40    2/22/98 12:19p John
70  * Externalized some strings
71  * 
72  * 39    2/20/98 8:32p Lawrance
73  * Make shockwaves affect subsystems more realistically.
74  * 
75  * 38    2/16/98 11:26a Lawrance
76  * ensure shockwave lasts full duration
77  * 
78  * 37    2/16/98 10:04a Lawrance
79  * Fix broken shockwave damage.
80  * 
81  * 36    2/14/98 4:42p Lawrance
82  * pass shockwave object (not parent) to ship_apply_global_damage()
83  * 
84  * 35    2/12/98 11:54p Lawrance
85  * restructure rendering code to use an animation
86  * 
87  * 34    2/11/98 5:38p Dave
88  * Put in a global inited flag for shockwaves.
89  * 
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.
93  * 
94  * 32    1/26/98 11:54a Lawrance
95  * Don't allow Navbuoys to be affected by area-effect damage and blasts.
96  * 
97  * 31    1/22/98 11:43p Lawrance
98  * Play sound effect when player is hit by shockwave.
99  * 
100  * 30    1/14/98 4:31p Dave
101  * Made shockwaves apply damage correctly.
102  * 
103  * 29    1/14/98 2:59p Allender
104  * if shockwave came from a weapon, make the shockwave's parent be the
105  * weapons parent.
106  * 
107  * 28    12/30/97 6:44p John
108  * Made g3_Draw_bitmap functions account for aspect of bitmap.
109  * 
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.
113  * 
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
117  * thruster radius's.
118  * 
119  * 25    11/19/97 10:20p Lawrance
120  * remove ship_shockwave from ship struct, handled in physics now
121  * 
122  * 24    11/16/97 8:52p Andsager
123  * For shockwaves, update physics damping info in physics code.
124  * 
125  * 23    9/18/97 10:48p Lawrance
126  * comment out unused struct member
127  * 
128  * 22    9/18/97 4:08p John
129  * Cleaned up & restructured ship damage stuff.
130  * 
131  * 21    9/17/97 5:12p John
132  * Restructured collision routines.  Probably broke a lot of stuff.
133  * 
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
138  * 
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.
143  * 
144  * 18    8/26/97 3:31p Andsager
145  * scaled shockwave shake duration according to damage
146  * 
147  * 17    8/05/97 1:25a Mike
148  * Make ship death roll be shortened by more damage.
149  * 
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
153  * collide.
154  * 
155  * 15    7/25/97 4:30p Andsager
156  * Save shockwave info
157  * 
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.
162  * 
163  * 13    7/22/97 2:40p Andsager
164  * shockwaves now cause proper rotation of ships
165  * 
166  * 12    7/20/97 7:01p Lawrance
167  * changed names of anim_ files to be more consistent
168  * 
169  * 11    7/18/97 10:52a Lawrance
170  * let player have some control when shockwave hits
171  * 
172  * 10    7/17/97 8:02p Lawrance
173  * tweaking shockwave effect
174  * 
175  * 9     7/16/97 5:51p Lawrance
176  * make shockwaves translucent
177  * 
178  * 8     7/16/97 4:00p Lawrance
179  * render shockwaves by default
180  * 
181  * 7     7/16/97 3:50p Lawrance
182  * render shockwaves first, to fake transparency
183  * 
184  * 6     7/16/97 2:52p Lawrance
185  * make shockwaves objects
186  * 
187  * 5     7/15/97 7:26p Lawrance
188  * make shockwave blast persist over time
189  * 
190  * 4     7/09/97 1:56p Lawrance
191  * add savegame support for shockwaves
192  * 
193  * 3     7/09/97 10:33a Lawrance
194  * make area-effect spheres translucent
195  * 
196  * 2     7/08/97 6:00p Lawrance
197  * implementing shockwaves
198  * 
199  * 1     7/08/97 1:30p Lawrance
200  *
201  * $NoKeywords: $
202  */
203
204 #include "2d.h"
205 #include        "3d.h"
206 #include "weapon.h"
207 #include "ship.h"
208 #include "freespace.h"  // for colors
209 #include "shockwave.h"
210 #include "timer.h"
211 #include "animplay.h"
212 #include "bmpman.h"
213 #include "linklist.h"
214 #include "shiphit.h"
215 #include "gamesnd.h"
216 #include "asteroid.h"
217
218 // -----------------------------------------------------------
219 // Data structures
220 // -----------------------------------------------------------
221
222 // -----------------------------------------------------------
223 // Module-wide globals
224 // -----------------------------------------------------------
225
226 static char *Shockwave_filenames[MAX_SHOCKWAVE_TYPES] = 
227 {
228 //XSTR:OFF
229         "shockwave01"
230 //XSTR:ON
231 };
232
233 shockwave                       Shockwaves[MAX_SHOCKWAVES];
234 shockwave_info  Shockwave_info[MAX_SHOCKWAVE_TYPES];
235
236 shockwave                       Shockwave_list;
237 int                                     Shockwave_inited = 0;
238
239 // -----------------------------------------------------------
240 // Function macros
241 // -----------------------------------------------------------
242 #define SW_INDEX(sw) (sw-Shockwaves)
243         
244 // -----------------------------------------------------------
245 // Externals
246 // -----------------------------------------------------------
247 extern int Show_area_effect;
248
249 // ------------------------------------------------------------------------------------
250 // shockwave_create()
251 //
252 // Call to create a shockwave
253 //
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
264 //
265 //      return: success                 =>      object number of shockwave
266 //                              failure                 =>      -1
267 //
268 int shockwave_create(int parent_objnum, vector *pos, shockwave_create_info *sci, int flag, int delay)
269 {
270         int                             i, objnum, real_parent;
271         shockwave               *sw;
272         shockwave_info  *si;
273         matrix                  orient;
274
275         for ( i = 0; i < MAX_SHOCKWAVES; i++ ) {
276                 if ( !(Shockwaves[i].flags & SW_USED) ){
277                         break;
278                 }
279         }
280
281         if ( i == MAX_SHOCKWAVES ) {
282                 return -1;
283         }
284
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;
288         } else {
289                 real_parent = parent_objnum;
290         }
291
292         sw = &Shockwaves[i];
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;
299         sw->radius = 1.0f;
300         sw->pos = *pos;
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;
304
305         sw->time_elapsed=0.0f;
306         sw->delay_stamp = delay;
307
308         sw->rot_angle = sci->rot_angle;
309
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;
313
314         if ( Objects[parent_objnum].type == OBJ_WEAPON ) {              
315                 sw->weapon_info_index = Weapons[Objects[parent_objnum].instance].weapon_info_index;
316         }
317         else {          
318                 sw->weapon_info_index = -1;
319         }
320
321         orient = vmd_identity_matrix;
322
323         objnum = obj_create( OBJ_SHOCKWAVE, real_parent, i, &orient, &sw->pos, sw->outer_radius, OF_RENDERS );
324
325         if ( objnum == -1 ){
326                 Int3();
327         }
328
329         sw->objnum = objnum;
330
331         list_append(&Shockwave_list, sw);
332
333         return objnum;
334 }
335
336 // ------------------------------------------------------------------------------------
337 // shockwave_delete()
338 //
339 // Delete a shockwave
340 //
341 //      input:  object *objp    =>              pointer to shockwave object
342 //
343 void shockwave_delete(object *objp)
344 {
345         Assert(objp->type == OBJ_SHOCKWAVE);
346         Assert(objp->instance >= 0 && objp->instance < MAX_SHOCKWAVES);
347
348         Shockwaves[objp->instance].flags = 0;
349         Shockwaves[objp->instance].objnum = -1; 
350         list_remove(&Shockwave_list, &Shockwaves[objp->instance]);
351 }
352
353 // ------------------------------------------------------------------------------------
354 // shockwave_delete_all()
355 //
356 //
357 void shockwave_delete_all()
358 {
359         shockwave       *sw, *next;
360         
361         sw = GET_FIRST(&Shockwave_list);
362         while ( sw != &Shockwave_list ) {
363                 next = sw->next;
364                 Assert(sw->objnum != -1);
365                 Objects[sw->objnum].flags |= OF_SHOULD_BE_DEAD;
366                 sw = next;
367         }
368 }
369
370 // Set the correct frame of animation for the shockwave
371 void shockwave_set_framenum(int index)
372 {
373         int                             framenum;
374         shockwave               *sw;
375         shockwave_info  *si;
376
377         sw = &Shockwaves[index];
378         si = &Shockwave_info[sw->shockwave_info_index];
379
380         framenum = fl2i(sw->time_elapsed / sw->total_time * si->num_frames + 0.5);
381
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;
386         }
387
388         if ( framenum < 0 ) {
389                 framenum = 0;
390         }
391
392         sw->current_bitmap = si->bitmap_id + framenum;
393 }
394
395 // ------------------------------------------------------------------------------------
396 // shockwave_move()
397 //
398 //      Simulate a single shockwave.  If the shockwave radius exceeds outer_radius, then
399 // delete the shockwave.
400 //
401 //      input:          ojbp                    =>              object pointer that points to shockwave object
402 //                                      frametime       =>              time to simulate shockwave
403 //
404 void shockwave_move(object *shockwave_objp, float frametime)
405 {
406         shockwave       *sw;
407         object          *objp;
408         float                   blast,damage;
409         int                     i;
410         
411         Assert(shockwave_objp->type == OBJ_SHOCKWAVE);
412         Assert(shockwave_objp->instance  >= 0 && shockwave_objp->instance < MAX_SHOCKWAVES);
413         sw = &Shockwaves[shockwave_objp->instance];
414
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;
419                 } else {
420                         return;
421                 }
422         }
423
424         sw->time_elapsed += frametime;
425 /*
426         if ( sw->time_elapsed > sw->total_time ) {
427                 shockwave_objp->flags |= OF_SHOULD_BE_DEAD;
428         }
429 */
430
431         shockwave_set_framenum(shockwave_objp->instance);
432                 
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;
437                 return;
438         }
439
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) ) {
443                         continue;
444                 }
445         
446                 if ( objp->type == OBJ_SHIP ) {
447                         // don't blast navbuoys
448                         if ( ship_get_SIF(objp->instance) & SIF_NAVBUOY ) {
449                                 continue;
450                         }
451                 }
452
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] ){
456                                 break;
457                         }
458                 }
459                 if ( i < sw->num_objs_hit ){
460                         continue;
461                 }
462
463                 if ( weapon_area_calc_damage(objp, &sw->pos, sw->inner_radius, sw->outer_radius, sw->blast, sw->damage, &blast, &damage, sw->radius) == -1 ){
464                         continue;
465                 }
466
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) {
470                         sw->num_objs_hit--;
471                 }
472
473                 switch(objp->type) {
474                 case OBJ_SHIP:
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);
478                         break;
479                 case OBJ_ASTEROID:
480                         asteroid_hit(objp, NULL, NULL, damage);
481                         break;
482                 default:
483                         Int3();
484                         break;
485                 }
486
487
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) );
491                 }
492
493         }       // end for
494 }
495
496 // ------------------------------------------------------------------------------------
497 // shockwave_render()
498 //
499 //      Draw the shockwave identified by handle
500 //
501 //      input:  objp    =>              pointer to shockwave object
502 //
503 void shockwave_render(object *objp)
504 {
505         shockwave               *sw;
506         shockwave_info  *si;
507         vertex                  p;
508
509         Assert(objp->type == OBJ_SHOCKWAVE);
510         Assert(objp->instance >= 0 && objp->instance < MAX_SHOCKWAVES);
511
512         sw = &Shockwaves[objp->instance];
513         si = &Shockwave_info[sw->shockwave_info_index];
514
515         if( (sw->delay_stamp != -1) && !timestamp_elapsed(sw->delay_stamp)){
516                 return;
517         }
518
519         if ( sw->current_bitmap < 0 ){
520                 return;
521         }
522
523         // turn off fogging
524         if(The_mission.flags & MISSION_FLAG_FULLNEB){
525                 gr_fog_set(GR_FOGMODE_NONE, 0, 0, 0);
526         }
527
528         g3_rotate_vertex(&p, &sw->pos );
529
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);   
532 }
533
534 // ------------------------------------------------------------------------------------
535 // shockwave_init()
536 //
537 // Call once at the start of each level (mission)
538 //
539 void shockwave_level_init()
540 {
541         int i;  
542         shockwave_info  *si;
543
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]);
550                 }
551         }
552         
553         list_init(&Shockwave_list);
554
555         for ( i = 0; i < MAX_SHOCKWAVES; i++ ) {
556                 Shockwaves[i].flags = 0;
557                 Shockwaves[i].objnum = -1;
558         }
559
560         Shockwave_inited = 1;
561 }
562
563 // ------------------------------------------------------------------------------------
564 // shockwave_level_close()
565 //
566 // Call at the close of each level (mission)
567 void shockwave_level_close()
568 {
569         if(Shockwave_inited){
570                 shockwave_delete_all();         
571         }
572         Shockwave_inited = 0;
573 }
574
575 // ------------------------------------------------------------------------------------
576 // shockwave_close()
577 //
578 //      Called at game-shutdown to 
579 //
580 void shockwave_close()
581 {
582 }
583
584 // ------------------------------------------------------------------------------------
585 // shockwave_move_all()
586 //
587 //      Simulate all shockwaves in Shockwave_list
588 //
589 //      input:  frametime       =>              time for last frame in ms
590 //
591 void shockwave_move_all(float frametime)
592 {
593         shockwave       *sw, *next;
594         
595         sw = GET_FIRST(&Shockwave_list);
596         while ( sw != &Shockwave_list ) {
597                 next = sw->next;
598                 Assert(sw->objnum != -1);
599                 shockwave_move(&Objects[sw->objnum], frametime);
600                 sw = next;
601         }
602 }
603
604 // ------------------------------------------------------------------------------------
605 // shockwave_render_all()
606 //
607 //
608 void shockwave_render_all()
609 {
610         shockwave       *sw, *next;
611         
612         sw = GET_FIRST(&Shockwave_list);
613         while ( sw != &Shockwave_list ) {
614                 next = sw->next;
615                 Assert(sw->objnum != -1);
616                 shockwave_render(&Objects[sw->objnum]);
617                 sw = next;
618         }
619 }
620
621 // return the weapon_info_index field for a shockwave
622 int shockwave_weapon_index(int index)
623 {
624         return Shockwaves[index].weapon_info_index;
625 }
626
627 // return the maximum radius for specified shockwave
628 float   shockwave_max_radius(int index)
629 {
630         return Shockwaves[index].outer_radius;
631 }
632
633 void shockwave_page_in()
634 {
635         int i;
636         shockwave_info  *si;
637
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 );
642         }
643
644 }