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/CMeasure/CMeasure.cpp $
15 * Counter measures. Created by Mike Kulas, May 12, 1997.
18 * Revision 1.2 2002/06/09 04:41:15 relnev
19 * added copyright header
21 * Revision 1.1.1.1 2002/05/03 03:28:08 root
25 * 5 9/05/99 11:25p Mikek
26 * Debug code (only on NDEBUG). Don't drop countermeasures if
27 * Ai_firing_enabled not set.
29 * 4 11/05/98 5:55p Dave
30 * Big pass at reducing #includes
32 * 3 10/13/98 9:28a Dave
33 * Started neatening up freespace.h. Many variables renamed and
34 * reorganized. Added AlphaColors.[h,cpp]
36 * 2 10/07/98 10:52a Dave
39 * 1 10/07/98 10:48a Dave
41 * 44 4/29/98 9:36p Allender
42 * ingame join tweaks. added network message for countermeasures
44 * 43 4/13/98 5:11p Mike
45 * More improvement to countermeasure code.
47 * 42 4/13/98 2:14p Mike
48 * Countermeasure balance testing for Jim.
50 * 41 4/10/98 11:02p Mike
51 * Make countermeasures less effective against aspect seekers than against
53 * Make AI ships match bank with each other when attacking a faraway
55 * Make ships not do silly loop-de-loop sometimes when attacking a faraway
58 * 40 3/31/98 5:11p John
59 * Removed demo/save/restore. Made NDEBUG defined compile. Removed a
60 * bunch of debug stuff out of player file. Made model code be able to
61 * unload models and malloc out only however many models are needed.
63 * 39 3/17/98 3:49p John
64 * Turned off lighting on counter measures.
66 * 38 2/26/98 10:07p Hoffoss
67 * Rewrote state saving and restoring to fix bugs and simplify the code.
69 * 37 2/23/98 5:44p Johnson
70 * Resolve build error.
72 * 36 2/23/98 4:30p Mike
73 * Make homing missiles detonate after they pass up their target. Make
74 * countermeasures less effective.
76 * 35 2/09/98 8:04p Lawrance
77 * Add objnum to cmeasure struct, correctly set source_objnum
79 * 34 2/05/98 11:20p Lawrance
80 * save/restore countermeasure data
82 * 33 2/05/98 12:51a Mike
83 * Early asteroid stuff.
85 * 32 2/04/98 12:20p Mike
86 * Make countermeasures detonate in a smaller radius. Make all in radius,
87 * not just homing one, detonate.
89 * 31 1/29/98 11:48a John
90 * Added new counter measure rendering as model code. Made weapons be
91 * able to have impact explosion.
93 * 30 1/29/98 11:11a John
94 * Put in code to show dummy counter measure object.
96 * 29 1/23/98 5:06p John
97 * Took L out of vertex structure used B (blue) instead. Took all small
98 * fireballs out of fireball types and used particles instead. Fixed some
99 * debris explosion things. Restructured fireball code. Restructured
100 * some lighting code. Made dynamic lighting on by default. Made groups
101 * of lasers only cast one light. Made fireballs not cast light.
103 * 28 1/23/98 9:43a Mike
104 * Debug-C to disallow countermeasure firing.
105 * Fix bug in countermeasure tracking by aspect seekers.
107 * 27 1/20/98 9:47a Mike
108 * Suppress optimized compiler warnings.
109 * Some secondary weapon work.
111 * 26 1/16/98 11:43a Mike
112 * Fix countermeasures.
114 * 25 12/30/97 6:44p John
115 * Made g3_Draw_bitmap functions account for aspect of bitmap.
117 * 24 11/29/97 2:05p 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
122 * 23 10/27/97 3:24p Lawrance
123 * ensure countermeasures keep their initial velocity
125 * 22 9/14/97 4:50p Lawrance
126 * added some demo debugging code
128 * 21 9/04/97 5:09p Andsager
129 * implement physics using moment of inertia and mass (from BSPgen).
130 * Added to phys_info struct. Updated ship_info, polymodel structs.
131 * Updated weapon ($Mass and $Force) and ship ($Mass -> $Density) tables
133 * 20 8/20/97 11:09a Mike
134 * Make countermeasure lifetime based on skill level.
136 * 19 8/13/97 9:50p Allender
137 * split *_move into *_process_pre and *_process_post functions.
138 * process_pre functions called before object is moved. _process_post
139 * functions called after object is moved. Reordered code in ship_post
140 * and weapon_post for multiplayer
142 * 18 8/13/97 4:45p Allender
143 * fixed ship_fire_primary and fire_secondary to not take parameter for
144 * determining whether to count ammo or not. Fixed countermeasure firing
147 * 17 8/13/97 12:06p Lawrance
148 * supporting multiple types of fireball explosions
150 * 16 8/11/97 6:03p Mike
151 * Make ships with no shields not claim to have shields in target box.
153 * 15 8/08/97 4:29p Allender
154 * countermeasure stuff for multiplayer
156 * 14 7/31/97 5:55p John
157 * made so you pass flags to obj_create.
158 * Added new collision code that ignores any pairs that will never
161 * 13 7/15/97 12:03p Andsager
164 * 12 7/11/97 11:54a John
165 * added rotated 3d bitmaps.
167 * 11 6/24/97 10:04a Allender
168 * major multiplayer improvements. Better sequencing before game.
169 * Dealing with weapon/fireball/counter measure objects between
172 * 10 6/24/97 12:38a Lawrance
173 * fix minor bug with cycling cmeasure
175 * 9 6/05/97 1:37a Lawrance
176 * change syntax of a snd_play()
178 * 8 5/22/97 5:45p Mike
179 * Better countermeasure firing, key off availability, specify in
182 * 7 5/22/97 12:06p Lawrance
183 * include Sound.h for playing sound fx
185 * 6 5/22/97 12:04p Lawrance
186 * added soundhook for cmeasure cycle
188 * 5 5/15/97 5:05p Mike
189 * In the midst of changing subsystem targetnig from type-based to
191 * Also allowed you to view a target while dead.
193 * 4 5/14/97 4:08p Lawrance
194 * removing my_index from game arrays
196 * 3 5/14/97 10:50a Mike
197 * More countermeasure stuff.
199 * 2 5/12/97 5:58p Mike
200 * Add countermeasures.
202 * 1 5/12/97 2:23p Mike
208 #include "systemvars.h"
209 #include "cmeasure.h"
210 #include "freespace.h"
216 #include "floating.h"
220 #include "fireballs.h"
222 #include "missionparse.h" // For MAX_SPECIES_NAMES
224 #include "objectsnd.h"
226 #include "staticrand.h"
228 cmeasure_info Cmeasure_info[MAX_CMEASURE_TYPES];
229 cmeasure Cmeasures[MAX_CMEASURES];
231 int Num_cmeasure_types = 0;
232 int Num_cmeasures = 0;
233 int Cmeasure_inited = 0;
234 int Cmeasures_homing_check = 0;
235 int Countermeasures_enabled = 1; // Debug, set to 0 means no one can fire countermeasures.
237 // This will get called at the start of each level.
242 if ( !Cmeasure_inited ) {
245 /* // Do all the processing that happens only once
246 if ( Debris_model < 0 ) {
247 if (Debris_model>-1) {
249 pm = model_get(Debris_model);
250 Debris_num_submodels = pm->n_models;
254 for (i=0; i<MAX_SPECIES_NAMES; i++ ) {
255 Debris_textures[i] = bm_load( Debris_texture_files[i] );
256 if ( Debris_textures[i] < 0 ) {
257 Warning( LOCATION, "Couldn't load species %d debris\ntexture, '%s'\n", i, Debris_texture_files[i] );
263 // Reset everything between levels
266 for (i=0; i<MAX_CMEASURES; i++ ) {
267 Cmeasures[i].subtype = CMEASURE_UNUSED;
272 void cmeasure_render(object * objp)
274 // JAS TODO: Replace with proper fireball
278 cmp = &Cmeasures[objp->instance];
279 cmip = &Cmeasure_info[cmp->subtype];
281 if ( cmp->subtype == CMEASURE_UNUSED ) {
282 Int3(); // Hey, what are we doing in here?
286 // float size = -1.0f;
288 // g3_rotate_vertex(&p, &objp->pos );
289 // if ( rand() > RAND_MAX/2 ) {
290 // gr_set_color( 255, 0, 0 );
292 // gr_set_color( 255, 255, 255 );
294 // g3_draw_sphere(&p, 100.0f );
296 if ( cmip->model_num > -1 ) {
297 model_clear_instance(cmip->model_num);
298 model_render(cmip->model_num, &objp->orient, &objp->pos, MR_NO_LIGHTING );
300 mprintf(( "Not rendering countermeasure because model_num is negative\n" ));
305 // JAS TODO: Replace with proper fireball
313 cmp = &Cmeasures[objp->instance];
314 fd = &Fireball_data[FIREBALL_SHIP_EXPLODE1];
316 switch (cmp->subtype) {
317 case CMEASURE_UNUSED:
318 Int3(); // Hey, what are we doing in here?
321 framenum = (int) (fd->num_frames * Cmeasures[objp->instance].lifeleft*4) % fd->num_frames;
326 Assert(framenum != -1);
327 Assert(size != -1.0f);
329 gr_set_bitmap(fd->bitmap_id + framenum);
330 g3_rotate_vertex(&p, &objp->pos );
331 g3_draw_bitmap(&p, 0, size*0.5f, TMAP_FLAG_TEXTURED );
335 void cmeasure_delete( object * objp )
339 num = objp->instance;
341 // Assert( Cmeasures[num].objnum == OBJ_INDEX(objp));
343 Cmeasures[num].subtype = CMEASURE_UNUSED;
345 Assert( Num_cmeasures >= 0 );
348 // broke cmeasure_move into two functions -- process_pre and process_post (as was done with
349 // all *_move functions). Nothing to do for process_pre
351 void cmeasure_process_pre( object *objp, float frame_time)
355 void cmeasure_process_post(object * objp, float frame_time)
358 num = objp->instance;
360 // Assert( Cmeasures[num].objnum == objnum );
361 cmeasure *cmp = &Cmeasures[num];
363 if ( cmp->lifeleft >= 0.0f) {
364 cmp->lifeleft -= frame_time;
365 if ( cmp->lifeleft < 0.0f ) {
366 objp->flags |= OF_SHOULD_BE_DEAD;
367 // demo_do_flag_dead(OBJ_INDEX(objp));
373 float Skill_level_cmeasure_life_scale[NUM_SKILL_LEVELS] = {3.0f, 2.0f, 1.5f, 1.25f, 1.0f};
375 // creates one countermeasure. A ship fires 1 of these per launch. rand_val is used
376 // in multiplayer. If -1, then create a random number. If non-negative, use this
377 // number for static_rand functions
378 int cmeasure_create( object * source_obj, vector * pos, int cm_type, int rand_val )
380 int n, objnum, parent_objnum, arand;
384 cmeasure_info *cmeasurep;
387 if (!Countermeasures_enabled || !Ai_firing_enabled)
391 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!
393 parent_objnum = OBJ_INDEX(source_obj);
395 Assert( source_obj->type == OBJ_SHIP );
396 Assert( source_obj->instance >= 0 && source_obj->instance < MAX_SHIPS );
398 shipp = &Ships[source_obj->instance];
400 if ( Num_cmeasures >= MAX_CMEASURES)
403 for (n=0; n<MAX_CMEASURES; n++ )
404 if ( Cmeasures[n].subtype == CMEASURE_UNUSED)
406 if ( n == MAX_CMEASURES)
409 nprintf(("Network", "Cmeasure created by %s\n", Ships[source_obj->instance].ship_name));
412 cmeasurep = &Cmeasure_info[cm_type];
415 pos = &source_obj->pos;
417 objnum = obj_create( OBJ_CMEASURE, parent_objnum, n, &source_obj->orient, pos, 1.0f, OF_RENDERS | OF_PHYSICS );
419 Assert( objnum >= 0 && objnum < MAX_OBJECTS );
421 // Create Debris piece n!
422 if ( rand_val == -1 )
423 arand = myrand(); // use a random number to get lifeleft, and random vector for displacement from ship
427 cmp->lifeleft = static_randf(arand) * (cmeasurep->life_max - cmeasurep->life_min) / cmeasurep->life_min;
428 if (source_obj->flags & OF_PLAYER_SHIP){
429 cmp->lifeleft *= Skill_level_cmeasure_life_scale[Game_skill_level];
431 cmp->lifeleft = cmeasurep->life_min + cmp->lifeleft * (cmeasurep->life_max - cmeasurep->life_min);
433 // cmp->objnum = objnum;
434 cmp->team = shipp->team;
435 cmp->subtype = cm_type;
436 cmp->objnum = objnum;
437 cmp->source_objnum = parent_objnum;
438 cmp->source_sig = Objects[objnum].signature;
442 nprintf(("Jim", "Frame %i: Launching countermeasure #%i\n", Framecount, Objects[objnum].signature));
444 obj = &Objects[objnum];
448 vector vel, rand_vec;
450 vm_vec_scale_add(&vel, &source_obj->phys_info.vel, &source_obj->orient.fvec, -25.0f);
452 static_randvec(arand+1, &rand_vec);
454 vm_vec_scale_add2(&vel, &rand_vec, 2.0f);
456 obj->phys_info.vel = vel;
458 vm_vec_zero(&obj->phys_info.rotvel);
460 // blow out his reverse thrusters. Or drag, same thing.
461 obj->phys_info.rotdamp = 10000.0f;
462 obj->phys_info.side_slip_time_const = 10000.0f;
464 vm_vec_zero(&obj->phys_info.max_vel); // make so he can't turn on his own VOLITION anymore.
465 obj->phys_info.max_vel.z = -25.0f;
466 vm_vec_copy_scale(&obj->phys_info.desired_vel, &obj->orient.fvec, obj->phys_info.max_vel.z );
468 vm_vec_zero(&obj->phys_info.max_rotvel); // make so he can't change speed on his own VOLITION anymore.
470 // obj->phys_info.flags |= PF_USE_VEL;
472 return arand; // need to return this value for multiplayer purposes
475 void cmeasure_select_next(object *objp)
479 Assert(objp->type == OBJ_SHIP);
481 shipp = &Ships[objp->instance];
482 shipp->current_cmeasure++;
484 if (shipp->current_cmeasure >= Num_cmeasure_types)
485 shipp->current_cmeasure = 0;
487 //snd_play( &Snds[SND_CMEASURE_CYCLE] );
489 mprintf(("Countermeasure type set to %i in frame %i\n", shipp->current_cmeasure, Framecount));