Esempio n. 1
0
// -----------------------------------------------------------------------------
//	Increase the size of Cursegp in dimension dimension by amount
int segsize_common(int dimension, fix amount)
{
    int	i;
    int	propagated[MAX_SIDES_PER_SEGMENT];
    vms_vector	uvec, rvec, fvec, scalevec;

    Degenerate_segment_found = 0;

    med_scale_segment_new(Cursegp, dimension, amount);

    med_extract_up_vector_from_segment_side(Cursegp, Curside, &uvec);
    med_extract_right_vector_from_segment_side(Cursegp, Curside, &rvec);
    extract_forward_vector_from_segment(Cursegp, &fvec);

    scalevec.x = vm_vec_mag(&rvec);
    scalevec.y = vm_vec_mag(&uvec);
    scalevec.z = vm_vec_mag(&fvec);

    if (Degenerate_segment_found) {
        Degenerate_segment_found = 0;
        // mprintf(0, "Applying scale would create degenerate segments.  Aborting scale.\n");
        editor_status("Applying scale would create degenerate segments.  Aborting scale.");
        med_scale_segment_new(Cursegp, dimension, -amount);
        return 1;
    }

    med_create_new_segment(&scalevec);

    //	For all segments to which Cursegp is connected, propagate tmap (uv coordinates) from the connected
    //	segment back to Cursegp.  This will meaningfully propagate uv coordinates to all sides which havve
    //	an incident edge.  It will also do some sides more than once.  And it is probably just not what you want.
    for (i=0; i<MAX_SIDES_PER_SEGMENT; i++)
        propagated[i] = 0;

    for (i=0; i<MAX_SIDES_PER_SEGMENT; i++)
        if (IS_CHILD(Cursegp->children[i])) {
            int	s;
            for (s=0; s<MAX_SIDES_PER_SEGMENT; s++)
                propagated[s]++;
            propagated[Side_opposite[i]]--;
            med_propagate_tmaps_to_segments(&Segments[Cursegp->children[i]],Cursegp,1);
        }

    //	Now, for all sides that were not adjacent to another side, and therefore did not get tmaps
    //	propagated to them, treat as a back side.
    for (i=0; i<MAX_SIDES_PER_SEGMENT; i++)
        if (!propagated[i]) {
            med_propagate_tmaps_to_back_side(Cursegp, i, 1);
        }

    //	New stuff, assign default texture to all affected sides.

    Update_flags |= UF_WORLD_CHANGED;
    mine_changed = 1;
    return 1;
}
Esempio n. 2
0
void create_low_detail_poly(int global_index, vec3d *tcp, vec3d *rightv, vec3d *upv)
{
    float		scale;
    gshield_tri	*trip;

    trip = &Global_tris[global_index];

    scale = vm_vec_mag(tcp) * 2.0f;

    vm_vec_scale_add(&trip->verts[0].pos, tcp, rightv, -scale/2.0f);
    vm_vec_scale_add2(&trip->verts[0].pos, upv, scale/2.0f);

    vm_vec_scale_add(&trip->verts[1].pos, &trip->verts[0].pos, rightv, scale);

    vm_vec_scale_add(&trip->verts[2].pos, &trip->verts[1].pos, upv, -scale);

    vm_vec_scale_add(&trip->verts[3].pos, &trip->verts[2].pos, rightv, -scale);

    //	Set u, v coordinates.
    //	Note, this need only be done once, as it's common for all explosions.
    trip->verts[0].u = 0.0f;
    trip->verts[0].v = 0.0f;

    trip->verts[1].u = 1.0f;
    trip->verts[1].v = 0.0f;

    trip->verts[2].u = 1.0f;
    trip->verts[2].v = 1.0f;

    trip->verts[3].u = 0.0f;
    trip->verts[3].v = 1.0f;

}
Esempio n. 3
0
//	-----------------------------------------------------------------------------
//	Applies an instantaneous whack on an object, resulting in an instantaneous
//	change in orientation.
void phys_apply_rot(object *obj,vms_vector *force_vec)
{
	fix	rate, vecmag;

	if (obj->movement_type != MT_PHYSICS)
		return;

	vecmag = vm_vec_mag(force_vec)/8;
	if (vecmag < F1_0/256)
		rate = 4*F1_0;
	else if (vecmag < obj->mtype.phys_info.mass >> 14)
		rate = 4*F1_0;
	else {
		rate = fixdiv(obj->mtype.phys_info.mass, vecmag);
		if (obj->type == OBJ_ROBOT) {
			if (rate < F1_0/4)
				rate = F1_0/4;
			obj->ctype.ai_info.SKIP_AI_COUNT = 2;
		} else {
			if (rate < F1_0/2)
				rate = F1_0/2;
		}
	}

	//	Turn amount inversely proportional to mass.  Third parameter is seconds to do 360 turn.
	physics_turn_towards_vector(force_vec, obj, rate);


}
Esempio n. 4
0
// if i'm an observer, zoom to near my targted object (if any)
void multi_obs_zoom_to_target()
{
	vec3d direct;
	float dist;

	// if i'm not an observer, do nothing
	if (!(Game_mode & GM_MULTIPLAYER) || (Net_player == NULL) || !(Net_player->flags & NETINFO_FLAG_OBSERVER) ||
		(Player_obj->type != OBJ_OBSERVER))
	{
		return;
	}

	// if I have no targeted object, do nothing
	if (Player_ai->target_objnum == -1)
	{
		return;
	}

	// get the normalized direction vector between the observer and the targeted object
	vm_vec_sub(&direct, &Objects[Player_ai->target_objnum].pos, &Player_obj->pos);
	dist = vm_vec_mag(&direct);
	vm_vec_normalize(&direct);

	// orient the guy correctly
	vm_vec_ang_2_matrix(&Player_obj->orient, &direct, 0.0f);

	// keep about 3 object radii away when moving
	dist -= (Objects[Player_ai->target_objnum].radius * 3.0f);

	// get the movement vector
	vm_vec_scale(&direct, dist);

	// move
	vm_vec_add2(&Player_obj->pos, &direct);
}
Esempio n. 5
0
// given a just fired flak shell, pick a detonating distance for it
void flak_pick_range(object *objp, vector *predicted_target_pos, float weapon_subsys_strength)
{
	float final_range;
	vector temp;
	
	// make sure this flak object is valid
	Assert(objp->type == OBJ_WEAPON);
	Assert(objp->instance >= 0);
	Assert(Weapons[objp->instance].weapon_info_index >= 0);
	Assert(Weapon_info[Weapons[objp->instance].weapon_info_index].wi_flags & WIF_FLAK);	
	
	// if the flak index is invalid, do nothing - if this fails the flak simply becomes a non-rendering bullet
	if(Weapons[objp->instance].flak_index < 0){
		return;
	}

	// get the range to the target
	vm_vec_sub(&temp, &objp->pos, predicted_target_pos);
	final_range = vm_vec_mag(&temp);

	// add in some randomness
	final_range += (Flak_range + (Flak_range * 0.65f * (1.0f - weapon_subsys_strength))) * frand_range(-1.0f, 1.0f);	

	// make sure we're firing at least 10 meters away
	if(final_range < 10.0f){
		final_range = 10.0f;
	}

	// set the range
	flak_set_range(objp, &objp->pos, final_range);
}
Esempio n. 6
0
/*
  This works like any other clip plane... if this is enabled and you
rotate a point, the CC_OFF_USER bit will be set in the clipping codes.
It is completely handled by most g3_draw primitives, except maybe lines.

  As far as performance, when enabled, it will slow down each point
rotation (or g3_code_vertex call) by a vector subtraction and dot
product.   It won't slow anything down for polys that are completely
clipped on or off by the plane, and will slow each clipped polygon by
not much more than any other clipping we do.
*/
void g3_start_user_clip_plane( vector *plane_point, vector *plane_normal )
{
	float mag = vm_vec_mag( plane_normal );
	if ( (mag < 0.1f) || (mag > 1.5f ) )	{
		// Invalid plane_normal passed in.  Get Allender (since it is
		// probably a ship warp in bug:) or John.   
		Int3();			
		return;
	}

	G3_user_clip = 1;
	if(!Cmdline_nohtl) {
		G3_user_clip_normal = *plane_normal;
		G3_user_clip_point = *plane_point;
//	return;


		gr_start_clip();
	}
	vm_vec_rotate(&G3_user_clip_normal, plane_normal, &View_matrix );
	vm_vec_normalize(&G3_user_clip_normal);

	vector tempv;
	vm_vec_sub(&tempv,plane_point,&View_position);
	vm_vec_rotate(&G3_user_clip_point,&tempv,&View_matrix );
}
Esempio n. 7
0
int hud_lock_world_pos_in_range(vector *target_world_pos, vector *vec_to_target)
{
	float			dist_to_target, weapon_range;
	weapon_info	*wip;
	ship_weapon	*swp;

	int target_in_range=1;

	swp = &Player_ship->weapons;
	wip = &Weapon_info[swp->secondary_bank_weapons[swp->current_secondary_bank]];

	vm_vec_sub(vec_to_target, target_world_pos, &Player_obj->pos);
	dist_to_target = vm_vec_mag(vec_to_target);

	//local ssms are always in range :)
	if (wip->wi_flags2 & WIF2_LOCAL_SSM)
		weapon_range=wip->lssm_lock_range;
	else
		// calculate the range of the weapon, and only display the lead target indicator when
		// if the weapon can actually hit the target
		weapon_range = wip->max_speed * wip->lifetime;

	

	// reduce firing range in nebula
	if ((The_mission.flags & MISSION_FLAG_FULLNEB) && Nebula_sec_range) {
		weapon_range *= 0.8f;
	}

	if (dist_to_target > weapon_range) {
		target_in_range=0;
	}

	return target_in_range;
}
Esempio n. 8
0
//find the distance between a segment and a point
static fix compute_dist(const vcsegptr_t seg,const vms_vector &pos)
{
	auto delta = compute_segment_center(seg);
	vm_vec_sub2(delta,pos);

	return vm_vec_mag(delta);

}
void physics_apply_whack(vec3d *impulse, vec3d *pos, physics_info *pi, matrix *orient, float mass)
{
	vec3d	local_torque, torque;
//	vec3d	npos;

	//	Detect null vector.
	if ((fl_abs(impulse->xyz.x) <= WHACK_LIMIT) && (fl_abs(impulse->xyz.y) <= WHACK_LIMIT) && (fl_abs(impulse->xyz.z) <= WHACK_LIMIT))
		return;

	// first do the rotational velocity
	// calculate the torque on the body based on the point on the
	// object that was hit and the momentum being applied to the object

	vm_vec_crossprod(&torque, pos, impulse);
	vm_vec_rotate ( &local_torque, &torque, orient );

	vec3d delta_rotvel;
	vm_vec_rotate( &delta_rotvel, &local_torque, &pi->I_body_inv );
	vm_vec_scale ( &delta_rotvel, (float) ROTVEL_WHACK_CONST );
	vm_vec_add2( &pi->rotvel, &delta_rotvel );

	//mprintf(("Whack: %7.3f %7.3f %7.3f\n", pi->rotvel.xyz.x, pi->rotvel.xyz.y, pi->rotvel.xyz.z));

	// instant whack on the velocity
	// reduce damping on all axes
	pi->flags |= PF_REDUCED_DAMP;
	update_reduced_damp_timestamp( pi, vm_vec_mag(impulse) );

	// find time for shake from weapon to end
	int dtime = timestamp_until(pi->afterburner_decay);
	if (dtime < WEAPON_SHAKE_TIME) {
		pi->afterburner_decay = timestamp( WEAPON_SHAKE_TIME );
	}

	// Goober5000 - pi->mass should probably be just mass, as specified in the header
	vm_vec_scale_add2( &pi->vel, impulse, 1.0f / mass );
	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_whack [speed: %f]\n", vm_vec_mag(&pi->vel)));
		vm_vec_normalize(&pi->vel);
		vm_vec_scale(&pi->vel, (float)RESET_SHIP_SPEED);
	}
	vm_vec_rotate( &pi->prev_ramp_vel, &pi->vel, orient );		// set so velocity will ramp starting from current speed
																					// ramped velocity is now affected by collision
}
Esempio n. 10
0
//	---------------------------------------------------------------------------
int	PerturbCursideCommon(fix amount)
{
    int			saveSegSizeMode = SegSizeMode;
    vms_vector	fvec, rvec, uvec;
    fix			fmag, rmag, umag;
    int			v;

    SegSizeMode = SEGSIZEMODE_CURSIDE;

    Modified_vertex_index = 0;

    extract_forward_vector_from_segment(Cursegp, &fvec);
    extract_right_vector_from_segment(Cursegp, &rvec);
    extract_up_vector_from_segment(Cursegp, &uvec);

    fmag = vm_vec_mag(&fvec);
    rmag = vm_vec_mag(&rvec);
    umag = vm_vec_mag(&uvec);

    for (v=0; v<4; v++) {
        vms_vector perturb_vec;

        perturb_vec.x = fixmul(rmag, rand()*2 - 32767);
        perturb_vec.y = fixmul(umag, rand()*2 - 32767);
        perturb_vec.z = fixmul(fmag, rand()*2 - 32767);

        scale_vert(Cursegp, Cursegp->verts[Side_to_verts[Curside][v]], &perturb_vec, amount);
    }

//	validate_segment(Cursegp);
//	if (SegSizeMode) {
//		for (i=0; i<MAX_SIDES_PER_SEGMENT; i++)
//			if (Cursegp->children[i] != -1)
//				validate_segment(&Segments[Cursegp->children[i]]);
//	}

    validate_modified_segments();
    SegSizeMode = saveSegSizeMode;

    Update_flags |= UF_WORLD_CHANGED;
    mine_changed = 1;

    return 1;
}
Esempio n. 11
0
//find the distance between a segment and a point
fix compute_dist(segment *seg,vms_vector *pos)
{
	vms_vector delta;

	compute_segment_center(&delta,seg);
	vm_vec_sub2(&delta,pos);

	return vm_vec_mag(&delta);

}
Esempio n. 12
0
// maybe detonate a flak shell early/late (call from weapon_process_pre(...))
void flak_maybe_detonate(object *objp)
{			
	vector temp;	

	// multiplayer clients should never detonate flak early
	// if(MULTIPLAYER_CLIENT){
		// return;
	// }

	// if the shell has gone past its range, blow it up
	vm_vec_sub(&temp, &objp->pos, &Flak[Weapons[objp->instance].flak_index].start_pos);
	if(vm_vec_mag(&temp) >= Flak[Weapons[objp->instance].flak_index].range){
		weapon_detonate(objp);		
	}
}
Esempio n. 13
0
void physics_collide_whack( vec3d *impulse, vec3d *world_delta_rotvel, physics_info *pi, matrix *orient, bool is_landing )
{
	vec3d	body_delta_rotvel;

	//	Detect null vector.
	if ((fl_abs(impulse->xyz.x) <= WHACK_LIMIT) && (fl_abs(impulse->xyz.y) <= WHACK_LIMIT) && (fl_abs(impulse->xyz.z) <= WHACK_LIMIT))
		return;

	vm_vec_rotate( &body_delta_rotvel, world_delta_rotvel, orient );
//	vm_vec_scale( &body_delta_rotvel, (float)	ROTVEL_COLLIDE_WHACK_CONST );
	vm_vec_add2( &pi->rotvel, &body_delta_rotvel );

	update_reduced_damp_timestamp( pi, vm_vec_mag(impulse) );

	// find time for shake from weapon to end
	if (!is_landing) {
		int dtime = timestamp_until(pi->afterburner_decay);
		if (dtime < WEAPON_SHAKE_TIME) {
			pi->afterburner_decay = timestamp( WEAPON_SHAKE_TIME );
		}
	}

	pi->flags |= PF_REDUCED_DAMP;
	vm_vec_scale_add2( &pi->vel, impulse, 1.0f / pi->mass );
	// check that collision does not give ship too much speed
	// reset if too high
	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_collide_whack [speed: %f]\n", vm_vec_mag(&pi->vel)));
		vm_vec_normalize(&pi->vel);
		vm_vec_scale(&pi->vel, (float)RESET_SHIP_SPEED);
	}
	vm_vec_rotate( &pi->prev_ramp_vel, &pi->vel, orient );		// set so velocity will ramp starting from current speed
																					// ramped velocity is now affected by collision
	// rotate previous ramp velocity (in model coord) to be same as vel (in world coords)
}
Esempio n. 14
0
//	-----------------------------------------------------------------------------------------------------------
// Simulate a physics object for this frame
void physics_sim(vec3d* position, matrix* orient, physics_info* pi, float sim_time)
{
	// check flag which tells us whether or not to do velocity translation
	if (pi->flags & PF_CONST_VEL) {
		vm_vec_scale_add2(position, &pi->vel, sim_time);
	}
	else
	{
		physics_sim_vel(position, pi, sim_time, orient);
		physics_sim_rot(orient, pi, sim_time);

		pi->speed = vm_vec_mag(&pi->vel);							//	Note, cannot use quick version, causes cumulative error, increasing speed.
		pi->fspeed = vm_vec_dot(&orient->vec.fvec, &pi->vel);		// instead of vector magnitude -- use only forward vector since we are only interested in forward velocity
	}

}
Esempio n. 15
0
//	-----------------------------------------------------------------------------
//	Applies an instantaneous whack on an object, resulting in an instantaneous
//	change in orientation.
void phys_apply_rot(object *obj,vms_vector *force_vec)
{
	fix	rate, vecmag;

	if (obj->movement_type != MT_PHYSICS)
		return;

	vecmag = vm_vec_mag(force_vec)/8;
	if (vecmag < F1_0/256)
		rate = 4*F1_0;
	else if (vecmag < obj->mtype.phys_info.mass >> 14)
		rate = 4*F1_0;
	else {
		rate = fixdiv(obj->mtype.phys_info.mass, vecmag);
		if (obj->type == OBJ_ROBOT) {
			if (rate < F1_0/4)
				rate = F1_0/4;
			//	Changed by mk, 10/24/95, claw guys should not slow down when attacking!
			if (!Robot_info[obj->id].thief && !Robot_info[obj->id].attack_type) {
				if (obj->ctype.ai_info.SKIP_AI_COUNT * FrameTime < 3*F1_0/4) {
					fix	tval = fixdiv(F1_0, 8*FrameTime);
					int	addval;

					addval = f2i(tval);

					if ( (d_rand() * 2) < (tval & 0xffff))
						addval++;
					obj->ctype.ai_info.SKIP_AI_COUNT += addval;
					// -- mk: too much stuff making hard to see my debug messages...mprintf((0, "FrameTime = %7.3f, addval = %i\n", f2fl(FrameTime), addval));
				}
			}
		} else {
			if (rate < F1_0/2)
				rate = F1_0/2;
		}
	}

	//	Turn amount inversely proportional to mass.  Third parameter is seconds to do 360 turn.
	physics_turn_towards_vector(force_vec, obj, rate);


}
Esempio n. 16
0
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);
	}
}
Esempio n. 17
0
int generate_curve( fix r1scale, fix r4scale ) {
    vms_vector vec_dir, tvec;
    vms_vector coord,prev_point;
    vms_equation coeffs;
    fix enddist, nextdist;
    int firstsegflag;
    fix t, maxscale;
    fixang rangle, uangle;

	const vcsegptr_t cursegp = Cursegp;
	compute_center_point_on_side(p1, cursegp, Curside);

    switch( Curside ) {
        case WLEFT:
            extract_right_vector_from_segment(cursegp, r1);
            vm_vec_scale(r1, -F1_0 );
            break;
        case WTOP:
            extract_up_vector_from_segment(cursegp, r1);
            break;
        case WRIGHT:
            extract_right_vector_from_segment(cursegp, r1);
            break;
        case WBOTTOM:
            extract_up_vector_from_segment(cursegp, r1);
            vm_vec_scale(r1, -F1_0 );
            break;
        case WBACK:
            extract_forward_vector_from_segment(cursegp, r1);
            break;
        case WFRONT:
            extract_forward_vector_from_segment(cursegp, r1);
            vm_vec_scale(r1, -F1_0 );
            break;
        }            

	const vcsegptr_t markedsegp = Markedsegp;
	compute_center_point_on_side(p4, markedsegp, Markedside);

    switch( Markedside ) {
        case WLEFT:
            extract_right_vector_from_segment(markedsegp, r4);
            extract_up_vector_from_segment(markedsegp, r4t);
            break;
        case WTOP:
            extract_up_vector_from_segment(markedsegp, r4);
            vm_vec_scale(r4, -F1_0 );
            extract_forward_vector_from_segment(markedsegp, r4t);
            vm_vec_scale(r4t, -F1_0 );
            break;
        case WRIGHT:
            extract_right_vector_from_segment(markedsegp, r4);
            vm_vec_scale(r4, -F1_0 );
            extract_up_vector_from_segment(markedsegp, r4t);
            break;
        case WBOTTOM:
            extract_up_vector_from_segment(markedsegp, r4);
            extract_forward_vector_from_segment(markedsegp, r4t);
            break;
        case WBACK:
            extract_forward_vector_from_segment(markedsegp, r4);
            vm_vec_scale(r4, -F1_0 );
            extract_up_vector_from_segment(markedsegp, r4t);
            break;
        case WFRONT:
            extract_forward_vector_from_segment(markedsegp, r4);
            extract_up_vector_from_segment(markedsegp, r4t);
            break;
        }

    r1save = r1;
    tvec = r1;
    vm_vec_scale(r1,r1scale);
    vm_vec_scale(r4,r4scale);

    create_curve( p1, p4, r1, r4, coeffs );
    OriginalSeg = Cursegp;
    OriginalMarkedSeg = Markedsegp;
    OriginalSide = Curside;
    OriginalMarkedSide = Markedside;
    CurveNumSegs = 0;
    coord = prev_point = p1;

    t=0;
    firstsegflag = 1;
    enddist = F1_0; nextdist = 0;
    while ( enddist > fixmul( nextdist, 1.5*F1_0 )) {
            vms_matrix  rotmat;
            if (firstsegflag==1)
                firstsegflag=0;
            else
                extract_forward_vector_from_segment(cursegp, tvec);
            nextdist = vm_vec_mag(tvec);                                   // nextdist := distance to next point
            t = curve_dist(&coeffs, 3, t, prev_point, nextdist);               // t = argument at which function is forward vector magnitude units away from prev_point (in 3-space, not along curve)
            coord = evaluate_curve(&coeffs, 3, t);                                          // coord := point about forward vector magnitude units away from prev_point
            enddist = vm_vec_dist(coord, p4);                  // enddist := distance from current to end point, vec_dir used as a temporary variable
            //vm_vec_normalize(vm_vec_sub(&vec_dir, &coord, &prev_point));
            vm_vec_normalized_dir(vec_dir, coord, prev_point);
			if (!med_attach_segment(Cursegp, vmsegptr(&New_segment), Curside, AttachSide))
		{
			med_extract_matrix_from_segment(cursegp, &rotmat);                   // rotmat := matrix describing orientation of Cursegp
			const auto tdest = vm_vec_rotate(vec_dir,rotmat);	// tdest := vec_dir in reference frame of Cursegp
			vec_dir = tdest;

            const auto rotmat2 = vm_vector_2_matrix(vec_dir,nullptr,nullptr);

            med_rotate_segment( Cursegp, rotmat2 );
			prev_point = coord;
            Curside = Side_opposite[AttachSide];

            CurveSegs[CurveNumSegs]=Cursegp;
            CurveNumSegs++;
        } else return 0;
	}

    extract_up_vector_from_segment(cursegp, tvec);
    uangle = vm_vec_delta_ang( tvec, r4t, r4 );
    if (uangle >= F1_0 * 1/8) uangle -= F1_0 * 1/4;
    if (uangle >= F1_0 * 1/8) uangle -= F1_0 * 1/4;
    if (uangle <= -F1_0 * 1/8) uangle += F1_0 * 1/4;
    if (uangle <= -F1_0 * 1/8) uangle += F1_0 * 1/4;
    extract_right_vector_from_segment(cursegp, tvec);
    rangle = vm_vec_delta_ang( tvec, r4t, r4 );
    if (rangle >= F1_0/8) rangle -= F1_0/4;
    if (rangle >= F1_0/8) rangle -= F1_0/4;
    if (rangle <= -F1_0/8) rangle += F1_0/4;
    if (rangle <= -F1_0/8) rangle += F1_0/4;

    if ((uangle != 0) && (rangle != 0)) {
        maxscale = CurveNumSegs*F1_0;
        generate_banked_curve(maxscale, coeffs);
    }

    if (CurveNumSegs) {
        med_form_bridge_segment( Cursegp, Side_opposite[AttachSide], Markedsegp, Markedside );
        CurveSegs[CurveNumSegs] = vmsegptr(Markedsegp->children[Markedside]);
        CurveNumSegs++;
	}

    Cursegp = OriginalSeg;
    Curside = OriginalSide;

	med_create_new_segment_from_cursegp();

	//warn_if_concave_segments();

    if (CurveNumSegs) return 1;
        else return 0;
}
Esempio n. 18
0
// function looks at the flying controls and the current velocity to determine a goal velocity
// function determines velocity in object's reference frame and goal velocity in object's reference frame
void physics_read_flying_controls( matrix * orient, physics_info * pi, control_info * ci, float sim_time, vec3d *wash_rot)
{
	vec3d goal_vel;		// goal velocity in local coords, *not* accounting for ramping of velcity
	float ramp_time_const;		// time constant for velocity ramping

	// apply throttle, unless reverse thrusters are held down
	if (ci->forward != -1.0f)
		ci->forward += (ci->forward_cruise_percent / 100.0f);

	// give control input to cause rotation in engine wash
	extern int Wash_on;
	if ( wash_rot && Wash_on ) {
		ci->pitch += wash_rot->xyz.x;
		ci->bank += wash_rot->xyz.z;
		ci->heading += wash_rot->xyz.y;
	}

	if (ci->pitch > 1.0f ) ci->pitch = 1.0f;
	else if (ci->pitch < -1.0f ) ci->pitch = -1.0f;

	if (ci->vertical > 1.0f ) ci->vertical = 1.0f;
	else if (ci->vertical < -1.0f ) ci->vertical = -1.0f;

	if (ci->heading > 1.0f ) ci->heading = 1.0f;
	else if (ci->heading < -1.0f ) ci->heading = -1.0f;

	if (ci->sideways > 1.0f  ) ci->sideways = 1.0f;
	else if (ci->sideways < -1.0f  ) ci->sideways = -1.0f;

	if (ci->bank > 1.0f ) ci->bank = 1.0f;
	else if (ci->bank < -1.0f ) ci->bank = -1.0f;

	if ( pi->flags & PF_AFTERBURNER_ON ){
		//SparK: modifield to accept reverse burners
		if (!(pi->afterburner_max_reverse_vel > 0.0f)){
			ci->forward = 1.0f;
		}
	}

	if (ci->forward > 1.0f ) ci->forward = 1.0f;
	else if (ci->forward < -1.0f ) ci->forward = -1.0f;

	if (!Flight_controls_follow_eyepoint_orientation || (Player_obj == NULL) || (Player_obj->type != OBJ_SHIP)) {
		// Default behavior; eyepoint orientation has no effect on controls
		pi->desired_rotvel.xyz.x = ci->pitch * pi->max_rotvel.xyz.x;
		pi->desired_rotvel.xyz.y = ci->heading * pi->max_rotvel.xyz.y;
	} else {
		// Optional behavior; pitch and yaw are always relative to the eyepoint
		// orientation (excluding slew)
		vec3d tmp_vec, new_rotvel;
		matrix tmp_mat, eyemat, rotvelmat;

		ship_get_eye(&tmp_vec, &eyemat, Player_obj, false);

		vm_copy_transpose_matrix(&tmp_mat, &Player_obj->orient);
		vm_matrix_x_matrix(&rotvelmat, &tmp_mat, &eyemat);

		vm_vec_rotate(&new_rotvel, &pi->max_rotvel, &rotvelmat);
		vm_vec_unrotate(&tmp_vec, &pi->max_rotvel, &rotvelmat);
		new_rotvel.xyz.x = tmp_vec.xyz.x;

		new_rotvel.xyz.x = ci->pitch * new_rotvel.xyz.x;
		new_rotvel.xyz.y = ci->heading * new_rotvel.xyz.y;

		vm_vec_unrotate(&tmp_vec, &new_rotvel, &rotvelmat);

		pi->desired_rotvel = tmp_vec;
	}

	float	delta_bank;

#ifdef BANK_WHEN_TURN
	//	To change direction of bank, negate the whole expression.
	//	To increase magnitude of banking, decrease denominator.
	//	Adam: The following statement is all the math for banking while turning.
	delta_bank = - (ci->heading * pi->max_rotvel.xyz.y) * pi->delta_bank_const;
#else
	delta_bank = 0.0f;
#endif

	pi->desired_rotvel.xyz.z = ci->bank * pi->max_rotvel.xyz.z + delta_bank;
	pi->forward_thrust = ci->forward;
	pi->vert_thrust = ci->vertical;	//added these two in order to get side and forward thrusters
	pi->side_thrust = ci->sideways;	//to glow brighter when the ship is moving in the right direction -Bobboau

	if ( pi->flags & PF_AFTERBURNER_ON ) {
		goal_vel.xyz.x = ci->sideways*pi->afterburner_max_vel.xyz.x;
		goal_vel.xyz.y = ci->vertical*pi->afterburner_max_vel.xyz.y;
		if(ci->forward < 0.0f)
			goal_vel.xyz.z = ci->forward* pi->afterburner_max_reverse_vel;
		else
			goal_vel.xyz.z = ci->forward* pi->afterburner_max_vel.xyz.z;
	}
	else if ( pi->flags & PF_BOOSTER_ON ) {
		goal_vel.xyz.x = ci->sideways*pi->booster_max_vel.xyz.x;
		goal_vel.xyz.y = ci->vertical*pi->booster_max_vel.xyz.y;
		goal_vel.xyz.z = ci->forward* pi->booster_max_vel.xyz.z;
	}
	else {
		goal_vel.xyz.x = ci->sideways*pi->max_vel.xyz.x;
		goal_vel.xyz.y = ci->vertical*pi->max_vel.xyz.y;
		goal_vel.xyz.z = ci->forward* pi->max_vel.xyz.z;
	}

	if ( goal_vel.xyz.z < -pi->max_rear_vel && !(pi->flags & PF_AFTERBURNER_ON) )
		goal_vel.xyz.z = -pi->max_rear_vel;


	if ( pi->flags & PF_ACCELERATES )	{
		//
		// Determine *resultant* DESIRED VELOCITY (desired_vel) accounting for RAMPING of velocity
		// Use LOCAL coordinates
		// if slide_enabled, ramp velocity for x and y, otherwise set goal (0)
		//    always ramp velocity for z
		//

		// If reduced damp in effect, then adjust ramp_velocity and desired_velocity can not change as fast.
		// Scale according to reduced_damp_time_expansion.
		float reduced_damp_ramp_time_expansion;
		if ( pi->flags & PF_REDUCED_DAMP && !timestamp_elapsed(pi->reduced_damp_decay) ) {
			float reduced_damp_fraction_time_left = timestamp_until( pi->reduced_damp_decay ) / (float) REDUCED_DAMP_TIME;
			reduced_damp_ramp_time_expansion = 1.0f + (REDUCED_DAMP_FACTOR-1) * reduced_damp_fraction_time_left;
		} else {
			reduced_damp_ramp_time_expansion = 1.0f;
		}

		if (pi->flags & PF_SLIDE_ENABLED)  {
			// determine the local velocity
			// deterimine whether accelerating or decleration toward goal for x
			if ( goal_vel.xyz.x > 0.0f )  {
				if ( goal_vel.xyz.x >= pi->prev_ramp_vel.xyz.x )
					ramp_time_const = pi->slide_accel_time_const;
				else
					ramp_time_const = pi->slide_decel_time_const;
			} else if ( goal_vel.xyz.x < 0.0f ) {
				if ( goal_vel.xyz.x <= pi->prev_ramp_vel.xyz.x )
					ramp_time_const = pi->slide_accel_time_const;
				else
					ramp_time_const = pi->slide_decel_time_const;
			} else {
				ramp_time_const = pi->slide_decel_time_const;
			}
			// If reduced damp in effect, then adjust ramp_velocity and desired_velocity can not change as fast
			if ( pi->flags & PF_REDUCED_DAMP ) {
				ramp_time_const *= reduced_damp_ramp_time_expansion;
			}
			pi->prev_ramp_vel.xyz.x = velocity_ramp(pi->prev_ramp_vel.xyz.x, goal_vel.xyz.x, ramp_time_const, sim_time);

			// deterimine whether accelerating or decleration toward goal for y
			if ( goal_vel.xyz.y > 0.0f )  {
				if ( goal_vel.xyz.y >= pi->prev_ramp_vel.xyz.y )
					ramp_time_const = pi->slide_accel_time_const;
				else
					ramp_time_const = pi->slide_decel_time_const;
			} else if ( goal_vel.xyz.y < 0.0f ) {
				if ( goal_vel.xyz.y <= pi->prev_ramp_vel.xyz.y )
					ramp_time_const = pi->slide_accel_time_const;
				else
					ramp_time_const = pi->slide_decel_time_const;
			} else {
				ramp_time_const = pi->slide_decel_time_const;
			}
			// If reduced damp in effect, then adjust ramp_velocity and desired_velocity can not change as fast
			if ( pi->flags & PF_REDUCED_DAMP ) {
				ramp_time_const *= reduced_damp_ramp_time_expansion;
			}
			pi->prev_ramp_vel.xyz.y = velocity_ramp( pi->prev_ramp_vel.xyz.y, goal_vel.xyz.y, ramp_time_const, sim_time);
		} else  {
			// slide not enabled
			pi->prev_ramp_vel.xyz.x = 0.0f;
			pi->prev_ramp_vel.xyz.y = 0.0f;
		}

		// deterimine whether accelerating or decleration toward goal for z
		if ( goal_vel.xyz.z > 0.0f )  {
			if ( goal_vel.xyz.z >= pi->prev_ramp_vel.xyz.z )  {
				if ( pi->flags & PF_AFTERBURNER_ON )
					ramp_time_const = pi->afterburner_forward_accel_time_const;
				else if (pi->flags & PF_BOOSTER_ON)
					ramp_time_const = pi->booster_forward_accel_time_const;
				else
					ramp_time_const = pi->forward_accel_time_const;
			} else {
				ramp_time_const = pi->forward_decel_time_const;
			}
		} else if ( goal_vel.xyz.z < 0.0f ) {
			if ( pi->flags & PF_AFTERBURNER_ON )
				ramp_time_const = pi->afterburner_reverse_accel;
			else
				ramp_time_const = pi->forward_decel_time_const;
		} else {
			ramp_time_const = pi->forward_decel_time_const;
		}

		// If reduced damp in effect, then adjust ramp_velocity and desired_velocity can not change as fast
		if ( pi->flags & PF_REDUCED_DAMP ) {
			ramp_time_const *= reduced_damp_ramp_time_expansion;
		}
		pi->prev_ramp_vel.xyz.z = velocity_ramp(pi->prev_ramp_vel.xyz.z, goal_vel.xyz.z, ramp_time_const, sim_time);

		//Deternine the current dynamic glide cap, and ramp to it
		//This is outside the normal "glide" block since we want the cap to adjust whether or not the ship is in glide mode
		float dynamic_glide_cap_goal = 0.0;
		if (pi->flags & PF_AFTERBURNER_ON) {
			dynamic_glide_cap_goal = ( goal_vel.xyz.z >= 0.0f ) ? pi->afterburner_max_vel.xyz.z : pi->afterburner_max_reverse_vel;
		}
		else {
			//Use the maximum value in X, Y, and Z (including overclocking)
			dynamic_glide_cap_goal = MAX(MAX(pi->max_vel.xyz.x,pi->max_vel.xyz.y), pi->max_vel.xyz.z);
		}
		pi->cur_glide_cap = velocity_ramp(pi->cur_glide_cap, dynamic_glide_cap_goal, ramp_time_const, sim_time);


		if ( (pi->flags & PF_GLIDING) || (pi->flags & PF_FORCE_GLIDE ) ) {
			pi->desired_vel = pi->vel;

			//SUSHI: A (hopefully better) approach to dealing with accelerations in glide mode
			//Get *actual* current velocities along each axis and use those instead of ramped velocities
			vec3d local_vel;
			vm_vec_rotate(&local_vel, &pi->vel, orient);

			//Having pi->glide_cap == 0 means we're using a dynamic glide cap
			float curGlideCap = 0.0f;
			if (pi->glide_cap == 0.0f) 
				curGlideCap = pi->cur_glide_cap;
			else 
				curGlideCap = pi->glide_cap;

			//If we're near the (positive) glide cap, decay velocity where we aren't thrusting
			//This is a hack, but makes the flight feel a lot smoother
			//Don't do this if we aren't applying any thrust, we have no glide cap, or the accel multiplier is 0 (no thrust while gliding)
			float cap_decay_threshold = 0.95f;
			float cap_decay_amount = 0.2f;
			if (curGlideCap >= 0.0f && vm_vec_mag(&pi->desired_vel) >= cap_decay_threshold * curGlideCap && 
					vm_vec_mag(&goal_vel) > 0.0f &&
					pi->glide_accel_mult != 0.0f) 
			{
				if (goal_vel.xyz.x == 0.0f)
					vm_vec_scale_add2(&pi->desired_vel, &orient->vec.rvec, -cap_decay_amount * local_vel.xyz.x);
				if (goal_vel.xyz.y == 0.0f)
					vm_vec_scale_add2(&pi->desired_vel, &orient->vec.uvec, -cap_decay_amount * local_vel.xyz.y);
				if (goal_vel.xyz.z == 0.0f)
					vm_vec_scale_add2(&pi->desired_vel, &orient->vec.fvec, -cap_decay_amount * local_vel.xyz.z);
			}

			//The glide_ramp function uses (basically) the same math as the velocity ramp so that thruster power is consistent
			//Only ramp if the glide cap is positive
			float xVal = glide_ramp(local_vel.xyz.x, goal_vel.xyz.x, pi->slide_accel_time_const, pi->glide_accel_mult, sim_time);
			float yVal = glide_ramp(local_vel.xyz.y, goal_vel.xyz.y, pi->slide_accel_time_const, pi->glide_accel_mult, sim_time);
			float zVal = 0.0;
			if (pi->flags & PF_AFTERBURNER_ON) 
				zVal = glide_ramp(local_vel.xyz.z, goal_vel.xyz.z, pi->afterburner_forward_accel_time_const, pi->glide_accel_mult, sim_time);
			else {
				if (goal_vel.xyz.z >= 0.0f)
					zVal = glide_ramp(local_vel.xyz.z, goal_vel.xyz.z, pi->forward_accel_time_const, pi->glide_accel_mult, sim_time);
				else
					zVal = glide_ramp(local_vel.xyz.z, goal_vel.xyz.z, pi->forward_decel_time_const, pi->glide_accel_mult, sim_time);
			}

			//Compensate for effect of dampening: normal flight cheats here, so /we make up for it this way so glide acts the same way
			xVal *= pi->side_slip_time_const / sim_time;
			yVal *= pi->side_slip_time_const / sim_time;
			if (pi->use_newtonian_damp) zVal *= pi->side_slip_time_const / sim_time;

			vm_vec_scale_add2(&pi->desired_vel, &orient->vec.fvec, zVal);
			vm_vec_scale_add2(&pi->desired_vel, &orient->vec.rvec, xVal);
			vm_vec_scale_add2(&pi->desired_vel, &orient->vec.uvec, yVal);

			// Only do the glide cap if we have one and are actively thrusting in some direction.
			if ( curGlideCap >= 0.0f && (ci->forward != 0.0f || ci->sideways != 0.0f || ci->vertical != 0.0f) ) {
				float currentmag = vm_vec_mag(&pi->desired_vel);
				if ( currentmag > curGlideCap ) {
					vm_vec_scale( &pi->desired_vel, curGlideCap / currentmag );
				}
			}
		}
		else
		{
			// this translates local desired velocities to world velocities
			vm_vec_zero(&pi->desired_vel);
			vm_vec_scale_add2( &pi->desired_vel, &orient->vec.rvec, pi->prev_ramp_vel.xyz.x );
			vm_vec_scale_add2( &pi->desired_vel, &orient->vec.uvec, pi->prev_ramp_vel.xyz.y );
			vm_vec_scale_add2( &pi->desired_vel, &orient->vec.fvec, pi->prev_ramp_vel.xyz.z );
		}
	} else  // object does not accelerate  (PF_ACCELERATES not set)
		pi->desired_vel = pi->vel;
}
Esempio n. 19
0
void do_object_physics( object * obj )
{
	vms_angvec rotang;
	vms_vector frame_vec;	//movement in this frame
	vms_vector new_pos,ipos;		//position after this frame
	int iseg;
	int hit;
	vms_matrix rotmat,new_pm;
	int count=0;
	short joy_x,joy_y,btns;
	int joyx_moved,joyy_moved;
	fix speed;
	vms_vector *desired_upvec;
	fixang delta_ang,roll_ang;
	vms_vector forvec = {0,0,f1_0};
	vms_matrix temp_matrix;

	//check keys

	rotang.pitch = ROT_SPEED * (key_down_time(KEY_UP) - key_down_time(KEY_DOWN));
	rotang.head  = ROT_SPEED * (key_down_time(KEY_RIGHT) - key_down_time(KEY_LEFT));
	rotang.bank = 0;

	//check for joystick movement

	joy_get_pos(&joy_x,&joy_y);
	btns=joy_get_btns();

	joyx_moved = (abs(joy_x - _old_joy_x)>JOY_NULL);
	joyy_moved = (abs(joy_y - _old_joy_y)>JOY_NULL);

	if (abs(joy_x) < JOY_NULL) joy_x = 0;
	if (abs(joy_y) < JOY_NULL) joy_y = 0;

	if (!rotang.pitch) rotang.pitch = fixmul(-joy_y * 128,FrameTime);
	if (!rotang.head) rotang.head = fixmul(joy_x * 128,FrameTime);
	
	if (joyx_moved) _old_joy_x = joy_x;
	if (joyy_moved) _old_joy_y = joy_y;

	speed = ((btns&2) || keyd_pressed[KEY_A])?SLOW_SPEED*3:(keyd_pressed[KEY_Z]?SLOW_SPEED/2:SLOW_SPEED);

	//now build matrices, do rotations, etc., etc.

	vm_angles_2_matrix(&rotmat,&rotang);
	vm_matrix_x_matrix(&new_pm,&obj->orient,&rotmat);
	obj->orient = new_pm;

	//move player

	vm_vec_copy_scale(&obj->velocity,&obj->orient.fvec,speed);
	vm_vec_copy_scale(&frame_vec,&obj->velocity,FrameTime);

	do {
		fix wall_part;
		vms_vector tvec;

		count++;

		vm_vec_add(&new_pos,&obj->pos,&frame_vec);

		hit = find_vector_intersection(&ipos,&iseg,&obj->pos,obj->seg_id,&new_pos,obj->size,-1);

		obj->seg_id = iseg;
		obj->pos = ipos;

		//-FIXJOHN-if (hit==HIT_OBJECT) ExplodeObject(hit_objnum);

		if (hit==HIT_WALL) {
			vm_vec_sub(&frame_vec,&new_pos,&obj->pos);	//part through wall
			wall_part = vm_vec_dot(wall_norm,&frame_vec);
			vm_vec_copy_scale(&tvec,wall_norm,wall_part);
			if ((wall_part == 0) || (vm_vec_mag(&tvec) < 5)) Int3();
			vm_vec_sub2(&frame_vec,&tvec);
		}

	} while (hit == HIT_WALL);

	Assert(check_point_in_seg(&obj->pos,obj->seg_id,0).centermask==0);

	//now bank player according to segment orientation

	desired_upvec = &Segments[obj->seg_id].sides[3].faces[0].normal;

	if (labs(vm_vec_dot(desired_upvec,&obj->orient.fvec)) < f1_0/2) {

		vm_vector_2_matrix(&temp_matrix,&obj->orient.fvec,desired_upvec,NULL);

		delta_ang = vm_vec_delta_ang(&obj->orient.uvec,&temp_matrix.uvec,&obj->orient.fvec);

		if (rotang.head) delta_ang += (rotang.head<0)?TURNROLL_ANG:-TURNROLL_ANG;

		if (abs(delta_ang) > DAMP_ANG) {

			roll_ang = fixmul(FrameTime,ROLL_RATE);

			if (abs(delta_ang) < roll_ang) roll_ang = delta_ang;
			else if (delta_ang<0) roll_ang = -roll_ang;

			vm_vec_ang_2_matrix(&rotmat,&forvec,roll_ang);

			vm_matrix_x_matrix(&new_pm,&obj->orient,&rotmat);
			obj->orient = new_pm;
		}
	}

}
Esempio n. 20
0
// ------------------------------------------------------------------
// swarm_update_direction()
//
//	Check if we want to update the direction of a swarm missile.
//
void swarm_update_direction(object *objp, float frametime)
{
	weapon_info	*wip;
	weapon		*wp;
	object		*hobjp;
	swarm_info	*swarmp;
	vec3d		obj_to_target;
	float			vel, target_dist, radius, missile_speed, missile_dist;
	physics_info	*pi;

	Assert(objp->instance >= 0 && objp->instance < MAX_WEAPONS);

	wp = &Weapons[objp->instance];

	if (wp->swarm_index == -1) {
		return;
	}

	wip = &Weapon_info[wp->weapon_info_index];
	hobjp = wp->homing_object;
	pi = &Objects[wp->objnum].phys_info;
	swarmp = &Swarm_missiles[wp->swarm_index];

	// check if homing is lost.. if it is then get a new path to move swarm missile along
	if ( swarmp->homing_objnum != -1 && hobjp == &obj_used_list ) {
		swarmp->change_timestamp = 1;
		swarmp->path_num = -1;
		swarmp->homing_objnum = -1;
	}

	if ( hobjp != &obj_used_list ) {
		swarmp->homing_objnum = OBJ_INDEX(hobjp);
	}

	if ( timestamp_elapsed(swarmp->change_timestamp) ) {

		if ( swarmp->path_num == -1 ) {
			if ( Objects[objp->parent].type != OBJ_SHIP ) {
				//AL: parent ship died... so just pick some random paths
				swarmp->path_num	= myrand()%4;
			} else {
				ship *parent_shipp;
				parent_shipp = &Ships[Objects[objp->parent].instance];
				swarmp->path_num = (parent_shipp->next_swarm_path++)%4;

				if ( parent_shipp->next_swarm_path%4 == 0 ) {
					swarmp->flags ^= SWARM_POSITIVE_PATH;
				}
			}

			vm_vec_scale_add(&swarmp->original_target, &objp->pos, &objp->orient.vec.fvec, SWARM_CONE_LENGTH);
			swarmp->circle_rvec = objp->orient.vec.rvec;
			swarmp->circle_uvec = objp->orient.vec.uvec;

			swarmp->change_count = 1;
			swarmp->change_time = fl2i(SWARM_CHANGE_DIR_TIME + SWARM_TIME_VARIANCE*(frand() - 0.5f) * 2);

			vm_vec_zero(&swarmp->last_offset);

			missile_speed = pi->speed;
			missile_dist	= missile_speed * swarmp->change_time/1000.0f;
			if ( missile_dist < SWARM_DIST_OFFSET ) {
				missile_dist=i2fl(SWARM_DIST_OFFSET);
			}
			swarmp->angle_offset = (float)(asin(SWARM_DIST_OFFSET / missile_dist));
			Assert(!_isnan(swarmp->angle_offset) );
		}

		swarmp->change_timestamp = timestamp(swarmp->change_time);

		// check if swarm missile is homing, if so need to calculate a new target pos to turn towards
		if ( hobjp != &obj_used_list && f2fl(Missiontime - wp->creation_time) > 0.5f && ( f2fl(Missiontime - wp->creation_time) > wip->free_flight_time ) ) {
			swarmp->original_target = wp->homing_pos;

			// Calculate a rvec and uvec that will determine the displacement from the
			// intended target.  Use crossprod to generate a right vector, from the missile
			// up vector and the vector connecting missile to the homing object.
			swarmp->circle_uvec = objp->orient.vec.uvec;
			swarmp->circle_rvec = objp->orient.vec.rvec;

			missile_speed = pi->speed;
			missile_dist = missile_speed * swarmp->change_time/1000.0f;
			if ( missile_dist < SWARM_DIST_OFFSET ) {
				missile_dist = i2fl(SWARM_DIST_OFFSET);
			}
			swarmp->angle_offset = (float)(asin(SWARM_DIST_OFFSET / missile_dist));
			Assert(!_isnan(swarmp->angle_offset) );
		}

		vm_vec_sub(&obj_to_target, &swarmp->original_target, &objp->pos);
		target_dist = vm_vec_mag_quick(&obj_to_target);
		swarmp->last_dist = target_dist;

		// If homing swarm missile is close to target, let missile home in on original target
		if ( target_dist < SWARM_DIST_STOP_SWARMING ) {
			swarmp->new_target = swarmp->original_target;
			goto swarm_new_target_calced;
		}

		radius = (float)tan(swarmp->angle_offset) * target_dist;
		vec3d rvec_component, uvec_component;

		swarmp->change_count++;
		if ( swarmp->change_count > 2 ) {
			swarmp->flags ^= SWARM_POSITIVE_PATH;
			swarmp->change_count = 0;
		}

		// pick a new path number to follow once at center
		if ( swarmp->change_count == 1 ) {
			swarmp->path_num = swarmp->path_num + myrand()%3;
			if ( swarmp->path_num > 3 ) {
				swarmp->path_num = 0;
			}
		}

		vm_vec_zero(&rvec_component);
		vm_vec_zero(&uvec_component);

		switch ( swarmp->path_num ) {
			case 0:	// straight up and down
				if ( swarmp->flags & SWARM_POSITIVE_PATH )
					vm_vec_copy_scale( &uvec_component, &swarmp->circle_uvec, radius);
				else
					vm_vec_copy_scale( &uvec_component, &swarmp->circle_uvec, -radius);
				break;

			case 1:	// left/right
				if ( swarmp->flags & SWARM_POSITIVE_PATH )
					vm_vec_copy_scale( &rvec_component, &swarmp->circle_rvec, radius);
				else
					vm_vec_copy_scale( &rvec_component, &swarmp->circle_rvec, -radius);
				break;

			case 2:	// top/right - bottom/left
				if ( swarmp->flags & SWARM_POSITIVE_PATH ) {
					vm_vec_copy_scale( &rvec_component, &swarmp->circle_rvec, radius);
					vm_vec_copy_scale( &uvec_component, &swarmp->circle_uvec, radius);
				}
				else {
					vm_vec_copy_scale( &rvec_component, &swarmp->circle_rvec, -radius);
					vm_vec_copy_scale( &uvec_component, &swarmp->circle_uvec, -radius);
				}
				break;

			case 3:	// top-left - bottom/right
				if ( swarmp->flags & SWARM_POSITIVE_PATH ) {
					vm_vec_copy_scale( &rvec_component, &swarmp->circle_rvec, -radius);
					vm_vec_copy_scale( &uvec_component, &swarmp->circle_uvec, radius);
				}
				else {
					vm_vec_copy_scale( &rvec_component, &swarmp->circle_rvec, radius);
					vm_vec_copy_scale( &uvec_component, &swarmp->circle_uvec, -radius);
				}
				break;
			default:
				Int3();
				break;
		}

		swarmp->new_target = swarmp->original_target;
		vm_vec_zero(&swarmp->last_offset);
		vm_vec_add(&swarmp->last_offset, &uvec_component, &rvec_component);
		vm_vec_add2(&swarmp->new_target, &swarmp->last_offset);
	}
	else {
		if ( hobjp != &obj_used_list && f2fl(Missiontime - wp->creation_time) > 0.5f ) {

			swarmp->new_target = swarmp->original_target;
			if ( swarmp->last_dist < SWARM_DIST_STOP_SWARMING ) {
				swarmp->new_target = wp->homing_pos;
				goto swarm_new_target_calced;
			}

			vm_vec_add2(&swarmp->new_target, &swarmp->last_offset);
		}
	}

	swarm_new_target_calced:

	ai_turn_towards_vector(&swarmp->new_target, objp, frametime, wip->turn_time, NULL, NULL, 0.0f, 0);
	vel = vm_vec_mag(&objp->phys_info.desired_vel);
	vm_vec_copy_scale(&objp->phys_info.desired_vel, &objp->orient.vec.fvec, vel);
}
Esempio n. 21
0
void generate_banked_curve(fix maxscale, vms_equation coeffs) {
    vms_vector vec_dir, tvec, b4r4t;
    vms_vector coord,prev_point;
    fix enddist, nextdist;
    int firstsegflag;
    fixang rangle, uangle, angle, scaled_ang=0;
    fix t;

    if (CurveNumSegs) {

		const vcsegptr_t cursegp = Cursegp;
		extract_up_vector_from_segment(cursegp, b4r4t);
    uangle = vm_vec_delta_ang( b4r4t, r4t, r4 );
    if (uangle >= F1_0 * 1/8) uangle -= F1_0 * 1/4;
    if (uangle >= F1_0 * 1/8) uangle -= F1_0 * 1/4;
    if (uangle <= -F1_0 * 1/8) uangle += F1_0 * 1/4;
    if (uangle <= -F1_0 * 1/8) uangle += F1_0 * 1/4;

		extract_right_vector_from_segment(cursegp, b4r4t);
    rangle = vm_vec_delta_ang( b4r4t, r4t, r4 );
    if (rangle >= F1_0/8) rangle -= F1_0/4;
    if (rangle >= F1_0/8) rangle -= F1_0/4;
    if (rangle <= -F1_0/8) rangle += F1_0/4;
    if (rangle <= -F1_0/8) rangle += F1_0/4;

    angle = uangle;
    if (abs(rangle) < abs(uangle)) angle = rangle;

	delete_curve();

    coord = prev_point = p1;

#define MAGIC_NUM 0.707*F1_0

    if (maxscale)
        scaled_ang = fixdiv(angle,fixmul(maxscale,MAGIC_NUM));

    t=0; 
    tvec = r1save;
    firstsegflag = 1;
    enddist = F1_0; nextdist = 0;
    while ( enddist > fixmul( nextdist, 1.5*F1_0 )) {
            vms_matrix  rotmat;
            if (firstsegflag==1)
                firstsegflag=0;
            else
				extract_forward_vector_from_segment(cursegp, tvec);
            nextdist = vm_vec_mag(tvec);                                   // nextdist := distance to next point
            t = curve_dist(&coeffs, 3, t, prev_point, nextdist);               // t = argument at which function is forward vector magnitude units away from prev_point (in 3-space, not along curve)
            coord = evaluate_curve(&coeffs, 3, t);                                          // coord := point about forward vector magnitude units away from prev_point
            enddist = vm_vec_dist(coord, p4);                  // enddist := distance from current to end point, vec_dir used as a temporary variable
            //vm_vec_normalize(vm_vec_sub(&vec_dir, &coord, &prev_point));
            vm_vec_normalized_dir(vec_dir, coord, prev_point);
			if (!med_attach_segment(Cursegp, vmsegptr(&New_segment), Curside, AttachSide))
			{
				med_extract_matrix_from_segment(cursegp, &rotmat);                   // rotmat := matrix describing orientation of Cursegp
			const auto tdest = vm_vec_rotate(vec_dir,rotmat);	// tdest := vec_dir in reference frame of Cursegp
			vec_dir = tdest;
            const auto rotmat2 = vm_vec_ang_2_matrix(vec_dir,scaled_ang);

			med_rotate_segment( Cursegp, rotmat2 );
			prev_point = coord;
            Curside = Side_opposite[AttachSide];

            CurveSegs[CurveNumSegs]=Cursegp;
            CurveNumSegs++;
        }
      }
    }
}
Esempio n. 22
0
//	-----------------------------------------------------------------------------------------------------------
//Simulate a physics object for this frame
void do_physics_sim(object *obj)
{
	int ignore_obj_list[MAX_IGNORE_OBJS],n_ignore_objs;
	int iseg;
	int try_again;
	int fate=0;
	vms_vector frame_vec;			//movement in this frame
	vms_vector new_pos,ipos;		//position after this frame
	int count=0;
	int objnum;
	int WallHitSeg, WallHitSide;
	fvi_info hit_info;
	fvi_query fq;
	vms_vector save_pos;
	int save_seg;
	fix drag;
	fix sim_time;
	vms_vector start_pos;
	int obj_stopped=0;
	fix moved_time; 			//how long objected moved before hit something
	physics_info *pi;
	int orig_segnum = obj->segnum;
	fix PhysTime = (FrameTime<F1_0/30?F1_0/30:FrameTime);

	Assert(obj->movement_type == MT_PHYSICS);

#ifndef NDEBUG
	if (Dont_move_ai_objects)
		if (obj->control_type == CT_AI)
			return;
#endif

	pi = &obj->mtype.phys_info;

	do_physics_sim_rot(obj);

	if (!(pi->velocity.x || pi->velocity.y || pi->velocity.z || pi->thrust.x || pi->thrust.y || pi->thrust.z))
		return;

	objnum = obj-Objects;

	n_phys_segs = 0;

	/* As this engine was not designed for that high FPS as we intend, we use F1_0/30 max. for sim_time to ensure
	   scaling and dot products stay accurate and reliable. The object position intended for this frame will be scaled down later,
	   after the main collision-loop is done.
	   This won't make collision results be equal in all FPS settings, but hopefully more accurate, the higher our FPS are.
	*/
	sim_time = PhysTime; //FrameTime;

	//debug_obj = obj;

#ifdef EXTRA_DEBUG
	//check for correct object segment 
        if(!get_seg_masks(&obj->pos,obj->segnum,0,__FILE__,__LINE__).centermask==0) {
		//Int3();  Removed by Rob 10/5/94
		if (!update_object_seg(obj)) {
			if (!(Game_mode & GM_MULTI))
				Int3();
			compute_segment_center(&obj->pos,&Segments[obj->segnum]);
			obj->pos.x += objnum;
		}
	}
#endif

	start_pos = obj->pos;

	n_ignore_objs = 0;

	Assert(obj->mtype.phys_info.brakes==0);		//brakes not used anymore?

		//if uses thrust, cannot have zero drag
        Assert(!(obj->mtype.phys_info.flags&PF_USES_THRUST) || obj->mtype.phys_info.drag!=0);

	//do thrust & drag
	// NOTE: this always must be dependent on FrameTime, if sim_time differs!
	if ((drag = obj->mtype.phys_info.drag) != 0) {

		int count;
		vms_vector accel;
		fix r,k,have_accel;

		count = FrameTime / FT;
		r = FrameTime % FT;
		k = fixdiv(r,FT);

		if (obj->mtype.phys_info.flags & PF_USES_THRUST) {

			vm_vec_copy_scale(&accel,&obj->mtype.phys_info.thrust,fixdiv(f1_0,obj->mtype.phys_info.mass));
			have_accel = (accel.x || accel.y || accel.z);

			while (count--) {
				if (have_accel)
					vm_vec_add2(&obj->mtype.phys_info.velocity,&accel);

				vm_vec_scale(&obj->mtype.phys_info.velocity,f1_0-drag);
			}

			//do linear scale on remaining bit of time

			vm_vec_scale_add2(&obj->mtype.phys_info.velocity,&accel,k);
			if (drag)
				vm_vec_scale(&obj->mtype.phys_info.velocity,f1_0-fixmul(k,drag));
		}
		else if (drag)
		{
			fix total_drag=f1_0;

			while (count--)
				total_drag = fixmul(total_drag,f1_0-drag);

			//do linear scale on remaining bit of time

			total_drag = fixmul(total_drag,f1_0-fixmul(k,drag));

			vm_vec_scale(&obj->mtype.phys_info.velocity,total_drag);
		}
	}

	do {
		try_again = 0;

		//Move the object
		vm_vec_copy_scale(&frame_vec, &obj->mtype.phys_info.velocity, sim_time);

		if ( (frame_vec.x==0) && (frame_vec.y==0) && (frame_vec.z==0) )	
			break;

		count++;

		//	If retry count is getting large, then we are trying to do something stupid.
		if (count > 8) break; // in original code this was 3 for all non-player objects. still leave us some limit in case fvi goes apeshit.

		vm_vec_add(&new_pos,&obj->pos,&frame_vec);

		ignore_obj_list[n_ignore_objs] = -1;

		fq.p0						= &obj->pos;
		fq.startseg				= obj->segnum;
		fq.p1						= &new_pos;
		fq.rad					= obj->size;
		fq.thisobjnum			= objnum;
		fq.ignore_obj_list	= ignore_obj_list;
		fq.flags					= FQ_CHECK_OBJS;

		if (obj->type == OBJ_WEAPON)
			fq.flags |= FQ_TRANSPOINT;

		if (obj->type == OBJ_PLAYER)
			fq.flags |= FQ_GET_SEGLIST;

		fate = find_vector_intersection(&fq,&hit_info);
		//	Matt: Mike's hack.
		if (fate == HIT_OBJECT) {
			object	*objp = &Objects[hit_info.hit_object];

			if (((objp->type == OBJ_WEAPON) && (objp->id == PROXIMITY_ID)) || objp->type == OBJ_POWERUP) // do not increase count for powerups since they *should* not change our movement
				count--;
		}

#ifndef NDEBUG
		if (fate == HIT_BAD_P0) {
			Int3();
		}
#endif

		if (obj->type == OBJ_PLAYER) {
			int i;

			if (n_phys_segs && phys_seglist[n_phys_segs-1]==hit_info.seglist[0])
				n_phys_segs--;

			for (i=0;(i<hit_info.n_segs) && (n_phys_segs<MAX_FVI_SEGS-1);  )
				phys_seglist[n_phys_segs++] = hit_info.seglist[i++];
		}

		ipos = hit_info.hit_pnt;
		iseg = hit_info.hit_seg;
		WallHitSide = hit_info.hit_side;
		WallHitSeg = hit_info.hit_side_seg;

		if (iseg==-1) {		//some sort of horrible error
			if (obj->type == OBJ_WEAPON)
				obj->flags |= OF_SHOULD_BE_DEAD;
			break;
		}

		Assert(!((fate==HIT_WALL) && ((WallHitSeg == -1) || (WallHitSeg > Highest_segment_index))));

		//if(!get_seg_masks(&hit_info.hit_pnt,hit_info.hit_seg,0).centermask==0)
		//	Int3();

		save_pos = obj->pos;			//save the object's position
		save_seg = obj->segnum;

		// update object's position and segment number
		obj->pos = ipos;

		if ( iseg != obj->segnum )
			obj_relink(objnum, iseg );

		//if start point not in segment, move object to center of segment
                if (get_seg_masks(&obj->pos,obj->segnum,0,__FILE__,__LINE__).centermask!=0) {
			int n;

			if ((n=find_object_seg(obj))==-1) {
				//Int3();
				if (obj->type==OBJ_PLAYER && (n=find_point_seg(&obj->last_pos,obj->segnum))!=-1) {
					obj->pos = obj->last_pos;
					obj_relink(objnum, n );
				}
				else {
					compute_segment_center(&obj->pos,&Segments[obj->segnum]);
					obj->pos.x += objnum;
				}
				if (obj->type == OBJ_WEAPON)
					obj->flags |= OF_SHOULD_BE_DEAD;
			}
			return;
		}

		//calulate new sim time
		{
			//vms_vector moved_vec;
			vms_vector moved_vec_n;
			fix attempted_dist,actual_dist;

			actual_dist = vm_vec_normalized_dir(&moved_vec_n,&obj->pos,&save_pos);

			if (fate==HIT_WALL && vm_vec_dot(&moved_vec_n,&frame_vec) < 0) {		//moved backwards

				//don't change position or sim_time

				obj->pos = save_pos;
		
				//iseg = obj->segnum;		//don't change segment

				obj_relink(objnum, save_seg );

				moved_time = 0;
			}
			else {
				fix old_sim_time;

				attempted_dist = vm_vec_mag(&frame_vec);

				old_sim_time = sim_time;

				sim_time = fixmuldiv(sim_time,attempted_dist-actual_dist,attempted_dist);

				moved_time = old_sim_time - sim_time;

				if (sim_time < 0 || sim_time>old_sim_time) {
					sim_time = old_sim_time;
					//WHY DOES THIS HAPPEN??

					moved_time = 0;
				}
			}
		}


		switch( fate )		{

			case HIT_WALL:		{
				vms_vector moved_v;
				fix hit_speed=0, wall_part=0;

				// Find hit speed	

				vm_vec_sub(&moved_v,&obj->pos,&save_pos);

				wall_part = vm_vec_dot(&moved_v,&hit_info.hit_wallnorm);

				if ((wall_part != 0 && moved_time>0 && (hit_speed=-fixdiv(wall_part,moved_time))>0) || obj->type == OBJ_WEAPON || obj->type == OBJ_DEBRIS)
					collide_object_with_wall( obj, hit_speed, WallHitSeg, WallHitSide, &hit_info.hit_pnt );
				if (obj->type == OBJ_PLAYER)
					scrape_player_on_wall(obj, WallHitSeg, WallHitSide, &hit_info.hit_pnt );

				Assert( WallHitSeg > -1 );				
				Assert( WallHitSide > -1 );				

				if ( !(obj->flags&OF_SHOULD_BE_DEAD) )	{


					Assert(! (obj->mtype.phys_info.flags & PF_STICK && obj->mtype.phys_info.flags & PF_BOUNCE));	//can't be bounce and stick

					if (obj->mtype.phys_info.flags & PF_STICK) {		//stop moving

						add_stuck_object(obj, WallHitSeg, WallHitSide);

						vm_vec_zero(&obj->mtype.phys_info.velocity);
						obj_stopped = 1;
						try_again = 0;
					}
					else {					// Slide object along wall

						//We're constrained by wall, so subtract wall part from 
						//velocity vector

						wall_part = vm_vec_dot(&hit_info.hit_wallnorm,&obj->mtype.phys_info.velocity);

						// if wall_part, make sure the value is sane enough to get usable velocity computed
						if (wall_part < 0 && wall_part > -f1_0) wall_part = -f1_0;
						if (wall_part > 0 && wall_part < f1_0) wall_part = f1_0;

						if (obj->mtype.phys_info.flags & PF_BOUNCE)		//bounce off wall
							wall_part *= 2;	//Subtract out wall part twice to achieve bounce

						vm_vec_scale_add2(&obj->mtype.phys_info.velocity,&hit_info.hit_wallnorm,-wall_part);

						try_again = 1;
					}
				}

				break;
			}

			case HIT_OBJECT:		{
				vms_vector old_vel;

				// Mark the hit object so that on a retry the fvi code
				// ignores this object.

				Assert(hit_info.hit_object != -1);
				//	Calculcate the hit point between the two objects.
				{	vms_vector	*ppos0, *ppos1, pos_hit;
					fix			size0, size1;
					ppos0 = &Objects[hit_info.hit_object].pos;
					ppos1 = &obj->pos;
					size0 = Objects[hit_info.hit_object].size;
					size1 = obj->size;
					Assert(size0+size1 != 0);	// Error, both sizes are 0, so how did they collide, anyway?!?
					//vm_vec_scale(vm_vec_sub(&pos_hit, ppos1, ppos0), fixdiv(size0, size0 + size1));
					//vm_vec_add2(&pos_hit, ppos0);
					vm_vec_sub(&pos_hit, ppos1, ppos0);
					vm_vec_scale_add(&pos_hit,ppos0,&pos_hit,fixdiv(size0, size0 + size1));

					old_vel = obj->mtype.phys_info.velocity;

					collide_two_objects( obj, &Objects[hit_info.hit_object], &pos_hit);

				}

				// Let object continue its movement
				if ( !(obj->flags&OF_SHOULD_BE_DEAD)  )	{
					//obj->pos = save_pos;

					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)) {
						//if (Objects[hit_info.hit_object].type == OBJ_POWERUP)
							ignore_obj_list[n_ignore_objs++] = hit_info.hit_object;
						try_again = 1;
					}
				}

				break;
			}	
			case HIT_NONE:		
				break;

#ifndef NDEBUG
			case HIT_BAD_P0:
				Int3();		// Unexpected collision type: start point not in specified segment.
				break;
			default:
				// Unknown collision type returned from find_vector_intersection!!
				Int3();
				break;
#endif
		}
	} while ( try_again );

	//	Pass retry count info to AI.
	if (obj->control_type == CT_AI) {
		if (count > 0) {
			Ai_local_info[objnum].retry_count = count-1;
			Total_retries += count-1;
			Total_sims++;
		}
	}

	// As sim_time may not base on FrameTime, scale actual object position to get accurate movement
	if (PhysTime/FrameTime > 0)
	{
		vms_vector md;
		vm_vec_sub(&md, &obj->pos, &start_pos);
		vm_vec_scale(&md, F1_0/((float)PhysTime/FrameTime));
		vm_vec_add(&obj->pos,&start_pos, &md);
		//check for and update correct object segment
		if(!get_seg_masks(&obj->pos, obj->segnum, 0, __FILE__, __LINE__).centermask == 0)
		{
			if (!update_object_seg(obj)) {
				if (!(Game_mode & GM_MULTI))
					Int3();
				compute_segment_center(&obj->pos,&Segments[obj->segnum]);
				obj->pos.x += objnum;
			}
		}
	}

	// After collision with objects and walls, set velocity from actual movement
	if (!obj_stopped
		&& ((obj->type == OBJ_PLAYER) || (obj->type == OBJ_ROBOT) || (obj->type == OBJ_DEBRIS)) 
		&& ((fate == HIT_WALL) || (fate == HIT_OBJECT) || (fate == HIT_BAD_P0))
		)
	{	
		vms_vector moved_vec;
		vm_vec_sub(&moved_vec,&obj->pos,&start_pos);
		vm_vec_copy_scale(&obj->mtype.phys_info.velocity,&moved_vec,fixdiv(f1_0,FrameTime));
	}

	fix_illegal_wall_intersection(obj, &start_pos);

	//Assert(check_point_in_seg(&obj->pos,obj->segnum,0).centermask==0);

	//if (obj->control_type == CT_FLYING)
	if (obj->mtype.phys_info.flags & PF_LEVELLING)
		do_physics_align_object( obj );


	//hack to keep player from going through closed doors
	if (obj->type==OBJ_PLAYER && obj->segnum!=orig_segnum && (!cheats.ghostphysics) ) {
		int sidenum;

		sidenum = find_connect_side(&Segments[obj->segnum],&Segments[orig_segnum]);

		if (sidenum != -1) {

			if (! (WALL_IS_DOORWAY(&Segments[orig_segnum],sidenum) & WID_FLY_FLAG)) {
				side *s;
				int vertnum,num_faces,i;
				fix dist;
				int vertex_list[6];

				//bump object back

				s = &Segments[orig_segnum].sides[sidenum];

                                create_abs_vertex_lists( &num_faces, vertex_list, orig_segnum, sidenum, __FILE__,__LINE__);

				//let's pretend this wall is not triangulated
				vertnum = vertex_list[0];
				for (i=1;i<4;i++)
					if (vertex_list[i] < vertnum)
						vertnum = vertex_list[i];

#ifdef COMPACT_SEGS
					{
						vms_vector _vn;
						get_side_normal(&Segments[orig_segnum], sidenum, 0, &_vn );
						dist = vm_dist_to_plane(&start_pos, &_vn, &Vertices[vertnum]);
						vm_vec_scale_add(&obj->pos,&start_pos,&_vn,obj->size-dist);
					}
#else
					dist = vm_dist_to_plane(&start_pos, &s->normals[0], &Vertices[vertnum]);
					vm_vec_scale_add(&obj->pos,&start_pos,&s->normals[0],obj->size-dist);
#endif
				update_object_seg(obj);

			}
		}
	}

