FS2_Open
Open source remastering of the Freespace 2 engine
physics.cpp
Go to the documentation of this file.
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 the
6  * source.
7  *
8 */
9 
10 
11 
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <math.h>
16 
17 #include "ai/ai_profiles.h" // for the damping issue
18 #include "freespace2/freespace.h"
19 #include "io/timer.h"
20 #include "mission/missionparse.h"
21 #include "mod_table/mod_table.h"
22 #include "physics/physics.h"
23 #include "ship/ship.h"
24 
25 
26 
27 // defines for physics functions
28 #define MAX_TURN_LIMIT 0.2618f // about 15 degrees
29 
30 #define ROTVEL_TOL 0.1 // Amount of rotvel is decreased if over cap
31 #define ROTVEL_CAP 14.0 // Rotational velocity cap for live objects
32 #define DEAD_ROTVEL_CAP 16.3 // Rotational velocity cap for dead objects
33 
34 #define MAX_SHIP_SPEED 500 // Maximum speed allowed after whack or shockwave
35 #define RESET_SHIP_SPEED 440 // Speed that a ship is reset to after exceeding MAX_SHIP_SPEED
36 
37 #define SW_ROT_FACTOR 5 // increase in rotational time constant in shockwave
38 #define SW_BLAST_DURATION 2000 // maximum duration of shockwave
39 #define REDUCED_DAMP_FACTOR 10 // increase in side_slip and acceleration time constants (scaled according to reduced damp time)
40 #define REDUCED_DAMP_VEL 30 // change in velocity at which reduced_damp_time is 2000 ms
41 #define REDUCED_DAMP_TIME 2000 // ms (2.0 sec)
42 #define WEAPON_SHAKE_TIME 500 // ms (0.5 sec) viewer shake time after hit by weapon (implemented via afterburner shake)
43 #define SPECIAL_WARP_T_CONST 0.651 // special warp time constant (loose 99 % of excess speed in 3 sec)
44 
45 void update_reduced_damp_timestamp( physics_info *pi, float impulse );
46 float velocity_ramp (float v_in, float v_goal, float time_const, float t);
47 float glide_ramp (float v_in, float v_goal, float ramp_time_const, float accel_mult, float t);
48 
50 {
51  memset( pi, 0, sizeof(physics_info) );
52 
53  pi->mass = 10.0f; // This ship weighs 10 units
54  pi->side_slip_time_const = 0.05f;
55  pi->rotdamp = 0.1f;
56 
57  pi->max_vel.xyz.x = 100.0f; //sideways
58  pi->max_vel.xyz.y = 100.0f; //up/down
59  pi->max_vel.xyz.z = 100.0f; //forward
60  pi->max_rear_vel = 100.0f; //backward -- controlled seperately
61 
62  pi->max_rotvel.xyz.x = 2.0f; //pitch
63  pi->max_rotvel.xyz.y = 1.0f; //heading
64  pi->max_rotvel.xyz.z = 2.0f; //bank
65 
66  pi->prev_ramp_vel.xyz.x = 0.0f;
67  pi->prev_ramp_vel.xyz.y = 0.0f;
68  pi->prev_ramp_vel.xyz.z = 0.0f;
69 
70  pi->desired_vel.xyz.x = 0.0f;
71  pi->desired_vel.xyz.y = 0.0f;
72  pi->desired_vel.xyz.z = 0.0f;
73 
74  pi->slide_accel_time_const=pi->side_slip_time_const; // slide using max_vel.xyz.x & .xyz.y
75  pi->slide_decel_time_const=pi->side_slip_time_const; // slide using max_vel.xyz.x & .xyz.y
76 
77  pi->afterburner_decay = 1;
78  pi->forward_thrust = 0.0f;
79  pi->vert_thrust = 0.0f; //added these two in order to get side and forward thrusters
80  pi->side_thrust = 0.0f; //to glow brighter when the ship is moving in the right direction -Bobboau
81 
82  pi->flags = 0;
83 
84  // default values for moment of inertia
85  vm_vec_make( &pi->I_body_inv.vec.rvec, 1e-5f, 0.0f, 0.0f );
86  vm_vec_make( &pi->I_body_inv.vec.uvec, 0.0f, 1e-5f, 0.0f );
87  vm_vec_make( &pi->I_body_inv.vec.fvec, 0.0f, 0.0f, 1e-5f );
88 
89 }
90 
91 
92 //==========================================================================
93 // apply_physics - This does correct physics independent of frame rate.
94 //
95 // Given:
96 // damping = damping factor. Setting this to zero make the object instantly
97 // go to the target velocity. Increasing it makes the object ramp
98 // up or down to the target velocity.
99 // desired_vel = the target velocity
100 // initial_vel = velocity at last call
101 // t = elapsed time since last call
102 //
103 // Returns:
104 // new_vel = current velocity
105 // delta_pos = delta position (framevec)
106 // You can extend this to 3d by calling it 3 times, once for each x,y,z component.
107 
108 void apply_physics( float damping, float desired_vel, float initial_vel, float t, float * new_vel, float * delta_pos )
109 {
110  if ( damping < 0.0001f ) {
111  if ( delta_pos )
112  *delta_pos = desired_vel*t;
113  if ( new_vel )
114  *new_vel = desired_vel;
115  } else {
116  float dv, e;
117  dv = initial_vel - desired_vel;
118  e = (float)exp( -t/damping );
119  if ( delta_pos )
120  *delta_pos = (1.0f - e)*dv*damping + desired_vel*t;
121  if ( new_vel )
122  *new_vel = dv*e + desired_vel;
123  }
124 }
125 
126 
127 
128 float Physics_viewer_bank = 0.0f;
131 
132 // If you would like Physics_viewer_bank to be tracked (Which is needed
133 // for rotating 3d bitmaps) call this and pass it a pointer to the
134 // viewer's physics info.
136 {
137  if ( (Viewer_physics_info != p) || (Physics_viewer_direction != dir) ) {
138  Viewer_physics_info = p;
139  Physics_viewer_bank = 0.0f;
141  }
142 }
143 
144 
145 
146 // -----------------------------------------------------------------------------------------------------------
147 // add rotational velocity & acceleration
148 
149 
150 
151 void physics_sim_rot(matrix * orient, physics_info * pi, float sim_time )
152 {
153  angles tangles;
154  vec3d new_vel;
155  matrix tmp;
156  float shock_amplitude;
157  float rotdamp;
158  float shock_fraction_time_left;
159 
160  Assert(is_valid_matrix(orient));
161  Assert(is_valid_vec(&pi->rotvel));
163 
164  // Handle special case of shockwave
165  shock_amplitude = 0.0f;
166  if ( pi->flags & PF_IN_SHOCKWAVE ) {
167  if ( timestamp_elapsed(pi->shockwave_decay) ) {
168  pi->flags &= ~PF_IN_SHOCKWAVE;
169  rotdamp = pi->rotdamp;
170  } else {
171  shock_fraction_time_left = timestamp_until( pi->shockwave_decay ) / (float) SW_BLAST_DURATION;
172  rotdamp = pi->rotdamp + pi->rotdamp * (SW_ROT_FACTOR - 1) * shock_fraction_time_left;
173  shock_amplitude = pi->shockwave_shake_amp * shock_fraction_time_left;
174  }
175  } else {
176  rotdamp = pi->rotdamp;
177  }
178 
179  // Do rotational physics with given damping
180  apply_physics( rotdamp, pi->desired_rotvel.xyz.x, pi->rotvel.xyz.x, sim_time, &new_vel.xyz.x, NULL );
181  apply_physics( rotdamp, pi->desired_rotvel.xyz.y, pi->rotvel.xyz.y, sim_time, &new_vel.xyz.y, NULL );
182  apply_physics( rotdamp, pi->desired_rotvel.xyz.z, pi->rotvel.xyz.z, sim_time, &new_vel.xyz.z, NULL );
183 
184  Assert(is_valid_vec(&new_vel));
185 
186  pi->rotvel = new_vel;
187 
188  tangles.p = pi->rotvel.xyz.x*sim_time;
189  tangles.h = pi->rotvel.xyz.y*sim_time;
190  tangles.b = pi->rotvel.xyz.z*sim_time;
191 
192 /* // Make ship shake due to afterburner.
193  if (pi->flags & PF_AFTERBURNER_ON || !timestamp_elapsed(pi->afterburner_decay) ) {
194  float max_speed;
195 
196  max_speed = vm_vec_mag_quick(&pi->max_vel);
197  tangles.p += (float) (rand()-RAND_MAX_2) * RAND_MAX_1f * pi->speed/max_speed/64.0f;
198  tangles.h += (float) (rand()-RAND_MAX_2) * RAND_MAX_1f * pi->speed/max_speed/64.0f;
199  if ( pi->flags & PF_AFTERBURNER_ON ) {
200  pi->afterburner_decay = timestamp(ABURN_DECAY_TIME);
201  }
202  }
203 */
204 
205  // Make ship shake due to shockwave, decreasing in amplitude at the end of the shockwave
206  if ( pi->flags & PF_IN_SHOCKWAVE ) {
207  tangles.p += (float) (myrand()-RAND_MAX_2) * RAND_MAX_1f * shock_amplitude;
208  tangles.h += (float) (myrand()-RAND_MAX_2) * RAND_MAX_1f * shock_amplitude;
209  }
210 
211 
212  vm_angles_2_matrix(&pi->last_rotmat, &tangles );
213  vm_matrix_x_matrix( &tmp, orient, &pi->last_rotmat );
214  *orient = tmp;
215 
216  vm_orthogonalize_matrix(orient);
217 
218 }
219 
220 // -----------------------------------------------------------------------------------------------------------
221 // add rotational velocity & acceleration
222 
223 void physics_sim_rot_editor(matrix * orient, physics_info * pi, float sim_time)
224 {
225  angles tangles;
226  vec3d new_vel;
227  matrix tmp;
228  angles t1, t2;
229 
230  apply_physics( pi->rotdamp, pi->desired_rotvel.xyz.x, pi->rotvel.xyz.x, sim_time,
231  &new_vel.xyz.x, NULL );
232 
233  apply_physics( pi->rotdamp, pi->desired_rotvel.xyz.y, pi->rotvel.xyz.y, sim_time,
234  &new_vel.xyz.y, NULL );
235 
236  apply_physics( pi->rotdamp, pi->desired_rotvel.xyz.z, pi->rotvel.xyz.z, sim_time,
237  &new_vel.xyz.z, NULL );
238 
239  pi->rotvel = new_vel;
240 
241  tangles.p = pi->rotvel.xyz.x*sim_time;
242  tangles.h = pi->rotvel.xyz.y*sim_time;
243  tangles.b = pi->rotvel.xyz.z*sim_time;
244 
245  t1 = t2 = tangles;
246  t1.h = 0.0f; t1.b = 0.0f;
247  t2.p = 0.0f; t2.b = 0.0f;
248 
249  // put in p & b like normal
250  vm_angles_2_matrix(&pi->last_rotmat, &t1 );
251  vm_matrix_x_matrix( &tmp, orient, &pi->last_rotmat );
252 
253  // Put in heading separately
254  vm_angles_2_matrix(&pi->last_rotmat, &t2 );
255  vm_matrix_x_matrix( orient, &pi->last_rotmat, &tmp );
256 
257  vm_orthogonalize_matrix(orient);
258 
259 }
260 
261 // Adds velocity to position
262 // finds velocity and displacement in local coords
263 void physics_sim_vel(vec3d * position, physics_info * pi, float sim_time, matrix *orient)
264 {
265  vec3d local_disp; // displacement in this frame
266  vec3d local_v_in; // velocity in local coords at the start of this frame
267  vec3d local_desired_vel; // desired velocity in local coords
268  vec3d local_v_out; // velocity in local coords following this frame
269  vec3d damp;
270 
271  // Maybe clear the reduced_damp flag.
272  // This fixes the problem of the player getting near-instantaneous acceleration under unknown circumstances.
273  // The larger problem is probably that PF_USE_VEL is getting stuck set.
275  pi->flags &= ~PF_REDUCED_DAMP;
276  }
277 
278  // Set up damping constants based on special conditions
279  // ie. shockwave, collision, weapon, dead
280  if (pi->flags & PF_DEAD_DAMP) {
281  // side_slip_time_const is already quite large and now needs to be applied in all directions
283 
284  } else if (pi->flags & PF_REDUCED_DAMP) {
285  // case of shock, weapon, collide, etc.
287  vm_vec_make( &damp, pi->side_slip_time_const, pi->side_slip_time_const, 0.0f );
288  } else {
289  // damp is multiplied by fraction and not fraction^2, gives better collision separation
290  float reduced_damp_fraction_time_left = timestamp_until( pi->reduced_damp_decay ) / (float) REDUCED_DAMP_TIME;
291  damp.xyz.x = pi->side_slip_time_const * ( 1 + (REDUCED_DAMP_FACTOR-1) * reduced_damp_fraction_time_left );
292  damp.xyz.y = pi->side_slip_time_const * ( 1 + (REDUCED_DAMP_FACTOR-1) * reduced_damp_fraction_time_left );
293  damp.xyz.z = pi->side_slip_time_const * reduced_damp_fraction_time_left * REDUCED_DAMP_FACTOR;
294  }
295  } else {
296  // regular damping
297  if (pi->use_newtonian_damp) {
299  } else {
300  vm_vec_make( &damp, pi->side_slip_time_const, pi->side_slip_time_const, 0.0f );
301  }
302  }
303 
304  // Note: CANNOT maintain a *local velocity* since a rotation can occur in this frame.
305  // thus the local velocity of in the next frame can be different (this would require rotate to change local vel
306  // and this is not desired
307 
308  // get local components of current velocity
309  vm_vec_rotate (&local_v_in, &pi->vel, orient);
310 
311  // get local components of desired velocity
312  vm_vec_rotate (&local_desired_vel, &pi->desired_vel, orient);
313 
314  // find updated LOCAL velocity and position in the local x direction
315  apply_physics (damp.xyz.x, local_desired_vel.xyz.x, local_v_in.xyz.x, sim_time, &local_v_out.xyz.x, &local_disp.xyz.x);
316 
317  // find updated LOCAL velocity and position in the local y direction
318  apply_physics (damp.xyz.y, local_desired_vel.xyz.y, local_v_in.xyz.y, sim_time, &local_v_out.xyz.y, &local_disp.xyz.y);
319 
320  // find updated LOCAL velocity and position in the local z direction
321  // for player ship, damp should normally be zero, but may be altered in a shockwave
322  // in death, shockwave,etc. we want damping time const large for all 3 axes
323  // warp in test - make excessive speed drop exponentially from max allowed
324  // become (0.01x in 3 sec)
325 
326  int special_warp_in = FALSE;
327  float excess = local_v_in.xyz.z - pi->max_vel.xyz.z;
328  if (excess > 5 && (pi->flags & PF_SPECIAL_WARP_IN)) {
329  special_warp_in = TRUE;
330  float exp_factor = float(exp(-sim_time / SPECIAL_WARP_T_CONST));
331  local_v_out.xyz.z = pi->max_vel.xyz.z + excess * exp_factor;
332  local_disp.xyz.z = (pi->max_vel.xyz.z * sim_time) + excess * (float(SPECIAL_WARP_T_CONST) * (1.0f - exp_factor));
333  } else if (pi->flags & PF_SPECIAL_WARP_OUT) {
334  float exp_factor = float(exp(-sim_time / SPECIAL_WARP_T_CONST));
335  vec3d temp;
336  vm_vec_rotate(&temp, &pi->prev_ramp_vel, orient);
337  float deficeit = temp.xyz.z - local_v_in.xyz.z;
338  local_v_out.xyz.z = local_v_in.xyz.z + deficeit * (1.0f - exp_factor);
339  local_disp.xyz.z = (local_v_in.xyz.z * sim_time) + deficeit * (sim_time - (float(SPECIAL_WARP_T_CONST) * (1.0f - exp_factor)));
340  } else {
341  apply_physics (damp.xyz.z, local_desired_vel.xyz.z, local_v_in.xyz.z, sim_time, &local_v_out.xyz.z, &local_disp.xyz.z);
342  }
343 
344  // maybe turn off special warp in flag
345  if ((pi->flags & PF_SPECIAL_WARP_IN) && (excess < 5)) {
346  pi->flags &= ~(PF_SPECIAL_WARP_IN);
347  }
348 
349  // update world position from local to world coords using orient
350  vec3d world_disp;
351  vm_vec_unrotate (&world_disp, &local_disp, orient);
352  vm_vec_add2 (position, &world_disp);
353 
354  // update world velocity
355  vm_vec_unrotate(&pi->vel, &local_v_out, orient);
356 
357  if (special_warp_in) {
358  vm_vec_rotate(&pi->prev_ramp_vel, &pi->vel, orient);
359  }
360 }
361 
362 // -----------------------------------------------------------------------------------------------------------
363 // Simulate a physics object for this frame
364 void physics_sim(vec3d* position, matrix* orient, physics_info* pi, float sim_time)
365 {
366  // check flag which tells us whether or not to do velocity translation
367  if (pi->flags & PF_CONST_VEL) {
368  vm_vec_scale_add2(position, &pi->vel, sim_time);
369  }
370  else
371  {
372  physics_sim_vel(position, pi, sim_time, orient);
373  physics_sim_rot(orient, pi, sim_time);
374 
375  pi->speed = vm_vec_mag(&pi->vel); // Note, cannot use quick version, causes cumulative error, increasing speed.
376  pi->fspeed = vm_vec_dot(&orient->vec.fvec, &pi->vel); // instead of vector magnitude -- use only forward vector since we are only interested in forward velocity
377  }
378 
379 }
380 
381 // -----------------------------------------------------------------------------------------------------------
382 // Simulate a physics object for this frame. Used by the editor. The difference between
383 // this function and physics_sim() is that this one uses a heading change to rotate around
384 // the universal Y axis, rather than the local orientation's Y axis. Banking is also ignored.
385 void physics_sim_editor(vec3d *position, matrix * orient, physics_info * pi, float sim_time )
386 {
387  physics_sim_vel(position, pi, sim_time, orient);
388  physics_sim_rot_editor(orient, pi, sim_time);
389  pi->speed = vm_vec_mag_quick(&pi->vel);
390  pi->fspeed = vm_vec_dot(&orient->vec.fvec, &pi->vel); // instead of vector magnitude -- use only forward vector since we are only interested in forward velocity
391 }
392 
393 // function to predict an object's position given the delta time and an objects physics info
394 void physics_predict_pos(physics_info *pi, float delta_time, vec3d *predicted_pos)
395 {
396  apply_physics( pi->side_slip_time_const, pi->desired_vel.xyz.x, pi->vel.xyz.x, delta_time,
397  NULL, &predicted_pos->xyz.x );
398 
399  apply_physics( pi->side_slip_time_const, pi->desired_vel.xyz.y, pi->vel.xyz.y, delta_time,
400  NULL, &predicted_pos->xyz.y );
401 
402  apply_physics( pi->side_slip_time_const, pi->desired_vel.xyz.z, pi->vel.xyz.z, delta_time,
403  NULL, &predicted_pos->xyz.z );
404 }
405 
406 // function to predict an object's velocity given the parameters
407 void physics_predict_vel(physics_info *pi, float delta_time, vec3d *predicted_vel)
408 {
409  if (pi->flags & PF_CONST_VEL) {
410  predicted_vel = &pi->vel;
411  } else {
412  apply_physics( pi->side_slip_time_const, pi->desired_vel.xyz.x, pi->vel.xyz.x, delta_time,
413  &predicted_vel->xyz.x, NULL );
414 
415  apply_physics( pi->side_slip_time_const, pi->desired_vel.xyz.y, pi->vel.xyz.y, delta_time,
416  &predicted_vel->xyz.y, NULL );
417 
418  apply_physics( pi->side_slip_time_const, pi->desired_vel.xyz.z, pi->vel.xyz.z, delta_time,
419  &predicted_vel->xyz.z, NULL );
420  }
421 }
422 
423 // function to predict position and velocity of an object
424 void physics_predict_pos_and_vel(physics_info *pi, float delta_time, vec3d *predicted_vel, vec3d *predicted_pos)
425 {
426 
427  apply_physics( pi->side_slip_time_const, pi->desired_vel.xyz.x, pi->vel.xyz.x, delta_time,
428  &predicted_vel->xyz.x, &predicted_pos->xyz.x );
429 
430  apply_physics( pi->side_slip_time_const, pi->desired_vel.xyz.y, pi->vel.xyz.y, delta_time,
431  &predicted_vel->xyz.y, &predicted_pos->xyz.y );
432 
433  apply_physics( pi->side_slip_time_const, pi->desired_vel.xyz.z, pi->vel.xyz.z, delta_time,
434  &predicted_vel->xyz.z, &predicted_pos->xyz.z );
435 }
436 
437 // physics_read_flying_controls()
438 //
439 // parmeters: *orient ==>
440 // *pi ==>
441 // *ci ==>
442 // Adam: Uncomment-out this define to enable banking while turning.
443 #define BANK_WHEN_TURN
444 
445 
446 
447 // function looks at the flying controls and the current velocity to determine a goal velocity
448 // function determines velocity in object's reference frame and goal velocity in object's reference frame
449 void physics_read_flying_controls( matrix * orient, physics_info * pi, control_info * ci, float sim_time, vec3d *wash_rot)
450 {
451  vec3d goal_vel; // goal velocity in local coords, *not* accounting for ramping of velcity
452  float ramp_time_const; // time constant for velocity ramping
453 
454  // apply throttle, unless reverse thrusters are held down
455  if (ci->forward != -1.0f)
456  ci->forward += (ci->forward_cruise_percent / 100.0f);
457 
458  // give control input to cause rotation in engine wash
459  extern int Wash_on;
460  if ( wash_rot && Wash_on ) {
461  ci->pitch += wash_rot->xyz.x;
462  ci->bank += wash_rot->xyz.z;
463  ci->heading += wash_rot->xyz.y;
464  }
465 
466  if (ci->pitch > 1.0f ) ci->pitch = 1.0f;
467  else if (ci->pitch < -1.0f ) ci->pitch = -1.0f;
468 
469  if (ci->vertical > 1.0f ) ci->vertical = 1.0f;
470  else if (ci->vertical < -1.0f ) ci->vertical = -1.0f;
471 
472  if (ci->heading > 1.0f ) ci->heading = 1.0f;
473  else if (ci->heading < -1.0f ) ci->heading = -1.0f;
474 
475  if (ci->sideways > 1.0f ) ci->sideways = 1.0f;
476  else if (ci->sideways < -1.0f ) ci->sideways = -1.0f;
477 
478  if (ci->bank > 1.0f ) ci->bank = 1.0f;
479  else if (ci->bank < -1.0f ) ci->bank = -1.0f;
480 
481  if ( pi->flags & PF_AFTERBURNER_ON ){
482  //SparK: modifield to accept reverse burners
483  if (!(pi->afterburner_max_reverse_vel > 0.0f)){
484  ci->forward = 1.0f;
485  }
486  }
487 
488  if (ci->forward > 1.0f ) ci->forward = 1.0f;
489  else if (ci->forward < -1.0f ) ci->forward = -1.0f;
490 
492  // Default behavior; eyepoint orientation has no effect on controls
493  pi->desired_rotvel.xyz.x = ci->pitch * pi->max_rotvel.xyz.x;
494  pi->desired_rotvel.xyz.y = ci->heading * pi->max_rotvel.xyz.y;
495  } else {
496  // Optional behavior; pitch and yaw are always relative to the eyepoint
497  // orientation (excluding slew)
498  vec3d tmp_vec, new_rotvel;
499  matrix tmp_mat, eyemat, rotvelmat;
500 
501  ship_get_eye(&tmp_vec, &eyemat, Player_obj, false);
502 
503  vm_copy_transpose(&tmp_mat, &Player_obj->orient);
504  vm_matrix_x_matrix(&rotvelmat, &tmp_mat, &eyemat);
505 
506  vm_vec_rotate(&new_rotvel, &pi->max_rotvel, &rotvelmat);
507  vm_vec_unrotate(&tmp_vec, &pi->max_rotvel, &rotvelmat);
508  new_rotvel.xyz.x = tmp_vec.xyz.x;
509 
510  new_rotvel.xyz.x = ci->pitch * new_rotvel.xyz.x;
511  new_rotvel.xyz.y = ci->heading * new_rotvel.xyz.y;
512 
513  vm_vec_unrotate(&tmp_vec, &new_rotvel, &rotvelmat);
514 
515  pi->desired_rotvel = tmp_vec;
516  }
517 
518  float delta_bank;
519 
520 #ifdef BANK_WHEN_TURN
521  // To change direction of bank, negate the whole expression.
522  // To increase magnitude of banking, decrease denominator.
523  // Adam: The following statement is all the math for banking while turning.
524  delta_bank = - (ci->heading * pi->max_rotvel.xyz.y) * pi->delta_bank_const;
525 #else
526  delta_bank = 0.0f;
527 #endif
528 
529  pi->desired_rotvel.xyz.z = ci->bank * pi->max_rotvel.xyz.z + delta_bank;
530  pi->forward_thrust = ci->forward;
531  pi->vert_thrust = ci->vertical; //added these two in order to get side and forward thrusters
532  pi->side_thrust = ci->sideways; //to glow brighter when the ship is moving in the right direction -Bobboau
533 
534  if ( pi->flags & PF_AFTERBURNER_ON ) {
535  goal_vel.xyz.x = ci->sideways*pi->afterburner_max_vel.xyz.x;
536  goal_vel.xyz.y = ci->vertical*pi->afterburner_max_vel.xyz.y;
537  if(ci->forward < 0.0f)
538  goal_vel.xyz.z = ci->forward* pi->afterburner_max_reverse_vel;
539  else
540  goal_vel.xyz.z = ci->forward* pi->afterburner_max_vel.xyz.z;
541  }
542  else if ( pi->flags & PF_BOOSTER_ON ) {
543  goal_vel.xyz.x = ci->sideways*pi->booster_max_vel.xyz.x;
544  goal_vel.xyz.y = ci->vertical*pi->booster_max_vel.xyz.y;
545  goal_vel.xyz.z = ci->forward* pi->booster_max_vel.xyz.z;
546  }
547  else {
548  goal_vel.xyz.x = ci->sideways*pi->max_vel.xyz.x;
549  goal_vel.xyz.y = ci->vertical*pi->max_vel.xyz.y;
550  goal_vel.xyz.z = ci->forward* pi->max_vel.xyz.z;
551  }
552 
553  if ( goal_vel.xyz.z < -pi->max_rear_vel && !(pi->flags & PF_AFTERBURNER_ON) )
554  goal_vel.xyz.z = -pi->max_rear_vel;
555 
556 
557  if ( pi->flags & PF_ACCELERATES ) {
558  //
559  // Determine *resultant* DESIRED VELOCITY (desired_vel) accounting for RAMPING of velocity
560  // Use LOCAL coordinates
561  // if slide_enabled, ramp velocity for x and y, otherwise set goal (0)
562  // always ramp velocity for z
563  //
564 
565  // If reduced damp in effect, then adjust ramp_velocity and desired_velocity can not change as fast.
566  // Scale according to reduced_damp_time_expansion.
567  float reduced_damp_ramp_time_expansion;
569  float reduced_damp_fraction_time_left = timestamp_until( pi->reduced_damp_decay ) / (float) REDUCED_DAMP_TIME;
570  reduced_damp_ramp_time_expansion = 1.0f + (REDUCED_DAMP_FACTOR-1) * reduced_damp_fraction_time_left;
571  } else {
572  reduced_damp_ramp_time_expansion = 1.0f;
573  }
574 
575  if (pi->flags & PF_SLIDE_ENABLED) {
576  // determine the local velocity
577  // deterimine whether accelerating or decleration toward goal for x
578  if ( goal_vel.xyz.x > 0.0f ) {
579  if ( goal_vel.xyz.x >= pi->prev_ramp_vel.xyz.x )
580  ramp_time_const = pi->slide_accel_time_const;
581  else
582  ramp_time_const = pi->slide_decel_time_const;
583  } else if ( goal_vel.xyz.x < 0.0f ) {
584  if ( goal_vel.xyz.x <= pi->prev_ramp_vel.xyz.x )
585  ramp_time_const = pi->slide_accel_time_const;
586  else
587  ramp_time_const = pi->slide_decel_time_const;
588  } else {
589  ramp_time_const = pi->slide_decel_time_const;
590  }
591  // If reduced damp in effect, then adjust ramp_velocity and desired_velocity can not change as fast
592  if ( pi->flags & PF_REDUCED_DAMP ) {
593  ramp_time_const *= reduced_damp_ramp_time_expansion;
594  }
595  pi->prev_ramp_vel.xyz.x = velocity_ramp(pi->prev_ramp_vel.xyz.x, goal_vel.xyz.x, ramp_time_const, sim_time);
596 
597  // deterimine whether accelerating or decleration toward goal for y
598  if ( goal_vel.xyz.y > 0.0f ) {
599  if ( goal_vel.xyz.y >= pi->prev_ramp_vel.xyz.y )
600  ramp_time_const = pi->slide_accel_time_const;
601  else
602  ramp_time_const = pi->slide_decel_time_const;
603  } else if ( goal_vel.xyz.y < 0.0f ) {
604  if ( goal_vel.xyz.y <= pi->prev_ramp_vel.xyz.y )
605  ramp_time_const = pi->slide_accel_time_const;
606  else
607  ramp_time_const = pi->slide_decel_time_const;
608  } else {
609  ramp_time_const = pi->slide_decel_time_const;
610  }
611  // If reduced damp in effect, then adjust ramp_velocity and desired_velocity can not change as fast
612  if ( pi->flags & PF_REDUCED_DAMP ) {
613  ramp_time_const *= reduced_damp_ramp_time_expansion;
614  }
615  pi->prev_ramp_vel.xyz.y = velocity_ramp( pi->prev_ramp_vel.xyz.y, goal_vel.xyz.y, ramp_time_const, sim_time);
616  } else {
617  // slide not enabled
618  pi->prev_ramp_vel.xyz.x = 0.0f;
619  pi->prev_ramp_vel.xyz.y = 0.0f;
620  }
621 
622  // deterimine whether accelerating or decleration toward goal for z
623  if ( goal_vel.xyz.z > 0.0f ) {
624  if ( goal_vel.xyz.z >= pi->prev_ramp_vel.xyz.z ) {
625  if ( pi->flags & PF_AFTERBURNER_ON )
626  ramp_time_const = pi->afterburner_forward_accel_time_const;
627  else if (pi->flags & PF_BOOSTER_ON)
628  ramp_time_const = pi->booster_forward_accel_time_const;
629  else
630  ramp_time_const = pi->forward_accel_time_const;
631  } else {
632  ramp_time_const = pi->forward_decel_time_const;
633  }
634  } else if ( goal_vel.xyz.z < 0.0f ) {
635  if ( pi->flags & PF_AFTERBURNER_ON )
636  ramp_time_const = pi->afterburner_reverse_accel;
637  else
638  ramp_time_const = pi->forward_decel_time_const;
639  } else {
640  ramp_time_const = pi->forward_decel_time_const;
641  }
642 
643  // If reduced damp in effect, then adjust ramp_velocity and desired_velocity can not change as fast
644  if ( pi->flags & PF_REDUCED_DAMP ) {
645  ramp_time_const *= reduced_damp_ramp_time_expansion;
646  }
647  pi->prev_ramp_vel.xyz.z = velocity_ramp(pi->prev_ramp_vel.xyz.z, goal_vel.xyz.z, ramp_time_const, sim_time);
648 
649  //Deternine the current dynamic glide cap, and ramp to it
650  //This is outside the normal "glide" block since we want the cap to adjust whether or not the ship is in glide mode
651  float dynamic_glide_cap_goal = 0.0;
652  if (pi->flags & PF_AFTERBURNER_ON) {
653  dynamic_glide_cap_goal = ( goal_vel.xyz.z >= 0.0f ) ? pi->afterburner_max_vel.xyz.z : pi->afterburner_max_reverse_vel;
654  }
655  else {
656  //Use the maximum value in X, Y, and Z (including overclocking)
657  dynamic_glide_cap_goal = MAX(MAX(pi->max_vel.xyz.x,pi->max_vel.xyz.y), pi->max_vel.xyz.z);
658  }
659  pi->cur_glide_cap = velocity_ramp(pi->cur_glide_cap, dynamic_glide_cap_goal, ramp_time_const, sim_time);
660 
661 
662  if ( (pi->flags & PF_GLIDING) || (pi->flags & PF_FORCE_GLIDE ) ) {
663  pi->desired_vel = pi->vel;
664 
665  //SUSHI: A (hopefully better) approach to dealing with accelerations in glide mode
666  //Get *actual* current velocities along each axis and use those instead of ramped velocities
667  vec3d local_vel;
668  vm_vec_rotate(&local_vel, &pi->vel, orient);
669 
670  //Having pi->glide_cap == 0 means we're using a dynamic glide cap
671  float curGlideCap = 0.0f;
672  if (pi->glide_cap == 0.0f)
673  curGlideCap = pi->cur_glide_cap;
674  else
675  curGlideCap = pi->glide_cap;
676 
677  //If we're near the (positive) glide cap, decay velocity where we aren't thrusting
678  //This is a hack, but makes the flight feel a lot smoother
679  //Don't do this if we aren't applying any thrust, we have no glide cap, or the accel multiplier is 0 (no thrust while gliding)
680  float cap_decay_threshold = 0.95f;
681  float cap_decay_amount = 0.2f;
682  if (curGlideCap >= 0.0f && vm_vec_mag(&pi->desired_vel) >= cap_decay_threshold * curGlideCap &&
683  vm_vec_mag(&goal_vel) > 0.0f &&
684  pi->glide_accel_mult != 0.0f)
685  {
686  if (goal_vel.xyz.x == 0.0f)
687  vm_vec_scale_add2(&pi->desired_vel, &orient->vec.rvec, -cap_decay_amount * local_vel.xyz.x);
688  if (goal_vel.xyz.y == 0.0f)
689  vm_vec_scale_add2(&pi->desired_vel, &orient->vec.uvec, -cap_decay_amount * local_vel.xyz.y);
690  if (goal_vel.xyz.z == 0.0f)
691  vm_vec_scale_add2(&pi->desired_vel, &orient->vec.fvec, -cap_decay_amount * local_vel.xyz.z);
692  }
693 
694  //The glide_ramp function uses (basically) the same math as the velocity ramp so that thruster power is consistent
695  //Only ramp if the glide cap is positive
696  float xVal = glide_ramp(local_vel.xyz.x, goal_vel.xyz.x, pi->slide_accel_time_const, pi->glide_accel_mult, sim_time);
697  float yVal = glide_ramp(local_vel.xyz.y, goal_vel.xyz.y, pi->slide_accel_time_const, pi->glide_accel_mult, sim_time);
698  float zVal = 0.0;
699  if (pi->flags & PF_AFTERBURNER_ON)
700  zVal = glide_ramp(local_vel.xyz.z, goal_vel.xyz.z, pi->afterburner_forward_accel_time_const, pi->glide_accel_mult, sim_time);
701  else {
702  if (goal_vel.xyz.z >= 0.0f)
703  zVal = glide_ramp(local_vel.xyz.z, goal_vel.xyz.z, pi->forward_accel_time_const, pi->glide_accel_mult, sim_time);
704  else
705  zVal = glide_ramp(local_vel.xyz.z, goal_vel.xyz.z, pi->forward_decel_time_const, pi->glide_accel_mult, sim_time);
706  }
707 
708  //Compensate for effect of dampening: normal flight cheats here, so /we make up for it this way so glide acts the same way
709  xVal *= pi->side_slip_time_const / sim_time;
710  yVal *= pi->side_slip_time_const / sim_time;
711  if (pi->use_newtonian_damp) zVal *= pi->side_slip_time_const / sim_time;
712 
713  vm_vec_scale_add2(&pi->desired_vel, &orient->vec.fvec, zVal);
714  vm_vec_scale_add2(&pi->desired_vel, &orient->vec.rvec, xVal);
715  vm_vec_scale_add2(&pi->desired_vel, &orient->vec.uvec, yVal);
716 
717  // Only do the glide cap if we have one and are actively thrusting in some direction.
718  // Unless AIPF2_GLIDE_DECAY_REQUIRES_THRUST isn't set. -MageKing17
719  if ( curGlideCap >= 0.0f && (!(The_mission.ai_profile->flags2 & AIPF2_GLIDE_DECAY_REQUIRES_THRUST) || ci->forward != 0.0f || ci->sideways != 0.0f || ci->vertical != 0.0f) ) {
720  float currentmag = vm_vec_mag(&pi->desired_vel);
721  if ( currentmag > curGlideCap ) {
722  vm_vec_scale( &pi->desired_vel, curGlideCap / currentmag );
723  }
724  }
725  }
726  else
727  {
728  // this translates local desired velocities to world velocities
729  vm_vec_zero(&pi->desired_vel);
730  vm_vec_scale_add2( &pi->desired_vel, &orient->vec.rvec, pi->prev_ramp_vel.xyz.x );
731  vm_vec_scale_add2( &pi->desired_vel, &orient->vec.uvec, pi->prev_ramp_vel.xyz.y );
732  vm_vec_scale_add2( &pi->desired_vel, &orient->vec.fvec, pi->prev_ramp_vel.xyz.z );
733  }
734  } else // object does not accelerate (PF_ACCELERATES not set)
735  pi->desired_vel = pi->vel;
736 }
737 
738 
739 
740 // ----------------------------------------------------------------
741 // Do *dest = *delta unless:
742 // *delta is pretty small
743 // and they are of different signs.
744 void physics_set_rotvel_and_saturate(float *dest, float delta)
745 {
746  /*
747  if ((delta ^ *dest) < 0) {
748  if (abs(delta) < F1_0/8) {
749  // mprintf((0, "D"));
750  *dest = delta/4;
751  } else
752  // mprintf((0, "d"));
753  *dest = delta;
754  } else {
755  // mprintf((0, "!"));
756  *dest = delta;
757  }
758  */
759  *dest = delta;
760 }
761 
762 
763 // ----------------------------------------------------------------------------
764 // physics_apply_whack applies an instaneous whack on an object changing
765 // both the objects velocity and the rotational velocity based on the impulse
766 // being applied.
767 //
768 // input: impulse => impulse vector ( force*time = impulse = change in momentum (mv) )
769 // pos => vector from center of mass to location of where the force acts
770 // pi => pointer to phys_info struct of object getting whacked
771 // orient => orientation matrix (needed to set rotational impulse in body coords)
772 // mass => mass of the object (may be different from pi.mass if docked)
773 //
774 #define WHACK_LIMIT 0.001f
775 #define ROTVEL_WHACK_CONST 0.12
776 void physics_apply_whack(vec3d *impulse, vec3d *pos, physics_info *pi, matrix *orient, float mass)
777 {
778  vec3d local_torque, torque;
779 // vec3d npos;
780 
781  // Detect null vector.
782  if ((fl_abs(impulse->xyz.x) <= WHACK_LIMIT) && (fl_abs(impulse->xyz.y) <= WHACK_LIMIT) && (fl_abs(impulse->xyz.z) <= WHACK_LIMIT))
783  return;
784 
785  // first do the rotational velocity
786  // calculate the torque on the body based on the point on the
787  // object that was hit and the momentum being applied to the object
788 
789  vm_vec_cross(&torque, pos, impulse);
790  vm_vec_rotate ( &local_torque, &torque, orient );
791 
792  vec3d delta_rotvel;
793  vm_vec_rotate( &delta_rotvel, &local_torque, &pi->I_body_inv );
794  vm_vec_scale ( &delta_rotvel, (float) ROTVEL_WHACK_CONST );
795  vm_vec_add2( &pi->rotvel, &delta_rotvel );
796 
797  //mprintf(("Whack: %7.3f %7.3f %7.3f\n", pi->rotvel.xyz.x, pi->rotvel.xyz.y, pi->rotvel.xyz.z));
798 
799  // instant whack on the velocity
800  // reduce damping on all axes
801  pi->flags |= PF_REDUCED_DAMP;
803 
804  // find time for shake from weapon to end
805  int dtime = timestamp_until(pi->afterburner_decay);
806  if (dtime < WEAPON_SHAKE_TIME) {
808  }
809 
810  // Goober5000 - pi->mass should probably be just mass, as specified in the header
811  vm_vec_scale_add2( &pi->vel, impulse, 1.0f / mass );
813  // Get DaveA
814  nprintf(("Physics", "speed reset in physics_apply_whack [speed: %f]\n", vm_vec_mag(&pi->vel)));
815  vm_vec_normalize(&pi->vel);
816  vm_vec_scale(&pi->vel, (float)RESET_SHIP_SPEED);
817  }
818  vm_vec_rotate( &pi->prev_ramp_vel, &pi->vel, orient ); // set so velocity will ramp starting from current speed
819  // ramped velocity is now affected by collision
820 }
821 
822 // function generates a velocity ramp with a given time constant independent of frame rate
823 // uses an exponential approach to desired velocity and a cheat when close to improve closure speed
824 float velocity_ramp (float v_in, float v_goal, float ramp_time_const, float t)
825 {
826  float delta_v;
827  float decay_factor;
828  float dist;
829 
830  // JAS: If no time elapsed, change nothing
831  if ( t==0.0f )
832  return v_in;
833 
834  delta_v = v_goal - v_in;
835  dist = (float)fl_abs(delta_v);
836 
837  // hack to speed up closure when close to goal
838  if (dist < ramp_time_const/3)
839  ramp_time_const = dist / 3;
840 
841  // Rather than get a divide by zero, just go to the goal
842  if ( ramp_time_const < 0.0001f ) {
843  return v_goal;
844  }
845 
846  // determine decay factor (ranges from 0 for short times to 1 for long times)
847  // when decay factor is near 0, the velocity in nearly unchanged
848  // when decay factor in near 1, the velocity approaches goal
849  decay_factor = (float)exp(- t / ramp_time_const);
850 
851  return (v_in + delta_v * (1.0f - decay_factor) );
852 }
853 
854 //Handles thrust values when gliding. Purposefully similar to velocity_ramp in order to yeild a similar "feel" in
855 //terms of thruster accels (as much as possible)
856 //This is all in the local frame of reference for a single movement axis
857 float glide_ramp (float v_in, float v_goal, float ramp_time_const, float accel_mult, float t)
858 {
859  if (v_goal == 0.0f) {
860  return 0.0f;
861  }
862 
863  //This approach to delta_v allows us to ramp accelerations even in glide mode
864  //Get the difference in velocity between current and goal as thrust
865  //(capped by the goal velocity on one end and 0 on the other)
866  //If accel_mult is < 0, don't ramp (fixed acceleration)
867  float delta_v = 0.0f;
868  if (accel_mult < 0.0f) {
869  if (v_goal > 0.0f) {
870  delta_v = MAX(MIN(v_goal - v_in, v_goal), 0.0f);
871  }
872  else {
873  delta_v = MIN(MAX(v_goal - v_in, v_goal), 0.0f);
874  }
875  }
876  else {
877  delta_v = v_goal * accel_mult;
878  }
879 
880  //Calculate the (decayed) thrust
881  float decay_factor = (ramp_time_const > 0.0f) ? (1.0f - (float)exp(-t / ramp_time_const)) : 1.0f;
882  return delta_v * decay_factor;
883 }
884 
885 
886 // ----------------------------------------------------------------------------
887 // physics_apply_shock applies applies a shockwave to an object. This causes a velocity impulse and
888 // and a rotational impulse. This is different than physics_apply_whack since a shock wave is a pressure
889 // wave which acts over the *surface* of the object, not a point.
890 //
891 // inputs: direction_vec => a position vector whose direction is from the center of the shock wave to the object
892 // pressure => the pressure of the shock wave at the object
893 // pi => physics_info structure
894 // orient => matrix orientation of the object
895 // min => vector of minimum values of the bounding box
896 // max => vector of maximum values of the bounding box
897 // radius => bounding box radius of the object, used for scaling rotation
898 //
899 // outputs: makes changes to physics_info structure rotvel and vel variables
900 //
901 #define STD_PRESSURE 1000 // amplitude of standard shockwave blasts
902 #define MIN_RADIUS 10 // radius within which full rotvel and shake applied
903 #define MAX_RADIUS 50 // radius at which no rotvel or shake applied
904 #define MAX_ROTVEL 0.4 // max rotational velocity
905 #define MAX_SHAKE 0.1 // max rotational amplitude of shake
906 #define MAX_VEL 8 // max vel from shockwave
907 void physics_apply_shock(vec3d *direction_vec, float pressure, physics_info *pi, matrix *orient, vec3d *min, vec3d *max, float radius)
908 {
909  vec3d normal;
910  vec3d local_torque, temp_torque, torque;
911  vec3d impact_vec;
912  vec3d area;
913  vec3d sin;
914 
915  if (radius > MAX_RADIUS) {
916  return;
917  }
918 
919  vm_vec_normalize_safe ( direction_vec );
920 
921  area.xyz.x = (max->xyz.y - min->xyz.z) * (max->xyz.z - min->xyz.z);
922  area.xyz.y = (max->xyz.x - min->xyz.x) * (max->xyz.z - min->xyz.z);
923  area.xyz.z = (max->xyz.x - min->xyz.x) * (max->xyz.y - min->xyz.y);
924 
925  normal.xyz.x = vm_vec_dot( direction_vec, &orient->vec.rvec );
926  normal.xyz.y = vm_vec_dot( direction_vec, &orient->vec.uvec );
927  normal.xyz.z = vm_vec_dot( direction_vec, &orient->vec.fvec );
928 
929  sin.xyz.x = fl_sqrt( fl_abs(1.0f - normal.xyz.x*normal.xyz.x) );
930  sin.xyz.y = fl_sqrt( fl_abs(1.0f - normal.xyz.y*normal.xyz.y) );
931  sin.xyz.z = fl_sqrt( fl_abs(1.0f - normal.xyz.z*normal.xyz.z) );
932 
933  vm_vec_make( &torque, 0.0f, 0.0f, 0.0f );
934 
935  // find the torque exerted due to the shockwave hitting each face
936  // model the effect of the shockwave as if the shockwave were a plane of projectiles,
937  // all moving in the direction direction_vec. then find the torque as the cross prod
938  // of the force (pressure * area * normal * sin * scale * mass)
939  // normal takes account the fraction of the surface exposed to the shockwave
940  // the sin term is not technically needed but "feels" better
941  // scale factors out the increase in area with larger objects
942  // more massive objects get less rotation
943 
944  // find torque due to forces on the right/left face
945  if ( normal.xyz.x < 0.0f ) // normal < 0, hits the right face
946  vm_vec_copy_scale( &impact_vec, &orient->vec.rvec, max->xyz.x * pressure * area.xyz.x * normal.xyz.x * sin.xyz.x / pi->mass );
947  else // normal > 0, hits the left face
948  vm_vec_copy_scale( &impact_vec, &orient->vec.rvec, min->xyz.x * pressure * area.xyz.x * -normal.xyz.x * sin.xyz.x / pi->mass );
949 
950  vm_vec_cross( &temp_torque, &impact_vec, direction_vec );
951  vm_vec_add2( &torque, &temp_torque );
952 
953  // find torque due to forces on the up/down face
954  if ( normal.xyz.y < 0.0f )
955  vm_vec_copy_scale( &impact_vec, &orient->vec.uvec, max->xyz.y * pressure * area.xyz.y * normal.xyz.y * sin.xyz.y / pi->mass );
956  else
957  vm_vec_copy_scale( &impact_vec, &orient->vec.uvec, min->xyz.y * pressure * area.xyz.y * -normal.xyz.y * sin.xyz.y / pi->mass );
958 
959  vm_vec_cross( &temp_torque, &impact_vec, direction_vec );
960  vm_vec_add2( &torque, &temp_torque );
961 
962  // find torque due to forces on the forward/backward face
963  if ( normal.xyz.z < 0.0f )
964  vm_vec_copy_scale( &impact_vec, &orient->vec.fvec, max->xyz.z * pressure * area.xyz.z * normal.xyz.z * sin.xyz.z / pi->mass );
965  else
966  vm_vec_copy_scale( &impact_vec, &orient->vec.fvec, min->xyz.z * pressure * area.xyz.z * -normal.xyz.z * sin.xyz.z / pi->mass );
967 
968  vm_vec_cross( &temp_torque, &impact_vec, direction_vec );
969  vm_vec_add2( &torque, &temp_torque );
970 
971  // compute delta rotvel, scale according to blast and radius
972  float scale;
973 
974  if (radius < MIN_RADIUS) {
975  scale = 1.0f;
976  } else {
977  scale = (MAX_RADIUS - radius)/(MAX_RADIUS-MIN_RADIUS);
978  }
979 
980  // set shockwave shake amplitude, duration, flag
983  pi->flags |= PF_IN_SHOCKWAVE;
984 
985  // safety dance
986  if (!(IS_VEC_NULL_SQ_SAFE(&torque))) {
987  vec3d delta_rotvel;
988  vm_vec_rotate( &local_torque, &torque, orient );
989  vm_vec_copy_normalize(&delta_rotvel, &local_torque);
990 
991  vm_vec_scale(&delta_rotvel, (float)(MAX_ROTVEL*(pressure/STD_PRESSURE)*scale));
992  // nprintf(("Physics", "rotvel scale %f\n", (MAX_ROTVEL*(pressure/STD_PRESSURE)*scale)));
993  vm_vec_add2(&pi->rotvel, &delta_rotvel);
994  }
995 
996  // set reduced translational damping, set flags
997  float velocity_scale = (float)MAX_VEL*scale;
998  pi->flags |= PF_REDUCED_DAMP;
999  update_reduced_damp_timestamp( pi, velocity_scale*pi->mass );
1000  vm_vec_scale_add2( &pi->vel, direction_vec, velocity_scale );
1001  vm_vec_rotate(&pi->prev_ramp_vel, &pi->vel, orient); // set so velocity will ramp starting from current speed
1002 
1003  // check that kick from shockwave is not too large
1005  // Get DaveA
1006  nprintf(("Physics", "speed reset in physics_apply_shock [speed: %f]\n", vm_vec_mag(&pi->vel)));
1007  vm_vec_normalize(&pi->vel);
1008  vm_vec_scale(&pi->vel, (float)RESET_SHIP_SPEED);
1009  }
1010 }
1011 
1012 // ----------------------------------------------------------------------------
1013 // physics_collide_whack applies an instaneous whack on an object changing
1014 // both the objects velocity and the rotational velocity based on the impulse
1015 // being applied.
1016 //
1017 // input: impulse => impulse vector ( force*time = impulse = change in momentum (mv) )
1018 // world_delta_rotvel => change in rotational velocity (already calculated)
1019 // pi => pointer to phys_info struct of object getting whacked
1020 // orient => orientation matrix (needed to set rotational impulse in body coords)
1021 //
1022 
1023 // Warning: Do not change ROTVEL_COLLIDE_WHACK_CONST. This will mess up collision physics.
1024 // If you need to change the rotation, change COLLISION_ROTATION_FACTOR in collide_ship_ship.
1025 #define ROTVEL_COLLIDE_WHACK_CONST 1.0
1026 void physics_collide_whack( vec3d *impulse, vec3d *world_delta_rotvel, physics_info *pi, matrix *orient, bool is_landing )
1027 {
1028  vec3d body_delta_rotvel;
1029 
1030  // Detect null vector.
1031  if ((fl_abs(impulse->xyz.x) <= WHACK_LIMIT) && (fl_abs(impulse->xyz.y) <= WHACK_LIMIT) && (fl_abs(impulse->xyz.z) <= WHACK_LIMIT))
1032  return;
1033 
1034  vm_vec_rotate( &body_delta_rotvel, world_delta_rotvel, orient );
1035 // vm_vec_scale( &body_delta_rotvel, (float) ROTVEL_COLLIDE_WHACK_CONST );
1036  vm_vec_add2( &pi->rotvel, &body_delta_rotvel );
1037 
1038  update_reduced_damp_timestamp( pi, vm_vec_mag(impulse) );
1039 
1040  // find time for shake from weapon to end
1041  if (!is_landing) {
1042  int dtime = timestamp_until(pi->afterburner_decay);
1043  if (dtime < WEAPON_SHAKE_TIME) {
1045  }
1046  }
1047 
1048  pi->flags |= PF_REDUCED_DAMP;
1049  vm_vec_scale_add2( &pi->vel, impulse, 1.0f / pi->mass );
1050  // check that collision does not give ship too much speed
1051  // reset if too high
1053  // Get DaveA
1054  nprintf(("Physics", "speed reset in physics_collide_whack [speed: %f]\n", vm_vec_mag(&pi->vel)));
1055  vm_vec_normalize(&pi->vel);
1056  vm_vec_scale(&pi->vel, (float)RESET_SHIP_SPEED);
1057  }
1058  vm_vec_rotate( &pi->prev_ramp_vel, &pi->vel, orient ); // set so velocity will ramp starting from current speed
1059  // ramped velocity is now affected by collision
1060  // rotate previous ramp velocity (in model coord) to be same as vel (in world coords)
1061 }
1062 
1063 
1065 {
1066  if ( 0 == pi->flags ) // weapon
1067  return 0;
1068 
1069  if ( Fred_running )
1070  return 0;
1071 
1072  int change_made = 0;
1073  if ( !(pi->flags & PF_DEAD_DAMP) ) {
1074  // case of normal, live ship
1075  // -- Commented out by MK: Assert( vm_vec_mag_squared(&pi->max_rotvel) > ROTVEL_TOL );
1076  // Assert( (pi->max_rotvel.xyz.x <= ROTVEL_CAP) && (pi->max_rotvel.xyz.y <= ROTVEL_CAP) && (pi->max_rotvel.xyz.z <= ROTVEL_CAP) );
1077  // Warning(LOCATION,"Excessive rotvel (wx: %f, wy: %f, wz:%f)\n", pi->rotvel.xyz.x, pi->rotvel.xyz.y, pi->rotvel.xyz.z);
1078  if ( fl_abs(pi->rotvel.xyz.x) > pi->max_rotvel.xyz.x ) {
1079  pi->rotvel.xyz.x = (pi->rotvel.xyz.x / fl_abs(pi->rotvel.xyz.x)) * (pi->max_rotvel.xyz.x - (float) ROTVEL_TOL);
1080  change_made = 1;
1081  }
1082  if ( fl_abs(pi->rotvel.xyz.y) > pi->max_rotvel.xyz.y ) {
1083  pi->rotvel.xyz.y = (pi->rotvel.xyz.y / fl_abs(pi->rotvel.xyz.y)) * (pi->max_rotvel.xyz.y - (float) ROTVEL_TOL);
1084  change_made = 1;
1085  }
1086  if ( fl_abs(pi->rotvel.xyz.z) > pi->max_rotvel.xyz.z ) {
1087  pi->rotvel.xyz.z = (pi->rotvel.xyz.z / fl_abs(pi->rotvel.xyz.z)) * (pi->max_rotvel.xyz.z - (float) ROTVEL_TOL);
1088  change_made = 1;
1089  }
1090  } else {
1091  // case of dead ship
1092  if ( fl_abs(pi->rotvel.xyz.x) > DEAD_ROTVEL_CAP ) {
1093  pi->rotvel.xyz.x = (pi->rotvel.xyz.x / fl_abs(pi->rotvel.xyz.x)) * (float) (DEAD_ROTVEL_CAP - ROTVEL_TOL);
1094  change_made = 1;
1095  }
1096  if ( fl_abs(pi->rotvel.xyz.y) > DEAD_ROTVEL_CAP ) {
1097  pi->rotvel.xyz.y = (pi->rotvel.xyz.y / fl_abs(pi->rotvel.xyz.y)) * (float) (DEAD_ROTVEL_CAP - ROTVEL_TOL);
1098  change_made = 1;
1099  }
1100  if ( fl_abs(pi->rotvel.xyz.z) > DEAD_ROTVEL_CAP ) {
1101  pi->rotvel.xyz.z = (pi->rotvel.xyz.z / fl_abs(pi->rotvel.xyz.z)) * (float) (DEAD_ROTVEL_CAP - ROTVEL_TOL);
1102  change_made = 1;
1103  }
1104  }
1105  return change_made;
1106 }
1107 
1108 // ----------------------------------------------------------------------------
1109 // update_reduced_damp_timestamp()
1110 //
1112 {
1113 
1114  // Compute duration of reduced damp from present
1115  // Compare with current value and increase if greater, otherwise ignore
1116  int reduced_damp_decay_time;
1117  reduced_damp_decay_time = (int) (REDUCED_DAMP_TIME * impulse / (REDUCED_DAMP_VEL * pi->mass));
1118  if ( reduced_damp_decay_time > REDUCED_DAMP_TIME )
1119  reduced_damp_decay_time = REDUCED_DAMP_TIME;
1120 
1121  // Reset timestamp if larger than current (if any)
1122  if ( timestamp_valid( pi->reduced_damp_decay ) ) {
1123  int time_left = timestamp_until( pi->reduced_damp_decay );
1124  if ( time_left > 0 ) {
1125  // increment old time, but apply cap
1126  int new_time = reduced_damp_decay_time + time_left;
1127  if ( new_time < REDUCED_DAMP_TIME ) {
1128  pi->reduced_damp_decay = timestamp( new_time );
1129  }
1130  } else {
1131  pi->reduced_damp_decay = timestamp( reduced_damp_decay_time );
1132  }
1133  } else {
1134  // set if not valid
1135  pi->reduced_damp_decay = timestamp( reduced_damp_decay_time );
1136  }
1137 
1138 }
1139 
1140 //*************************CLASS: avd_movement*************************
1141 avd_movement::avd_movement() : Pc(0.0f), Vc(0.0f), TSi(0), Pi(0.0f), Vi(0.0f), Pf(0.0f), Tf(0.0f), Tai(0.0f), Taf(0.0f), Vf(0.0f), Vm(0.0f), Ai(0.0f), Af(0.0f)
1142 {
1143 }
1144 
1146 {
1147  // We should really refactor so that a ::clear() method isn't needed.
1148  // For now, be sure this syncs with the class declaration
1149 
1150  //Current
1151  Pc = 0; //Current position
1152  Vc = 0; //Current velocity
1153 
1154  //Initial
1155  TSi = 0; //Initial timestamp <-- note TIMESTAMP
1156  Pi = 0; //Initial position
1157  Vi = 0; //Initial velocity
1158 
1159  //Given
1160  Pf = 0; //Final position
1161  Tf = 0; //Final duration
1162  Tai = 0; //Starting acceleration duration
1163  Taf = 0; //Ending acceleration duration
1164  Vf = 0; //Final velocity
1165 
1166  //Calculated
1167  Vm = 0; //Middle velocity
1168  Ai = 0; //Starting acceleration
1169  Af = 0; //Ending acceleration
1170 }
1171 
1172 void avd_movement::get(float Time, float *Position, float *Velocity)
1173 {
1174  this->update(Time);
1175 
1176  if(Position != NULL)
1177  *Position = Pc;
1178  if(Velocity != NULL)
1179  *Velocity = Vc;
1180 }
1181 
1182 void avd_movement::get(float *Position, float *Velocity)
1183 {
1184  float time = (float)(timestamp() - TSi)/1000.0f;
1185  this->get(time, Position, Velocity);
1186 }
1187 
1188 void avd_movement::set(float position)
1189 {
1190  this->clear();
1191  Pi = Pf = Pc = position;
1192 }
1193 
1194 void avd_movement::setAVD(float final_position, float total_movement_time, float starting_accleration_time, float ending_acceleration_time, float final_velocity)
1195 {
1196  //Make sure Pc et al are up-to-date
1197  this->update();
1198 
1199  Pf = final_position;
1200  Tf = total_movement_time;
1201  Tai = starting_accleration_time;
1202  Taf = ending_acceleration_time;
1203  Vf = final_velocity;
1204 
1205  if(Tai+Taf >= Tf)
1206  {
1207  Tai = Tf;
1208  Taf = 0.0f;
1209  }
1210 
1211  if(Tf <= 0.0f)
1212  {
1213  Pc = Pi = Pf;
1214  Vc = Vi = Vf;
1215  return;
1216  }
1217 
1218  Pi = Pc;
1219  Vi = Vc;
1220  TSi = timestamp();
1221 
1222  Vm = (Pf-Pi-0.5f*(Vi*Tai)-0.5f*(Vf*Taf)) / (Tf - 0.5f*Tai - 0.5f*Taf);
1223  Ai = (Vm-Vi)/Tai;
1224  Af = (Vf-Vm)/Taf;
1225 }
1226 
1227 void avd_movement::setVD(float total_movement_time, float ending_acceleration_time, float final_velocity)
1228 {
1229  //Make sure Pc et al are up-to-date
1230  this->update();
1231 
1232  Tf = total_movement_time;
1233  Tai = 0.0f;
1234  Taf = ending_acceleration_time;
1235  Vf = final_velocity;
1236 
1237  Pi = Pc;
1238  Vm = Vi = Vc;
1239 
1240  TSi = timestamp();
1241  Ai = 0.0f;
1242  Af = (Vf-Vm)/Taf;
1243  Pf = Pi + Pf*(Tf - Taf) + Vm*Taf + 0.5f*Af*(Taf*Taf);
1244 }
1245 
1247 {
1248  float time = (float)(timestamp() - TSi)/1000.0f;
1249  this->update(time);
1250 }
1251 
1252 void avd_movement::update(float Time)
1253 {
1254  if(Tf <= 0.0f)
1255  {
1256  //This avd_movement is just serving as static storage
1257  Pc = Pi;
1258  Vc = Vi;
1259  }
1260  else if(Time >= Tf)
1261  {
1262  //Movement has ended, but the thing may still have a constant velocity
1263  Pc = Pf + Vf*(Time-Tf);
1264  Vc = Vf;
1265  }
1266  else
1267  {
1268  //Movement is in-progress and we must calculate where the thing is now.
1269  float t = Time;
1270  float Tc = 0.0f;
1271 
1272  if(t >= 0.0f)
1273  {
1274  Pc = Pi;
1275  Vc = Vi;
1276  }
1277 
1278  if(t >= 0.0f && Tai > 0.0f)
1279  {
1280  if(t < Tai)
1281  Tc = t;
1282  else
1283  Tc = Tai;
1284  Pc = Pc + Vi*Tc + 0.5f*Ai*(Tc*Tc);
1285  Vc = Vc + Ai*Tc;
1286  }
1287 
1288  if(t >= Tai && (Tai+Taf) < Tf)
1289  {
1290  if(t < (Tf-Taf))
1291  Tc = (t-Tai);
1292  else
1293  Tc = (Tf-Tai-Taf);
1294 
1295  Pc = Pc + Vm*Tc;
1296  // Vc = Vc;
1297  }
1298 
1299  if(t >= (Tf-Taf) && Taf > 0.0f)
1300  {
1301  if(t < Tf)
1302  Tc = t-(Tf-Taf);
1303  else
1304  Tc = Taf;
1305 
1306  Pc = Pc + Vm*Tc + 0.5f*Af*(Tc*Tc);
1307  Vc = Vc + Af*Tc;
1308  }
1309  }
1310 }
float max_rear_vel
Definition: physics.h:53
float cur_glide_cap
Definition: physics.h:90
int timestamp(int delta_ms)
Definition: timer.cpp:226
void physics_predict_pos_and_vel(physics_info *pi, float delta_time, vec3d *predicted_vel, vec3d *predicted_pos)
Definition: physics.cpp:424
float p
Definition: pstypes.h:111
#define MIN(a, b)
Definition: pstypes.h:296
int is_valid_matrix(const matrix *m)
Definition: vecmat.cpp:2395
void setVD(float total_movement_time, float ending_acceleration_time, float final_velocity)
Definition: physics.cpp:1227
float vm_vec_mag_quick(const vec3d *v)
Definition: vecmat.cpp:371
matrix * vm_matrix_x_matrix(matrix *dest, const matrix *src0, const matrix *src1)
Definition: vecmat.cpp:1006
vec3d rotvel
Definition: physics.h:78
void update()
Definition: physics.cpp:1246
float vm_vec_mag(const vec3d *v)
Definition: vecmat.cpp:325
vec3d desired_vel
Definition: physics.h:70
float afterburner_forward_accel_time_const
Definition: physics.h:60
void set(float position)
Definition: physics.cpp:1188
void physics_set_viewer(physics_info *p, int dir)
Definition: physics.cpp:135
int Fred_running
Definition: fred.cpp:44
matrix * vm_angles_2_matrix(matrix *m, const angles *a)
Definition: vecmat.cpp:752
bool use_newtonian_damp
Definition: physics.h:92
#define DEAD_ROTVEL_CAP
Definition: physics.cpp:32
#define PF_GLIDING
Definition: physics.h:32
Assert(pm!=NULL)
#define SW_ROT_FACTOR
Definition: physics.cpp:37
Definition: pstypes.h:88
#define WHACK_LIMIT
Definition: physics.cpp:774
float side_slip_time_const
Definition: physics.h:44
#define PF_CONST_VEL
Definition: physics.h:26
#define MAX_SHAKE
Definition: physics.cpp:905
void get(float Time, float *Position, float *Velocity)
Definition: physics.cpp:1172
#define ROTVEL_TOL
Definition: physics.cpp:30
struct vec3d::@225::@227 xyz
#define RESET_SHIP_SPEED
Definition: physics.cpp:35
vec3d max_vel
Definition: physics.h:49
GLclampf f
Definition: Glext.h:7097
#define PF_SPECIAL_WARP_IN
Definition: physics.h:28
#define TRUE
Definition: pstypes.h:399
#define MAX_ROTVEL
Definition: physics.cpp:904
matrix * vm_copy_transpose(matrix *dest, const matrix *src)
Definition: vecmat.cpp:984
vec3d * vm_vec_rotate(vec3d *dest, const vec3d *src, const matrix *m)
Definition: vecmat.cpp:933
fix t2
Definition: animplay.cpp:37
float side_thrust
Definition: physics.h:73
const int RAND_MAX_2
Definition: pstypes.h:308
void vm_vec_scale_add2(vec3d *dest, const vec3d *src, float k)
Definition: vecmat.cpp:284
float afterburner_reverse_accel
Definition: physics.h:94
void physics_set_rotvel_and_saturate(float *dest, float delta)
Definition: physics.cpp:744
hull_check orient
Definition: lua.cpp:5049
vec3d booster_max_vel
Definition: physics.h:51
float booster_forward_accel_time_const
Definition: physics.h:61
GLenum GLenum GLenum GLenum GLenum scale
Definition: Glext.h:8503
matrix I_body_inv
Definition: physics.h:41
vec3d max_rotvel
Definition: physics.h:52
float glide_ramp(float v_in, float v_goal, float ramp_time_const, float accel_mult, float t)
Definition: physics.cpp:857
void physics_apply_shock(vec3d *direction_vec, float pressure, physics_info *pi, matrix *orient, vec3d *min, vec3d *max, float radius)
Definition: physics.cpp:907
void apply_physics(float damping, float desired_vel, float initial_vel, float t, float *new_vel, float *delta_pos)
Definition: physics.cpp:108
float vm_vec_mag_squared(const vec3d *v)
Definition: vecmat.cpp:339
void ship_get_eye(vec3d *eye_pos, matrix *eye_orient, object *obj, bool do_slew, bool from_origin)
Definition: ship.cpp:13227
#define IS_VEC_NULL_SQ_SAFE(v)
Definition: vecmat.h:24
float forward_decel_time_const
Definition: physics.h:62
#define PF_SPECIAL_WARP_OUT
Definition: physics.h:30
void physics_sim_vel(vec3d *position, physics_info *pi, float sim_time, matrix *orient)
Definition: physics.cpp:263
#define PF_BOOSTER_ON
Definition: physics.h:31
void physics_collide_whack(vec3d *impulse, vec3d *world_delta_rotvel, physics_info *pi, matrix *orient, bool is_landing)
Definition: physics.cpp:1026
typedef int(SCP_EXT_CALLCONV *SCPDLL_PFVERSION)(SCPDLL_Version *)
int afterburner_decay
Definition: physics.h:85
float delta_bank_const
Definition: physics.h:47
void vm_vec_add2(vec3d *dest, const vec3d *src)
Definition: vecmat.cpp:178
#define MIN_RADIUS
Definition: physics.cpp:902
float pitch
Definition: physics.h:100
vec3d desired_rotvel
Definition: physics.h:71
struct matrix::@228::@230 vec
#define PF_REDUCED_DAMP
Definition: physics.h:22
void vm_vec_scale(vec3d *dest, float s)
Definition: vecmat.cpp:248
int timestamp_until(int stamp)
Definition: timer.cpp:242
#define nprintf(args)
Definition: pstypes.h:239
float rotdamp
Definition: physics.h:43
void physics_sim_editor(vec3d *position, matrix *orient, physics_info *pi, float sim_time)
Definition: physics.cpp:385
ai_profile_t * ai_profile
Definition: missionparse.h:168
float slide_decel_time_const
Definition: physics.h:64
float speed
Definition: physics.h:79
void physics_sim_rot(matrix *orient, physics_info *pi, float sim_time)
Definition: physics.cpp:151
bool Flight_controls_follow_eyepoint_orientation
Definition: mod_table.cpp:31
int Wash_on
Definition: shipfx.cpp:2864
#define PF_ACCELERATES
Definition: physics.h:18
int reduced_damp_decay
Definition: physics.h:87
void vm_orthogonalize_matrix(matrix *m_src)
Definition: vecmat.cpp:1247
float forward
Definition: physics.h:105
const float RAND_MAX_1f
Definition: pstypes.h:309
void physics_init(physics_info *pi)
Definition: physics.cpp:49
#define fl_abs(fl)
Definition: floating.h:31
#define PF_FORCE_GLIDE
Definition: physics.h:33
#define MAX_VEL
Definition: physics.cpp:906
#define ROTVEL_WHACK_CONST
Definition: physics.cpp:775
#define delta
Definition: fvi.cpp:418
float vm_vec_normalize_safe(vec3d *v)
Definition: vecmat.cpp:471
GLdouble GLdouble t
Definition: Glext.h:5329
void setAVD(float final_position, float total_movement_time, float starting_accleration_time, float ending_acceleration_time, float final_velocity)
Definition: physics.cpp:1194
vec3d * vm_vec_unrotate(vec3d *dest, const vec3d *src, const matrix *m)
Definition: vecmat.cpp:959
#define REDUCED_DAMP_TIME
Definition: physics.cpp:41
vec3d afterburner_max_vel
Definition: physics.h:50
#define vm_vec_zero(v)
Definition: vecmat.h:37
uint flags
Definition: physics.h:37
#define PF_USE_VEL
Definition: physics.h:19
#define MAX_RADIUS
Definition: physics.cpp:903
float glide_cap
Definition: physics.h:89
#define vm_vec_make(v, _x, _y, _z)
Definition: vecmat.h:48
int Physics_viewer_direction
Definition: physics.cpp:129
matrix orient
Definition: object.h:153
void vm_vec_copy_scale(vec3d *dest, const vec3d *src, float s)
Definition: vecmat.cpp:257
#define OBJ_SHIP
Definition: object.h:32
#define PHYSICS_VIEWER_FRONT
Definition: physics.h:153
float bank
Definition: physics.h:104
float forward_cruise_percent
Definition: physics.h:106
int is_valid_vec(const vec3d *vec)
Definition: vecmat.cpp:2389
void physics_read_flying_controls(matrix *orient, physics_info *pi, control_info *ci, float sim_time, vec3d *wash_rot)
Definition: physics.cpp:449
vec3d vel
Definition: physics.h:77
void clear()
Definition: physics.cpp:1145
float fspeed
Definition: physics.h:80
fix t1
Definition: animplay.cpp:37
int check_rotvel_limit(physics_info *pi)
Definition: physics.cpp:1064
if(aifft_max_checks<=0)
Definition: aiturret.cpp:1581
void physics_sim(vec3d *position, matrix *orient, physics_info *pi, float sim_time)
Definition: physics.cpp:364
typedef float(SCP_EXT_CALLCONV *SCPTRACKIR_PFFLOATVOID)()
#define AIPF2_GLIDE_DECAY_REQUIRES_THRUST
Definition: ai_profiles.h:70
#define REDUCED_DAMP_VEL
Definition: physics.cpp:40
#define REDUCED_DAMP_FACTOR
Definition: physics.cpp:39
void physics_predict_pos(physics_info *pi, float delta_time, vec3d *predicted_pos)
Definition: physics.cpp:394
float Physics_viewer_bank
Definition: physics.cpp:128
physics_info * Viewer_physics_info
Definition: physics.cpp:130
float heading
Definition: physics.h:102
float forward_accel_time_const
Definition: physics.h:59
matrix last_rotmat
Definition: physics.h:83
#define MAX_SHIP_SPEED
Definition: physics.cpp:34
float vm_vec_copy_normalize(vec3d *dest, const vec3d *src)
Definition: vecmat.cpp:427
void physics_apply_whack(vec3d *impulse, vec3d *pos, physics_info *pi, matrix *orient, float mass)
Definition: physics.cpp:776
#define fl_sqrt(fl)
Definition: floating.h:29
GLfloat GLfloat p
Definition: Glext.h:8373
float slide_accel_time_const
Definition: physics.h:63
float vertical
Definition: physics.h:101
#define PF_DEAD_DAMP
Definition: physics.h:24
float afterburner_max_reverse_vel
Definition: physics.h:93
#define timestamp_elapsed(stamp)
Definition: timer.h:102
#define PF_SLIDE_ENABLED
Definition: physics.h:21
hull_check pos
Definition: lua.cpp:5050
float vm_vec_dot(const vec3d *v0, const vec3d *v1)
Definition: vecmat.cpp:312
#define WEAPON_SHAKE_TIME
Definition: physics.cpp:42
float velocity_ramp(float v_in, float v_goal, float time_const, float t)
Definition: physics.cpp:824
float sideways
Definition: physics.h:103
float shockwave_shake_amp
Definition: physics.h:65
#define SPECIAL_WARP_T_CONST
Definition: physics.cpp:43
object * Player_obj
Definition: object.cpp:56
vec3d prev_ramp_vel
Definition: physics.h:69
int temp
Definition: lua.cpp:4996
#define PF_AFTERBURNER_ON
Definition: physics.h:20
#define MAX(a, b)
Definition: pstypes.h:299
int shockwave_decay
Definition: physics.h:86
float mass
Definition: physics.h:39
vec3d * vm_vec_cross(vec3d *dest, const vec3d *src0, const vec3d *src1)
Definition: vecmat.cpp:645
#define PF_IN_SHOCKWAVE
Definition: physics.h:23
mission The_mission
float h
Definition: pstypes.h:111
char type
Definition: object.h:146
void physics_sim_rot_editor(matrix *orient, physics_info *pi, float sim_time)
Definition: physics.cpp:223
float glide_accel_mult
Definition: physics.h:91
#define FALSE
Definition: pstypes.h:400
#define STD_PRESSURE
Definition: physics.cpp:901
void physics_predict_vel(physics_info *pi, float delta_time, vec3d *predicted_vel)
Definition: physics.cpp:407
#define timestamp_valid(stamp)
Definition: timer.h:104
float vert_thrust
Definition: physics.h:74
int myrand()
Definition: systemvars.cpp:102
#define SW_BLAST_DURATION
Definition: physics.cpp:38
void update_reduced_damp_timestamp(physics_info *pi, float impulse)
Definition: physics.cpp:1111
float b
Definition: pstypes.h:111
float forward_thrust
Definition: physics.h:72
float vm_vec_normalize(vec3d *v)
Definition: vecmat.cpp:460