]> icculus.org git repositories - taylor/freespace2.git/blob - src/weapon/shockwave.cpp
added copyright header
[taylor/freespace2.git] / src / weapon / shockwave.cpp
1 /*
2  * Copyright (C) Volition, Inc. 1999.  All rights reserved.
3  *
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
6  * the source.
7  */
8
9 /*
10  * $Logfile: /Freespace2/code/Weapon/Shockwave.cpp $
11  * $Revision$
12  * $Date$
13  * $Author$
14  *
15  * C file for creating and managing shockwaves
16  *
17  * $Log$
18  * Revision 1.3  2002/06/09 04:41:29  relnev
19  * added copyright header
20  *
21  * Revision 1.2  2002/05/07 03:16:53  theoddone33
22  * The Great Newline Fix
23  *
24  * Revision 1.1.1.1  2002/05/03 03:28:11  root
25  * Initial import.
26  *
27  * 
28  * 7     9/01/99 10:15a Dave
29  * 
30  * 6     7/18/99 12:32p Dave
31  * Randomly oriented shockwaves.
32  * 
33  * 5     3/23/99 2:29p Andsager
34  * Fix shockwaves for kamikazi and Fred defined.  Collect together
35  * shockwave_create_info struct.
36  * 
37  * 4     2/26/99 4:14p Dave
38  * Put in the ability to have multiple shockwaves for ships.
39  * 
40  * 3     11/05/98 5:55p Dave
41  * Big pass at reducing #includes
42  * 
43  * 2     10/07/98 10:54a Dave
44  * Initial checkin.
45  * 
46  * 1     10/07/98 10:51a Dave
47  * 
48  * 49    5/18/98 3:04p Lawrance
49  * Play shockwave impact sound
50  * 
51  * 48    5/18/98 12:59a Lawrance
52  * Replace shockwave impact sound with a new "whoosh" sound that
53  * originates from the shockwave center
54  * 
55  * 47    4/15/98 10:17p Mike
56  * Training mission #5.
57  * Fix application of subsystem damage.
58  * 
59  * 46    4/09/98 7:58p John
60  * Cleaned up tmapper code a bit.   Put NDEBUG around some ndebug stuff.
61  * Took out XPARENT flag settings in all the alpha-blended texture stuff.
62  * 
63  * 45    3/31/98 5:19p John
64  * Removed demo/save/restore.  Made NDEBUG defined compile.  Removed a
65  * bunch of debug stuff out of player file.  Made model code be able to
66  * unload models and malloc out only however many models are needed.
67  *  
68  * 
69  * 44    3/30/98 4:02p John
70  * Made machines with < 32 MB of RAM use every other frame of certain
71  * bitmaps.   Put in code to keep track of how much RAM we've malloc'd.
72  * 
73  * 43    3/26/98 5:26p John
74  * added new paging code. nonfunctional.
75  * 
76  * 42    3/04/98 4:11p Lawrance
77  * Have area effects affect asteroids, have asteroids cast an area effect,
78  * fix ship shockwaves
79  * 
80  * 41    2/26/98 10:08p Hoffoss
81  * Rewrote state saving and restoring to fix bugs and simplify the code.
82  * 
83  * 40    2/22/98 12:19p John
84  * Externalized some strings
85  * 
86  * 39    2/20/98 8:32p Lawrance
87  * Make shockwaves affect subsystems more realistically.
88  * 
89  * 38    2/16/98 11:26a Lawrance
90  * ensure shockwave lasts full duration
91  * 
92  * 37    2/16/98 10:04a Lawrance
93  * Fix broken shockwave damage.
94  * 
95  * 36    2/14/98 4:42p Lawrance
96  * pass shockwave object (not parent) to ship_apply_global_damage()
97  * 
98  * 35    2/12/98 11:54p Lawrance
99  * restructure rendering code to use an animation
100  * 
101  * 34    2/11/98 5:38p Dave
102  * Put in a global inited flag for shockwaves.
103  * 
104  * 33    2/02/98 8:47a Andsager
105  * Ship death area damage applied as instantaneous damage for small ships
106  * and shockwaves for large (>50 radius) ships.
107  * 
108  * 32    1/26/98 11:54a Lawrance
109  * Don't allow Navbuoys to be affected by area-effect damage and blasts.
110  * 
111  * 31    1/22/98 11:43p Lawrance
112  * Play sound effect when player is hit by shockwave.
113  * 
114  * 30    1/14/98 4:31p Dave
115  * Made shockwaves apply damage correctly.
116  * 
117  * 29    1/14/98 2:59p Allender
118  * if shockwave came from a weapon, make the shockwave's parent be the
119  * weapons parent.
120  * 
121  * 28    12/30/97 6:44p John
122  * Made g3_Draw_bitmap functions account for aspect of bitmap.
123  * 
124  * 27    12/02/97 4:00p John
125  * Added first rev of thruster glow, along with variable levels of
126  * translucency, which retquired some restructing of palman.
127  * 
128  * 26    11/29/97 2:06p John
129  * made g3_draw_bitmap and g3_draw_rotated bitmap take w&h, not w/2 & h/2,
130  * like they used to incorrectly assume.   Added code to model to read in
131  * thruster radius's.
132  * 
133  * 25    11/19/97 10:20p Lawrance
134  * remove ship_shockwave from ship struct, handled in physics now
135  * 
136  * 24    11/16/97 8:52p Andsager
137  * For shockwaves, update physics damping info in physics code.
138  * 
139  * 23    9/18/97 10:48p Lawrance
140  * comment out unused struct member
141  * 
142  * 22    9/18/97 4:08p John
143  * Cleaned up & restructured ship damage stuff.
144  * 
145  * 21    9/17/97 5:12p John
146  * Restructured collision routines.  Probably broke a lot of stuff.
147  * 
148  * 20    9/04/97 5:10p Andsager
149  * implement physics using moment of inertia and mass (from BSPgen).
150  * Added to phys_info struct.  Updated ship_info, polymodel structs.
151  * Updated weapon ($Mass and $Force) and ship ($Mass -> $Density) tables
152  * 
153  * 19    9/03/97 4:33p John
154  * changed bmpman to only accept ani and pcx's.  made passing .pcx or .ani
155  * to bm_load functions not needed.   Made bmpman keep track of palettes
156  * for bitmaps not mapped into game palettes.
157  * 
158  * 18    8/26/97 3:31p Andsager
159  * scaled shockwave shake duration according to damage
160  * 
161  * 17    8/05/97 1:25a Mike
162  * Make ship death roll be shortened by more damage.
163  * 
164  * 16    7/31/97 5:55p John
165  * made so you pass flags to obj_create.
166  * Added new collision code that ignores any pairs that will never
167  * collide.
168  * 
169  * 15    7/25/97 4:30p Andsager
170  * Save shockwave info
171  * 
172  * 14    7/25/97 1:04p Andsager
173  * Modified physics flag PF_REDUCED_DAMP for damping when object is hit.
174  * Flag is now set in physics_apply_whack/shock and turned off in
175  * physics_sim_vel.  Weapons should not directly set this flag.
176  * 
177  * 13    7/22/97 2:40p Andsager
178  * shockwaves now cause proper rotation of ships
179  * 
180  * 12    7/20/97 7:01p Lawrance
181  * changed names of anim_ files to be more consistent
182  * 
183  * 11    7/18/97 10:52a Lawrance
184  * let player have some control when shockwave hits
185  * 
186  * 10    7/17/97 8:02p Lawrance
187  * tweaking shockwave effect
188  * 
189  * 9     7/16/97 5:51p Lawrance
190  * make shockwaves translucent
191  * 
192  * 8     7/16/97 4:00p Lawrance
193  * render shockwaves by default
194  * 
195  * 7     7/16/97 3:50p Lawrance
196  * render shockwaves first, to fake transparency
197  * 
198  * 6     7/16/97 2:52p Lawrance
199  * make shockwaves objects
200  * 
201  * 5     7/15/97 7:26p Lawrance
202  * make shockwave blast persist over time
203  * 
204  * 4     7/09/97 1:56p Lawrance
205  * add savegame support for shockwaves
206  * 
207  * 3     7/09/97 10:33a Lawrance
208  * make area-effect spheres translucent
209  * 
210  * 2     7/08/97 6:00p Lawrance
211  * implementing shockwaves
212  * 
213  * 1     7/08/97 1:30p Lawrance
214  *
215  * $NoKeywords: $
216  */
217
218 #include "2d.h"
219 #include        "3d.h"
220 #include "weapon.h"
221 #include "ship.h"
222 #include "freespace.h"  // for colors
223 #include "shockwave.h"
224 #include "timer.h"
225 #include "animplay.h"
226 #include "bmpman.h"
227 #include "linklist.h"
228 #include "shiphit.h"
229 #include "gamesnd.h"
230 #include "asteroid.h"
231
232 // -----------------------------------------------------------
233 // Data structures
234 // -----------------------------------------------------------
235
236 // -----------------------------------------------------------
237 // Module-wide globals
238 // -----------------------------------------------------------
239
240 static char *Shockwave_filenames[MAX_SHOCKWAVE_TYPES] = 
241 {
242 //XSTR:OFF
243         "shockwave01"
244 //XSTR:ON
245 };
246
247 shockwave                       Shockwaves[MAX_SHOCKWAVES];
248 shockwave_info  Shockwave_info[MAX_SHOCKWAVE_TYPES];
249
250 shockwave                       Shockwave_list;
251 int                                     Shockwave_inited = 0;
252
253 // -----------------------------------------------------------
254 // Function macros
255 // -----------------------------------------------------------
256 #define SW_INDEX(sw) (sw-Shockwaves)
257         
258 // -----------------------------------------------------------
259 // Externals
260 // -----------------------------------------------------------
261 extern int Show_area_effect;
262
263 // ------------------------------------------------------------------------------------
264 // shockwave_create()
265 //
266 // Call to create a shockwave
267 //
268 //      input:  parent_objnum   => object number of object spawning the shockwave
269 //                              pos                             =>      vector specifing global position of shockwave center
270 //                              speed                           =>      speed at which shockwave expands (m/s)
271 //                              inner_radius    =>      radius at which damage applied is at maximum
272 //                              outer_radius    => damage decreases linearly to zero from inner_radius to
273 //                                                                              outer_radius.  Outside outer_radius, damage is 0.
274 //                              damage                  =>      the maximum damage (ie within inner_radius)
275 //                              blast                           => the maximux blast (within inner_radius)
276 //                              sw_flag                 => indicates whether shockwave is from weapon or ship explosion
277 //                              delay          => delay in ms before the shockwave actually starts
278 //
279 //      return: success                 =>      object number of shockwave
280 //                              failure                 =>      -1
281 //
282 int shockwave_create(int parent_objnum, vector *pos, shockwave_create_info *sci, int flag, int delay)
283 {
284         int                             i, objnum, real_parent;
285         shockwave               *sw;
286         shockwave_info  *si;
287         matrix                  orient;
288
289         for ( i = 0; i < MAX_SHOCKWAVES; i++ ) {
290                 if ( !(Shockwaves[i].flags & SW_USED) ){
291                         break;
292                 }
293         }
294
295         if ( i == MAX_SHOCKWAVES ) {
296                 return -1;
297         }
298
299         // real_parent is the guy who caused this shockwave to happen
300         if ( Objects[parent_objnum].type == OBJ_WEAPON ){
301                 real_parent = Objects[parent_objnum].parent;
302         } else {
303                 real_parent = parent_objnum;
304         }
305
306         sw = &Shockwaves[i];
307         sw->flags = (SW_USED | flag);
308         sw->speed = sci->speed;
309         sw->inner_radius = sci->inner_rad;
310         sw->outer_radius = sci->outer_rad;
311         sw->damage = sci->damage;
312         sw->blast = sci->blast;
313         sw->radius = 1.0f;
314         sw->pos = *pos;
315         sw->num_objs_hit = 0;
316         sw->shockwave_info_index=0;             // only one type for now... type could be passed is as a parameter
317         sw->current_bitmap=-1;
318
319         sw->time_elapsed=0.0f;
320         sw->delay_stamp = delay;
321
322         sw->rot_angle = sci->rot_angle;
323
324         si = &Shockwave_info[sw->shockwave_info_index];
325 //      sw->total_time = i2fl(si->num_frames) / si->fps;        // in seconds
326         sw->total_time = sw->outer_radius / sw->speed;
327
328         if ( Objects[parent_objnum].type == OBJ_WEAPON ) {              
329                 sw->weapon_info_index = Weapons[Objects[parent_objnum].instance].weapon_info_index;
330         }
331         else {          
332                 sw->weapon_info_index = -1;
333         }
334
335         orient = vmd_identity_matrix;
336
337         objnum = obj_create( OBJ_SHOCKWAVE, real_parent, i, &orient, &sw->pos, sw->outer_radius, OF_RENDERS );
338
339         if ( objnum == -1 ){
340                 Int3();
341         }
342
343         sw->objnum = objnum;
344
345         list_append(&Shockwave_list, sw);
346
347         return objnum;
348 }
349
350 // ------------------------------------------------------------------------------------
351 // shockwave_delete()
352 //
353 // Delete a shockwave
354 //
355 //      input:  object *objp    =>              pointer to shockwave object
356 //
357 void shockwave_delete(object *objp)
358 {
359         Assert(objp->type == OBJ_SHOCKWAVE);
360         Assert(objp->instance >= 0 && objp->instance < MAX_SHOCKWAVES);
361
362         Shockwaves[objp->instance].flags = 0;
363         Shockwaves[objp->instance].objnum = -1; 
364         list_remove(&Shockwave_list, &Shockwaves[objp->instance]);
365 }
366
367 // ------------------------------------------------------------------------------------
368 // shockwave_delete_all()
369 //
370 //
371 void shockwave_delete_all()
372 {
373         shockwave       *sw, *next;
374         
375         sw = GET_FIRST(&Shockwave_list);
376         while ( sw != &Shockwave_list ) {
377                 next = sw->next;
378                 Assert(sw->objnum != -1);
379                 Objects[sw->objnum].flags |= OF_SHOULD_BE_DEAD;
380                 sw = next;
381         }
382 }
383
384 // Set the correct frame of animation for the shockwave
385 void shockwave_set_framenum(int index)
386 {
387         int                             framenum;
388         shockwave               *sw;
389         shockwave_info  *si;
390
391         sw = &Shockwaves[index];
392         si = &Shockwave_info[sw->shockwave_info_index];
393
394         framenum = fl2i(sw->time_elapsed / sw->total_time * si->num_frames + 0.5);
395
396         // ensure we don't go past the number of frames of animation
397         if ( framenum > (si->num_frames-1) ) {
398                 framenum = (si->num_frames-1);
399                 Objects[sw->objnum].flags |= OF_SHOULD_BE_DEAD;
400         }
401
402         if ( framenum < 0 ) {
403                 framenum = 0;
404         }
405
406         sw->current_bitmap = si->bitmap_id + framenum;
407 }
408
409 // ------------------------------------------------------------------------------------
410 // shockwave_move()
411 //
412 //      Simulate a single shockwave.  If the shockwave radius exceeds outer_radius, then
413 // delete the shockwave.
414 //
415 //      input:          ojbp                    =>              object pointer that points to shockwave object
416 //                                      frametime       =>              time to simulate shockwave
417 //
418 void shockwave_move(object *shockwave_objp, float frametime)
419 {
420         shockwave       *sw;
421         object          *objp;
422         float                   blast,damage;
423         int                     i;
424         
425         Assert(shockwave_objp->type == OBJ_SHOCKWAVE);
426         Assert(shockwave_objp->instance  >= 0 && shockwave_objp->instance < MAX_SHOCKWAVES);
427         sw = &Shockwaves[shockwave_objp->instance];
428
429         // if the shockwave has a delay on it
430         if(sw->delay_stamp != -1){
431                 if(timestamp_elapsed(sw->delay_stamp)){
432                         sw->delay_stamp = -1;
433                 } else {
434                         return;
435                 }
436         }
437
438         sw->time_elapsed += frametime;
439 /*
440         if ( sw->time_elapsed > sw->total_time ) {
441                 shockwave_objp->flags |= OF_SHOULD_BE_DEAD;
442         }
443 */
444
445         shockwave_set_framenum(shockwave_objp->instance);
446                 
447         sw->radius += (frametime * sw->speed);
448         if ( sw->radius > sw->outer_radius ) {
449                 sw->radius = sw->outer_radius;
450                 shockwave_objp->flags |= OF_SHOULD_BE_DEAD;
451                 return;
452         }
453
454         // blast ships and asteroids
455         for ( objp = GET_FIRST(&obj_used_list); objp !=END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) {
456                 if ( (objp->type != OBJ_SHIP) && (objp->type != OBJ_ASTEROID) ) {
457                         continue;
458                 }
459         
460                 if ( objp->type == OBJ_SHIP ) {
461                         // don't blast navbuoys
462                         if ( ship_get_SIF(objp->instance) & SIF_NAVBUOY ) {
463                                 continue;
464                         }
465                 }
466
467                 // only apply damage to a ship once from a shockwave
468                 for ( i = 0; i < sw->num_objs_hit; i++ ) {
469                         if ( objp->signature == sw->obj_sig_hitlist[i] ){
470                                 break;
471                         }
472                 }
473                 if ( i < sw->num_objs_hit ){
474                         continue;
475                 }
476
477                 if ( weapon_area_calc_damage(objp, &sw->pos, sw->inner_radius, sw->outer_radius, sw->blast, sw->damage, &blast, &damage, sw->radius) == -1 ){
478                         continue;
479                 }
480
481                 // okay, we have damage applied, record the object signature so we don't repeatedly apply damage
482                 Assert(sw->num_objs_hit < SW_MAX_OBJS_HIT);
483                 if ( sw->num_objs_hit >= SW_MAX_OBJS_HIT) {
484                         sw->num_objs_hit--;
485                 }
486
487                 switch(objp->type) {
488                 case OBJ_SHIP:
489                         sw->obj_sig_hitlist[sw->num_objs_hit++] = objp->signature;
490                         ship_apply_global_damage(objp, shockwave_objp, &sw->pos, damage );
491                         weapon_area_apply_blast(NULL, objp, &sw->pos, blast, 1);
492                         break;
493                 case OBJ_ASTEROID:
494                         asteroid_hit(objp, NULL, NULL, damage);
495                         break;
496                 default:
497                         Int3();
498                         break;
499                 }
500
501
502                 // If this shockwave hit the player, play shockwave impact sound
503                 if ( objp == Player_obj ) {
504                         snd_play( &Snds[SND_SHOCKWAVE_IMPACT], 0.0f, max(0.4f, damage/Weapon_info[sw->weapon_info_index].damage) );
505                 }
506
507         }       // end for
508 }
509
510 // ------------------------------------------------------------------------------------
511 // shockwave_render()
512 //
513 //      Draw the shockwave identified by handle
514 //
515 //      input:  objp    =>              pointer to shockwave object
516 //
517 void shockwave_render(object *objp)
518 {
519         shockwave               *sw;
520         shockwave_info  *si;
521         vertex                  p;
522
523         Assert(objp->type == OBJ_SHOCKWAVE);
524         Assert(objp->instance >= 0 && objp->instance < MAX_SHOCKWAVES);
525
526         sw = &Shockwaves[objp->instance];
527         si = &Shockwave_info[sw->shockwave_info_index];
528
529         if( (sw->delay_stamp != -1) && !timestamp_elapsed(sw->delay_stamp)){
530                 return;
531         }
532
533         if ( sw->current_bitmap < 0 ){
534                 return;
535         }
536
537         // turn off fogging
538         if(The_mission.flags & MISSION_FLAG_FULLNEB){
539                 gr_fog_set(GR_FOGMODE_NONE, 0, 0, 0);
540         }
541
542         g3_rotate_vertex(&p, &sw->pos );
543
544         gr_set_bitmap(sw->current_bitmap, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, 1.3f );
545         g3_draw_rotated_bitmap(&p, fl_radian(sw->rot_angle), sw->radius, TMAP_FLAG_TEXTURED);   
546 }
547
548 // ------------------------------------------------------------------------------------
549 // shockwave_init()
550 //
551 // Call once at the start of each level (mission)
552 //
553 void shockwave_level_init()
554 {
555         int i;  
556         shockwave_info  *si;
557
558         // load in shockwaves
559         for ( i=0; i<MAX_SHOCKWAVE_TYPES; i++ ) {
560                 si = &Shockwave_info[i];
561                 si->bitmap_id   = bm_load_animation( Shockwave_filenames[i], &si->num_frames, &si->fps, 1 );
562                 if ( si->bitmap_id < 0 ) {
563                         Error(LOCATION, "Could not load %s anim file\n", Shockwave_filenames[i]);
564                 }
565         }
566         
567         list_init(&Shockwave_list);
568
569         for ( i = 0; i < MAX_SHOCKWAVES; i++ ) {
570                 Shockwaves[i].flags = 0;
571                 Shockwaves[i].objnum = -1;
572         }
573
574         Shockwave_inited = 1;
575 }
576
577 // ------------------------------------------------------------------------------------
578 // shockwave_level_close()
579 //
580 // Call at the close of each level (mission)
581 void shockwave_level_close()
582 {
583         if(Shockwave_inited){
584                 shockwave_delete_all();         
585         }
586         Shockwave_inited = 0;
587 }
588
589 // ------------------------------------------------------------------------------------
590 // shockwave_close()
591 //
592 //      Called at game-shutdown to 
593 //
594 void shockwave_close()
595 {
596 }
597
598 // ------------------------------------------------------------------------------------
599 // shockwave_move_all()
600 //
601 //      Simulate all shockwaves in Shockwave_list
602 //
603 //      input:  frametime       =>              time for last frame in ms
604 //
605 void shockwave_move_all(float frametime)
606 {
607         shockwave       *sw, *next;
608         
609         sw = GET_FIRST(&Shockwave_list);
610         while ( sw != &Shockwave_list ) {
611                 next = sw->next;
612                 Assert(sw->objnum != -1);
613                 shockwave_move(&Objects[sw->objnum], frametime);
614                 sw = next;
615         }
616 }
617
618 // ------------------------------------------------------------------------------------
619 // shockwave_render_all()
620 //
621 //
622 void shockwave_render_all()
623 {
624         shockwave       *sw, *next;
625         
626         sw = GET_FIRST(&Shockwave_list);
627         while ( sw != &Shockwave_list ) {
628                 next = sw->next;
629                 Assert(sw->objnum != -1);
630                 shockwave_render(&Objects[sw->objnum]);
631                 sw = next;
632         }
633 }
634
635 // return the weapon_info_index field for a shockwave
636 int shockwave_weapon_index(int index)
637 {
638         return Shockwaves[index].weapon_info_index;
639 }
640
641 // return the maximum radius for specified shockwave
642 float   shockwave_max_radius(int index)
643 {
644         return Shockwaves[index].outer_radius;
645 }
646
647 void shockwave_page_in()
648 {
649         int i;
650         shockwave_info  *si;
651
652         // load in shockwaves
653         for ( i=0; i<MAX_SHOCKWAVE_TYPES; i++ ) {
654                 si = &Shockwave_info[i];
655                 bm_page_in_texture( si->bitmap_id, si->num_frames );
656         }
657
658 }