]> icculus.org git repositories - taylor/freespace2.git/blob - src/weapon/corkscrew.cpp
ryan's struct patch for gcc 2.95
[taylor/freespace2.git] / src / weapon / corkscrew.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/Corkscrew.cpp $
11  * $Revision$
12  * $Date$
13  * $Author$
14  *
15  * C module for managing corkscrew missiles
16  * 
17  * $NoKeywords: $
18  */
19
20 #include "corkscrew.h"
21 #include "weapon.h"
22 #include "ship.h"
23 #include "timer.h"
24 #include "freespace.h"  // for Missiontime
25 #include "trails.h"
26
27 // corkscrew structure flags
28 #define CS_FLAG_USED                                            (1<<0)          // this structure is in use
29 #define CS_FLAG_COUNTER                                 (1<<1)          // counterrotate this guy
30
31 // corkscrew settings
32 int Corkscrew_missile_delay                     = 30;                   // delay between missile firings
33 int Corkscrew_num_missiles_fired                = 4;                    // # of missiles fire in one shot
34 float Corkscrew_radius                                  = 1.25f;                // radius of the corkscrew itself
35 float Corkscrew_twist                                   = 5.0f;         // in degrees/second
36 int Corkscrew_helix                                             = 1;                    // attempt to point the missile in the right direction
37 int Corkscrew_counterrotate                     = 1;                    // counterrotate every other missile
38 int Corkscrew_shrink                                            = 0;                    // shrink the radius of every successive missile
39 float Corkscrew_shrink_val                              = 0.3f;         // rate at which the radius shrinks
40 int Corkscrew_down_first                                = 1;                    // have the corkscrew go "down" first
41
42 // current counterrotation and radius shrink values
43 float Corkscrew_radius_cur = Corkscrew_radius;
44
45 typedef struct cscrew_info {            
46         int flags;                                                                                              // flags for the missile
47         
48         // info about the corkscrew effect for this missile
49         vector cen_p;                                                                                   // vector pointing to the "center" of the corkscrew     
50         float radius;                                                                                   // radius of the corkscrew
51         matrix real_orient;                                                                     // the orientation used when calling physics (bashed before rendering)
52         vector last_corkscrew_pos;                                                      // last position along the corkscrew
53 } cscrew_info;
54
55 #define MAX_CORKSCREW_MISSILES  100
56 cscrew_info     Corkscrew_missiles[MAX_CORKSCREW_MISSILES];
57
58 // ------------------------------------------------------------------
59 // cscrew_level_init()
60 //
61 // Called at the start of each new mission
62 //
63 void cscrew_level_init()
64 {
65         memset(Corkscrew_missiles, 0, sizeof(cscrew_info) * MAX_CORKSCREW_MISSILES);
66 }
67
68 // ------------------------------------------------------------------
69 // cscrew_maybe_fire_missile()
70 //
71 // Check if there are any swarm missiles to fire, and if enough time
72 // has elapsed since last one fired, go ahead and fire it.
73 //
74 // This is called once per ship frame in ship_move()
75 //
76 void cscrew_maybe_fire_missile(int shipnum)
77 {
78         ship                    *sp;
79         ship_weapon *swp;
80         int                     weapon_info_index;
81
82         Assert(shipnum >= 0 && shipnum < MAX_SHIPS );
83         sp = &Ships[shipnum];
84
85         // make sure we're supposed to be firing some missiles
86         if ( sp->num_corkscrew_to_fire <= 0 ){
87                 return;
88         }
89
90         // make sure we have a valid weapon band
91         swp = &sp->weapons;
92         if ( swp->current_secondary_bank == -1 ) {
93                 sp->num_corkscrew_to_fire = 0;
94                 return;
95         }
96
97         weapon_info_index = swp->secondary_bank_weapons[swp->current_secondary_bank];
98         Assert( weapon_info_index >= 0 && weapon_info_index < MAX_WEAPON_TYPES );
99
100         // if current secondary bank is not a corkscrew missile, return
101         if ( !(Weapon_info[weapon_info_index].wi_flags & WIF_CORKSCREW) ) {
102                 sp->num_corkscrew_to_fire = 0;
103                 return;
104         }
105
106         if ( timestamp_elapsed(sp->next_corkscrew_fire) ) {
107                 sp->next_corkscrew_fire = timestamp(Corkscrew_missile_delay);
108                 ship_fire_secondary( &Objects[sp->objnum], 1 );
109                 sp->num_corkscrew_to_fire--;
110         }
111 }
112
113 // ------------------------------------------------------------------
114 // cscrew_create()
115 //
116 //      Get a free corkscrew missile entry, and initialize the struct members
117 //
118 int cscrew_create(object *obj)
119 {
120         int                     i;
121         cscrew_info     *cscrewp = NULL;        
122         
123         for ( i = 0; i < MAX_CORKSCREW_MISSILES; i++ ) {
124                 cscrewp = &Corkscrew_missiles[i];
125                 if ( !(cscrewp->flags & CS_FLAG_USED) ) {
126                         break;          
127                 }
128         }
129
130         if ( i >= MAX_CORKSCREW_MISSILES ) {
131                 nprintf(("Warning","No more corkscrew missiles are available\n"));
132                 return -1;
133         }
134
135         // mark the guy as "used"
136         cscrewp->flags = CS_FLAG_USED;
137
138         // determine if he is counterrotating
139         if(Corkscrew_counterrotate){
140                 if(frand_range(0.0f, 1.0f) < 0.5f){
141                         cscrewp->flags |= CS_FLAG_COUNTER;
142                 }               
143         }
144
145         // get the "center" pointing vector
146         vector neg;
147         neg = obj->orient.v.uvec;
148         if(Corkscrew_down_first){
149                 vm_vec_negate(&neg);
150         }
151         vm_vec_scale_add2(&cscrewp->cen_p, &neg, Corkscrew_radius);     
152
153         // move the missile up so that the corkscrew point is at the muzzle of the gun
154         // vm_vec_scale_add2(&obj->pos, &obj->orient.uvec, Corkscrew_radius);
155
156         // store some initial helix params
157         cscrewp->real_orient = obj->orient;
158         cscrewp->last_corkscrew_pos = obj->pos;
159         
160         return i;
161 }
162
163 // ------------------------------------------------------------------
164 // cscrew_delete()
165 //
166 //
167 void cscrew_delete(int i)
168 {       
169         if ( !(Corkscrew_missiles[i].flags & CS_FLAG_USED) ) {
170                 Int3(); 
171         }
172
173         memset(&Corkscrew_missiles[i], 0, sizeof(cscrew_info));
174 }
175
176 // pre process the corkscrew weapon by putting him in the "center" of his corkscrew
177 void cscrew_process_pre(object *objp)
178 {               
179         cscrew_info *ci;
180
181         // check stuff
182         Assert(objp->type == OBJ_WEAPON);       
183         Assert(Weapons[objp->instance].cscrew_index >= 0);
184         Assert(Corkscrew_missiles[Weapons[objp->instance].cscrew_index].flags & CS_FLAG_USED);
185
186         ci = &Corkscrew_missiles[Weapons[objp->instance].cscrew_index];
187
188         // unrotate the missile itself
189         if(Corkscrew_helix){
190                 // restore the "real" matrix now
191                 objp->orient = ci->real_orient;         
192         }
193         // move the missile back to the center of the corkscrew 
194         vm_vec_add2(&objp->pos, &ci->cen_p);    
195 }
196
197 // post process the corkscrew weapon by putting him back to the right spot on his corkscrew
198 void cscrew_process_post(object *objp)
199 {       
200         vector cen, neg;
201         vector new_pt;  
202         weapon *wp;
203         weapon_info *wip;
204         cscrew_info *ci;
205         float twist_val;
206
207         // check stuff
208         Assert(objp->type == OBJ_WEAPON);       
209         Assert(Weapons[objp->instance].cscrew_index >= 0);
210         Assert(Corkscrew_missiles[Weapons[objp->instance].cscrew_index].flags & CS_FLAG_USED);
211
212         // get various useful pointers
213         wp = &Weapons[objp->instance];
214         wip = &Weapon_info[wp->weapon_info_index];
215         ci = &Corkscrew_missiles[wp->cscrew_index];
216
217         // move to the outside of the corkscrew                 
218         neg = ci->cen_p;
219         cen = objp->pos;        
220         vm_vec_negate(&neg);            
221         vm_vec_add2(&objp->pos, &neg);          
222
223         // determine what direction (clockwise or counterclockwise) the missile will spin       
224         twist_val = ci->flags & CS_FLAG_COUNTER ? -Corkscrew_twist : Corkscrew_twist;
225         twist_val *= flFrametime;       
226         
227         // rotate the missile position
228         vm_rot_point_around_line(&new_pt, &objp->pos, twist_val, &cen, &objp->orient.v.fvec);
229         objp->pos = new_pt;
230
231         // rotate the missile itself
232         if(Corkscrew_helix){            
233                 vector dir;
234         
235                 // compute a "fake" orient and store the old one for safekeeping
236                 ci->real_orient = objp->orient;
237                 vm_vec_sub(&dir, &objp->pos, &ci->last_corkscrew_pos);
238                 vm_vec_normalize(&dir);
239                 vm_vector_2_matrix(&objp->orient, &dir, NULL, NULL);    
240                 
241                 // mark down this position so we can orient nicely _next_ frame
242                 ci->last_corkscrew_pos = objp->pos;
243         }       
244
245         // get the new center pointing vector
246         vm_vec_sub(&ci->cen_p, &cen, &objp->pos);
247
248         // do trail stuff here
249         if ( wp->trail_num > -1 )       {
250                 if (trail_stamp_elapsed(wp->trail_num)) {
251                         trail_add_segment( wp->trail_num, &objp->pos );
252                         trail_set_stamp(wp->trail_num);
253                 } else {
254                         trail_set_segment( wp->trail_num, &objp->pos );
255                 }
256         }       
257 }
258
259 // debug console functionality
260 void cscrew_display_dcf()
261 {
262         dc_printf("Corkscrew settings\n\n");
263         dc_printf("Delay (cscrew_delay) : %d\n",Corkscrew_missile_delay);
264         dc_printf("Count (cscrew_count) : %d\n",Corkscrew_num_missiles_fired);
265         dc_printf("Radius (cscrew_radius) :     %f\n",Corkscrew_radius);
266         dc_printf("Twist (cscrew_twist) : %f\n",Corkscrew_twist);       
267         if(Corkscrew_helix){
268                 dc_printf("Helix (cscrew_helix): ON\n");
269         } else {
270                 dc_printf("Helix (cscrew_helix): OFF\n");
271         }
272         if(Corkscrew_counterrotate){
273                 dc_printf("Counterrotate (cscrew_counter): ON\n");
274         } else {
275                 dc_printf("Counterrotate (cscrew_counter): OFF\n");
276         }
277         if(Corkscrew_shrink){
278                 dc_printf("Shrink (cscrew_shrink): ON\n");
279         } else {
280                 dc_printf("Shrink (cscrew_shrink): OFF\n");
281         }
282         dc_printf("Corkscrew shrink (cscrew_shrinkval): %f\n", Corkscrew_shrink_val);
283         if(Corkscrew_down_first){
284                 dc_printf("Corkscrew down first : ON\n");
285         } else {
286                 dc_printf("Corkscrew down first : OFF\n");
287         }
288 }
289
290 DCF(cscrew, "Listing of corkscrew missile debug console functions")
291 {
292         cscrew_display_dcf();
293 }
294
295 DCF(cscrew_delay, "Change the delay between corkscrew firing")
296 {       
297         dc_get_arg(ARG_INT);
298         if(Dc_arg_type & ARG_INT){
299                 Corkscrew_missile_delay = Dc_arg_int;           
300         }
301
302         cscrew_display_dcf();
303 }
304
305 DCF(cscrew_count, "Change the # of corkscrew missiles fired")
306 {       
307         dc_get_arg(ARG_INT);
308         if(Dc_arg_type & ARG_INT){
309                 Corkscrew_num_missiles_fired = Dc_arg_int;              
310         }
311
312         cscrew_display_dcf();
313 }
314
315 DCF(cscrew_radius, "Change the radius of corkscrew missiles")
316 {       
317         dc_get_arg(ARG_FLOAT);
318         if(Dc_arg_type & ARG_FLOAT){
319                 Corkscrew_radius = Dc_arg_float;
320         }
321
322         cscrew_display_dcf();
323 }
324
325 DCF(cscrew_twist, "Change the rate of the corkscrew twist")
326 {
327         dc_get_arg(ARG_FLOAT);
328         if(Dc_arg_type & ARG_FLOAT){
329                 Corkscrew_twist = Dc_arg_float;
330         }
331
332         cscrew_display_dcf();
333 }
334
335 DCF(cscrew_helix, "Attempt to orient missile nicely along the corkscrew")
336 {
337         Corkscrew_helix = !Corkscrew_helix;
338
339         cscrew_display_dcf();
340 }
341
342 DCF(cscrew_counter, "Counterrotate every other missile")
343 {
344         Corkscrew_counterrotate = !Corkscrew_counterrotate;
345
346         cscrew_display_dcf();
347 }
348
349 DCF(cscrew_shrink, "Shrink the radius of every other missile")
350 {
351         Corkscrew_shrink = !Corkscrew_shrink;
352
353         cscrew_display_dcf();
354 }
355
356 DCF(cscrew_shrinkval, "Change the rate at which the radii shrink")
357 {
358         dc_get_arg(ARG_FLOAT);
359         if(Dc_arg_type & ARG_FLOAT){
360                 Corkscrew_shrink_val = Dc_arg_float;
361         }
362
363         cscrew_display_dcf();
364 }
365
366 DCF(cscrew_down, "Cause the missile to spiral down first")
367 {
368         Corkscrew_down_first = !Corkscrew_down_first;
369
370         cscrew_display_dcf();
371 }
372