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/Physics/Physics.cpp $
18 * Revision 1.3 2002/06/09 04:41:25 relnev
19 * added copyright header
21 * Revision 1.2 2002/05/03 13:34:33 theoddone33
24 * Revision 1.1.1.1 2002/05/03 03:28:10 root
28 * 5 8/13/99 10:49a Andsager
29 * Knossos and HUGE ship warp out. HUGE ship warp in. Stealth search
30 * modes dont collide big ships.
32 * 4 7/03/99 5:50p Dave
33 * Make rotated bitmaps draw properly in padlock views.
35 * 3 5/11/99 10:16p Andsager
36 * First pass on engine wash effect. Rotation (control input), damage,
39 * 2 10/07/98 10:53a Dave
42 * 1 10/07/98 10:50a Dave
44 * 125 8/26/98 4:00p Johnson
45 * Removed max velocity assert so the new huge cap ship can warp in
48 * 124 5/18/98 5:01p Comet
49 * don't do displacement checks in multiplayer
51 * 123 4/06/98 2:38p Duncan
52 * AL: Fix potential negative sqrt due to numerical inaccuracy
54 * 122 3/25/98 1:30p Andsager
55 * comment out physics assert
57 * 121 3/23/98 9:48a Andsager
60 * 120 3/22/98 4:11p Andsager
61 * Remove global Freespace_running
63 * 119 3/20/98 5:15p Andsager
64 * Revised calculation of rotation, shake, and velocity in response to
65 * shockwave since capital ships were seen to shake.
67 * 118 3/19/98 1:06p Andsager
68 * Fix bug checking excessive velocity with accelerated time.
70 * 117 3/17/98 5:43p Andsager
71 * Modify physics checks for very slow frame rates.
73 * 116 3/17/98 9:54a Andsager
74 * Temporary take out Int3()s in velocity checks
76 * 115 3/17/98 9:51a Allender
77 * temporarily commented out Int3 that was causing pain
79 * 114 3/16/98 6:07p Johnson
80 * DA: check that ship velocity does not get too high from collisons
82 * 113 3/16/98 4:39p Adam
83 * change Dave's asserts so that displacement checks don't get used when
86 * 112 3/16/98 1:11p Andsager
87 * Turn on velocity, displacement limit checks
89 * 111 3/12/98 5:21p Andsager
90 * Optimize physics for lasers and dumbfire missiles
92 * 110 3/09/98 2:10p Andsager
93 * Put in checks for debris (other) with excessive velocity.
95 * 109 3/09/98 12:59p Mike
96 * Put error checking in physics code to detect NANs.
98 * 108 3/09/98 12:13a Andsager
99 * Add code to help find jumps in position.
101 * 107 3/03/98 10:39a Andsager
102 * Fixed erroneous mprintf for log term in physics_apply_shock
104 * 106 2/11/98 4:52p Mike
105 * Better attacking by ships.
106 * Fix stupidity in AI classes, which were in backward order!
108 * 105 2/03/98 6:01p Andsager
109 * Fix excessive rotvel in debris_create. Check using physics function
110 * check_rotvel_limit.
112 * 104 2/03/98 10:45a Mike
113 * Comment out mprintf that could occur very often.
115 * 103 1/29/98 2:38p Andsager
116 * Fix bug in physics_apply_shock so that large ships have a smaller
117 * effect from shockwaves.
119 * 102 1/23/98 11:31a Andsager
120 * Added I_body_inv to phys_init. Needed for shockwaves hitting ships in
121 * descent style physics.
123 * 101 1/23/98 9:02a John
124 * Took out Dave's debugging Int3 since they aren't finding what he
125 * thought they would and they broke Testcode and pofview.
127 * 100 1/22/98 5:10p Mike
128 * Fix bug with player's damp getting stuck off.
130 * 99 1/20/98 3:13p Allender
131 * check for Player_obj being valid before doing some other andsager
132 * sanity check in physics_sim_vel
134 * 98 1/20/98 10:08a Andsager
135 * Remove uninitialized viariable warnings.
137 * 97 1/19/98 3:46p Allender
138 * fixed problem where a previous changed caused optimized builds to
139 * break. Don't do a quick out on velcoity_ramp() anymore
141 * 96 1/19/98 12:00p Dave
142 * DA: Revise instantaneous velocity debug check to work with
145 * 95 1/16/98 3:03p Andsager
146 * Fix debug info from int3() on player death.
148 * 94 1/16/98 2:54p Andsager
151 * 93 1/16/98 2:34p Andsager
152 * Added debug code to find instantaneous acceleration.
154 * 92 1/16/98 12:14p Andsager
155 * Add error checking for the current brief stage
157 * 91 12/29/97 5:10p Allender
158 * fixed problems with speed not being reported properly in multiplayer
159 * games. Made read_flying_controls take frametime as a parameter. More
160 * ship/weapon select stuff
162 * 90 12/29/97 12:58p Johnson
163 * don't debug rotational velocity when Fred is running
165 * 89 12/08/97 10:29a Andsager
166 * Remove shockwave physics parameters from weapon_area_apply_blast and
169 * 88 12/05/97 3:31p Andsager
170 * Added view shake if hit by a weapon or collisoin.
172 * 87 12/03/97 5:47p Andsager
173 * Changed reduced damping following collision or weapon to run off time
176 * 86 11/24/97 1:54p Dan
177 * Mike: Comment out Assert() in physics, debug_rotvel().
179 * 85 11/24/97 8:46a Andsager
180 * Added rotational velocity caps and debug info.
182 * 84 11/20/97 4:01p Mike
183 * Prevent divide overflow.
185 * 83 11/20/97 12:34a Mike
186 * Make ships coast to a stop when their engines have been destroyed.
187 * Tricky because code doesn't use damp in forward dimension.
189 * 82 11/19/97 5:57p Mike
190 * Hmm, undid all my changes, except for the crucial removal of a blank
191 * between "physics_sim" and the open paren.
193 * 81 11/19/97 1:26a Andsager
194 * Made shockwaves work again, including shake.
196 * 80 11/17/97 5:15p Andsager
198 * 79 11/13/97 6:01p Andsager
199 * Improve comment in physic_collide_whack
201 * 78 11/13/97 5:41p Andsager
202 * Decreased the rotational whack after getting hit by lasers and
205 * 77 10/29/97 5:01p Andsager
206 * fixed bug in collision physics (physics_collide_whack)
208 * 76 9/16/97 5:28p Andsager
209 * calculate velocity in physics_sim_vel
211 * 75 9/11/97 5:25p Mike
212 * Fix ! vs. & precedence bug in physics_sim_vel().
214 * 74 9/09/97 10:14p Andsager
216 * 73 9/04/97 5:09p Andsager
217 * implement physics using moment of inertia and mass (from BSPgen).
218 * Added to phys_info struct. Updated ship_info, polymodel structs.
219 * Updated weapon ($Mass and $Force) and ship ($Mass -> $Density) tables
221 * 72 9/03/97 5:43p Andsager
222 * fixed bug calculating ramp velocity after getting whacked
224 * 71 9/02/97 4:19p Mike
225 * Comment out code at end of physics_apply_whack() that made ships nearly
228 * 70 8/29/97 10:13a Allender
229 * work on server/client prediction code -- doesn't work too well. Made
230 * all clients simulate their own orientation with the server giving
231 * corrections every so often.
233 * 69 8/25/97 2:41p Andsager
234 * collision code also changes ramp velocity to take account of collison.
235 * some optimization of collision physics.
237 * 68 8/19/97 9:56a John
238 * new thruster effect fairly functional
240 * 67 8/18/97 6:26p Andsager
241 * preliminary version of collision physics
243 * 66 8/17/97 9:19p Andsager
244 * improvement to collision physics
246 * 65 8/13/97 12:16p Andsager
247 * intermediate level checkin for use with collision with extended objects
249 * 64 8/05/97 3:13p Andsager
250 * improved comments to apply_whack
252 * 63 8/05/97 10:18a Lawrance
253 * my_rand() being used temporarily instead of rand()
255 * 62 7/31/97 12:44p Andsager
257 * 61 7/25/97 5:05p John
258 * fixed a potential bug in ramp_velocity when delta dist becomes 0, a
259 * bunch of sideways 8 thingys appear :-)
262 * 60 7/25/97 1:04p Andsager
263 * Modified physics flag PF_REDUCED_DAMP for damping when object is hit.
264 * Flag is now set in physics_apply_whack/shock and turned off in
265 * physics_sim_vel. Weapons should not directly set this flag.
267 * 59 7/25/97 9:07a Andsager
268 * modified apply_whack
270 * 58 7/23/97 5:10p Andsager
271 * Enhanced shockwave effect with shake based on blast force.
273 * 57 7/22/97 2:40p Andsager
274 * shockwaves now cause proper rotation of ships
276 * 56 7/21/97 4:12p Mike
277 * Two ships move as one while docked, including physics whacks. Spin of
278 * objects when killed based on speed.
280 * 55 7/21/97 2:19p John
281 * made descent-style physics work for testcode. fixed bug in the
282 * velocity_ramp code with t==0.0f
284 * 54 7/17/97 8:02p Lawrance
285 * improve comments to physics_apply_whack()
287 * 53 7/16/97 4:42p Mike
288 * Make afterburner shake viewer, not ship.
289 * Shake for limited time.
290 * Add timestamp_until() function to timer library.
292 * 52 7/16/97 11:53a Andsager
294 * 51 7/16/97 11:06a Andsager
295 * Allow damping on z to support shockwaves
297 * 50 7/15/97 12:28p Andsager
298 * commented out some debug code.
300 * 49 7/15/97 12:25p Andsager
301 * More integration with new physics.
303 * 48 7/15/97 12:03p Andsager
306 * 47 7/11/97 11:54a John
307 * added rotated 3d bitmaps.
309 * 46 6/25/97 12:22p Mike
310 * Diminish bashing into of objects. Make ships flying waypoints fly in
313 * 45 6/17/97 10:59p Mike
314 * Comment out irritating mprintf().
316 * 44 6/11/97 4:27p Mike
317 * Balance the whack ships take when they get hit.
319 * 43 4/17/97 10:02a Lawrance
320 * allow ship shaking for ABURN_DECAY_TIME after afterburners cut out
322 * 42 4/16/97 10:48p Mike
324 * Made afterburner engagement a bit in physics flags, removed from ship
325 * flags, removed a parameter to physics_read_flying_controls().
327 * 41 4/11/97 3:17p Mike
328 * Modify physics_sim() to use non quick version of vm_vec_mag(). Quick
329 * version was causing cumulative errors in velocity of homing missiles.
331 * 40 4/10/97 3:20p Mike
332 * Change hull damage to be like shields.
334 * 39 4/04/97 11:08a Adam
335 * played with banking values
337 * 38 4/04/97 12:19a Mike
338 * Make ships bank when they turn.
340 * 37 3/04/97 3:10p Mike
341 * Intermediate checkin: Had to resolve some build errors. Working on two
342 * docked ships moving as one.
344 * 36 2/25/97 7:39p Lawrance
345 * added afterburner_on flag to physics_read_flying_controls() to account
346 * for afterburner effects
348 * 35 2/05/97 6:02p Hoffoss
349 * Added heading rotation around universal Y axis to Fred when controlling
352 * 34 2/05/97 9:15a Mike
353 * Partial implementation of new docking system, integrated so I could
354 * update on John's new turret code.
356 * 33 1/20/97 7:58p John
357 * Fixed some link errors with testcode.
368 #include "floating.h"
370 #include "freespace.h"
371 #include "linklist.h"
375 // defines for physics functions
376 #define MAX_TURN_LIMIT 0.2618f // about 15 degrees
379 #define ROTVEL_TOL 0.1 // Amount of rotvel is decreased if over cap
380 #define ROTVEL_CAP 14.0 // Rotational velocity cap for live objects
381 #define DEAD_ROTVEL_CAP 16.3 // Rotational velocity cap for dead objects
383 #define MAX_SHIP_SPEED 300 // Maximum speed allowed after whack or shockwave
384 #define RESET_SHIP_SPEED 240 // Speed that a ship is reset to after exceeding MAX_SHIP_SPEED
386 #define SW_ROT_FACTOR 5 // increase in rotational time constant in shockwave
387 #define SW_BLAST_DURATION 2000 // maximum duration of shockwave
388 #define REDUCED_DAMP_FACTOR 10 // increase in side_slip and acceleration time constants (scaled according to reduced damp time)
389 #define REDUCED_DAMP_VEL 30 // change in velocity at which reduced_damp_time is 2000 ms
390 #define REDUCED_DAMP_TIME 2000 // ms (2.0 sec)
391 #define WEAPON_SHAKE_TIME 500 // ms (0.5 sec) viewer shake time after hit by weapon (implemented via afterburner shake)
392 #define SPECIAL_WARP_T_CONST 0.651 // special warp time constant (loose 99 % of excess speed in 3 sec)
394 #define PHYS_DEBUG // check if (vel > 500) or (displacement in one frame > 350)
396 void update_reduced_damp_timestamp( physics_info *pi, float impulse );
398 void physics_init( physics_info * pi )
400 memset( pi, 0, sizeof(physics_info) );
402 pi->mass = 10.0f; // This ship weighs 10 units
403 pi->side_slip_time_const = 0.05f;
406 pi->max_vel.x = 100.0f; //sideways
407 pi->max_vel.y = 100.0f; //up/down
408 pi->max_vel.z = 100.0f; //forward
409 pi->max_rear_vel = 100.0f; //backward -- controlled seperately
411 pi->max_rotvel.x = 2.0f; //pitch
412 pi->max_rotvel.y = 1.0f; //heading
413 pi->max_rotvel.z = 2.0f; //bank
415 pi->prev_ramp_vel.x = 0.0f;
416 pi->prev_ramp_vel.y = 0.0f;
417 pi->prev_ramp_vel.z = 0.0f;
419 pi->desired_vel.x = 0.0f;
420 pi->desired_vel.y = 0.0f;
421 pi->desired_vel.z = 0.0f;
423 pi->slide_accel_time_const=pi->side_slip_time_const; // slide using max_vel.x & .y
424 pi->slide_decel_time_const=pi->side_slip_time_const; // slide using max_vel.x & .y
426 pi->afterburner_decay = 1;
427 pi->forward_thrust = 0.0f;
431 // default values for moment of inetaia
432 vm_vec_make( &pi->I_body_inv.rvec, 1e-5f, 0.0f, 0.0f );
433 vm_vec_make( &pi->I_body_inv.uvec, 0.0f, 1e-5f, 0.0f );
434 vm_vec_make( &pi->I_body_inv.fvec, 0.0f, 0.0f, 1e-5f );
439 //==========================================================================
440 // apply_physics - This does correct physics independent of frame rate.
443 // damping = damping factor. Setting this to zero make the object instantly
444 // go to the target velocity. Increasing it makes the object ramp
445 // up or down to the target velocity.
446 // desired_vel = the target velocity
447 // initial_vel = velocity at last call
448 // t = elapsed time since last call
451 // new_vel = current velocity
452 // delta_pos = delta position (framevec)
453 // You can extend this to 3d by calling it 3 times, once for each x,y,z component.
455 void apply_physics( float damping, float desired_vel, float initial_vel, float t, float * new_vel, float * delta_pos )
457 if ( damping < 0.0001f ) {
459 *delta_pos = desired_vel*t;
461 *new_vel = desired_vel;
464 dv = initial_vel - desired_vel;
465 e = (float)exp( -t/damping );
467 *delta_pos = (1.0f - e)*dv*damping + desired_vel*t;
469 *new_vel = dv*e + desired_vel;
475 float Physics_viewer_bank = 0.0f;
476 int Physics_viewer_direction = PHYSICS_VIEWER_FRONT;
477 static physics_info * Viewer_physics_info = NULL;
479 // If you would like Physics_viewer_bank to be tracked (Which is needed
480 // for rotating 3d bitmaps) call this and pass it a pointer to the
481 // viewer's physics info.
482 void physics_set_viewer( physics_info * p, int dir )
484 if ( (Viewer_physics_info != p) || (Physics_viewer_direction != dir) ) {
485 Viewer_physics_info = p;
486 Physics_viewer_bank = 0.0f;
487 Physics_viewer_direction = dir;
493 // -----------------------------------------------------------------------------------------------------------
494 // add rotational velocity & acceleration
498 void physics_sim_rot(matrix * orient, physics_info * pi, float sim_time )
503 float shock_amplitude;
505 float shock_fraction_time_left;
507 Assert(is_valid_matrix(orient));
508 Assert(is_valid_vec(&pi->rotvel));
509 Assert(is_valid_vec(&pi->desired_rotvel));
511 // Handle special case of shockwave
512 shock_amplitude = 0.0f;
513 if ( pi->flags & PF_IN_SHOCKWAVE ) {
514 if ( timestamp_elapsed(pi->shockwave_decay) ) {
515 pi->flags &= ~PF_IN_SHOCKWAVE;
516 rotdamp = pi->rotdamp;
518 shock_fraction_time_left = timestamp_until( pi->shockwave_decay ) / (float) SW_BLAST_DURATION;
519 rotdamp = pi->rotdamp + pi->rotdamp * (SW_ROT_FACTOR - 1) * shock_fraction_time_left;
520 shock_amplitude = pi->shockwave_shake_amp * shock_fraction_time_left;
523 rotdamp = pi->rotdamp;
526 // Do rotational physics with given damping
527 apply_physics( rotdamp, pi->desired_rotvel.x, pi->rotvel.x, sim_time, &new_vel.x, NULL );
528 apply_physics( rotdamp, pi->desired_rotvel.y, pi->rotvel.y, sim_time, &new_vel.y, NULL );
529 apply_physics( rotdamp, pi->desired_rotvel.z, pi->rotvel.z, sim_time, &new_vel.z, NULL );
533 if (check_rotvel_limit( pi )) {
534 nprintf(("Physics", "rotvel reset in physics_sim_rot\n"));
538 Assert(is_valid_vec(&new_vel));
540 pi->rotvel = new_vel;
542 tangles.p = pi->rotvel.x*sim_time;
543 tangles.h = pi->rotvel.y*sim_time;
544 tangles.b = pi->rotvel.z*sim_time;
546 // If this is the viewer_object, keep track of the
547 // changes in banking so that rotated bitmaps look correct.
548 // This is used by the g3_draw_rotated_bitmap function.
549 if ( pi == Viewer_physics_info ) {
550 switch(Physics_viewer_direction){
551 case PHYSICS_VIEWER_FRONT:
552 Physics_viewer_bank -= tangles.b;
555 case PHYSICS_VIEWER_UP:
556 Physics_viewer_bank -= tangles.h;
559 case PHYSICS_VIEWER_REAR:
560 Physics_viewer_bank += tangles.b;
563 case PHYSICS_VIEWER_LEFT:
564 Physics_viewer_bank += tangles.p;
567 case PHYSICS_VIEWER_RIGHT:
568 Physics_viewer_bank -= tangles.p;
572 Physics_viewer_bank -= tangles.b;
576 if ( Physics_viewer_bank < 0.0f ){
577 Physics_viewer_bank += 2.0f * PI;
580 if ( Physics_viewer_bank > 2.0f * PI ){
581 Physics_viewer_bank -= 2.0f * PI;
585 /* // Make ship shake due to afterburner.
586 if (pi->flags & PF_AFTERBURNER_ON || !timestamp_elapsed(pi->afterburner_decay) ) {
589 max_speed = vm_vec_mag_quick(&pi->max_vel);
590 tangles.p += (float) (rand()-RAND_MAX/2)/RAND_MAX * pi->speed/max_speed/64.0f;
591 tangles.h += (float) (rand()-RAND_MAX/2)/RAND_MAX * pi->speed/max_speed/64.0f;
592 if ( pi->flags & PF_AFTERBURNER_ON ) {
593 pi->afterburner_decay = timestamp(ABURN_DECAY_TIME);
598 // Make ship shake due to shockwave, decreasing in amplitude at the end of the shockwave
599 if ( pi->flags & PF_IN_SHOCKWAVE ) {
600 tangles.p += (float) (myrand()-RAND_MAX/2)/RAND_MAX * shock_amplitude;
601 tangles.h += (float) (myrand()-RAND_MAX/2)/RAND_MAX * shock_amplitude;
605 vm_angles_2_matrix(&pi->last_rotmat, &tangles );
606 vm_matrix_x_matrix( &tmp, orient, &pi->last_rotmat );
609 vm_orthogonalize_matrix(orient);
613 // -----------------------------------------------------------------------------------------------------------
614 // add rotational velocity & acceleration
616 void physics_sim_rot_editor(matrix * orient, physics_info * pi, float sim_time)
623 apply_physics( pi->rotdamp, pi->desired_rotvel.x, pi->rotvel.x, sim_time,
626 apply_physics( pi->rotdamp, pi->desired_rotvel.y, pi->rotvel.y, sim_time,
629 apply_physics( pi->rotdamp, pi->desired_rotvel.z, pi->rotvel.z, sim_time,
632 pi->rotvel = new_vel;
634 tangles.p = pi->rotvel.x*sim_time;
635 tangles.h = pi->rotvel.y*sim_time;
636 tangles.b = pi->rotvel.z*sim_time;
639 t1.h = 0.0f; t1.b = 0.0f;
640 t2.p = 0.0f; t2.b = 0.0f;
642 // put in p & b like normal
643 vm_angles_2_matrix(&pi->last_rotmat, &t1 );
644 vm_matrix_x_matrix( &tmp, orient, &pi->last_rotmat );
646 // Put in heading separately
647 vm_angles_2_matrix(&pi->last_rotmat, &t2 );
648 vm_matrix_x_matrix( orient, &pi->last_rotmat, &tmp );
650 vm_orthogonalize_matrix(orient);
654 // Adds velocity to position
655 // finds velocity and displacement in local coords
656 void physics_sim_vel(vector * position, physics_info * pi, float sim_time, matrix *orient)
658 vector local_disp; // displacement in this frame
659 vector local_v_in; // velocity in local coords at the start of this frame
660 vector local_desired_vel; // desired velocity in local coords
661 vector local_v_out; // velocity in local coords following this frame
664 // Maybe clear the reduced_damp flag.
665 // This fixes the problem of the player getting near-instantaneous acceleration under unknown circumstances.
666 // The larger problem is probably that PF_USE_VEL is getting stuck set.
667 if ((pi->flags & PF_REDUCED_DAMP) && (timestamp_elapsed(pi->reduced_damp_decay))) {
668 pi->flags &= ~PF_REDUCED_DAMP;
671 // Set up damping constants based on special conditions
672 // ie. shockwave, collision, weapon, dead
673 if (pi->flags & PF_DEAD_DAMP) {
674 // side_slip_time_const is already quite large and now needs to be applied in all directions
675 vm_vec_make( &damp, pi->side_slip_time_const, pi->side_slip_time_const, pi->side_slip_time_const );
677 } else if (pi->flags & PF_REDUCED_DAMP) {
678 // case of shock, weapon, collide, etc.
679 if ( timestamp_elapsed(pi->reduced_damp_decay) ) {
680 vm_vec_make( &damp, pi->side_slip_time_const, pi->side_slip_time_const, 0.0f );
682 // damp is multiplied by fraction and not fraction^2, gives better collision separation
683 float reduced_damp_fraction_time_left = timestamp_until( pi->reduced_damp_decay ) / (float) REDUCED_DAMP_TIME;
684 damp.x = pi->side_slip_time_const * ( 1 + (REDUCED_DAMP_FACTOR-1) * reduced_damp_fraction_time_left );
685 damp.y = pi->side_slip_time_const * ( 1 + (REDUCED_DAMP_FACTOR-1) * reduced_damp_fraction_time_left );
686 damp.z = pi->side_slip_time_const * reduced_damp_fraction_time_left * REDUCED_DAMP_FACTOR;
690 vm_vec_make( &damp, pi->side_slip_time_const, pi->side_slip_time_const, 0.0f );
693 // Note: CANNOT maintain a *local velocity* since a rotation can occur in this frame.
694 // thus the local velocity of in the next frame can be different (this would require rotate to change local vel
695 // and this is not desired
697 // get local components of current velocity
698 vm_vec_rotate (&local_v_in, &pi->vel, orient);
700 // get local components of desired velocity
701 vm_vec_rotate (&local_desired_vel, &pi->desired_vel, orient);
703 // find updated LOCAL velocity and position in the local x direction
704 apply_physics (damp.x, local_desired_vel.x, local_v_in.x, sim_time, &local_v_out.x, &local_disp.x);
706 // find updated LOCAL velocity and position in the local y direction
707 apply_physics (damp.y, local_desired_vel.y, local_v_in.y, sim_time, &local_v_out.y, &local_disp.y);
709 // find updated LOCAL velocity and position in the local z direction
710 // for player ship, damp should normally be zero, but may be altered in a shockwave
711 // in death, shockwave,etc. we want damping time const large for all 3 axes
712 // warp in test - make excessive speed drop exponentially from max allowed
713 // become (0.01x in 3 sec)
715 int special_warp_in = FALSE;
716 float excess = local_v_in.z - pi->max_vel.z;
717 if (excess > 5 && (pi->flags & PF_SPECIAL_WARP_IN)) {
718 special_warp_in = TRUE;
719 float exp_factor = float(exp(-sim_time / SPECIAL_WARP_T_CONST));
720 local_v_out.z = pi->max_vel.z + excess * exp_factor;
721 local_disp.z = (pi->max_vel.z * sim_time) + excess * (float(SPECIAL_WARP_T_CONST) * (1.0f - exp_factor));
722 } else if (pi->flags & PF_SPECIAL_WARP_OUT) {
723 float exp_factor = float(exp(-sim_time / SPECIAL_WARP_T_CONST));
725 vm_vec_rotate(&temp, &pi->prev_ramp_vel, orient);
726 float deficeit = temp.z - local_v_in.z;
727 local_v_out.z = local_v_in.z + deficeit * (1.0f - exp_factor);
728 local_disp.z = (local_v_in.z * sim_time) + deficeit * (sim_time - (float(SPECIAL_WARP_T_CONST) * (1.0f - exp_factor)));
730 apply_physics (damp.z, local_desired_vel.z, local_v_in.z, sim_time, &local_v_out.z, &local_disp.z);
733 // maybe turn off special warp in flag
734 if ((pi->flags & PF_SPECIAL_WARP_IN) && (excess < 5)) {
735 pi->flags &= ~(PF_SPECIAL_WARP_IN);
738 // update world position from local to world coords using orient
740 vm_vec_unrotate (&world_disp, &local_disp, orient);
742 // check for excess velocity or translation
744 if ( (Game_mode & GM_IN_MISSION) && (Game_mode & GM_NORMAL) ) {
745 // Assert( (sim_time > 0.5f) || (vm_vec_mag_squared(&pi->vel) < 500*500) );
746 // Assert( (sim_time > 0.5f) || (vm_vec_mag_squared(&world_disp) < 350*350) );
749 vm_vec_add2 (position, &world_disp);
751 // update world velocity
752 vm_vec_unrotate(&pi->vel, &local_v_out, orient);
754 if (special_warp_in) {
755 vm_vec_rotate(&pi->prev_ramp_vel, &pi->vel, orient);
759 // -----------------------------------------------------------------------------------------------------------
760 // Simulate a physics object for this frame
761 void physics_sim(vector* position, matrix* orient, physics_info* pi, float sim_time)
763 // check flag which tells us whether or not to do velocity translation
764 if (pi->flags & PF_CONST_VEL) {
765 vm_vec_scale_add2(position, &pi->vel, sim_time);
767 physics_sim_vel(position, pi, sim_time, orient);
769 physics_sim_rot(orient, pi, sim_time);
771 pi->speed = vm_vec_mag(&pi->vel); // Note, cannot use quick version, causes cumulative error, increasing speed.
772 pi->fspeed = vm_vec_dot(&orient->fvec, &pi->vel); // instead of vector magnitude -- use only forward vector since we are only interested in forward velocity
777 // -----------------------------------------------------------------------------------------------------------
778 // Simulate a physics object for this frame. Used by the editor. The difference between
779 // this function and physics_sim() is that this one uses a heading change to rotate around
780 // the universal Y axis, rather than the local orientation's Y axis. Banking is also ignored.
781 void physics_sim_editor(vector *position, matrix * orient, physics_info * pi, float sim_time )
783 physics_sim_vel(position, pi, sim_time, orient);
784 physics_sim_rot_editor(orient, pi, sim_time);
785 pi->speed = vm_vec_mag_quick(&pi->vel);
786 pi->fspeed = vm_vec_dot(&orient->fvec, &pi->vel); // instead of vector magnitude -- use only forward vector since we are only interested in forward velocity
789 // function to predict an object's position given the delta time and an objects physics info
790 void physics_predict_pos(physics_info *pi, float delta_time, vector *predicted_pos)
792 apply_physics( pi->side_slip_time_const, pi->desired_vel.x, pi->vel.x, delta_time,
793 NULL, &predicted_pos->x );
795 apply_physics( pi->side_slip_time_const, pi->desired_vel.y, pi->vel.y, delta_time,
796 NULL, &predicted_pos->y );
798 apply_physics( pi->side_slip_time_const, pi->desired_vel.z, pi->vel.z, delta_time,
799 NULL, &predicted_pos->z );
802 // function to predict an object's velocity given the parameters
803 void physics_predict_vel(physics_info *pi, float delta_time, vector *predicted_vel)
805 if (pi->flags & PF_CONST_VEL) {
806 predicted_vel = &pi->vel;
808 apply_physics( pi->side_slip_time_const, pi->desired_vel.x, pi->vel.x, delta_time,
809 &predicted_vel->x, NULL );
811 apply_physics( pi->side_slip_time_const, pi->desired_vel.y, pi->vel.y, delta_time,
812 &predicted_vel->y, NULL );
814 apply_physics( pi->side_slip_time_const, pi->desired_vel.z, pi->vel.z, delta_time,
815 &predicted_vel->z, NULL );
819 // function to predict position and velocity of an object
820 void physics_predict_pos_and_vel(physics_info *pi, float delta_time, vector *predicted_vel, vector *predicted_pos)
823 apply_physics( pi->side_slip_time_const, pi->desired_vel.x, pi->vel.x, delta_time,
824 &predicted_vel->x, &predicted_pos->x );
826 apply_physics( pi->side_slip_time_const, pi->desired_vel.y, pi->vel.y, delta_time,
827 &predicted_vel->y, &predicted_pos->y );
829 apply_physics( pi->side_slip_time_const, pi->desired_vel.z, pi->vel.z, delta_time,
830 &predicted_vel->z, &predicted_pos->z );
833 // physics_read_flying_controls()
835 // parmeters: *orient ==>
838 // Adam: Uncomment-out this define to enable banking while turning.
839 #define BANK_WHEN_TURN
843 // function looks at the flying controls and the current velocity to determine a goal velocity
844 // function determines velocity in object's reference frame and goal velocity in object's reference frame
845 void physics_read_flying_controls( matrix * orient, physics_info * pi, control_info * ci, float sim_time, vector *wash_rot)
847 vector goal_vel; // goal velocity in local coords, *not* accounting for ramping of velcity
848 float ramp_time_const; // time constant for velocity ramping
850 float velocity_ramp (float v_in, float v_goal, float time_const, float t);
852 // if ( keyd_pressed[KEY_LSHIFT] ) {
853 // keyd_pressed[KEY_LSHIFT] = 0;
857 ci->forward += (ci->forward_cruise_percent / 100.0f);
859 // mprintf(("ci->forward == %7.3f\n", ci->forward));
861 // give control imput to cause rotation in engine wash
863 if ( wash_rot && Wash_on ) {
864 ci->pitch += wash_rot->x;
865 ci->bank += wash_rot->z;
866 ci->heading += wash_rot->y;
869 if (ci->pitch > 1.0f ) ci->pitch = 1.0f;
870 else if (ci->pitch < -1.0f ) ci->pitch = -1.0f;
872 if (ci->vertical > 1.0f ) ci->vertical = 1.0f;
873 else if (ci->vertical < -1.0f ) ci->vertical = -1.0f;
875 if (ci->heading > 1.0f ) ci->heading = 1.0f;
876 else if (ci->heading < -1.0f ) ci->heading = -1.0f;
878 if (ci->sideways > 1.0f ) ci->sideways = 1.0f;
879 else if (ci->sideways < -1.0f ) ci->sideways = -1.0f;
881 if (ci->bank > 1.0f ) ci->bank = 1.0f;
882 else if (ci->bank < -1.0f ) ci->bank = -1.0f;
884 if ( pi->flags & PF_AFTERBURNER_ON )
887 if (ci->forward > 1.0f ) ci->forward = 1.0f;
888 else if (ci->forward < -1.0f ) ci->forward = -1.0f;
890 pi->desired_rotvel.x = ci->pitch * pi->max_rotvel.x;
891 pi->desired_rotvel.y = ci->heading * pi->max_rotvel.y;
895 #ifdef BANK_WHEN_TURN
896 // To change direction of bank, negate the whole expression.
897 // To increase magnitude of banking, decrease denominator.
898 // Adam: The following statement is all the math for banking while turning.
899 delta_bank = - (ci->heading * pi->max_rotvel.y)/2.0f;
904 pi->desired_rotvel.z = ci->bank * pi->max_rotvel.z + delta_bank;
905 pi->forward_thrust = ci->forward;
907 if ( pi->flags & PF_AFTERBURNER_ON ) {
908 goal_vel.x = ci->sideways*pi->afterburner_max_vel.x;
909 goal_vel.y = ci->vertical*pi->afterburner_max_vel.y;
910 goal_vel.z = ci->forward* pi->afterburner_max_vel.z;
913 goal_vel.x = ci->sideways*pi->max_vel.x;
914 goal_vel.y = ci->vertical*pi->max_vel.y;
915 goal_vel.z = ci->forward* pi->max_vel.z;
918 if ( goal_vel.z < -pi->max_rear_vel )
919 goal_vel.z = -pi->max_rear_vel;
922 if ( pi->flags & PF_ACCELERATES ) {
924 // Determine *resultant* DESIRED VELOCITY (desired_vel) accounting for RAMPING of velocity
925 // Use LOCAL coordinates
926 // if slide_enabled, ramp velocity for x and y, otherwise set goal (0)
927 // always ramp velocity for z
930 // If reduced damp in effect, then adjust ramp_velocity and desired_velocity can not change as fast.
931 // Scale according to reduced_damp_time_expansion.
932 float reduced_damp_ramp_time_expansion;
933 if ( pi->flags & PF_REDUCED_DAMP ) {
934 float reduced_damp_fraction_time_left = timestamp_until( pi->reduced_damp_decay ) / (float) REDUCED_DAMP_TIME;
935 reduced_damp_ramp_time_expansion = 1.0f + (REDUCED_DAMP_FACTOR-1) * reduced_damp_fraction_time_left;
937 reduced_damp_ramp_time_expansion = 1.0f;
940 // if ( !use_descent && (Player_obj->phys_info.forward_accel_time_const < 0.1) && !(Ships[Player_obj->instance].flags & SF_DYING) && (Player_obj->type != OBJ_OBSERVER) )
941 // Int3(); // Get dave A
943 if (pi->flags & PF_SLIDE_ENABLED) {
944 // determine the local velocity
945 // deterimine whether accelerating or decleration toward goal for x
946 if ( goal_vel.x > 0.0f ) {
947 if ( goal_vel.x >= pi->prev_ramp_vel.x )
948 ramp_time_const = pi->slide_accel_time_const;
950 ramp_time_const = pi->slide_decel_time_const;
951 } else { // goal_vel.x <= 0.0
952 if ( goal_vel.x <= pi->prev_ramp_vel.x )
953 ramp_time_const = pi->slide_accel_time_const;
955 ramp_time_const = pi->slide_decel_time_const;
957 // If reduced damp in effect, then adjust ramp_velocity and desired_velocity can not change as fast
958 if ( pi->flags & PF_REDUCED_DAMP ) {
959 ramp_time_const *= reduced_damp_ramp_time_expansion;
961 pi->prev_ramp_vel.x = velocity_ramp(pi->prev_ramp_vel.x, goal_vel.x, ramp_time_const, sim_time);
963 // deterimine whether accelerating or decleration toward goal for y
964 if ( goal_vel.y > 0.0f ) {
965 if ( goal_vel.y >= pi->prev_ramp_vel.y )
966 ramp_time_const = pi->slide_accel_time_const;
968 ramp_time_const = pi->slide_decel_time_const;
969 } else { // goal_vel.y <= 0.0
970 if ( goal_vel.y <= pi->prev_ramp_vel.y )
971 ramp_time_const = pi->slide_accel_time_const;
973 ramp_time_const = pi->slide_decel_time_const;
975 // If reduced damp in effect, then adjust ramp_velocity and desired_velocity can not change as fast
976 if ( pi->flags & PF_REDUCED_DAMP ) {
977 ramp_time_const *= reduced_damp_ramp_time_expansion;
979 pi->prev_ramp_vel.y = velocity_ramp( pi->prev_ramp_vel.y, goal_vel.y, ramp_time_const, sim_time);
982 pi->prev_ramp_vel.x = 0.0f;
983 pi->prev_ramp_vel.y = 0.0f;
986 // find ramp velocity in the forward direction
987 if ( goal_vel.z >= pi->prev_ramp_vel.z ) {
988 if ( pi->flags & PF_AFTERBURNER_ON )
989 ramp_time_const = pi->afterburner_forward_accel_time_const;
991 ramp_time_const = pi->forward_accel_time_const;
993 ramp_time_const = pi->forward_decel_time_const;
995 // If reduced damp in effect, then adjust ramp_velocity and desired_velocity can not change as fast
996 if ( pi->flags & PF_REDUCED_DAMP ) {
997 ramp_time_const *= reduced_damp_ramp_time_expansion;
999 pi->prev_ramp_vel.z = velocity_ramp( pi->prev_ramp_vel.z, goal_vel.z, ramp_time_const, sim_time);
1002 // this translates local desired velocities to world velocities
1004 vm_vec_zero(&pi->desired_vel);
1005 vm_vec_scale_add2( &pi->desired_vel, &orient->rvec, pi->prev_ramp_vel.x );
1006 vm_vec_scale_add2( &pi->desired_vel, &orient->uvec, pi->prev_ramp_vel.y );
1007 vm_vec_scale_add2( &pi->desired_vel, &orient->fvec, pi->prev_ramp_vel.z );
1008 } else // object does not accelerate (PF_ACCELERATES not set)
1009 pi->desired_vel = pi->vel;
1014 // ----------------------------------------------------------------
1015 // Do *dest = *delta unless:
1016 // *delta is pretty small
1017 // and they are of different signs.
1018 void physics_set_rotvel_and_saturate(float *dest, float delta)
1021 if ((delta ^ *dest) < 0) {
1022 if (abs(delta) < F1_0/8) {
1023 // mprintf((0, "D"));
1026 // mprintf((0, "d"));
1029 // mprintf((0, "!"));
1037 // ----------------------------------------------------------------------------
1038 // physics_apply_whack applies an instaneous whack on an object changing
1039 // both the objects velocity and the rotational velocity based on the impulse
1042 // input: impulse => impulse vector ( force*time = impulse = change in momentum (mv) )
1043 // pos => vector from center of mass to location of where the force acts
1044 // pi => pointer to phys_info struct of object getting whacked
1045 // orient => orientation matrix (needed to set rotational impulse in body coords)
1046 // mass => mass of the object (may be different from pi.mass if docked)
1048 #define WHACK_LIMIT 0.001f
1049 #define ROTVEL_WHACK_CONST 0.12
1050 void physics_apply_whack(vector *impulse, vector *pos, physics_info *pi, matrix *orient, float mass)
1052 vector local_torque, torque;
1055 // Detect null vector.
1056 if ((fl_abs(impulse->x) <= WHACK_LIMIT) && (fl_abs(impulse->y) <= WHACK_LIMIT) && (fl_abs(impulse->z) <= WHACK_LIMIT))
1059 // first do the rotational velocity
1060 // calculate the torque on the body based on the point on the
1061 // object that was hit and the momentum being applied to the object
1063 vm_vec_crossprod(&torque, pos, impulse);
1064 vm_vec_rotate ( &local_torque, &torque, orient );
1066 vector delta_rotvel;
1067 vm_vec_rotate( &delta_rotvel, &local_torque, &pi->I_body_inv );
1068 vm_vec_scale ( &delta_rotvel, (float) ROTVEL_WHACK_CONST );
1069 vm_vec_add2( &pi->rotvel, &delta_rotvel );
1072 if (check_rotvel_limit( pi )) {
1073 nprintf(("Physics", "rotvel reset in physics_apply_whack\n"));
1077 //mprintf(("Whack: %7.3f %7.3f %7.3f\n", pi->rotvel.x, pi->rotvel.y, pi->rotvel.z));
1079 // instant whack on the velocity
1080 // reduce damping on all axes
1081 pi->flags |= PF_REDUCED_DAMP;
1082 update_reduced_damp_timestamp( pi, vm_vec_mag(impulse) );
1084 // find time for shake from weapon to end
1085 int dtime = timestamp_until(pi->afterburner_decay);
1086 if (dtime < WEAPON_SHAKE_TIME) {
1087 pi->afterburner_decay = timestamp( WEAPON_SHAKE_TIME );
1090 vm_vec_scale_add2( &pi->vel, impulse, 1.0f / pi->mass );
1091 if (!(pi->flags & PF_USE_VEL) && (vm_vec_mag_squared(&pi->vel) > MAX_SHIP_SPEED*MAX_SHIP_SPEED)) {
1093 nprintf(("Physics", "speed reset in physics_apply_whack [speed: %f]\n", vm_vec_mag(&pi->vel)));
1095 vm_vec_normalize(&pi->vel);
1096 vm_vec_scale(&pi->vel, (float)RESET_SHIP_SPEED);
1098 vm_vec_rotate( &pi->prev_ramp_vel, &pi->vel, orient ); // set so velocity will ramp starting from current speed
1099 // ramped velocity is now affected by collision
1102 // function generates a velocity ramp with a given time constant independent of frame rate
1103 // uses an exponential approach to desired velocity and a cheat when close to improve closure speed
1104 float velocity_ramp (float v_in, float v_goal, float ramp_time_const, float t)
1110 // JAS: If no time elapsed, change nothing
1114 delta_v = v_goal - v_in;
1115 dist = (float)fl_abs(delta_v);
1117 // hack to speed up closure when close to goal
1118 if (dist < ramp_time_const/3)
1119 ramp_time_const = dist / 3;
1121 // Rather than get a divide by zero, just go to the goal
1122 if ( ramp_time_const < 0.0001f ) {
1126 // determine decay factor (ranges from 0 for short times to 1 for long times)
1127 // when decay factor is near 0, the velocity in nearly unchanged
1128 // when decay factor in near 1, the velocity approaches goal
1129 decay_factor = (float)exp(- t / ramp_time_const);
1131 return (v_in + delta_v * (1.0f - decay_factor) );
1135 // ----------------------------------------------------------------------------
1136 // physics_apply_shock applies applies a shockwave to an object. This causes a velocity impulse and
1137 // and a rotational impulse. This is different than physics_apply_whack since a shock wave is a pressure
1138 // wave which acts over the *surface* of the object, not a point.
1140 // inputs: direction_vec => a position vector whose direction is from the center of the shock wave to the object
1141 // pressure => the pressure of the shock wave at the object
1142 // pi => physics_info structure
1143 // orient => matrix orientation of the object
1144 // min => vector of minimum values of the bounding box
1145 // max => vector of maximum values of the bounding box
1146 // radius => bounding box radius of the object, used for scaling rotation
1148 // outputs: makes changes to physics_info structure rotvel and vel variables
1150 #define STD_PRESSURE 1000 // amplitude of standard shockwave blasts
1151 #define MIN_RADIUS 10 // radius within which full rotvel and shake applied
1152 #define MAX_RADIUS 50 // radius at which no rotvel or shake applied
1153 #define MAX_ROTVEL 0.4 // max rotational velocity
1154 #define MAX_SHAKE 0.1 // max rotational amplitude of shake
1155 #define MAX_VEL 8 // max vel from shockwave
1156 void physics_apply_shock(vector *direction_vec, float pressure, physics_info *pi, matrix *orient, vector *min, vector *max, float radius)
1159 vector local_torque, temp_torque, torque;
1164 if (radius > MAX_RADIUS) {
1168 vm_vec_normalize_safe ( direction_vec );
1170 area.x = (max->y - min->z) * (max->z - min->z);
1171 area.y = (max->x - min->x) * (max->z - min->z);
1172 area.z = (max->x - min->x) * (max->y - min->y);
1174 normal.x = vm_vec_dotprod( direction_vec, &orient->rvec );
1175 normal.y = vm_vec_dotprod( direction_vec, &orient->uvec );
1176 normal.z = vm_vec_dotprod( direction_vec, &orient->fvec );
1178 sin.x = fl_sqrt( fl_abs(1.0f - normal.x*normal.x) );
1179 sin.y = fl_sqrt( fl_abs(1.0f - normal.y*normal.y) );
1180 sin.z = fl_sqrt( fl_abs(1.0f - normal.z*normal.z) );
1182 vm_vec_make( &torque, 0.0f, 0.0f, 0.0f );
1184 // find the torque exerted due to the shockwave hitting each face
1185 // model the effect of the shockwave as if the shockwave were a plane of projectiles,
1186 // all moving in the direction direction_vec. then find the torque as the cross prod
1187 // of the force (pressure * area * normal * sin * scale * mass)
1188 // normal takes account the fraction of the surface exposed to the shockwave
1189 // the sin term is not technically needed but "feels" better
1190 // scale factors out the increase in area with larger objects
1191 // more massive objects get less rotation
1193 // find torque due to forces on the right/left face
1194 if ( normal.x < 0.0f ) // normal < 0, hits the right face
1195 vm_vec_copy_scale( &impact_vec, &orient->rvec, max->x * pressure * area.x * normal.x * sin.x / pi->mass );
1196 else // normal > 0, hits the left face
1197 vm_vec_copy_scale( &impact_vec, &orient->rvec, min->x * pressure * area.x * -normal.x * sin.x / pi->mass );
1199 vm_vec_crossprod( &temp_torque, &impact_vec, direction_vec );
1200 vm_vec_add2( &torque, &temp_torque );
1202 // find torque due to forces on the up/down face
1203 if ( normal.y < 0.0f )
1204 vm_vec_copy_scale( &impact_vec, &orient->uvec, max->y * pressure * area.y * normal.y * sin.y / pi->mass );
1206 vm_vec_copy_scale( &impact_vec, &orient->uvec, min->y * pressure * area.y * -normal.y * sin.y / pi->mass );
1208 vm_vec_crossprod( &temp_torque, &impact_vec, direction_vec );
1209 vm_vec_add2( &torque, &temp_torque );
1211 // find torque due to forces on the forward/backward face
1212 if ( normal.z < 0.0f )
1213 vm_vec_copy_scale( &impact_vec, &orient->fvec, max->z * pressure * area.z * normal.z * sin.z / pi->mass );
1215 vm_vec_copy_scale( &impact_vec, &orient->fvec, min->z * pressure * area.z * -normal.z * sin.z / pi->mass );
1217 vm_vec_crossprod( &temp_torque, &impact_vec, direction_vec );
1218 vm_vec_add2( &torque, &temp_torque );
1220 // compute delta rotvel, scale according to blast and radius
1222 vector delta_rotvel;
1223 vm_vec_rotate( &local_torque, &torque, orient );
1224 vm_vec_copy_normalize(&delta_rotvel, &local_torque);
1225 if (radius < MIN_RADIUS) {
1228 scale = (MAX_RADIUS - radius)/(MAX_RADIUS-MIN_RADIUS);
1230 vm_vec_scale(&delta_rotvel, (float)(MAX_ROTVEL*(pressure/STD_PRESSURE)*scale));
1231 // nprintf(("Physics", "rotvel scale %f\n", (MAX_ROTVEL*(pressure/STD_PRESSURE)*scale)));
1232 vm_vec_add2(&pi->rotvel, &delta_rotvel);
1234 // set shockwave shake amplitude, duration, flag
1235 pi->shockwave_shake_amp = (float)(MAX_SHAKE*(pressure/STD_PRESSURE)*scale);
1236 pi->shockwave_decay = timestamp( SW_BLAST_DURATION );
1237 pi->flags |= PF_IN_SHOCKWAVE;
1239 // set reduced translational damping, set flags
1240 float velocity_scale = (float)MAX_VEL*scale;
1241 pi->flags |= PF_REDUCED_DAMP;
1242 update_reduced_damp_timestamp( pi, velocity_scale*pi->mass );
1243 vm_vec_scale_add2( &pi->vel, direction_vec, velocity_scale );
1244 vm_vec_rotate(&pi->prev_ramp_vel, &pi->vel, orient); // set so velocity will ramp starting from current speed
1246 // check that kick from shockwave is not too large
1247 if (!(pi->flags & PF_USE_VEL) && (vm_vec_mag_squared(&pi->vel) > MAX_SHIP_SPEED*MAX_SHIP_SPEED)) {
1249 nprintf(("Physics", "speed reset in physics_apply_shock [speed: %f]\n", vm_vec_mag(&pi->vel)));
1251 vm_vec_normalize(&pi->vel);
1252 vm_vec_scale(&pi->vel, (float)RESET_SHIP_SPEED);
1256 if (check_rotvel_limit( pi )) {
1257 nprintf(("Physics", "rotvel reset in physics_apply_shock\n"));
1261 // ramped velocity is now affected by collision
1264 // ----------------------------------------------------------------------------
1265 // physics_collide_whack applies an instaneous whack on an object changing
1266 // both the objects velocity and the rotational velocity based on the impulse
1269 // input: impulse => impulse vector ( force*time = impulse = change in momentum (mv) )
1270 // world_delta_rotvel => change in rotational velocity (already calculated)
1271 // pi => pointer to phys_info struct of object getting whacked
1272 // orient => orientation matrix (needed to set rotational impulse in body coords)
1275 // Warning: Do not change ROTVEL_COLLIDE_WHACK_CONST. This will mess up collision physics.
1276 // If you need to change the rotation, change COLLISION_ROTATION_FACTOR in collide_ship_ship.
1277 #define ROTVEL_COLLIDE_WHACK_CONST 1.0
1278 void physics_collide_whack( vector *impulse, vector *world_delta_rotvel, physics_info *pi, matrix *orient )
1280 vector body_delta_rotvel;
1282 // Detect null vector.
1283 if ((fl_abs(impulse->x) <= WHACK_LIMIT) && (fl_abs(impulse->y) <= WHACK_LIMIT) && (fl_abs(impulse->z) <= WHACK_LIMIT))
1286 vm_vec_rotate( &body_delta_rotvel, world_delta_rotvel, orient );
1287 // vm_vec_scale( &body_delta_rotvel, (float) ROTVEL_COLLIDE_WHACK_CONST );
1288 vm_vec_add2( &pi->rotvel, &body_delta_rotvel );
1291 if (check_rotvel_limit( pi )) {
1292 nprintf(("Physics", "rotvel reset in physics_collide_whack\n"));
1296 update_reduced_damp_timestamp( pi, vm_vec_mag(impulse) );
1298 // find time for shake from weapon to end
1299 int dtime = timestamp_until(pi->afterburner_decay);
1300 if (dtime < WEAPON_SHAKE_TIME) {
1301 pi->afterburner_decay = timestamp( WEAPON_SHAKE_TIME );
1304 pi->flags |= PF_REDUCED_DAMP;
1305 vm_vec_scale_add2( &pi->vel, impulse, 1.0f / pi->mass );
1306 // check that collision does not give ship too much speed
1307 // reset if too high
1308 if (!(pi->flags & PF_USE_VEL) && (vm_vec_mag_squared(&pi->vel) > MAX_SHIP_SPEED*MAX_SHIP_SPEED)) {
1310 nprintf(("Physics", "speed reset in physics_collide_whack [speed: %f]\n", vm_vec_mag(&pi->vel)));
1312 vm_vec_normalize(&pi->vel);
1313 vm_vec_scale(&pi->vel, (float)RESET_SHIP_SPEED);
1315 vm_vec_rotate( &pi->prev_ramp_vel, &pi->vel, orient ); // set so velocity will ramp starting from current speed
1316 // ramped velocity is now affected by collision
1317 // rotate previous ramp velocity (in model coord) to be same as vel (in world coords)
1321 int check_rotvel_limit( physics_info *pi )
1323 if ( 0 == pi->flags ) // weapon
1329 int change_made = 0;
1330 if ( !(pi->flags & PF_DEAD_DAMP) ) {
1331 // case of normal, live ship
1332 // -- Commented out by MK: Assert( vm_vec_mag_squared(&pi->max_rotvel) > ROTVEL_TOL );
1333 // Assert( (pi->max_rotvel.x <= ROTVEL_CAP) && (pi->max_rotvel.y <= ROTVEL_CAP) && (pi->max_rotvel.z <= ROTVEL_CAP) );
1334 // Warning(LOCATION,"Excessive rotvel (wx: %f, wy: %f, wz:%f)\n", pi->rotvel.x, pi->rotvel.y, pi->rotvel.z);
1335 if ( fl_abs(pi->rotvel.x) > pi->max_rotvel.x ) {
1336 pi->rotvel.x = (pi->rotvel.x / fl_abs(pi->rotvel.x)) * (pi->max_rotvel.x - (float) ROTVEL_TOL);
1339 if ( fl_abs(pi->rotvel.y) > pi->max_rotvel.y ) {
1340 pi->rotvel.y = (pi->rotvel.y / fl_abs(pi->rotvel.y)) * (pi->max_rotvel.y - (float) ROTVEL_TOL);
1343 if ( fl_abs(pi->rotvel.z) > pi->max_rotvel.z ) {
1344 pi->rotvel.z = (pi->rotvel.z / fl_abs(pi->rotvel.z)) * (pi->max_rotvel.z - (float) ROTVEL_TOL);
1348 // case of dead ship
1349 if ( fl_abs(pi->rotvel.x) > DEAD_ROTVEL_CAP ) {
1350 pi->rotvel.x = (pi->rotvel.x / fl_abs(pi->rotvel.x)) * (float) (DEAD_ROTVEL_CAP - ROTVEL_TOL);
1353 if ( fl_abs(pi->rotvel.y) > DEAD_ROTVEL_CAP ) {
1354 pi->rotvel.y = (pi->rotvel.y / fl_abs(pi->rotvel.y)) * (float) (DEAD_ROTVEL_CAP - ROTVEL_TOL);
1357 if ( fl_abs(pi->rotvel.z) > DEAD_ROTVEL_CAP ) {
1358 pi->rotvel.z = (pi->rotvel.z / fl_abs(pi->rotvel.z)) * (float) (DEAD_ROTVEL_CAP - ROTVEL_TOL);
1365 // ----------------------------------------------------------------------------
1366 // update_reduced_damp_timestamp()
1368 void update_reduced_damp_timestamp( physics_info *pi, float impulse )
1371 // Compute duration of reduced damp from present
1372 // Compare with current value and increase if greater, otherwise ignore
1373 int reduced_damp_decay_time;
1374 reduced_damp_decay_time = (int) (REDUCED_DAMP_TIME * impulse / (REDUCED_DAMP_VEL * pi->mass));
1375 if ( reduced_damp_decay_time > REDUCED_DAMP_TIME )
1376 reduced_damp_decay_time = REDUCED_DAMP_TIME;
1378 // Reset timestamp if larger than current (if any)
1379 if ( timestamp_valid( pi->reduced_damp_decay ) ) {
1380 int time_left = timestamp_until( pi->reduced_damp_decay );
1381 if ( time_left > 0 ) {
1382 // increment old time, but apply cap
1383 int new_time = reduced_damp_decay_time + time_left;
1384 if ( new_time < REDUCED_DAMP_TIME ) {
1385 pi->reduced_damp_decay = timestamp( new_time );
1388 pi->reduced_damp_decay = timestamp( reduced_damp_decay_time );
1392 pi->reduced_damp_decay = timestamp( reduced_damp_decay_time );