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/Weapon/Corkscrew.cpp $
15 * C module for managing corkscrew missiles
20 #include "corkscrew.h"
24 #include "freespace.h" // for Missiontime
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
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
42 // current counterrotation and radius shrink values
43 float Corkscrew_radius_cur = Corkscrew_radius;
45 typedef struct cscrew_info {
46 int flags; // flags for the missile
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
55 #define MAX_CORKSCREW_MISSILES 100
56 cscrew_info Corkscrew_missiles[MAX_CORKSCREW_MISSILES];
58 // ------------------------------------------------------------------
59 // cscrew_level_init()
61 // Called at the start of each new mission
63 void cscrew_level_init()
65 memset(Corkscrew_missiles, 0, sizeof(cscrew_info) * MAX_CORKSCREW_MISSILES);
68 // ------------------------------------------------------------------
69 // cscrew_maybe_fire_missile()
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.
74 // This is called once per ship frame in ship_move()
76 void cscrew_maybe_fire_missile(int shipnum)
80 int weapon_info_index;
82 Assert(shipnum >= 0 && shipnum < MAX_SHIPS );
85 // make sure we're supposed to be firing some missiles
86 if ( sp->num_corkscrew_to_fire <= 0 ){
90 // make sure we have a valid weapon band
92 if ( swp->current_secondary_bank == -1 ) {
93 sp->num_corkscrew_to_fire = 0;
97 weapon_info_index = swp->secondary_bank_weapons[swp->current_secondary_bank];
98 Assert( weapon_info_index >= 0 && weapon_info_index < MAX_WEAPON_TYPES );
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;
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--;
113 // ------------------------------------------------------------------
116 // Get a free corkscrew missile entry, and initialize the struct members
118 int cscrew_create(object *obj)
121 cscrew_info *cscrewp = NULL;
123 for ( i = 0; i < MAX_CORKSCREW_MISSILES; i++ ) {
124 cscrewp = &Corkscrew_missiles[i];
125 if ( !(cscrewp->flags & CS_FLAG_USED) ) {
130 if ( i >= MAX_CORKSCREW_MISSILES ) {
131 nprintf(("Warning","No more corkscrew missiles are available\n"));
135 // mark the guy as "used"
136 cscrewp->flags = CS_FLAG_USED;
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;
145 // get the "center" pointing vector
147 neg = obj->orient.v.uvec;
148 if(Corkscrew_down_first){
151 vm_vec_scale_add2(&cscrewp->cen_p, &neg, Corkscrew_radius);
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);
156 // store some initial helix params
157 cscrewp->real_orient = obj->orient;
158 cscrewp->last_corkscrew_pos = obj->pos;
163 // ------------------------------------------------------------------
167 void cscrew_delete(int i)
169 if ( !(Corkscrew_missiles[i].flags & CS_FLAG_USED) ) {
173 memset(&Corkscrew_missiles[i], 0, sizeof(cscrew_info));
176 // pre process the corkscrew weapon by putting him in the "center" of his corkscrew
177 void cscrew_process_pre(object *objp)
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);
186 ci = &Corkscrew_missiles[Weapons[objp->instance].cscrew_index];
188 // unrotate the missile itself
190 // restore the "real" matrix now
191 objp->orient = ci->real_orient;
193 // move the missile back to the center of the corkscrew
194 vm_vec_add2(&objp->pos, &ci->cen_p);
197 // post process the corkscrew weapon by putting him back to the right spot on his corkscrew
198 void cscrew_process_post(object *objp)
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);
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];
217 // move to the outside of the corkscrew
221 vm_vec_add2(&objp->pos, &neg);
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;
227 // rotate the missile position
228 vm_rot_point_around_line(&new_pt, &objp->pos, twist_val, &cen, &objp->orient.v.fvec);
231 // rotate the missile itself
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);
241 // mark down this position so we can orient nicely _next_ frame
242 ci->last_corkscrew_pos = objp->pos;
245 // get the new center pointing vector
246 vm_vec_sub(&ci->cen_p, &cen, &objp->pos);
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);
254 trail_set_segment( wp->trail_num, &objp->pos );
259 // debug console functionality
260 void cscrew_display_dcf()
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);
268 dc_printf("Helix (cscrew_helix): ON\n");
270 dc_printf("Helix (cscrew_helix): OFF\n");
272 if(Corkscrew_counterrotate){
273 dc_printf("Counterrotate (cscrew_counter): ON\n");
275 dc_printf("Counterrotate (cscrew_counter): OFF\n");
277 if(Corkscrew_shrink){
278 dc_printf("Shrink (cscrew_shrink): ON\n");
280 dc_printf("Shrink (cscrew_shrink): OFF\n");
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");
286 dc_printf("Corkscrew down first : OFF\n");
290 DCF(cscrew, "Listing of corkscrew missile debug console functions")
292 cscrew_display_dcf();
295 DCF(cscrew_delay, "Change the delay between corkscrew firing")
298 if(Dc_arg_type & ARG_INT){
299 Corkscrew_missile_delay = Dc_arg_int;
302 cscrew_display_dcf();
305 DCF(cscrew_count, "Change the # of corkscrew missiles fired")
308 if(Dc_arg_type & ARG_INT){
309 Corkscrew_num_missiles_fired = Dc_arg_int;
312 cscrew_display_dcf();
315 DCF(cscrew_radius, "Change the radius of corkscrew missiles")
317 dc_get_arg(ARG_FLOAT);
318 if(Dc_arg_type & ARG_FLOAT){
319 Corkscrew_radius = Dc_arg_float;
322 cscrew_display_dcf();
325 DCF(cscrew_twist, "Change the rate of the corkscrew twist")
327 dc_get_arg(ARG_FLOAT);
328 if(Dc_arg_type & ARG_FLOAT){
329 Corkscrew_twist = Dc_arg_float;
332 cscrew_display_dcf();
335 DCF(cscrew_helix, "Attempt to orient missile nicely along the corkscrew")
337 Corkscrew_helix = !Corkscrew_helix;
339 cscrew_display_dcf();
342 DCF(cscrew_counter, "Counterrotate every other missile")
344 Corkscrew_counterrotate = !Corkscrew_counterrotate;
346 cscrew_display_dcf();
349 DCF(cscrew_shrink, "Shrink the radius of every other missile")
351 Corkscrew_shrink = !Corkscrew_shrink;
353 cscrew_display_dcf();
356 DCF(cscrew_shrinkval, "Change the rate at which the radii shrink")
358 dc_get_arg(ARG_FLOAT);
359 if(Dc_arg_type & ARG_FLOAT){
360 Corkscrew_shrink_val = Dc_arg_float;
363 cscrew_display_dcf();
366 DCF(cscrew_down, "Cause the missile to spiral down first")
368 Corkscrew_down_first = !Corkscrew_down_first;
370 cscrew_display_dcf();