Exemple #1
0
//find which side to fly out of
find_exit_side(object *obj)
{
	int i;
	vms_vector prefvec,segcenter,sidevec;
	fix best_val=-f2_0;
	int best_side;
	segment *pseg = &Segments[obj->segnum];

	//find exit side

	vm_vec_normalized_dir_quick(&prefvec,&obj->pos,&obj->last_pos);

	compute_segment_center(&segcenter,pseg);

	best_side=-1;
	for (i=MAX_SIDES_PER_SEGMENT;--i >= 0;) {
		fix d;

		if (pseg->children[i]!=-1) {

			compute_center_point_on_side(&sidevec,pseg,i);
			vm_vec_normalized_dir_quick(&sidevec,&sidevec,&segcenter);
			d = vm_vec_dotprod(&sidevec,&prefvec);

			if (labs(d) < MIN_D) d=0;

			if (d > best_val) {best_val=d; best_side=i;}

		}
	}

	Assert(best_side!=-1);

	return best_side;
}
void physics_apply_shock(vec3d *direction_vec, float pressure, physics_info *pi, matrix *orient, vec3d *min, vec3d *max, float radius)
{
	vec3d normal;
	vec3d local_torque, temp_torque, torque;
	vec3d impact_vec;
	vec3d area;
	vec3d sin;

	if (radius > MAX_RADIUS) {
		return;
	}

	vm_vec_normalize_safe ( direction_vec );

	area.xyz.x = (max->xyz.y - min->xyz.z) * (max->xyz.z - min->xyz.z);
	area.xyz.y = (max->xyz.x - min->xyz.x) * (max->xyz.z - min->xyz.z);
	area.xyz.z = (max->xyz.x - min->xyz.x) * (max->xyz.y - min->xyz.y);

	normal.xyz.x = vm_vec_dotprod( direction_vec, &orient->vec.rvec );
	normal.xyz.y = vm_vec_dotprod( direction_vec, &orient->vec.uvec );
	normal.xyz.z = vm_vec_dotprod( direction_vec, &orient->vec.fvec );

	sin.xyz.x = fl_sqrt( fl_abs(1.0f - normal.xyz.x*normal.xyz.x) );
	sin.xyz.y = fl_sqrt( fl_abs(1.0f - normal.xyz.y*normal.xyz.y) );
	sin.xyz.z = fl_sqrt( fl_abs(1.0f - normal.xyz.z*normal.xyz.z) );

	vm_vec_make( &torque, 0.0f, 0.0f, 0.0f );

	// find the torque exerted due to the shockwave hitting each face
	//  model the effect of the shockwave as if the shockwave were a plane of projectiles,
	//  all moving in the direction direction_vec.  then find the torque as the cross prod
	//  of the force (pressure * area * normal * sin * scale * mass)
	//  normal takes account the fraction of the surface exposed to the shockwave
	//  the sin term is not technically needed but "feels" better
	//  scale factors out the increase in area with larger objects
	//  more massive objects get less rotation

	// find torque due to forces on the right/left face
	if ( normal.xyz.x < 0.0f )		// normal < 0, hits the right face
		vm_vec_copy_scale( &impact_vec, &orient->vec.rvec, max->xyz.x * pressure * area.xyz.x *  normal.xyz.x * sin.xyz.x / pi->mass );
	else								// normal > 0, hits the left face
		vm_vec_copy_scale( &impact_vec, &orient->vec.rvec, min->xyz.x * pressure * area.xyz.x * -normal.xyz.x * sin.xyz.x / pi->mass );

	vm_vec_crossprod( &temp_torque, &impact_vec, direction_vec );
	vm_vec_add2( &torque, &temp_torque );

	// find torque due to forces on the up/down face
	if ( normal.xyz.y < 0.0f )
		vm_vec_copy_scale( &impact_vec, &orient->vec.uvec, max->xyz.y * pressure * area.xyz.y *  normal.xyz.y * sin.xyz.y / pi->mass );
	else
		vm_vec_copy_scale( &impact_vec, &orient->vec.uvec, min->xyz.y * pressure * area.xyz.y * -normal.xyz.y * sin.xyz.y / pi->mass );

	vm_vec_crossprod( &temp_torque, &impact_vec, direction_vec );
	vm_vec_add2( &torque, &temp_torque );

	// find torque due to forces on the forward/backward face
	if ( normal.xyz.z < 0.0f )
		vm_vec_copy_scale( &impact_vec, &orient->vec.fvec, max->xyz.z * pressure * area.xyz.z *  normal.xyz.z * sin.xyz.z / pi->mass );
	else
		vm_vec_copy_scale( &impact_vec, &orient->vec.fvec, min->xyz.z * pressure * area.xyz.z * -normal.xyz.z * sin.xyz.z / pi->mass );

	vm_vec_crossprod( &temp_torque, &impact_vec, direction_vec );
	vm_vec_add2( &torque, &temp_torque );

	// compute delta rotvel, scale according to blast and radius
	float scale;

	if (radius < MIN_RADIUS) {
		scale = 1.0f;
	} else {
		scale = (MAX_RADIUS - radius)/(MAX_RADIUS-MIN_RADIUS);
	}

	// set shockwave shake amplitude, duration, flag
	pi->shockwave_shake_amp = (float)(MAX_SHAKE*(pressure/STD_PRESSURE)*scale);
	pi->shockwave_decay = timestamp( SW_BLAST_DURATION );
	pi->flags |= PF_IN_SHOCKWAVE;

	// safety dance
	if (!(IS_VEC_NULL_SQ_SAFE(&torque))) {
		vec3d delta_rotvel;
		vm_vec_rotate( &local_torque, &torque, orient );
		vm_vec_copy_normalize(&delta_rotvel, &local_torque);
		
		vm_vec_scale(&delta_rotvel, (float)(MAX_ROTVEL*(pressure/STD_PRESSURE)*scale));
		// nprintf(("Physics", "rotvel scale %f\n", (MAX_ROTVEL*(pressure/STD_PRESSURE)*scale)));
		vm_vec_add2(&pi->rotvel, &delta_rotvel);
	}

	// set reduced translational damping, set flags
	float velocity_scale = (float)MAX_VEL*scale;
	pi->flags |= PF_REDUCED_DAMP;
	update_reduced_damp_timestamp( pi, velocity_scale*pi->mass );
	vm_vec_scale_add2( &pi->vel, direction_vec, velocity_scale );
	vm_vec_rotate(&pi->prev_ramp_vel, &pi->vel, orient);	// set so velocity will ramp starting from current speed

	// check that kick from shockwave is not too large
	if (!(pi->flags & PF_USE_VEL) && (vm_vec_mag_squared(&pi->vel) > MAX_SHIP_SPEED*MAX_SHIP_SPEED)) {
		// Get DaveA
		nprintf(("Physics", "speed reset in physics_apply_shock [speed: %f]\n", vm_vec_mag(&pi->vel)));
		vm_vec_normalize(&pi->vel);
		vm_vec_scale(&pi->vel, (float)RESET_SHIP_SPEED);
	}
}
// Returns TRUE if the weapon will never hit the other object.
// If it can it predicts how long until these two objects need
// to be checked and fills the time in in current_pair.
int weapon_will_never_hit( object *obj_weapon, object *other, obj_pair * current_pair )
{

	Assert( obj_weapon->type == OBJ_WEAPON );
	weapon *wp = &Weapons[obj_weapon->instance];
	weapon_info *wip = &Weapon_info[wp->weapon_info_index];

//	mprintf(( "Frame: %d,  Weapon=%d, Other=%d, pair=$%08x\n", G3_frame_count, OBJ_INDEX(weapon), OBJ_INDEX(other), current_pair ));
	

	// Do some checks for weapons that don't turn
	if ( !(wip->wi_flags & WIF_TURNS) )	{

		// This first check is to see if a weapon is behind an object, and they
		// are heading in opposite directions.   If so, we don't need to ever check	
		// them again.   This is only valid for weapons that don't turn. 

		float vdot;
		if (wip->subtype == WP_LASER) {
			vec3d velocity_rel_weapon;
			vm_vec_sub(&velocity_rel_weapon, &obj_weapon->phys_info.vel, &other->phys_info.vel);
			vdot = -vm_vec_dot(&velocity_rel_weapon, &obj_weapon->orient.vec.fvec);
		} else {
			vdot = vm_vec_dot( &other->phys_info.vel, &obj_weapon->phys_info.vel);
		}
		if ( vdot <= 0.0f )	{
			// They're heading in opposite directions...
			// check their positions
			vec3d weapon2other;
			vm_vec_sub( &weapon2other, &other->pos, &obj_weapon->pos );
			float pdot = vm_vec_dot( &obj_weapon->orient.vec.fvec, &weapon2other );
			if ( pdot <= -other->radius )	{
				// The other object is behind the weapon by more than
				// its radius, so it will never hit...
				return 1;
			}
		}

		// FUTURE ENHANCEMENT IDEAS 

		// Given a laser does it hit a slow or not moving object
		// in its life or the next n seconds?  We'd actually need to check the 
		// model for this.
				
	}


	// This check doesn't care about orient, only looks at the maximum speed
	// of the two objects, so it knows that in the next n seconds, they can't
	// go further than some distance, so don't bother checking collisions for 
	// that time.   This is very rough, but is so general that it works for
	// everything and immidiately gets rid of a lot of cases.
	
	if ( current_pair )	{
		// Find the time it will take before these get within each others distances.
		// tmp->next_check_time = timestamp(500);
		//vector	max_vel;			//maximum foward velocity in x,y,z

		float max_vel_weapon, max_vel_other;

		//SUSHI: Fix bug where additive weapon velocity screws up collisions
		//Assumes that weapons which don't home don't change speed, which is currently the case.
		if (!(wip->wi_flags & WIF_TURNS))
			max_vel_weapon = obj_weapon->phys_info.speed;
		else if (wp->lssm_stage==5)
			max_vel_weapon = wip->lssm_stage5_vel;
		else
			max_vel_weapon = wp->weapon_max_vel;

		max_vel_other = other->phys_info.max_vel.xyz.z;
		if (max_vel_other < 10.0f) {
			if ( vm_vec_mag_squared( &other->phys_info.vel ) > 100 ) {
				// bump up velocity from collision
				max_vel_other = vm_vec_mag( &other->phys_info.vel ) + 10.0f;
			} else {
				max_vel_other = 10.0f;		// object may move from collision
			}
		}

		// check weapon that does not turn against sphere expanding at ship maxvel
		// compare (weeapon) ray with expanding sphere (ship) to find earliest possible collision time
		// look for two time solutions to Xw = Xs, where Xw = Xw0 + Vwt*t  Xs = Xs + Vs*(t+dt), where Vs*dt = radius of ship 
		// Since direction of Vs is unknown, solve for (Vs*t) and find norm of both sides
		if ( !(wip->wi_flags & WIF_TURNS) ) {
			vec3d delta_x, laser_vel;
			float a,b,c, delta_x_dot_vl, delta_t;
			float root1, root2, root, earliest_time;

			if (max_vel_weapon == max_vel_other) {
				// this will give us NAN using the below formula, so check every frame
				current_pair->next_check_time = timestamp(0);
				return 0;
			}

			vm_vec_sub( &delta_x, &obj_weapon->pos, &other->pos );
			laser_vel = obj_weapon->phys_info.vel;
			// vm_vec_copy_scale( &laser_vel, &weapon->orient.vec.fvec, max_vel_weapon );
			delta_t = (other->radius + 10.0f) / max_vel_other;		// time to get from center to radius of other obj
			delta_x_dot_vl = vm_vec_dotprod( &delta_x, &laser_vel );

			a = max_vel_weapon*max_vel_weapon - max_vel_other*max_vel_other;
			b = 2.0f * (delta_x_dot_vl - max_vel_other*max_vel_other*delta_t);
			c = vm_vec_mag_squared( &delta_x ) - max_vel_other*max_vel_other*delta_t*delta_t;

			float discriminant = b*b - 4.0f*a*c;
			if ( discriminant < 0) {
				// never hit
				return 1;
			} else {
				root = fl_sqrt( discriminant );
				root1 = (-b + root) / (2.0f * a) * 1000.0f;	// get time in ms
				root2 = (-b - root) / (2.0f * a) * 1000.0f;	// get time in ms
			}

			// standard algorithm
			if (max_vel_weapon > max_vel_other) {
				// find earliest positive time
				if ( root1 > root2 ) {
					float temp = root1;
					root1 = root2;
					root2 = temp;
				}

				if (root1 > 0) {
					earliest_time = root1;
				} else if (root2 > 0) {
					// root1 < 0 and root2 > 0, so we're inside sphere and next check should be next frame
					current_pair->next_check_time = timestamp(0);	// check next time
					return 0;
				} else {
					// both times negative, so never collides
					return 1;
				}
			}
			// need to modify it for weapons that are slower than ships
			else {
				if (root2 > 0) {
					earliest_time = root2;
				} else {
					current_pair->next_check_time = timestamp(0);
					return 0;
				}
			}



			// check if possible collision occurs after weapon expires
			if ( earliest_time > 1000*wp->lifeleft )
				return 1;

			// Allow one worst case frametime to elapse (~5 fps)
			earliest_time -= 200.0f;

			if (earliest_time > 100) {
				current_pair->next_check_time = timestamp( fl2i(earliest_time) );
				return 0;
			} else {
				current_pair->next_check_time = timestamp(0);	// check next time
				return 0;
			}

		} else {

			float dist, max_vel, time;

			max_vel = max_vel_weapon + max_vel_other;

			// suggest that fudge factor for other radius be changed to other_radius + const (~10)
			dist = vm_vec_dist( &other->pos, &obj_weapon->pos ) - (other->radius + 10.0f);
			if ( dist > 0.0f )	{
				time = (dist*1000.0f) / max_vel;
				int time_ms = fl2i(time);

				// check if possible collision occurs after weapon expires
				if ( time_ms > 1000*wp->lifeleft )
					return 1;

				time_ms -= 200;	// Allow at least one worst case frametime to elapse (~5 fps)
						
				if ( time_ms > 100 )	{		// If it takes longer than 1/10th of a second, then delay it
					current_pair->next_check_time = timestamp(time_ms);
					//mprintf(( "Delaying %d ms\n", time_ms ));
					return 0;
				}
			}
			current_pair->next_check_time = timestamp(0);	// check next time

		}
	}

	return 0;
}
Exemple #4
0
void objfly_move_to_new_segment( object * obj, short newseg, int first_time )
{
	segment *pseg;
	int old_object_seg = obj->segnum;

	if ( newseg != obj->segnum )
		obj_relink(obj-Objects, newseg );

	pseg = &Segments[obj->segnum];

	if ( first_time || obj->segnum != old_object_seg) {		//moved into new seg
		vms_vector curcenter,nextcenter;
		fix step_size,seg_time;
		short entry_side,exit_side;	//what sides we entry and leave through
		vms_vector dest_point;		//where we are heading (center of exit_side)
		vms_angvec dest_angles;		//where we want to be pointing

		//find new exit side

		if ( !first_time ) {

			entry_side = matt_find_connect_side(obj->segnum,old_object_seg);
			exit_side = Side_opposite[entry_side];
		}

		//if (first_time) obj->fly_info.ft_mode = FP_FORWARD;

		if (first_time || entry_side==-1 || (pseg->children[exit_side]==-1) || (obj->fly_info.ft_mode!=FP_FORWARD) ) {
			int i;
			vms_vector prefvec,segcenter,sidevec;
			fix best_val=-f2_0;
			int best_side;

			//find exit side

			if (obj->fly_info.ft_mode == FP_FORWARD) {
				if (first_time) 
					prefvec = obj->orient.fvec;
				else
					prefvec = obj->fly_info.heading;
				vm_vec_normalize(&prefvec);
			}
			else
				prefvec = obj->orient.vecs[obj->fly_info.ft_mode%3];

			if (obj->fly_info.ft_mode >= 3) {prefvec.x = -prefvec.x; prefvec.y = -prefvec.y; prefvec.z = -prefvec.z;}

			compute_segment_center(&segcenter,pseg);

			best_side=-1;
			for (i=MAX_SIDES_PER_SEGMENT;--i >= 0;) {
				fix d;

				if (pseg->children[i]!=-1) {

					compute_center_point_on_side(&sidevec,pseg,i);
					vm_vec_sub2(&sidevec,&segcenter);
					vm_vec_normalize(&sidevec);
					d = vm_vec_dotprod(&sidevec,&prefvec);

					if (labs(d) < MIN_D) d=0;

					if (d > best_val || (d==best_val && i==exit_side)) {best_val=d; best_side=i;}

				}
			}

			if (best_val > 0) obj->fly_info.ft_mode = FP_FORWARD;

			Assert(best_side!=-1);

			exit_side = best_side;
		}

		//update target point & angles

		compute_center_point_on_side(&dest_point,pseg,exit_side);

		//update target point and movement points

		vm_vec_sub(&obj->phys_info.velocity,&dest_point,&obj->pos);
		step_size = vm_vec_normalize(&obj->phys_info.velocity);
		vm_vec_scale(&obj->phys_info.velocity, obj->phys_info.speed);

		compute_segment_center(&curcenter,pseg);
		compute_segment_center(&nextcenter,&Segments[pseg->children[exit_side]]);
		vm_vec_sub(&obj->fly_info.heading,&nextcenter,&curcenter);

		angles_from_vector(&dest_angles,&obj->fly_info.heading);	//extract angles

		if (first_time) 
			angles_from_vector(&obj->phys_info.rotvel,&obj->orient.fvec);

		seg_time = fixdiv(step_size,obj->phys_info.speed);	//how long through seg

		if (seg_time) {
			obj->fly_info.angle_step.p = fixdiv(delta_ang(obj->phys_info.rotvel.p,dest_angles.p),seg_time);
			obj->fly_info.angle_step.b = fixdiv(delta_ang(obj->phys_info.rotvel.b,dest_angles.b),seg_time);
			obj->fly_info.angle_step.h = fixdiv(delta_ang(obj->phys_info.rotvel.h,dest_angles.h),seg_time);
		}
		else {
			obj->phys_info.rotvel = dest_angles;
			obj->fly_info.angle_step.p = obj->fly_info.angle_step.b = obj->fly_info.angle_step.h = 0;
		}
	}
}
/**
 * When inside radius of big ship, check if we can cull collision pair determine the time when pair should next be checked
 * @return 1 if pair can be culled
 * @return 0 if pair can not be culled
 */
