Example #1
0
bool ElevatorTrim::ProcessMouse2D (int event, int mx, int my)
{
	double tgtlvl = vessel->GetControlSurfaceLevel (AIRCTRL_ELEVATORTRIM);
	tgtlvl += oapiGetSimStep() * (my < 30 ? -0.2:0.2);
	tgtlvl = max (-1.0, min (1.0, tgtlvl));
	vessel->SetControlSurfaceLevel (AIRCTRL_ELEVATORTRIM, tgtlvl);
	return true;
}
Example #2
0
void Saturn1b::AutoPilot(double autoT)
{
	TRACESETUP("Saturn1b::AutoPilot");

	const double GRAVITY=6.67259e-11;
	static int first_time=1;
	static int t = 0;
	static int out_level=0;
	double level=0.;
	double altitude;
	double pitch;
	double pitch_c;
	double heading;
	double bank;
	VECTOR3 rhoriz;

	double TO_HDG = agc.GetDesiredAzimuth();

	AltitudePREV = altitude = GetAltitude();
	VESSELSTATUS vsp;
	GetStatus(vsp);
	double totalRot=0;
	totalRot=vsp.vrot.x+vsp.vrot.y+vsp.vrot.z;
	if (fabs(totalRot) >= 0.0025){
		StopRot = true;
	}

	// This vector rotation will be used to tell if heads up (rhoriz.z<0) or heads down.
	HorizonRot(_V(1,0,0), rhoriz);

	//
	// Shut down the engines when we reach the desired
	// orbit.
	//

	double apogee, perigee;
	OBJHANDLE ref = GetGravityRef();
	GetApDist(apogee);
	GetPeDist(perigee);
	apogee = (apogee - oapiGetSize(ref)) / 1000.;
	perigee = (perigee - oapiGetSize(ref)) / 1000.;

	// We're aiming for periapsis and shutdown when apoapsis is reached at the opposite side of the orbit
	if (apogee >= agc.GetDesiredApogee() && perigee >= agc.GetDesiredPerigee() - 0.1) {
		// See Saturn::CheckForLaunchShutdown()
		if (GetThrusterLevel(th_main[0]) > 0){
			SetThrusterLevel(th_main[0], 0);			
			if (oapiGetTimeAcceleration() > 1.0)
				oapiSetTimeAcceleration(1.0);

			agc.LaunchShutdown();

			// Reset autopilot commands
			AtempP  = 0;
			AtempY  = 0;
			AtempR  = 0;			
		}
		return;
	}

	// navigation
	pitch = GetPitch();
	pitch = pitch*180./PI;
	//sprintf(oapiDebugString(), "Autopilot %f", altitude);
	// guidance
	pitch_c = GetCPitch(autoT);
	// control
	if (altitude > 4500) {
		// Damp roll motion
		bank = GetBank();
		bank = bank *180. / PI;
		if (bank > 90) bank = bank - 180.;
		else if (bank < -90) bank = bank + 180.;
		AtempR = -bank / 20.0;
		if (fabs(bank) < 0.3) AtempR = 0;

		// navigation
		pitch = GetPitch();
		pitch = pitch * 180. / PI;

		if (IGMEnabled) {
			VECTOR3 target;
			double pit, yaw;
			double bradius = oapiGetSize(ref);
			double bmass = oapiGetMass(ref);
			double mu = GRAVITY * bmass;
			// Aim for periapsis
			double altco = agc.GetDesiredPerigee() * 1000.;
			double velo = sqrt(mu / (bradius + altco));
			target.x = velo;
			target.y = 0.0;
			target.z = altco;
			LinearGuidance(target, pit, yaw);
			AtempP=(pit * DEG - pitch) / 30.0;
			if (AtempP < -0.15) AtempP = -0.15;
			if (AtempP >  0.15) AtempP =  0.15;
		}
		else {
			 // guidance
			pitch_c = GetCPitch(autoT);

			 // control
			double SatApo;
			GetApDist(SatApo);

			if ((SatApo >= ((agc.GetDesiredApogee() *.90) + ERADIUS)*1000) || MissionTime >= IGMStartTime)
				IGMEnabled = true;
		
			level = pitch_c - pitch;

			//sprintf(oapiDebugString(), "Autopilot Pitch Mode%f", elemSaturn1B.a );

			if (fabs(level)<10 && StopRot){	// above atmosphere, soft correction
				AtempP = 0.0;
				AtempR = 0.0;
				AtempY = 0.0;
				StopRot = false;
			}
			if (fabs(level)<0.05){	// above atmosphere, soft correction
				AtempP = 0.0;
				AtempR = 0.0;
				AtempY = 0.0;
			}
			else if (level>0 && fabs(vsp.vrot.z) < 0.09){
				AtempP = -(fabs(level) / 10.);
				if (AtempP < -1.0)AtempP = -1.0;
				if (rhoriz.z>0) AtempP = -AtempP;
			}
			else if (level<0 && fabs(vsp.vrot.z) < 0.09) {
				AtempP = (fabs(level) / 10.);
				if (AtempP > 1.0) AtempP = 1.0;
				if (rhoriz.z>0) AtempP = -AtempP;
			}
			else {
				AtempP = 0.0;
				AtempR = 0.0;
				AtempY = 0.0;
			}
			// sprintf(oapiDebugString(), "autoT %f AtempP %f AtempR %f AtempY %f altitude %f pitch %f pitch_c %f", 
			//  					       autoT, AtempP, AtempR, AtempY, altitude, pitch, pitch_c);
		}
	}
	// sprintf(oapiDebugString(), "Alt %f Pitch %f Roll %f Yaw %f autoT %f", altitude, AtempP, AtempR, AtempY, autoT);

	double slip;
	VECTOR3 az;
	VECTOR3 up, north, east, ygl, zgl, zerogl;
	OBJHANDLE hbody=GetGravityRef();
	double bradius=oapiGetSize(hbody);

	// set up our reference frame
	Local2Global(_V(0.0, 0.0, 0.0), zerogl);
	Local2Global(_V(0.0, 1.0, 0.0), ygl);
	Local2Global(_V(0.0, 0.0, 1.0), zgl);
	ygl=ygl-zerogl;
	zgl=zgl-zerogl;

	oapiGetHeading(GetHandle(),&heading);
	heading = heading*180./PI;

	// Inclination control
	static int incinit = 0; 
	static ELEMENTS elemlast; 
	static double incratelast;

	ELEMENTS elem;
	GetElements(ref, elem, 0, 0, FRAME_EQU);
	double incrate = (elem.i - elemlast.i) / oapiGetSimStep();
	double incraterate = (incrate - incratelast) / oapiGetSimStep();	
	double target = (agc.GetDesiredInclination() - elem.i * DEG) / (FirstStageShutdownTime - MissionTime);

	if (agc.GetDesiredInclination() != 0 && autoT > 45) {	
		if (incinit < 2) {
			incinit++;
			AtempY = 0;
		} else {
			if (autoT < FirstStageShutdownTime - 10) {	
				AtempY = (incrate * DEG - target) / 0.7 + incraterate * DEG / 2.;
				if (AtempY < -0.1) AtempY = -0.1;
				if (AtempY >  0.1) AtempY =  0.1;
			} else if (autoT < FirstStageShutdownTime + 10) {	
				AtempY = 0;
			} else {
				AtempY = (elem.i * DEG - agc.GetDesiredInclination()) / 7. + (incrate * DEG ) / 1.;
				if (AtempY < -0.01) AtempY = -0.01;
				if (AtempY >  0.01) AtempY =  0.01;
			}
		}
	}
	
	elemlast = elem;
	incratelast = incrate;

	// stage handling
	switch (stage){
		case LAUNCH_STAGE_ONE:
			GetRelativePos(hbody, up);
			up=Normalize(up);
			agc.EquToRel(PI/2.0, 0.0, bradius, north);
			north=Normalize(north);
			east=Normalize(CrossProduct(north, up));
			north=Normalize(CrossProduct(up, east));
			az=east*sin(TO_HDG*RAD)-north*cos(TO_HDG*RAD);
			if(autoT < 60.0) normal=Normalize(CrossProduct(up, az));

			slip=GetSlipAngle()*DEG;

			if(autoT < 10.) {
				AtempR=0.0;
				AtempY=0.0;
				// cancel out the yaw maneuver...
				AtempY=(-0.4+asin(zgl*normal)*DEG)/20.0;
			}

			if(autoT > 10.0 && autoT < 30.0) {
				// roll program
				AtempR=asin(ygl*normal)*DEG/20.0;
				AtempY=asin(zgl*normal)*DEG/20.0;
				if (AtempR < -0.25) AtempR = -0.25;
				if (AtempR >  0.25) AtempR =  0.25;
			}

			if(autoT > 30.0 && autoT < 45.0) {
				//pitch and adjust for relative wind
				AtempR=asin(ygl*normal)*DEG/20.0;
				//AtempY=(slip+asin(zgl*normal)*DEG)/20.0;
				AtempY=(TO_HDG-(heading+slip))/20.0;
				if (AtempR < -0.25) AtempR = -0.25;
				if (AtempR >  0.25) AtempR =  0.25;
			}
			pitch = GetPitch();
			pitch=pitch*180./PI;
			pitch_c=GetCPitch(autoT);
			AtempP = (pitch_c - pitch);

			// Fix for LC 39
			if (autoT < 10 && heading > 180)
				AtempP = -(180. - pitch_c - pitch);

			if (AtempP > 1.0) AtempP = 1.0;
			if (AtempP < -1.0) AtempP = -1.0;

			// zero angle-of-attack...
			if(autoT > 45.0 && autoT < 115.0) {

				/// \todo Disabled for now, the Saturn 1B doesn't seem to do that...
				//double aoa=GetAOA()*DEG;
				//pitch_c=pitch+aoa-0.3;

				AtempP=(pitch_c - pitch) / 5.0;
				if(AtempP < -0.2) AtempP = -0.2;
				if(AtempP >  0.2) AtempP = 0.2;
				// sprintf(oapiDebugString(), " pitch=%.3f pc=%.3f ap=%.3f", pitch, pitch_c, AtempP);
			}
			if (autoT > 115.0) {
				if (autoT < 120.0) {
					if (AtempP < -0.1) AtempP = -0.1;
					if (AtempP >  0.1) AtempP =  0.1;
				} else {
					if (AtempP < -0.2) AtempP = -0.2;
					if (AtempP >  0.2) AtempP =  0.2;
				}
				normal=Normalize(CrossProduct(Normalize(vsp.rpos), Normalize(vsp.rvel)));
			}
			// sprintf(oapiDebugString(), "roll=%.3f yaw=%.3f slip=%.3f sum=%.3f hdg+slip=%.3f hdg=%.3f ay=%.3f", 
			//     asin(ygl*normal)*DEG, asin(zgl*normal)*DEG, slip, slip+asin(zgl*normal)*DEG, heading+slip, heading, AtempY);
			// sprintf(oapiDebugString(), "autoT %f AtempP %f AtempR %f AtempY %f altitude %f pitch %f pitch_c %f rhoriz.z %f", 
			//     autoT, AtempP, AtempR, AtempY, altitude, pitch, pitch_c, rhoriz.z);
			/*
			char buffer[80];
			sprintf(buffer,"AtempP %f AtempR %f AtempY %f", AtempP, AtempR, AtempY);	
			TRACE(buffer);
			*/

			AttitudeLaunch1();
			break;

		case LAUNCH_STAGE_SIVB:
			AttitudeLaunchSIVB();
			break;
	}

	// sprintf(oapiDebugString(), "AP - inc %f rate %f target %f raterate %f AtempP %f AtempR %f AtempY %f", elem.i * DEG, incrate * DEG, target, incraterate * DEG, AtempP, AtempR, AtempY);
	// sprintf(oapiDebugString(), "AP - pitch %f pitch_c %f heading %f AtempP %f AtempR %f AtempY %f", pitch, pitch_c, heading, AtempP, AtempR, AtempY);
}
Example #3
0
bool ADIBall::Redraw2D (SURFHANDLE surf)
{
	VECTOR3 euler = aref->GetEulerAngles ();
	double rho = euler.x; // roll angle
	double tht = euler.y; // pitch angle
	double phi = euler.z; // yaw angle
	double dt = oapiGetSimStep();

	const double ballspeed = 3.0;
	double dangle_max = ballspeed*dt;

	double drho = rho-rho_curr;
	if (drho > PI)       drho -= PI2;
	else if (drho < -PI) drho += PI2;
	double dtht = tht-tht_curr;
	if (dtht > PI)       dtht -= PI2;
	else if (dtht < -PI) dtht += PI2;
	double dphi = phi-phi_curr;
	if (dphi > PI)       dphi -= PI2;
	else if (dphi < -PI) dphi += PI2;
	double dangle = max (fabs(drho), max (fabs(dtht), fabs(dphi)));
	if (dangle > dangle_max) {
		double scale = dangle_max/dangle;
		rho = rho_curr + drho*scale;
		tht = tht_curr + dtht*scale;
		phi = phi_curr + dphi*scale;
	}
	rho_curr = rho;
	tht_curr = tht;
	phi_curr = phi;

	DWORD i;

	double sinp = sin(phi), cosp = cos(phi);
	double sint = sin(tht), cost = cos(tht);
	double sinr = sin(rho), cosr = cos(rho);

	// Ball transformation
	double a1, b1, c1, a2, b2, c2, a3, b3, c3;

	if (layout == 0) {
		// below are the coefficients of the rows of the rotation matrix M for the ball,
		// given by M = RTP, with
		// MATRIX3 P = {cosp,0,-sinp,  0,1,0,  sinp,0,cosp};
		// MATRIX3 T = {1,0,0,  0,cost,-sint,  0,sint,cost};
		// MATRIX3 R = {cosr,sinr,0,  -sinr,cosr,0,  0,0,1};

		a1 =  cosr*cosp - sinr*sint*sinp;
		b1 =  sinr*cost;
		c1 = -cosr*sinp - sinr*sint*cosp;
		a2 = -sinr*cosp - cosr*sint*sinp;
		b2 =  cosr*cost;
		c2 =  sinr*sinp - cosr*sint*cosp;
		a3 =  cost*sinp;
		b3 =  sint;
		c3 =  cost*cosp;

	} else {
		// below are the coefficients of the rows of the rotation matrix M for the ball,
		// given by M = ZRPT, with
		// MATRIX3 Z = {0,1,0,  -1,0,0,  0,0,1};
		// MATRIX3 P = {1,0,0,  0,cosp,-sinp,  0,sinp,cosp};  // yaw
		// MATRIX3 T = {cost,0,sint,  0,1,0,  -sint,0,cost};  // pitch
		// MATRIX3 R = {cosr,sinr,0,  -sinr,cosr,0,  0,0,1};  // bank

		a1 = -sinr*cost + cosr*sinp*sint;
		b1 =  cosr*cosp;
		c1 = -sinr*sint - cosr*sinp*cost;
		a2 = -cosr*cost - sinr*sinp*sint;
		b2 = -sinr*cosp;
		c2 = -cosr*sint + sinr*sinp*cost;
		a3 = -cosp*sint;
		b3 =  sinp;
		c3 =  cosp*cost;
	}

	for (i = 0; i < nballvtx; i++) {
		ballgrp->Vtx[ballofs+i].x = bb_cntx + (float)(a1*ballvtx0[i].x + b1*ballvtx0[i].y + c1*ballvtx0[i].z);
		ballgrp->Vtx[ballofs+i].y = bb_cnty - (float)(a2*ballvtx0[i].x + b2*ballvtx0[i].y + c2*ballvtx0[i].z);
	}

	// Roll indicator transformation
	static const float bx[4] = {-bank_dx2,bank_dx2,-bank_dx2,bank_dx2};
	static const float by[4] = {-bank_rad,-bank_rad,-bank_rad+bank_dy,-bank_rad+bank_dy};
	for (i = 0; i < 4; i++) {
		indgrp->Vtx[rollindofs+i].x = bb_cntx + (float)(bx[i]*cosr-by[i]*sinr);
		indgrp->Vtx[rollindofs+i].y = bb_cnty + (float)(bx[i]*sinr+by[i]*cosr);
	}

	// error needles
	double tgtx, tgty;
	static const float yexofs[4] = {bb_cntx-needle_w2,bb_cntx+needle_w2,bb_cntx-needle_w2,bb_cntx+needle_w2};
	static const float peyofs[4] = {bb_cnty+needle_w2,bb_cnty-needle_w2,bb_cnty+needle_w2,bb_cnty-needle_w2};
	const float erange = 42.0f;
	int tgtflag;
	VECTOR3 euler_tgt;
	if (!aref->GetTgtEulerAngles (euler_tgt)) {
		tgtx = tgty = 0.0;
		tgtflag = 0;
	} else {
		VECTOR3 tgt;
		double sint = sin(euler_tgt.y), cost = cos(euler_tgt.y);
		double sinp = sin(euler_tgt.z), cosp = cos(euler_tgt.z);
		if (layout == 0) {
			tgt = _V(rad*sinp*cost, rad*sint, rad*cosp*cost);
		} else {
			tgt = _V(-rad*sint*cosp, rad*sinp, rad*cost*cosp);
		}
		tgtx = min(max( (a1*tgt.x + b1*tgt.y + c1*tgt.z), -erange), erange);
		tgty = min(max(-(a2*tgt.x + b2*tgt.y + c2*tgt.z), -erange), erange);
		double tgtz =    a3*tgt.x + b3*tgt.y + c3*tgt.z;
		tgtflag = (tgtz >= 0.0 ? 1 : 2);
	}
	const double needlespeed = 50.0;
	double dneedlemax = needlespeed*dt;
	if (fabs(tgtx-tgtx_curr) > dneedlemax)
		tgtx = (tgtx > tgtx_curr ? tgtx_curr + dneedlemax : tgtx_curr - dneedlemax);
	if (fabs(tgty-tgty_curr) > dneedlemax)
		tgty = (tgty > tgty_curr ? tgty_curr + dneedlemax : tgty_curr - dneedlemax);
	tgtx_curr = tgtx;
	tgty_curr = tgty;
	for (i = 0; i < 4; i++) {
		indgrp->Vtx[yeofs+i].x = (float)tgtx+yexofs[i];
		indgrp->Vtx[peofs+i].y = (float)tgty+peyofs[i];
	}
	// to/from indicator
	static float tf_tu[4] = {tx_tf_x0/texw,(tx_tf_x0+tx_tf_dx)/texw,tx_tf_x0/texw,(tx_tf_x0+tx_tf_dx)/texw};
	float tf_dtu = tgtflag * tx_tf_dx/texw;
	for (i = 0; i < 4; i++)
		indgrp->Vtx[tfofs+i].tu = tf_tu[i] + tf_dtu;

	// Rate indicators
	const double rate_scale = DEG*4.0;
	const double rate_max = 41.0;
	if (rate_local) {
		vessel->GetAngularVel (vrot);
	} else {
		double t = oapiGetSimTime();
		if (t > euler_t) {
			VECTOR3 de = (euler-peuler)/(t-euler_t);
			vrot.x =  de.y;
			vrot.y = -de.z;
			vrot.z = -de.x;
			peuler = euler;
			euler_t = t;
		}
	}

	// Pitch rate indicator transformation
	static const float pry[4] = {bb_cnty+rate_w2,bb_cnty-rate_w2,bb_cnty+rate_w2,bb_cnty-rate_w2};
	float dp = (float)max (-rate_max, min (rate_max, vrot.x*rate_scale));
	for (i = 0; i < 4; i++) indgrp->Vtx[prateofs+i].y = pry[i]-dp;

	// Roll rate indicator transformation
	static const float brx[4] = {bb_cntx+rate_w2,bb_cntx-rate_w2,bb_cntx+rate_w2,bb_cntx-rate_w2};
	float db = (float)max (-rate_max, min (rate_max, vrot.z*rate_scale));
	for (i = 0; i < 4; i++) indgrp->Vtx[brateofs+i].x = brx[i]+db;

	// Yaw rate indicator transformation
	static const float yrx[4] = {bb_cntx-rate_w2,bb_cntx+rate_w2,bb_cntx-rate_w2,bb_cntx+rate_w2};
	float dy = (float)max (-rate_max, min (rate_max, vrot.y*rate_scale));
	for (i = 0; i < 4; i++) indgrp->Vtx[yrateofs+i].x = yrx[i]-dy;

	return false;
}
Example #4
0
void VOBJ::TimeStep(int SoundID)
{
	if (!oapiIsVessel(hook)){
		sprintf(msg, "Unknown Error");
		return;
	}
	if (!oapiGetVesselByIndex(iTarget) && mode == VTOV){
		mode=MAGIC;
		iTargetSource=0;
		iTarget=0;
	}
	if (VESSEL(hook).GetPropellantCount() < 1)
	{
		sprintf(msg, "No fuel sources available");
		return;
	}
	if (status==IDLE)
	{
		sprintf(msg, "IDLE: Waiting for action");
		return;
	}
	PlayMFDWave(SoundID, 0);
	if (mode==VTOV)
	{
		VESSEL * vHook = oapiGetVesselInterface(hook);
		VESSEL * vTarget = oapiGetVesselInterface(oapiGetVesselByIndex(iTarget));
		if (vTarget->GetPropellantCount() < 1)
		{
			sprintf(msg, "Target has no fuel sources");
			return;
		}
		PROPELLANT_HANDLE hpTarget = vTarget->GetPropellantHandleByIndex(iTargetSource);
		PROPELLANT_HANDLE hpHook   = vHook->GetPropellantHandleByIndex(iSelectedSource);
		if (!hpHook||!hpTarget){
			sprintf(msg, "Unknown Error!");
			return;
		}
		double maxMasstarget = vTarget->GetPropellantMaxMass(hpTarget);
		double massTarget = vTarget->GetPropellantMass(hpTarget);
		double maxMasshook = vHook->GetPropellantMaxMass(hpHook);
		double massHook = vHook->GetPropellantMass(hpHook);

		if (massTarget<CUT_OFF)
		{
			sprintf(msg, "No fuel left to transfer!");
			return;
		}
		if (fabs(maxMasshook-massHook) < CUT_OFF)
		{
			sprintf(msg, "Tank full");
			return;
		}
		if (hook == oapiGetVesselByIndex(iTarget))
		{
			if (iSelectedSource == iTargetSource)
			{
				sprintf(msg, "Cannot transfer fuel to the same source");
				return;
			}
		}
		double dFuelTrans = 0;
		if (massTarget-dTransferRate >= 0 && massHook+dTransferRate <= maxMasshook)
		{
			dFuelTrans = dTransferRate;
		}else
		{
			if (maxMasshook-massHook < massTarget)
			{
				dFuelTrans = maxMasshook-massHook;
			}else if (maxMasshook-massHook > massTarget)
			{
				dFuelTrans = massTarget;
			}else
				dFuelTrans = massTarget;
		}
		dFuelTrans*=oapiGetSimStep();
		vTarget->SetPropellantMass(hpTarget, massTarget-dFuelTrans);
		vHook->SetPropellantMass(hpHook, massHook+dFuelTrans);
		sprintf(msg, "Transfering %.2f%%", ((massHook+dFuelTrans)/maxMasshook)*100, 
			vTarget->GetName(), ((massTarget-dFuelTrans)/maxMasstarget)*100);
	}
	else if (mode == MAGIC)
	{
		VESSEL * v = oapiGetVesselInterface(hook);
		PROPELLANT_HANDLE hpr = v->GetPropellantHandleByIndex(iSelectedSource);
		if (!hpr)
		{
			sprintf(msg, "Unknown error!");
			return;
		}
		double mass = v->GetPropellantMass(hpr);
		double maxmass = v->GetPropellantMaxMass(hpr);
		if (fabs(maxmass-mass) < CUT_OFF){
			sprintf(msg, "Tank full");
			return;
		}
		double dFuelTrans = 0;
		if (mass+dTransferRate > maxmass)
			dFuelTrans = maxmass-mass;
		else
			dFuelTrans = dTransferRate;
		dFuelTrans*=oapiGetSimStep();
		v->SetPropellantMass(hpr, dFuelTrans+mass);
		sprintf(msg, "Transfering %.2f%%", ((mass+dFuelTrans)/maxmass)*100);
	}else if (mode == DUMPING)
	{
		VESSEL * v = oapiGetVesselInterface(hook);
		PROPELLANT_HANDLE hpr = v->GetPropellantHandleByIndex(iSelectedSource);
		if (!hpr)
		{
			sprintf(msg, "Unknown error!");
			return;
		}
		double mass = v->GetPropellantMass(hpr);
		double maxmass = v->GetPropellantMaxMass(hpr);
		if (mass <CUT_OFF)
		{
			sprintf(msg, "No more fuel left");
			return;
		}
		double dFuelTrans=0;
		if (mass-dTransferRate < 0)
			dFuelTrans = mass;
		else
			dFuelTrans = dTransferRate;
		dFuelTrans*=oapiGetSimStep();
		v->SetPropellantMass(hpr, mass-dFuelTrans);
		sprintf(msg, "Dumping %.2f%%", ((mass-dFuelTrans)/maxmass)*100);
	}
}