]> icculus.org git repositories - taylor/freespace2.git/blob - src/weapon/corkscrew.cpp
fix compiling issues with lang changes
[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         SDL_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         SDL_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         SDL_assert(objp->type == OBJ_WEAPON);   
183         SDL_assert(Weapons[objp->instance].cscrew_index >= 0);
184         SDL_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         cscrew_info *ci;
204         float twist_val;
205
206         // check stuff
207         SDL_assert(objp->type == OBJ_WEAPON);   
208         SDL_assert(Weapons[objp->instance].cscrew_index >= 0);
209         SDL_assert(Corkscrew_missiles[Weapons[objp->instance].cscrew_index].flags & CS_FLAG_USED);
210
211         // get various useful pointers
212         wp = &Weapons[objp->instance];
213         ci = &Corkscrew_missiles[wp->cscrew_index];
214
215         // move to the outside of the corkscrew                 
216         neg = ci->cen_p;
217         cen = objp->pos;        
218         vm_vec_negate(&neg);            
219         vm_vec_add2(&objp->pos, &neg);          
220
221         // determine what direction (clockwise or counterclockwise) the missile will spin       
222         twist_val = ci->flags & CS_FLAG_COUNTER ? -Corkscrew_twist : Corkscrew_twist;
223         twist_val *= flFrametime;       
224         
225         // rotate the missile position
226         vm_rot_point_around_line(&new_pt, &objp->pos, twist_val, &cen, &objp->orient.v.fvec);
227         objp->pos = new_pt;
228
229         // rotate the missile itself
230         if(Corkscrew_helix){            
231                 vector dir;
232         
233                 // compute a "fake" orient and store the old one for safekeeping
234                 ci->real_orient = objp->orient;
235                 vm_vec_sub(&dir, &objp->pos, &ci->last_corkscrew_pos);
236                 vm_vec_normalize(&dir);
237                 vm_vector_2_matrix(&objp->orient, &dir, NULL, NULL);    
238                 
239                 // mark down this position so we can orient nicely _next_ frame
240                 ci->last_corkscrew_pos = objp->pos;
241         }       
242
243         // get the new center pointing vector
244         vm_vec_sub(&ci->cen_p, &cen, &objp->pos);
245
246         // do trail stuff here
247         if ( wp->trail_num > -1 )       {
248                 if (trail_stamp_elapsed(wp->trail_num)) {
249                         trail_add_segment( wp->trail_num, &objp->pos );
250                         trail_set_stamp(wp->trail_num);
251                 } else {
252                         trail_set_segment( wp->trail_num, &objp->pos );
253                 }
254         }       
255 }
256
257 // debug console functionality
258 void cscrew_display_dcf()
259 {
260         dc_printf("Corkscrew settings\n\n");
261         dc_printf("Delay (cscrew_delay) : %d\n",Corkscrew_missile_delay);
262         dc_printf("Count (cscrew_count) : %d\n",Corkscrew_num_missiles_fired);
263         dc_printf("Radius (cscrew_radius) :     %f\n",Corkscrew_radius);
264         dc_printf("Twist (cscrew_twist) : %f\n",Corkscrew_twist);       
265         if(Corkscrew_helix){
266                 dc_printf("Helix (cscrew_helix): ON\n");
267         } else {
268                 dc_printf("Helix (cscrew_helix): OFF\n");
269         }
270         if(Corkscrew_counterrotate){
271                 dc_printf("Counterrotate (cscrew_counter): ON\n");
272         } else {
273                 dc_printf("Counterrotate (cscrew_counter): OFF\n");
274         }
275         if(Corkscrew_shrink){
276                 dc_printf("Shrink (cscrew_shrink): ON\n");
277         } else {
278                 dc_printf("Shrink (cscrew_shrink): OFF\n");
279         }
280         dc_printf("Corkscrew shrink (cscrew_shrinkval): %f\n", Corkscrew_shrink_val);
281         if(Corkscrew_down_first){
282                 dc_printf("Corkscrew down first : ON\n");
283         } else {
284                 dc_printf("Corkscrew down first : OFF\n");
285         }
286 }
287
288 DCF(cscrew, "Listing of corkscrew missile debug console functions")
289 {
290         cscrew_display_dcf();
291 }
292
293 DCF(cscrew_delay, "Change the delay between corkscrew firing")
294 {       
295         dc_get_arg(ARG_INT);
296         if(Dc_arg_type & ARG_INT){
297                 Corkscrew_missile_delay = Dc_arg_int;           
298         }
299
300         cscrew_display_dcf();
301 }
302
303 DCF(cscrew_count, "Change the # of corkscrew missiles fired")
304 {       
305         dc_get_arg(ARG_INT);
306         if(Dc_arg_type & ARG_INT){
307                 Corkscrew_num_missiles_fired = Dc_arg_int;              
308         }
309
310         cscrew_display_dcf();
311 }
312
313 DCF(cscrew_radius, "Change the radius of corkscrew missiles")
314 {       
315         dc_get_arg(ARG_FLOAT);
316         if(Dc_arg_type & ARG_FLOAT){
317                 Corkscrew_radius = Dc_arg_float;
318         }
319
320         cscrew_display_dcf();
321 }
322
323 DCF(cscrew_twist, "Change the rate of the corkscrew twist")
324 {
325         dc_get_arg(ARG_FLOAT);
326         if(Dc_arg_type & ARG_FLOAT){
327                 Corkscrew_twist = Dc_arg_float;
328         }
329
330         cscrew_display_dcf();
331 }
332
333 DCF(cscrew_helix, "Attempt to orient missile nicely along the corkscrew")
334 {
335         Corkscrew_helix = !Corkscrew_helix;
336
337         cscrew_display_dcf();
338 }
339
340 DCF(cscrew_counter, "Counterrotate every other missile")
341 {
342         Corkscrew_counterrotate = !Corkscrew_counterrotate;
343
344         cscrew_display_dcf();
345 }
346
347 DCF(cscrew_shrink, "Shrink the radius of every other missile")
348 {
349         Corkscrew_shrink = !Corkscrew_shrink;
350
351         cscrew_display_dcf();
352 }
353
354 DCF(cscrew_shrinkval, "Change the rate at which the radii shrink")
355 {
356         dc_get_arg(ARG_FLOAT);
357         if(Dc_arg_type & ARG_FLOAT){
358                 Corkscrew_shrink_val = Dc_arg_float;
359         }
360
361         cscrew_display_dcf();
362 }
363
364 DCF(cscrew_down, "Cause the missile to spiral down first")
365 {
366         Corkscrew_down_first = !Corkscrew_down_first;
367
368         cscrew_display_dcf();
369 }
370