//--WE ALWYS WANT THIS IN, MATT AND MIKE DECISION ON 12/10/94, TWO MONTHS AFTER FINAL 	#ifndef NDEBUG
	//if end point not in segment, move object to last pos, or segment center
        if (get_seg_masks(&obj->pos,obj->segnum,0,__FILE__,__LINE__).centermask!=0) {
		if (find_object_seg(obj)==-1) {
			int n;

			//Int3();
			if (obj->type==OBJ_PLAYER && (n=find_point_seg(&obj->last_pos,obj->segnum))!=-1) {
				obj->pos = obj->last_pos;
				obj_relink(objnum, n );
			}
			else {
				compute_segment_center(&obj->pos,&Segments[obj->segnum]);
				obj->pos.x += objnum;
			}
			if (obj->type == OBJ_WEAPON)
				obj->flags |= OF_SHOULD_BE_DEAD;
		}
	}
//--WE ALWYS WANT THIS IN, MATT AND MIKE DECISION ON 12/10/94, TWO MONTHS AFTER FINAL 	#endif
}
Esempio n. 23
0
// ********************************************************************************************
// Engages autopilot
// This does:
//        * Control switched from player to AI
//        * Time compression to 32x
//        * Lock time compression -WMC
//        * Tell AI to fly to targeted Nav Point (for all nav-status wings/ships)
//		  * Sets max waypoint speed to the best-speed of the slowest ship tagged
bool StartAutopilot()
{
	// Check for support ship and dismiss it if it is not doing anything.
	// If the support ship is doing something then tell the user such.
	for ( object *objp = GET_FIRST(&obj_used_list); objp !=END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) )
	{
		if ((objp->type == OBJ_SHIP) && !(objp->flags & OF_SHOULD_BE_DEAD))
		{
			Assertion((objp->instance >= 0) && (objp->instance < MAX_SHIPS),
				"objp does not have a valid pointer to a ship. Pointer is %d, which is smaller than 0 or bigger than %d",
				objp->instance, MAX_SHIPS);
			ship *shipp = &Ships[objp->instance];

			if (shipp->team != Player_ship->team)
				continue;

			Assertion((shipp->ship_info_index >= 0) && (shipp->ship_info_index < MAX_SHIP_CLASSES),
				"Ship '%s' does not have a valid pointer to a ship class. Pointer is %d, which is smaller than 0 or bigger than %d",
				shipp->ship_name, shipp->ship_info_index, MAX_SHIP_CLASSES);
			ship_info *sip = &Ship_info[shipp->ship_info_index];

			if ( !(sip->flags & SIF_SUPPORT) )
				continue;

			// don't deal with dying or departing support ships
			if ( shipp->flags & (SF_DYING | SF_DEPARTING) )
				continue;

			Assert(shipp->ai_index != -1);
			ai_info* support_ship_aip = &(Ai_info[Ships[objp->instance].ai_index]);

			// is support ship trying to rearm-repair
			if ( ai_find_goal_index( support_ship_aip->goals, AI_GOAL_REARM_REPAIR ) == -1 ) {
				// no, so tell it to depart
				ai_add_ship_goal_player( AIG_TYPE_PLAYER_SHIP, AI_GOAL_WARP, -1, NULL, support_ship_aip );
			} else {
				// yes
				send_autopilot_msgID(NP_MSG_FAIL_SUPPORT_WORKING);
				return false;
			}
		}
	}
	if (!CanAutopilot())
		return false;

	AutoPilotEngaged = true;

	// find the ship that is "leading" all of the ships when the player starts
	// autopilot
	// by default the ship that is leading the autopilot session the player's
	// wing leader (if the player is the wing leader then it will be the
	// player).
	// TODO:implement a way to allow a FREDer to say a different ship is leader
	Autopilot_flight_leader = get_wing_leader(Player_ship->wingnum);
	if ( Autopilot_flight_leader == NULL ) {
		// force player to be the leader if he doesn't have a wing
		Autopilot_flight_leader = Player_obj;
	}

	if (The_mission.flags & MISSION_FLAG_USE_AP_CINEMATICS)
		LockAPConv = timestamp(); // lock convergence instantly
	else
		LockAPConv = timestamp(3000); // 3 seconds before we lock convergence
	Player_use_ai = 1;
	set_time_compression(1);
	lock_time_compression(true);

	// determine speed cap
	int i,j, wcount=1, tc_factor=1;
	float speed_cap = 1000000.0; // 1m is a safe starting point
	float radius = Player_obj->radius, distance = 0.0f, ftemp;
	bool capshipPresent = false;
	int capship_counts[3]; // three size classes
	capship_counts[0] = 0;
	capship_counts[1] = 0;
	capship_counts[2] = 0;

	int capship_placed[3]; // three size classes
	capship_placed[0] = 0;
	capship_placed[1] = 0;
	capship_placed[2] = 0;

	float capship_spreads[3];
	capship_spreads[0] = 0.0f;
	capship_spreads[1] = 0.0f;
	capship_spreads[2] = 0.0f;

	SCP_vector<int> capIndexes;

	// empty the autopilot wings map
	autopilot_wings.clear();

	// vars for usage w/ cinematic
	vec3d pos, norm1, perp, tpos, rpos = Player_obj->pos, zero;
	memset(&zero, 0, sizeof(vec3d));


	// instantly turn player toward tpos
	if (The_mission.flags & MISSION_FLAG_USE_AP_CINEMATICS)
	{
		vm_vec_sub(&norm1, Navs[CurrentNav].GetPosition(), &Player_obj->pos);
		vm_vector_2_matrix(&Player_obj->orient, &norm1, NULL, NULL);
	}

	for (i = 0; i < MAX_SHIPS; i++)
	{
		if (Ships[i].objnum != -1 && 
				(Ships[i].flags2 & SF2_NAVPOINT_CARRY || 
					(Ships[i].wingnum != -1 && Wings[Ships[i].wingnum].flags & WF_NAV_CARRY)
				)
			)
		{
			if (speed_cap > vm_vec_mag(&Ship_info[Ships[i].ship_info_index].max_vel))
				speed_cap = vm_vec_mag(&Ship_info[Ships[i].ship_info_index].max_vel);
		}
	}

	// damp speed_cap to 90% of actual -- to make sure ships stay in formation
	if (The_mission.flags & MISSION_FLAG_USE_AP_CINEMATICS)
		speed_cap = 0.90f * speed_cap;

	if ( speed_cap < 1.0f ) {
		/* We need to deal with this so that incorrectly flagged ships will not
		cause the engine to fail to limit all the ships speeds correctly. */
		Warning(LOCATION, "Ship speed cap is way too small (%f)!\n"
			"This is normally caused by a ship that has nav-carry-status set, but cannot move itself (like a Cargo container).\n"
			"Speed cap has been set to 1.0 m/s.",
			speed_cap);
		speed_cap = 1.0f;
	}

	ramp_bias = speed_cap/50.0f;

	// assign ship goals
	// when assigning goals to individual ships only do so if Ships[shipnum].wingnum != -1 
	// we will assign wing goals below

	for (i = 0; i < MAX_SHIPS; i++)
	{
		if (Ships[i].objnum != -1 && 
				(Ships[i].flags2 & SF2_NAVPOINT_CARRY || 
					(Ships[i].wingnum != -1 && Wings[Ships[i].wingnum].flags & WF_NAV_CARRY)
				)
			)
		{
			// do we have capital ships in the area?
			if (Ship_info[Ships[i].ship_info_index].flags 
				& ( SIF_CRUISER | SIF_CAPITAL | SIF_SUPERCAP | SIF_CORVETTE | SIF_AWACS | SIF_GAS_MINER | SIF_FREIGHTER | SIF_TRANSPORT))
			{
				capshipPresent = true;

				capIndexes.push_back(i);
				// ok.. what size class

				if (Ship_info[Ships[i].ship_info_index].flags & (SIF_CAPITAL | SIF_SUPERCAP))
				{
					capship_counts[0]++;
					if (capship_spreads[0] < Objects[Ships[i].objnum].radius)
						capship_spreads[0] = Objects[Ships[i].objnum].radius;
				}
				else if (Ship_info[Ships[i].ship_info_index].flags & (SIF_CORVETTE))
				{
					capship_counts[1]++;
					if (capship_spreads[1] < Objects[Ships[i].objnum].radius)
						capship_spreads[1] = Objects[Ships[i].objnum].radius;
				}
				else
				{
					capship_counts[2]++;
					if (capship_spreads[2] < Objects[Ships[i].objnum].radius)
						capship_spreads[2] = Objects[Ships[i].objnum].radius;
				}
			}



			// check for bigger radius for usage later
			/*if (!vm_vec_cmp(&rpos, &Player_obj->pos)) 
				// want to make sure rpos isn't player pos - we can worry about it being largest object's later
			{
				rpos = Objects[Ships[i].objnum].pos;
			}*/

			if (Objects[Ships[i].objnum].radius > radius)
			{
				rpos = Objects[Ships[i].objnum].pos;
				radius = Objects[Ships[i].objnum].radius;
			}

			if (The_mission.flags & MISSION_FLAG_USE_AP_CINEMATICS)
			{// instantly turn the ship to match the direction player is looking
				//vm_vec_sub(&norm1, Navs[CurrentNav].GetPosition(), &Player_obj->pos);
				vm_vector_2_matrix(&Objects[Ships[i].objnum].orient, &norm1, NULL, NULL);
			}

			// snap wings into formation
			if (The_mission.flags & MISSION_FLAG_USE_AP_CINEMATICS &&  // only if using cinematics 
				(Ships[i].wingnum != -1 && Wings[Ships[i].wingnum].flags & WF_NAV_CARRY) // only if in a wing
				&& Autopilot_flight_leader != &Objects[Ships[i].objnum]) //only if not flight leader's object
			{	
				ai_info	*aip = &Ai_info[Ships[i].ai_index];
				int wingnum = aip->wing, wing_index = get_wing_index(&Objects[Ships[i].objnum], wingnum);
				vec3d goal_point;
				object *leader_objp = get_wing_leader(wingnum);
				
				if (leader_objp != &Objects[Ships[i].objnum])
				{
					// not leader.. get our position relative to leader
					get_absolute_wing_pos_autopilot(&goal_point, leader_objp, wing_index, aip->ai_flags & AIF_FORMATION_OBJECT);
				}
				else
				{
					ai_clear_wing_goals(wingnum);
					j = 1+int( (float)floor(double(wcount-1)/2.0) );
					switch (wcount % 2)
					{
						case 1: // back-left
							vm_vec_add(&perp, &zero, &Autopilot_flight_leader->orient.vec.rvec);
							//vm_vec_sub(&perp, &perp, &Player_obj->orient.vec.fvec);
							vm_vec_normalize(&perp);
							vm_vec_scale(&perp, -166.0f*j); // 166m is supposedly the optimal range according to tolwyn
							vm_vec_add(&goal_point, &Autopilot_flight_leader->pos, &perp);
							break;

						default: //back-right
						case 0:
							vm_vec_add(&perp, &zero, &Autopilot_flight_leader->orient.vec.rvec);
							//vm_vec_sub(&perp, &perp, &Player_obj->orient.vec.fvec);
							vm_vec_normalize(&perp);
							vm_vec_scale(&perp, 166.0f*j);
							vm_vec_add(&goal_point, &Autopilot_flight_leader->pos, &perp);
							break;
					}
					autopilot_wings[wingnum] = wcount;
					wcount++;
				}
				Objects[Ships[i].objnum].pos = goal_point;			
				if (vm_vec_dist_quick(&Autopilot_flight_leader->pos, &Objects[Ships[i].objnum].pos) > distance)
				{
					distance = vm_vec_dist_quick(&Autopilot_flight_leader->pos, &Objects[Ships[i].objnum].pos);
				}
			}
			// lock primary and secondary weapons
			if ( LockWeaponsDuringAutopilot )
				Ships[i].flags2 |= (SF2_PRIMARIES_LOCKED | SF2_SECONDARIES_LOCKED);

			// clear the ship goals and cap the waypoint speed
			ai_clear_ship_goals(&Ai_info[Ships[i].ai_index]);
			Ai_info[Ships[i].ai_index].waypoint_speed_cap = (int)speed_cap;

			
			// if they're not part of a wing set their goal
			if (Ships[i].wingnum == -1 || The_mission.flags & MISSION_FLAG_USE_AP_CINEMATICS)
			{ 
				if (Navs[CurrentNav].flags & NP_WAYPOINT)
				{
					ai_add_ship_goal_player( AIG_TYPE_PLAYER_SHIP, AI_GOAL_WAYPOINTS_ONCE, 0, ((waypoint_list*)Navs[CurrentNav].target_obj)->get_name(), &Ai_info[Ships[i].ai_index] );
					//fixup has to wait until after wing goals
				}
				else
				{
					ai_add_ship_goal_player( AIG_TYPE_PLAYER_SHIP, AI_GOAL_FLY_TO_SHIP, 0, ((ship*)Navs[CurrentNav].target_obj)->ship_name, &Ai_info[Ships[i].ai_index] );
				}

			}
		}
	}

	// assign wing goals
	if (!(The_mission.flags & MISSION_FLAG_USE_AP_CINEMATICS))
	{
		for (i = 0; i < MAX_WINGS; i++)
		{
			if (Wings[i].flags & WF_NAV_CARRY )
			{	
				//ai_add_ship_goal_player( int type, int mode, int submode, char *shipname, ai_info *aip );

				//ai_add_wing_goal_player( AIG_TYPE_PLAYER_WING, AI_GOAL_STAY_NEAR_SHIP, 0, target_shipname, wingnum );
				//ai_add_wing_goal_player( AIG_TYPE_PLAYER_WING, AI_GOAL_WAYPOINTS_ONCE, 0, target_shipname, wingnum );
				//ai_clear_ship_goals( &(Ai_info[Ships[num].ai_index]) );
				
				ai_clear_wing_goals( i );
				if (Navs[CurrentNav].flags & NP_WAYPOINT)
				{
					
					ai_add_wing_goal_player( AIG_TYPE_PLAYER_WING, AI_GOAL_WAYPOINTS_ONCE, 0, ((waypoint_list*)Navs[CurrentNav].target_obj)->get_name(), i );

					// "fix up" the goal
					for (j = 0; j < MAX_AI_GOALS; j++)
					{
						if (Wings[i].ai_goals[j].ai_mode == AI_GOAL_WAYPOINTS_ONCE ||
							Wings[i].ai_goals[j].ai_mode == AIM_WAYPOINTS )
						{
							autopilot_ai_waypoint_goal_fixup(&(Wings[i].ai_goals[j]));
						}
					}
				}
				else
				{
					ai_add_wing_goal_player( AIG_TYPE_PLAYER_WING, AI_GOAL_FLY_TO_SHIP, 0, ((ship*)Navs[CurrentNav].target_obj)->ship_name, i );

				}
			}
		}
	}

	// fixup has to go down here because ships are assigned goals during wing goals as well
	for (i = 0; i < MAX_SHIPS; i++)
	{
		if (Ships[i].objnum != -1)
		{
			if (Ships[i].flags2 & SF2_NAVPOINT_CARRY || 
				(Ships[i].wingnum != -1 && Wings[Ships[i].wingnum].flags & WF_NAV_CARRY))
				for (j = 0; j < MAX_AI_GOALS; j++)
				{
					if (Ai_info[Ships[i].ai_index].goals[j].ai_mode == AI_GOAL_WAYPOINTS_ONCE ||
						Ai_info[Ships[i].ai_index].goals[j].ai_mode == AIM_WAYPOINTS)
					{
						autopilot_ai_waypoint_goal_fixup( &(Ai_info[Ships[i].ai_index].goals[j]) );

						
						// formation fixup
						//ai_form_on_wing(&Objects[Ships[i].objnum], &Objects[Player_ship->objnum]);
					}
				}
		}
	}
	start_dist = DistanceTo(CurrentNav);

	// ----------------------------- setup cinematic -----------------------------
	if (The_mission.flags & MISSION_FLAG_USE_AP_CINEMATICS)
	{	
		if (capshipPresent)
		{
			// position capships

			vec3d right, front, up, offset;
			for (SCP_vector<int>::iterator idx = capIndexes.begin(); idx != capIndexes.end(); ++idx)
			{
				vm_vec_add(&right, &Autopilot_flight_leader->orient.vec.rvec, &zero);
				vm_vec_add(&front, &Autopilot_flight_leader->orient.vec.fvec, &zero);
				vm_vec_add(&up, &Autopilot_flight_leader->orient.vec.uvec, &zero);
				vm_vec_add(&offset, &zero, &zero);
				if (Ship_info[Ships[*idx].ship_info_index].flags & (SIF_CAPITAL | SIF_SUPERCAP))
				{
					//0 - below - three lines of position

					// front/back to zero
					vm_vec_add(&front, &zero, &zero);

					// position below
					vm_vec_scale(&up, capship_spreads[0]); // scale the up vector by the radius of the largest ship in this formation part


					switch (capship_placed[0] % 3)
					{
						case 1: // right
							vm_vec_scale(&right, capship_spreads[0]);
							break;
							
						case 2: // left
							vm_vec_scale(&right, -capship_spreads[0]);
							break;

						default: // straight
						case 0:
							vm_vec_add(&right, &zero, &zero);
							vm_vec_scale(&up, 1.5); // add an extra half-radius
							break;
					}
		
					// scale by  row
					vm_vec_scale(&right, (1+((float)floor((float)capship_placed[0]/3)))); 
					vm_vec_scale(&up, -(1+((float)floor((float)capship_placed[0]/3))));

					capship_placed[0]++;
				}
				else if (Ship_info[Ships[*idx].ship_info_index].flags & SIF_CORVETTE)
				{
					//1 above - 3 lines of position
					// front/back to zero
					vm_vec_add(&front, &zero, &zero);

					// position below
					vm_vec_scale(&up, capship_spreads[1]); // scale the up vector by the radius of the largest ship in this formation part


					switch (capship_placed[1] % 3)
					{
						case 1: // right
							vm_vec_scale(&right, capship_spreads[1]); 
							break;
							
						case 2: // left
							vm_vec_scale(&right, -capship_spreads[1]); 
							break;

						default: // straight
						case 0:
							vm_vec_add(&right, &zero, &zero);
							vm_vec_scale(&up, 1.5); // add an extra half-radius
							break;
					}
		
					// scale by  row
					vm_vec_scale(&right, (1+((float)floor((float)capship_placed[1]/3)))); 
					vm_vec_scale(&up, (1+((float)floor((float)capship_placed[1]/3))));

					// move ourselves up and out of the way of the smaller ships
					vm_vec_add(&perp, &Autopilot_flight_leader->orient.vec.uvec, &zero);
					vm_vec_scale(&perp, capship_spreads[2]);
					vm_vec_add(&up, &up, &perp);

					capship_placed[1]++;
				}
				else
				{
					//2 either side - 6 lines of position (right (dir, front, back), left (dir, front, back) )
					// placing pattern: right, left, front right, front left, rear right, rear left

					// up/down to zero
					vm_vec_add(&up, &zero, &zero);


					switch (capship_placed[2] % 6)
					{
						case 5:  // rear left
							vm_vec_scale(&right, -capship_spreads[2]);
							vm_vec_scale(&front, -capship_spreads[2]); 
							break;

						case 4:  // rear right
							vm_vec_scale(&right, capship_spreads[2]); 
							vm_vec_scale(&front, -capship_spreads[2]); 
							break;

						case 3:  // front left
							vm_vec_scale(&right, -capship_spreads[2]); 
							vm_vec_scale(&front, capship_spreads[2]); 
							break;

						case 2:  // front right
							vm_vec_scale(&right, capship_spreads[2]); 
							vm_vec_scale(&front, capship_spreads[2]);
							break;

						case 1:  // straight left
							vm_vec_scale(&right, 1.5);
							vm_vec_scale(&right, -capship_spreads[2]);
							vm_vec_add(&front, &zero, &zero);
							break;

						default: // straight right
						case 0:
							vm_vec_scale(&right, 1.5);
							vm_vec_scale(&right, capship_spreads[2]);
							vm_vec_add(&front, &zero, &zero);
							break;
					}
					// these ships seem to pack a little too tightly
					vm_vec_scale(&right, 2*(1+((float)floor((float)capship_placed[2]/3)))); 
					vm_vec_scale(&front, 2*(1+((float)floor((float)capship_placed[2]/3))));

					// move "out" by 166*(wcount-1) so we don't bump into fighters
					vm_vec_add(&perp, &Autopilot_flight_leader->orient.vec.rvec, &zero);
					vm_vec_scale(&perp, 166.0f*float(wcount-1));
					if ( (capship_placed[2] % 2) == 0)
						vm_vec_add(&right, &right, &perp);
					else
						vm_vec_sub(&right, &right, &perp);

					capship_placed[2]++;
				}

				// integrate the up/down componant
				vm_vec_add(&offset, &offset, &up);

				//integrate the left/right componant
				vm_vec_add(&offset, &offset, &right);

				//integrate the left/right componant
				vm_vec_add(&offset, &offset, &front);

				// global scale the position by 50%
				//vm_vec_scale(&offset, 1.5);

				vm_vec_add(&Objects[Ships[*idx].objnum].pos, &Autopilot_flight_leader->pos, &offset);

				if (vm_vec_dist_quick(&Autopilot_flight_leader->pos, &Objects[Ships[*idx].objnum].pos) > distance)
				{
					distance = vm_vec_dist_quick(&Autopilot_flight_leader->pos, &Objects[Ships[*idx].objnum].pos);
				}
			}
		}

		ftemp = floor(Autopilot_flight_leader->phys_info.max_vel.xyz.z/speed_cap);
		if (ftemp >= 2.0f && ftemp < 4.0f)
			tc_factor = 2;
		else if (ftemp >= 4.0f && ftemp < 8.0f)
			tc_factor = 4;
		else if (ftemp >= 8.0f)
			tc_factor = 8;



		tpos = *Navs[CurrentNav].GetPosition();
		// determine distance toward nav at which camera will be
		vm_vec_sub(&pos, &tpos, &Autopilot_flight_leader->pos);
		vm_vec_normalize(&pos); // pos is now a unit vector in the direction we will be moving the camera
		//norm1 = pos;
		vm_vec_scale(&pos, 5*speed_cap*tc_factor); // pos is now scaled by 5 times the speed (5 seconds ahead)
		vm_vec_add(&pos, &pos, &Autopilot_flight_leader->pos); // pos is now 5*speed cap in front of player ship

		switch (myrand()%24) 
		// 8 different ways of getting perp points
		// 4 of which will not be used when capships are present (anything below, or straight above)
		{

			case 1: // down
			case 9:
			case 16:
				if (capship_placed[0] == 0)
					vm_vec_sub(&perp, &zero, &Autopilot_flight_leader->orient.vec.uvec);
				else
				{	// become up-left
					vm_vec_add(&perp, &zero, &Autopilot_flight_leader->orient.vec.uvec);
					vm_vec_sub(&perp, &perp, &Autopilot_flight_leader->orient.vec.rvec);
				}
				break;

			case 2: // up
			case 10:
			case 23:
				vm_vec_add(&perp, &perp, &Autopilot_flight_leader->orient.vec.uvec);
				if (capshipPresent) // become up-right
					vm_vec_add(&perp, &perp, &Autopilot_flight_leader->orient.vec.rvec);
				break;

			case 3: // left
			case 11:
			case 22:
				vm_vec_sub(&perp, &zero, &Autopilot_flight_leader->orient.vec.rvec);
				break;

			case 4: // up-left
			case 12:
			case 21:
				vm_vec_sub(&perp, &zero, &Autopilot_flight_leader->orient.vec.rvec);
				vm_vec_add(&perp, &perp, &Autopilot_flight_leader->orient.vec.uvec);
				break;

			case 5: // up-right
			case 13:
			case 20:
				vm_vec_add(&perp, &zero, &Autopilot_flight_leader->orient.vec.rvec);
				vm_vec_add(&perp, &perp, &Autopilot_flight_leader->orient.vec.uvec);
				break;

			case 6: // down-left
			case 14:
			case 19:
				vm_vec_sub(&perp, &zero, &Autopilot_flight_leader->orient.vec.rvec);
				if (capship_placed[0] < 2)
					vm_vec_sub(&perp, &perp, &Autopilot_flight_leader->orient.vec.uvec);
				else
					vm_vec_add(&perp, &perp, &Autopilot_flight_leader->orient.vec.uvec);
				break;

			case 7: // down-right
			case 15:
			case 18:
				vm_vec_add(&perp, &zero, &Autopilot_flight_leader->orient.vec.rvec);
				if (capship_placed[0] < 1)
					vm_vec_sub(&perp, &perp, &Autopilot_flight_leader->orient.vec.uvec);
				else
					vm_vec_add(&perp, &perp, &Autopilot_flight_leader->orient.vec.uvec);
				break;

			default:
			case 0: // right
			case 8:
			case 17:
				perp = Autopilot_flight_leader->orient.vec.rvec;
				break;

		}
		vm_vec_normalize(&perp);
		//vm_vec_scale(&perp, 2*radius+distance);

		vm_vec_scale(&perp,  Autopilot_flight_leader->radius+radius);

		// randomly scale up/down by up to 20%
		j = 20-myrand()%40; // [-20,20]

		vm_vec_scale(&perp, 1.0f+(float(j)/100.0f));
		vm_vec_add(&cameraPos, &pos, &perp);

		if (capshipPresent)
		{
			vm_vec_normalize(&perp);

			// place it behind
			//vm_vec_copy_scale(&norm1, &Player_obj->orient.vec.fvec, -2*(Player_obj->radius+radius*(1.0f+(float(j)/100.0f))));
			//vm_vec_add(&cameraTarget, &cameraTarget, &norm1);

			vm_vec_copy_scale(&cameraTarget,&perp, radius/5.0f);

			//vm_vec_scale(&cameraTarget, Player_obj->radius+radius*(1.0f+(float(j)/100.0f)));

			//vm_vec_add(&cameraTarget, &pos, &cameraTarget);
			//CameraSpeed = (radius+distance)/25;

			//vm_vec_add(&cameraTarget, &zero, &perp);
			//vm_vec_scale(&CameraVelocity, (radius+distance/100.f));
			//vm_vec_scale(&CameraVelocity, 1.0f/float(NPS_TICKRATE*tc_factor));
		}
		else
		{
			vm_vec_add(&cameraTarget, &zero, &zero);
			//CameraSpeed = 0;
		}
		//CameraMoving = false;


		EndAPCinematic = timestamp((10000*tc_factor)+NPS_TICKRATE); // 10 objective seconds before end of cinematic 
		MoveCamera = timestamp((5500*tc_factor)+NPS_TICKRATE);
		camMovingTime = int(4.5*float(tc_factor));
		set_time_compression((float)tc_factor);
	}

	return true;
}
Esempio n. 24
0
// apply the EMP effect to all relevant ships
void emp_apply(vec3d *pos, float inner_radius, float outer_radius, float emp_intensity, float emp_time, bool use_emp_time_for_capship_turrets)
{	
	float actual_intensity, actual_time;
	vec3d dist;
	float dist_mag;
	float scale_factor;
	object *target;
	ship_obj *so;
	missile_obj *mo;
	ship_subsys *moveup;
	weapon_info *wip_target;

	// all machines check to see if the blast hit a bomb. if so, shut it down (can't move anymore)	
	for( mo = GET_FIRST(&Missile_obj_list); mo != END_OF_LIST(&Missile_obj_list); mo = GET_NEXT(mo) ) {
		target = &Objects[mo->objnum];
		if(target->type != OBJ_WEAPON){
			continue;
		}

		Assert(target->instance >= 0);
		if(target->instance < 0){
			continue;
		}
		Assert(Weapons[target->instance].weapon_info_index >= 0);
		if(Weapons[target->instance].weapon_info_index < 0){
			continue;
		}
		
		// if we have a bomb weapon
		wip_target = &Weapon_info[Weapons[target->instance].weapon_info_index];
		if((wip_target->weapon_hitpoints > 0) && !(wip_target->wi_flags2 & WIF2_NO_EMP_KILL)) {
			// get the distance between the detonation and the target object
			vm_vec_sub(&dist, &target->pos, pos);
			dist_mag = vm_vec_mag(&dist);

			// if the bomb was within 1/4 of the outer radius, castrate it
			if(dist_mag <= (outer_radius * 0.25f)){
				// memset(&target->phys_info, 0, sizeof(physics_info));
				Weapons[target->instance].weapon_flags |= WF_DEAD_IN_WATER;
				mprintf(("EMP killing weapon\n"));
			}
		}	
	}

	// if I'm only a client in a multiplayer game, do nothing
	if(MULTIPLAYER_CLIENT){
		return;
	}

	// See if there are any friendly ships present, if so return without preventing msg
	for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {		
		target = &Objects[so->objnum];
		if(target->type != OBJ_SHIP){
			continue;
		}	
		
		Assert(Objects[so->objnum].instance >= 0);
		if(Objects[so->objnum].instance < 0){
			continue;
		}
		Assert(Ships[Objects[so->objnum].instance].ship_info_index >= 0);
		if(Ships[Objects[so->objnum].instance].ship_info_index < 0){
			continue;
		}

		// if the ship is a cruiser or cap ship, only apply the EMP effect to turrets
		if(Ship_info[Ships[target->instance].ship_info_index].flags & (SIF_BIG_SHIP | SIF_HUGE_SHIP)) {
			float capship_emp_time = use_emp_time_for_capship_turrets ? emp_time : MAX_TURRET_DISRUPT_TIME;
			
			moveup = &Ships[target->instance].subsys_list;
			if(moveup->next != NULL){
				moveup = moveup->next;
			}
			while(moveup != &Ships[target->instance].subsys_list){
				// if this is a turret, disrupt it
				if((moveup->system_info != NULL) && (moveup->system_info->type == SUBSYSTEM_TURRET)){
					vec3d actual_pos;					
					
					// get the distance to the subsys					
					vm_vec_unrotate(&actual_pos, &moveup->system_info->pnt, &target->orient);
					vm_vec_add2(&actual_pos, &target->pos);					
					vm_vec_sub(&dist, &actual_pos, pos);
					dist_mag = vm_vec_mag(&dist);
			
					// if for some reason, the object was outside the blast, radius
					if(dist_mag > outer_radius){			
						// next item
						moveup = moveup->next;
						continue;
					}

					// compute a scale factor for the emp effect
					scale_factor = 1.0f;
					if(dist_mag >= inner_radius){
						scale_factor = 1.0f - (dist_mag / outer_radius);
					} 

					scale_factor -= Ship_info[Ships[target->instance].ship_info_index].emp_resistance_mod;

					if (scale_factor < 0.0f) {
						moveup = moveup->next;
						continue;
					}

					// disrupt the turret
					ship_subsys_set_disrupted(moveup, (int)(capship_emp_time * scale_factor));

					mprintf(("EMP disrupting subsys %s on ship %s (%f, %f)\n", moveup->system_info->subobj_name, Ships[Objects[so->objnum].instance].ship_name, scale_factor, capship_emp_time * scale_factor));
				}
				
				// next item
				moveup = moveup->next;
			}
		}
		// otherwise coat the whole ship with the effect. mmmmmmmmm.
		else {				
			// get the distance between the detonation and the target object
			vm_vec_sub(&dist, &target->pos, pos);
			dist_mag = vm_vec_mag(&dist);

			// if for some reason, the object was outside the blast, radius
			if(dist_mag > outer_radius){			
				continue;
			}

			// compute a scale factor for the emp effect
			scale_factor = 1.0f;
			if(dist_mag >= inner_radius){
				scale_factor = 1.0f - (dist_mag / outer_radius);	
			} 

			scale_factor -= Ship_info[Ships[target->instance].ship_info_index].emp_resistance_mod;

			if (scale_factor < 0.0f) {
				continue;
			}
		
			// calculate actual EMP effect values
			actual_intensity = emp_intensity * scale_factor;
			actual_time = emp_time * scale_factor;			
			mprintf(("EMP effect s : %f, i : %f, t : %f\n", scale_factor, actual_intensity, actual_time));

			// if this effect happened to be on me, start it now
			if((target == Player_obj) && !(Game_mode & GM_STANDALONE_SERVER)){
				emp_start_local(actual_intensity, actual_time);
			} 

			// if this is a multiplayer game, notify other players of the effect
			if(Game_mode & GM_MULTIPLAYER){		
				Assert(MULTIPLAYER_MASTER);				
				send_emp_effect(target->net_signature, actual_intensity, actual_time);
			}
			
			// now be sure to start the emp effect for the ship itself
			emp_start_ship(target, actual_intensity, actual_time);
		}
	}
}
/**
 * Checks asteroid-ship collisions.  
 * @param pair obj_pair pointer to the two objects. pair->a is asteroid and pair->b is ship.
 * @return 1 if all future collisions between these can be ignored
 */
