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