2 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
3 SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
4 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
5 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
6 IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
7 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
8 FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
9 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS
10 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
11 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
16 * Code for flying through the mines
52 //Global variables for physics system
54 #define ROLL_RATE 0x2000
55 #define DAMP_ANG 0x400 //min angle to bank
57 #define TURNROLL_SCALE (0x4ec4/2)
59 #define MAX_OBJECT_VEL i2f(100)
61 #define BUMP_HACK 1 //if defined, bump player when he gets stuck
63 //--unused-- int mike_mode=0;
65 //check point against each side of segment. return bitmask, where bit
66 //set means behind that side
68 int Physics_cheat_flag = 0;
69 extern char BounceCheat;
71 //##//returns the distance of a point (checkp) from a plane (defined by norm & planep)
72 //##fix dist_to_plane(vms_vector *checkp,vms_vector *norm,vms_vector *planep)
74 //## vms_vector deltap;
76 //## vm_vec_sub(&deltap,checkp,planep);
78 //## return vm_vec_dot(&deltap,norm);
81 //--unused-- int dpjm_old_joy_x, dpjm_old_joy_y;
83 int floor_levelling=0;
85 //--unused-- level_with_floor()
87 //--unused-- floor_levelling=1;
90 //make sure matrix is orthogonal
91 void check_and_fix_matrix(vms_matrix *m)
95 vm_vector_2_matrix(&tempm,&m->fvec,&m->uvec,NULL);
100 void do_physics_align_object( object * obj )
102 vms_vector desired_upvec;
103 fixang delta_ang,roll_ang;
104 //vms_vector forvec = {0,0,f1_0};
105 vms_matrix temp_matrix;
106 fix d,largest_d=-f1_0;
110 // bank player according to segment orientation
112 //find side of segment that player is most alligned with
117 get_side_normal( &Segments[obj->segnum], i, 0, &_tv1 );
118 d = vm_vec_dot(&_tv1,&obj->orient.uvec);
120 d = vm_vec_dot(&Segments[obj->segnum].sides[i].normals[0],&obj->orient.uvec);
123 if (d > largest_d) {largest_d = d; best_side=i;}
126 if (floor_levelling) {
128 // old way: used floor's normal as upvec
130 get_side_normal(&Segments[obj->segnum], 3, 0, &desired_upvec );
132 desired_upvec = Segments[obj->segnum].sides[3].normals[0];
136 else // new player leveling code: use normal of side closest to our up vec
137 if (get_num_faces(&Segments[obj->segnum].sides[best_side])==2) {
139 vms_vector normals[2];
140 get_side_normals(&Segments[obj->segnum], best_side, &normals[0], &normals[1] );
142 desired_upvec.x = (normals[0].x + normals[1].x) / 2;
143 desired_upvec.y = (normals[0].y + normals[1].y) / 2;
144 desired_upvec.z = (normals[0].z + normals[1].z) / 2;
146 vm_vec_normalize(&desired_upvec);
148 side *s = &Segments[obj->segnum].sides[best_side];
149 desired_upvec.x = (s->normals[0].x + s->normals[1].x) / 2;
150 desired_upvec.y = (s->normals[0].y + s->normals[1].y) / 2;
151 desired_upvec.z = (s->normals[0].z + s->normals[1].z) / 2;
153 vm_vec_normalize(&desired_upvec);
158 get_side_normal(&Segments[obj->segnum], best_side, 0, &desired_upvec );
160 desired_upvec = Segments[obj->segnum].sides[best_side].normals[0];
163 if (labs(vm_vec_dot(&desired_upvec,&obj->orient.fvec)) < f1_0/2) {
164 fixang save_delta_ang;
167 vm_vector_2_matrix(&temp_matrix,&obj->orient.fvec,&desired_upvec,NULL);
169 save_delta_ang = delta_ang = vm_vec_delta_ang(&obj->orient.uvec,&temp_matrix.uvec,&obj->orient.fvec);
171 delta_ang += obj->mtype.phys_info.turnroll;
173 if (abs(delta_ang) > DAMP_ANG) {
174 vms_matrix rotmat, new_pm;
176 roll_ang = fixmul(FrameTime,ROLL_RATE);
178 if (abs(delta_ang) < roll_ang) roll_ang = delta_ang;
179 else if (delta_ang<0) roll_ang = -roll_ang;
181 tangles.p = tangles.h = 0; tangles.b = roll_ang;
182 vm_angles_2_matrix(&rotmat,&tangles);
184 vm_matrix_x_matrix(&new_pm,&obj->orient,&rotmat);
185 obj->orient = new_pm;
187 else floor_levelling=0;
192 void set_object_turnroll(object *obj)
196 desired_bank = -fixmul(obj->mtype.phys_info.rotvel.y,TURNROLL_SCALE);
198 if (obj->mtype.phys_info.turnroll != desired_bank) {
199 fixang delta_ang,max_roll;
201 max_roll = fixmul(ROLL_RATE,FrameTime);
203 delta_ang = desired_bank - obj->mtype.phys_info.turnroll;
205 if (labs(delta_ang) < max_roll)
206 max_roll = delta_ang;
209 max_roll = -max_roll;
211 obj->mtype.phys_info.turnroll += max_roll;
216 //list of segments went through
217 int phys_seglist[MAX_FVI_SEGS],n_phys_segs;
220 #define MAX_IGNORE_OBJS 100
223 #define EXTRA_DEBUG 1 //no extra debug when NDEBUG is on
227 object *debug_obj=NULL;
230 #define XYZ(v) (v)->x,(v)->y,(v)->z
234 int Total_retries=0, Total_sims=0;
235 int Dont_move_ai_objects=0;
240 extern int disable_new_fvi_stuff;
241 // -----------------------------------------------------------------------------------------------------------
242 // add rotational velocity & acceleration
243 void do_physics_sim_rot(object *obj)
246 vms_matrix rotmat,new_orient;
250 Assert(FrameTime > 0); //Get MATT if hit this!
252 pi = &obj->mtype.phys_info;
254 if (!(pi->rotvel.x || pi->rotvel.y || pi->rotvel.z || pi->rotthrust.x || pi->rotthrust.y || pi->rotthrust.z))
257 if (obj->mtype.phys_info.drag) {
262 count = FrameTime / FT;
266 drag = (obj->mtype.phys_info.drag*5)/2;
268 if (obj->mtype.phys_info.flags & PF_USES_THRUST) {
270 vm_vec_copy_scale(&accel,&obj->mtype.phys_info.rotthrust,fixdiv(f1_0,obj->mtype.phys_info.mass));
274 vm_vec_add2(&obj->mtype.phys_info.rotvel,&accel);
276 vm_vec_scale(&obj->mtype.phys_info.rotvel,f1_0-drag);
279 //do linear scale on remaining bit of time
281 vm_vec_scale_add2(&obj->mtype.phys_info.rotvel,&accel,k);
282 vm_vec_scale(&obj->mtype.phys_info.rotvel,f1_0-fixmul(k,drag));
284 else if (! (obj->mtype.phys_info.flags & PF_FREE_SPINNING)) {
288 total_drag = fixmul(total_drag,f1_0-drag);
290 //do linear scale on remaining bit of time
292 total_drag = fixmul(total_drag,f1_0-fixmul(k,drag));
294 vm_vec_scale(&obj->mtype.phys_info.rotvel,total_drag);
299 //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) ));
303 //unrotate object for bank caused by turn
304 if (obj->mtype.phys_info.turnroll) {
307 tangles.p = tangles.h = 0;
308 tangles.b = -obj->mtype.phys_info.turnroll;
309 vm_angles_2_matrix(&rotmat,&tangles);
310 vm_matrix_x_matrix(&new_pm,&obj->orient,&rotmat);
311 obj->orient = new_pm;
314 tangles.p = fixmul(obj->mtype.phys_info.rotvel.x,FrameTime);
315 tangles.h = fixmul(obj->mtype.phys_info.rotvel.y,FrameTime);
316 tangles.b = fixmul(obj->mtype.phys_info.rotvel.z,FrameTime);
318 vm_angles_2_matrix(&rotmat,&tangles);
319 vm_matrix_x_matrix(&new_orient,&obj->orient,&rotmat);
320 obj->orient = new_orient;
322 if (obj->mtype.phys_info.flags & PF_TURNROLL)
323 set_object_turnroll(obj);
325 //re-rotate object for bank caused by turn
326 if (obj->mtype.phys_info.turnroll) {
329 tangles.p = tangles.h = 0;
330 tangles.b = obj->mtype.phys_info.turnroll;
331 vm_angles_2_matrix(&rotmat,&tangles);
332 vm_matrix_x_matrix(&new_pm,&obj->orient,&rotmat);
333 obj->orient = new_pm;
336 check_and_fix_matrix(&obj->orient);
339 // -----------------------------------------------------------------------------------------------------------
340 //Simulate a physics object for this frame
341 void do_physics_sim(object *obj)
343 int ignore_obj_list[MAX_IGNORE_OBJS],n_ignore_objs;
347 vms_vector frame_vec; //movement in this frame
348 vms_vector new_pos,ipos; //position after this frame
351 int WallHitSeg, WallHitSide;
357 fix sim_time,old_sim_time;
358 vms_vector start_pos;
360 fix moved_time; //how long objected moved before hit something
361 vms_vector save_p0,save_p1;
363 int orig_segnum = obj->segnum;
366 Assert(obj->type != OBJ_NONE);
367 Assert(obj->movement_type == MT_PHYSICS);
370 if (Dont_move_ai_objects)
371 if (obj->control_type == CT_AI)
375 pi = &obj->mtype.phys_info;
377 do_physics_sim_rot(obj);
379 if (!(pi->velocity.x || pi->velocity.y || pi->velocity.z || pi->thrust.x || pi->thrust.y || pi->thrust.z))
382 objnum = OBJECT_NUMBER(obj);
386 disable_new_fvi_stuff = (obj->type != OBJ_PLAYER);
388 sim_time = FrameTime;
393 if (obj == debug_obj) {
394 printf("object %d:\n start pos = %x %x %x\n",objnum,XYZ(&obj->pos));
395 printf(" thrust = %x %x %x\n",XYZ(&obj->mtype.phys_info.thrust));
396 printf(" sim_time = %x\n",sim_time);
399 //check for correct object segment
400 if(!get_seg_masks(&obj->pos, obj->segnum, 0, __FILE__, __LINE__).centermask == 0)
403 mprintf((0,"Warning: object %d not in given seg!\n",objnum));
405 //Int3(); Removed by Rob 10/5/94
406 if (!update_object_seg(obj)) {
408 mprintf((0,"Warning: can't find seg for object %d - moving\n",objnum));
410 if (!(Game_mode & GM_MULTI))
412 compute_segment_center(&obj->pos,&Segments[obj->segnum]);
413 obj->pos.x += objnum;
418 start_pos = obj->pos;
422 Assert(obj->mtype.phys_info.brakes==0); //brakes not used anymore?
424 //if uses thrust, cannot have zero drag
425 Assert(!(obj->mtype.phys_info.flags&PF_USES_THRUST) || obj->mtype.phys_info.drag!=0);
427 //mprintf((0,"thrust=%x speed=%x\n",vm_vec_mag(&obj->mtype.phys_info.thrust),vm_vec_mag(&obj->mtype.phys_info.velocity)));
431 if ((drag = obj->mtype.phys_info.drag) != 0) {
437 count = sim_time / FT;
441 if (obj->mtype.phys_info.flags & PF_USES_THRUST) {
443 vm_vec_copy_scale(&accel,&obj->mtype.phys_info.thrust,fixdiv(f1_0,obj->mtype.phys_info.mass));
447 vm_vec_add2(&obj->mtype.phys_info.velocity,&accel);
449 vm_vec_scale(&obj->mtype.phys_info.velocity,f1_0-drag);
452 //do linear scale on remaining bit of time
454 vm_vec_scale_add2(&obj->mtype.phys_info.velocity,&accel,k);
456 vm_vec_scale(&obj->mtype.phys_info.velocity,f1_0-fixmul(k,drag));
462 total_drag = fixmul(total_drag,f1_0-drag);
464 //do linear scale on remaining bit of time
466 total_drag = fixmul(total_drag,f1_0-fixmul(k,drag));
468 vm_vec_scale(&obj->mtype.phys_info.velocity,total_drag);
473 if (obj == debug_obj)
474 printf(" velocity = %x %x %x\n",XYZ(&obj->mtype.phys_info.velocity));
481 vm_vec_copy_scale(&frame_vec, &obj->mtype.phys_info.velocity, sim_time);
484 if (obj == debug_obj)
485 printf(" pass %d, frame_vec = %x %x %x\n",count,XYZ(&frame_vec));
488 if ( (frame_vec.x==0) && (frame_vec.y==0) && (frame_vec.z==0) )
493 // If retry count is getting large, then we are trying to do something stupid.
495 if (obj->type == OBJ_PLAYER) {
502 vm_vec_add(&new_pos,&obj->pos,&frame_vec);
505 if (obj == debug_obj)
506 printf(" desired_pos = %x %x %x\n",XYZ(&new_pos));
509 ignore_obj_list[n_ignore_objs] = -1;
512 if (obj == debug_obj) {
513 printf(" FVI parms: p0 = %8x %8x %8x, segnum=%x, size=%x\n",XYZ(&obj->pos),obj->segnum,obj->size);
514 printf(" p1 = %8x %8x %8x\n",XYZ(&new_pos));
519 fq.startseg = obj->segnum;
522 fq.thisobjnum = objnum;
523 fq.ignore_obj_list = ignore_obj_list;
524 fq.flags = FQ_CHECK_OBJS;
526 if (obj->type == OBJ_WEAPON)
527 fq.flags |= FQ_TRANSPOINT;
529 if (obj->type == OBJ_PLAYER)
530 fq.flags |= FQ_GET_SEGLIST;
532 //@@ if (get_seg_masks(&obj->pos, obj->segnum, 0, __FILE__, __LINE__).centermask != 0)
539 fate = find_vector_intersection(&fq,&hit_info);
540 // Matt: Mike's hack.
541 if (fate == HIT_OBJECT) {
542 object *objp = &Objects[hit_info.hit_object];
544 if ((objp->type == OBJ_WEAPON) && ((objp->id == PROXIMITY_ID) || (objp->id == SUPERPROX_ID)))
549 if (fate == HIT_BAD_P0) {
550 mprintf((0, "Warning: Bad p0 in physics! Object = %i, type = %i [%s]\n", OBJECT_NUMBER(obj), obj->type, Object_type_names[obj->type]));
555 if (obj->type == OBJ_PLAYER) {
558 if (n_phys_segs && phys_seglist[n_phys_segs-1]==hit_info.seglist[0])
561 for (i=0;(i<hit_info.n_segs) && (n_phys_segs<MAX_FVI_SEGS-1); )
562 phys_seglist[n_phys_segs++] = hit_info.seglist[i++];
566 if (obj == debug_obj)
567 printf(" fate = %d, hit_pnt = %8x %8x %8x\n",fate,XYZ(&hit_info.hit_pnt));;
570 ipos = hit_info.hit_pnt;
571 iseg = hit_info.hit_seg;
572 WallHitSide = hit_info.hit_side;
573 WallHitSeg = hit_info.hit_side_seg;
575 if (iseg==-1) { //some sort of horrible error
577 mprintf((1, "iseg==-1 in physics! Object = %i, type = %i (%s)\n", OBJECT_NUMBER(obj), obj->type, Object_type_names[obj->type]));
580 //compute_segment_center(&ipos,&Segments[obj->segnum]);
582 //iseg = obj->segnum;
584 if (obj->type == OBJ_WEAPON)
585 obj->flags |= OF_SHOULD_BE_DEAD;
589 Assert(!((fate==HIT_WALL) && ((WallHitSeg == -1) || (WallHitSeg > Highest_segment_index))));
591 //if(!get_seg_masks(&hit_info.hit_pnt, hit_info.hit_seg, 0, __FILE__, __LINE__).centermask == 0)
594 save_pos = obj->pos; //save the object's position
595 save_seg = obj->segnum;
597 // update object's position and segment number
601 if (obj == debug_obj)
602 printf(" new pos = %x %x %x\n",XYZ(&obj->pos));
605 if ( iseg != obj->segnum )
606 obj_relink(objnum, iseg );
608 //if start point not in segment, move object to center of segment
609 if (get_seg_masks(&obj->pos, obj->segnum, 0, __FILE__, __LINE__).centermask !=0 )
613 if ((n=find_object_seg(obj))==-1) {
615 if (obj->type==OBJ_PLAYER && (n=find_point_seg(&obj->last_pos,obj->segnum))!=-1) {
616 obj->pos = obj->last_pos;
617 obj_relink(objnum, n );
620 compute_segment_center(&obj->pos,&Segments[obj->segnum]);
621 obj->pos.x += objnum;
623 if (obj->type == OBJ_WEAPON)
624 obj->flags |= OF_SHOULD_BE_DEAD;
629 //calulate new sim time
631 //vms_vector moved_vec;
632 vms_vector moved_vec_n;
633 fix attempted_dist,actual_dist;
635 old_sim_time = sim_time;
637 actual_dist = vm_vec_normalized_dir(&moved_vec_n,&obj->pos,&save_pos);
639 if (fate==HIT_WALL && vm_vec_dot(&moved_vec_n,&frame_vec) < 0) { //moved backwards
641 //don't change position or sim_time
643 //******* mprintf((0, "Obj %d moved backwards\n", OBJECT_NUMBER(obj)));
646 if (obj == debug_obj)
647 printf(" Warning: moved backwards!\n");
652 //iseg = obj->segnum; //don't change segment
654 obj_relink(objnum, save_seg );
660 //if (obj == debug_obj)
661 // printf(" moved_vec = %x %x %x\n",XYZ(&moved_vec));
663 attempted_dist = vm_vec_mag(&frame_vec);
665 sim_time = fixmuldiv(sim_time,attempted_dist-actual_dist,attempted_dist);
667 moved_time = old_sim_time - sim_time;
669 if (sim_time < 0 || sim_time>old_sim_time) {
671 mprintf((0,"Bogus sim_time = %x, old = %x\n",sim_time,old_sim_time));
672 if (obj == debug_obj)
673 printf(" Bogus sim_time = %x, old = %x, attempted_dist = %x, actual_dist = %x\n",sim_time,old_sim_time,attempted_dist,actual_dist);
674 //Int3(); Removed by Rob
676 sim_time = old_sim_time;
677 //WHY DOES THIS HAPPEN??
684 if (obj == debug_obj)
685 printf(" new sim_time = %x\n",sim_time);
695 //@@fix total_d,moved_d;
696 fix hit_speed,wall_part;
700 vm_vec_sub(&moved_v,&obj->pos,&save_pos);
702 wall_part = vm_vec_dot(&moved_v,&hit_info.hit_wallnorm);
704 if (wall_part != 0 && moved_time>0 && (hit_speed=-fixdiv(wall_part,moved_time))>0)
705 collide_object_with_wall( obj, hit_speed, WallHitSeg, WallHitSide, &hit_info.hit_pnt );
707 scrape_object_on_wall(obj, WallHitSeg, WallHitSide, &hit_info.hit_pnt );
709 Assert( WallHitSeg > -1 );
710 Assert( WallHitSide > -1 );
712 if ( !(obj->flags&OF_SHOULD_BE_DEAD) ) {
713 int forcefield_bounce; //bounce off a forcefield
715 Assert(BounceCheat || !(obj->mtype.phys_info.flags & PF_STICK && obj->mtype.phys_info.flags & PF_BOUNCE)); //can't be bounce and stick
717 forcefield_bounce = (TmapInfo[Segments[WallHitSeg].sides[WallHitSide].tmap_num].flags & TMI_FORCE_FIELD);
719 if (!forcefield_bounce && (obj->mtype.phys_info.flags & PF_STICK)) { //stop moving
721 // mprintf((0, "Object %i stuck at %i:%i\n", OBJECT_NUMBER(obj), WallHitSeg, WallHitSide));
722 add_stuck_object(obj, WallHitSeg, WallHitSide);
724 vm_vec_zero(&obj->mtype.phys_info.velocity);
728 else { // Slide object along wall
731 //We're constrained by wall, so subtract wall part from
734 wall_part = vm_vec_dot(&hit_info.hit_wallnorm,&obj->mtype.phys_info.velocity);
736 // mprintf((0, "%d", f2i(vm_vec_mag(&hit_info.hit_wallnorm)) ));
738 if (forcefield_bounce || (obj->mtype.phys_info.flags & PF_BOUNCE)) { //bounce off wall
739 wall_part *= 2; //Subtract out wall part twice to achieve bounce
741 if (forcefield_bounce) {
742 check_vel = 1; //check for max velocity
743 if (obj->type == OBJ_PLAYER)
744 wall_part *= 2; //player bounce twice as much
747 if ( obj->mtype.phys_info.flags & PF_BOUNCES_TWICE) {
748 Assert(obj->mtype.phys_info.flags & PF_BOUNCE);
749 if (obj->mtype.phys_info.flags & PF_BOUNCED_ONCE)
750 obj->mtype.phys_info.flags &= ~(PF_BOUNCE+PF_BOUNCED_ONCE+PF_BOUNCES_TWICE);
752 obj->mtype.phys_info.flags |= PF_BOUNCED_ONCE;
755 bounced = 1; //this object bounced
758 vm_vec_scale_add2(&obj->mtype.phys_info.velocity,&hit_info.hit_wallnorm,-wall_part);
760 // mprintf((0, "Velocity at bounce time = %d\n", f2i(vm_vec_mag(&obj->mtype.phys_info.velocity))));
762 //if (obj==ConsoleObject)
763 // mprintf((0,"player vel = %x\n",vm_vec_mag_quick(&obj->mtype.phys_info.velocity)));
766 fix vel = vm_vec_mag_quick(&obj->mtype.phys_info.velocity);
768 if (vel > MAX_OBJECT_VEL)
769 vm_vec_scale(&obj->mtype.phys_info.velocity,fixdiv(MAX_OBJECT_VEL,vel));
772 if (bounced && obj->type == OBJ_WEAPON)
773 vm_vector_2_matrix(&obj->orient,&obj->mtype.phys_info.velocity,&obj->orient.uvec,NULL);
776 if (obj == debug_obj) {
777 printf(" sliding - wall_norm %x %x %x %x\n",wall_part,XYZ(&hit_info.hit_wallnorm));
778 printf(" wall_part %x, new velocity = %x %x %x\n",wall_part,XYZ(&obj->mtype.phys_info.velocity));
791 // Mark the hit object so that on a retry the fvi code
792 // ignores this object.
794 Assert(hit_info.hit_object != -1);
796 // Calculcate the hit point between the two objects.
797 { vms_vector *ppos0, *ppos1, pos_hit;
799 ppos0 = &Objects[hit_info.hit_object].pos;
801 size0 = Objects[hit_info.hit_object].size;
803 Assert(size0+size1 != 0); // Error, both sizes are 0, so how did they collide, anyway?!?
804 //vm_vec_scale(vm_vec_sub(&pos_hit, ppos1, ppos0), fixdiv(size0, size0 + size1));
805 //vm_vec_add2(&pos_hit, ppos0);
806 vm_vec_sub(&pos_hit, ppos1, ppos0);
807 vm_vec_scale_add(&pos_hit,ppos0,&pos_hit,fixdiv(size0, size0 + size1));
809 old_vel = obj->mtype.phys_info.velocity;
811 collide_two_objects( obj, &Objects[hit_info.hit_object], &pos_hit);
815 // Let object continue its movement
816 if ( !(obj->flags&OF_SHOULD_BE_DEAD) ) {
817 //obj->pos = save_pos;
819 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)) {
820 //if (Objects[hit_info.hit_object].type == OBJ_POWERUP)
821 ignore_obj_list[n_ignore_objs++] = hit_info.hit_object;
830 if (TactileStick && obj==ConsoleObject && !(FrameCount & 15))
831 Tactile_Xvibrate_clear ();
837 Int3(); // Unexpected collision type: start point not in specified segment.
838 mprintf((0,"Warning: Bad p0 in physics!!!\n"));
841 // Unknown collision type returned from find_vector_intersection!!
847 } while ( try_again );
849 // Pass retry count info to AI.
850 if (obj->control_type == CT_AI) {
852 Ai_local_info[objnum].retry_count = count-1;
854 Total_retries += count-1;
860 //I'm not sure why we do this. I wish there were a comment that
861 //explained it. I think maybe it only needs to be done if the object
862 //is sliding, but I don't know
863 if (!obj_stopped && !bounced) { //Set velocity from actual movement
864 vms_vector moved_vec;
866 vm_vec_sub(&moved_vec,&obj->pos,&start_pos);
867 vm_vec_copy_scale(&obj->mtype.phys_info.velocity,&moved_vec,fixdiv(f1_0,FrameTime));
870 if (obj==ConsoleObject && (obj->mtype.phys_info.velocity.x==0 && obj->mtype.phys_info.velocity.y==0 && obj->mtype.phys_info.velocity.z==0) &&
871 !(obj->mtype.phys_info.thrust.x==0 && obj->mtype.phys_info.thrust.y==0 && obj->mtype.phys_info.thrust.z==0)) {
872 vms_vector center,bump_vec;
874 //bump player a little towards center of segment to unstick
876 compute_segment_center(¢er,&Segments[obj->segnum]);
877 vm_vec_normalized_dir_quick(&bump_vec,¢er,&obj->pos);
879 //don't bump player toward center of reactor segment
880 if (Segment2s[obj->segnum].special == SEGMENT_IS_CONTROLCEN)
881 vm_vec_negate(&bump_vec);
883 vm_vec_scale_add2(&obj->pos,&bump_vec,obj->size/5);
885 //if moving away from seg, might move out of seg, so update
886 if (Segment2s[obj->segnum].special == SEGMENT_IS_CONTROLCEN)
887 update_object_seg(obj);
892 //Assert(check_point_in_seg(&obj->pos,obj->segnum,0).centermask==0);
894 //if (obj->control_type == CT_FLYING)
895 if (obj->mtype.phys_info.flags & PF_LEVELLING)
896 do_physics_align_object( obj );
899 //hack to keep player from going through closed doors
900 if (obj->type==OBJ_PLAYER && obj->segnum!=orig_segnum && (Physics_cheat_flag!=0xBADA55) ) {
903 sidenum = find_connect_side(&Segments[obj->segnum],&Segments[orig_segnum]);
907 if (! (WALL_IS_DOORWAY(&Segments[orig_segnum],sidenum) & WID_FLY_FLAG)) {
909 int vertnum,num_faces,i;
915 s = &Segments[orig_segnum].sides[sidenum];
918 Error("orig_segnum == -1 in physics");
920 create_abs_vertex_lists(&num_faces, vertex_list, orig_segnum, sidenum, __FILE__, __LINE__);
922 //let's pretend this wall is not triangulated
923 vertnum = vertex_list[0];
925 if (vertex_list[i] < vertnum)
926 vertnum = vertex_list[i];
931 get_side_normal(&Segments[orig_segnum], sidenum, 0, &_vn );
932 dist = vm_dist_to_plane(&start_pos, &_vn, &Vertices[vertnum]);
933 vm_vec_scale_add(&obj->pos,&start_pos,&_vn,obj->size-dist);
936 dist = vm_dist_to_plane(&start_pos, &s->normals[0], &Vertices[vertnum]);
937 vm_vec_scale_add(&obj->pos,&start_pos,&s->normals[0],obj->size-dist);
939 update_object_seg(obj);
945 //--WE ALWYS WANT THIS IN, MATT AND MIKE DECISION ON 12/10/94, TWO MONTHS AFTER FINAL #ifndef NDEBUG
946 //if end point not in segment, move object to last pos, or segment center
947 if (get_seg_masks(&obj->pos, obj->segnum, 0, __FILE__, __LINE__).centermask != 0)
949 if (find_object_seg(obj)==-1) {
953 if (obj->type==OBJ_PLAYER && (n=find_point_seg(&obj->last_pos,obj->segnum))!=-1) {
954 obj->pos = obj->last_pos;
955 obj_relink(objnum, n );
958 compute_segment_center(&obj->pos,&Segments[obj->segnum]);
959 obj->pos.x += objnum;
961 if (obj->type == OBJ_WEAPON)
962 obj->flags |= OF_SHOULD_BE_DEAD;
965 //--WE ALWYS WANT THIS IN, MATT AND MIKE DECISION ON 12/10/94, TWO MONTHS AFTER FINAL #endif
970 //--unused-- //tell us what the given object will do (as far as hiting walls) in
971 //--unused-- //the given time (in seconds) t. Igores acceleration (sorry)
972 //--unused-- //if check_objects is set, check with objects, else just with walls
973 //--unused-- //returns fate, fills in hit time. If fate==HIT_NONE, hit_time undefined
974 //--unused-- int physics_lookahead(object *obj,fix t,int fvi_flags,fix *hit_time, fvi_info *hit_info)
976 //--unused-- vms_vector new_pos;
977 //--unused-- int objnum,fate;
978 //--unused-- fvi_query fq;
980 //--unused-- Assert(obj->movement_type == MT_PHYSICS);
982 //--unused-- objnum = OBJECT_NUMBER(obj);
984 //--unused-- vm_vec_scale_add(&new_pos, &obj->pos, &obj->mtype.phys_info.velocity, t);
986 //--unused-- fq.p0 = &obj->pos;
987 //--unused-- fq.startseg = obj->segnum;
988 //--unused-- fq.p1 = &new_pos;
989 //--unused-- fq.rad = obj->size;
990 //--unused-- fq.thisobjnum = objnum;
991 //--unused-- fq.ignore_obj_list = NULL;
992 //--unused-- fq.flags = fvi_flags;
994 //--unused-- fate = find_vector_intersection(&fq,hit_info);
996 //--unused-- if (fate != HIT_NONE) {
997 //--unused-- fix dist,speed;
999 //--unused-- dist = vm_vec_dist(&obj->pos, &hit_info->hit_pnt);
1001 //--unused-- speed = vm_vec_mag(&obj->mtype.phys_info.velocity);
1003 //--unused-- *hit_time = fixdiv(dist,speed);
1007 //--unused-- return fate;
1011 //Applies an instantaneous force on an object, resulting in an instantaneous
1012 //change in velocity.
1013 void phys_apply_force(object *obj,vms_vector *force_vec)
1016 // Put in by MK on 2/13/96 for force getting applied to Omega blobs, which have 0 mass,
1017 // in collision with crazy reactor robot thing on d2levf-s.
1018 if (obj->mtype.phys_info.mass == 0)
1021 if (obj->movement_type != MT_PHYSICS)
1025 if (TactileStick && obj==&Objects[Players[Player_num].objnum])
1026 Tactile_apply_force (force_vec,&obj->orient);
1029 //Add in acceleration due to force
1030 vm_vec_scale_add2(&obj->mtype.phys_info.velocity,force_vec,fixdiv(f1_0,obj->mtype.phys_info.mass));
1035 // ----------------------------------------------------------------
1036 // Do *dest = *delta unless:
1037 // *delta is pretty small
1038 // and they are of different signs.
1039 void physics_set_rotvel_and_saturate(fix *dest, fix delta)
1041 if ((delta ^ *dest) < 0) {
1042 if (abs(delta) < F1_0/8) {
1043 // mprintf((0, "D"));
1046 // mprintf((0, "d"));
1049 // mprintf((0, "!"));
1054 // ------------------------------------------------------------------------------------------------------
1055 // Note: This is the old ai_turn_towards_vector code.
1056 // phys_apply_rot used to call ai_turn_towards_vector until I fixed it, which broke phys_apply_rot.
1057 void physics_turn_towards_vector(vms_vector *goal_vector, object *obj, fix rate)
1059 vms_angvec dest_angles, cur_angles;
1060 fix delta_p, delta_h;
1061 vms_vector *rotvel_ptr = &obj->mtype.phys_info.rotvel;
1063 // Make this object turn towards the goal_vector. Changes orientation, doesn't change direction of movement.
1064 // If no one moves, will be facing goal_vector in 1 second.
1066 // Detect null vector.
1067 if ((goal_vector->x == 0) && (goal_vector->y == 0) && (goal_vector->z == 0))
1070 // Make morph objects turn more slowly.
1071 if (obj->control_type == CT_MORPH)
1074 vm_extract_angles_vector(&dest_angles, goal_vector);
1075 vm_extract_angles_vector(&cur_angles, &obj->orient.fvec);
1077 delta_p = (dest_angles.p - cur_angles.p);
1078 delta_h = (dest_angles.h - cur_angles.h);
1080 if (delta_p > F1_0/2) delta_p = dest_angles.p - cur_angles.p - F1_0;
1081 if (delta_p < -F1_0/2) delta_p = dest_angles.p - cur_angles.p + F1_0;
1082 if (delta_h > F1_0/2) delta_h = dest_angles.h - cur_angles.h - F1_0;
1083 if (delta_h < -F1_0/2) delta_h = dest_angles.h - cur_angles.h + F1_0;
1085 delta_p = fixdiv(delta_p, rate);
1086 delta_h = fixdiv(delta_h, rate);
1088 if (abs(delta_p) < F1_0/16) delta_p *= 4;
1089 if (abs(delta_h) < F1_0/16) delta_h *= 4;
1091 physics_set_rotvel_and_saturate(&rotvel_ptr->x, delta_p);
1092 physics_set_rotvel_and_saturate(&rotvel_ptr->y, delta_h);
1096 // -----------------------------------------------------------------------------
1097 // Applies an instantaneous whack on an object, resulting in an instantaneous
1098 // change in orientation.
1099 void phys_apply_rot(object *obj,vms_vector *force_vec)
1103 if (obj->movement_type != MT_PHYSICS)
1106 vecmag = vm_vec_mag(force_vec)/8;
1107 if (vecmag < F1_0/256)
1109 else if (vecmag < obj->mtype.phys_info.mass >> 14)
1112 rate = fixdiv(obj->mtype.phys_info.mass, vecmag);
1113 if (obj->type == OBJ_ROBOT) {
1116 // Changed by mk, 10/24/95, claw guys should not slow down when attacking!
1117 if (!Robot_info[obj->id].thief && !Robot_info[obj->id].attack_type) {
1118 if (obj->ctype.ai_info.SKIP_AI_COUNT * FrameTime < 3*F1_0/4) {
1119 fix tval = fixdiv(F1_0, 8*FrameTime);
1124 if ( (d_rand() * 2) < (tval & 0xffff))
1126 obj->ctype.ai_info.SKIP_AI_COUNT += addval;
1127 // -- mk: too much stuff making hard to see my debug messages...mprintf((0, "FrameTime = %7.3f, addval = %i\n", f2fl(FrameTime), addval));
1136 // Turn amount inversely proportional to mass. Third parameter is seconds to do 360 turn.
1137 physics_turn_towards_vector(force_vec, obj, rate);
1143 //this routine will set the thrust for an object to a value that will
1144 //(hopefully) maintain the object's current velocity
1145 void set_thrust_from_velocity(object *obj)
1149 Assert(obj->movement_type == MT_PHYSICS);
1151 k = fixmuldiv(obj->mtype.phys_info.mass,obj->mtype.phys_info.drag,(f1_0-obj->mtype.phys_info.drag));
1153 vm_vec_copy_scale(&obj->mtype.phys_info.thrust,&obj->mtype.phys_info.velocity,k);