Project Shuttle-D Development version 1.2

I think,maybe the cockpit should look something like the Shuttle A cockpit,but more modern,I will try,and test her out in different atmosphereic situations as soon as I get some spare time.Thanks
 
Last edited:
Beta Testing Alert:
For some reason, my computer will only let me use the Shuttle-D a limited number of times: after that, attempting to use or create a Shuttle-D will cause Orbiter to crash:(
 
Beta Testing Alert:
For some reason, my computer will only let me use the Shuttle-D a limited number of times: after that, attempting to use or create a Shuttle-D will cause Orbiter to crash:(

lol, bug report eh? Get in line, Ive had a silly number of issues crop up in the last couple of days. Can you give a log for it, and does a restart of your computer seem to help? There might be an issue with memory leaks or something similar that I havent caught due to inexperience.

BTW, First day of university! :)
 
Congrats.

I'm getting the standard Windows program crash. "This program has a problem, and needs to close," etc.

Orbiter log doesn't show anything strange...
 
Congrats.

I'm getting the standard Windows program crash. "This program has a problem, and needs to close," etc.

Orbiter log doesn't show anything strange...

Nothing strange? Usually the log cuts off at said module in the load list doesnt it?

Thanks by the way. 15 mins to first class in Physics
 
That's funny...now it's working again in my backup installation...

okay, so is the CTD happening as a max # of ShuttleD's being added into a scenario, or is it the number of times loaded through a orbiter installation? Obvious, I know, but can you list off what other addons are in use? Boy, do I ever have a long way to go before this project is really ready :facepalm:
 
No, I never load more than one at a time. But after a few times of running Orbiter and pulling up a Shuttle-D I get the crash. It doesn't even go back to the Orbiter launch pad, just Windows with an error message.

Don't sweat it:) I think the project is almost ready:thumbup: The only thing you really need to do is work on the MFDs:)

I watch this problem more closely though, and see if I can find a pattern.

EDIT:
Other Addons:
See the IHP Abstract.
 
Rather strange question for anyone testing, do the thruster lights appear backwards to any of you? Im beginning to wonder if my computer does odd things with left/right up/down
 
Orbiter does odd things with left and right.

It uses a left hand z coordinate system as opposed to the more traditional right hand x

the result of copying coordinates from one format to the other is that you'll get a mirrior image.
 
Orbiter does odd things with left and right.

It uses a left hand z coordinate system as opposed to the more traditional right hand x

the result of copying coordinates from one format to the other is that you'll get a mirrior image.

Oh, okay, I was beginning to wonder if it was just my computer. I had to wrestle with this to make the thruster lights cooperate with the ShuttleD, but when I loaded up a DG on a fresh orbiter install, I noticed that the thruster lights are backwards. I cant say for sure, but I have the UMMU-DG mod installed, so maybe the author of that compiled it directionally mirrored & didnt notice.
 
Finally got back to work on this project after a fairly long delay due to real-life stuff and lack of personal interest. I fixed the data load and save calls just like Face & Orb suggested in my SDK help request, and it appears to have fixed the problem perfectly. The extra lines that were skipped on each load call had been causing odd behaviour in my animations (snapping back & forth at random, etc. which was eliminated by the function being used in the right way. I was also really excited to add an oxygen management variable which now kills the crew when the tank runs out (morbid, but I wanted some realism). My issue at this point is trying to create a function that returns the tanks current value in kilograms on the hud. What Im not sure how to do is to have a function "return" or "get" the value of that variable, in the way that the UMMU/UCGO libraries have calls to do just that.

The other somewhat major problem I seem to be encountering is that my UMMU action areas have dissapeared for reasons I cant identify. I have gone back & read through Danstephs documentation for UMMU, checked it against my code and have been unable to find what has gone missing (the action areas were working before), so I thought I would post the source here in case someone else spots what has gone wrong.

the cpp:

Code:
// SHD.cpp : Defines the exported functions for the DLL application.
//

#define STRICT
#define ORBITER_MODULE
#include "D9base.h"
#include "UCGOCargoSDK.h"
#include "orbitersdk.h"
#include <math.h>
#include <stdio.h>
#include "OrbiterSoundSDK35.h"
#include "VesselAPI.h"

#define MY500METERSOUND				1		// those are definition so all function will be more clear to read..
#define MYRADARSOUND				2		// because we will know wich sound is concerned by function instead
#define MYEXTERNAL_UFO_FADEDSOUND	3		// of having simple number.
#define GEARUP						 4
#define GEARDOWN					 5
#define PLBAYAOPEN					 6
#define PLBAYACLOSE					 7
#define PLBAYBOPEN					 8
#define PLBAYBCLOSE					 9

HINSTANCE g_hDLL;
VISHANDLE MainExternalMeshVisual = 0;

// ==============================================================
// Airfoil definition
// ==============================================================

void Shuttle_MomentCoeff (double aoa,double M,double Re,double *cl,double *cm,double *cd)
{
	int i;
	const int nabsc = 7;
	static const double AOA[nabsc] = {-180*RAD, -90*RAD,-30*RAD, 0*RAD, 60*RAD,90*RAD,180*RAD};
	static const double CL[nabsc]  = {       0,     -0.0005,   -0.001,     0,     0.0071,     0.0011,      0.00001};
	static const double CM[nabsc]  = {       0,      0,   0.0007,  0,-0.0010,     0,      0};

	for (i = 0; i < nabsc-1 && AOA[i+1] < aoa; i++);
	double f = (aoa-AOA[i]) / (AOA[i+1]-AOA[i]);
	*cl = CL[i] + (CL[i+1]-CL[i]) * f;  // aoa-dependent lift coefficient
	*cm = CM[i] + (CM[i+1]-CM[i]) * f;  // aoa-dependent moment coefficient
	double saoa = sin(aoa);
	double pd = 0.045 + 0.4*saoa*saoa;  // profile drag
	*cd = pd + oapiGetInducedDrag (*cl, 0.1,0.7) + oapiGetWaveDrag (M, 0.75, 1.0, 1.1, 0.04);
	// profile drag + (lift-)induced drag + transonic/supersonic wave (compressibility) drag
}

ShuttleD::ShuttleD (OBJHANDLE hObj, int fmodel)
	: VESSEL3 (hObj, fmodel)
{
	GEAR_status = GEAR_UP;
	GEAR_proc = 0.0;
	PLBAYA_status = PLBAYA_UP;
	PLBAYA_proc = 0.0;
	PLBAYB_status = PLBAYB_UP;
	PLBAYB_proc = 0.0;
	O2Tank = 1000;

	DefineAnimations();
}

//=========================================================
// Vessel Animations
//=========================================================
void ShuttleD::DefineAnimations()
{
	//ANIMATIONCOMPONENT_HANDLE parent;
	static UINT gearback[1] = {38};
	static MGROUP_ROTATE gear (
		0,
		gearback,
		1,
		_V(0,-2.4,-27.97),
		_V(1,0,0),
		(float)(-90*RAD)
		);
	static UINT gearfront[1] = {39};
	static MGROUP_ROTATE gearf (
		0,
		gearfront,
		1,
		_V(0,-2.4,24.73),
		_V(1,0,0),
		(float)(90*RAD)
		);
	anim_gear = CreateAnimation (0);
	AddAnimationComponent (anim_gear, 0, 1, &gear);
	AddAnimationComponent (anim_gear, 0, 1, &gearf);

	static UINT PLBAYA[1] = {33};
	static MGROUP_ROTATE PLBAYA1 (
		0,
		PLBAYA,
		1,
		_V(0.858,-1.821666,-5.07),
		_V(0,0,1),
		(float)(90*RAD)
		);
	anim_PLBAYA = CreateAnimation (0);
	AddAnimationComponent (anim_PLBAYA, 0, 1, &PLBAYA1);

	static UINT PLBAYB[1] = {29};
	static MGROUP_ROTATE PLBAYB1 (
		0,
		PLBAYB,
		1,
		_V(0,4.413,-28.79),
		_V(1,0,0),
		(float)(-90*RAD)
		);
	anim_PLBAYB = CreateAnimation (0);
	AddAnimationComponent (anim_PLBAYB, 0, 1, &PLBAYB1);
}

void ShuttleD::RevertGEAR (void)
{
	GEAR_status = ((GEAR_status == GEAR_UP || GEAR_status == GEAR_RAISING) ?
GEAR_LOWERING : GEAR_RAISING);
}

void ShuttleD::RevertPLBAYA (void)
{
	PLBAYA_status = ((PLBAYA_status == PLBAYA_UP || PLBAYA_status == PLBAYA_CLOSING) ?
PLBAYA_OPENING : PLBAYA_CLOSING);
}

void ShuttleD::RevertPLBAYB (void)
{
	PLBAYB_status = ((PLBAYB_status == PLBAYB_UP || PLBAYB_status == PLBAYB_CLOSING) ?
PLBAYB_OPENING : PLBAYB_CLOSING);
}

void ShuttleD::SetUMMUAirlockPos(void)
{
	int AirlockStatus=Crew.GetAirlockDoorState();
	Crew.SetActiveDockForTransfer(iActiveDockNumber);

	switch(iActiveDockNumber)
	{
	case 0:
		Crew.DefineAirLockShape(TRUE,-1,1,-3.04,2.84, 23.93,26.93);
		Crew.SetMembersPosRotOnEVA(_V(0,-0.937,25.935),_V(0,-225,0));
		break;
	case 1:

		Crew.DefineAirLockShape(AirlockStatus, -1,1,2,4,-23,-21.6);
		Crew.SetMembersPosRotOnEVA(_V(0,3.9,-22.568),_V(0,0,0));
		break;
	}
}

//=========================================================
// Vessel Capabilities
//=========================================================
void ShuttleD::clbkSetClassCaps (FILEHANDLE cfg)
{
	Crew.InitUmmu(GetHandle());	
	float UMmuVersion=Crew.GetUserUMmuVersion();
	//	double UMmuVersion=Crew.GetUserUMmuVersion();
	Crew.SetMaxSeatAvailableInShip(4);

	Crew.DeclareActionArea(0,_V(2,-3.05,12.63),2.9,TRUE,"Sound\\ShuttleD\\ActionCommand.wav","Payload Bay A Activated");
	Crew.DeclareActionArea(1,_V(0,3.120,-22.568),2.9,TRUE, "Sound\\ShuttleD\\ActionCommand.wav","Payload Bay B Activated");
	Crew.DeclareActionArea(2,_V(0,-0.937,26.2),4.5,TRUE,"Sound\\ShuttleD\\ActionCommand.wav","Airlock Activated");

	iActionAreaDemoStep=0;	// this is just to show a feature of action area, see below "DetectActionAreaActivated"

	SelectedUmmuMember =0;  // our current selected member


	// The HUD display method variables, see PDF doc
	cUmmuHudDisplay[0] =0;	// Initialisation of UMmu hud char variable
	dHudMessageDelay =0;	// Initialisation of UMmu delay variable
	strcpy(SendHudMessage(),"Welcome aboard ! E=EVA 1,2=select UMmu\n A=Open/Close airlock S=info M=add crew");

	// The Add mmu without scenery editor variable see PDF doc
	cAddUMmuToVessel[0]=0;

	//UCGO 2.0 Initialisation, cargo slot pos, rot declaration
	hUcgo.Init(GetHandle());
	// in contrary of the PDF code we declare 6 slots
	// because it's fun :)
	hUcgo.DeclareCargoSlot(0,_V(-0.65,-3.3,11.53),_V(0,0,270)); // slot 0
	hUcgo.DeclareCargoSlot(1,_V(-0.65,-3.3,10.23),_V(0,0,270)); // slot 1
	hUcgo.DeclareCargoSlot(2,_V(-0.65,-3.3,8.93),_V(0,0,270)); // slot 2
	hUcgo.DeclareCargoSlot(3,_V(-0.65,-3.3,7.63),_V(0,0,270)); // slot 3
	hUcgo.DeclareCargoSlot(4,_V(-0.65,-3.3,6.33),_V(0,0,270)); // slot 4
	hUcgo.DeclareCargoSlot(5,_V(-0.65,-3.3,5.03),_V(0,0,270)); // slot 5
	hUcgo.DeclareCargoSlot(6,_V(-0.65,-3.3,3.73),_V(0,0,270)); // slot 6
	hUcgo.DeclareCargoSlot(7,_V(-0.65,-3.3,2.43),_V(0,0,270)); // slot 7
	hUcgo.DeclareCargoSlot(8,_V(-0.65,-3.3,1.13),_V(0,0,270)); // slot 8
	hUcgo.DeclareCargoSlot(9,_V(-0.65,-3.3,-0.17),_V(0,0,270)); // slot 9
	hUcgo.DeclareCargoSlot(10,_V(-0.65,-3.3,-1.47),_V(0,0,270)); // slot 10
	hUcgo.DeclareCargoSlot(11,_V(-0.65,-3.3,-2.77),_V(0,0,270)); // slot 11
	hUcgo.DeclareCargoSlot(12,_V(-0.65,-3.3,-4.07),_V(0,0,270)); // slot 12
	hUcgo.DeclareCargoSlot(13,_V(-0.65,-3.3,-5.37),_V(0,0,270)); // slot 13
	hUcgo.DeclareCargoSlot(14,_V(-0.65,-3.3,-6.67),_V(0,0,270)); // slot 14
	hUcgo.DeclareCargoSlot(15,_V(-0.65,-3.3,-7.97),_V(0,0,270)); // slot 15
	hUcgo.DeclareCargoSlot(16,_V(-0.65,-3.3,-9.27),_V(0,0,270)); // slot 16
	hUcgo.DeclareCargoSlot(17,_V(-0.65,-3.3,-10.57),_V(0,0,270)); // slot 17

	hUcgo.SetSlotGroundReleasePos(0,_V(2,-3.6,11.53)); // slot 0
	hUcgo.SetSlotGroundReleasePos(1,_V(2,-3.6,10.23)); // slot 1
	hUcgo.SetSlotGroundReleasePos(2,_V(2,-3.6,8.93)); // slot 2
	hUcgo.SetSlotGroundReleasePos(3,_V(2,-3.6,7.63)); // slot 3
	hUcgo.SetSlotGroundReleasePos(4,_V(2,-3.6,6.33)); // slot 4
	hUcgo.SetSlotGroundReleasePos(5,_V(2,-3.6,5.03)); // slot 5
	hUcgo.SetSlotGroundReleasePos(6,_V(2,-3.6,3.73)); // slot 6
	hUcgo.SetSlotGroundReleasePos(7,_V(2,-3.6,2.43)); // slot 7
	hUcgo.SetSlotGroundReleasePos(8,_V(2,-3.6,1.13)); // slot 8
	hUcgo.SetSlotGroundReleasePos(9,_V(2,-3.6,-0.17)); // slot 9
	hUcgo.SetSlotGroundReleasePos(10,_V(2,-3.6,-1.47)); // slot 10
	hUcgo.SetSlotGroundReleasePos(11,_V(2,-3.6,-2.77)); // slot 11
	hUcgo.SetSlotGroundReleasePos(12,_V(2,-3.6,-4.07)); // slot 12
	hUcgo.SetSlotGroundReleasePos(13,_V(2,-3.6,-5.37)); // slot 13
	hUcgo.SetSlotGroundReleasePos(14,_V(2,-3.6,-6.67)); // slot 14
	hUcgo.SetSlotGroundReleasePos(15,_V(2,-3.6,-7.97)); // slot 15
	hUcgo.SetSlotGroundReleasePos(16,_V(2,-3.6,-9.27)); // slot 16
	hUcgo.SetSlotGroundReleasePos(17,_V(2,-3.6,-10.57)); // slot 17

	// UCGO 2.0 Parameters settings
	hUcgo.SetReleaseSpeedInSpace(0.001f);	   // release speed of cargo in space in m/s
	hUcgo.SetMaxCargoMassAcceptable(50000.0);   // max cargo mass in kg that your vessel can carry
	hUcgo.SetGrappleDistance(60);		       // grapple distance radius in meter from center of ship


	// UCGO Variables initialisation
	cCargoHudDisplay[0]=0;						// Cargo hud display char variable
	dCargHudMessageDelay=0;						// Cargo hud display delay
	iSelectedCargo=-1;							// for the selection of cargos (-1 mean "default" see header)
	// welcome message with keys for users
	strcpy(SendCargHudMessage(),"Cargo key: C/SHF+C = grapple/release, 9/SHF+9 = snc editor add cargo, 8=infos on cargos");

	THRUSTER_HANDLE th_main, th_hover, th_rcs[14], th_group[4];
	DOCKHANDLE Dock0, Dock1;

	iActiveDockNumber = 0;
	SetUMMUAirlockPos();


	// ************************ Airfoil  ****************************
	ClearAirfoilDefinitions();
	CreateAirfoil (LIFT_VERTICAL, _V(0,0,0), Shuttle_MomentCoeff,  8, 140, 0.1);


	// vessel caps definitions

	AddMesh ("Shuttle-D");
	SetMeshVisibilityMode (AddMesh (DVCInterior = oapiLoadMeshGlobal ("ShuttleDVC")), MESHVIS_VC);
	

	SetCameraOffset (_V(0,0.14,24.13));
	SetAlbedoRGB (_V(0.77,0.20,0.73));
	SetSize (EXP_SIZE);

	SetEmptyMass (EXP_EMPTYMASS + O2Tank);
	void UpdateEmptyMass(void);

	SetPMI (EXP_PMI);
	SetCrossSections (EXP_CS);
	SetSurfaceFrictionCoeff (0.55, 0.79);
	SetRotDrag (_V(0.9, 0.76, 0.2));

	EnableTransponder (true);
	InitNavRadios (4);

	// propellant resources
	PROPELLANT_HANDLE MainFuel = CreatePropellantResource (EXP_FUELMASS);
	PROPELLANT_HANDLE RCS1 = CreatePropellantResource (EXP_RCS1FUELMASS);
	PROPELLANT_HANDLE RCS2 = CreatePropellantResource (EXP_RCS2FUELMASS);
	PROPELLANT_HANDLE RCS3 = CreatePropellantResource (EXP_RCS3FUELMASS);
	PROPELLANT_HANDLE RCS4 = CreatePropellantResource (EXP_RCS4FUELMASS);
	PROPELLANT_HANDLE RCS5 = CreatePropellantResource (EXP_RCS5FUELMASS);
	PROPELLANT_HANDLE RCS6 = CreatePropellantResource (EXP_RCS6FUELMASS);
	PROPELLANT_HANDLE RCS7 = CreatePropellantResource (EXP_RCS7FUELMASS);
	PROPELLANT_HANDLE RCS8 = CreatePropellantResource (EXP_RCS8FUELMASS);
	PROPELLANT_HANDLE RCS9 = CreatePropellantResource (EXP_RCS9FUELMASS);
	PROPELLANT_HANDLE RCS10 = CreatePropellantResource (EXP_RCS10FUELMASS);
	PROPELLANT_HANDLE RCS11 = CreatePropellantResource (EXP_RCS11FUELMASS);
	PROPELLANT_HANDLE RCS12 = CreatePropellantResource (EXP_RCS12FUELMASS);
	PROPELLANT_HANDLE RCSRES = CreatePropellantResource (EXP_RCSRESFUELMASS);

	// main engine
	th_main = CreateThruster (_V(0,0,-36.52), _V(0,0,1), EXP_MAXMAINTH, MainFuel, VACSHD_ISP, NMLSHD_ISP, P_NML);
	CreateThrusterGroup (&th_main, 1, THGROUP_MAIN);
	AddExhaust (th_main, 18, 5, _V(0,0.13,-36.52), _V(0,0,-1));

	PARTICLESTREAMSPEC contrail_main = {
		0, 5.0, 16, 200, 0.15, 1.0, 5, 3.0, PARTICLESTREAMSPEC::DIFFUSE,
		PARTICLESTREAMSPEC::LVL_PSQRT, 0, 2,
		PARTICLESTREAMSPEC::ATM_PLOG, 1e-4, 1
	};
	PARTICLESTREAMSPEC exhaust_main = {
		0, 2.0, 20, 200, 0.05, 0.1, 8, 1.0, PARTICLESTREAMSPEC::EMISSIVE,
		PARTICLESTREAMSPEC::LVL_SQRT, 0, 1,
		PARTICLESTREAMSPEC::ATM_PLOG, 1e-5, 0.1
	};
	AddExhaustStream (th_main, _V(0,0.13,-36.52), &contrail_main);
	AddExhaustStream (th_main, _V(0,0.13,-36.52), &exhaust_main);

	// hover engine
	th_hover = CreateThruster (_V(0,-2.94,0), _V(0,1,0), EXP_MAXHOVERTH, MainFuel,  VACSHD_ISP, NMLSHD_ISP, P_NML);
	CreateThrusterGroup (&th_hover, 1, THGROUP_HOVER);
	AddExhaust (th_hover, 8, 1, _V(0.0,-3.04,-22.16), _V(0,-1,0));
	AddExhaust (th_hover, 11.05675834, 1, _V(0.0,-3.04,18.55), _V(0,-1,0));



	PARTICLESTREAMSPEC contrail_hover = {
		0, 5.0, 8, 200, 0.15, 1.0, 5, 3.0, PARTICLESTREAMSPEC::DIFFUSE,
		PARTICLESTREAMSPEC::LVL_PSQRT, 0, 2,
		PARTICLESTREAMSPEC::ATM_PLOG, 1e-4, 1
	};
	PARTICLESTREAMSPEC exhaust_hover = {
		0, 2.0, 10, 200, 0.05, 0.05, 8, 1.0, PARTICLESTREAMSPEC::EMISSIVE,
		PARTICLESTREAMSPEC::LVL_SQRT, 0, 1,
		PARTICLESTREAMSPEC::ATM_PLOG, 1e-5, 0.1
	};

	AddExhaustStream (th_hover, _V(0,-3.04, 18.55), &contrail_hover);
	AddExhaustStream (th_hover, _V(0,-3.04,-22.16), &contrail_hover);
	AddExhaustStream (th_hover, _V(0,-3.04, 18.55), &exhaust_hover);
	AddExhaustStream (th_hover, _V(0,-3.04,-22.16), &exhaust_hover);

	// RCS engines
	th_rcs[0] = CreateThruster (_V( 1.601,0, 24.707), _V(0,0,1), RCSTH0, RCS1,  VACSHD_ISP, NMLSHD_ISP, P_NML);//CM FRONT RIGHT SIDE FORWARD
	th_rcs[1] = CreateThruster (_V( -1.601,0, 24.707), _V(0,0,1), RCSTH1, RCS2,  VACSHD_ISP, NMLSHD_ISP, P_NML);//CM FRONT LEFT SIDE FORWARD

	th_rcs[2] = CreateThruster (_V(1.8505,0, 24.299), _V(-1, 0,0), RCSTH2, RCS1,  VACSHD_ISP, NMLSHD_ISP, P_NML);//CM FRONT RIGHT SIDE RIGHT
	th_rcs[3] = CreateThruster (_V(-1.8505,0, 24.299), _V(1,0,0), RCSTH3, RCS2,  VACSHD_ISP, NMLSHD_ISP, P_NML);//CM FRONT LEFT SIDE LEFT

	th_rcs[4] = CreateThruster (_V( 1.171,1.94,16.182), _V(0, 1,0), RCSTH4, RCS3,  VACSHD_ISP, NMLSHD_ISP, P_NML);//TRUSS FORWARD RIGHT SIDE UP
	th_rcs[5] = CreateThruster (_V( -1.171,1.94,16.182), _V(0,1,0), RCSTH5, RCS4,  VACSHD_ISP, NMLSHD_ISP, P_NML);//TRUSS FORWARD LEFT SIDE UP
	th_rcs[6] = CreateThruster (_V(1.171,-1.836,16.182), _V(0,-1,0), RCSTH6, RCS5,  VACSHD_ISP, NMLSHD_ISP, P_NML);//TRUSS FORWARD RIGHT SIDE DOWN
	th_rcs[7] = CreateThruster (_V(-1.171,-1.836,16.182), _V(0,-1,0), RCSTH7, RCS6,  VACSHD_ISP, NMLSHD_ISP, P_NML);//TRUSS FORWARD LEFT SIDE DOWN

	th_rcs[8] = CreateThruster (_V( 1.171,1.94, -16.125), _V(0,1,0), RCSTH8, RCS7,  VACSHD_ISP, NMLSHD_ISP, P_NML);//TRUSS AFT RIGHT SIDE UP
	th_rcs[9] = CreateThruster (_V( -1.171,1.94, -16.125), _V( 0,1,0), RCSTH9, RCS8,  VACSHD_ISP, NMLSHD_ISP, P_NML);//TRUSS AFT LEFT SIDE UP
	th_rcs[10] = CreateThruster (_V(1.171,-1.836,-16.125), _V(0,-1,0), RCSTH10, RCS9,  VACSHD_ISP, NMLSHD_ISP, P_NML);//TRUSS AFT RIGHT SIDE DOWN
	th_rcs[11] = CreateThruster (_V(-1.171,-1.836,-16.125), _V( 0,-1,0), RCSTH11, RCS10,  VACSHD_ISP, NMLSHD_ISP, P_NML);//TRUSS AFT LEFT SIDE DOWN

	th_rcs[12] = CreateThruster (_V( 1.89,0,-29.371), _V(0,0, -1), RCSTH12, RCS11,  VACSHD_ISP, NMLSHD_ISP, P_NML);//SM BACK RIGHT SIDE BACKWARDS
	th_rcs[13] = CreateThruster (_V( -1.89,0,-29.371), _V(0,0,-1), RCSTH13, RCS12,  VACSHD_ISP, NMLSHD_ISP, P_NML);//SM BACK LEFT SIDE BACKWARDS

	th_rcs[14] = CreateThruster (_V(2.22,0,-28.963), _V( -1,0,0), RCSTH14, RCS11,  VACSHD_ISP, NMLSHD_ISP, P_NML);//SM BACK RIGHT SIDE RIGHT
	th_rcs[15] = CreateThruster (_V(-2.22,0,-28.963), _V(1,0, 0), RCSTH15, RCS12,  VACSHD_ISP, NMLSHD_ISP, P_NML);//SM BACK LEFT SIDE LEFT

	AddExhaust (th_rcs[12], 0.6,  0.078, _V( 1.601,0,24.707), _V(0,0,1));
	AddExhaust (th_rcs[13], 0.6,  0.078, _V( -1.601,0,24.707), _V(0,0,1));

	AddExhaust (th_rcs[2], 0.79, 0.103, _V(1.8905,0, 24.299), _V(-1, 0,0));
	AddExhaust (th_rcs[3], 0.79, 0.103, _V(-1.8905,0, 24.299), _V(1,0,0));

	AddExhaust (th_rcs[6], 0.6,  0.078, _V( 1.171,1.94,16.182), _V(0, 1,0));
	AddExhaust (th_rcs[7], 0.6,  0.078, _V( -1.171,1.94,16.182), _V(0,1,0));
	AddExhaust (th_rcs[4], 0.79, 0.103, _V(1.171,-1.836,16.182), _V(0,-1,0));
	AddExhaust (th_rcs[5], 0.79, 0.103, _V(-1.171,-1.836,16.182), _V(0,-1,0));

	AddExhaust (th_rcs[10], 0.6,  0.078, _V( 1.171,1.94, -16.125), _V(0,1,0));
	AddExhaust (th_rcs[11], 0.6,  0.078, _V( -1.171,1.94, -16.125), _V( 0,1,0));
	AddExhaust (th_rcs[8], 0.79, 0.103, _V(1.171,-1.836,-16.125), _V(0,-1,0));
	AddExhaust (th_rcs[9], 0.79, 0.103, _V(-1.171,-1.836,-16.125), _V( 0,-1,0));

	AddExhaust (th_rcs[0], 0.6,  0.078, _V( 1.89,0,-29.371), _V(0,0, -1));
	AddExhaust (th_rcs[1], 0.6,  0.078, _V( -1.89,0,-29.371), _V(0,0,-1));

	AddExhaust (th_rcs[14], 0.79, 0.103, _V(2.22,0,-28.963), _V( -1,0,0));
	AddExhaust (th_rcs[15], 0.79, 0.103, _V(-2.22,0,-28.963), _V(1,0, 0));


	th_group[0] = th_rcs[4];
	th_group[1] = th_rcs[5];
	th_group[2] = th_rcs[10];
	th_group[3] = th_rcs[11];
	CreateThrusterGroup (th_group, 4, THGROUP_ATT_PITCHUP);

	th_group[0] = th_rcs[6];
	th_group[1] = th_rcs[7];
	th_group[2] = th_rcs[8];
	th_group[3] = th_rcs[9];
	CreateThrusterGroup (th_group, 4, THGROUP_ATT_PITCHDOWN);

	th_group[0] = th_rcs[4];
	th_group[1] = th_rcs[7];
	th_group[2] = th_rcs[8];
	th_group[3] = th_rcs[11];
	CreateThrusterGroup (th_group, 4, THGROUP_ATT_BANKLEFT);

	th_group[0] = th_rcs[5];
	th_group[1] = th_rcs[6];
	th_group[2] = th_rcs[9];
	th_group[3] = th_rcs[10];
	CreateThrusterGroup (th_group, 4, THGROUP_ATT_BANKRIGHT);

	th_group[0] = th_rcs[4];
	th_group[1] = th_rcs[5];
	th_group[2] = th_rcs[8];
	th_group[3] = th_rcs[9];
	CreateThrusterGroup (th_group, 4, THGROUP_ATT_UP);

	th_group[0] = th_rcs[6];
	th_group[1] = th_rcs[7];
	th_group[2] = th_rcs[10];
	th_group[3] = th_rcs[11];
	CreateThrusterGroup (th_group, 4, THGROUP_ATT_DOWN);

	th_group[0] = th_rcs[2];
	th_group[1] = th_rcs[15];
	CreateThrusterGroup (th_group, 2, THGROUP_ATT_YAWLEFT);

	th_group[0] = th_rcs[3];
	th_group[1] = th_rcs[14];
	CreateThrusterGroup (th_group, 2, THGROUP_ATT_YAWRIGHT);

	th_group[0] = th_rcs[2];
	th_group[1] = th_rcs[14];
	CreateThrusterGroup (th_group, 2, THGROUP_ATT_LEFT);

	th_group[0] = th_rcs[3];
	th_group[1] = th_rcs[15];
	CreateThrusterGroup (th_group, 2, THGROUP_ATT_RIGHT);

	th_group[0] = th_rcs[0];
	th_group[1] = th_rcs[1];
	CreateThrusterGroup (th_group, 2, THGROUP_ATT_FORWARD);

	th_group[0] = th_rcs[12];
	th_group[1] = th_rcs[13];
	CreateThrusterGroup (th_group, 2, THGROUP_ATT_BACK);

	Dock0 = CreateDock(_V(0,-0.737,25.385),_V(0,0,1),_V(0,1,0));
	Dock1 = CreateDock(_V(0,2.630,-22.568),_V(0,1,0),_V(0,0,1));

	// ************************ Attachment points ****************************
//	char attach_id[8]={"SH"};
//
//	payload_attachment[0]  = CreateAttachment (false,_V(1.76f,0.0f,-7.000f),_V(0.0f,0.0f,-1.0f),_V(0.0f,1.0f,0.0f),attach_id);
//	payload_attachment[1]  = CreateAttachment (false,_V(-1.76f,0.0f,-7.000f),_V(0.0f,0.0f,-1.0f),_V(0.0f,1.0f,0.0f),attach_id);
}

void ShuttleD::clbkMFDMode (int mfd, int mode)
{
	//	When an MFD changes mode (either in Panel or VC modes), this call back is
	//	invoked. Here, it is a general TriggerRedrawArea function used, which can
	//	be used to redraw MFD's for VC or Panel views. You can just as effectively
	//	use oapiTriggerVCRedrawArea for this ship, however, as there is no 2D panel.
	switch (mfd) {
	case MFD_LEFT:
		oapiTriggerRedrawArea (1, 2, AID_MFD1_LBUTTONS);
		oapiTriggerRedrawArea (1, 3, AID_MFD1_RBUTTONS);
		break;
		case MFD_RIGHT:
		oapiTriggerRedrawArea (1, 2, AID_MFD2_LBUTTONS);
		oapiTriggerRedrawArea (1, 3, AID_MFD2_RBUTTONS);
	}
}


//-------------------------------------------------------------------------

bool ShuttleD::clbkLoadVC (int id)
{

	//	 VCHUDSPEC hud;
	VCMFDSPEC mfd;

	oapiVCRegisterMFD(0,&mfd);
//	mfd.ngroup=19;
//	mfd.nmesh=1;
	oapiVCRegisterMFD(1,&mfd);
	static VCHUDSPEC hud_pilot  = {1, 4,{0.55,1.94,24.4162},1.12999};
	static VCHUDSPEC hud_copilot  = {1, 4,{-0.55,1.94,24.4162},1.12999};
	static VCHUDSPEC hud_fdeckfloor  = {1, 4,{0.55,1.94,23.86},1.12999};
	//	oapiVCRegisterHUD (&hud_pilot); // HUD parameters

	mfds_right.nmesh = 1;	//	The mesh number (the first one loaded, or 0, in this case).
	mfds_right.ngroup  = 19;	//	The mesh group that is the MFD screen in the above identified mesh.

	mfds_left.nmesh = 1;	//	The mesh number (the first one loaded, or 0, in this case).
	mfds_left.ngroup  = 18;	//	The mesh group that is the MFD screen in the above identified mesh.

	SetCameraDefaultDirection(_V(0, 0, 1)); // View angles down so you can see the
	//	MFD in VC view by default (it is the sine and cosine of 11º in Y and Z, respectively).

	SURFHANDLE MFDbuttons1 = oapiGetTextureHandle (DVCInterior,12); 
	//	Get the MFDButtons.dds D texture for redrawing purposes.

	int i;
	switch (id) {
	case 0:	//	The first VC cockpit view (id 0). Carefull with mixing up id.
		//	There are more references to id in the code, but what they identify is 
		//	according to the specific callback. For example, in clbkVCMouseEvent,
		//	id is the identity of the MFD buttons, not the cockpit view. 
		SetCameraOffset (_V(0.50,1.94,22.86));
		SetCameraRotationRange (RAD*120, RAD*120, RAD*180, RAD*100); 
		SetCameraShiftRange (_V(0,0,0.1), _V(-0.2,0,0), _V(0.05,0,0));
		oapiVCSetNeighbours (1, -1, -1, 2);

		oapiVCRegisterMFD (MFD_LEFT, &mfds_left);
		oapiVCRegisterMFD (MFD_RIGHT, &mfds_right);
		oapiVCRegisterHUD (&hud_pilot); // HUD parameters
		//		oapiVCRegisterSYSTAT (&systat_pilot); // Sytem Display parameters


			// Register main panel SYSTAT display


		oapiVCRegisterArea (AID_MFD1_LBUTTONS, _R( 0, 0, 32, 220), PANEL_REDRAW_USER, PANEL_MOUSE_IGNORE, PANEL_MAP_BACKGROUND, MFDbuttons1);		

		oapiVCRegisterArea (AID_MFD1_RBUTTONS, _R( 32, 0, 64, 220), PANEL_REDRAW_USER, PANEL_MOUSE_IGNORE, PANEL_MAP_BACKGROUND, MFDbuttons1);

		oapiVCRegisterArea (AID_MFD2_LBUTTONS, _R( 0, 0, 32, 220), PANEL_REDRAW_USER, PANEL_MOUSE_IGNORE, PANEL_MAP_BACKGROUND, MFDbuttons1);		

		oapiVCRegisterArea (AID_MFD2_RBUTTONS, _R( 32, 0, 64, 220), PANEL_REDRAW_USER, PANEL_MOUSE_IGNORE, PANEL_MAP_BACKGROUND, MFDbuttons1);

		//	These area registrations are for redrawing purposes only, and are used by 
		//	the clbkVCRedrawEvent. The _R(X1, Y1, X2, Y2) coordinates pertain to the
		//	texture coordinates on the MFDButtons.dds texture (in PIXELS), which is the 
		//	dynamic texture that SURFHANDLE MFDbuttons1 gets from the mesh file.
		//	Note that as the bottom buttons are not ever redrawn, no registration of
		//	them for texture coords is needed.
		//	Have a look at the clbkMFDMode and clbkVCRedrawEvent. 
		//	The only areas triggered for redrawing and then redrawn are
		//	those two registered above (AID_MFD1_LBUTTONS and AID_MFD1_RBUTTONS.
		//	And have a look at the definitions in the AstroMatiz.h file. You will see their
		//	id's that are passed to the preprocessor during compile.

		//	For reference, here are the rectangular area 3D coordinates of the 
		//	left, right and bottom MFD buttons, in MESH coordinates. You WILL need to
		//	get this info, if you want to make your own VC work properly. 
		//	(Use Meshwizard, or go into the mesh file itself and find them).
		//				The mesh area of the 6 left buttons of MFD_LEFT
		//					_V(-0.32f, 0.067f, 0.654f),
		//					_V(-0.30f, 0.067f, 0.654f),
		//					_V(-0.32f, -0.080f, 0.643f),
		//					_V(-0.30f, -0.080f, 0.643f));
		//				The mesh area of the 6 right buttons of MFD_LEFT
		//					_V(-0.117f, 0.067f, 0.654f),
		//					_V(-0.097f, 0.067f, 0.654f),
		//					_V(-0.117f, -0.080f, 0.643f),
		//					_V(-0.097f, -0.080f, 0.643f));
		//				The mesh area of the three bottom buttons of MFD_LEFT
		//					_V(-0.267f, -0.095f, 0.642f),
		//					_V(-0.158f, -0.095f, 0.642f),
		//					_V(-0.267f, -0.114f, 0.641f),
		//					_V(-0.158f, -0.114f, 0.641f));

		for (i = 0; i < 6; i++) {
			oapiVCRegisterArea (MFD1_LBUTTON1+i, PANEL_REDRAW_NEVER, PANEL_MOUSE_LBDOWN);
			oapiVCSetAreaClickmode_Spherical(MFD1_LBUTTON1+i, _V(-0.07125, 2.4464 - (i *0.0352), 23.77135 + (i *0.0161)), 0.0300);

			oapiVCRegisterArea (MFD1_RBUTTON1+i, PANEL_REDRAW_NEVER, PANEL_MOUSE_LBDOWN);
			oapiVCSetAreaClickmode_Spherical(MFD1_RBUTTON1+i, _V(0.25895, 2.4464 - (i *0.0352), 23.77135 + (i *0.0161)), 0.0300);
		}
		//	Define the area for mouse events on each button of left and right columns.

		for (i = 0; i < 3; i++) {
			oapiVCRegisterArea (MFD1_BBUTTON1+i, PANEL_REDRAW_NEVER, PANEL_MOUSE_LBDOWN);
			oapiVCSetAreaClickmode_Spherical(MFD1_BBUTTON1+i, _V(0.05295 + (i * 0.0387), 2.2081, 23.87965), 0.0300);
		}

				for (i = 0; i < 6; i++) {
			oapiVCRegisterArea (MFD2_LBUTTON1+i, PANEL_REDRAW_NEVER, PANEL_MOUSE_LBDOWN);
			oapiVCSetAreaClickmode_Spherical(MFD2_LBUTTON1+i, _V(0.27325, 2.4464 - (i *0.0352), 23.77135 + (i *0.0161)), 0.0300);

			oapiVCRegisterArea (MFD2_RBUTTON1+i, PANEL_REDRAW_NEVER, PANEL_MOUSE_LBDOWN);
			oapiVCSetAreaClickmode_Spherical(MFD2_RBUTTON1+i, _V(0.60355, 2.4464 - (i *0.0352), 23.77135 + (i *0.0161)), 0.0300);
		}
		//	Define the area for mouse events on each button of left and right columns.

		for (i = 0; i < 3; i++) {
			oapiVCRegisterArea (MFD2_BBUTTON1+i, PANEL_REDRAW_NEVER, PANEL_MOUSE_LBDOWN);
			oapiVCSetAreaClickmode_Spherical(MFD2_BBUTTON1+i, _V(0.3975 + (i * 0.0387), 2.2081, 23.87965), 0.0300);
		}
		//	Define the area for mouse events on the bottom buttons. Coordinates are in
		//	mesh 3D coords (see why you needed to get this info?)

		campos = CAM_VCPILOT;
		break;



	case 1: // front left passenger
		SetCameraOffset (_V(-0.55,1.94,22.86));
		SetCameraRotationRange (RAD*120, RAD*120, RAD*100, RAD*180); 
		SetCameraShiftRange (_V(0,0,0.1), _V(-0.05,0,0), _V(0.2,0,0));
//		SetCameraMovement (_V(0.2,-0.05,0.3), -10*RAD, 10*RAD, _V(-0.3,0,0), 80*RAD, 0, _V(0.4,0,0), -90*RAD, 0);
		oapiVCSetNeighbours (-1, 0, -1, 2);
		oapiVCRegisterHUD (&hud_copilot); // HUD parameters

		oapiVCRegisterMFD (MFD_LEFT, &mfds_left);
		oapiVCRegisterMFD (MFD_RIGHT, &mfds_right);

				for (i = 0; i < 6; i++) {
			oapiVCRegisterArea (MFD1_LBUTTON1+i, PANEL_REDRAW_NEVER, PANEL_MOUSE_LBDOWN);
			oapiVCSetAreaClickmode_Spherical(MFD1_LBUTTON1+i, _V(-0.07125, 2.4464 - (i *0.0352), 23.77135 + (i *0.0161)), 0.0300);

			oapiVCRegisterArea (MFD1_RBUTTON1+i, PANEL_REDRAW_NEVER, PANEL_MOUSE_LBDOWN);
			oapiVCSetAreaClickmode_Spherical(MFD1_RBUTTON1+i, _V(0.25895, 2.4464 - (i *0.0352), 23.77135 + (i *0.0161)), 0.0300);
		}
		//	Define the area for mouse events on each button of left and right columns.

		for (i = 0; i < 3; i++) {
			oapiVCRegisterArea (MFD1_BBUTTON1+i, PANEL_REDRAW_NEVER, PANEL_MOUSE_LBDOWN);
			oapiVCSetAreaClickmode_Spherical(MFD1_BBUTTON1+i, _V(0.05295 + (i * 0.0387), 2.2081, 23.87965), 0.0300);
		}

				for (i = 0; i < 6; i++) {
			oapiVCRegisterArea (MFD2_LBUTTON1+i, PANEL_REDRAW_NEVER, PANEL_MOUSE_LBDOWN);
			oapiVCSetAreaClickmode_Spherical(MFD2_LBUTTON1+i, _V(0.29325, 2.4464 - (i *0.0352), 23.77135 + (i *0.0161)), 0.0300);

			oapiVCRegisterArea (MFD2_RBUTTON1+i, PANEL_REDRAW_NEVER, PANEL_MOUSE_LBDOWN);
			oapiVCSetAreaClickmode_Spherical(MFD2_RBUTTON1+i, _V(0.62355, 2.4464 - (i *0.0352), 23.77135 + (i *0.0161)), 0.0300);
		}
		//	Define the area for mouse events on each button of left and right columns.

		for (i = 0; i < 3; i++) {
			oapiVCRegisterArea (MFD2_BBUTTON1+i, PANEL_REDRAW_NEVER, PANEL_MOUSE_LBDOWN);
			oapiVCSetAreaClickmode_Spherical(MFD2_BBUTTON1+i, _V(0.4175 + (i * 0.0387), 2.2081, 23.87965), 0.0300);
		}
		//	Define the area for mouse events on the bottom buttons. Coordinates are in
		//	mesh 3D coords (see why you needed to get this info?)

		campos = CAM_VCPSNGR1;
		break;

	case 2: // front right passenger
		SetCameraOffset (_V(0,-0.3,22.86));
		SetCameraRotationRange (RAD*180, RAD*70, RAD*100, RAD*100); 
		SetCameraShiftRange (_V(0,0,0.1), _V(-0.05,0,0), _V(0.05,0,0));
		oapiVCSetNeighbours (1, 0, -1, 3);
		oapiVCRegisterHUD (&hud_fdeckfloor); // HUD parameters
		oapiVCRegisterMFD (MFD_LEFT, &mfds_left);
		oapiVCRegisterMFD (MFD_RIGHT, &mfds_right);
		//		oapiVCRegisterSYSTAT (&systat_fdeckfloor); // Sytem Display parameters
		campos = CAM_VCPSNGR2;
		break;

	case 3: // rear left passenger
		SetCameraOffset (_V(0.5, -0.1, -0.67));
		SetCameraRotationRange (RAD*180, RAD*70, RAD*270, RAD*100); 
		SetCameraShiftRange (_V(0,0,10.0), _V(-0.05,0,0), _V(0.05,0,0));
		oapiVCSetNeighbours (-1, -1, 2, 4);
		campos = CAM_VCPSNGR3;
		break;

	case 4: // rear right passenger
		SetCameraOffset (_V(0, 0.1, -23.07));
		SetCameraRotationRange (RAD*180, RAD*180, RAD*180, RAD*180); 
		SetCameraShiftRange (_V(0,0,1.0), _V(-0.05,0,0), _V(0.05,0,0));
		oapiVCSetNeighbours (-1, -1, 3, -1);
		campos = CAM_VCPSNGR4;
		return true;

	};

	return true;
}
bool ShuttleD::clbkDrawHUD(int mode, const HUDPAINTSPEC *hps, oapi::Sketchpad *skp)
{
	// draw the default HUD
	VESSEL3::clbkDrawHUD (mode, hps, skp);

	// UMmu display messages
	if(dHudMessageDelay>0)
	{
		skp->Text(5,hps->H/60*25,cUmmuHudDisplay,strlen(cUmmuHudDisplay));
		dHudMessageDelay-=oapiGetSimStep();
		if(dHudMessageDelay<0)
			dHudMessageDelay=0;
	}
	// UCGO display messages
	if(dCargHudMessageDelay>0)
	{
		skp->Text(5,hps->H/60*15,cCargoHudDisplay,strlen(cCargoHudDisplay));
		dCargHudMessageDelay-=oapiGetSimStep();
		if(dCargHudMessageDelay<0)
			dCargHudMessageDelay=0;
	}
	return true; 
}
char *ShuttleD::SendHudMessage() //<---- Change the class name here
{
	dHudMessageDelay=15;
	return cUmmuHudDisplay;
}
//-------------------------------------------------------------------------

bool ShuttleD::clbkVCMouseEvent (int id, int event, VECTOR3 &p)
{
	if ((id) >= MFD1_LBUTTON1 && (id) < MFD1_LBUTTON1 + 12)
	{
		oapiProcessMFDButton (MFD_LEFT, id - MFD1_LBUTTON1, event);
		return true;
	}
	//	Processes the events for mouse clicks on VC view MFD buttons, left and
	//	right columns, by matching the id of the event to the #defined identifier of
	//	the button (see AstroMatiz.h file).

	if ((id) == MFD1_BBUTTON1)
	{
		oapiToggleMFD_on (MFD_LEFT);
		return true;
	}
	//	The ON / OFF button (left MFD button on the bottom).

	if ((id) == MFD1_BBUTTON2)
	{
		oapiSendMFDKey (MFD_LEFT, OAPI_KEY_F1);
		return true;
	}
	//	The MODE button (center MFD button on the bottom).

	if ((id) == MFD1_BBUTTON3)
	{
		oapiSendMFDKey (MFD_LEFT, OAPI_KEY_GRAVE);
		return true;
	}
	//	The MENU button (right MFD button on the bottom).

		if ((id) >= MFD2_LBUTTON1 && (id) < MFD2_LBUTTON1 + 12)
	{
		oapiProcessMFDButton (MFD_RIGHT, id - MFD2_LBUTTON1, event);
		return true;
	}
	//	Processes the events for mouse clicks on VC view MFD buttons, left and
	//	right columns, by matching the id of the event to the #defined identifier of
	//	the button (see AstroMatiz.h file).

	if ((id) == MFD2_BBUTTON1)
	{
		oapiToggleMFD_on (MFD_RIGHT);
		return true;
	}
	//	The ON / OFF button (left MFD button on the bottom).

	if ((id) == MFD2_BBUTTON2)
	{
		oapiSendMFDKey (MFD_RIGHT, OAPI_KEY_F1);
		return true;
	}
	//	The MODE button (center MFD button on the bottom).

	if ((id) == MFD2_BBUTTON3)
	{
		oapiSendMFDKey (MFD_RIGHT, OAPI_KEY_GRAVE);
		return true;
	}
	//	The MENU button (right MFD button on the bottom).

	return false;
}
//-------------------------------------------------------------------------


bool ShuttleD::clbkVCRedrawEvent (int id, int event, SURFHANDLE surf)
{
	int bt, side;
	switch (id) {
		const char *label;
	case AID_MFD1_LBUTTONS:
	case AID_MFD1_RBUTTONS:
		side = (id == AID_MFD1_LBUTTONS ? 0: 1);
		HDC hDC = oapiGetDC (surf);
		SelectObject (hDC, hFont);
		SetTextColor (hDC, RGB(250, 250, 100));
		SetTextAlign (hDC, TA_CENTER);
		SetBkMode (hDC, TRANSPARENT);
		for (bt = 0; bt < 6; bt++) {
			if (label = oapiMFDButtonLabel (MFD_LEFT, bt+side*6))
				TextOut (hDC, 16, 8+36*bt, label, strlen(label));
			else break;
		}


		oapiReleaseDC (surf, hDC);
		return true;
	}
	return false;

	//	This redraw business is the most complicated thing about making VC's. This is 
	//	where the registered areas AID_MFD1_LBUTTONS and AID_MFD1_RBUTTONS are used.
	//	This part has absolutely nothing to do with triggering mouse events. It is
	//	ONLY blitting your MFDButtons texture on the buttons again, but with text on it.
	//	Important points with this issue are;
	//	1.	Get your mesh UV coordinates right for the mesh. DON'T get is backwards.
	//	2.	Make sure your texture is dynamic (just D suffix it in the mesh file).
	//	3.	Get the texture in the program (in clbkLoadVC) as a SURFHANDLE.

};

//=========================================================
// Vessel Load and Save Parameters
//=========================================================
void ShuttleD::clbkLoadStateEx (FILEHANDLE scn, void *status)
{
	char *line;
	while (oapiReadScenario_nextline (scn, line)) 
	{

		if (!_strnicmp (line, "GEAR", 4)) {
			sscanf (line+4, "%d%lf", &GEAR_status, &GEAR_proc);
		}

		if (!_strnicmp (line, "PLBAYA", 6)) {
			sscanf (line+6, "%d%lf", &PLBAYA_status, &PLBAYA_proc);
		}

		if (!_strnicmp (line, "PLBAYB", 6)) {
			sscanf (line+6, "%d%lf", &PLBAYB_status, &PLBAYB_proc);
		}

		if (!_strnicmp (line, "O2Tank", 6)) {
			sscanf (line+6, "%lf", &O2Tank);
		}

		if(Crew.LoadAllMembersFromOrbiterScenario(line)==TRUE)
			continue;

		// Load UCGO 2.0 cargo from scenario
		if(hUcgo.LoadCargoFromScenario(line)==TRUE) // UCGO load cargo 
			continue;

		ParseScenarioLineEx (line, status);
	}
	SetAnimation (anim_gear, GEAR_proc);
	SetAnimation (anim_PLBAYA, PLBAYA_proc);
	SetAnimation (anim_PLBAYB, PLBAYB_proc);

}


void ShuttleD::clbkSaveState (FILEHANDLE scn)
{
	char cbuf[256];

	VESSEL3::clbkSaveState (scn);
	sprintf (cbuf, "%d %0.4f", GEAR_status, GEAR_proc);
	oapiWriteScenario_string (scn, "GEAR", cbuf);

	sprintf (cbuf, "%d %0.4f", PLBAYA_status, PLBAYA_proc);
	oapiWriteScenario_string (scn, "PLBAYA", cbuf);

	sprintf (cbuf, "%d %0.4f", PLBAYB_status, PLBAYB_proc);
	oapiWriteScenario_string (scn, "PLBAYB", cbuf);

	sprintf (cbuf, "%0.4f", O2Tank);
	oapiWriteScenario_string (scn, "O2Tank", cbuf);

	Crew.SaveAllMembersInOrbiterScenarios(scn);

	// Save UCGO 2.0 cargo in scenario
	hUcgo.SaveCargoToScenario(scn);	
}

// --------------------------------------------------------------
// clbkVisualCreated
// --------------------------------------------------------------
void ShuttleD::clbkVisualCreated (VISHANDLE vis, int refcount)
{
	hUcgo.SetUcgoVisual(vis);	// must be called in clbkVisualCreated.
}
////////////////////////////////////////////////////////
// SendCargHudMessage
////////////////////////////////////////////////////////
char *ShuttleD::SendCargHudMessage(void)
{
	dCargHudMessageDelay=15; // 15 seconds display delay for msg
	return cCargoHudDisplay;
}
//=========================================================
// Animation Template
//=========================================================
void ShuttleD::clbkPostStep(double simt, double simdt, double mjd)
{
//	double OxygenLevel = GetPropellantMass(O2Tank);
//	double CrewNumber = Crew.GetCrewTotalNumber();
//	double OxygenConsumption = 1.2*CrewNumber;

	int ReturnCode=Crew.ProcessUniversalMMu();
	switch(ReturnCode)
	{
	case UMMU_TRANSFERED_TO_OUR_SHIP: 
		sprintf(SendHudMessage(),"%s \"%s\" aged %i was transfered to our ship",
			Crew.GetCrewMiscIdByName(Crew.GetLastEnteredCrewName()),Crew.GetLastEnteredCrewName()
			,Crew.GetCrewAgeByName(Crew.GetLastEnteredCrewName()));
		break;
	case UMMU_RETURNED_TO_OUR_SHIP:
		sprintf(SendHudMessage(),"%s \"%s\" aged %i entered into our ship",
			Crew.GetCrewMiscIdByName(Crew.GetLastEnteredCrewName()),
			Crew.GetLastEnteredCrewName(),Crew.GetCrewAgeByName(Crew.GetLastEnteredCrewName()));
		break;
	}

		int ActionAreaReturnCode=Crew.DetectActionAreaActivated();
	if(ActionAreaReturnCode>-1)
	{
		// this is just an example, we have four area declared
		// action area ID 0 triggered 
		if(ActionAreaReturnCode==0)
		{
		RevertPLBAYA();
		}
		// action area ID 1 triggered
		else if(ActionAreaReturnCode==1)
		{
		RevertPLBAYB();
		}
		// action area ID 2 triggered
		else if(ActionAreaReturnCode==2)
		{
		// switch state
		Crew.SetAirlockDoorState(!Crew.GetAirlockDoorState());
		// display state
		if(Crew.GetAirlockDoorState()==TRUE)
			strcpy(SendHudMessage(),"Airlock is now open");	
		else
			strcpy(SendHudMessage(),"Airlock is now closed");	
		}
	}

	if (GEAR_status >= GEAR_RAISING) { 
		double da = simdt * GEAR_OPERATING_SPEED;
		if (GEAR_status == GEAR_RAISING) {
			if (GEAR_proc > 0.0) GEAR_proc = max (0.0, GEAR_proc-da);
			else                GEAR_status = GEAR_UP;
		} else {
			if (GEAR_proc < 1.0) GEAR_proc = min (1.0, GEAR_proc+da);
			else                GEAR_status = GEAR_DOWN;
		}
		SetAnimation (anim_gear, GEAR_proc);

	}
	SetTouchdownPoints (_V(0,-4.89+GEAR_proc*0.99,1), _V(-1,-4.89+GEAR_proc*0.99,-1), _V(1,-4.89+GEAR_proc*0.99,-1));
	//sprintf(oapiDebugString(),"anim %2.2f", GEAR_proc );

	if (PLBAYA_status >= PLBAYA_CLOSING) {
		double da = simdt * PLBAYA_OPERATING_SPEED;
		if (PLBAYA_status == PLBAYA_CLOSING) {
			if (PLBAYA_proc > 0.0) PLBAYA_proc = max (0.0, PLBAYA_proc-da);
			else                PLBAYA_status = PLBAYA_UP;
		} else {
			if (PLBAYA_proc < 1.0) PLBAYA_proc = min (1.0, PLBAYA_proc+da);
			else                PLBAYA_status = PLBAYA_DOWN;
		}
		SetAnimation (anim_PLBAYA, PLBAYA_proc);



	}

	if (PLBAYB_status >= PLBAYB_CLOSING) {
		double da = simdt * PLBAYB_OPERATING_SPEED;
		if (PLBAYB_status == PLBAYB_CLOSING) {
			if (PLBAYB_proc > 0.0) PLBAYB_proc = max (0.0, PLBAYB_proc-da);
			else                PLBAYB_status = PLBAYB_UP;
		} else {
			if (PLBAYB_proc < 1.0) PLBAYB_proc = min (1.0, PLBAYB_proc+da);
			else                PLBAYB_status = PLBAYB_DOWN;
		}
		SetAnimation (anim_PLBAYB, PLBAYB_proc);



	}

	if (GEAR_status == GEAR_RAISING) {
		{if(GEAR_proc > 0.99)
			PlayVesselWave3(SHD,GEARDOWN);
		}
	}

	if (GEAR_status == GEAR_LOWERING) {
		{if(GEAR_proc < 0.01)
			PlayVesselWave3(SHD,GEARUP);
		}
	}
	if (PLBAYA_status == PLBAYA_CLOSING) {
		{if(PLBAYA_proc > 0.99)
			PlayVesselWave3(SHD,PLBAYACLOSE);
		}
	}

	if (PLBAYA_status == PLBAYA_OPENING) {
		{if(PLBAYA_proc < 0.01)
			PlayVesselWave3(SHD,PLBAYAOPEN);
		}
	}
	if (PLBAYB_status == PLBAYB_CLOSING) {
		{if(PLBAYB_proc > 0.9)
			PlayVesselWave3(SHD,PLBAYBCLOSE);
		}
	}

	if (PLBAYB_status == PLBAYB_OPENING) {
		{if(PLBAYB_proc < 0.1)
			PlayVesselWave3(SHD,PLBAYBOPEN);
		}
	}

	if(GroundContact()==TRUE)
	{
		// we check vertical speed
		int I;
		VECTOR3 vHorizonAirspeedVector={0};
		GetHorizonAirspeedVector (vHorizonAirspeedVector);
		double VertSpeed		=vHorizonAirspeedVector.y;
		if(VertSpeed<-3)
		{
			// we touched ground with more than -3 m/s, sorry dude, time to kill you all :(
			for(I=0;I<Crew.GetCrewTotalNumber();I++)
			{
				Crew.SetCrewMemberPulseBySlotNumber(I,0);	// set cardiac pulse to zero
			}
			strcpy(SendHudMessage(),"Oooh no ! Crash - All crew aboard killed");
		}
	}


	if (PLBAYA_status == PLBAYA_UP) {
		hUcgo.SetSlotDoorState(FALSE);
	}

	if (PLBAYA_status == PLBAYA_DOWN) {
		hUcgo.SetSlotDoorState(TRUE);
	}

	if (PLBAYB_status == PLBAYB_OPENING) {
		{if(PLBAYB_proc < 0.1)
			PlayVesselWave3(SHD,PLBAYBOPEN);
		}
	}

	double CrewNumber = Crew.GetCrewTotalNumber();
	double OxygenConsumption = 1.2*1.157407E-5*CrewNumber;
	double OxygenLevel = O2Tank;

{
	if (O2Tank>0)
	{
	O2Tank = (O2Tank - OxygenConsumption*simdt);
	}
	else 
	{
	O2Tank=0;
	}
}
	int I;
	if(O2Tank == 0)
{
			// You ran out of oxygen, sorry dude, time to kill you all :(
			for(I=0;I<Crew.GetCrewTotalNumber();I++)
			{
				Crew.SetCrewMemberPulseBySlotNumber(I,0);	// set cardiac pulse to zero
		}
		strcpy(SendHudMessage(),"Oooh no ! Oxygen Depleted - All crew dead");
}


	// Orientation mode switch

	{
	// RCS Stack Optimization...
	double RCSMode = GetAttitudeMode (); // Checks current RCS mode 1 = ROT, 2 = LIN
	if (RCSMode==2)
		{ 

		}

	if (RCSMode==1)
		{ 


		}
	}


		//Cancel Linear Torque.
//		IncThrusterLevel_SingleStep (th_rcs[2],456.6447615); 	
//		IncThrusterLevel_SingleStep (th_rcs[3],456.6447615);

//		SetThrusterLevel (th_rcs[14],1);
//		SetThrusterLevel (th_rcs[15],1);

//		IncThrusterLevel (th_rcs[14],5);
//		IncThrusterLevel (th_rcs[15],5);
//		IncThrusterLevel_SingleStep (th_rcs[12], VertThrust*Ratio*0.965925826289); 
//		IncThrusterLevel_SingleStep (th_rcs[13],-VertThrust*Ratio*0.965925826289); 



		//	if (GetAttitudeMode = RCS_LIN)
		//	{

		// RCS Stack Optimization...
//		double RCSMode = GetAttitudeMode (); // Checks current RCS mode 1 = ROT, 2 = LIN
//		if (RCSMode==2)
//		{ 
//			(RCSTH0 = EXP_LINRCSTH0);
//			(RCSTH1 = EXP_LINRCSTH1);
//			(RCSTH2 = EXP_LINRCSTH2);
//			(RCSTH3 = EXP_LINRCSTH3);
//			(RCSTH4 = EXP_LINRCSTH4);
//			(RCSTH5 = EXP_LINRCSTH5);
//			(RCSTH6 = EXP_LINRCSTH6);
//			(RCSTH7 = EXP_LINRCSTH7);
//			(RCSTH8 = EXP_LINRCSTH8);
//			(RCSTH9 = EXP_LINRCSTH9);
//			(RCSTH10 = EXP_LINRCSTH10);
//			(RCSTH11 = EXP_LINRCSTH11);
//			(RCSTH12 = EXP_LINRCSTH12);
//			(RCSTH13 = EXP_LINRCSTH13);
//			(RCSTH14 = EXP_LINRCSTH14);
//			(RCSTH15 = EXP_LINRCSTH15);
//		}

//		if (RCSMode==1)
//		{ 
//			(RCSTH0 = EXP_RCSTH0);
//			(RCSTH1 = EXP_RCSTH1);
//			(RCSTH2 = EXP_RCSTH2);
//			(RCSTH3 = EXP_RCSTH3);
//			(RCSTH4 = EXP_RCSTH4);
//			(RCSTH5 = EXP_RCSTH5);
//			(RCSTH6 = EXP_RCSTH6);
//			(RCSTH7 = EXP_RCSTH7);
//			(RCSTH8 = EXP_RCSTH8);
//			(RCSTH9 = EXP_RCSTH9);
//			(RCSTH10 = EXP_RCSTH10);
//			(RCSTH11 = EXP_RCSTH11);
//			(RCSTH12 = EXP_RCSTH12);
//			(RCSTH13 = EXP_RCSTH13);
//			(RCSTH14 = EXP_RCSTH14);
//			(RCSTH15 = EXP_RCSTH15);
//		}

		AddUMmuToVessel();

		Crew.WarnUserUMMUNotInstalled("Shuttle-D");
		// At the very end of clbkPostStep or clbkPreStep
		hUcgo.WarnUserUCGONotInstalled("Shuttle-D");
	}
// --------------------------------------------------------------
// Respond to buffered keyboard events
// --------------------------------------------------------------
int ShuttleD::clbkConsumeBufferedKey (DWORD key, bool down, char *kstate)
{

	if (!down) return 0;       // only process keydown events

	if(key==OAPI_KEY_G)
	{ //Gear
		RevertGEAR();
		return 1;
	}  
	if(key==OAPI_KEY_K)
	{// Payload Bay B
		RevertPLBAYB();
		return 1;
	}  
	if(key==OAPI_KEY_O)
	{// Payload Bay A
		RevertPLBAYA();
		return 1;
	} 

	if(key==OAPI_KEY_E&&!KEYMOD_SHIFT(kstate)&&!KEYMOD_CONTROL (kstate))
	{
		// PERFORM THE EVA, first we get is name with "GetCrewNameBySlotNumber" then we perform EVA with "EvaCrewMember"
		int Returned=Crew.EvaCrewMember(Crew.GetCrewNameBySlotNumber(SelectedUmmuMember));
		// we provide feedback to user (You can display a message on panel or wathewer)
		// here below all the return code possible:
		switch(Returned)
		{
		case TRANSFER_TO_DOCKED_SHIP_OK:
			sprintf(SendHudMessage(),"Transfer to docked ship Ok - %s transfered",
				Crew.GetLastEvaedCrewName());SelectedUmmuMember=0;
			break;
		case EVA_OK:
			sprintf(SendHudMessage(),"EVA OK - %s left the ship",
				Crew.GetLastEvaedCrewName());SelectedUmmuMember=0;
			break;
		case ERROR_NO_ONE_ON_BOARD:
			strcpy(SendHudMessage(),"Error, no one on board, unable to EVA");
			break;
		case ERROR_AIRLOCK_CLOSED:
			strcpy(SendHudMessage(),"Error, airlock is closed, unable to EVA");
			break;
		case ERROR_DOCKED_SHIP_HAVE_AIRLOCK_CLOSED:
			strcpy(SendHudMessage(),"Error, docked ship's airlock is closed, unable to transfer");
			break;
		case ERROR_DOCKED_SHIP_IS_FULL:
			strcpy(SendHudMessage(),"Error, docked ship is already full transfer failed");
			break;
		case ERROR_CREW_MEMBER_NOT_FOUND:
			strcpy(SendHudMessage(),"Error, no crew by this name in ship");
			break;
		case ERROR_DOCKEDSHIP_DONOT_USE_UMMU:
			strcpy(SendHudMessage(),"Error, docked ship do not use UMmu 2.0, ask author to add it");
			break;
		case ERROR_MISC_ERROR_EVAFAILED:
			strcpy(SendHudMessage(),"Misc error with UMMU install it again");
			break;
		}
		return TRUE;
	}

	//---------------------------------------------------------------------------
	// Ummu Key "1" Select next member This is just internal to the demo
	// you may do your own selection system by panel button, name etc etc
	if(key==OAPI_KEY_1&&!KEYMOD_SHIFT(kstate)&&!KEYMOD_CONTROL (kstate))
	{
		// we test there is someone aboard
		if(Crew.GetCrewTotalNumber()==0)
		{
			strcpy(SendHudMessage(),"Sorry no one aboard unable to select");	
			return 1;
		}

		// we test that we select existing member
		if(SelectedUmmuMember<Crew.GetCrewTotalNumber()-1)
			SelectedUmmuMember++;
		char * Name=Crew.GetCrewNameBySlotNumber(SelectedUmmuMember);
		sprintf(SendHudMessage(),"Slot %i  %s \"%s\" aged %i Selected for EVA or Transfer, please press \"E\" to EVA",
			SelectedUmmuMember,Crew.GetCrewMiscIdBySlotNumber(SelectedUmmuMember),
			Name,Crew.GetCrewAgeBySlotNumber(SelectedUmmuMember));
		return 1;
	}

	//---------------------------------------------------------------------------
	// Ummu Key "2" Select previous member This is just internal to the demo
	// you may do your own selection system by panel button
	if(key==OAPI_KEY_2&&!KEYMOD_SHIFT(kstate)&&!KEYMOD_CONTROL (kstate))
	{
		// we test there is someone aboard
		if(Crew.GetCrewTotalNumber()==0)
		{
			strcpy(SendHudMessage(),"Sorry no one aboard unable to select");	
			return 1;
		}
		if(SelectedUmmuMember>0)
			SelectedUmmuMember--;
		char * Name=Crew.GetCrewNameBySlotNumber(SelectedUmmuMember);
		sprintf(SendHudMessage(),"Slot %i %s \"%s\" aged %i Selected for EVA or Transfer"
			", please press \"E\" to EVA",SelectedUmmuMember,
			Crew.GetCrewMiscIdBySlotNumber(SelectedUmmuMember),Name,
			Crew.GetCrewAgeBySlotNumber(SelectedUmmuMember));
		return 1;
	}

		//---------------------------------------------------------------------------
	// Ummu Key "3" Select next member This is just internal to the demo
	// you may do your own selection system by panel button, name etc etc
	if(key==OAPI_KEY_4&&!KEYMOD_SHIFT(kstate)&&!KEYMOD_CONTROL (kstate))
	{


		// we test that we select existing member
		if(iSelectedCargo<18-1)
			iSelectedCargo++;
		char * SlotName=Crew.GetCrewNameBySlotNumber(SelectedUmmuMember);
		double GetCargoSlotMass(int Num); 
		sprintf(SendHudMessage(),"Slot %i selected",
			iSelectedCargo);
		return 1;
	}

	//---------------------------------------------------------------------------
	// Ummu Key "4" Select previous member This is just internal to the demo
	// you may do your own selection system by panel button
	if(key==OAPI_KEY_3&&!KEYMOD_SHIFT(kstate)&&!KEYMOD_CONTROL (kstate))
	{

		if(iSelectedCargo>0)
			iSelectedCargo--;
		char * SlotName=Crew.GetCrewNameBySlotNumber(SelectedUmmuMember);
		double GetCargoSlotMass(int Num); 
		sprintf(SendHudMessage(),"Slot %i selected",
			iSelectedCargo);
		return 1;
	}

			//---------------------------------------------------------------------------
	// Ummu Key "5" Select next Dock/Airlock
	if(key==OAPI_KEY_5&&!KEYMOD_SHIFT(kstate)&&!KEYMOD_CONTROL (kstate))
	{
	if(iActiveDockNumber > 0)
	iActiveDockNumber--;
	sprintf(SendHudMessage(),"Active dock number changed to: %i", iActiveDockNumber);
	SetUMMUAirlockPos();
	return 1;

	}

	//---------------------------------------------------------------------------
	// Ummu Key "6" Select previous Dock/Airlock
	if(key==OAPI_KEY_6&&!KEYMOD_SHIFT(kstate)&&!KEYMOD_CONTROL (kstate))
	{
	if(iActiveDockNumber < 1)
	iActiveDockNumber++;
	sprintf(SendHudMessage(),"Active dock number changed to: %i", iActiveDockNumber);
	SetUMMUAirlockPos();
	return 1;
	}

	//---------------------------------------------------------------------------
	// Ummu Key "A" Open & Close the virtual UMMU airlock door
	if(key==OAPI_KEY_A&&!KEYMOD_SHIFT(kstate)&&!KEYMOD_CONTROL (kstate))
	{
		// switch state
		Crew.SetAirlockDoorState(!Crew.GetAirlockDoorState());
		// display state
		if(Crew.GetAirlockDoorState()==TRUE)
			strcpy(SendHudMessage(),"Airlock is now open");	
		else
			strcpy(SendHudMessage(),"Airlock is now closed");	
		return 1;
	}
	//---------------------------------------------------------------------------
	// Get some infos Name of ship and total soul aboard
	if(key==OAPI_KEY_S)
	{
		sprintf(SendHudMessage(),"%i souls aboard ship %s, %i seats available",
			Crew.GetCrewTotalNumber(),GetName(),4-Crew.GetCrewTotalNumber());
		return 1;
	}

	//---------------------------------------------------------------------------
	// ADD some Fun, Eject the guy, No check of all return code here to keep listing small and clear.
	// Notice eject function doesn't check airlock state at all.
	// GOOD IDEA: Get the Object's handle after ejection with function "GetObjHandleOfLastEVACrew"
	// and add to it one very small tank, thruster and smoke, then fire thruster (see pilot ejection of DGIV)
	// BAD IDEA: Not testing the handle returned by "GetObjHandleOfLastEVACrew" before using may
	// cause a CTD if by any bad luck the pointer is invalid (handle==NULL)
	if(key==OAPI_KEY_ESCAPE&&!KEYMOD_SHIFT(kstate)&&!KEYMOD_CONTROL (kstate))
	{
		if(Crew.EjectCrewMember(Crew.GetCrewNameBySlotNumber(SelectedUmmuMember))==EVA_OK)
			sprintf(SendHudMessage(),"%s EJECTED",Crew.GetLastEvaedCrewName());
		SelectedUmmuMember=0;
		return 1;
	}
	// THIS IS FOR ADDING CREW SEE PDF doc "Allow user to add crew to your ship 
	// without scenery editor"
	if(key==OAPI_KEY_M&&!KEYMOD_SHIFT(kstate)&&!KEYMOD_CONTROL (kstate))
	{
		AddUMmuToVessel(TRUE);
	}
	// 9 key "select" one cargo on disk (cycle)
	if(key==OAPI_KEY_9&&!KEYMOD_SHIFT(kstate)&&!KEYMOD_CONTROL (kstate))
	{
		sprintf(SendCargHudMessage(),"%s - selected",hUcgo.ScnEditor_SelectNextCargoAvailableOnDisk());
		return 1;
	}
	// SHIFT+9 key "add last cargo selected by key 9"
	// If iSelectedCargo=-1 (default) add to the first free slot found
	if(key==OAPI_KEY_9&&KEYMOD_SHIFT(kstate)&&!KEYMOD_CONTROL (kstate))
	{
		if(hUcgo.ScnEditor_AddLastSelectedCargoToSlot(iSelectedCargo)==TRUE)
		{
			strcpy(SendCargHudMessage(),"Cargo added to ship");
		}
		else
		{
			if(iSelectedCargo<0)
			{
				strcpy(SendCargHudMessage(),"Cargo not added (ship full or weight excess ?)");
			}
			else
			{
				strcpy(SendCargHudMessage(),"Cargo not added (slot full ship full or weight excess ?)");
			}
		}
		return 1;
	}
	// "C" grapple cargo. If iSelectedCargo=-1 (default) add to the first free slot found
	if(key==OAPI_KEY_C&&!KEYMOD_SHIFT(kstate)&&!KEYMOD_CONTROL (kstate))
	{
		int ReturnedCode=hUcgo.GrappleOneCargo(iSelectedCargo);
		// for return code list see function "GrappleOneCargo" in the header
		switch(ReturnedCode)
		{
		case 1:
			strcpy(SendCargHudMessage(),"Cargo grappled");
			break;
		case 0:
			strcpy(SendCargHudMessage(),"No cargo in range");
			break;
		case -1:
			strcpy(SendCargHudMessage(),"cargo exceed maximum mass");
			break;
		case -2:
			strcpy(SendCargHudMessage(),"bad config, mesh not found or slot not declared");
			break;
		case -3:
			strcpy(SendCargHudMessage(),"Can't grapple cargo, slot not empty");
			break;
		case -4:
			strcpy(SendCargHudMessage(),"Can't grapple cargo,doors closed ");
			break;
		case -5:
			strcpy(SendCargHudMessage(),"Can't grapple cargo,Ship full");
			break;
		default:
			strcpy(SendCargHudMessage(),"Misc error Unable to grapple cargo");
		}
		return 1;
	}
	// SHIFT+C release cargo. If iSelectedCargo=-1 (default) release the first free slot found
	if(key==OAPI_KEY_C&&KEYMOD_SHIFT(kstate)&&!KEYMOD_CONTROL (kstate))
	{
		if(hUcgo.ReleaseOneCargo(iSelectedCargo)!=FALSE)
		{
			strcpy(SendCargHudMessage(),"Cargo released");
		}
		else
		{
			strcpy(SendCargHudMessage(),"Cargo not released (empty slot, no cargo aboard?)");
		}
		return 1;
	}
	// "8" show some info on cargo
	if(key==OAPI_KEY_8&&!KEYMOD_SHIFT(kstate)&&!KEYMOD_CONTROL (kstate))
	{
		sprintf(SendCargHudMessage(),"%i cargos aboard. "
			"Total cargos weight: %.0fkg",hUcgo.GetNbrCargoLoaded(),hUcgo.GetCargoTotalMass());
		return 1;
	}
	return 0;
}
//-------------------------------------------------------------------------
// THIS IS FOR ADDING CREW SEE PDF doc "Allow user to add crew to your ship 
// without scenery editor"
bool UMmuCrewAddCallback(void *id, char *str, void *data)
{
	if(strlen(str)<2||strlen(str)>38)
		return false;
	char *cPtr=(char*)data;	if(*cPtr==2){*cPtr=3;strcpy(cPtr+2,str);}
	else if(*cPtr==4){*cPtr=5;strcpy(cPtr+42,str);}
	else if(*cPtr==6){*cPtr=7;strcpy(cPtr+82,str);}return true;
}
void ShuttleD::AddUMmuToVessel(BOOL bStartAdding)
{
	if(bStartAdding==FALSE&&cAddUMmuToVessel[0]==0)
		return;
	if(bStartAdding==TRUE){
		int salut=sizeof(cAddUMmuToVessel);
		memset(cAddUMmuToVessel,0,sizeof(cAddUMmuToVessel));
		cAddUMmuToVessel[0]=1;
	}
	else if(cAddUMmuToVessel[0]==1){
		cAddUMmuToVessel[0]=2;
		oapiOpenInputBox ("Enter new crew's name (or escape)",UMmuCrewAddCallback,0,30,(void*)cAddUMmuToVessel);
	}
	else if(cAddUMmuToVessel[0]==3){
		cAddUMmuToVessel[0]=4;
		oapiOpenInputBox ("Enter crew's age",UMmuCrewAddCallback,0,30,(void*)cAddUMmuToVessel);
	}
	else if(cAddUMmuToVessel[0]==5){
		cAddUMmuToVessel[0]=6;
		oapiOpenInputBox ("Enter function (Capt,Sec,Vip,Sci,Doc,Tech,Crew,Pax)",UMmuCrewAddCallback,0,30,(void*)cAddUMmuToVessel);
	}
	else if(cAddUMmuToVessel[0]==7){
		cAddUMmuToVessel[0]=0;
		int Age=max(5,min(100,atoi(&cAddUMmuToVessel[42])));
		if(Crew.AddCrewMember(&cAddUMmuToVessel[2],Age,70,70,&cAddUMmuToVessel[82])==TRUE){
			sprintf(SendHudMessage(),"Crew \"%s\" aged %i added to vessel",&cAddUMmuToVessel[2],Age);
		}
		else{
			strcpy(SendHudMessage(),"ERROR: Crew not added (vessel full?)");
		}
	}
}

//	hFont = CreateFont (-20, 3, 0, 0, 150, 0, 0, 0, 0, 0, 0, 0, 0, "Arial");

//=========================================================
// Load and Delete Module Stuff
//=========================================================
DLLCLBK void InitModule (HINSTANCE hModule)
{
	g_hDLL = hModule;
	hFont = CreateFont (-20, 3, 0, 0, 150, 0, 0, 0, 0, 0, 0, 0, 0, "Haettenschweiler");
	hPen = CreatePen (PS_SOLID, 3, RGB (120,220,120));
	hBrush = CreateSolidBrush (RGB(0,128,0));

	// perform global module initialisation here
}
DLLCLBK void ExitModule (HINSTANCE hModule)
{
	// perform module cleanup here
	DeleteObject (hFont);
	DeleteObject (hPen);
	DeleteObject (hBrush);

}

//=========================================================
// Load and Delete Vessel Stuff
//=========================================================
DLLCLBK VESSEL *ovcInit (OBJHANDLE hvessel, int flightmodel)
{
	return new ShuttleD (hvessel, flightmodel);
}
DLLCLBK void ovcExit (VESSEL *vessel)
{
	if (vessel)
		delete (ShuttleD*)vessel;
}

void ShuttleD::clbkPostCreation (void)
{

	////////////////////////////////////////////////////////////////
	// 3-ORBITERSOUND EXAMPLE - INIT AND LOADING OF WAV
	// THIS MUST BE CALLED ABSOLUTELY IN THE "POSTCREATION CALLBACK" 
	////////////////////////////////////////////////////////////////
	// here we connect to OrbiterSound and store the returned ID in your class
	// this is the first thing to do. You must call this in "clbkPostCreation" 
	// (new version of ovcPostCreation wich is now obsolet)
	SHD=ConnectToOrbiterSoundDLL3(GetHandle());

	RequestLoadVesselWave3(SHD,GEARUP,"Sound\\ShuttleD\\gearup.wav",INTERNAL_ONLY);
	RequestLoadVesselWave3(SHD,GEARDOWN,"Sound\\ShuttleD\\geardown.wav",INTERNAL_ONLY);
	RequestLoadVesselWave3(SHD,PLBAYAOPEN,"Sound\\ShuttleD\\plbayaopen.wav",INTERNAL_ONLY);
	RequestLoadVesselWave3(SHD,PLBAYACLOSE,"Sound\\ShuttleD\\plbayaclose.wav",INTERNAL_ONLY);
	RequestLoadVesselWave3(SHD,PLBAYBOPEN,"Sound\\ShuttleD\\plbaybopen.wav",INTERNAL_ONLY);
	RequestLoadVesselWave3(SHD,PLBAYBCLOSE,"Sound\\ShuttleD\\plbaybclose.wav",INTERNAL_ONLY);

	// now we are allowed for example to replace variable sound of OrbiterSound.
	// it will use them instead of the stock one when our vessel have the focus, see header file for parameter 
	// (you can replace more than the four below see parameters for "ReplaceStockSound3()")
	ReplaceStockSound3(SHD,"Sound\\ShuttleD\\mainext.wav",	REPLACE_MAIN_THRUST);
	ReplaceStockSound3(SHD,"Sound\\ShuttleD\\attfire.wav",		REPLACE_RCS_THRUST_ATTACK);
	ReplaceStockSound3(SHD,"Sound\\ShuttleD\\attsustain.wav",	REPLACE_RCS_THRUST_SUSTAIN);
	ReplaceStockSound3(SHD,"Sound\\ShuttleD\\aircond.wav",		REPLACE_AIR_CONDITIONNING);

	ReplaceStockSound3(SHD,"Sound\\ShuttleD\\aircond.wav",		REPLACE_COCKPIT_AMBIENCE_1);
	ReplaceStockSound3(SHD,"Sound\\ShuttleD\\aircond.wav",		REPLACE_COCKPIT_AMBIENCE_2);
	ReplaceStockSound3(SHD,"Sound\\ShuttleD\\aircond.wav",		REPLACE_COCKPIT_AMBIENCE_3);
	ReplaceStockSound3(SHD,"Sound\\ShuttleD\\aircond.wav",		REPLACE_COCKPIT_AMBIENCE_4);
	ReplaceStockSound3(SHD,"Sound\\ShuttleD\\aircond.wav",		REPLACE_COCKPIT_AMBIENCE_5);
	ReplaceStockSound3(SHD,"Sound\\ShuttleD\\aircond.wav",		REPLACE_COCKPIT_AMBIENCE_6);
	ReplaceStockSound3(SHD,"Sound\\ShuttleD\\aircond.wav",		REPLACE_COCKPIT_AMBIENCE_7);
	ReplaceStockSound3(SHD,"Sound\\ShuttleD\\aircond.wav",		REPLACE_COCKPIT_AMBIENCE_8);
	ReplaceStockSound3(SHD,"Sound\\ShuttleD\\aircond.wav",		REPLACE_COCKPIT_AMBIENCE_9);

	// Now your ship have custom sound you can end here if you don't want to bother anymore
	// with sound, your ship is already customised. Anyway I'll show you more below.

	//...

	// here we will load a sound that will play when we pass 500 meter altitude
	// We will play it later ourself when we reach 500 meter (see opcPreStep below)
	RequestLoadVesselWave3(SHD,MY500METERSOUND,"Sound\\OrbiterSound_SDK\\sound\\my500meter.wav",RADIO_SOUND);
	// AS we will play it using the "radioexclusive function" and as we don't want to be disturbed
	// by OrbiterSound's ATC we set the ATC option of OrbiterSound to false (no more ATC will play)
	// it's not an obligation while the "playradio..." function stop any stock ATC sound that is already playing
	// but if you want to use radio sound you may not want to be disturbed by "off-topic" atc.
	SoundOptionOnOff3(SHD,PLAYRADIOATC,FALSE);

	// we disable also the stock countdown when we take-off.. it's annoying :)
	SoundOptionOnOff3(SHD,PLAYCOUNTDOWNWHENTAKEOFF,FALSE);

	// Here we will load a radar sound that will play in cockpit view only and after take-off below 500 meter
	// this sound will be looped and will see it's frequency varying as we approach ground
	RequestLoadVesselWave3(SHD,MYRADARSOUND,"Sound\\OrbiterSound_SDK\\sound\\myradar.wav",INTERNAL_ONLY);

	// Here is THE example of an external sound that must be also faded by distance and pressure 
	// as stated in the header of ObiterSoundSDK3.h it's IMPORTANT that you call this sound looped
	// and at each frame otherwise it will not be faded properly.
	// "EXTERNAL_ONLY_FADED_CLOSE" mean that it will be faded at close distance as the RCS sound in external view.
	RequestLoadVesselWave3(SHD,MYEXTERNAL_UFO_FADEDSOUND,"Sound\\OrbiterSound_SDK\\sound\\myUfoSound.wav",EXTERNAL_ONLY_FADED_CLOSE);
}

// --------------------------------------------------------------
// loop called each frame
// --------------------------------------------------------------
void ShuttleD::clbkPreStep (double simt, double simdt, double mjd) 
{
	double Altitude=0;
	static BOOL AltitudeSoundPlayed=FALSE;
	static BOOL RadarFlagForSound=FALSE;

	///////////////////////////////////////////////////////////////////
	// 4-ORBITERSOUND EXAMPLE - PLAYING THE SOUND WE LOADED DYNAMICALLY
	///////////////////////////////////////////////////////////////////

	// ----------------------------------------------------------
	// We play the "500 meter" sound we loaded previously 
	// we use the function "playradio" wich stop OrbiterSound atc
	// sound if one is playing.
	// ----------------------------------------------------------
	oapiGetFocusAltitude(&Altitude);
	if(Altitude>500&&Altitude<550&&AltitudeSoundPlayed==FALSE)
	{
		PlayVesselRadioExclusiveWave3(SHD,MY500METERSOUND,255);	// 255=volume maximum 
		AltitudeSoundPlayed=TRUE;
	}
	if(Altitude<500||Altitude>550)
		AltitudeSoundPlayed=FALSE;


	// ------------------------------------------------------
	// here we play our radar sound that slide with altitude
	// ------------------------------------------------------
	if(Altitude<500&&Altitude>2)
	{
		PlayVesselWave3(SHD,MYRADARSOUND,LOOP,255,(int)(11025+((500-Altitude)*40)));		// play looped and a frequency that increase with altitude
		RadarFlagForSound=TRUE;
	}
	else if(RadarFlagForSound=TRUE)
	{
		// we stop the sound only once (it would not harm else but it will save a bit of processor time)
		StopVesselWave3(SHD,MYRADARSOUND);
	}


	// ------------------------------------------------------
	// here we play our external "ufo" sound
	// ------------------------------------------------------
	// As stated a sound that play in external view must be called looped heach frame so it
	// fade properly with distance and pressure. Also we add a litle effect: if the ship is landed
	// the frequency is lower simulating an "iddle" engine.
	if(Altitude<2)
		PlayVesselWave3(SHD,MYEXTERNAL_UFO_FADEDSOUND,LOOP,255,11025); // original wav is 11025 hz
	else
		PlayVesselWave3(SHD,MYEXTERNAL_UFO_FADEDSOUND,LOOP,255,9000);  


	// -------------------------------------------------------------
	// another example with a different behaviour of the "Ufo" sound
	// -------------------------------------------------------------
	// here an example of the ufo sound that will play only beetween 0 and 500 meter high.
	// I show it here so you know how to stop/start an external sound.
	//if(Altitude<500)
	//	PlayVesselWave3(MyID,MYEXTERNAL_UFO_FADEDSOUND,LOOP,255); // original wav is 11025 hz
	//else
	//	StopVesselWave3(MyID,MYEXTERNAL_UFO_FADEDSOUND);		   // you can use a flag to avoid reapeated call (even the impact is very low, the function return immediately if the sound is already stoped)
}

ShuttleD::~ShuttleD() 
{
     delete th_rcs, th_main, th_hover;
}

and header:

Code:
#pragma once
#include "Orbitersdk.h"
#include "UMmuSDK.h"
#include "UCGOCargoSDK.h" //UCGO 2.0 copy past this line


#define	BLACK		RGB(0x00, 0x00, 0x00)
#define	WHITE		RGB(0xFF, 0xFF, 0xFF)
#define RED			RGB(0xFF, 0x00, 0x00)
#define GREEN		RGB(0x00, 0xFF, 0x00)
#define BLUE		RGB(0x00, 0x00, 0xFF)
#define YELLOW		RGB(0xFF, 0xFF, 0x00)

// Vessel Parameters
const double EXP_SIZE = 37.4; // mean radius in meters
const VECTOR3 EXP_CS = {95,82,20}; //Shuttle-D cross section in m^2
const VECTOR3 EXP_PMI = {14.00,16.00,2.20}; //Principal Moments of Inertia, normalized, m^2
const double EXP_EMPTYMASS = 16970; //empty vessel mass in kg
const double EXP_FUELMASS =  18000; //max fuel mass in kg
const double EXP_RCS1FUELMASS =  120; //max fuel mass in kg
const double EXP_RCS2FUELMASS =  120; //max fuel mass in kg
const double EXP_RCS3FUELMASS =  120; //max fuel mass in kg
const double EXP_RCS4FUELMASS =  120; //max fuel mass in kg
const double EXP_RCS5FUELMASS =  120; //max fuel mass in kg
const double EXP_RCS6FUELMASS =  120; //max fuel mass in kg
const double EXP_RCS7FUELMASS =  120; //max fuel mass in kg
const double EXP_RCS8FUELMASS =  120; //max fuel mass in kg
const double EXP_RCS9FUELMASS =  120; //max fuel mass in kg
const double EXP_RCS10FUELMASS =  120; //max fuel mass in kg
const double EXP_RCS11FUELMASS =  120; //max fuel mass in kg
const double EXP_RCS12FUELMASS =  120; //max fuel mass in kg
const double EXP_RCS13FUELMASS =  120; //max fuel mass in kg
const double EXP_RCS14FUELMASS =  120; //max fuel mass in kg
const double EXP_RCSRESFUELMASS =  1000; //max fuel mass in kg
const double EXP_O2TANKMASS =  1000; //max fuel mass in kg
const double VACSHD_ISP = 9000; //fuel-specific impulse in m/s
const double NMLSHD_ISP = 4200; //fuel-specific impulse in m/s
const double P_NML = 101.4e3;
const double EXP_MAXMAINTH = 200000; 
const double EXP_MAXHOVERTH = 150000;
const double RCSTH0 = 1200; 
const double RCSTH1 = 1200;
const double RCSTH2 = 1470; 
const double RCSTH3 = 1470;
const double RCSTH4 = 1200; 
const double RCSTH5 = 1200;
const double RCSTH6 = 1200; 
const double RCSTH7 = 1200;
const double RCSTH8 = 1200; 
const double RCSTH9 = 1200;
const double RCSTH10 = 1200; 
const double RCSTH11 = 1200;
const double RCSTH12 = 1200; 
const double RCSTH13 = 1200;
const double RCSTH14 = 1200; 
const double RCSTH15 = 1200;
const double GEAR_OPERATING_SPEED = 0.10;
const double PLBAYA_OPERATING_SPEED = 0.07;
const double PLBAYB_OPERATING_SPEED = 0.18;


class ShuttleD :public VESSEL3
{
public:
    ShuttleD (OBJHANDLE hObj, int fmodel);

	~ShuttleD();

	MESHHANDLE DVCInterior;
	void DefineAnimations();
	void clbkSetClassCaps (FILEHANDLE cfg);
	void clbkLoadStateEx (FILEHANDLE scn, void *status);
	bool clbkDrawHUD (int mode, const HUDPAINTSPEC *hps, oapi::Sketchpad *skp);
	void clbkSaveState (FILEHANDLE scn);
	void Timestep (double simt);
	void clbkPostStep (double simtt, double simdt, double mjd);
	void RevertGEAR (void);
	void RevertPLBAYA (void);
	void RevertPLBAYB (void);
	void CheckFuelState (void);
	void clbkPreStep (double simt, double simdt, double mjd);
	void clbkPostCreation(void);

	void LCDPrint(SURFHANDLE surf, char* text, int row, int _length);

	void SetUMMUAirlockPos (void);

	enum GEARStatus { GEAR_UP, GEAR_DOWN, GEAR_RAISING, GEAR_LOWERING } GEAR_status;
	enum PLBAYAStatus { PLBAYA_UP, PLBAYA_DOWN, PLBAYA_CLOSING, PLBAYA_OPENING } PLBAYA_status;
	enum PLBAYBStatus { PLBAYB_UP, PLBAYB_DOWN, PLBAYB_CLOSING, PLBAYB_OPENING } PLBAYB_status;
	enum {CAM_VCPILOT, CAM_VCPSNGR1, CAM_VCPSNGR2, CAM_VCPSNGR3, CAM_VCPSNGR4} campos;
	int SHD;	// this is your unique Id, it will identify your ship in OrbiterSound.

	int  clbkConsumeBufferedKey (DWORD key, bool down, char *kstate);
	void clbkVisualCreated (VISHANDLE vis, int refcount);
	void clbkMFDMode (int mfd, int mode);
	bool clbkLoadVC (int id);
	bool clbkVCRedrawEvent (int id, int event, SURFHANDLE surf);
	bool clbkVCMouseEvent (int id, int event, VECTOR3 &p);
	VCMFDSPEC mfds_left;
	VCMFDSPEC mfds_right;

		// UMMU 2.0 DECLARATION
	UMMUCREWMANAGMENT Crew;
	int SelectedUmmuMember;				// for the SDK demo, select the member to eva
	int iActionAreaDemoStep;			// this is just to show one feature of action area.
	void clbkSetClassCaps_UMMu(void);	// our special SetClassCap function just added for more readability

	// The HUD display method variable, see PDF doc
	char cUmmuHudDisplay[255];			// UMmu hud char variable
	double dHudMessageDelay;			// UMmu hud display delay
	char *SendHudMessage(void);			// UMmu hud display function

	// THIS IS FOR ADDING CREW SEE PDF doc "Allow user to add crew to your ship 
	// without scenery editor"
	char cAddUMmuToVessel[255];
	void AddUMmuToVessel(BOOL bStartAdding=FALSE);

	// UCGO 2.0 CLASS HANDLE FUNCTION AND VARIABLES
	UCGO	hUcgo;						// Cargo class handle
	char   *SendCargHudMessage(void);	// Cargo hud display function
	char	cCargoHudDisplay[255];		// Cargo hud display char variable
	double	dCargHudMessageDelay;		// Cargo hud display delay
	int		iSelectedCargo;				// for the selection of cargos -1 by default



//	OBJHANDLE GetDockStatus (DOCKHANDLE hDock) const;

	/**
	 * \brief Returns a status flag for a docking port.
	 * \param port docking port index (>= 0)
	 * \return Docking status (0=free, 1=engaged)
	 * \note This method has the same functionality as 
	 *   \code (GetDockStatus (GetDockHandle(port)) ? 1:0) \endcode
	 * \sa GetDockStatus, GetDockHandle
	 */
private:
	int iActiveDockNumber;
	UINT anim_gear;
	UINT anim_PLBAYA;
	UINT anim_PLBAYB;
	double GEAR_proc,PLBAYA_proc,PLBAYB_proc;
	double O2Tank;
//	double RCSMode;
//	ATTACHMENTHANDLE  payload_attachment[2];
	PROPELLANT_HANDLE *MainFuel, *RCSRES, *RCS1, *RCS2, *RCS3, *RCS4, *RCS5, *RCS6, *RCS7, *RCS8, *RCS9, *RCS10, *RCS11, *RCS12;
	THRUSTER_HANDLE *th_rcs, *th_main, *th_hover;

	//double LIFT_SPEED;
};


HINSTANCE hDLL;
HFONT hFont;
HPEN hPen;
HBRUSH hBrush; 

#define AID_MFD1_LBUTTONS		0
#define AID_MFD1_RBUTTONS		1
#define MFD1_LBUTTON1			2
#define MFD1_LBUTTON2			3
#define MFD1_LBUTTON3			4
#define MFD1_LBUTTON4			5
#define MFD1_LBUTTON5			6
#define MFD1_LBUTTON6			7
#define MFD1_RBUTTON1			8
#define MFD1_RBUTTON2			9
#define MFD1_RBUTTON3			10
#define MFD1_RBUTTON4			11
#define MFD1_RBUTTON5			12
#define MFD1_RBUTTON6			13
#define MFD1_BBUTTON1			14
#define MFD1_BBUTTON2			15
#define MFD1_BBUTTON3			16
#define AID_MFD2_LBUTTONS		17
#define AID_MFD2_RBUTTONS		18
#define MFD2_LBUTTON1			19
#define MFD2_LBUTTON2			20
#define MFD2_LBUTTON3			21
#define MFD2_LBUTTON4			22
#define MFD2_LBUTTON5			23
#define MFD2_LBUTTON6			24
#define MFD2_RBUTTON1			25
#define MFD2_RBUTTON2			26
#define MFD2_RBUTTON3			27
#define MFD2_RBUTTON4			28
#define MFD2_RBUTTON5			29
#define MFD2_RBUTTON6			30
#define MFD2_BBUTTON1			31
#define MFD2_BBUTTON2			32
#define MFD2_BBUTTON3			33

On the more positive side, however I have been able to find a reliable Earth launch combination using the core of the Themis ETS rocket without a fairing, carrying the ShuttleD on top to orbit. My current main engine thrust values are a fair bit high for current estimates of NTR engines at the scale my ship could carry, but attaching velcro rockets booster engines onto the Shuttle D for use after BoosterSep may be enough for reaching orbit even with a NTR engine using current technology. Very excited about that

:woohoo:
 


I would just like to let everyone know that my 1.0 release for this project is going to be quite soon. I plan on releasing on the 21-24 of december or so, hopefully after Dansteph comes out with his UCGO/UMMU updates, but I dont feel like waiting any longer if not. To list the features available in 1.0 release:

-A virtual cockpit with working MFDs and controls for the payload bays & gear
-UMMU, UCGO, & Orbitersound 4.0 support
-Animated Gear & Payload bay doors
-Thruster lights aligned with the proper spots & using a custom exhaust texture
-UMMU Action areas for the bays & airlock
-Oxygen depletion, crashes, & atmospheric reentry can now kill the UMMU crew
 
Now that a fairly succesful 1.0 release is done, Im starting some work on a 1.1 release. The update will split the project into two variants, the Shuttle-DA & DB. The DA will have some improvements & tweaks to the original model, while the DB should have the main payload bay ripped out & replaced with another fuel tank. While Im getting started I was wondering if anyone could give me some suggestions on what the external communications hardware should look like?
 
Depends on the purpose.

Simple short range (ship-to-ship and EVA type) communications are usually done in the VHF/UHF band so a couple of simple whip or fin type antennas scattered about the hull are all you need.

Anything more sophisticated (longer range or high data rate) generally requires either a dish or a phased-array type assembly.

640px-Ku_Band_Antenna.jpg
 
Depends on the purpose.

Simple short range (ship-to-ship and EVA type) communications are usually done in the VHF/UHF band so a couple of simple whip or fin type antennas scattered about the hull are all you need.

Anything more sophisticated (longer range or high data rate) generally requires either a dish or a phased-array type assembly.

640px-Ku_Band_Antenna.jpg

Assuming the Ku-band is the short range version, Ill give a shot at adding that into the mesh. If I remove the landing gear, the underside of the forward hull might be a nice place for an equipment bay.

Second question: If I were to tear out the main payload bay & replace it with another fuel tank, how much would the ships dry mass change?
 
The KU band is the long range/data-link antenna. The short-range antennas would look like the simple whip or blade assemblies you have on your car.

ETA: the mass involve depends on the structural mass of the bay vs the structural mass of the tank.
 
Last edited:
The KU band is the long range/data-link antenna. The short-range antennas would look like the simple whip or blade assemblies you have on your car.

ETA: the mass involve depends on the structural mass of the bay vs the structural mass of the tank.

Will add those coms in first chance I get.

WRT the bay vs tank thing, I understand that, I was wondering if you or anyone else could provide an estimate of roughly how much they should mass?
 
How much fuel are we talking about and will it mass more or less than what you were orginally planning to carry?
 
How much fuel are we talking about and will it mass more or less than what you were orginally planning to carry?

No need to worry about fuel, Im only concerned with what the change in dry mass will be if I replace the main bay under the tunnel with another main fuel tank.
 
Back
Top