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 SDL_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 SDL_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 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);
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)
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);
211 // get various useful pointers
212 wp = &Weapons[objp->instance];
213 ci = &Corkscrew_missiles[wp->cscrew_index];
215 // move to the outside of the corkscrew
219 vm_vec_add2(&objp->pos, &neg);
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;
225 // rotate the missile position
226 vm_rot_point_around_line(&new_pt, &objp->pos, twist_val, &cen, &objp->orient.v.fvec);
229 // rotate the missile itself
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);
239 // mark down this position so we can orient nicely _next_ frame
240 ci->last_corkscrew_pos = objp->pos;
243 // get the new center pointing vector
244 vm_vec_sub(&ci->cen_p, &cen, &objp->pos);
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);
252 trail_set_segment( wp->trail_num, &objp->pos );
257 // debug console functionality
258 void cscrew_display_dcf()
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);
266 dc_printf("Helix (cscrew_helix): ON\n");
268 dc_printf("Helix (cscrew_helix): OFF\n");
270 if(Corkscrew_counterrotate){
271 dc_printf("Counterrotate (cscrew_counter): ON\n");
273 dc_printf("Counterrotate (cscrew_counter): OFF\n");
275 if(Corkscrew_shrink){
276 dc_printf("Shrink (cscrew_shrink): ON\n");
278 dc_printf("Shrink (cscrew_shrink): OFF\n");
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");
284 dc_printf("Corkscrew down first : OFF\n");
288 DCF(cscrew, "Listing of corkscrew missile debug console functions")
290 cscrew_display_dcf();
293 DCF(cscrew_delay, "Change the delay between corkscrew firing")
296 if(Dc_arg_type & ARG_INT){
297 Corkscrew_missile_delay = Dc_arg_int;
300 cscrew_display_dcf();
303 DCF(cscrew_count, "Change the # of corkscrew missiles fired")
306 if(Dc_arg_type & ARG_INT){
307 Corkscrew_num_missiles_fired = Dc_arg_int;
310 cscrew_display_dcf();
313 DCF(cscrew_radius, "Change the radius of corkscrew missiles")
315 dc_get_arg(ARG_FLOAT);
316 if(Dc_arg_type & ARG_FLOAT){
317 Corkscrew_radius = Dc_arg_float;
320 cscrew_display_dcf();
323 DCF(cscrew_twist, "Change the rate of the corkscrew twist")
325 dc_get_arg(ARG_FLOAT);
326 if(Dc_arg_type & ARG_FLOAT){
327 Corkscrew_twist = Dc_arg_float;
330 cscrew_display_dcf();
333 DCF(cscrew_helix, "Attempt to orient missile nicely along the corkscrew")
335 Corkscrew_helix = !Corkscrew_helix;
337 cscrew_display_dcf();
340 DCF(cscrew_counter, "Counterrotate every other missile")
342 Corkscrew_counterrotate = !Corkscrew_counterrotate;
344 cscrew_display_dcf();
347 DCF(cscrew_shrink, "Shrink the radius of every other missile")
349 Corkscrew_shrink = !Corkscrew_shrink;
351 cscrew_display_dcf();
354 DCF(cscrew_shrinkval, "Change the rate at which the radii shrink")
356 dc_get_arg(ARG_FLOAT);
357 if(Dc_arg_type & ARG_FLOAT){
358 Corkscrew_shrink_val = Dc_arg_float;
361 cscrew_display_dcf();
364 DCF(cscrew_down, "Cause the missile to spiral down first")
366 Corkscrew_down_first = !Corkscrew_down_first;
368 cscrew_display_dcf();