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.3 2002/06/17 06:33:08 relnev
19 * ryan's struct patch for gcc 2.95
21 * Revision 1.2 2002/06/09 04:41:15 relnev
22 * added copyright header
24 * Revision 1.1.1.1 2002/05/03 03:28:08 root
28 * 5 9/05/99 11:25p Mikek
29 * Debug code (only on NDEBUG). Don't drop countermeasures if
30 * Ai_firing_enabled not set.
32 * 4 11/05/98 5:55p Dave
33 * Big pass at reducing #includes
35 * 3 10/13/98 9:28a Dave
36 * Started neatening up freespace.h. Many variables renamed and
37 * reorganized. Added AlphaColors.[h,cpp]
39 * 2 10/07/98 10:52a Dave
42 * 1 10/07/98 10:48a Dave
44 * 44 4/29/98 9:36p Allender
45 * ingame join tweaks. added network message for countermeasures
47 * 43 4/13/98 5:11p Mike
48 * More improvement to countermeasure code.
50 * 42 4/13/98 2:14p Mike
51 * Countermeasure balance testing for Jim.
53 * 41 4/10/98 11:02p Mike
54 * Make countermeasures less effective against aspect seekers than against
56 * Make AI ships match bank with each other when attacking a faraway
58 * Make ships not do silly loop-de-loop sometimes when attacking a faraway
61 * 40 3/31/98 5:11p John
62 * Removed demo/save/restore. Made NDEBUG defined compile. Removed a
63 * bunch of debug stuff out of player file. Made model code be able to
64 * unload models and malloc out only however many models are needed.
66 * 39 3/17/98 3:49p John
67 * Turned off lighting on counter measures.
69 * 38 2/26/98 10:07p Hoffoss
70 * Rewrote state saving and restoring to fix bugs and simplify the code.
72 * 37 2/23/98 5:44p Johnson
73 * Resolve build error.
75 * 36 2/23/98 4:30p Mike
76 * Make homing missiles detonate after they pass up their target. Make
77 * countermeasures less effective.
79 * 35 2/09/98 8:04p Lawrance
80 * Add objnum to cmeasure struct, correctly set source_objnum
82 * 34 2/05/98 11:20p Lawrance
83 * save/restore countermeasure data
85 * 33 2/05/98 12:51a Mike
86 * Early asteroid stuff.
88 * 32 2/04/98 12:20p Mike
89 * Make countermeasures detonate in a smaller radius. Make all in radius,
90 * not just homing one, detonate.
92 * 31 1/29/98 11:48a John
93 * Added new counter measure rendering as model code. Made weapons be
94 * able to have impact explosion.
96 * 30 1/29/98 11:11a John
97 * Put in code to show dummy counter measure object.
99 * 29 1/23/98 5:06p John
100 * Took L out of vertex structure used B (blue) instead. Took all small
101 * fireballs out of fireball types and used particles instead. Fixed some
102 * debris explosion things. Restructured fireball code. Restructured
103 * some lighting code. Made dynamic lighting on by default. Made groups
104 * of lasers only cast one light. Made fireballs not cast light.
106 * 28 1/23/98 9:43a Mike
107 * Debug-C to disallow countermeasure firing.
108 * Fix bug in countermeasure tracking by aspect seekers.
110 * 27 1/20/98 9:47a Mike
111 * Suppress optimized compiler warnings.
112 * Some secondary weapon work.
114 * 26 1/16/98 11:43a Mike
115 * Fix countermeasures.
117 * 25 12/30/97 6:44p John
118 * Made g3_Draw_bitmap functions account for aspect of bitmap.
120 * 24 11/29/97 2:05p John
121 * made g3_draw_bitmap and g3_draw_rotated bitmap take w&h, not w/2 & h/2,
122 * like they used to incorrectly assume. Added code to model to read in
125 * 23 10/27/97 3:24p Lawrance
126 * ensure countermeasures keep their initial velocity
128 * 22 9/14/97 4:50p Lawrance
129 * added some demo debugging code
131 * 21 9/04/97 5:09p Andsager
132 * implement physics using moment of inertia and mass (from BSPgen).
133 * Added to phys_info struct. Updated ship_info, polymodel structs.
134 * Updated weapon ($Mass and $Force) and ship ($Mass -> $Density) tables
136 * 20 8/20/97 11:09a Mike
137 * Make countermeasure lifetime based on skill level.
139 * 19 8/13/97 9:50p Allender
140 * split *_move into *_process_pre and *_process_post functions.
141 * process_pre functions called before object is moved. _process_post
142 * functions called after object is moved. Reordered code in ship_post
143 * and weapon_post for multiplayer
145 * 18 8/13/97 4:45p Allender
146 * fixed ship_fire_primary and fire_secondary to not take parameter for
147 * determining whether to count ammo or not. Fixed countermeasure firing
150 * 17 8/13/97 12:06p Lawrance
151 * supporting multiple types of fireball explosions
153 * 16 8/11/97 6:03p Mike
154 * Make ships with no shields not claim to have shields in target box.
156 * 15 8/08/97 4:29p Allender
157 * countermeasure stuff for multiplayer
159 * 14 7/31/97 5:55p John
160 * made so you pass flags to obj_create.
161 * Added new collision code that ignores any pairs that will never
164 * 13 7/15/97 12:03p Andsager
167 * 12 7/11/97 11:54a John
168 * added rotated 3d bitmaps.
170 * 11 6/24/97 10:04a Allender
171 * major multiplayer improvements. Better sequencing before game.
172 * Dealing with weapon/fireball/counter measure objects between
175 * 10 6/24/97 12:38a Lawrance
176 * fix minor bug with cycling cmeasure
178 * 9 6/05/97 1:37a Lawrance
179 * change syntax of a snd_play()
181 * 8 5/22/97 5:45p Mike
182 * Better countermeasure firing, key off availability, specify in
185 * 7 5/22/97 12:06p Lawrance
186 * include Sound.h for playing sound fx
188 * 6 5/22/97 12:04p Lawrance
189 * added soundhook for cmeasure cycle
191 * 5 5/15/97 5:05p Mike
192 * In the midst of changing subsystem targetnig from type-based to
194 * Also allowed you to view a target while dead.
196 * 4 5/14/97 4:08p Lawrance
197 * removing my_index from game arrays
199 * 3 5/14/97 10:50a Mike
200 * More countermeasure stuff.
202 * 2 5/12/97 5:58p Mike
203 * Add countermeasures.
205 * 1 5/12/97 2:23p Mike
211 #include "systemvars.h"
212 #include "cmeasure.h"
213 #include "freespace.h"
219 #include "floating.h"
223 #include "fireballs.h"
225 #include "missionparse.h" // For MAX_SPECIES_NAMES
227 #include "objectsnd.h"
229 #include "staticrand.h"
231 cmeasure_info Cmeasure_info[MAX_CMEASURE_TYPES];
232 cmeasure Cmeasures[MAX_CMEASURES];
234 int Num_cmeasure_types = 0;
235 int Num_cmeasures = 0;
236 int Cmeasure_inited = 0;
237 int Cmeasures_homing_check = 0;
238 int Countermeasures_enabled = 1; // Debug, set to 0 means no one can fire countermeasures.
240 // This will get called at the start of each level.
245 if ( !Cmeasure_inited ) {
248 /* // Do all the processing that happens only once
249 if ( Debris_model < 0 ) {
250 if (Debris_model>-1) {
252 pm = model_get(Debris_model);
253 Debris_num_submodels = pm->n_models;
257 for (i=0; i<MAX_SPECIES_NAMES; i++ ) {
258 Debris_textures[i] = bm_load( Debris_texture_files[i] );
259 if ( Debris_textures[i] < 0 ) {
260 Warning( LOCATION, "Couldn't load species %d debris\ntexture, '%s'\n", i, Debris_texture_files[i] );
266 // Reset everything between levels
269 for (i=0; i<MAX_CMEASURES; i++ ) {
270 Cmeasures[i].subtype = CMEASURE_UNUSED;
275 void cmeasure_render(object * objp)
277 // JAS TODO: Replace with proper fireball
281 cmp = &Cmeasures[objp->instance];
282 cmip = &Cmeasure_info[cmp->subtype];
284 if ( cmp->subtype == CMEASURE_UNUSED ) {
285 Int3(); // Hey, what are we doing in here?
289 // float size = -1.0f;
291 // g3_rotate_vertex(&p, &objp->pos );
292 // if ( rand() > RAND_MAX/2 ) {
293 // gr_set_color( 255, 0, 0 );
295 // gr_set_color( 255, 255, 255 );
297 // g3_draw_sphere(&p, 100.0f );
299 if ( cmip->model_num > -1 ) {
300 model_clear_instance(cmip->model_num);
301 model_render(cmip->model_num, &objp->orient, &objp->pos, MR_NO_LIGHTING );
303 mprintf(( "Not rendering countermeasure because model_num is negative\n" ));
308 // JAS TODO: Replace with proper fireball
316 cmp = &Cmeasures[objp->instance];
317 fd = &Fireball_data[FIREBALL_SHIP_EXPLODE1];
319 switch (cmp->subtype) {
320 case CMEASURE_UNUSED:
321 Int3(); // Hey, what are we doing in here?
324 framenum = (int) (fd->num_frames * Cmeasures[objp->instance].lifeleft*4) % fd->num_frames;
329 SDL_assert(framenum != -1);
330 SDL_assert(size != -1.0f);
332 gr_set_bitmap(fd->bitmap_id + framenum);
333 g3_rotate_vertex(&p, &objp->pos );
334 g3_draw_bitmap(&p, 0, size*0.5f, TMAP_FLAG_TEXTURED );
338 void cmeasure_delete( object * objp )
342 num = objp->instance;
344 // SDL_assert( Cmeasures[num].objnum == OBJ_INDEX(objp));
346 Cmeasures[num].subtype = CMEASURE_UNUSED;
348 SDL_assert( Num_cmeasures >= 0 );
351 // broke cmeasure_move into two functions -- process_pre and process_post (as was done with
352 // all *_move functions). Nothing to do for process_pre
354 void cmeasure_process_pre( object *objp, float frame_time)
358 void cmeasure_process_post(object * objp, float frame_time)
361 num = objp->instance;
363 // SDL_assert( Cmeasures[num].objnum == objnum );
364 cmeasure *cmp = &Cmeasures[num];
366 if ( cmp->lifeleft >= 0.0f) {
367 cmp->lifeleft -= frame_time;
368 if ( cmp->lifeleft < 0.0f ) {
369 objp->flags |= OF_SHOULD_BE_DEAD;
370 // demo_do_flag_dead(OBJ_INDEX(objp));
376 float Skill_level_cmeasure_life_scale[NUM_SKILL_LEVELS] = {3.0f, 2.0f, 1.5f, 1.25f, 1.0f};
378 // creates one countermeasure. A ship fires 1 of these per launch. rand_val is used
379 // in multiplayer. If -1, then create a random number. If non-negative, use this
380 // number for static_rand functions
381 int cmeasure_create( object * source_obj, vector * pos, int cm_type, int rand_val )
383 int n, objnum, parent_objnum, arand;
387 cmeasure_info *cmeasurep;
390 if (!Countermeasures_enabled || !Ai_firing_enabled)
394 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!
396 parent_objnum = OBJ_INDEX(source_obj);
398 SDL_assert( source_obj->type == OBJ_SHIP );
399 SDL_assert( source_obj->instance >= 0 && source_obj->instance < MAX_SHIPS );
401 shipp = &Ships[source_obj->instance];
403 if ( Num_cmeasures >= MAX_CMEASURES)
406 for (n=0; n<MAX_CMEASURES; n++ )
407 if ( Cmeasures[n].subtype == CMEASURE_UNUSED)
409 if ( n == MAX_CMEASURES)
412 nprintf(("Network", "Cmeasure created by %s\n", Ships[source_obj->instance].ship_name));
415 cmeasurep = &Cmeasure_info[cm_type];
418 pos = &source_obj->pos;
420 objnum = obj_create( OBJ_CMEASURE, parent_objnum, n, &source_obj->orient, pos, 1.0f, OF_RENDERS | OF_PHYSICS );
422 SDL_assert( objnum >= 0 && objnum < MAX_OBJECTS );
424 // Create Debris piece n!
425 if ( rand_val == -1 )
426 arand = myrand(); // use a random number to get lifeleft, and random vector for displacement from ship
430 cmp->lifeleft = static_randf(arand) * (cmeasurep->life_max - cmeasurep->life_min) / cmeasurep->life_min;
431 if (source_obj->flags & OF_PLAYER_SHIP){
432 cmp->lifeleft *= Skill_level_cmeasure_life_scale[Game_skill_level];
434 cmp->lifeleft = cmeasurep->life_min + cmp->lifeleft * (cmeasurep->life_max - cmeasurep->life_min);
436 // cmp->objnum = objnum;
437 cmp->team = shipp->team;
438 cmp->subtype = cm_type;
439 cmp->objnum = objnum;
440 cmp->source_objnum = parent_objnum;
441 cmp->source_sig = Objects[objnum].signature;
445 nprintf(("Jim", "Frame %i: Launching countermeasure #%i\n", Framecount, Objects[objnum].signature));
447 obj = &Objects[objnum];
451 vector vel, rand_vec;
453 vm_vec_scale_add(&vel, &source_obj->phys_info.vel, &source_obj->orient.v.fvec, -25.0f);
455 static_randvec(arand+1, &rand_vec);
457 vm_vec_scale_add2(&vel, &rand_vec, 2.0f);
459 obj->phys_info.vel = vel;
461 vm_vec_zero(&obj->phys_info.rotvel);
463 // blow out his reverse thrusters. Or drag, same thing.
464 obj->phys_info.rotdamp = 10000.0f;
465 obj->phys_info.side_slip_time_const = 10000.0f;
467 vm_vec_zero(&obj->phys_info.max_vel); // make so he can't turn on his own VOLITION anymore.
468 obj->phys_info.max_vel.xyz.z = -25.0f;
469 vm_vec_copy_scale(&obj->phys_info.desired_vel, &obj->orient.v.fvec, obj->phys_info.max_vel.xyz.z );
471 vm_vec_zero(&obj->phys_info.max_rotvel); // make so he can't change speed on his own VOLITION anymore.
473 // obj->phys_info.flags |= PF_USE_VEL;
475 return arand; // need to return this value for multiplayer purposes
478 void cmeasure_select_next(object *objp)
482 SDL_assert(objp->type == OBJ_SHIP);
484 shipp = &Ships[objp->instance];
485 shipp->current_cmeasure++;
487 if (shipp->current_cmeasure >= Num_cmeasure_types)
488 shipp->current_cmeasure = 0;
490 //snd_play( &Snds[SND_CMEASURE_CYCLE] );
492 mprintf(("Countermeasure type set to %i in frame %i\n", shipp->current_cmeasure, Framecount));