int collide_asteroid_ship( obj_pair * pair )
{
	if (!Asteroids_enabled)
		return 0;

	float		dist;
	object	*pasteroid = pair->a;
	object	*pship = pair->b;

	// Don't check collisions for warping out player
	if ( Player->control_mode != PCM_NORMAL )	{
		if ( pship == Player_obj ) return 0;
	}

	if (pasteroid->hull_strength < 0.0f)
		return 0;

	Assert( pasteroid->type == OBJ_ASTEROID );
	Assert( pship->type == OBJ_SHIP );

	dist = vm_vec_dist( &pasteroid->pos, &pship->pos );

	if ( dist < pasteroid->radius + pship->radius )	{
		int hit;
		vec3d	hitpos;
		// create and initialize ship_ship_hit_info struct
		collision_info_struct asteroid_hit_info;
		init_collision_info_struct(&asteroid_hit_info);

		if ( pasteroid->phys_info.mass > pship->phys_info.mass ) {
			asteroid_hit_info.heavy = pasteroid;
			asteroid_hit_info.light = pship;
		} else {
			asteroid_hit_info.heavy = pship;
			asteroid_hit_info.light = pasteroid;
		}

		hit = asteroid_check_collision(pasteroid, pship, &hitpos, &asteroid_hit_info );
		if ( hit )
		{
			//Scripting support (WMC)
			Script_system.SetHookObjects(4, "Ship", pship, "Asteroid", pasteroid, "Self",pship, "Object", pasteroid);
			bool ship_override = Script_system.IsConditionOverride(CHA_COLLIDEASTEROID, pship);

			Script_system.SetHookObjects(2, "Self",pasteroid, "Object", pship);
			bool asteroid_override = Script_system.IsConditionOverride(CHA_COLLIDESHIP, pasteroid);

			if(!ship_override && !asteroid_override)
			{
				float		ship_damage;	
				float		asteroid_damage;

				vec3d asteroid_vel = pasteroid->phys_info.vel;

				// do collision physics
				calculate_ship_ship_collision_physics( &asteroid_hit_info );

				if ( asteroid_hit_info.impulse < 0.5f )
					return 0;

				// limit damage from impulse by making max impulse (for damage) 2*m*v_max_relative
				float max_ship_impulse = (2.0f*pship->phys_info.max_vel.xyz.z+vm_vec_mag_quick(&asteroid_vel)) * 
					(pship->phys_info.mass*pasteroid->phys_info.mass) / (pship->phys_info.mass + pasteroid->phys_info.mass);

				if (asteroid_hit_info.impulse > max_ship_impulse) {
					ship_damage = 0.001f * max_ship_impulse;
				} else {
					ship_damage = 0.001f * asteroid_hit_info.impulse;	//	Cut collision-based damage in half.
				}

				//	Decrease heavy damage by 2x.
				if (ship_damage > 5.0f)
					ship_damage = 5.0f + (ship_damage - 5.0f)/2.0f;

				if ((ship_damage > 500.0f) && (ship_damage > Ships[pship->instance].ship_max_hull_strength/8.0f)) {
					ship_damage = Ships[pship->instance].ship_max_hull_strength/8.0f;
					nprintf(("AI", "Pinning damage to %s from asteroid at %7.3f (%7.3f percent)\n", Ships[pship->instance].ship_name, ship_damage, 100.0f * ship_damage/Ships[pship->instance].ship_max_hull_strength));
				}

				//	Decrease damage during warp out because it's annoying when your escoree dies during warp out.
				if (Ai_info[Ships[pship->instance].ai_index].mode == AIM_WARP_OUT)
					ship_damage /= 3.0f;

				// calculate asteroid damage and set asteroid damage to greater or asteroid and ship
				// asteroid damage is needed since we can really whack some small asteroid with afterburner and not do
				// significant damage to ship but the asteroid goes off faster than afterburner speed.
				asteroid_damage = asteroid_hit_info.impulse/pasteroid->phys_info.mass;	// ie, delta velocity of asteroid
				asteroid_damage = (asteroid_damage > ship_damage) ? asteroid_damage : ship_damage;

				// apply damage to asteroid
				asteroid_hit( pasteroid, pship, &hitpos, asteroid_damage);		// speed => damage

				//extern fix Missiontime;

				int quadrant_num;
				if ( asteroid_hit_info.heavy == pship ) {
					quadrant_num = get_ship_quadrant_from_global(&hitpos, pship);
					if ((pship->flags[Object::Object_Flags::No_shields]) || !ship_is_shield_up(pship, quadrant_num) ) {
						quadrant_num = -1;
					}
					ship_apply_local_damage(asteroid_hit_info.heavy, asteroid_hit_info.light, &hitpos, ship_damage, quadrant_num, CREATE_SPARKS, asteroid_hit_info.submodel_num);
				} else {
					// don't draw sparks (using sphere hitpos)
					ship_apply_local_damage(asteroid_hit_info.light, asteroid_hit_info.heavy, &hitpos, ship_damage, MISS_SHIELDS, NO_SPARKS);
				}

				// maybe print Collision on HUD
				if ( pship == Player_obj ) {					
					hud_start_text_flash(XSTR("Collision", 1431), 2000);
				}

				collide_ship_ship_do_sound(&hitpos, pship, pasteroid, pship==Player_obj);
			}

			Script_system.SetHookObjects(2, "Self",pship, "Object", pasteroid);
			if(!(asteroid_override && !ship_override))
				Script_system.RunCondition(CHA_COLLIDEASTEROID, '\0', NULL, pship);

			Script_system.SetHookObjects(2, "Self",pasteroid, "Object", pship);
			if((asteroid_override && !ship_override) || (!asteroid_override && !ship_override))
				Script_system.RunCondition(CHA_COLLIDESHIP, '\0', NULL, pasteroid);

			Script_system.RemHookVars(4, "Ship", "Asteroid", "Self", "Object");

			return 0;
		}

		return 0;
	} else {
		// estimate earliest time at which pair can hit
		float asteroid_max_speed, ship_max_speed, time;
		ship *shipp = &Ships[pship->instance];

		asteroid_max_speed = vm_vec_mag(&pasteroid->phys_info.vel);		// Asteroid... vel gets reset, not max vel.z
		asteroid_max_speed = MAX(asteroid_max_speed, 10.0f);

		if (ship_is_beginning_warpout_speedup(pship)) {
			ship_max_speed = MAX(ship_get_max_speed(shipp), ship_get_warpout_speed(pship));
		} else {
			ship_max_speed = ship_get_max_speed(shipp);
		}
		ship_max_speed = MAX(ship_max_speed, 10.0f);
		ship_max_speed = MAX(ship_max_speed, pship->phys_info.vel.xyz.z);


		time = 1000.0f * (dist - pship->radius - pasteroid->radius - 10.0f) / (asteroid_max_speed + ship_max_speed);		// 10.0f is a safety factor
		time -= 200.0f;		// allow one frame slow frame at ~5 fps

		if (time > 100) {
			pair->next_check_time = timestamp( fl2i(time) );
		} else {
			pair->next_check_time = timestamp(0);	// check next time
		}
		return 0;
	}
}
void asteroid_editor::update_init()
{
	int num_asteroids, idx, cur_choice;

	UpdateData(TRUE);
	if (last_field >= 0) {
		// store into temp asteroid field
		num_asteroids = a_field[last_field].num_initial_asteroids;
		a_field[last_field].num_initial_asteroids = m_enable_asteroids ? m_density : 0;
		if (a_field[last_field].num_initial_asteroids < 0)
			a_field[last_field].num_initial_asteroids = 0;

		if (a_field[last_field].num_initial_asteroids > MAX_ASTEROIDS)
			a_field[last_field].num_initial_asteroids = MAX_ASTEROIDS;

		if (num_asteroids != a_field[last_field].num_initial_asteroids)
			set_modified();

		vec3d	vel_vec = {1.0f, 0.0f, 0.0f};
		vm_vec_scale(&vel_vec, (float) m_avg_speed);

		MODIFY(a_field[last_field].vel.xyz.x, vel_vec.xyz.x);
		MODIFY(a_field[last_field].vel.xyz.y, vel_vec.xyz.y);
		MODIFY(a_field[last_field].vel.xyz.z, vel_vec.xyz.z);

		MODIFY(a_field[last_field].min_bound.xyz.x, (float) atof(m_min_x));
		MODIFY(a_field[last_field].min_bound.xyz.y, (float) atof(m_min_y));
		MODIFY(a_field[last_field].min_bound.xyz.z, (float) atof(m_min_z));
		MODIFY(a_field[last_field].max_bound.xyz.x, (float) atof(m_max_x));
		MODIFY(a_field[last_field].max_bound.xyz.y, (float) atof(m_max_y));
		MODIFY(a_field[last_field].max_bound.xyz.z, (float) atof(m_max_z));

		// type of field
		MODIFY(a_field[last_field].field_type, m_field_type);
		MODIFY(a_field[last_field].debris_genre, m_debris_genre);
		if ( (m_field_type == FT_PASSIVE) && (m_debris_genre == DG_SHIP) ) {
			// we should have ship debris
			for (idx=0; idx<MAX_ACTIVE_DEBRIS_TYPES; idx++) {
				// loop over combo boxes, store the item data of the cur selection, -1 in no cur selection
				int cur_sel = ((CComboBox*)GetDlgItem(Dlg_id[idx]))->GetCurSel();
				if (cur_sel != CB_ERR) {
					cur_choice = ((CComboBox*)GetDlgItem(Dlg_id[idx]))->GetItemData(cur_sel);
				} else {
					cur_choice = -1;
				}
				MODIFY(a_field[cur_field].field_debris_type[idx], cur_choice);
			}
		}

		if ( m_debris_genre == DG_ASTEROID ) {
			if ( ((CButton *)GetDlgItem(IDC_SUBTYPE1))->GetCheck() == 1) {
				cur_choice = 1;
			} else {
				cur_choice = -1;
			}
			MODIFY(a_field[cur_field].field_debris_type[0], cur_choice);


			if ( ((CButton *)GetDlgItem(IDC_SUBTYPE2))->GetCheck() == 1) {
				cur_choice = 1;
			} else {
				cur_choice = -1;
			}
			MODIFY(a_field[cur_field].field_debris_type[1], cur_choice);


			if ( ((CButton *)GetDlgItem(IDC_SUBTYPE3))->GetCheck() == 1) {
				cur_choice = 1;
			} else {
				cur_choice = -1;
			}
			MODIFY(a_field[cur_field].field_debris_type[2], cur_choice);
		}

		MODIFY(a_field[last_field].has_inner_bound, m_enable_inner_bounds);

		MODIFY(a_field[last_field].inner_min_bound.xyz.x, (float) atof(m_box_min_x));
		MODIFY(a_field[last_field].inner_min_bound.xyz.y, (float) atof(m_box_min_y));
		MODIFY(a_field[last_field].inner_min_bound.xyz.z, (float) atof(m_box_min_z));
		MODIFY(a_field[last_field].inner_max_bound.xyz.x, (float) atof(m_box_max_x));
		MODIFY(a_field[last_field].inner_max_bound.xyz.y, (float) atof(m_box_max_y));
		MODIFY(a_field[last_field].inner_max_bound.xyz.z, (float) atof(m_box_max_z));
	}

	Assert(cur_field >= 0);
	// get from temp asteroid field into class
	m_enable_asteroids = a_field[cur_field].num_initial_asteroids ? TRUE : FALSE;
	m_enable_inner_bounds = a_field[cur_field].has_inner_bound ? TRUE : FALSE;
	m_density = a_field[cur_field].num_initial_asteroids;
	if (!m_enable_asteroids)
		m_density = 10;

	// set field type
	m_field_type = a_field[cur_field].field_type;
	m_debris_genre = a_field[cur_field].debris_genre;
//	m_debris_species = a_field[cur_field].debris_species;

	m_avg_speed = (int) vm_vec_mag(&a_field[cur_field].vel);
	m_min_x.Format("%.1f", a_field[cur_field].min_bound.xyz.x);
	m_min_y.Format("%.1f", a_field[cur_field].min_bound.xyz.y);
	m_min_z.Format("%.1f", a_field[cur_field].min_bound.xyz.z);
	m_max_x.Format("%.1f", a_field[cur_field].max_bound.xyz.x);
	m_max_y.Format("%.1f", a_field[cur_field].max_bound.xyz.y);
	m_max_z.Format("%.1f", a_field[cur_field].max_bound.xyz.z);

	m_box_min_x.Format("%.1f", a_field[cur_field].inner_min_bound.xyz.x);
	m_box_min_y.Format("%.1f", a_field[cur_field].inner_min_bound.xyz.y);
	m_box_min_z.Format("%.1f", a_field[cur_field].inner_min_bound.xyz.z);
	m_box_max_x.Format("%.1f", a_field[cur_field].inner_max_bound.xyz.x);
	m_box_max_y.Format("%.1f", a_field[cur_field].inner_max_bound.xyz.y);
	m_box_max_z.Format("%.1f", a_field[cur_field].inner_max_bound.xyz.z);

	// set up combo boxes
	uint i;
	int j, k, index, box_index;

	// add "None" to each box
	for (k = 0; k < MAX_ACTIVE_DEBRIS_TYPES; k++)
	{
		box_index = ((CComboBox*)GetDlgItem(Dlg_id[k]))->AddString("None");
		((CComboBox*)GetDlgItem(Dlg_id[k]))->SetItemData(box_index, -1);
	}

	// now add each kind of debris to each box
	CString name;
	char *debris_size[NUM_DEBRIS_SIZES] = { "Small", "Medium", "Large" };

	// each species
	for (i = 0; i < Species_info.size(); i++)
	{
		// each size
		for (j = 0; j < NUM_DEBRIS_SIZES; j++)
		{
			name = CString(Species_info[i].species_name) + " " + debris_size[j];
			index = NUM_DEBRIS_SIZES + ((i * NUM_DEBRIS_SIZES) + j);

			// each box
			for (k = 0; k < MAX_ACTIVE_DEBRIS_TYPES; k++)
			{
				box_index = ((CComboBox*)GetDlgItem(Dlg_id[k]))->AddString(name);
				((CComboBox*)GetDlgItem(Dlg_id[k]))->SetItemData(box_index, index);
			}
		}
	}

	// set active debris type for each combo box
	int box_count, cur_box_data;
	for (idx=0;idx<MAX_ACTIVE_DEBRIS_TYPES; idx++) {
		// Only set selection if not "None"
		if (a_field[cur_field].field_debris_type[idx] != -1) {
			box_count = ((CComboBox*)GetDlgItem(Dlg_id[idx]))->GetCount();
			for (box_index=0; box_index<box_count; box_index++) {
				cur_box_data = ((CComboBox*)GetDlgItem(Dlg_id[idx]))->GetItemData(box_index);
				if (cur_box_data == a_field[cur_field].field_debris_type[idx]) {
					// set cur sel
					((CComboBox*)GetDlgItem(Dlg_id[idx]))->SetCurSel(box_index);
					break;
				}
			}
		}
	}

	// set up asteroid subtype checkboxes
	((CButton*)GetDlgItem(IDC_SUBTYPE1))->SetCheck(a_field[cur_field].field_debris_type[0] == 1);
	((CButton*)GetDlgItem(IDC_SUBTYPE2))->SetCheck(a_field[cur_field].field_debris_type[1] == 1);
	((CButton*)GetDlgItem(IDC_SUBTYPE3))->SetCheck(a_field[cur_field].field_debris_type[2] == 1);


	UpdateData(FALSE);
	OnEnableAsteroids();

	last_field = cur_field;
}
Esempio n. 27
0
//	-----------------------------------------------------------------------------------------------------------
//Simulate a physics object for this frame
do_physics_sim(object *obj)
{
	int ignore_obj_list[MAX_IGNORE_OBJS],n_ignore_objs;
	int iseg;
	int try_again;
	int fate;
	vms_vector frame_vec;			//movement in this frame
	vms_vector new_pos,ipos;		//position after this frame
	int count=0;
	int objnum;
	int WallHitSeg, WallHitSide;
	fvi_info hit_info;
	fvi_query fq;
	vms_vector save_pos;
	int save_seg;
	fix drag;
	fix sim_time;
	vms_vector start_pos;
	int obj_stopped=0;
	fix moved_time;			//how long objected moved before hit something
	vms_vector save_p0,save_p1;
	physics_info *pi;
	int orig_segnum = obj->segnum;

	Assert(obj->type != OBJ_NONE);
	Assert(obj->movement_type == MT_PHYSICS);

#ifndef NDEBUG
if (Dont_move_ai_objects)
	if (obj->control_type == CT_AI)
		return;
#endif

	pi = &obj->mtype.phys_info;

	do_physics_sim_rot(obj);

	if (!(pi->velocity.x || pi->velocity.y || pi->velocity.z || pi->thrust.x || pi->thrust.y || pi->thrust.z))
		return;

	objnum = obj-Objects;

	n_phys_segs = 0;

	disable_new_fvi_stuff = (obj->type != OBJ_PLAYER);

	sim_time = FrameTime;

//debug_obj = obj;

	#ifdef EXTRA_DEBUG
	if (obj == debug_obj) {
		printf("object %d:\n  start pos = %x %x %x\n",objnum,XYZ(&obj->pos));
		printf("  thrust = %x %x %x\n",XYZ(&obj->mtype.phys_info.thrust));
		printf("  sim_time = %x\n",sim_time);
	}

	//check for correct object segment 
	if(!get_seg_masks(&obj->pos,obj->segnum,0).centermask==0) {
		#ifndef NDEBUG
		mprintf((0,"Warning: object %d not in given seg!\n",objnum));
		#endif
		//Int3();  Removed by Rob 10/5/94
		if (!update_object_seg(obj)) {
			#ifndef NDEBUG
			mprintf((0,"Warning: can't find seg for object %d - moving\n",objnum));
			#endif
			if (!(Game_mode & GM_MULTI))
				Int3();
			compute_segment_center(&obj->pos,&Segments[obj->segnum]);
			obj->pos.x += objnum;
		}
	}
	#endif

	start_pos = obj->pos;

	n_ignore_objs = 0;

	Assert(obj->mtype.phys_info.brakes==0);		//brakes not used anymore?

		//if uses thrust, cannot have zero drag
	Assert(!(obj->mtype.phys_info.flags&PF_USES_THRUST) || obj->mtype.phys_info.drag!=0);

//mprintf((0,"thrust=%x  speed=%x\n",vm_vec_mag(&obj->mtype.phys_info.thrust),vm_vec_mag(&obj->mtype.phys_info.velocity)));

	//do thrust & drag
	
	if ((drag = obj->mtype.phys_info.drag) != 0) {

		int count;
		vms_vector accel;
		fix r,k;

		count = sim_time / FT;
		r = sim_time % FT;
		k = fixdiv(r,FT);

		if (obj->mtype.phys_info.flags & PF_USES_THRUST) {

			vm_vec_copy_scale(&accel,&obj->mtype.phys_info.thrust,fixdiv(f1_0,obj->mtype.phys_info.mass));

			while (count--) {

				vm_vec_add2(&obj->mtype.phys_info.velocity,&accel);

				vm_vec_scale(&obj->mtype.phys_info.velocity,f1_0-drag);
			}

			//do linear scale on remaining bit of time

			vm_vec_scale_add2(&obj->mtype.phys_info.velocity,&accel,k);

			vm_vec_scale(&obj->mtype.phys_info.velocity,f1_0-fixmul(k,drag));
		}
		else {
			fix total_drag=f1_0;

			while (count--)
				total_drag = fixmul(total_drag,f1_0-drag);

			//do linear scale on remaining bit of time

			total_drag = fixmul(total_drag,f1_0-fixmul(k,drag));

			vm_vec_scale(&obj->mtype.phys_info.velocity,total_drag);
		}
	}

	#ifdef EXTRA_DEBUG
	if (obj == debug_obj)
		printf("  velocity = %x %x %x\n",XYZ(&obj->mtype.phys_info.velocity));
	#endif

	do {
		try_again = 0;

		//Move the object
		vm_vec_copy_scale(&frame_vec, &obj->mtype.phys_info.velocity, sim_time);

		#ifdef EXTRA_DEBUG
		if (obj == debug_obj)
			printf("  pass %d, frame_vec = %x %x %x\n",count,XYZ(&frame_vec));
		#endif

		if ( (frame_vec.x==0) && (frame_vec.y==0) && (frame_vec.z==0) )	
			break;

		count++;

		//	If retry count is getting large, then we are trying to do something stupid.
		if ( count > 3) 	{
			if (obj->type == OBJ_PLAYER) {
				if (count > 8)
					break;
			} else
				break;
		}

		vm_vec_add(&new_pos,&obj->pos,&frame_vec);

		#ifdef EXTRA_DEBUG
		if (obj == debug_obj)
			printf("   desired_pos  = %x %x %x\n",XYZ(&new_pos));
		#endif

		ignore_obj_list[n_ignore_objs] = -1;

		#ifdef EXTRA_DEBUG
		if (obj == debug_obj) {
			printf("   FVI parms: p0 = %8x %8x %8x, segnum=%x, size=%x\n",XYZ(&obj->pos),obj->segnum,obj->size);
			printf("              p1 = %8x %8x %8x\n",XYZ(&new_pos));
		}
		#endif

		fq.p0						= &obj->pos;
		fq.startseg				= obj->segnum;
		fq.p1						= &new_pos;
		fq.rad					= obj->size;
		fq.thisobjnum			= objnum;
		fq.ignore_obj_list	= ignore_obj_list;
		fq.flags					= FQ_CHECK_OBJS;

		if (obj->type == OBJ_WEAPON)
			fq.flags |= FQ_TRANSPOINT;

		if (obj->type == OBJ_PLAYER)
			fq.flags |= FQ_GET_SEGLIST;

//@@			if (get_seg_masks(&obj->pos,obj->segnum,0).centermask!=0)
//@@				Int3();

save_p0 = *fq.p0;
save_p1 = *fq.p1;


		fate = find_vector_intersection(&fq,&hit_info);
		//	Matt: Mike's hack.
		if (fate == HIT_OBJECT) {
			object	*objp = &Objects[hit_info.hit_object];

			if ((objp->type == OBJ_WEAPON) && (objp->id == PROXIMITY_ID))
				count--;
		}

		#ifndef NDEBUG
		if (fate == HIT_BAD_P0) {
			mprintf((0,"Warning: Bad p0 in physics!  Object = %i, type = %i [%s]\n", obj-Objects, obj->type, Object_type_names[obj->type]));
			Int3();
		}
		#endif

		if (obj->type == OBJ_PLAYER) {
			int i;

			if (n_phys_segs && phys_seglist[n_phys_segs-1]==hit_info.seglist[0])
				n_phys_segs--;

			for (i=0;(i<hit_info.n_segs) && (n_phys_segs<MAX_FVI_SEGS-1);  )
				phys_seglist[n_phys_segs++] = hit_info.seglist[i++];
		}

		#ifdef EXTRA_DEBUG
		if (obj == debug_obj)
			printf("   fate  = %d, hit_pnt = %8x %8x %8x\n",fate,XYZ(&hit_info.hit_pnt));;
		#endif

		ipos = hit_info.hit_pnt;
		iseg = hit_info.hit_seg;
		WallHitSide = hit_info.hit_side;
		WallHitSeg = hit_info.hit_side_seg;

		if (iseg==-1) {		//some sort of horrible error
			#ifndef NDEBUG
			mprintf((1,"iseg==-1 in physics!  Object = %i, type = %i (%s)\n", obj-Objects, obj->type, Object_type_names[obj->type]));
			#endif
			//Int3();
			//compute_segment_center(&ipos,&Segments[obj->segnum]);
			//ipos.x += objnum;
			//iseg = obj->segnum;
			//fate = HIT_NONE;
			if (obj->type == OBJ_WEAPON)
				obj->flags |= OF_SHOULD_BE_DEAD;
			break;
		}

		Assert(!((fate==HIT_WALL) && ((WallHitSeg == -1) || (WallHitSeg > Highest_segment_index))));

		//if(!get_seg_masks(&hit_info.hit_pnt,hit_info.hit_seg,0).centermask==0)
		//	Int3();

		save_pos = obj->pos;			//save the object's position
		save_seg = obj->segnum;

		// update object's position and segment number
		obj->pos = ipos;

		#ifdef EXTRA_DEBUG
		if (obj == debug_obj)
			printf("   new pos = %x %x %x\n",XYZ(&obj->pos));
		#endif

		if ( iseg != obj->segnum )
			obj_relink(objnum, iseg );

		//if start point not in segment, move object to center of segment
		if (get_seg_masks(&obj->pos,obj->segnum,0).centermask!=0) {
			int n;

			if ((n=find_object_seg(obj))==-1) {
				//Int3();
				if (obj->type==OBJ_PLAYER && (n=find_point_seg(&obj->last_pos,obj->segnum))!=-1) {
					obj->pos = obj->last_pos;
					obj_relink(objnum, n );
				}
				else {
					compute_segment_center(&obj->pos,&Segments[obj->segnum]);
					obj->pos.x += objnum;
				}
				if (obj->type == OBJ_WEAPON)
					obj->flags |= OF_SHOULD_BE_DEAD;
			}
			return;
		}

		//calulate new sim time
		{
			//vms_vector moved_vec;
			vms_vector moved_vec_n;
			fix attempted_dist,actual_dist;

			actual_dist = vm_vec_normalized_dir(&moved_vec_n,&obj->pos,&save_pos);

			if (fate==HIT_WALL && vm_vec_dot(&moved_vec_n,&frame_vec) < 0) {		//moved backwards

				//don't change position or sim_time

//*******					mprintf((0,"Obj %d moved backwards\n",obj-Objects));

				#ifdef EXTRA_DEBUG
				if (obj == debug_obj)
					printf("   Warning: moved backwards!\n");
				#endif

				obj->pos = save_pos;
		
				//iseg = obj->segnum;		//don't change segment

				obj_relink(objnum, save_seg );

				moved_time = 0;
			}
			else {
				fix old_sim_time;

				//if (obj == debug_obj)
				//	printf("   moved_vec = %x %x %x\n",XYZ(&moved_vec));
			
				attempted_dist = vm_vec_mag(&frame_vec);

				old_sim_time = sim_time;

				sim_time = fixmuldiv(sim_time,attempted_dist-actual_dist,attempted_dist);

				moved_time = old_sim_time - sim_time;

				if (sim_time < 0 || sim_time>old_sim_time) {
					#ifndef NDEBUG
					mprintf((0,"Bogus sim_time = %x, old = %x\n",sim_time,old_sim_time));
					if (obj == debug_obj)
						printf("   Bogus sim_time = %x, old = %x, attempted_dist = %x, actual_dist = %x\n",sim_time,old_sim_time,attempted_dist,actual_dist);
					//Int3(); Removed by Rob
					#endif
					sim_time = old_sim_time;
					//WHY DOES THIS HAPPEN??

					moved_time = 0;
				}
			}

			#ifdef EXTRA_DEBUG
			if (obj == debug_obj)
				printf("   new sim_time = %x\n",sim_time);
			#endif

		}


		switch( fate )		{

			case HIT_WALL:		{
				vms_vector moved_v;
				//@@fix total_d,moved_d;
				fix hit_speed,wall_part;
	
				// Find hit speed	

				vm_vec_sub(&moved_v,&obj->pos,&save_pos);

				wall_part = vm_vec_dot(&moved_v,&hit_info.hit_wallnorm);

				if (wall_part != 0 && moved_time>0 && (hit_speed=-fixdiv(wall_part,moved_time))>0)
					collide_object_with_wall( obj, hit_speed, WallHitSeg, WallHitSide, &hit_info.hit_pnt );
				else
					scrape_object_on_wall(obj, WallHitSeg, WallHitSide, &hit_info.hit_pnt );

				Assert( WallHitSeg > -1 );				
				Assert( WallHitSide > -1 );				

				if ( !(obj->flags&OF_SHOULD_BE_DEAD) )	{


					Assert(! (obj->mtype.phys_info.flags & PF_STICK && obj->mtype.phys_info.flags & PF_BOUNCE));	//can't be bounce and stick

					if (obj->mtype.phys_info.flags & PF_STICK) {		//stop moving

						// mprintf((0, "Object %i stuck at %i:%i\n", obj-Objects, WallHitSeg, WallHitSide));
						add_stuck_object(obj, WallHitSeg, WallHitSide);

						vm_vec_zero(&obj->mtype.phys_info.velocity);
						obj_stopped = 1;
						try_again = 0;
					}
					else {					// Slide object along wall

						//We're constrained by wall, so subtract wall part from 
						//velocity vector

						wall_part = vm_vec_dot(&hit_info.hit_wallnorm,&obj->mtype.phys_info.velocity);

						if (obj->mtype.phys_info.flags & PF_BOUNCE)		//bounce off wall
							wall_part *= 2;	//Subtract out wall part twice to achieve bounce

						vm_vec_scale_add2(&obj->mtype.phys_info.velocity,&hit_info.hit_wallnorm,-wall_part);

						#ifdef EXTRA_DEBUG
						if (obj == debug_obj) {
							printf("   sliding - wall_norm %x %x %x\n",wall_part,XYZ(&hit_info.hit_wallnorm));
							printf("   wall_part %x, new velocity = %x %x %x\n",wall_part,XYZ(&obj->mtype.phys_info.velocity));
						}
						#endif

						try_again = 1;
					}
				}
				break;
			}

			case HIT_OBJECT:		{
				vms_vector old_vel;

				// Mark the hit object so that on a retry the fvi code
				// ignores this object.

				Assert(hit_info.hit_object != -1);

				//	Calculcate the hit point between the two objects.
				{	vms_vector	*ppos0, *ppos1, pos_hit;
					fix			size0, size1;
					ppos0 = &Objects[hit_info.hit_object].pos;
					ppos1 = &obj->pos;
					size0 = Objects[hit_info.hit_object].size;
					size1 = obj->size;
					Assert(size0+size1 != 0);	// Error, both sizes are 0, so how did they collide, anyway?!?
					//vm_vec_scale(vm_vec_sub(&pos_hit, ppos1, ppos0), fixdiv(size0, size0 + size1));
					//vm_vec_add2(&pos_hit, ppos0);
					vm_vec_sub(&pos_hit, ppos1, ppos0);
					vm_vec_scale_add(&pos_hit,ppos0,&pos_hit,fixdiv(size0, size0 + size1));

					old_vel = obj->mtype.phys_info.velocity;

					collide_two_objects( obj, &Objects[hit_info.hit_object], &pos_hit);

				}

				// Let object continue its movement
				if ( !(obj->flags&OF_SHOULD_BE_DEAD)  )	{
					//obj->pos = save_pos;

					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)) {
						//if (Objects[hit_info.hit_object].type == OBJ_POWERUP)
							ignore_obj_list[n_ignore_objs++] = hit_info.hit_object;
						try_again = 1;
					}
				}

				break;
			}	
			case HIT_NONE:		
				break;

			#ifndef NDEBUG
			case HIT_BAD_P0:
				Int3();		// Unexpected collision type: start point not in specified segment.
				mprintf((0,"Warning: Bad p0 in physics!!!\n"));
				break;
			default:
				// Unknown collision type returned from find_vector_intersection!!
				Int3();
				break;
			#endif
		}

	} while ( try_again );

	//	Pass retry count info to AI.
	if (obj->control_type == CT_AI) {
		if (count > 0) {
			Ai_local_info[objnum].retry_count = count-1;
			Total_retries += count-1;
			Total_sims++;
		}
	}

	if (! obj_stopped)	{	//Set velocity from actual movement
		vms_vector moved_vec;
		vm_vec_sub(&moved_vec,&obj->pos,&start_pos);
		vm_vec_copy_scale(&obj->mtype.phys_info.velocity,&moved_vec,fixdiv(f1_0,FrameTime));

		#ifdef BUMP_HACK
		if (obj==ConsoleObject && (obj->mtype.phys_info.velocity.x==0 && obj->mtype.phys_info.velocity.y==0 && obj->mtype.phys_info.velocity.z==0) &&
			  !(obj->mtype.phys_info.thrust.x==0 && obj->mtype.phys_info.thrust.y==0 && obj->mtype.phys_info.thrust.z==0)) {
			vms_vector center,bump_vec;

			//bump player a little towards center of segment to unstick

			compute_segment_center(&center,&Segments[obj->segnum]);
			vm_vec_normalized_dir_quick(&bump_vec,&center,&obj->pos);
			vm_vec_scale_add2(&obj->pos,&bump_vec,obj->size/5);
		}
		#endif
	}

	//Assert(check_point_in_seg(&obj->pos,obj->segnum,0).centermask==0);

	//if (obj->control_type == CT_FLYING)
	if (obj->mtype.phys_info.flags & PF_LEVELLING)
		do_physics_align_object( obj );


	//hack to keep player from going through closed doors
	if (obj->type==OBJ_PLAYER && obj->segnum!=orig_segnum && (Physics_cheat_flag!=0xBADA55) ) {
		int sidenum;

		sidenum = find_connect_side(&Segments[obj->segnum],&Segments[orig_segnum]);

		if (sidenum != -1) {

			if (! (WALL_IS_DOORWAY(&Segments[orig_segnum],sidenum) & WID_FLY_FLAG)) {
				side *s;
				int vertnum,num_faces,i;
				fix dist;
				int vertex_list[6];

				//bump object back

				s = &Segments[orig_segnum].sides[sidenum];

				create_abs_vertex_lists( &num_faces, vertex_list, orig_segnum, sidenum);

				//let's pretend this wall is not triangulated
				vertnum = vertex_list[0];
				for (i=1;i<4;i++)
					if (vertex_list[i] < vertnum)
						vertnum = vertex_list[i];

				#ifdef COMPACT_SEGS
					{
					vms_vector _vn;
					get_side_normal(&Segments[orig_segnum], sidenum, 0, &_vn );
					dist = vm_dist_to_plane(&start_pos, &_vn, &Vertices[vertnum]);
					vm_vec_scale_add(&obj->pos,&start_pos,&_vn,obj->size-dist);
					}
				#else
					dist = vm_dist_to_plane(&start_pos, &s->normals[0], &Vertices[vertnum]);
					vm_vec_scale_add(&obj->pos,&start_pos,&s->normals[0],obj->size-dist);
				#endif
				update_object_seg(obj);

			}
		}
	}

