]> icculus.org git repositories - taylor/freespace2.git/blob - src/weapon/flak.cpp
silence various MSVC warnings
[taylor/freespace2.git] / src / weapon / flak.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/Flak.cpp $
11  * $Revision$
12  * $Date$
13  * $Author$
14  *
15  * flak functions
16  *
17  * $Log$
18  * Revision 1.4  2002/06/17 06:33:11  relnev
19  * ryan's struct patch for gcc 2.95
20  *
21  * Revision 1.3  2002/06/09 04:41:29  relnev
22  * added copyright header
23  *
24  * Revision 1.2  2002/05/07 03:16:53  theoddone33
25  * The Great Newline Fix
26  *
27  * Revision 1.1.1.1  2002/05/03 03:28:11  root
28  * Initial import.
29  * 
30  * 
31  * 9     7/31/99 2:57p Dave
32  * Scaled flak aim and jitter by weapon subsystem strength.
33  * 
34  * 8     5/24/99 5:45p Dave
35  * Added detail levels to the nebula, with a decent speedup. Split nebula
36  * lightning into its own section.
37  * 
38  * $NoKeywords: $
39  */
40
41 #include "flak.h"
42 #include "vecmat.h"
43 #include "bmpman.h"
44 #include "particle.h"
45 #include "weapon.h"
46 #include "systemvars.h"
47 #include "multi.h"
48 #include "muzzleflash.h"
49
50 // --------------------------------------------------------------------------------------------------------------------------------------
51 // FLAK DEFINES/VARS
52 //
53
54 // temporary - max distance from target that a jittered flak aim direction can point at
55 #define FLAK_MAX_ERROR                                                                                  60.0f                                                   // aim at _most_ this far off of the predicted target position
56 float Flak_error = FLAK_MAX_ERROR;
57
58 // muzzle flash animation
59 #define MUZZLE_FLASH_FILE                                                                               "flk2"
60 #define MUZZLE_FLASH_RADIUS                                                                     15.0f
61 float Flak_muzzle_radius = MUZZLE_FLASH_RADIUS;
62 int Flak_muzzle_flash_ani = -1;
63
64 // muzzle flash limiting
65 #define FLAK_MUZZLE_MOD         3
66 int Flak_muzzle_mod = 0;
67
68 // flak ranging info
69 #define FLAK_RANGE_DEFAULT                                                                              65.0f                                                   // spherical radius around the predicted target position
70 float Flak_range = FLAK_RANGE_DEFAULT;
71
72 // flak info
73 #define MAX_FLAK_INFO                                                                                   350
74 typedef struct flak_info {      
75         vector start_pos;                                                       // initial pos
76         float range;                                                            // range at which we'll detonate (-1 if unused);
77 } flak_info;
78 flak_info Flak[MAX_FLAK_INFO];
79
80
81 // --------------------------------------------------------------------------------------------------------------------------------------
82 // FLAK FUNCTIONS
83 //
84
85 // initialize flak stuff for the level
86 void flak_level_init()
87 {
88         int num_frames;
89         int fps;
90         int idx;
91
92         // if the muzzle flash ani is not loaded, do so
93         if(Flak_muzzle_flash_ani == -1){
94                 Flak_muzzle_flash_ani = bm_load_animation(MUZZLE_FLASH_FILE, &num_frames, &fps, 1);
95         }
96
97         // zero out flak info
98         memset(Flak, 0, sizeof(flak_info) * MAX_FLAK_INFO);
99         for(idx=0; idx<MAX_FLAK_INFO; idx++){
100                 Flak[idx].range = -1.0f;
101         }
102 }
103
104 // close down flak stuff
105 void flak_level_close()
106 {
107         // zero out the ani (bitmap manager will take care of releasing it I think)
108         if(Flak_muzzle_flash_ani != -1){
109                 Flak_muzzle_flash_ani = -1;
110         }
111 }
112
113 // given a newly created weapon, turn it into a flak weapon
114 void flak_create(weapon *wp)
115 {
116         int idx;
117         int found;
118         
119         // make sure this is a valid flak weapon object
120         SDL_assert(wp->objnum >= 0);
121         SDL_assert(Objects[wp->objnum].type == OBJ_WEAPON);
122         SDL_assert(wp->weapon_info_index >= 0);
123         SDL_assert(Weapon_info[wp->weapon_info_index].wi_flags & WIF_FLAK);
124
125         // switch off rendering for the object
126         obj_set_flags(&Objects[wp->objnum], Objects[wp->objnum].flags & ~(OF_RENDERS));
127
128         // try and find a free flak index
129         found = 0;
130         for(idx=0; idx<MAX_FLAK_INFO; idx++){
131                 if(Flak[idx].range < 0.0f){
132                         found = 1;
133                         break;
134                 }
135         }
136
137         // if we found a free slot
138         if(found){
139                 Flak[idx].range = 0.0f;
140                 wp->flak_index = (short)idx;
141         } else {
142                 nprintf(("General", "Out of FLAK slots!\n"));
143         }
144 }
145
146 // free up a flak object
147 void flak_delete(int flak_index)
148 {
149         SDL_assert((flak_index >= 0) && (flak_index < MAX_FLAK_INFO));
150         memset(&Flak[flak_index], 0, sizeof(flak_info));
151         Flak[flak_index].range = -1;
152 }
153
154 // given a just fired flak shell, pick a detonating distance for it
155 void flak_pick_range(object *objp, vector *predicted_target_pos, float weapon_subsys_strength)
156 {
157         float final_range;
158         vector temp;
159         
160         // make sure this flak object is valid
161         SDL_assert(objp->type == OBJ_WEAPON);
162         SDL_assert(objp->instance >= 0);
163         SDL_assert(Weapons[objp->instance].weapon_info_index >= 0);
164         SDL_assert(Weapon_info[Weapons[objp->instance].weapon_info_index].wi_flags & WIF_FLAK); 
165         
166         // if the flak index is invalid, do nothing - if this fails the flak simply becomes a non-rendering bullet
167         if(Weapons[objp->instance].flak_index < 0){
168                 return;
169         }
170
171         // get the range to the target
172         vm_vec_sub(&temp, &objp->pos, predicted_target_pos);
173         final_range = vm_vec_mag(&temp);
174
175         // add in some randomness
176         final_range += (Flak_range + (Flak_range * 0.65f * (1.0f - weapon_subsys_strength))) * frand_range(-1.0f, 1.0f);        
177
178         // make sure we're firing at least 10 meters away
179         if(final_range < 10.0f){
180                 final_range = 10.0f;
181         }
182
183         // set the range
184         flak_set_range(objp, &objp->pos, final_range);
185 }
186
187 // add some jitter to a flak gun's aiming direction, take into account range to target so that we're never _too_ far off
188 // assumes dir is normalized
189 void flak_jitter_aim(vector *dir, float dist_to_target, float weapon_subsys_strength)
190 {                       
191         vector rand_twist_pre, rand_twist_post;         
192         matrix temp;
193         vector final_aim;
194         float error_val;
195         
196         // get the matrix needed to rotate the base direction to the actual direction           
197         vm_vector_2_matrix(&temp, dir, NULL, NULL);
198
199         // error value  
200         error_val = Flak_error + (Flak_error * 0.65f * (1.0f - weapon_subsys_strength));
201         
202         // scale the rvec by some random value and make it the "pre-twist" value
203         float rand_dist = frand_range(0.0f, error_val);
204         // no jitter - so do nothing
205         if(rand_dist <= 0.0f){
206                 return;
207         }
208         vm_vec_copy_scale(&rand_twist_pre, &temp.v.rvec, rand_dist);
209
210         // now rotate the twist vector around the x axis (the base aim axis) at a random angle
211         vm_rot_point_around_line(&rand_twist_post, &rand_twist_pre, fl_radian(359.0f * frand_range(0.0f, 1.0f)), &vmd_zero_vector, dir);
212
213         // add the resulting vector to the base aim vector and normalize
214         final_aim = *dir;
215         vm_vec_scale(&final_aim, dist_to_target);
216         vm_vec_add(dir, &final_aim, &rand_twist_post);
217         vm_vec_normalize(dir);
218 }
219
220 // create a muzzle flash from a flak gun based upon firing position and weapon type
221 void flak_muzzle_flash(vector *pos, vector *dir, int turret_weapon_class)
222 {
223         // sanity
224         SDL_assert((turret_weapon_class >= 0) && (turret_weapon_class < Num_weapon_types));
225         if((turret_weapon_class < 0) || (turret_weapon_class >= Num_weapon_types)){
226                 return;
227         }
228         SDL_assert(Weapon_info[turret_weapon_class].wi_flags & WIF_FLAK);
229         if(!(Weapon_info[turret_weapon_class].wi_flags & WIF_FLAK)){
230                 return;
231         }
232         SDL_assert(Weapon_info[turret_weapon_class].wi_flags & WIF_MFLASH);
233         if(!(Weapon_info[turret_weapon_class].wi_flags & WIF_MFLASH)){
234                 return;
235         }
236         SDL_assert(Weapon_info[turret_weapon_class].muzzle_flash >= 0);
237         if(Weapon_info[turret_weapon_class].muzzle_flash < 0){
238                 return;
239         }
240
241         // maybe skip this flash
242         if(!(Flak_muzzle_mod % FLAK_MUZZLE_MOD)){
243                 // call the muzzle flash code
244                 mflash_create(pos, dir, Weapon_info[turret_weapon_class].muzzle_flash);
245         }
246
247         Flak_muzzle_mod++;
248         if(Flak_muzzle_mod >= 10000){
249                 Flak_muzzle_mod = 0;
250         }       
251 }
252
253 // maybe detonate a flak shell early/late (call from weapon_process_pre(...))
254 void flak_maybe_detonate(object *objp)
255 {                       
256         vector temp;    
257
258         // multiplayer clients should never detonate flak early
259         // if(MULTIPLAYER_CLIENT){
260                 // return;
261         // }
262
263         // if the shell has gone past its range, blow it up
264         vm_vec_sub(&temp, &objp->pos, &Flak[Weapons[objp->instance].flak_index].start_pos);
265         if(vm_vec_mag(&temp) >= Flak[Weapons[objp->instance].flak_index].range){
266                 weapon_detonate(objp);          
267         }
268 }
269
270 // given a just fired flak shell, pick a detonating distance for it
271 void flak_set_range(object *objp, vector *start_pos, float range)
272 {
273         SDL_assert(objp->type == OBJ_WEAPON);
274         SDL_assert(objp->instance >= 0);        
275         SDL_assert(Weapons[objp->instance].flak_index >= 0);
276
277         // setup the flak info
278         Flak[Weapons[objp->instance].flak_index].range = range;
279         Flak[Weapons[objp->instance].flak_index].start_pos = *start_pos;
280 }
281
282 // get the current range for the flak object
283 float flak_get_range(object *objp)
284 {
285         SDL_assert(objp->type == OBJ_WEAPON);
286         SDL_assert(objp->instance >= 0);        
287         SDL_assert(Weapons[objp->instance].flak_index >= 0);
288         
289         return Flak[Weapons[objp->instance].flak_index].range;
290 }
291
292 DCF(flak, "show flak dcf commands")
293 {
294         dc_printf("flak_err <float>      : set the radius of error for flak targeting\n");      
295         dc_printf("flak_range <float>           : set the radius of error for detonation of a flak shell\n");
296         dc_printf("flak_rad <float>      : set the radius for the muzzle flash on a flak gun\n");
297 }
298
299 DCF(flak_err, "set the radius of error for flak targeting")
300 {
301         dc_get_arg(ARG_FLOAT);
302         if(Dc_arg_type & ARG_FLOAT){             
303                 Flak_error = Dc_arg_float;
304         }
305 }
306
307 DCF(flak_range, "set the radius of error for detonation of a flak shell")
308 {
309         dc_get_arg(ARG_FLOAT);
310         if(Dc_arg_type & ARG_FLOAT){             
311                 Flak_range = Dc_arg_float;
312         }
313 }
314
315 DCF(flak_rad, "set the radius of flak gun muzzle flash")
316 {
317         dc_get_arg(ARG_FLOAT);
318         if(Dc_arg_type & ARG_FLOAT){             
319                 Flak_muzzle_radius = Dc_arg_float;
320         }
321 }