]> icculus.org git repositories - btb/d2x.git/blob - main/physics.c
remove some redundancy by not needing to do SoundSlots[i].playing = 0; in addition...
[btb/d2x.git] / main / physics.c
1 /* $Id: physics.c,v 1.6 2004-05-22 01:06:25 btb Exp $ */
2 /*
3 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
4 SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
5 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
6 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
7 IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
8 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
9 FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
10 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
11 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
12 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
13 */
14
15 /*
16  *
17  * Code for flying through the mines
18  *
19  * Old Log:
20  * Revision 1.5  1995/10/12  17:28:08  allender
21  * put in code to move and object to center of segment in
22  * do_physics sim when fvi fails with bad point
23  *
24  * Revision 1.4  1995/08/23  21:32:44  allender
25  * fix mcc compiler warnings
26  *
27  * Revision 1.3  1995/07/28  15:38:56  allender
28  * removed isqrt thing -- not required here
29  *
30  * Revision 1.2  1995/07/28  15:13:29  allender
31  * fixed vector magnitude thing
32  *
33  * Revision 1.1  1995/05/16  15:29:42  allender
34  * Initial revision
35  *
36  * Revision 2.2  1995/03/24  14:48:54  john
37  * Added cheat for player to go thru walls.
38  *
39  * Revision 2.1  1995/03/20  18:15:59  john
40  * Added code to not store the normals in the segment structure.
41  *
42  * Revision 2.0  1995/02/27  11:32:06  john
43  * New version 2.0, which has no anonymous unions, builds with
44  * Watcom 10.0, and doesn't require parsing BITMAPS.TBL.
45  *
46  * Revision 1.213  1995/02/22  13:40:48  allender
47  * remove anonymous unions from object structure
48  *
49  * Revision 1.212  1995/02/22  13:24:42  john
50  * Removed the vecmat anonymous unions.
51  *
52  * Revision 1.211  1995/02/06  19:46:59  matt
53  * New function (untested), set_thrust_from_velocity()
54  *
55  * Revision 1.210  1995/02/02  16:26:12  matt
56  * Changed assert that was causing a problem
57  *
58  * Revision 1.209  1995/02/02  14:07:00  matt
59  * Fixed confusion about which segment you are touching when you're
60  * touching a wall.  This manifested itself in spurious lava burns.
61  *
62  * Revision 1.208  1995/02/01  21:03:24  john
63  * Lintified.
64  *
65  * Revision 1.207  1995/01/25  13:53:35  rob
66  * Removed an Int3 from multiplayer games.
67  *
68  * Revision 1.206  1995/01/23  17:30:47  rob
69  * Removed Int3 on bogus sim time.
70  *
71  * Revision 1.205  1995/01/17  11:08:56  matt
72  * Disable new-ish FVI edge checking for all objects except the player,
73  * since it was causing problems with the fusion cannon.
74  *
75  * Revision 1.204  1995/01/05  09:43:49  matt
76  * Took out int3s from new code
77  *
78  * Revision 1.203  1995/01/04  22:19:23  matt
79  * Added hack to keep player from squeezing through closed walls/doors
80  *
81  * Revision 1.202  1995/01/02  12:38:48  mike
82  * physics hack to crazy josh not get hung up on proximity bombs.  Matt notified via email.
83  *
84  * Revision 1.201  1994/12/13  15:39:22  mike
85  * #ifndef NDEBUG some code.
86  *
87  * Revision 1.200  1994/12/13  13:28:34  yuan
88  * Fixed type.
89  *
90  * Revision 1.199  1994/12/13  13:25:00  matt
91  * Made bump hack compile out if so desired
92  *
93  * Revision 1.198  1994/12/13  12:02:39  matt
94  * Added hack to bump player a little if stuck
95  *
96  * Revision 1.197  1994/12/12  00:32:23  matt
97  * When objects other than player go out of mine, jerk to center of segment
98  *
99  * Revision 1.196  1994/12/10  22:52:42  mike
100  * make physics left-the-mine checking always be in.
101  *
102  * Revision 1.195  1994/12/08  00:53:01  mike
103  * oops...phys rot bug.
104  *
105  * Revision 1.194  1994/12/07  12:54:54  mike
106  * tweak rotvel applied from collisions.
107  *
108  * Revision 1.193  1994/12/07  00:36:08  mike
109  * fix phys_apply_rot for robots -- ai was bashing effect in next frame.
110  *
111  * Revision 1.192  1994/12/05  17:23:10  matt
112  * Made a bunch of debug code compile out
113  *
114  * Revision 1.191  1994/12/05  16:30:10  matt
115  * Was illegally changing an object's segment...shoot me.
116  *
117  * Revision 1.190  1994/12/05  11:58:51  mike
118  * fix stupid apply_force_rot() bug.
119  *
120  * Revision 1.189  1994/12/05  09:42:17  mike
121  * fix 0 mag problem when object applies force to itself.
122  *
123  * Revision 1.188  1994/12/04  22:48:40  matt
124  * Physics & FVI now only build seglist for player objects, and they
125  * responsilby deal with buffer full conditions
126  *
127  * Revision 1.187  1994/12/04  22:14:07  mike
128  * apply instantaneous rotation to an object due to a force blow.
129  *
130  * Revision 1.186  1994/12/04  18:51:30  matt
131  * When weapons get stuck, delete them!
132  *
133  * Revision 1.185  1994/12/04  18:38:56  matt
134  * Added better handling of point-not-in-seg problem
135  *
136  * Revision 1.184  1994/11/27  23:13:42  matt
137  * Made changes for new mprintf calling convention
138  *
139  * Revision 1.183  1994/11/25  23:46:18  matt
140  * Fixed drag problems with framerates over 60Hz
141  *
142  * Revision 1.182  1994/11/25  22:15:52  matt
143  * Added asserts to try to trap frametime < 0 bug
144  *
145  * Revision 1.181  1994/11/21  11:42:44  mike
146  * ndebug stuff.
147  *
148  * Revision 1.180  1994/11/19  15:15:04  mike
149  * remove unused code and data
150  *
151  * Revision 1.179  1994/11/16  11:25:22  matt
152  * Abort physics if negative frametime
153  *
154  * Revision 1.178  1994/10/05  19:50:41  rob
155  * Removed a non-critical Int3 where an object's segnum is checked.
156  * Left mprintf message.
157  *
158  * Revision 1.177  1994/10/03  22:57:50  matt
159  * Fixed problem with matrix corruption of non-moving (but rotating) objects
160  *
161  * Revision 1.176  1994/09/28  09:23:28  mike
162  * Add useful information to mprintf(1,... error messages.
163  *
164  * Revision 1.175  1994/09/21  17:16:54  mike
165  * Make objects stuck in doors go away when door opens.
166  *
167  * Revision 1.174  1994/09/12  14:19:06  matt
168  * Drag & thrust now handled differently
169  *
170  * Revision 1.173  1994/09/09  14:21:12  matt
171  * Use new thrust flag
172  *
173  * Revision 1.172  1994/09/08  16:21:57  matt
174  * Cleaned up player-hit-wall code, and added object scrape handling
175  * Also added weapon-on-weapon hit sound
176  *
177  * Revision 1.171  1994/09/02  12:30:37  matt
178  * Fixed weapons which go through objects
179  *
180  * Revision 1.170  1994/09/02  11:55:14  mike
181  * Kill redefinition of a constant which is properly defined in object.h
182  *
183  * Revision 1.169  1994/09/02  11:35:01  matt
184  * Fixed typo
185  *
186  * Revision 1.168  1994/09/02  11:32:48  matt
187  * Fixed object/object collisions, so you can't fly through robots anymore.
188  * Cleaned up object damage system.
189  *
190  * Revision 1.167  1994/08/30  21:58:15  matt
191  * Made phys_apply_force() do nothing to an object if it's not a phys object
192  *
193  * Revision 1.166  1994/08/26  10:47:01  john
194  * New version of controls.
195  *
196  * Revision 1.165  1994/08/25  21:53:57  mike
197  * Prevent counts of -1 which eventually add up to a positive number in do_ai_frame, causing
198  * the too-many-retries behavior.
199  *
200  * Revision 1.164  1994/08/25  18:43:33  john
201  * First revision of new control code.
202  *
203  * Revision 1.163  1994/08/17  22:18:05  mike
204  * Make robots which have rotvel or rotthrust, but not movement, move.
205  *
206  * Revision 1.162  1994/08/13  17:31:18  mike
207  * retry count stuff.
208  *
209  * Revision 1.161  1994/08/11  18:59:16  mike
210  * *** empty log message ***
211  *
212  * Revision 1.160  1994/08/10  19:53:47  mike
213  * Debug code (which is still in...)
214  * and adapt to changed interface to create_path_to_player.
215  *
216  * Revision 1.159  1994/08/08  21:38:43  matt
217  * Cleaned up a code a little and optimized a little
218  *
219  * Revision 1.158  1994/08/08  15:21:50  mike
220  * Trap retry count >= 4, but don't do AI hack unless >= 6.
221  *
222  * Revision 1.157  1994/08/08  11:47:15  matt
223  * Cleaned up fvi and physics a little
224  *
225  * Revision 1.156  1994/08/05  10:10:10  yuan
226  * Commented out debug stuff that was killing framerate.
227  *
228  * Revision 1.155  1994/08/04  19:12:36  matt
229  * Changed a bunch of vecmat calls to use multiple-function routines, and to
230  * allow the use of C macros for some functions
231  *
232  * Revision 1.154  1994/08/04  16:33:57  mike
233  * Kill a pile of RCS stuff.
234  * Call create_path_to_player for a stuck object.
235  *
236  * Revision 1.153  1994/08/04  00:21:02  matt
237  * Cleaned up fvi & physics error handling; put in code to make sure objects
238  * are in correct segment; simplified segment finding for objects and points
239  *
240  * Revision 1.152  1994/08/01  16:25:34  matt
241  * Check for moved_time == 0 when computing hit speed
242  *
243  * Revision 1.151  1994/08/01  13:30:32  matt
244  * Made fvi() check holes in transparent walls, and changed fvi() calling
245  * parms to take all input data in query structure.
246  *
247  * Revision 1.150  1994/07/29  23:41:46  matt
248  * Fixed turn banking, which changed when I added rotational velocity
249  *
250  * Revision 1.149  1994/07/27  20:53:23  matt
251  * Added rotational drag & thrust, so turning now has momemtum like moving
252  *
253  */
254
255
256 #ifdef HAVE_CONFIG_H
257 #include <conf.h>
258 #endif
259
260 #ifdef RCS
261 static char rcsid[] = "$Id: physics.c,v 1.6 2004-05-22 01:06:25 btb Exp $";
262 #endif
263
264 #include <stdio.h>
265 #include <stdlib.h>
266
267 #include "joy.h"
268 #include "mono.h"
269 #include "error.h"
270
271 #include "inferno.h"
272 #include "segment.h"
273 #include "object.h"
274 #include "physics.h"
275 #include "key.h"
276 #include "game.h"
277 #include "collide.h"
278 #include "fvi.h"
279 #include "newdemo.h"
280 #include "timer.h"
281 #include "ai.h"
282 #include "wall.h"
283 #include "laser.h"
284 #include "bm.h"
285 #include "player.h"
286
287 #ifdef TACTILE
288 #include "tactile.h"
289 #endif
290
291 //Global variables for physics system
292
293 #define ROLL_RATE               0x2000
294 #define DAMP_ANG                        0x400                  //min angle to bank
295
296 #define TURNROLL_SCALE  (0x4ec4/2)
297
298 #define MAX_OBJECT_VEL i2f(100)
299
300 #define BUMP_HACK       1               //if defined, bump player when he gets stuck
301
302 //--unused-- int mike_mode=0;
303
304 //check point against each side of segment. return bitmask, where bit
305 //set means behind that side
306
307 int Physics_cheat_flag = 0;
308 extern char BounceCheat;
309
310 //##//returns the distance of a point (checkp) from a plane (defined by norm & planep)
311 //##fix dist_to_plane(vms_vector *checkp,vms_vector *norm,vms_vector *planep)
312 //##{
313 //##    vms_vector deltap;
314 //##
315 //##    vm_vec_sub(&deltap,checkp,planep);
316 //##
317 //##    return vm_vec_dot(&deltap,norm);
318 //##}
319
320 //--unused-- int dpjm_old_joy_x, dpjm_old_joy_y;
321
322 int floor_levelling=0;
323
324 //--unused-- level_with_floor()
325 //--unused-- {
326 //--unused--    floor_levelling=1;
327 //--unused-- }
328
329 //make sure matrix is orthogonal
330 void check_and_fix_matrix(vms_matrix *m)
331 {
332         vms_matrix tempm;
333
334         vm_vector_2_matrix(&tempm,&m->fvec,&m->uvec,NULL);
335         *m  = tempm;
336 }
337
338
339 void do_physics_align_object( object * obj )
340 {
341         vms_vector desired_upvec;
342         fixang delta_ang,roll_ang;
343         //vms_vector forvec = {0,0,f1_0};
344         vms_matrix temp_matrix;
345         fix d,largest_d=-f1_0;
346         int i,best_side;
347
348         best_side=0;
349         // bank player according to segment orientation
350
351         //find side of segment that player is most alligned with
352
353         for (i=0;i<6;i++) {
354                 #ifdef COMPACT_SEGS
355                         vms_vector _tv1;
356                         get_side_normal( &Segments[obj->segnum], i, 0, &_tv1 );
357                         d = vm_vec_dot(&_tv1,&obj->orient.uvec);
358                 #else                                   
359                         d = vm_vec_dot(&Segments[obj->segnum].sides[i].normals[0],&obj->orient.uvec);
360                 #endif
361
362                 if (d > largest_d) {largest_d = d; best_side=i;}
363         }
364
365         if (floor_levelling) {
366
367                 // old way: used floor's normal as upvec
368                 #ifdef COMPACT_SEGS
369                         get_side_normal(&Segments[obj->segnum], 3, 0, &desired_upvec );                 
370                 #else
371                         desired_upvec = Segments[obj->segnum].sides[3].normals[0];
372                 #endif
373
374         }
375         else  // new player leveling code: use normal of side closest to our up vec
376                 if (get_num_faces(&Segments[obj->segnum].sides[best_side])==2) {
377                         #ifdef COMPACT_SEGS
378                                 vms_vector normals[2];
379                                 get_side_normals(&Segments[obj->segnum], best_side, &normals[0], &normals[1] );                 
380
381                                 desired_upvec.x = (normals[0].x + normals[1].x) / 2;
382                                 desired_upvec.y = (normals[0].y + normals[1].y) / 2;
383                                 desired_upvec.z = (normals[0].z + normals[1].z) / 2;
384
385                                 vm_vec_normalize(&desired_upvec);
386                         #else
387                                 side *s = &Segments[obj->segnum].sides[best_side];
388                                 desired_upvec.x = (s->normals[0].x + s->normals[1].x) / 2;
389                                 desired_upvec.y = (s->normals[0].y + s->normals[1].y) / 2;
390                                 desired_upvec.z = (s->normals[0].z + s->normals[1].z) / 2;
391                 
392                                 vm_vec_normalize(&desired_upvec);
393                         #endif
394                 }
395                 else
396                         #ifdef COMPACT_SEGS
397                                 get_side_normal(&Segments[obj->segnum], best_side, 0, &desired_upvec );                 
398                         #else
399                                 desired_upvec = Segments[obj->segnum].sides[best_side].normals[0];
400                         #endif
401
402         if (labs(vm_vec_dot(&desired_upvec,&obj->orient.fvec)) < f1_0/2) {
403                 fixang save_delta_ang;
404                 vms_angvec tangles;
405                 
406                 vm_vector_2_matrix(&temp_matrix,&obj->orient.fvec,&desired_upvec,NULL);
407
408                 save_delta_ang = delta_ang = vm_vec_delta_ang(&obj->orient.uvec,&temp_matrix.uvec,&obj->orient.fvec);
409
410                 delta_ang += obj->mtype.phys_info.turnroll;
411
412                 if (abs(delta_ang) > DAMP_ANG) {
413                         vms_matrix rotmat, new_pm;
414
415                         roll_ang = fixmul(FrameTime,ROLL_RATE);
416
417                         if (abs(delta_ang) < roll_ang) roll_ang = delta_ang;
418                         else if (delta_ang<0) roll_ang = -roll_ang;
419
420                         tangles.p = tangles.h = 0;  tangles.b = roll_ang;
421                         vm_angles_2_matrix(&rotmat,&tangles);
422
423                         vm_matrix_x_matrix(&new_pm,&obj->orient,&rotmat);
424                         obj->orient = new_pm;
425                 }
426                 else floor_levelling=0;
427         }
428
429 }
430
431 void set_object_turnroll(object *obj)
432 {
433         fixang desired_bank;
434
435         desired_bank = -fixmul(obj->mtype.phys_info.rotvel.y,TURNROLL_SCALE);
436
437         if (obj->mtype.phys_info.turnroll != desired_bank) {
438                 fixang delta_ang,max_roll;
439
440                 max_roll = fixmul(ROLL_RATE,FrameTime);
441
442                 delta_ang = desired_bank - obj->mtype.phys_info.turnroll;
443
444                 if (labs(delta_ang) < max_roll)
445                         max_roll = delta_ang;
446                 else
447                         if (delta_ang < 0)
448                                 max_roll = -max_roll;
449
450                 obj->mtype.phys_info.turnroll += max_roll;
451         }
452
453 }
454
455 //list of segments went through
456 int phys_seglist[MAX_FVI_SEGS],n_phys_segs;
457
458
459 #define MAX_IGNORE_OBJS 100
460
461 #ifndef NDEBUG
462 #define EXTRA_DEBUG 1           //no extra debug when NDEBUG is on
463 #endif
464
465 #ifdef EXTRA_DEBUG
466 object *debug_obj=NULL;
467 #endif
468
469 #define XYZ(v) (v)->x,(v)->y,(v)->z
470
471
472 #ifndef NDEBUG
473 int     Total_retries=0, Total_sims=0;
474 int     Dont_move_ai_objects=0;
475 #endif
476
477 #define FT (f1_0/64)
478
479 extern int disable_new_fvi_stuff;
480 //      -----------------------------------------------------------------------------------------------------------
481 // add rotational velocity & acceleration
482 void do_physics_sim_rot(object *obj)
483 {
484         vms_angvec      tangles;
485         vms_matrix      rotmat,new_orient;
486         //fix                   rotdrag_scale;
487         physics_info *pi;
488
489         Assert(FrameTime > 0);  //Get MATT if hit this!
490
491         pi = &obj->mtype.phys_info;
492
493         if (!(pi->rotvel.x || pi->rotvel.y || pi->rotvel.z || pi->rotthrust.x || pi->rotthrust.y || pi->rotthrust.z))
494                 return;
495
496         if (obj->mtype.phys_info.drag) {
497                 int count;
498                 vms_vector accel;
499                 fix drag,r,k;
500
501                 count = FrameTime / FT;
502                 r = FrameTime % FT;
503                 k = fixdiv(r,FT);
504
505                 drag = (obj->mtype.phys_info.drag*5)/2;
506
507                 if (obj->mtype.phys_info.flags & PF_USES_THRUST) {
508
509                         vm_vec_copy_scale(&accel,&obj->mtype.phys_info.rotthrust,fixdiv(f1_0,obj->mtype.phys_info.mass));
510
511                         while (count--) {
512
513                                 vm_vec_add2(&obj->mtype.phys_info.rotvel,&accel);
514
515                                 vm_vec_scale(&obj->mtype.phys_info.rotvel,f1_0-drag);
516                         }
517
518                         //do linear scale on remaining bit of time
519
520                         vm_vec_scale_add2(&obj->mtype.phys_info.rotvel,&accel,k);
521                         vm_vec_scale(&obj->mtype.phys_info.rotvel,f1_0-fixmul(k,drag));
522                 }
523                 else if (! (obj->mtype.phys_info.flags & PF_FREE_SPINNING)) {
524                         fix total_drag=f1_0;
525
526                         while (count--)
527                                 total_drag = fixmul(total_drag,f1_0-drag);
528
529                         //do linear scale on remaining bit of time
530
531                         total_drag = fixmul(total_drag,f1_0-fixmul(k,drag));
532
533                         vm_vec_scale(&obj->mtype.phys_info.rotvel,total_drag);
534                 }
535
536         }
537
538         //mprintf( (0, "Rot vel = %.3f,%.3f,%.3f\n", f2fl(obj->mtype.phys_info.rotvel.x),f2fl(obj->mtype.phys_info.rotvel.y), f2fl(obj->mtype.phys_info.rotvel.z) ));
539
540         //now rotate object
541
542         //unrotate object for bank caused by turn
543         if (obj->mtype.phys_info.turnroll) {
544                 vms_matrix new_pm;
545
546                 tangles.p = tangles.h = 0;
547                 tangles.b = -obj->mtype.phys_info.turnroll;
548                 vm_angles_2_matrix(&rotmat,&tangles);
549                 vm_matrix_x_matrix(&new_pm,&obj->orient,&rotmat);
550                 obj->orient = new_pm;
551         }
552
553         tangles.p = fixmul(obj->mtype.phys_info.rotvel.x,FrameTime);
554         tangles.h = fixmul(obj->mtype.phys_info.rotvel.y,FrameTime);
555         tangles.b  = fixmul(obj->mtype.phys_info.rotvel.z,FrameTime);
556
557         vm_angles_2_matrix(&rotmat,&tangles);
558         vm_matrix_x_matrix(&new_orient,&obj->orient,&rotmat);
559         obj->orient = new_orient;
560
561         if (obj->mtype.phys_info.flags & PF_TURNROLL)
562                 set_object_turnroll(obj);
563
564         //re-rotate object for bank caused by turn
565         if (obj->mtype.phys_info.turnroll) {
566                 vms_matrix new_pm;
567
568                 tangles.p = tangles.h = 0;
569                 tangles.b = obj->mtype.phys_info.turnroll;
570                 vm_angles_2_matrix(&rotmat,&tangles);
571                 vm_matrix_x_matrix(&new_pm,&obj->orient,&rotmat);
572                 obj->orient = new_pm;
573         }
574
575         check_and_fix_matrix(&obj->orient);
576 }
577
578 //      -----------------------------------------------------------------------------------------------------------
579 //Simulate a physics object for this frame
580 void do_physics_sim(object *obj)
581 {
582         int ignore_obj_list[MAX_IGNORE_OBJS],n_ignore_objs;
583         int iseg;
584         int try_again;
585         int fate;
586         vms_vector frame_vec;                   //movement in this frame
587         vms_vector new_pos,ipos;                //position after this frame
588         int count=0;
589         int objnum;
590         int WallHitSeg, WallHitSide;
591         fvi_info hit_info;
592         fvi_query fq;
593         vms_vector save_pos;
594         int save_seg;
595         fix drag;
596         fix sim_time,old_sim_time;
597         vms_vector start_pos;
598         int obj_stopped=0;
599         fix moved_time;                 //how long objected moved before hit something
600         vms_vector save_p0,save_p1;
601         physics_info *pi;
602         int orig_segnum = obj->segnum;
603         int bounced=0;
604
605         Assert(obj->type != OBJ_NONE);
606         Assert(obj->movement_type == MT_PHYSICS);
607
608 #ifndef NDEBUG
609 if (Dont_move_ai_objects)
610         if (obj->control_type == CT_AI)
611                 return;
612 #endif
613
614         pi = &obj->mtype.phys_info;
615
616         do_physics_sim_rot(obj);
617
618         if (!(pi->velocity.x || pi->velocity.y || pi->velocity.z || pi->thrust.x || pi->thrust.y || pi->thrust.z))
619                 return;
620
621         objnum = obj-Objects;
622
623         n_phys_segs = 0;
624
625         disable_new_fvi_stuff = (obj->type != OBJ_PLAYER);
626
627         sim_time = FrameTime;
628
629 //debug_obj = obj;
630
631         #ifdef EXTRA_DEBUG
632         if (obj == debug_obj) {
633                 printf("object %d:\n  start pos = %x %x %x\n",objnum,XYZ(&obj->pos));
634                 printf("  thrust = %x %x %x\n",XYZ(&obj->mtype.phys_info.thrust));
635                 printf("  sim_time = %x\n",sim_time);
636         }
637
638         //check for correct object segment
639         if(!get_seg_masks(&obj->pos, obj->segnum, 0, __FILE__, __LINE__).centermask == 0)
640         {
641                 #ifndef NDEBUG
642                 mprintf((0,"Warning: object %d not in given seg!\n",objnum));
643                 #endif
644                 //Int3();  Removed by Rob 10/5/94
645                 if (!update_object_seg(obj)) {
646                         #ifndef NDEBUG
647                         mprintf((0,"Warning: can't find seg for object %d - moving\n",objnum));
648                         #endif
649                         if (!(Game_mode & GM_MULTI))
650                                 Int3();
651                         compute_segment_center(&obj->pos,&Segments[obj->segnum]);
652                         obj->pos.x += objnum;
653                 }
654         }
655         #endif
656
657         start_pos = obj->pos;
658
659         n_ignore_objs = 0;
660
661         Assert(obj->mtype.phys_info.brakes==0);         //brakes not used anymore?
662
663                 //if uses thrust, cannot have zero drag
664         Assert(!(obj->mtype.phys_info.flags&PF_USES_THRUST) || obj->mtype.phys_info.drag!=0);
665
666 //mprintf((0,"thrust=%x  speed=%x\n",vm_vec_mag(&obj->mtype.phys_info.thrust),vm_vec_mag(&obj->mtype.phys_info.velocity)));
667
668         //do thrust & drag
669         
670         if ((drag = obj->mtype.phys_info.drag) != 0) {
671
672                 int count;
673                 vms_vector accel;
674                 fix r,k;
675
676                 count = sim_time / FT;
677                 r = sim_time % FT;
678                 k = fixdiv(r,FT);
679
680                 if (obj->mtype.phys_info.flags & PF_USES_THRUST) {
681
682                         vm_vec_copy_scale(&accel,&obj->mtype.phys_info.thrust,fixdiv(f1_0,obj->mtype.phys_info.mass));
683
684                         while (count--) {
685
686                                 vm_vec_add2(&obj->mtype.phys_info.velocity,&accel);
687
688                                 vm_vec_scale(&obj->mtype.phys_info.velocity,f1_0-drag);
689                         }
690
691                         //do linear scale on remaining bit of time
692
693                         vm_vec_scale_add2(&obj->mtype.phys_info.velocity,&accel,k);
694
695                         vm_vec_scale(&obj->mtype.phys_info.velocity,f1_0-fixmul(k,drag));
696                 }
697                 else {
698                         fix total_drag=f1_0;
699
700                         while (count--)
701                                 total_drag = fixmul(total_drag,f1_0-drag);
702
703                         //do linear scale on remaining bit of time
704
705                         total_drag = fixmul(total_drag,f1_0-fixmul(k,drag));
706
707                         vm_vec_scale(&obj->mtype.phys_info.velocity,total_drag);
708                 }
709         }
710
711         #ifdef EXTRA_DEBUG
712         if (obj == debug_obj)
713                 printf("  velocity = %x %x %x\n",XYZ(&obj->mtype.phys_info.velocity));
714         #endif
715
716         do {
717                 try_again = 0;
718
719                 //Move the object
720                 vm_vec_copy_scale(&frame_vec, &obj->mtype.phys_info.velocity, sim_time);
721
722                 #ifdef EXTRA_DEBUG
723                 if (obj == debug_obj)
724                         printf("  pass %d, frame_vec = %x %x %x\n",count,XYZ(&frame_vec));
725                 #endif
726
727                 if ( (frame_vec.x==0) && (frame_vec.y==0) && (frame_vec.z==0) ) 
728                         break;
729
730                 count++;
731
732                 //      If retry count is getting large, then we are trying to do something stupid.
733                 if ( count > 3)         {
734                         if (obj->type == OBJ_PLAYER) {
735                                 if (count > 8)
736                                         break;
737                         } else
738                                 break;
739                 }
740
741                 vm_vec_add(&new_pos,&obj->pos,&frame_vec);
742
743                 #ifdef EXTRA_DEBUG
744                 if (obj == debug_obj)
745                         printf("   desired_pos  = %x %x %x\n",XYZ(&new_pos));
746                 #endif
747
748                 ignore_obj_list[n_ignore_objs] = -1;
749
750                 #ifdef EXTRA_DEBUG
751                 if (obj == debug_obj) {
752                         printf("   FVI parms: p0 = %8x %8x %8x, segnum=%x, size=%x\n",XYZ(&obj->pos),obj->segnum,obj->size);
753                         printf("              p1 = %8x %8x %8x\n",XYZ(&new_pos));
754                 }
755                 #endif
756
757                 fq.p0                                           = &obj->pos;
758                 fq.startseg                             = obj->segnum;
759                 fq.p1                                           = &new_pos;
760                 fq.rad                                  = obj->size;
761                 fq.thisobjnum                   = objnum;
762                 fq.ignore_obj_list      = ignore_obj_list;
763                 fq.flags                                        = FQ_CHECK_OBJS;
764
765                 if (obj->type == OBJ_WEAPON)
766                         fq.flags |= FQ_TRANSPOINT;
767
768                 if (obj->type == OBJ_PLAYER)
769                         fq.flags |= FQ_GET_SEGLIST;
770
771 //@@                    if (get_seg_masks(&obj->pos, obj->segnum, 0, __FILE__, __LINE__).centermask != 0)
772 //@@                            Int3();
773
774 save_p0 = *fq.p0;
775 save_p1 = *fq.p1;
776
777
778                 fate = find_vector_intersection(&fq,&hit_info);
779                 //      Matt: Mike's hack.
780                 if (fate == HIT_OBJECT) {
781                         object  *objp = &Objects[hit_info.hit_object];
782
783                         if ((objp->type == OBJ_WEAPON) && ((objp->id == PROXIMITY_ID) || (objp->id == SUPERPROX_ID)))
784                                 count--;
785                 }
786
787                 #ifndef NDEBUG
788                 if (fate == HIT_BAD_P0) {
789                         mprintf((0,"Warning: Bad p0 in physics!  Object = %i, type = %i [%s]\n", obj-Objects, obj->type, Object_type_names[obj->type]));
790                         Int3();
791                 }
792                 #endif
793
794                 if (obj->type == OBJ_PLAYER) {
795                         int i;
796
797                         if (n_phys_segs && phys_seglist[n_phys_segs-1]==hit_info.seglist[0])
798                                 n_phys_segs--;
799
800                         for (i=0;(i<hit_info.n_segs) && (n_phys_segs<MAX_FVI_SEGS-1);  )
801                                 phys_seglist[n_phys_segs++] = hit_info.seglist[i++];
802                 }
803
804                 #ifdef EXTRA_DEBUG
805                 if (obj == debug_obj)
806                         printf("   fate  = %d, hit_pnt = %8x %8x %8x\n",fate,XYZ(&hit_info.hit_pnt));;
807                 #endif
808
809                 ipos = hit_info.hit_pnt;
810                 iseg = hit_info.hit_seg;
811                 WallHitSide = hit_info.hit_side;
812                 WallHitSeg = hit_info.hit_side_seg;
813
814                 if (iseg==-1) {         //some sort of horrible error
815                         #ifndef NDEBUG
816                         mprintf((1,"iseg==-1 in physics!  Object = %i, type = %i (%s)\n", obj-Objects, obj->type, Object_type_names[obj->type]));
817                         #endif
818                         //Int3();
819                         //compute_segment_center(&ipos,&Segments[obj->segnum]);
820                         //ipos.x += objnum;
821                         //iseg = obj->segnum;
822                         //fate = HIT_NONE;
823                         if (obj->type == OBJ_WEAPON)
824                                 obj->flags |= OF_SHOULD_BE_DEAD;
825                         break;
826                 }
827
828                 Assert(!((fate==HIT_WALL) && ((WallHitSeg == -1) || (WallHitSeg > Highest_segment_index))));
829
830                 //if(!get_seg_masks(&hit_info.hit_pnt,hit_info.hit_seg,0).centermask==0)
831                 //      Int3();
832
833                 save_pos = obj->pos;                    //save the object's position
834                 save_seg = obj->segnum;
835
836                 // update object's position and segment number
837                 obj->pos = ipos;
838
839                 #ifdef EXTRA_DEBUG
840                 if (obj == debug_obj)
841                         printf("   new pos = %x %x %x\n",XYZ(&obj->pos));
842                 #endif
843
844                 if ( iseg != obj->segnum )
845                         obj_relink(objnum, iseg );
846
847                 //if start point not in segment, move object to center of segment
848                 if (get_seg_masks(&obj->pos, obj->segnum, 0, __FILE__, __LINE__).centermask !=0 )
849                 {
850                         int n;
851
852                         if ((n=find_object_seg(obj))==-1) {
853                                 //Int3();
854                                 if (obj->type==OBJ_PLAYER && (n=find_point_seg(&obj->last_pos,obj->segnum))!=-1) {
855                                         obj->pos = obj->last_pos;
856                                         obj_relink(objnum, n );
857                                 }
858                                 else {
859                                         compute_segment_center(&obj->pos,&Segments[obj->segnum]);
860                                         obj->pos.x += objnum;
861                                 }
862                                 if (obj->type == OBJ_WEAPON)
863                                         obj->flags |= OF_SHOULD_BE_DEAD;
864                         }
865                         return;
866                 }
867
868                 //calulate new sim time
869                 {
870                         //vms_vector moved_vec;
871                         vms_vector moved_vec_n;
872                         fix attempted_dist,actual_dist;
873
874                         old_sim_time = sim_time;
875
876                         actual_dist = vm_vec_normalized_dir(&moved_vec_n,&obj->pos,&save_pos);
877
878                         if (fate==HIT_WALL && vm_vec_dot(&moved_vec_n,&frame_vec) < 0) {                //moved backwards
879
880                                 //don't change position or sim_time
881
882 //*******                                       mprintf((0,"Obj %d moved backwards\n",obj-Objects));
883
884                                 #ifdef EXTRA_DEBUG
885                                 if (obj == debug_obj)
886                                         printf("   Warning: moved backwards!\n");
887                                 #endif
888
889                                 obj->pos = save_pos;
890                 
891                                 //iseg = obj->segnum;           //don't change segment
892
893                                 obj_relink(objnum, save_seg );
894
895                                 moved_time = 0;
896                         }
897                         else {
898
899                                 //if (obj == debug_obj)
900                                 //      printf("   moved_vec = %x %x %x\n",XYZ(&moved_vec));
901                         
902                                 attempted_dist = vm_vec_mag(&frame_vec);
903
904                                 sim_time = fixmuldiv(sim_time,attempted_dist-actual_dist,attempted_dist);
905
906                                 moved_time = old_sim_time - sim_time;
907
908                                 if (sim_time < 0 || sim_time>old_sim_time) {
909                                         #ifndef NDEBUG
910                                         mprintf((0,"Bogus sim_time = %x, old = %x\n",sim_time,old_sim_time));
911                                         if (obj == debug_obj)
912                                                 printf("   Bogus sim_time = %x, old = %x, attempted_dist = %x, actual_dist = %x\n",sim_time,old_sim_time,attempted_dist,actual_dist);
913                                         //Int3(); Removed by Rob
914                                         #endif
915                                         sim_time = old_sim_time;
916                                         //WHY DOES THIS HAPPEN??
917
918                                         moved_time = 0;
919                                 }
920                         }
921
922                         #ifdef EXTRA_DEBUG
923                         if (obj == debug_obj)
924                                 printf("   new sim_time = %x\n",sim_time);
925                         #endif
926
927                 }
928
929
930                 switch( fate )          {
931
932                         case HIT_WALL:          {
933                                 vms_vector moved_v;
934                                 //@@fix total_d,moved_d;
935                                 fix hit_speed,wall_part;
936         
937                                 // Find hit speed       
938
939                                 vm_vec_sub(&moved_v,&obj->pos,&save_pos);
940
941                                 wall_part = vm_vec_dot(&moved_v,&hit_info.hit_wallnorm);
942
943                                 if (wall_part != 0 && moved_time>0 && (hit_speed=-fixdiv(wall_part,moved_time))>0)
944                                         collide_object_with_wall( obj, hit_speed, WallHitSeg, WallHitSide, &hit_info.hit_pnt );
945                                 else
946                                         scrape_object_on_wall(obj, WallHitSeg, WallHitSide, &hit_info.hit_pnt );
947
948                                 Assert( WallHitSeg > -1 );
949                                 Assert( WallHitSide > -1 );
950
951                                 if ( !(obj->flags&OF_SHOULD_BE_DEAD) )  {
952                                         int forcefield_bounce;          //bounce off a forcefield
953
954                                         Assert(BounceCheat || !(obj->mtype.phys_info.flags & PF_STICK && obj->mtype.phys_info.flags & PF_BOUNCE));      //can't be bounce and stick
955
956                                         forcefield_bounce = (TmapInfo[Segments[WallHitSeg].sides[WallHitSide].tmap_num].flags & TMI_FORCE_FIELD);
957
958                                         if (!forcefield_bounce && (obj->mtype.phys_info.flags & PF_STICK)) {            //stop moving
959
960                                                 // mprintf((0, "Object %i stuck at %i:%i\n", obj-Objects, WallHitSeg, WallHitSide));
961                                                 add_stuck_object(obj, WallHitSeg, WallHitSide);
962
963                                                 vm_vec_zero(&obj->mtype.phys_info.velocity);
964                                                 obj_stopped = 1;
965                                                 try_again = 0;
966                                         }
967                                         else {                                  // Slide object along wall
968                                                 int check_vel=0;
969
970                                                 //We're constrained by wall, so subtract wall part from
971                                                 //velocity vector
972
973                                                 wall_part = vm_vec_dot(&hit_info.hit_wallnorm,&obj->mtype.phys_info.velocity);
974
975 //                                              mprintf((0, "%d", f2i(vm_vec_mag(&hit_info.hit_wallnorm)) ));
976
977                                                 if (forcefield_bounce || (obj->mtype.phys_info.flags & PF_BOUNCE)) {            //bounce off wall
978                                                         wall_part *= 2; //Subtract out wall part twice to achieve bounce
979
980                                                         if (forcefield_bounce) {
981                                                                 check_vel = 1;                          //check for max velocity
982                                                                 if (obj->type == OBJ_PLAYER)
983                                                                         wall_part *= 2;         //player bounce twice as much
984                                                         }
985
986                                                         if ( obj->mtype.phys_info.flags & PF_BOUNCES_TWICE) {
987                                                                 Assert(obj->mtype.phys_info.flags & PF_BOUNCE);
988                                                                 if (obj->mtype.phys_info.flags & PF_BOUNCED_ONCE)
989                                                                         obj->mtype.phys_info.flags &= ~(PF_BOUNCE+PF_BOUNCED_ONCE+PF_BOUNCES_TWICE);
990                                                                 else
991                                                                         obj->mtype.phys_info.flags |= PF_BOUNCED_ONCE;
992                                                         }
993
994                                                         bounced = 1;            //this object bounced
995                                                 }
996
997                                                 vm_vec_scale_add2(&obj->mtype.phys_info.velocity,&hit_info.hit_wallnorm,-wall_part);
998
999 //                                              mprintf((0, "Velocity at bounce time = %d\n", f2i(vm_vec_mag(&obj->mtype.phys_info.velocity))));
1000
1001 //if (obj==ConsoleObject)
1002 //      mprintf((0,"player vel = %x\n",vm_vec_mag_quick(&obj->mtype.phys_info.velocity)));
1003
1004                                                 if (check_vel) {
1005                                                         fix vel = vm_vec_mag_quick(&obj->mtype.phys_info.velocity);
1006
1007                                                         if (vel > MAX_OBJECT_VEL)
1008                                                                 vm_vec_scale(&obj->mtype.phys_info.velocity,fixdiv(MAX_OBJECT_VEL,vel));
1009                                                 }
1010
1011                                                 if (bounced && obj->type == OBJ_WEAPON)
1012                                                         vm_vector_2_matrix(&obj->orient,&obj->mtype.phys_info.velocity,&obj->orient.uvec,NULL);
1013
1014                                                 #ifdef EXTRA_DEBUG
1015                                                 if (obj == debug_obj) {
1016                                                         printf("   sliding - wall_norm %x %x %x %x\n",wall_part,XYZ(&hit_info.hit_wallnorm));
1017                                                         printf("   wall_part %x, new velocity = %x %x %x\n",wall_part,XYZ(&obj->mtype.phys_info.velocity));
1018                                                 }
1019                                                 #endif
1020
1021                                                 try_again = 1;
1022                                         }
1023                                 }
1024                                 break;
1025                         }
1026
1027                         case HIT_OBJECT:                {
1028                                 vms_vector old_vel;
1029
1030                                 // Mark the hit object so that on a retry the fvi code
1031                                 // ignores this object.
1032
1033                                 Assert(hit_info.hit_object != -1);
1034
1035                                 //      Calculcate the hit point between the two objects.
1036                                 {       vms_vector      *ppos0, *ppos1, pos_hit;
1037                                         fix                     size0, size1;
1038                                         ppos0 = &Objects[hit_info.hit_object].pos;
1039                                         ppos1 = &obj->pos;
1040                                         size0 = Objects[hit_info.hit_object].size;
1041                                         size1 = obj->size;
1042                                         Assert(size0+size1 != 0);       // Error, both sizes are 0, so how did they collide, anyway?!?
1043                                         //vm_vec_scale(vm_vec_sub(&pos_hit, ppos1, ppos0), fixdiv(size0, size0 + size1));
1044                                         //vm_vec_add2(&pos_hit, ppos0);
1045                                         vm_vec_sub(&pos_hit, ppos1, ppos0);
1046                                         vm_vec_scale_add(&pos_hit,ppos0,&pos_hit,fixdiv(size0, size0 + size1));
1047
1048                                         old_vel = obj->mtype.phys_info.velocity;
1049
1050                                         collide_two_objects( obj, &Objects[hit_info.hit_object], &pos_hit);
1051
1052                                 }
1053
1054                                 // Let object continue its movement
1055                                 if ( !(obj->flags&OF_SHOULD_BE_DEAD)  ) {
1056                                         //obj->pos = save_pos;
1057
1058                                         if (obj->mtype.phys_info.flags&PF_PERSISTENT || (old_vel.x == obj->mtype.phys_info.velocity.x && old_vel.y == obj->mtype.phys_info.velocity.y && old_vel.z == obj->mtype.phys_info.velocity.z)) {
1059                                                 //if (Objects[hit_info.hit_object].type == OBJ_POWERUP)
1060                                                         ignore_obj_list[n_ignore_objs++] = hit_info.hit_object;
1061                                                 try_again = 1;
1062                                         }
1063                                 }
1064
1065                                 break;
1066                         }       
1067                         case HIT_NONE:          
1068                         #ifdef TACTILE
1069                                 if (TactileStick && obj==ConsoleObject && !(FrameCount & 15))
1070                                  Tactile_Xvibrate_clear ();
1071                         #endif
1072                                 break;
1073
1074                         #ifndef NDEBUG
1075                         case HIT_BAD_P0:
1076                                 Int3();         // Unexpected collision type: start point not in specified segment.
1077                                 mprintf((0,"Warning: Bad p0 in physics!!!\n"));
1078                                 break;
1079                         default:
1080                                 // Unknown collision type returned from find_vector_intersection!!
1081                                 Int3();
1082                                 break;
1083                         #endif
1084                 }
1085
1086         } while ( try_again );
1087
1088         //      Pass retry count info to AI.
1089         if (obj->control_type == CT_AI) {
1090                 if (count > 0) {
1091                         Ai_local_info[objnum].retry_count = count-1;
1092                         #ifndef NDEBUG
1093                         Total_retries += count-1;
1094                         Total_sims++;
1095                         #endif
1096                 }
1097         }
1098
1099         //I'm not sure why we do this.  I wish there were a comment that
1100         //explained it.  I think maybe it only needs to be done if the object
1101         //is sliding, but I don't know
1102         if (!obj_stopped && !bounced)   {       //Set velocity from actual movement
1103                 vms_vector moved_vec;
1104
1105                 vm_vec_sub(&moved_vec,&obj->pos,&start_pos);
1106                 vm_vec_copy_scale(&obj->mtype.phys_info.velocity,&moved_vec,fixdiv(f1_0,FrameTime));
1107
1108                 #ifdef BUMP_HACK
1109                 if (obj==ConsoleObject && (obj->mtype.phys_info.velocity.x==0 && obj->mtype.phys_info.velocity.y==0 && obj->mtype.phys_info.velocity.z==0) &&
1110                           !(obj->mtype.phys_info.thrust.x==0 && obj->mtype.phys_info.thrust.y==0 && obj->mtype.phys_info.thrust.z==0)) {
1111                         vms_vector center,bump_vec;
1112
1113                         //bump player a little towards center of segment to unstick
1114
1115                         compute_segment_center(&center,&Segments[obj->segnum]);
1116                         vm_vec_normalized_dir_quick(&bump_vec,&center,&obj->pos);
1117
1118                         //don't bump player toward center of reactor segment
1119                         if (Segment2s[obj->segnum].special == SEGMENT_IS_CONTROLCEN)
1120                                 vm_vec_negate(&bump_vec);
1121
1122                         vm_vec_scale_add2(&obj->pos,&bump_vec,obj->size/5);
1123
1124                         //if moving away from seg, might move out of seg, so update
1125                         if (Segment2s[obj->segnum].special == SEGMENT_IS_CONTROLCEN)
1126                                 update_object_seg(obj);
1127                 }
1128                 #endif
1129         }
1130
1131         //Assert(check_point_in_seg(&obj->pos,obj->segnum,0).centermask==0);
1132
1133         //if (obj->control_type == CT_FLYING)
1134         if (obj->mtype.phys_info.flags & PF_LEVELLING)
1135                 do_physics_align_object( obj );
1136
1137
1138         //hack to keep player from going through closed doors
1139         if (obj->type==OBJ_PLAYER && obj->segnum!=orig_segnum && (Physics_cheat_flag!=0xBADA55) ) {
1140                 int sidenum;
1141
1142                 sidenum = find_connect_side(&Segments[obj->segnum],&Segments[orig_segnum]);
1143
1144                 if (sidenum != -1) {
1145
1146                         if (! (WALL_IS_DOORWAY(&Segments[orig_segnum],sidenum) & WID_FLY_FLAG)) {
1147                                 side *s;
1148                                 int vertnum,num_faces,i;
1149                                 fix dist;
1150                                 int vertex_list[6];
1151
1152                                 //bump object back
1153
1154                                 s = &Segments[orig_segnum].sides[sidenum];
1155
1156                                 if (orig_segnum==-1)
1157                                         Error("orig_segnum == -1 in physics");
1158
1159                                 create_abs_vertex_lists(&num_faces, vertex_list, orig_segnum, sidenum, __FILE__, __LINE__);
1160
1161                                 //let's pretend this wall is not triangulated
1162                                 vertnum = vertex_list[0];
1163                                 for (i=1;i<4;i++)
1164                                         if (vertex_list[i] < vertnum)
1165                                                 vertnum = vertex_list[i];
1166
1167                                 #ifdef COMPACT_SEGS
1168                                         {
1169                                         vms_vector _vn;
1170                                         get_side_normal(&Segments[orig_segnum], sidenum, 0, &_vn );
1171                                         dist = vm_dist_to_plane(&start_pos, &_vn, &Vertices[vertnum]);
1172                                         vm_vec_scale_add(&obj->pos,&start_pos,&_vn,obj->size-dist);
1173                                         }
1174                                 #else
1175                                         dist = vm_dist_to_plane(&start_pos, &s->normals[0], &Vertices[vertnum]);
1176                                         vm_vec_scale_add(&obj->pos,&start_pos,&s->normals[0],obj->size-dist);
1177                                 #endif
1178                                 update_object_seg(obj);
1179
1180                         }
1181                 }
1182         }
1183
1184 //--WE ALWYS WANT THIS IN, MATT AND MIKE DECISION ON 12/10/94, TWO MONTHS AFTER FINAL   #ifndef NDEBUG
1185         //if end point not in segment, move object to last pos, or segment center
1186         if (get_seg_masks(&obj->pos, obj->segnum, 0, __FILE__, __LINE__).centermask != 0)
1187         {
1188                 if (find_object_seg(obj)==-1) {
1189                         int n;
1190
1191                         //Int3();
1192                         if (obj->type==OBJ_PLAYER && (n=find_point_seg(&obj->last_pos,obj->segnum))!=-1) {
1193                                 obj->pos = obj->last_pos;
1194                                 obj_relink(objnum, n );
1195                         }
1196                         else {
1197                                 compute_segment_center(&obj->pos,&Segments[obj->segnum]);
1198                                 obj->pos.x += objnum;
1199                         }
1200                         if (obj->type == OBJ_WEAPON)
1201                                 obj->flags |= OF_SHOULD_BE_DEAD;
1202                 }
1203         }
1204 //--WE ALWYS WANT THIS IN, MATT AND MIKE DECISION ON 12/10/94, TWO MONTHS AFTER FINAL   #endif
1205
1206
1207 }
1208
1209 //--unused-- //tell us what the given object will do (as far as hiting walls) in
1210 //--unused-- //the given time (in seconds) t.  Igores acceleration (sorry)
1211 //--unused-- //if check_objects is set, check with objects, else just with walls
1212 //--unused-- //returns fate, fills in hit time.  If fate==HIT_NONE, hit_time undefined
1213 //--unused-- int physics_lookahead(object *obj,fix t,int fvi_flags,fix *hit_time, fvi_info *hit_info)
1214 //--unused-- {
1215 //--unused--    vms_vector new_pos;
1216 //--unused--    int objnum,fate;
1217 //--unused--    fvi_query fq;
1218 //--unused--
1219 //--unused--    Assert(obj->movement_type == MT_PHYSICS);
1220 //--unused--
1221 //--unused--    objnum = obj-Objects;
1222 //--unused--
1223 //--unused--    vm_vec_scale_add(&new_pos, &obj->pos, &obj->mtype.phys_info.velocity, t);
1224 //--unused--
1225 //--unused--    fq.p0                                           = &obj->pos;
1226 //--unused--    fq.startseg                             = obj->segnum;
1227 //--unused--    fq.p1                                           = &new_pos;
1228 //--unused--    fq.rad                                  = obj->size;
1229 //--unused--    fq.thisobjnum                   = objnum;
1230 //--unused--    fq.ignore_obj_list      = NULL;
1231 //--unused--    fq.flags                                        = fvi_flags;
1232 //--unused--
1233 //--unused--    fate = find_vector_intersection(&fq,hit_info);
1234 //--unused--
1235 //--unused--    if (fate != HIT_NONE) {
1236 //--unused--            fix dist,speed;
1237 //--unused--
1238 //--unused--            dist = vm_vec_dist(&obj->pos, &hit_info->hit_pnt);
1239 //--unused--
1240 //--unused--            speed = vm_vec_mag(&obj->mtype.phys_info.velocity);
1241 //--unused--
1242 //--unused--            *hit_time = fixdiv(dist,speed);
1243 //--unused--
1244 //--unused--    }
1245 //--unused--
1246 //--unused--    return fate;
1247 //--unused--
1248 //--unused-- }
1249
1250 //Applies an instantaneous force on an object, resulting in an instantaneous
1251 //change in velocity.
1252 void phys_apply_force(object *obj,vms_vector *force_vec)
1253 {
1254
1255         //      Put in by MK on 2/13/96 for force getting applied to Omega blobs, which have 0 mass,
1256         //      in collision with crazy reactor robot thing on d2levf-s.
1257         if (obj->mtype.phys_info.mass == 0)
1258                 return;
1259
1260         if (obj->movement_type != MT_PHYSICS)
1261                 return;
1262
1263 #ifdef TACTILE
1264    if (TactileStick && obj==&Objects[Players[Player_num].objnum])
1265                 Tactile_apply_force (force_vec,&obj->orient);
1266 #endif
1267
1268         //Add in acceleration due to force
1269         vm_vec_scale_add2(&obj->mtype.phys_info.velocity,force_vec,fixdiv(f1_0,obj->mtype.phys_info.mass));
1270
1271
1272 }
1273
1274 //      ----------------------------------------------------------------
1275 //      Do *dest = *delta unless:
1276 //                              *delta is pretty small
1277 //              and     they are of different signs.
1278 void physics_set_rotvel_and_saturate(fix *dest, fix delta)
1279 {
1280         if ((delta ^ *dest) < 0) {
1281                 if (abs(delta) < F1_0/8) {
1282                         // mprintf((0, "D"));
1283                         *dest = delta/4;
1284                 } else
1285                         // mprintf((0, "d"));
1286                         *dest = delta;
1287         } else {
1288                 // mprintf((0, "!"));
1289                 *dest = delta;
1290         }
1291 }
1292
1293 //      ------------------------------------------------------------------------------------------------------
1294 //      Note: This is the old ai_turn_towards_vector code.
1295 //      phys_apply_rot used to call ai_turn_towards_vector until I fixed it, which broke phys_apply_rot.
1296 void physics_turn_towards_vector(vms_vector *goal_vector, object *obj, fix rate)
1297 {
1298         vms_angvec      dest_angles, cur_angles;
1299         fix                     delta_p, delta_h;
1300         vms_vector      *rotvel_ptr = &obj->mtype.phys_info.rotvel;
1301
1302         // Make this object turn towards the goal_vector.  Changes orientation, doesn't change direction of movement.
1303         // If no one moves, will be facing goal_vector in 1 second.
1304
1305         //      Detect null vector.
1306         if ((goal_vector->x == 0) && (goal_vector->y == 0) && (goal_vector->z == 0))
1307                 return;
1308
1309         //      Make morph objects turn more slowly.
1310         if (obj->control_type == CT_MORPH)
1311                 rate *= 2;
1312
1313         vm_extract_angles_vector(&dest_angles, goal_vector);
1314         vm_extract_angles_vector(&cur_angles, &obj->orient.fvec);
1315
1316         delta_p = (dest_angles.p - cur_angles.p);
1317         delta_h = (dest_angles.h - cur_angles.h);
1318
1319         if (delta_p > F1_0/2) delta_p = dest_angles.p - cur_angles.p - F1_0;
1320         if (delta_p < -F1_0/2) delta_p = dest_angles.p - cur_angles.p + F1_0;
1321         if (delta_h > F1_0/2) delta_h = dest_angles.h - cur_angles.h - F1_0;
1322         if (delta_h < -F1_0/2) delta_h = dest_angles.h - cur_angles.h + F1_0;
1323
1324         delta_p = fixdiv(delta_p, rate);
1325         delta_h = fixdiv(delta_h, rate);
1326
1327         if (abs(delta_p) < F1_0/16) delta_p *= 4;
1328         if (abs(delta_h) < F1_0/16) delta_h *= 4;
1329
1330         physics_set_rotvel_and_saturate(&rotvel_ptr->x, delta_p);
1331         physics_set_rotvel_and_saturate(&rotvel_ptr->y, delta_h);
1332         rotvel_ptr->z = 0;
1333 }
1334
1335 //      -----------------------------------------------------------------------------
1336 //      Applies an instantaneous whack on an object, resulting in an instantaneous
1337 //      change in orientation.
1338 void phys_apply_rot(object *obj,vms_vector *force_vec)
1339 {
1340         fix     rate, vecmag;
1341
1342         if (obj->movement_type != MT_PHYSICS)
1343                 return;
1344
1345         vecmag = vm_vec_mag(force_vec)/8;
1346         if (vecmag < F1_0/256)
1347                 rate = 4*F1_0;
1348         else if (vecmag < obj->mtype.phys_info.mass >> 14)
1349                 rate = 4*F1_0;
1350         else {
1351                 rate = fixdiv(obj->mtype.phys_info.mass, vecmag);
1352                 if (obj->type == OBJ_ROBOT) {
1353                         if (rate < F1_0/4)
1354                                 rate = F1_0/4;
1355                         //      Changed by mk, 10/24/95, claw guys should not slow down when attacking!
1356                         if (!Robot_info[obj->id].thief && !Robot_info[obj->id].attack_type) {
1357                                 if (obj->ctype.ai_info.SKIP_AI_COUNT * FrameTime < 3*F1_0/4) {
1358                                         fix     tval = fixdiv(F1_0, 8*FrameTime);
1359                                         int     addval;
1360
1361                                         addval = f2i(tval);
1362
1363                                         if ( (d_rand() * 2) < (tval & 0xffff))
1364                                                 addval++;
1365                                         obj->ctype.ai_info.SKIP_AI_COUNT += addval;
1366                                         // -- mk: too much stuff making hard to see my debug messages...mprintf((0, "FrameTime = %7.3f, addval = %i\n", f2fl(FrameTime), addval));
1367                                 }
1368                         }
1369                 } else {
1370                         if (rate < F1_0/2)
1371                                 rate = F1_0/2;
1372                 }
1373         }
1374
1375         //      Turn amount inversely proportional to mass.  Third parameter is seconds to do 360 turn.
1376         physics_turn_towards_vector(force_vec, obj, rate);
1377
1378
1379 }
1380
1381
1382 //this routine will set the thrust for an object to a value that will
1383 //(hopefully) maintain the object's current velocity
1384 void set_thrust_from_velocity(object *obj)
1385 {
1386         fix k;
1387
1388         Assert(obj->movement_type == MT_PHYSICS);
1389
1390         k = fixmuldiv(obj->mtype.phys_info.mass,obj->mtype.phys_info.drag,(f1_0-obj->mtype.phys_info.drag));
1391
1392         vm_vec_copy_scale(&obj->mtype.phys_info.thrust,&obj->mtype.phys_info.velocity,k);
1393
1394 }
1395
1396