]> icculus.org git repositories - taylor/freespace2.git/blob - src/cmeasure/cmeasure.cpp
Initial revision
[taylor/freespace2.git] / src / cmeasure / cmeasure.cpp
1 /*
2  * $Logfile: /Freespace2/code/CMeasure/CMeasure.cpp $
3  * $Revision$
4  * $Date$
5  * $Author$
6  *
7  * Counter measures.  Created by Mike Kulas, May 12, 1997.
8  *
9  * $Log$
10  * Revision 1.1  2002/05/03 03:28:08  root
11  * Initial revision
12  *
13  * 
14  * 5     9/05/99 11:25p Mikek
15  * Debug code (only on NDEBUG).  Don't drop countermeasures if
16  * Ai_firing_enabled not set.
17  * 
18  * 4     11/05/98 5:55p Dave
19  * Big pass at reducing #includes
20  * 
21  * 3     10/13/98 9:28a Dave
22  * Started neatening up freespace.h. Many variables renamed and
23  * reorganized. Added AlphaColors.[h,cpp]
24  * 
25  * 2     10/07/98 10:52a Dave
26  * Initial checkin.
27  * 
28  * 1     10/07/98 10:48a Dave
29  * 
30  * 44    4/29/98 9:36p Allender
31  * ingame join tweaks.  added network message for countermeasures
32  * 
33  * 43    4/13/98 5:11p Mike
34  * More improvement to countermeasure code.
35  * 
36  * 42    4/13/98 2:14p Mike
37  * Countermeasure balance testing for Jim.
38  * 
39  * 41    4/10/98 11:02p Mike
40  * Make countermeasures less effective against aspect seekers than against
41  * heat seekers.
42  * Make AI ships match bank with each other when attacking a faraway
43  * target.
44  * Make ships not do silly loop-de-loop sometimes when attacking a faraway
45  * target.
46  * 
47  * 40    3/31/98 5:11p John
48  * Removed demo/save/restore.  Made NDEBUG defined compile.  Removed a
49  * bunch of debug stuff out of player file.  Made model code be able to
50  * unload models and malloc out only however many models are needed.
51  * 
52  * 39    3/17/98 3:49p John
53  * Turned off lighting on counter measures.
54  * 
55  * 38    2/26/98 10:07p Hoffoss
56  * Rewrote state saving and restoring to fix bugs and simplify the code.
57  * 
58  * 37    2/23/98 5:44p Johnson
59  * Resolve build error.
60  * 
61  * 36    2/23/98 4:30p Mike
62  * Make homing missiles detonate after they pass up their target.  Make
63  * countermeasures less effective.
64  * 
65  * 35    2/09/98 8:04p Lawrance
66  * Add objnum to cmeasure struct, correctly set source_objnum
67  * 
68  * 34    2/05/98 11:20p Lawrance
69  * save/restore countermeasure data
70  * 
71  * 33    2/05/98 12:51a Mike
72  * Early asteroid stuff.
73  * 
74  * 32    2/04/98 12:20p Mike
75  * Make countermeasures detonate in a smaller radius.  Make all in radius,
76  * not just homing one, detonate.
77  * 
78  * 31    1/29/98 11:48a John
79  * Added new counter measure rendering as model code.   Made weapons be
80  * able to have impact explosion.
81  * 
82  * 30    1/29/98 11:11a John
83  * Put in code to show dummy counter measure object.
84  * 
85  * 29    1/23/98 5:06p John
86  * Took L out of vertex structure used B (blue) instead.   Took all small
87  * fireballs out of fireball types and used particles instead.  Fixed some
88  * debris explosion things.  Restructured fireball code.   Restructured
89  * some lighting code.   Made dynamic lighting on by default. Made groups
90  * of lasers only cast one light.  Made fireballs not cast light.
91  * 
92  * 28    1/23/98 9:43a Mike
93  * Debug-C to disallow countermeasure firing.
94  * Fix bug in countermeasure tracking by aspect seekers.
95  * 
96  * 27    1/20/98 9:47a Mike
97  * Suppress optimized compiler warnings.
98  * Some secondary weapon work.
99  * 
100  * 26    1/16/98 11:43a Mike
101  * Fix countermeasures.
102  * 
103  * 25    12/30/97 6:44p John
104  * Made g3_Draw_bitmap functions account for aspect of bitmap.
105  * 
106  * 24    11/29/97 2:05p John
107  * made g3_draw_bitmap and g3_draw_rotated bitmap take w&h, not w/2 & h/2,
108  * like they used to incorrectly assume.   Added code to model to read in
109  * thruster radius's.
110  * 
111  * 23    10/27/97 3:24p Lawrance
112  * ensure countermeasures keep their initial velocity
113  * 
114  * 22    9/14/97 4:50p Lawrance
115  * added some demo debugging code
116  * 
117  * 21    9/04/97 5:09p Andsager
118  * implement physics using moment of inertia and mass (from BSPgen).
119  * Added to phys_info struct.  Updated ship_info, polymodel structs.
120  * Updated weapon ($Mass and $Force) and ship ($Mass -> $Density) tables
121  * 
122  * 20    8/20/97 11:09a Mike
123  * Make countermeasure lifetime based on skill level.
124  * 
125  * 19    8/13/97 9:50p Allender
126  * split *_move into *_process_pre and *_process_post functions.
127  * process_pre functions called before object is moved.  _process_post
128  * functions called after object is moved.  Reordered code in ship_post
129  * and weapon_post for multiplayer
130  * 
131  * 18    8/13/97 4:45p Allender
132  * fixed ship_fire_primary and fire_secondary to not take parameter for
133  * determining whether to count ammo or not.  Fixed countermeasure firing
134  * for multiplayer
135  * 
136  * 17    8/13/97 12:06p Lawrance
137  * supporting multiple types of fireball explosions
138  * 
139  * 16    8/11/97 6:03p Mike
140  * Make ships with no shields not claim to have shields in target box.
141  * 
142  * 15    8/08/97 4:29p Allender
143  * countermeasure stuff for multiplayer
144  * 
145  * 14    7/31/97 5:55p John
146  * made so you pass flags to obj_create.
147  * Added new collision code that ignores any pairs that will never
148  * collide.
149  * 
150  * 13    7/15/97 12:03p Andsager
151  * New physics stuff
152  * 
153  * 12    7/11/97 11:54a John
154  * added rotated 3d bitmaps.
155  * 
156  * 11    6/24/97 10:04a Allender
157  * major multiplayer improvements.  Better sequencing before game.
158  * Dealing with weapon/fireball/counter measure objects between
159  * client/host.  
160  * 
161  * 10    6/24/97 12:38a Lawrance
162  * fix minor bug with cycling cmeasure
163  * 
164  * 9     6/05/97 1:37a Lawrance
165  * change syntax of a snd_play()
166  * 
167  * 8     5/22/97 5:45p Mike
168  * Better countermeasure firing, key off availability, specify in
169  * weapons.tbl
170  * 
171  * 7     5/22/97 12:06p Lawrance
172  * include Sound.h for playing sound fx
173  * 
174  * 6     5/22/97 12:04p Lawrance
175  * added soundhook for cmeasure cycle
176  * 
177  * 5     5/15/97 5:05p Mike
178  * In the midst of changing subsystem targetnig from type-based to
179  * pointer-based.
180  * Also allowed you to view a target while dead.
181  * 
182  * 4     5/14/97 4:08p Lawrance
183  * removing my_index from game arrays
184  * 
185  * 3     5/14/97 10:50a Mike
186  * More countermeasure stuff.
187  * 
188  * 2     5/12/97 5:58p Mike
189  * Add countermeasures.
190  * 
191  * 1     5/12/97 2:23p Mike
192  *
193  * $NoKeywords: $
194  */
195
196 #include "pstypes.h"
197 #include "systemvars.h"
198 #include "cmeasure.h"
199 #include "freespace.h"
200 #include "vecmat.h"
201 #include "2d.h"
202 #include "3d.h"
203 #include "model.h"
204 #include "physics.h"
205 #include "floating.h"
206 #include "model.h"
207 #include "ship.h"
208 #include "timer.h"
209 #include "fireballs.h"
210 #include "radar.h"
211 #include "missionparse.h"               // For MAX_SPECIES_NAMES
212 #include "gamesnd.h"
213 #include "objectsnd.h"
214 #include "sound.h"
215 #include "staticrand.h"
216
217 cmeasure_info Cmeasure_info[MAX_CMEASURE_TYPES];
218 cmeasure Cmeasures[MAX_CMEASURES];
219
220 int     Num_cmeasure_types = 0;
221 int     Num_cmeasures = 0;
222 int     Cmeasure_inited = 0;
223 int     Cmeasures_homing_check = 0;
224 int     Countermeasures_enabled = 1;                    //      Debug, set to 0 means no one can fire countermeasures.
225
226 // This will get called at the start of each level.
227 void cmeasure_init()
228 {
229         int i;
230
231         if ( !Cmeasure_inited ) {
232                 Cmeasure_inited = 1;
233
234 /*              // Do all the processing that happens only once
235                 if ( Debris_model < 0 )         {
236                         if (Debris_model>-1)    {
237                                 polymodel * pm;
238                                 pm = model_get(Debris_model);
239                                 Debris_num_submodels = pm->n_models;
240                         }
241                 }
242
243                 for (i=0; i<MAX_SPECIES_NAMES; i++ )    {
244                         Debris_textures[i] = bm_load( Debris_texture_files[i] );
245                         if ( Debris_textures[i] < 0 ) { 
246                                 Warning( LOCATION, "Couldn't load species %d debris\ntexture, '%s'\n", i, Debris_texture_files[i] );
247                         }
248                 }
249 */      
250         }
251
252         // Reset everything between levels
253         Num_cmeasures = 0;
254
255         for (i=0; i<MAX_CMEASURES; i++ )        {
256                 Cmeasures[i].subtype = CMEASURE_UNUSED;
257         }
258                 
259 }
260
261 void cmeasure_render(object * objp)
262 {
263         // JAS TODO: Replace with proper fireball
264         cmeasure                        *cmp;
265         cmeasure_info   *cmip;
266         
267         cmp = &Cmeasures[objp->instance];
268         cmip = &Cmeasure_info[cmp->subtype];
269
270         if ( cmp->subtype == CMEASURE_UNUSED )  {
271                 Int3(); //      Hey, what are we doing in here?
272                 return;
273         }
274
275 //      float                           size = -1.0f;
276 //      vertex                  p;
277 //      g3_rotate_vertex(&p, &objp->pos );
278 //      if ( rand() > RAND_MAX/2 )      {
279 //              gr_set_color( 255, 0, 0 );
280 //      } else {
281 //              gr_set_color( 255, 255, 255 );
282 //      }
283 //      g3_draw_sphere(&p, 100.0f );
284         
285         if ( cmip->model_num > -1 )     {
286                 model_clear_instance(cmip->model_num);
287                 model_render(cmip->model_num, &objp->orient, &objp->pos, MR_NO_LIGHTING );
288         } else {
289                 mprintf(( "Not rendering countermeasure because model_num is negative\n" ));
290         }
291
292
293 /*
294         // JAS TODO: Replace with proper fireball
295         int                             framenum = -1;
296         float                           size = -1.0f;
297         vertex                  p;
298         cmeasure                        *cmp;
299
300         fireball_data   *fd;
301
302         cmp = &Cmeasures[objp->instance];
303         fd = &Fireball_data[FIREBALL_SHIP_EXPLODE1];
304
305         switch (cmp->subtype) {
306         case CMEASURE_UNUSED:
307                 Int3(); //      Hey, what are we doing in here?
308                 break;
309         default:
310                 framenum = (int) (fd->num_frames * Cmeasures[objp->instance].lifeleft*4) % fd->num_frames;
311                 size = objp->radius;
312                 break;
313         }
314
315         Assert(framenum != -1);
316         Assert(size != -1.0f);
317
318         gr_set_bitmap(fd->bitmap_id + framenum);
319         g3_rotate_vertex(&p, &objp->pos );
320         g3_draw_bitmap(&p, 0, size*0.5f, TMAP_FLAG_TEXTURED );
321 */
322 }
323
324 void cmeasure_delete( object * objp )
325 {
326         int num;
327
328         num = objp->instance;
329
330 //      Assert( Cmeasures[num].objnum == OBJ_INDEX(objp));
331
332         Cmeasures[num].subtype = CMEASURE_UNUSED;
333         Num_cmeasures--;
334         Assert( Num_cmeasures >= 0 );
335 }
336
337 // broke cmeasure_move into two functions -- process_pre and process_post (as was done with
338 // all *_move functions).  Nothing to do for process_pre
339
340 void cmeasure_process_pre( object *objp, float frame_time)
341 {
342 }
343
344 void cmeasure_process_post(object * objp, float frame_time)
345 {
346         int num;
347         num = objp->instance;
348         
349 //      Assert( Cmeasures[num].objnum == objnum );
350         cmeasure *cmp = &Cmeasures[num];
351
352         if ( cmp->lifeleft >= 0.0f) {
353                 cmp->lifeleft -= frame_time;
354                 if ( cmp->lifeleft < 0.0f )     {
355                         objp->flags |= OF_SHOULD_BE_DEAD;
356 //                      demo_do_flag_dead(OBJ_INDEX(objp));
357                 }
358         }
359
360 }
361
362 float Skill_level_cmeasure_life_scale[NUM_SKILL_LEVELS] = {3.0f, 2.0f, 1.5f, 1.25f, 1.0f};
363
364 // creates one countermeasure.  A ship fires 1 of these per launch.  rand_val is used
365 // in multiplayer.  If -1, then create a random number.  If non-negative, use this
366 // number for static_rand functions
367 int cmeasure_create( object * source_obj, vector * pos, int cm_type, int rand_val )
368 {
369         int             n, objnum, parent_objnum, arand;
370         object  * obj;
371         ship            *shipp;
372         cmeasure        *cmp;
373         cmeasure_info   *cmeasurep;
374
375 #ifndef NDEBUG
376         if (!Countermeasures_enabled || !Ai_firing_enabled)
377                 return -1;
378 #endif
379
380         Cmeasures_homing_check = 2;             //      Tell homing code to scan everything for two frames.  If only one frame, get sync problems due to objects being created at end of frame!
381
382         parent_objnum = OBJ_INDEX(source_obj);
383
384         Assert( source_obj->type == OBJ_SHIP ); 
385         Assert( source_obj->instance >= 0 && source_obj->instance < MAX_SHIPS );        
386         
387         shipp = &Ships[source_obj->instance];
388
389         if ( Num_cmeasures >= MAX_CMEASURES)
390                 return -1;
391
392         for (n=0; n<MAX_CMEASURES; n++ )        
393                 if ( Cmeasures[n].subtype == CMEASURE_UNUSED)
394                         break;
395         if ( n == MAX_CMEASURES)
396                 return -1;
397
398         nprintf(("Network", "Cmeasure created by %s\n", Ships[source_obj->instance].ship_name));
399
400         cmp = &Cmeasures[n];
401         cmeasurep = &Cmeasure_info[cm_type];
402
403         if ( pos == NULL )
404                 pos = &source_obj->pos;
405
406         objnum = obj_create( OBJ_CMEASURE, parent_objnum, n, &source_obj->orient, pos, 1.0f, OF_RENDERS | OF_PHYSICS );
407         
408         Assert( objnum >= 0 && objnum < MAX_OBJECTS );
409
410         // Create Debris piece n!
411         if ( rand_val == -1 )
412                 arand = myrand();                               // use a random number to get lifeleft, and random vector for displacement from ship
413         else
414                 arand = rand_val;
415
416         cmp->lifeleft = static_randf(arand) * (cmeasurep->life_max - cmeasurep->life_min) / cmeasurep->life_min;
417         if (source_obj->flags & OF_PLAYER_SHIP){
418                 cmp->lifeleft *= Skill_level_cmeasure_life_scale[Game_skill_level];
419         }
420         cmp->lifeleft = cmeasurep->life_min + cmp->lifeleft * (cmeasurep->life_max - cmeasurep->life_min);
421
422         //      cmp->objnum = objnum;
423         cmp->team = shipp->team;
424         cmp->subtype = cm_type;
425         cmp->objnum = objnum;
426         cmp->source_objnum = parent_objnum;
427         cmp->source_sig = Objects[objnum].signature;
428
429         cmp->flags = 0;
430
431         nprintf(("Jim", "Frame %i: Launching countermeasure #%i\n", Framecount, Objects[objnum].signature));
432
433         obj = &Objects[objnum];
434         
435         Num_cmeasures++;
436
437         vector vel, rand_vec;
438
439         vm_vec_scale_add(&vel, &source_obj->phys_info.vel, &source_obj->orient.fvec, -25.0f);
440
441         static_randvec(arand+1, &rand_vec);
442
443         vm_vec_scale_add2(&vel, &rand_vec, 2.0f);
444
445         obj->phys_info.vel = vel;
446
447         vm_vec_zero(&obj->phys_info.rotvel);
448
449         // blow out his reverse thrusters. Or drag, same thing.
450         obj->phys_info.rotdamp = 10000.0f;
451         obj->phys_info.side_slip_time_const = 10000.0f;
452
453         vm_vec_zero(&obj->phys_info.max_vel);           // make so he can't turn on his own VOLITION anymore.
454         obj->phys_info.max_vel.z = -25.0f;
455         vm_vec_copy_scale(&obj->phys_info.desired_vel, &obj->orient.fvec, obj->phys_info.max_vel.z );
456
457         vm_vec_zero(&obj->phys_info.max_rotvel);        // make so he can't change speed on his own VOLITION anymore.
458
459 //      obj->phys_info.flags |= PF_USE_VEL;
460
461         return arand;                                                                           // need to return this value for multiplayer purposes
462 }
463
464 void cmeasure_select_next(object *objp)
465 {
466         ship    *shipp;
467
468         Assert(objp->type == OBJ_SHIP);
469
470         shipp = &Ships[objp->instance];
471         shipp->current_cmeasure++;
472
473         if (shipp->current_cmeasure >= Num_cmeasure_types)
474                 shipp->current_cmeasure = 0;
475
476         //snd_play( &Snds[SND_CMEASURE_CYCLE] );
477
478         mprintf(("Countermeasure type set to %i in frame %i\n", shipp->current_cmeasure, Framecount));
479 }
480