2 * $Logfile: /Freespace2/code/Weapon/Corkscrew.cpp $
7 * C module for managing corkscrew missiles
12 #include "corkscrew.h"
16 #include "freespace.h" // for Missiontime
19 // corkscrew structure flags
20 #define CS_FLAG_USED (1<<0) // this structure is in use
21 #define CS_FLAG_COUNTER (1<<1) // counterrotate this guy
24 int Corkscrew_missile_delay = 30; // delay between missile firings
25 int Corkscrew_num_missiles_fired = 4; // # of missiles fire in one shot
26 float Corkscrew_radius = 1.25f; // radius of the corkscrew itself
27 float Corkscrew_twist = 5.0f; // in degrees/second
28 int Corkscrew_helix = 1; // attempt to point the missile in the right direction
29 int Corkscrew_counterrotate = 1; // counterrotate every other missile
30 int Corkscrew_shrink = 0; // shrink the radius of every successive missile
31 float Corkscrew_shrink_val = 0.3f; // rate at which the radius shrinks
32 int Corkscrew_down_first = 1; // have the corkscrew go "down" first
34 // current counterrotation and radius shrink values
35 float Corkscrew_radius_cur = Corkscrew_radius;
37 typedef struct cscrew_info {
38 int flags; // flags for the missile
40 // info about the corkscrew effect for this missile
41 vector cen_p; // vector pointing to the "center" of the corkscrew
42 float radius; // radius of the corkscrew
43 matrix real_orient; // the orientation used when calling physics (bashed before rendering)
44 vector last_corkscrew_pos; // last position along the corkscrew
47 #define MAX_CORKSCREW_MISSILES 100
48 cscrew_info Corkscrew_missiles[MAX_CORKSCREW_MISSILES];
50 // ------------------------------------------------------------------
51 // cscrew_level_init()
53 // Called at the start of each new mission
55 void cscrew_level_init()
57 memset(Corkscrew_missiles, 0, sizeof(cscrew_info) * MAX_CORKSCREW_MISSILES);
60 // ------------------------------------------------------------------
61 // cscrew_maybe_fire_missile()
63 // Check if there are any swarm missiles to fire, and if enough time
64 // has elapsed since last one fired, go ahead and fire it.
66 // This is called once per ship frame in ship_move()
68 void cscrew_maybe_fire_missile(int shipnum)
72 int weapon_info_index;
74 Assert(shipnum >= 0 && shipnum < MAX_SHIPS );
77 // make sure we're supposed to be firing some missiles
78 if ( sp->num_corkscrew_to_fire <= 0 ){
82 // make sure we have a valid weapon band
84 if ( swp->current_secondary_bank == -1 ) {
85 sp->num_corkscrew_to_fire = 0;
89 weapon_info_index = swp->secondary_bank_weapons[swp->current_secondary_bank];
90 Assert( weapon_info_index >= 0 && weapon_info_index < MAX_WEAPON_TYPES );
92 // if current secondary bank is not a corkscrew missile, return
93 if ( !(Weapon_info[weapon_info_index].wi_flags & WIF_CORKSCREW) ) {
94 sp->num_corkscrew_to_fire = 0;
98 if ( timestamp_elapsed(sp->next_corkscrew_fire) ) {
99 sp->next_corkscrew_fire = timestamp(Corkscrew_missile_delay);
100 ship_fire_secondary( &Objects[sp->objnum], 1 );
101 sp->num_corkscrew_to_fire--;
105 // ------------------------------------------------------------------
108 // Get a free corkscrew missile entry, and initialize the struct members
110 int cscrew_create(object *obj)
113 cscrew_info *cscrewp = NULL;
115 for ( i = 0; i < MAX_CORKSCREW_MISSILES; i++ ) {
116 cscrewp = &Corkscrew_missiles[i];
117 if ( !(cscrewp->flags & CS_FLAG_USED) ) {
122 if ( i >= MAX_CORKSCREW_MISSILES ) {
123 nprintf(("Warning","No more corkscrew missiles are available\n"));
127 // mark the guy as "used"
128 cscrewp->flags = CS_FLAG_USED;
130 // determine if he is counterrotating
131 if(Corkscrew_counterrotate){
132 if(frand_range(0.0f, 1.0f) < 0.5f){
133 cscrewp->flags |= CS_FLAG_COUNTER;
137 // get the "center" pointing vector
139 neg = obj->orient.uvec;
140 if(Corkscrew_down_first){
143 vm_vec_scale_add2(&cscrewp->cen_p, &neg, Corkscrew_radius);
145 // move the missile up so that the corkscrew point is at the muzzle of the gun
146 // vm_vec_scale_add2(&obj->pos, &obj->orient.uvec, Corkscrew_radius);
148 // store some initial helix params
149 cscrewp->real_orient = obj->orient;
150 cscrewp->last_corkscrew_pos = obj->pos;
155 // ------------------------------------------------------------------
159 void cscrew_delete(int i)
161 if ( !(Corkscrew_missiles[i].flags & CS_FLAG_USED) ) {
165 memset(&Corkscrew_missiles[i], 0, sizeof(cscrew_info));
168 // pre process the corkscrew weapon by putting him in the "center" of his corkscrew
169 void cscrew_process_pre(object *objp)
174 Assert(objp->type == OBJ_WEAPON);
175 Assert(Weapons[objp->instance].cscrew_index >= 0);
176 Assert(Corkscrew_missiles[Weapons[objp->instance].cscrew_index].flags & CS_FLAG_USED);
178 ci = &Corkscrew_missiles[Weapons[objp->instance].cscrew_index];
180 // unrotate the missile itself
182 // restore the "real" matrix now
183 objp->orient = ci->real_orient;
185 // move the missile back to the center of the corkscrew
186 vm_vec_add2(&objp->pos, &ci->cen_p);
189 // post process the corkscrew weapon by putting him back to the right spot on his corkscrew
190 void cscrew_process_post(object *objp)
200 Assert(objp->type == OBJ_WEAPON);
201 Assert(Weapons[objp->instance].cscrew_index >= 0);
202 Assert(Corkscrew_missiles[Weapons[objp->instance].cscrew_index].flags & CS_FLAG_USED);
204 // get various useful pointers
205 wp = &Weapons[objp->instance];
206 wip = &Weapon_info[wp->weapon_info_index];
207 ci = &Corkscrew_missiles[wp->cscrew_index];
209 // move to the outside of the corkscrew
213 vm_vec_add2(&objp->pos, &neg);
215 // determine what direction (clockwise or counterclockwise) the missile will spin
216 twist_val = ci->flags & CS_FLAG_COUNTER ? -Corkscrew_twist : Corkscrew_twist;
217 twist_val *= flFrametime;
219 // rotate the missile position
220 vm_rot_point_around_line(&new_pt, &objp->pos, twist_val, &cen, &objp->orient.fvec);
223 // rotate the missile itself
227 // compute a "fake" orient and store the old one for safekeeping
228 ci->real_orient = objp->orient;
229 vm_vec_sub(&dir, &objp->pos, &ci->last_corkscrew_pos);
230 vm_vec_normalize(&dir);
231 vm_vector_2_matrix(&objp->orient, &dir, NULL, NULL);
233 // mark down this position so we can orient nicely _next_ frame
234 ci->last_corkscrew_pos = objp->pos;
237 // get the new center pointing vector
238 vm_vec_sub(&ci->cen_p, &cen, &objp->pos);
240 // do trail stuff here
241 if ( wp->trail_num > -1 ) {
242 if (trail_stamp_elapsed(wp->trail_num)) {
243 trail_add_segment( wp->trail_num, &objp->pos );
244 trail_set_stamp(wp->trail_num);
246 trail_set_segment( wp->trail_num, &objp->pos );
251 // debug console functionality
252 void cscrew_display_dcf()
254 dc_printf("Corkscrew settings\n\n");
255 dc_printf("Delay (cscrew_delay) : %d\n",Corkscrew_missile_delay);
256 dc_printf("Count (cscrew_count) : %d\n",Corkscrew_num_missiles_fired);
257 dc_printf("Radius (cscrew_radius) : %f\n",Corkscrew_radius);
258 dc_printf("Twist (cscrew_twist) : %f\n",Corkscrew_twist);
260 dc_printf("Helix (cscrew_helix): ON\n");
262 dc_printf("Helix (cscrew_helix): OFF\n");
264 if(Corkscrew_counterrotate){
265 dc_printf("Counterrotate (cscrew_counter): ON\n");
267 dc_printf("Counterrotate (cscrew_counter): OFF\n");
269 if(Corkscrew_shrink){
270 dc_printf("Shrink (cscrew_shrink): ON\n");
272 dc_printf("Shrink (cscrew_shrink): OFF\n");
274 dc_printf("Corkscrew shrink (cscrew_shrinkval): %f\n", Corkscrew_shrink_val);
275 if(Corkscrew_down_first){
276 dc_printf("Corkscrew down first : ON\n");
278 dc_printf("Corkscrew down first : OFF\n");
282 DCF(cscrew, "Listing of corkscrew missile debug console functions")
284 cscrew_display_dcf();
287 DCF(cscrew_delay, "Change the delay between corkscrew firing")
290 if(Dc_arg_type & ARG_INT){
291 Corkscrew_missile_delay = Dc_arg_int;
294 cscrew_display_dcf();
297 DCF(cscrew_count, "Change the # of corkscrew missiles fired")
300 if(Dc_arg_type & ARG_INT){
301 Corkscrew_num_missiles_fired = Dc_arg_int;
304 cscrew_display_dcf();
307 DCF(cscrew_radius, "Change the radius of corkscrew missiles")
309 dc_get_arg(ARG_FLOAT);
310 if(Dc_arg_type & ARG_FLOAT){
311 Corkscrew_radius = Dc_arg_float;
314 cscrew_display_dcf();
317 DCF(cscrew_twist, "Change the rate of the corkscrew twist")
319 dc_get_arg(ARG_FLOAT);
320 if(Dc_arg_type & ARG_FLOAT){
321 Corkscrew_twist = Dc_arg_float;
324 cscrew_display_dcf();
327 DCF(cscrew_helix, "Attempt to orient missile nicely along the corkscrew")
329 Corkscrew_helix = !Corkscrew_helix;
331 cscrew_display_dcf();
334 DCF(cscrew_counter, "Counterrotate every other missile")
336 Corkscrew_counterrotate = !Corkscrew_counterrotate;
338 cscrew_display_dcf();
341 DCF(cscrew_shrink, "Shrink the radius of every other missile")
343 Corkscrew_shrink = !Corkscrew_shrink;
345 cscrew_display_dcf();
348 DCF(cscrew_shrinkval, "Change the rate at which the radii shrink")
350 dc_get_arg(ARG_FLOAT);
351 if(Dc_arg_type & ARG_FLOAT){
352 Corkscrew_shrink_val = Dc_arg_float;
355 cscrew_display_dcf();
358 DCF(cscrew_down, "Cause the missile to spiral down first")
360 Corkscrew_down_first = !Corkscrew_down_first;
362 cscrew_display_dcf();