int check_inside_radius_for_big_ships( object *ship, object *weapon, obj_pair *pair )
{
	vec3d error_vel;		// vel perpendicular to laser
	float error_vel_mag;	// magnitude of error_vel
	float time_to_max_error, time_to_exit_sphere;
	float ship_speed_at_exit_sphere, error_at_exit_sphere;	
	float max_error = (float) ERROR_STD / 150.0f * ship->radius;
	if (max_error < 2)
		max_error = 2.0f;

	time_to_exit_sphere = (ship->radius + vm_vec_dist(&ship->pos, &weapon->pos)) / (weapon->phys_info.max_vel.xyz.z - ship->phys_info.max_vel.xyz.z);
	ship_speed_at_exit_sphere = estimate_ship_speed_upper_limit( ship, time_to_exit_sphere );
	// update estimated time to exit sphere
	time_to_exit_sphere = (ship->radius + vm_vec_dist(&ship->pos, &weapon->pos)) / (weapon->phys_info.max_vel.xyz.z - ship_speed_at_exit_sphere);
	vm_vec_scale_add( &error_vel, &ship->phys_info.vel, &weapon->orient.vec.fvec, -vm_vec_dotprod(&ship->phys_info.vel, &weapon->orient.vec.fvec) );
	error_vel_mag = vm_vec_mag_quick( &error_vel );
	error_vel_mag += 0.5f * (ship->phys_info.max_vel.xyz.z - error_vel_mag)*(time_to_exit_sphere/ship->phys_info.forward_accel_time_const);
	// error_vel_mag is now average velocity over period
	error_at_exit_sphere = error_vel_mag * time_to_exit_sphere;
	time_to_max_error = max_error / error_at_exit_sphere * time_to_exit_sphere;

	// find the minimum time we can safely check into the future.
	// limited by (1) time to exit sphere (2) time to weapon expires
	// if ship_weapon_check_collision comes back with a hit_time > error limit, ok
	// if ship_weapon_check_collision comes finds no collision, next check time based on error time
	float limit_time;		// furthest time to check (either lifetime or exit sphere)
	if ( time_to_exit_sphere < Weapons[weapon->instance].lifeleft ) {
		limit_time = time_to_exit_sphere;
	} else {
		limit_time = Weapons[weapon->instance].lifeleft;
	}

	// Note:  when estimated hit time is less than 200 ms, look at every frame
	int hit_time;	// estimated time of hit in ms

	// modify ship_weapon_check_collision to do damage if hit_time is negative (ie, hit occurs in this frame)
	if ( ship_weapon_check_collision( ship, weapon, limit_time, &hit_time ) ) {
		// hit occured in while in sphere
		if (hit_time < 0) {
			// hit occured in the frame
			return 1;
		} else if (hit_time > 200) {
			pair->next_check_time = timestamp(hit_time - 200);
			return 0;
			// set next check time to time - 200
		} else {
			// set next check time to next frame
			pair->next_check_time = 1;
			return 0;
		}
	} else {
		if (limit_time > time_to_max_error) {
		// no hit, but beyond error tolerance
			if (1000*time_to_max_error > 200) {
				pair->next_check_time = timestamp( (int)(1000*time_to_max_error) - 200 );
			} else {
				pair->next_check_time = 1;
			}
			return 0;
		} else {
			// no hit and within error tolerance
			return 1;
		}
	}
}
Exemple #6
0
do_flythrough(object *obj,int first_time)		//set true if init
{
	segment *pseg;
	int old_player_seg = obj->segnum;

	if (first_time) {
		//vms_vector zero_vector = {0,0,0};

		obj->control_type = CT_FLYTHROUGH;

		//obj->fly_info.angle_step.p = 0;
		//obj->fly_info.angle_step.b = 0;
		//obj->fly_info.angle_step.h = 0;
		//obj->fly_info.heading = zero_vector;

	}
	
	//move the player for this frame

	if (!first_time) {
		//vms_vector tempv;
		//fix rot_step;

		vm_vec_scale_add2(&obj->pos,&player_step,FrameTime);
		angvec_add2_scale(&player_angles,&player_angstep,FrameTime);

		vm_angles_2_matrix(&obj->orient,&player_angles);
	}

	//check new player seg

	update_object_seg(obj);
	pseg = &Segments[obj->segnum];

	if (first_time || obj->segnum != old_player_seg) {		//moved into new seg
		vms_vector curcenter,nextcenter;
		fix step_size,seg_time;
		short entry_side,exit_side;	//what sides we entry and leave through
		vms_vector dest_point;		//where we are heading (center of exit_side)
		vms_angvec dest_angles;		//where we want to be pointing

		//find new exit side

		if (!first_time) {

			entry_side = matt_find_connect_side(obj->segnum,old_player_seg);
			exit_side = Side_opposite[entry_side];
		}

		if (first_time) ft_preference = FP_FORWARD;

		if (first_time || entry_side==-1 || pseg->children[exit_side]==-1 || ft_preference!=FP_FORWARD) {
			int i;
			vms_vector prefvec,segcenter,sidevec;
			fix best_val=-f2_0;
			int best_side;

			//find exit side

			if (ft_preference == FP_FORWARD) {
				if (first_time) prefvec = obj->orient.fvec;
				else prefvec = headvec;
				vm_vec_normalize(&prefvec);
			}
			else
				prefvec = obj->orient.vecs[ft_preference%3];

			if (ft_preference >= 3) {prefvec.x = -prefvec.x; prefvec.y = -prefvec.y; prefvec.z = -prefvec.z;}

			compute_segment_center(&segcenter,pseg);

			best_side=-1;
			for (i=MAX_SIDES_PER_SEGMENT;--i >= 0;) {
				fix d;

				if (pseg->children[i]!=-1) {

					compute_center_point_on_side(&sidevec,pseg,i);
					//vm_vec_sub2(&sidevec,&segcenter);
					//vm_vec_normalize(&sidevec);
					vm_vec_normalized_dir(&sidevec,&sidevec,&segcenter);
					d = vm_vec_dotprod(&sidevec,&prefvec);

					if (labs(d) < MIN_D) d=0;

					if (d > best_val || (d==best_val && i==exit_side)) {best_val=d; best_side=i;}

				}
			}

			if (best_val > 0) ft_preference = FP_FORWARD;

			Assert(best_side!=-1);

			exit_side = best_side;
		}

		//update target point & angles

		compute_center_point_on_side(&dest_point,pseg,exit_side);

		//update target point and movement points

		vm_vec_sub(&player_step,&dest_point,&obj->pos);
		step_size = vm_vec_normalize(&player_step);
		vm_vec_scale(&player_step,player_speed);

		compute_segment_center(&curcenter,pseg);
		compute_segment_center(&nextcenter,&Segments[pseg->children[exit_side]]);
		vm_vec_sub(&headvec,&nextcenter,&curcenter);

		//angles_from_vector(&dest_angles,&headvec);	//extract angles
		vm_extract_angles_vector(&dest_angles,&headvec);	//extract angles

		if (first_time)
			//angles_from_vector(&player_angles,&obj->orient.fvec);
			vm_extract_angles_vector(&player_angles,&obj->orient.fvec);

		seg_time = fixdiv(step_size,player_speed);	//how long through seg

		if (seg_time) {
			player_angstep.p = fixdiv(delta_ang(player_angles.p,dest_angles.p),seg_time);
			player_angstep.b = fixdiv(delta_ang(player_angles.b,dest_angles.b),seg_time);
			player_angstep.h = fixdiv(delta_ang(player_angles.h,dest_angles.h),seg_time);
		}
		else {
			player_angles = dest_angles;
			player_angstep.p = player_angstep.b = player_angstep.h = 0;
		}
	}
}