//--WE ALWYS WANT THIS IN, MATT AND MIKE DECISION ON 12/10/94, TWO MONTHS AFTER FINAL 	#ifndef NDEBUG
	//if end point not in segment, move object to last pos, or segment center
	if (get_seg_masks(&obj->pos,obj->segnum,0).centermask!=0) {
		if (find_object_seg(obj)==-1) {
			int n;

			//Int3();
			if (obj->type==OBJ_PLAYER && (n=find_point_seg(&obj->last_pos,obj->segnum))!=-1) {
				obj->pos = obj->last_pos;
				obj_relink(objnum, n );
			}
			else {
				compute_segment_center(&obj->pos,&Segments[obj->segnum]);
				obj->pos.x += objnum;
			}
			if (obj->type == OBJ_WEAPON)
				obj->flags |= OF_SHOULD_BE_DEAD;
		}
	}
//--WE ALWYS WANT THIS IN, MATT AND MIKE DECISION ON 12/10/94, TWO MONTHS AFTER FINAL 	#endif


}
Esempio n. 28
0
void asteroid_editor::update_init()
{
	int num_asteroids, idx, cur_choice;

	UpdateData(TRUE);
	if (last_field >= 0) {
		// store into temp asteroid field
		num_asteroids = a_field[last_field].num_initial_asteroids;
		a_field[last_field].num_initial_asteroids = m_enable_asteroids ? m_density : 0;
		if (a_field[last_field].num_initial_asteroids < 0)
			a_field[last_field].num_initial_asteroids = 0;

		if (a_field[last_field].num_initial_asteroids > MAX_ASTEROIDS)
			a_field[last_field].num_initial_asteroids = MAX_ASTEROIDS;

		if (num_asteroids != a_field[last_field].num_initial_asteroids)
			set_modified();

		vector	vel_vec = {1.0f, 0.0f, 0.0f};
		vm_vec_scale(&vel_vec, (float) m_avg_speed);

		MODIFY(a_field[last_field].vel.x, vel_vec.x);
		MODIFY(a_field[last_field].vel.y, vel_vec.y);
		MODIFY(a_field[last_field].vel.z, vel_vec.z);

		MODIFY(a_field[last_field].min_bound.x, (float) atof(m_min_x));
		MODIFY(a_field[last_field].min_bound.y, (float) atof(m_min_y));
		MODIFY(a_field[last_field].min_bound.z, (float) atof(m_min_z));
		MODIFY(a_field[last_field].max_bound.x, (float) atof(m_max_x));
		MODIFY(a_field[last_field].max_bound.y, (float) atof(m_max_y));
		MODIFY(a_field[last_field].max_bound.z, (float) atof(m_max_z));

		// type of field
		MODIFY(a_field[last_field].field_type, m_field_type);
		MODIFY(a_field[last_field].debris_genre, m_debris_genre);
		if ( (m_field_type == FT_PASSIVE) && (m_debris_genre == DG_SHIP) ) {
			// we should have ship debris
			for (idx=0; idx<3; idx++) {
				// loop over combo boxes, store the item data of the cur selection, -1 in no cur selection
				int cur_sel = ((CComboBox*)GetDlgItem(Dlg_id[idx]))->GetCurSel();
				if (cur_sel != CB_ERR) {
					cur_choice = ((CComboBox*)GetDlgItem(Dlg_id[idx]))->GetItemData(cur_sel);
				} else {
					cur_choice = -1;
				}
				MODIFY(a_field[cur_field].field_debris_type[idx], cur_choice);
			}
		}

		if ( m_debris_genre == DG_ASTEROID ) {
			if ( ((CButton *)GetDlgItem(IDC_SUBTYPE1))->GetCheck() == 1) {
				cur_choice = 1;
			} else {
				cur_choice = -1;
			}
			MODIFY(a_field[cur_field].field_debris_type[0], cur_choice);


			if ( ((CButton *)GetDlgItem(IDC_SUBTYPE2))->GetCheck() == 1) {
				cur_choice = 1;
			} else {
				cur_choice = -1;
			}
			MODIFY(a_field[cur_field].field_debris_type[1], cur_choice);


			if ( ((CButton *)GetDlgItem(IDC_SUBTYPE3))->GetCheck() == 1) {
				cur_choice = 1;
			} else {
				cur_choice = -1;
			}
			MODIFY(a_field[cur_field].field_debris_type[2], cur_choice);
		}

		MODIFY(a_field[last_field].has_inner_bound, m_enable_inner_bounds);

		MODIFY(a_field[last_field].inner_min_bound.x, (float) atof(m_box_min_x));
		MODIFY(a_field[last_field].inner_min_bound.y, (float) atof(m_box_min_y));
		MODIFY(a_field[last_field].inner_min_bound.z, (float) atof(m_box_min_z));
		MODIFY(a_field[last_field].inner_max_bound.x, (float) atof(m_box_max_x));
		MODIFY(a_field[last_field].inner_max_bound.y, (float) atof(m_box_max_y));
		MODIFY(a_field[last_field].inner_max_bound.z, (float) atof(m_box_max_z));
	}

	Assert(cur_field >= 0);
	// get from temp asteroid field into class
	m_enable_asteroids = a_field[cur_field].num_initial_asteroids ? TRUE : FALSE;
	m_enable_inner_bounds = a_field[cur_field].has_inner_bound ? TRUE : FALSE;
	m_density = a_field[cur_field].num_initial_asteroids;
	if (!m_enable_asteroids)
		m_density = 10;

	// set field type
	m_field_type = a_field[cur_field].field_type;
	m_debris_genre = a_field[cur_field].debris_genre;
//	m_debris_species = a_field[cur_field].debris_species;

	m_avg_speed = (int) vm_vec_mag(&a_field[cur_field].vel);
	m_min_x.Format("%.1f", a_field[cur_field].min_bound.x);
	m_min_y.Format("%.1f", a_field[cur_field].min_bound.y);
	m_min_z.Format("%.1f", a_field[cur_field].min_bound.z);
	m_max_x.Format("%.1f", a_field[cur_field].max_bound.x);
	m_max_y.Format("%.1f", a_field[cur_field].max_bound.y);
	m_max_z.Format("%.1f", a_field[cur_field].max_bound.z);

	m_box_min_x.Format("%.1f", a_field[cur_field].inner_min_bound.x);
	m_box_min_y.Format("%.1f", a_field[cur_field].inner_min_bound.y);
	m_box_min_z.Format("%.1f", a_field[cur_field].inner_min_bound.z);
	m_box_max_x.Format("%.1f", a_field[cur_field].inner_max_bound.x);
	m_box_max_y.Format("%.1f", a_field[cur_field].inner_max_bound.y);
	m_box_max_z.Format("%.1f", a_field[cur_field].inner_max_bound.z);

	// set up combo boxes
	int box_index;
	int num_field_debris_info = MAX_DEBRIS_TYPES + 1;

	for (idx=0; idx<num_field_debris_info; idx++) {
		box_index = ((CComboBox*)GetDlgItem(IDC_SHIP_DEBRIS1))->AddString(Field_debris_info[idx].name);
		((CComboBox*)GetDlgItem(IDC_SHIP_DEBRIS1))->SetItemData(box_index, Field_debris_info[idx].index);

		box_index = ((CComboBox*)GetDlgItem(IDC_SHIP_DEBRIS2))->AddString(Field_debris_info[idx].name);
		((CComboBox*)GetDlgItem(IDC_SHIP_DEBRIS2))->SetItemData(box_index, Field_debris_info[idx].index);

		box_index = ((CComboBox*)GetDlgItem(IDC_SHIP_DEBRIS3))->AddString(Field_debris_info[idx].name);
		((CComboBox*)GetDlgItem(IDC_SHIP_DEBRIS3))->SetItemData(box_index, Field_debris_info[idx].index);
	}

	// now delete asteroid data
	// search by string Field_debris_info[1-3].name

	for (idx=0; idx<3; idx++) {
		box_index = ((CComboBox*)GetDlgItem(Dlg_id[idx]))->FindStringExact(0, Field_debris_info[1].name);	// "Asteroid Small"
		if (box_index > 0) {
			((CComboBox*)GetDlgItem(Dlg_id[idx]))->DeleteString(box_index);
		}

		box_index = ((CComboBox*)GetDlgItem(Dlg_id[idx]))->FindStringExact(0, Field_debris_info[2].name);	// "Asteroid Medium"
		if (box_index > 0) {
			((CComboBox*)GetDlgItem(Dlg_id[idx]))->DeleteString(box_index);
		}

		box_index = ((CComboBox*)GetDlgItem(Dlg_id[idx]))->FindStringExact(0, Field_debris_info[3].name);	// "Asteroid Big"
		if (box_index > 0) {
			((CComboBox*)GetDlgItem(Dlg_id[idx]))->DeleteString(box_index);
		}
	}

	// set active debris type for each combo box
	int box_count, cur_box_data;
	for (idx=0;idx<3; idx++) {
		// Only set selection if not "None"
		if (a_field[cur_field].field_debris_type[idx] != -1) {
			box_count = ((CComboBox*)GetDlgItem(Dlg_id[idx]))->GetCount();
			for (box_index=0; box_index<box_count; box_index++) {
				cur_box_data = ((CComboBox*)GetDlgItem(Dlg_id[idx]))->GetItemData(box_index);
				if (cur_box_data == a_field[cur_field].field_debris_type[idx]) {
					// set cur sel
					((CComboBox*)GetDlgItem(Dlg_id[idx]))->SetCurSel(box_index);
					break;
				}
			}
		}
	}

	// set up asteroid subtype checkboxes
	((CButton*)GetDlgItem(IDC_SUBTYPE1))->SetCheck(a_field[cur_field].field_debris_type[0] == 1);
	((CButton*)GetDlgItem(IDC_SUBTYPE2))->SetCheck(a_field[cur_field].field_debris_type[1] == 1);
	((CButton*)GetDlgItem(IDC_SUBTYPE3))->SetCheck(a_field[cur_field].field_debris_type[2] == 1);


	UpdateData(FALSE);
	OnEnableAsteroids();

	last_field = cur_field;
}
// 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;
}
Esempio n. 30
0
// ********************************************************************************************
// Checks for changes every NPS_TICKRATE milliseconds
// Checks:
//			* if we've gotten close enough to a nav point for it to be counted as "Visited"
//			* If we're current AutoNavigating it checks if we need to autodisengage
void NavSystem_Do()
{
	static unsigned int last_update = 0;
	if (clock () - last_update > NPS_TICKRATE)
	{
		if (AutoPilotEngaged)
		{
			if (The_mission.flags & MISSION_FLAG_USE_AP_CINEMATICS)
			{
				camera *cam = nav_get_set_camera();
				if (CinematicStarted)
				{
					// update our cinematic and possibly perform warp
					//if (!CameraMoving)
					if(cam != NULL)
						cam->set_rotation_facing(&Player_obj->pos);

					if (timestamp() >= MoveCamera && !CameraMoving && vm_vec_mag(&cameraTarget) > 0.0f)
					{
						//Free_camera->set_position(&cameraTarget, float(camMovingTime), float(camMovingTime)/2.0f);
						//Free_camera->set_translation_velocity(&cameraTarget);
						CameraMoving = true;
					}


					if (timestamp() >= EndAPCinematic || !CanAutopilot())
					{
						nav_warp();
						EndAutoPilot();
					}
				}
				else
				{
					// start cinematic
					if (UseCutsceneBars)
					{
						Cutscene_bar_flags |= CUB_CUTSCENE;
						Cutscene_bar_flags &= ~CUB_GRADUAL;
					}
					nav_warp(true);

					if(cam != NULL)
					{
						cam->set_position(&cameraPos);
						cam->set_rotation_facing(&Autopilot_flight_leader->pos);
					}

					CinematicStarted = true;
				}
			}
			else
			{
				if (!CanAutopilot())
					EndAutoPilot();

			}

		}
		// check if a NavPoints target has left, delete it if so
		int i;

		for (i = 0; i < MAX_NAVPOINTS; i++)
		{
			if ((Navs[i].flags & NP_SHIP) && (Navs[i].target_obj != NULL))
			{
				if (((ship*)Navs[i].target_obj)->objnum == -1)
				{
					if (CurrentNav == i)
						CurrentNav = -1;
					DelNavPoint(i);
				}
			}
		}
		
		// check if we're reached a Node
		for (i = 0; i < MAX_NAVPOINTS; i++)
		{
			if (Navs[i].target_obj != NULL)
			{
				if (Navs[i].flags & NP_VALIDTYPE && DistanceTo(i) < 1000)
					Navs[i].flags |= NP_VISITED;
			}
		}
	}

	// ramp time compression - only if not using cinematics
	if (AutoPilotEngaged && !(The_mission.flags & MISSION_FLAG_USE_AP_CINEMATICS))
	{
		int dstfrm_start = start_dist - DistanceTo(CurrentNav);

		// Ramp UP time compression
		if (dstfrm_start < (3500*ramp_bias))
		{

			if (dstfrm_start >= (3000*ramp_bias) && DistanceTo(CurrentNav) > 30000)
				set_time_compression(64);
			else if (dstfrm_start >= (2000*ramp_bias))
				set_time_compression(32);
			else if (dstfrm_start >= (1600*ramp_bias))
				set_time_compression(16);
			else if (dstfrm_start >= (1200*ramp_bias))
				set_time_compression(8);
			else if (dstfrm_start >= (800*ramp_bias))
				set_time_compression(4);
			else if (dstfrm_start >= (400*ramp_bias))
				set_time_compression(2);
		}

		// Ramp DOWN time compression
		if (DistanceTo(CurrentNav) <= (7000*ramp_bias))
		{
			int dist = DistanceTo(CurrentNav);
			if (dist >= (5000*ramp_bias))
				set_time_compression(32);
			else if (dist >= (4000*ramp_bias))
				set_time_compression(16);
			else if (dist >= (3000*ramp_bias))
				set_time_compression(8);
			else if (dist >= (2000*ramp_bias))
				set_time_compression(4);
			else if (dist >= (1000*ramp_bias))
				set_time_compression(2);
		}
	}

	/* Link in any ships that need to be linked in when the player gets close
	enough.  Always done by the player because: "making sure the AI fighters 
	are where they're supposed to be at all times is like herding cats" -Woolie Wool
	*/
	for (int i = 0; i < MAX_SHIPS; i++)
	{
		if (Ships[i].objnum != -1 && Ships[i].flags2 & SF2_NAVPOINT_NEEDSLINK)
		{
			object *other_objp = &Objects[Ships[i].objnum];

			if (vm_vec_dist_quick(&Player_obj->pos, &other_objp->pos) < (NavLinkDistance + other_objp->radius))
			{
				Ships[i].flags2 &= ~SF2_NAVPOINT_NEEDSLINK;
				Ships[i].flags2 |= SF2_NAVPOINT_CARRY;
				
				send_autopilot_msgID(NP_MSG_MISC_LINKED);
			}
		
		}
	}
}