General Question Coding a parachute

BruceJohnJennerLawso

Dread Lord of the Idiots
Addon Developer
Joined
Apr 14, 2012
Messages
2,585
Reaction score
0
Points
36
Not really needed, but I recommend a state machine, which has the states:

Stored
Opening
Reefed
Unreefing
Deployed
Jettisoned

for example.

By gradually increasing the deployment of the parachutes, you can prevent large acceleration spikes and control issues.

Reefed is the initial deployed state of many large parachutes, with a band reducing the maximum diameter of the parachute for some time to let it stabilize and reduce the forces on the parachute. (Term comes from sailing: Reefing means reducing the area of the sail on a ship)

Something like this?

Code:
	enum ChuteStatus { 	Stored, Opening, Reefed, Unreefing, Deployed, Jettisoned } ChuteStatus;
 

Hlynkacg

Aspiring rocket scientist
Addon Developer
Tutorial Publisher
Donator
Joined
Dec 27, 2010
Messages
1,870
Reaction score
3
Points
0
Location
San Diego
Something like this?

Code:
	enum ChuteStatus { 	Stored, Opening, Reefed, Unreefing, Deployed, Jettisoned } ChuteStatus;

Yup but make sure you give them different names. using "ChuteStatus" twice is considered bad-form and may causes a compiler errors.

I.E

Code:
chutestate {STORED, DROGUE, OPENING, REFFED, UENREEFING, DEPLOYED, JETTISONED} CM_ChuteStatus;


---------- Post added at 10:37 ---------- Previous post was at 10:35 ----------

PS.

While I haven't actually gotten around to coding my re-entry sequence for Gumdrop, I'm watching this thread closely.
 

BruceJohnJennerLawso

Dread Lord of the Idiots
Addon Developer
Joined
Apr 14, 2012
Messages
2,585
Reaction score
0
Points
36
Yup but make sure you give them different names. using "ChuteStatus" twice is considered bad-form and may causes a compiler errors.

I.E

Code:
chutestate {STORED, DROGUE, OPENING, REFFED, UENREEFING, DEPLOYED, JETTISONED} CM_ChuteStatus;


---------- Post added at 10:37 ---------- Previous post was at 10:35 ----------

PS.

While I haven't actually gotten around to coding my re-entry sequence for Gumdrop, I'm watching this thread closely.

Yes I made sure to correct that issue.

At this point, I'm stumped frankly,

Variable drag elements is still not working. I adapted code from animations to create a chutestate enum that works with my para variable. I still get nothing from variable drag elements. Where exactly should I define variable drag elements to make it work?

I then tried my second option, defining a airfoil, but I found that that method isnt going to work, because Orbiter only allows you to create them in the vertical or horizontal axes of a vessel. My capsule looks straight up into the parachutes along its z-axis, so the airfoil method ends up causing uncontrollable shaking & rotating, Orbitersound plays the mach 1 clip, & the Phoenix ends up spinning uncontrollably somewhere in space :rolleyes:

So, that leaves me with only two options. I can simply use the vessel cross-sections method, which does work, but is unstable at high drag & timewarp, or I can go with the orginal suggestion by Sorindafabico, which was to use addforce with dynamic pressure.

Im rather lost on this at the moment, so I'll leave the source here for anyone to take a look.

Code:
#pragma once
#include "Orbitersdk.h"
#include "UMmuSDK.h"

// Vessel Parameters
// This is where data about the vessel class can be specified, then loaded later under a shorter name. For example,
// const double EXP_EMPTYMASS = 14770; allows me to put EXP_EMPTYMASS in place of 14770 when I specify the empty 
// mass of the vehicle later.

const double EXP_SIZE_BEFORE_SMJETT = 14; // mean radius in meters
const double EXP_SIZE_AFTER_SMJETT = 4; // mean radius in meters
const double EXP_SIZE_AFTER_CHUTESOPEN = 11; // mean radius in meters
const VECTOR3 EXP_CS_BEFORE_SMJETT = {57.99,58.69,17.33}; //Shuttle-D cross section in m^2
const VECTOR3 EXP_CS_AFTER_SMJETT = {10.13,10.25,17.11}; //Shuttle-D cross section in m^2
const VECTOR3 EXP_CS_AFTER_CHUTESOPEN = {12,12,17.11}; //Shuttle-D cross section in m^2
const VECTOR3 EXP_PMI_BEFORE_SMJETT = {14.48,14.49,2.16}; //Principal Moments of Inertia, normalized, m^2
const VECTOR3 EXP_PMI_AFTER_SMJETT = {1.50,1.50,1.93}; //Principal Moments of Inertia, normalized, m^2
const VECTOR3 EXP_PMI_AFTER_CHUTESOPEN = {9,9,3}; //Principal Moments of Inertia, normalized, m^2
const VECTOR3 CAPSULE_OFFSET = {0,0,6.214}; //Principal Moments of Inertia, normalized, m^2
const VECTOR3 SM_OFFSET = {0,0,-6.214}; //Principal Moments of Inertia, normalized, m^2
const VECTOR3 ZEROVECTOR = {0,0,0}; //Principal Moments of Inertia, normalized, m^2
const VECTOR3 FORWARD = {0,0,1}; //Principal Moments of Inertia, normalized, m^2
const VECTOR3 TENFORWARD = {0,0,10}; //Principal Moments of Inertia, normalized, m^2
const VECTOR3 TENTHOUSANDFORWARD = {0,0,10000}; //Principal Moments of Inertia, normalized, m^2
const VECTOR3 CHUTESATTACK = {0,20,0}; //Principal Moments of Inertia, normalized, m^2
const double CAPSULEMASS = 6400; //empty vessel mass in kg
const double SMMASS = 8900; //empty vessel mass in kg
const double EXP_MAINFUELMASS =  20000; //max fuel mass in kg
const double VACNTR_ISP = 5900; //fuel-specific impulse in m/s
const double NMLNTR_ISP = 2000; //fuel-specific impulse in m/s
const double MAINTH = 55000;
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 =  400; //max fuel mass in kg
const double EXP_RCS6FUELMASS =  400; //max fuel mass in kg
const double EXP_RCS7FUELMASS =  400; //max fuel mass in kg
const double EXP_RCS8FUELMASS =  400; //max fuel mass in kg
const double VACRCS_ISP = 1600; //fuel-specific impulse in m/s
const double NMLRCS_ISP = 710; //fuel-specific impulse in m/s
const double P_NML = 101.4e3;
const double RCSTH0 = 1200; 
const double RCSTH1 = 1200;
const double RCSTH2 = 1200; 
const double RCSTH3 = 1200;
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 RCSSMTH0 = 1600; 
const double RCSSMTH1 = 1600;
const double RCSSMTH2 = 1600; 
const double RCSSMTH3 = 1600;
const double RCSSMTH4 = 1600; 
const double RCSSMTH5 = 1600;
const double RCSSMTH6 = 1600; 
const double RCSSMTH7 = 1600;
const double RCSSMTH8 = 1600; 
const double RCSSMTH9 = 1600;
const double RCSSMTH10 = 1600; 
const double RCSSMTH11 = 1600;
const double RCSSMTH12 = 1600; 
const double RCSSMTH13 = 1600;
const double RCSSMTH14 = 1600; 
const double RCSSMTH15 = 1600;
const double PARACHUTE_SPEED = 0.400;


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

	~PhoenixASMN();

	// In this section functions to be called in the main body of the code are specified for use later. If a function placed in here is
	// never called later a "UNRESOLVED external" error will most likely pop up at compile-time. If a function is placed in the CPP but
	// not "created" here, it simply wont work.
	PROPELLANT_HANDLE RCS1, RCS2, RCS3, RCS4, RCS5, RCS6, RCS7, RCS8, MainFuel;
	DOCKHANDLE Dock0;
	THRUSTER_HANDLE th_rcsCM[12], th_rcsSM[16], th_group[4], th_main;



	MESHHANDLE PhoenixCapsule;
	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);
	double UpdateMass ();
	double O2Check ();
	double ParaCheck ();
	double WaterCheck ();
	void RevertChutes ();
	double Chutesclose ();
	double Chutesopen ();
	double AltitudeCheck ();
	double VelocityCheck ();
	double MeshControl ();
	double ClassControl ();
	double SMJettison ();
	double Checkint ();
	void clbkPostCreation(void);
	void SpawnObject(char* classname, char* ext, VECTOR3 ofs);

	// Bits of code used to give the gear & payload bay references to work with instead of 0,0.1,0.2...
	// The different VC camera positions are also identified here as well.

	enum {CAM_VCPILOT, CAM_VCPSNGR1, CAM_VCPSNGR2, CAM_VCPSNGR3, CAM_VCPSNGR4} campos;
	//enum chutestate {STORED, DROGUE, OPENING, REFFED, UNREEFING, DEPLOYED, JETTISONED} ChuteStatus;
	enum chutestate {OPENED, STORED, OPENING, CLOSING} ChuteStatus;


	// This is a unique id, used to identify the ship in OrbiterSound.

	int PHXASMN;	

	bool clbkLoadVC (int id);
	int  clbkConsumeBufferedKey (DWORD key, bool down, char *kstate);
	VCMFDSPEC mfds_left;
	VCMFDSPEC mfds_right;

	//UMMU 2.0 Code
	//This section contains code which is used to add support for UMMU crew, created by Dansteph.

		// 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

	// "Allow user to add crew to your ship 
	// without scenery editor"
	char cAddUMmuToVessel[255];
	void AddUMmuToVessel(BOOL bStartAdding=FALSE);

	char   *SendCargHudMessage(void);	// Cargo hud display function
	char	cCargoHudDisplay[255];		// Cargo hud display char variable
	double	dCargHudMessageDelay;		// Cargo hud display delay

	char   *SendCarg2HudMessage(void);	// Cargo hud display function
	char	cCargo2HudDisplay[255];		// Cargo hud display char variable
	double	dCarg2HudMessageDelay;		// Cargo hud display delay

	char   *SendCarg3HudMessage(void);	// Cargo hud display function
	char	cCargo3HudDisplay[255];		// Cargo hud display char variable
	double	dCarg3HudMessageDelay;		// Cargo hud display delay

	private:
	int iActiveDockNumber;

	// Vessel specific parameters are called here like the # of kilos of LOX in the onboard tanks, the positions of the gear & payload bay doors,
	//	a variable that Im hoping to use as a randomizer for this project in the future. Variables are used to store & keep track of various pieces
	// of information during a simulation session, but need to be saved & loaded properly in clbkLoadStateEx & clbkSaveState
	// if they are to be persistent. Oh hi Face... ;)



	int SMJett;
	double Para;
	int Chutes;
	double O2Tank;
	double Altitude;
	double Dv;
	double M0;
	double M1;
	double Airspeed;
	double Water;
	double MSStime;
	double Randomizer;
};


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

Code:
//=========================================================
// ShuttleDB 1.1 source code
// This is what I have been working on for the last few months. The Shuttle-D is currently designed as a NTR propelled cargo transport
// & utility vessel compatible with UMMU, UCGO, & Orbitersound. Ive made sure to heavily comment my source in order to give new addon devs
// a good resource for understanding many of the pitfalls I had to endure, and how to beat them. If youre planning on reading this as a tutorial,
// I would reccomend you start over in D9base.h, as I structured the tutorial starting from there.
//=========================================================

#define STRICT
#define ORBITER_MODULE
#include "PhoenixASMNbase.h"
#include "orbitersdk.h"
#include <math.h>
#include <stdio.h>
#include "OrbiterSoundSDK40.h"
#include "VesselAPI.h"

HINSTANCE g_hDLL;
VISHANDLE MainExternalMeshVisual = 0;


void Drogue_MomentCoeff (double aoa,double M,double Re,double *cl,double *cm,double *cd0)
{
	int i;
	const int nlift = 9;
	static const double AOA[nlift] = {-90*RAD,-85*RAD,-75*RAD,0*RAD,90*RAD,180*RAD,255*RAD,265*RAD,270*RAD};
	static const double CM[nlift]  = {       0,  -0.01,    -0.1,  -0.2,  0,    0.2,   0.1,     0.01,      0};

	static const double SCM[nlift] = {(CM[1]-CM[0])/(AOA[1]-AOA[0]), (CM[2]-CM[1])/(AOA[2]-AOA[1]),
		                              (CM[3]-CM[2])/(AOA[3]-AOA[2]), (CM[4]-CM[3])/(AOA[4]-AOA[3]),
									  (CM[5]-CM[4])/(AOA[5]-AOA[4]), (CM[6]-CM[5])/(AOA[6]-AOA[5]),
									  (CM[7]-CM[6])/(AOA[7]-AOA[6]), (CM[8]-CM[7])/(AOA[8]-AOA[7])};
	for (i = 0; i < nlift-1 && AOA[i+1] < aoa; i++);
	*cl= 0;

	*cm=CM[i] + (aoa-AOA[i])*SCM[i];

	*cd0 = 0.020  + oapiGetWaveDrag (M, 0.75, 1.0, 1.1, 0.04);
}
void Parachute_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, 30*RAD,90*RAD,180*RAD};
	static const double CL[nabsc]  = {    0,     0        ,0.5,      1,    0.5,   0  , 0     };
	static const double CM[nabsc]  = {    0,      0,     0.0010,   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)
// To the best of my knowledge, this is called when a Shuttle-D is first created & allows parameters to be set to specific values right away.
// For example 	O2Tank = 1000; indicates that the main oxygen tank parameter is set to 1000/1000; full, upon creation of a new Shuttle-D.
// ==============================================================

PhoenixASMN::PhoenixASMN (OBJHANDLE hObj, int fmodel)
	: VESSEL3 (hObj, fmodel)
{
	O2Tank = 70;
	Water = 230;
	SMJett = 1;
	Chutes = 0;
	Para = 0;
}

//=========================================================
// Mass Update Function
// A big prize to anyone who can guess what this does! Yes that is correct, it updates the mass of a Shuttle-D vessel based on its empty mass & the amount of O2 it is carrying!
// As a previous English teacher I once had was fond of saying, your prize is knoledge & undertanding (shows how much I learned :)
// This function does not fully complete the mass calculations, as the UCGO mass update function down in void clbkPostStep also has a hand in it, but this is the main place or things of that ilk, so...
//=========================================================

double PhoenixASMN::UpdateMass ()
{
double mass=(CAPSULEMASS+(SMJett*SMMASS));

double CrewComplement = Crew.GetCrewTotalNumber();

mass+=(O2Tank+(CrewComplement*85));

return mass;
}

void PhoenixASMN::SpawnObject(char* classname, char* ext, VECTOR3 ofs)
{
	VESSELSTATUS vs;
	char name[256];
	GetStatus(vs);
	Local2Rel (ofs, vs.rpos);
	vs.eng_main = 1.0;
	vs.status = 0;
	strcpy (name, GetName()); strcat (name, ext);
	oapiCreateVessel (name, classname, vs);
}


//=========================================================
// O2Check Function
// A very simple function here, that allows me to return the value of oxygen remaining in the tanks.
// I needed this in order for the hud check function that returns O2 levels to the pilot would work.
//=========================================================
double PhoenixASMN::O2Check ()
{
return O2Tank;
}


double PhoenixASMN::WaterCheck ()
{
return Water;
}

double PhoenixASMN::ParaCheck ()
{
return Para;
}

double PhoenixASMN::AltitudeCheck ()
{

Altitude = GetAltitude ();

return Altitude;
}

double PhoenixASMN::VelocityCheck ()
{

Airspeed = GetAirspeed ();

return Airspeed;
}

double PhoenixASMN::Checkint ()
{
return SMJett;
}

double PhoenixASMN::SMJettison ()
{
	SpawnObject( "PhoenixSMN", "SM", ZEROVECTOR);
	AddForce((TENTHOUSANDFORWARD), ZEROVECTOR);
	ShiftCG(CAPSULE_OFFSET);
	SMJett--;
	MeshControl ();
	ClassControl ();

	DelPropellantResource (MainFuel);
	DelPropellantResource (RCS5);
	DelPropellantResource (RCS6);
	DelPropellantResource (RCS7);
	DelPropellantResource (RCS8);

	SetThrusterResource(th_rcsCM[0], RCS1);
	SetThrusterResource(th_rcsCM[1], RCS1);
	SetThrusterResource(th_rcsCM[2], RCS3);
	SetThrusterResource(th_rcsCM[3], RCS3);
	SetThrusterResource(th_rcsCM[4], RCS2);
	SetThrusterResource(th_rcsCM[5], RCS2);
	SetThrusterResource(th_rcsCM[6], RCS4);
	SetThrusterResource(th_rcsCM[7], RCS4);
	SetThrusterResource(th_rcsCM[8], RCS3);
	SetThrusterResource(th_rcsCM[9], RCS3);
	SetThrusterResource(th_rcsCM[10], RCS4);
	SetThrusterResource(th_rcsCM[11], RCS4);

	SetThrusterResource(th_rcsSM[0], NULL);
	SetThrusterResource(th_rcsSM[1], NULL);
	SetThrusterResource(th_rcsSM[2], NULL);
	SetThrusterResource(th_rcsSM[3], NULL);
	SetThrusterResource(th_rcsSM[4], NULL);
	SetThrusterResource(th_rcsSM[5], NULL);
	SetThrusterResource(th_rcsSM[6], NULL);
	SetThrusterResource(th_rcsSM[7], NULL);
	SetThrusterResource(th_rcsSM[8], NULL);
	SetThrusterResource(th_rcsSM[9], NULL);
	SetThrusterResource(th_rcsSM[10], NULL);
	SetThrusterResource(th_rcsSM[11], NULL);
	SetThrusterResource(th_rcsSM[12], NULL);
	SetThrusterResource(th_rcsSM[13], NULL);
	SetThrusterResource(th_rcsSM[14], NULL);
	SetThrusterResource(th_rcsSM[15], NULL);
	SetThrusterResource(th_main, NULL);
return 1;
}

void PhoenixASMN::RevertChutes (void)
{
	ChuteStatus = ((ChuteStatus == OPENED || ChuteStatus == OPENING) ?
CLOSING : OPENING);
}

double PhoenixASMN::Chutesclose ()
{
ClearAirfoilDefinitions();
if (Chutes == 1)
		{
RevertChutes();
		strcpy(SendHudMessage(),"Splashdown! Chutes stowing");
	}
else
		{
	strcpy(SendHudMessage(),"Opening parachutes highly recommended when falling towards water at high velocity");
	}
return true;
}

double PhoenixASMN::Chutesopen ()
{
	RevertChutes();
	strcpy(SendHudMessage(),"Chutes open");
	ClearAirfoilDefinitions();
	CreateAirfoil (LIFT_VERTICAL, _V(0.0,0.0,22.0), Parachute_MomentCoeff,  0.04, 2600, 0.05);
return true;
}

double PhoenixASMN::MeshControl ()
{

ClearMeshes();
	if (SMJett == 1)
	{
SetMeshVisibilityMode (AddMesh (PhoenixCapsule = oapiLoadMeshGlobal ("PhoenixAoffset")), MESHVIS_ALWAYS);
SetMeshVisibilityMode (AddMesh (PhoenixCapsule = oapiLoadMeshGlobal ("PhoenixSMN MKII")), MESHVIS_ALWAYS);
SetMeshVisibilityMode (AddMesh (PhoenixCapsule = oapiLoadMeshGlobal ("PhoenixLES")), MESHVIS_ALWAYS);
return 1;
	}

	else
	{
SetMeshVisibilityMode (AddMesh (PhoenixCapsule = oapiLoadMeshGlobal ("PhoenixA")), MESHVIS_ALWAYS);
	if (Chutes == 1)
	{
SetMeshVisibilityMode (AddMesh (PhoenixCapsule = oapiLoadMeshGlobal ("PhoenixChutesMkI")), MESHVIS_ALWAYS);
	}
	
return 1;
	}
return 1;
}

// PhoenixSMN MKII

// 6.214

double PhoenixASMN::ClassControl ()
{

	ClearDockDefinitions ();

	if (SMJett == 1)
	{
	SetPMI (EXP_PMI_BEFORE_SMJETT);
	SetSize (EXP_SIZE_BEFORE_SMJETT);
	SetCrossSections (EXP_CS_BEFORE_SMJETT);
	SetTouchdownPoints (_V(0,-2,5.064), _V(-2,2,5.064), _V(2,2,5.064));
	SetCameraOffset (_V(0,1.707,6.753));
	Crew.DefineAirLockShape(TRUE,-3,-1.222,-1.700,1.700, 5.464,8.714);
	Crew.SetMembersPosRotOnEVA(_V(-2.180,0,7.123),_V(0,-225,0));
	Dock0 = CreateDock(_V(0,0,8.241),_V(0,0,1),_V(0,1,0));

	//SetThrusterResource(th_rcsSM[0], RCS5);
	//SetThrusterResource(th_rcsSM[1], RCS5);
	//SetThrusterResource(th_rcsSM[2], RCS5);
	//SetThrusterResource(th_rcsSM[3], RCS5);
	//SetThrusterResource(th_rcsSM[4], RCS6);
	//SetThrusterResource(th_rcsSM[5], RCS6);
	//SetThrusterResource(th_rcsSM[6], RCS6);
	//SetThrusterResource(th_rcsSM[7], RCS6);
	//SetThrusterResource(th_rcsSM[8], RCS7);
	//SetThrusterResource(th_rcsSM[9], RCS7);
	//SetThrusterResource(th_rcsSM[10], RCS7);
	//SetThrusterResource(th_rcsSM[11], RCS7);
	//SetThrusterResource(th_rcsSM[12], RCS8);
	//SetThrusterResource(th_rcsSM[13], RCS8);
	//SetThrusterResource(th_rcsSM[14], RCS8);
	//SetThrusterResource(th_rcsSM[15], RCS8);

	return 1;
	}

	if (SMJett == 0)
	{
	SetPMI (EXP_PMI_AFTER_SMJETT);
	SetSize (EXP_SIZE_AFTER_SMJETT);
	SetCrossSections (EXP_CS_AFTER_SMJETT);
	SetTouchdownPoints (_V(0,-2,-1.145), _V(-2,2,-1.145), _V(2,2,-1.145));
	SetCameraOffset (_V(0,1.707,0.539));
	Crew.DefineAirLockShape(TRUE,-3,-1.222,-1.700,1.700, -0.75,2.50);
	Crew.SetMembersPosRotOnEVA(_V(-2.180,0,0.909),_V(0,-225,0));
	Dock0 = CreateDock(_V(0,0,2.027),_V(0,0,1),_V(0,1,0));

	DelPropellantResource (MainFuel);
	DelPropellantResource (RCS5);
	DelPropellantResource (RCS6);
	DelPropellantResource (RCS7);
	DelPropellantResource (RCS8);

	SetThrusterResource(th_rcsCM[0], RCS1);
	SetThrusterResource(th_rcsCM[1], RCS1);
	SetThrusterResource(th_rcsCM[2], RCS3);
	SetThrusterResource(th_rcsCM[3], RCS3);
	SetThrusterResource(th_rcsCM[4], RCS2);
	SetThrusterResource(th_rcsCM[5], RCS2);
	SetThrusterResource(th_rcsCM[6], RCS4);
	SetThrusterResource(th_rcsCM[7], RCS4);
	SetThrusterResource(th_rcsCM[8], RCS3);
	SetThrusterResource(th_rcsCM[9], RCS3);
	SetThrusterResource(th_rcsCM[10], RCS4);
	SetThrusterResource(th_rcsCM[11], RCS4);

		if (Chutes == 1)
	{

	SetPMI (EXP_PMI_AFTER_CHUTESOPEN);
	SetSize (EXP_SIZE_AFTER_CHUTESOPEN);
	SetCrossSections (EXP_CS_AFTER_CHUTESOPEN);
	SetRotDrag(_V(5.5,5.5,10.3));

	Para == 1;

	//ClearVariableDragElements ();
	//CreateVariableDragElement (&Para, 2600,_V(0,0,22));
	}

	return 1;
	}

return 1;
}

//=========================================================
// Vessel Capabilities
// This is what you might consider the core of the addon. In clbkSetClassCaps, all of the core information about the way a vessel behaves
// as a physics object is declared. This includes empty mass, PMI (a measure of the dynamics involved in rotating the vessel), cross-sections,
// Albedo (the colour of the white dot when you zoom out), gear friction coefficients, thrusters & engines, the size of the vessel,
// & of course its mesh (what it looks like). Also included here in this addon are the UMMU & UCGO calls which specify how the vessel uses
// those libraries. They are fairly self-explanatory, so I wont go into detail on them here.
//=========================================================
void PhoenixASMN::clbkSetClassCaps (FILEHANDLE cfg)
{
	Crew.InitUmmu(GetHandle());	
	float UMmuVersion=Crew.GetUserUMmuVersion();
	Crew.SetMaxSeatAvailableInShip(3);

	Crew.DeclareActionArea(0,_V(-2.180,0,7.123),2.0,TRUE,"action_activated.wav","Airlock Activated");
	iActionAreaDemoStep=0;	// this is just to show a feature of action area, see below "DetectActionAreaActivated"

	SelectedUmmuMember =0;  // our current selected member

	//CreateVariableDragElement (&Para, 2600,_V(0,0,22));

	// 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. Press E to EVA, 1/2 to select crew, A to Open/Close airlock, 0 or 8 for info, and M to add crew.");

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

	cCargoHudDisplay[0]=0;						// Cargo hud display char variable
	dCargHudMessageDelay=0;						// Cargo hud display delay

	cCargo2HudDisplay[0]=0;						// Cargo hud display char variable
	dCarg2HudMessageDelay=0;						// Cargo hud display delay

	cCargo3HudDisplay[0]=0;						// Cargo hud display char variable
	dCarg3HudMessageDelay=0;						// Cargo hud display delay


	SetCameraOffset (_V(0,1.707,6.753));
	SetAlbedoRGB (_V(1,1,1));

	MeshControl ();

	SetSurfaceFrictionCoeff (0.88, 0.88);
	SetRotDrag (_V(0.9, 0.76, 0.2));

	EnableTransponder (true);
	InitNavRadios (4);


	// propellant resources
	MainFuel = CreatePropellantResource (EXP_MAINFUELMASS);
	RCS5 = CreatePropellantResource (EXP_RCS5FUELMASS);
	RCS6 = CreatePropellantResource (EXP_RCS6FUELMASS);
	RCS7 = CreatePropellantResource (EXP_RCS7FUELMASS);
	RCS8 = CreatePropellantResource (EXP_RCS8FUELMASS);

	RCS1 = CreatePropellantResource (EXP_RCS1FUELMASS);
	RCS2 = CreatePropellantResource (EXP_RCS2FUELMASS);
	RCS3 = CreatePropellantResource (EXP_RCS3FUELMASS);
	RCS4 = CreatePropellantResource (EXP_RCS4FUELMASS);

	// Service Module RCS engines

		// main engine
	th_main = CreateThruster (_V(0,0,-10.61), _V(0,0,1), MAINTH, MainFuel, VACNTR_ISP, NMLNTR_ISP, P_NML);
	CreateThrusterGroup (&th_main, 1, THGROUP_MAIN);
	SURFHANDLE texmain = oapiRegisterExhaustTexture ("ShuttleDMainExhaust");
	AddExhaust (th_main, 1.99, 0.80, _V(0,0,-10.61), _V(0,0,-4.1), texmain);

	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,-10.61), &contrail_main);
	AddExhaustStream (th_main, _V(0,0.13,-10.61), &exhaust_main);


	// RCS engines
	th_rcsSM[0] = CreateThruster (_V(-2.353,0.325, 0.357), _V(0,0,-1), RCSSMTH0, RCS5,  VACRCS_ISP, NMLRCS_ISP, P_NML);//LEFT QUAD FORWARD
	th_rcsSM[1] = CreateThruster (_V(-2.353,0.672, 0.000), _V(0,-1,0), RCSSMTH1, RCS5,  VACRCS_ISP, NMLRCS_ISP, P_NML);//LEFT QUAD UP
	th_rcsSM[2] = CreateThruster (_V(-2.353,0.000, 0.000), _V(0,1,0), RCSSMTH2, RCS5,  VACRCS_ISP, NMLRCS_ISP, P_NML);//LEFT QUAD DOWN
	th_rcsSM[3] = CreateThruster (_V(-2.353,0.325,-0.365), _V(0,0,1), RCSSMTH3, RCS5,  VACRCS_ISP, NMLRCS_ISP, P_NML);//LEFT QUAD AFT

	th_rcsSM[4] = CreateThruster (_V( 2.353,0.325, 0.357), _V(0,0,-1), RCSSMTH4, RCS6,  VACRCS_ISP, NMLRCS_ISP, P_NML);//RIGHT QUAD FORWARD
	th_rcsSM[5] = CreateThruster (_V( 2.353,0.672, 0.000), _V(0,-1,0), RCSSMTH5, RCS6,  VACRCS_ISP, NMLRCS_ISP, P_NML);//RIGHT QUAD UP
	th_rcsSM[6] = CreateThruster (_V( 2.353,0.000, 0.000), _V(0,1,0), RCSSMTH6, RCS6,  VACRCS_ISP, NMLRCS_ISP, P_NML);//RIGHT DOWN
	th_rcsSM[7] = CreateThruster (_V( 2.353,0.325,-0.365), _V(0,0,1), RCSSMTH7, RCS6,  VACRCS_ISP, NMLRCS_ISP, P_NML);//RIGHT AFT

	th_rcsSM[8] = CreateThruster (_V( 0.000,-2.272, 0.357), _V(0,0,-1), RCSSMTH8, RCS7,  VACRCS_ISP, NMLRCS_ISP, P_NML);//BOTTOM QUAD FORWARD
	th_rcsSM[9] = CreateThruster (_V( 0.000,-2.272,-0.336), _V(1,0,0), RCSSMTH9, RCS7,  VACRCS_ISP, NMLRCS_ISP, P_NML);//BOTTOM QUAD LEFT
	th_rcsSM[10] = CreateThruster(_V(-0.311,-2.272, 0.000), _V(-1,0,0), RCSSMTH10, RCS7,  VACRCS_ISP, NMLRCS_ISP, P_NML);//BOTTOM QUAD RIGHT
	th_rcsSM[11] = CreateThruster(_V( 0.311,-2.272, 0.000), _V(0,0,1), RCSSMTH11, RCS7,  VACRCS_ISP, NMLRCS_ISP, P_NML);//BOTTOM AFT

	th_rcsSM[12] = CreateThruster (_V( 0.000,2.259, 0.357), _V(0,0,-1), RCSSMTH12, RCS8,  VACRCS_ISP, NMLRCS_ISP, P_NML);//TOP QUAD FORWARD
	th_rcsSM[13] = CreateThruster (_V(0.325,2.281, 0.000), _V(1,0,0), RCSSMTH13, RCS8,  VACRCS_ISP, NMLRCS_ISP, P_NML);//TOP QUAD LEFT
	th_rcsSM[14] = CreateThruster(_V(-0.325,2.281, 0.000), _V(-1,0,0), RCSSMTH14, RCS8,  VACRCS_ISP, NMLRCS_ISP, P_NML);//TOP QUAD RIGHT
	th_rcsSM[15] = CreateThruster(_V( 0.000,2.259,-0.336), _V(0,0,1), RCSSMTH15, RCS8,  VACRCS_ISP, NMLRCS_ISP, P_NML);//TOP AFT

	SURFHANDLE texH2O2RCS = oapiRegisterExhaustTexture ("exhaust_atrcsShuttleD");

	AddExhaust (th_rcsSM[0], 1.9, 0.278, _V(-2.353,0.325, 0.357), _V(0,0,1), texH2O2RCS);
	AddExhaust (th_rcsSM[1], 1.9, 0.278, _V(-2.353,0.672, 0.000), _V(0,1,0), texH2O2RCS);
	AddExhaust (th_rcsSM[2], 1.9, 0.278, _V(-2.353,0.000, 0.000), _V(0,-1,0), texH2O2RCS);
	AddExhaust (th_rcsSM[3], 1.9, 0.278, _V(-2.353,0.325,-0.365), _V(0,0,-1), texH2O2RCS);

	AddExhaust (th_rcsSM[4], 1.9, 0.278, _V( 2.353,0.325, 0.357), _V(0,0,1), texH2O2RCS);
	AddExhaust (th_rcsSM[5], 1.9, 0.278, _V( 2.353,0.672, 0.000), _V(0,1,0), texH2O2RCS);
	AddExhaust (th_rcsSM[6], 1.9, 0.278, _V( 2.353,0.000, 0.000), _V(0,-1,0), texH2O2RCS);
	AddExhaust (th_rcsSM[7], 1.9, 0.278, _V( 2.353,0.325,-0.365), _V(0,0,-1), texH2O2RCS);

	AddExhaust (th_rcsSM[8], 1.9, 0.278, _V( 0.000,-2.272, 0.357), _V(0,0,1), texH2O2RCS);
	AddExhaust (th_rcsSM[9], 1.9, 0.278, _V(-0.311,-2.272,0.000), _V(-1,0,0), texH2O2RCS);
	AddExhaust (th_rcsSM[10], 1.9, 0.278, _V( 0.311,-2.272,0.000), _V(1,0,0), texH2O2RCS);
	AddExhaust (th_rcsSM[11], 1.9, 0.278, _V( 0.000,-2.272,-0.336), _V(0,0,-1), texH2O2RCS);

	AddExhaust (th_rcsSM[12], 1.9, 0.278, _V( 0.000,2.259, 0.357), _V(0,0,1), texH2O2RCS);
	AddExhaust (th_rcsSM[13], 1.9, 0.278, _V(	-0.325,2.281, 0.000), _V(-1,0,0), texH2O2RCS);
	AddExhaust (th_rcsSM[14], 1.9, 0.278, _V( 0.325,2.281, 0.000), _V(1,0,0), texH2O2RCS);
	AddExhaust (th_rcsSM[15], 1.9, 0.278, _V( 0.000,2.259,-0.336), _V(0,0,-1), texH2O2RCS);

	// Capsule RCS engines
	th_rcsCM[0] = CreateThruster (_V( 0.065,2.146, -0.400), _V(0,-1,-1), RCSTH0, NULL,  VACRCS_ISP, NMLRCS_ISP, P_NML);//TOP SIDE FORWARD A
	th_rcsCM[1] = CreateThruster (_V( -0.065,2.146,-0.400), _V(0,-1,-1), RCSTH1, NULL,  VACRCS_ISP, NMLRCS_ISP, P_NML);//TOP SIDE FORWARD B
	th_rcsCM[2] = CreateThruster (_V( 0.220,2.200,-0.487), _V(-1,0,0), RCSTH4, NULL,  VACRCS_ISP, NMLRCS_ISP, P_NML);//TOP SIDE LEFT
	th_rcsCM[3] = CreateThruster (_V(-0.220,2.200,-0.487), _V(1,0,0), RCSTH5, NULL,  VACRCS_ISP, NMLRCS_ISP, P_NML);//TOP SIDE RIGHT

	th_rcsCM[4] = CreateThruster (_V( 0.065,-2.185, -0.407), _V(0,1,-1), RCSTH2, NULL,  VACRCS_ISP, NMLRCS_ISP, P_NML);//BOTTOM SIDE FORWARD A
	th_rcsCM[5] = CreateThruster (_V( -0.065,-2.185,-0.407), _V(0,1,-1), RCSTH3, NULL,  VACRCS_ISP, NMLRCS_ISP, P_NML);//BOTTOM SIDE FORWARD B
	th_rcsCM[6] = CreateThruster (_V( 0.220,-2.200,-0.487), _V(-1,0,0), RCSTH8, NULL,  VACRCS_ISP, NMLRCS_ISP, P_NML);//BOTTOM SIDE LEFT
	th_rcsCM[7] = CreateThruster (_V( -0.220,-2.200,-0.487), _V(1,0,0), RCSTH9, NULL,  VACRCS_ISP, NMLRCS_ISP, P_NML);//BOTTOM SIDE RIGHT


	th_rcsCM[8] = CreateThruster (_V(2.186,-0.221,-0.487), _V(-1,0,-1), RCSTH6, NULL,  VACRCS_ISP, NMLRCS_ISP, P_NML);//RIGHT SIDE FORWARD A
	th_rcsCM[9] = CreateThruster (_V(2.186,0.075,-0.487), _V(-1,0,-1), RCSTH7, NULL,  VACRCS_ISP, NMLRCS_ISP, P_NML);//RIGHT SIDE FORWARD B

	th_rcsCM[10] = CreateThruster (_V(-2.186,-0.221,-0.487), _V(1,0,-1), RCSTH10, NULL,  VACRCS_ISP, NMLRCS_ISP, P_NML);//LEFT SIDE FORWARD B
	th_rcsCM[11] = CreateThruster (_V(-2.186,0.075,-0.487), _V(1,0,-1), RCSTH11, NULL,  VACRCS_ISP, NMLRCS_ISP, P_NML);//LEFT SIDE FORWARD B

	AddExhaust (th_rcsCM[0], 1.9, 0.278, _V( 0.065,2.146, -0.400), _V(0,1,1), texH2O2RCS);
	AddExhaust (th_rcsCM[1], 1.9, 0.278, _V( -0.065,2.146,-0.400), _V(0,1,1), texH2O2RCS);
	AddExhaust (th_rcsCM[2], 1.9, 0.278, _V( 0.220,2.200,-0.487), _V(1,0,0), texH2O2RCS);
	AddExhaust (th_rcsCM[3], 1.9, 0.278, _V(-0.220,2.200,-0.487), _V(-1,0,0), texH2O2RCS);

	AddExhaust (th_rcsCM[4], 1.9,  0.278, _V( 0.065,-2.185, -0.407), _V(0,-1,1), texH2O2RCS);
	AddExhaust (th_rcsCM[5], 1.9,  0.278, _V( -0.065,-2.185,-0.407), _V(0,-1,1), texH2O2RCS);
	AddExhaust (th_rcsCM[6], 1.9, 0.278, _V( 0.220,-2.200,-0.487), _V(1,0,0), texH2O2RCS);
	AddExhaust (th_rcsCM[7], 1.9, 0.278, _V( -0.220,-2.200,-0.487), _V(-1,0,0), texH2O2RCS);

	AddExhaust (th_rcsCM[8], 1.9,  0.278, _V(2.186,-0.221,-0.487), _V(1,0,1), texH2O2RCS);
	AddExhaust (th_rcsCM[9], 1.9,  0.278, _V(2.186,0.075,-0.487), _V(1,0,1), texH2O2RCS);

	AddExhaust (th_rcsCM[10], 1.9,  0.278, _V(-2.186,-0.221,-0.487), _V(-1,0,1), texH2O2RCS);
	AddExhaust (th_rcsCM[11], 1.9,  0.278, _V(-2.186,0.075,-0.487), _V(-1,0,1), texH2O2RCS);


	th_group[0] = th_rcsCM[0];
	th_group[1] = th_rcsCM[1];
	th_group[2] = th_rcsSM[11];
	th_group[3] = th_rcsSM[12];
	CreateThrusterGroup (th_group, 4, THGROUP_ATT_PITCHUP);

	th_group[0] = th_rcsCM[4];
	th_group[1] = th_rcsCM[5];
	th_group[2] = th_rcsSM[8];
	th_group[3] = th_rcsSM[15];
	CreateThrusterGroup (th_group, 4, THGROUP_ATT_PITCHDOWN);

	th_group[0] = th_rcsCM[2];
	th_group[1] = th_rcsCM[7];
	th_group[2] = th_rcsSM[1];
	th_group[3] = th_rcsSM[6];
	th_group[4] = th_rcsSM[9];
	th_group[5] = th_rcsSM[14];
	CreateThrusterGroup (th_group, 6, THGROUP_ATT_BANKLEFT);

	th_group[0] = th_rcsCM[3];
	th_group[1] = th_rcsCM[6];
	th_group[2] = th_rcsSM[2];
	th_group[3] = th_rcsSM[5];
	th_group[4] = th_rcsSM[10];
	th_group[5] = th_rcsSM[13];
	CreateThrusterGroup (th_group, 6, THGROUP_ATT_BANKRIGHT);

	th_group[0] = th_rcsSM[2];
	th_group[1] = th_rcsSM[6];
	CreateThrusterGroup (th_group, 2, THGROUP_ATT_UP);

	th_group[0] = th_rcsSM[1];
	th_group[1] = th_rcsSM[5];
	CreateThrusterGroup (th_group, 2, THGROUP_ATT_DOWN);

	th_group[0] = th_rcsCM[10];
	th_group[1] = th_rcsCM[11];
	th_group[2] = th_rcsSM[0];
	th_group[3] = th_rcsSM[7];
	CreateThrusterGroup (th_group, 4, THGROUP_ATT_YAWLEFT);

	th_group[0] = th_rcsCM[8];
	th_group[1] = th_rcsCM[9];
	th_group[2] = th_rcsSM[3];
	th_group[3] = th_rcsSM[4];
	CreateThrusterGroup (th_group, 4, THGROUP_ATT_YAWRIGHT);

	th_group[0] = th_rcsCM[2];
	th_group[1] = th_rcsCM[6];
	th_group[2] = th_rcsSM[10];
	th_group[3] = th_rcsSM[14];
	CreateThrusterGroup (th_group, 4, THGROUP_ATT_LEFT);

	th_group[0] = th_rcsCM[3];
	th_group[1] = th_rcsCM[7];
	th_group[2] = th_rcsSM[9];
	th_group[3] = th_rcsSM[13];
	CreateThrusterGroup (th_group, 4, THGROUP_ATT_RIGHT);

	th_group[0] = th_rcsSM[3];
	th_group[1] = th_rcsSM[7];
	th_group[2] = th_rcsSM[11];
	th_group[3] = th_rcsSM[15];
	CreateThrusterGroup (th_group, 4, THGROUP_ATT_FORWARD);

	th_group[0] = th_rcsSM[0];
	th_group[1] = th_rcsSM[4];
	th_group[2] = th_rcsSM[8];
	th_group[3] = th_rcsSM[12];
	CreateThrusterGroup (th_group, 4, THGROUP_ATT_BACK);

}

//=========================================================
// clbkDrawHUD
// This code helps in drawing the custom hud displays that UMMU & UCGO use to send messages. All I really know about this at this point is that in
//   5,hps->H/60*25,cUmmuHudDisplay 
// 60 & 25 appear to change where the text appears on the display.
//=========================================================

bool PhoenixASMN::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*20,cCargoHudDisplay,strlen(cCargoHudDisplay));
		dCargHudMessageDelay-=oapiGetSimStep();
		if(dCargHudMessageDelay<0)
			dCargHudMessageDelay=0;
	}
		// UCGO display messages
	if(dCarg2HudMessageDelay>0)
	{
		skp->Text(5,hps->H/60*22.5,cCargo2HudDisplay,strlen(cCargo2HudDisplay));
		dCarg2HudMessageDelay-=oapiGetSimStep();
		if(dCarg2HudMessageDelay<0)
			dCarg2HudMessageDelay=0;
	}
		// UCGO display messages
	if(dCarg3HudMessageDelay>0)
	{
		skp->Text(5,hps->H/60*17.5,cCargo3HudDisplay,strlen(cCargo3HudDisplay));
		dCarg3HudMessageDelay-=oapiGetSimStep();
		if(dCarg3HudMessageDelay<0)
			dCarg3HudMessageDelay=0;
	}

	return true; 
}

//=========================================================
// clbkLoadVC
// This is where most code for the VC is added. oapiVCRegisterMFD & VCHUDSPEC are used to "create" the MFDs and the Heads-up display. After that,
// the code is subdivided into "case" sections, each one representing a different camera view in the virtual cockpit. The key to switching between these
// is the oapiVCSetNeighbours (a, b, c, d) function. All you need to do is remember a=left, b=right, c=up, d=down, and place the id # of the campos you
// want to switch to in place of that letter when the user its ctrl-directional arrow. -1 specifies a null value (camera wont move) and thats about all
// you need to know to have multiple VC camera points.
//=========================================================

bool PhoenixASMN::clbkLoadVC (int id)
{

	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).

		//SetCameraOffset (_V(0+(0.8*sin(Randomizer)),1.707+(0.8*sin(Randomizer)),6.753));
		SetCameraRotationRange (RAD*120, RAD*120, RAD*180, RAD*10); 
		SetCameraShiftRange (_V(0,0.1,0), _V(-0.7,0,0), _V(0.7,0,0));
		return true;
}


char *PhoenixASMN::SendHudMessage() //<---- Change the class name here
{
	dHudMessageDelay=15;
	return cUmmuHudDisplay;
}


//=========================================================
// clbkLoadStateEx
// I would like to dedicate this as the Face function, lol. A big thanks to Face who helped me fix this part of the code when it wasnt written properly,
// and was causing me a lot of grief. The key thing to remember here and in clbkSaveState is that when custom variables (data about your ship) gets saved
// it gets a line in the SCN file. In say,
//
//		if (!_strnicmp (line, "O2Tank", 6)) {
//			sscanf (line+6, "%lf", &O2Tank);
//		}
//
// The number 6 refers to the number of characters in O2Tank - 6. This is the length of the id string, NOT how many lines it has to slip down in the
// scn file.
//=========================================================
void PhoenixASMN::clbkLoadStateEx (FILEHANDLE scn, void *status)
{
	char *line;
	while (oapiReadScenario_nextline (scn, line)) 
	{

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

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

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

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

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

		ParseScenarioLineEx (line, status);
	}

}

//=========================================================
// clbkSaveState
// Nothing too exciting here, just the same rules as above, but it is worth noting that in "%d %0.4f", the d & f appear to specify
// the data type being saved. In other words, the specifier "%d" or "%0.4f" will determine how many zeroes get written to the SCN, &
// as a result remembered.
//=========================================================

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

	VESSEL3::clbkSaveState (scn);

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

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

	sprintf (cbuf, "%d", SMJett);
	oapiWriteScenario_string (scn, "SMJett", cbuf);

	sprintf (cbuf, "%d", Chutes);
	oapiWriteScenario_string (scn, "Chutes", cbuf);

	Crew.SaveAllMembersInOrbiterScenarios(scn);

}

//=========================================================
// SendCargHudMessage
// Another UCGO specific function, which you would think would be related to the hud.
//=========================================================

char *PhoenixASMN::SendCargHudMessage(void)
{
	dCargHudMessageDelay=15; // 15 seconds display delay for msg
	return cCargoHudDisplay;
}

char *PhoenixASMN::SendCarg2HudMessage(void)
{
	dCarg2HudMessageDelay=15; // 15 seconds display delay for msg
	return cCargo2HudDisplay;
}

char *PhoenixASMN::SendCarg3HudMessage(void)
{
	dCarg3HudMessageDelay=15; // 15 seconds display delay for msg
	return cCargo3HudDisplay;
}

//=========================================================
// clbkPostStep
// This is the step-to-step, always-in-motion part of the code during an Orbiter simulation. Orbiter does physics caculations every timestep,
// and as a result, interesting things can be done here like constant updating of variables, the nuts & bolts that drive the animations up & down,
// as well as functions to kill the crew when crashing or running out of air. I wont go into great detail on what I have in here, but this tends to be
// the exciting part of the code. This is where things happen!
//=========================================================

void PhoenixASMN::clbkPostStep(double simt, double simdt, double mjd)
{

SetEmptyMass(UpdateMass());

	int ReturnCode=Crew.ProcessUniversalMMu();
	switch(ReturnCode)
	{
	case UMMU_TRANSFERED_TO_OUR_SHIP: 
		sprintf(SendHudMessage(),"%s \"%s\" transfered to %s",
			Crew.GetCrewMiscIdByName(Crew.GetLastEnteredCrewName()),Crew.GetLastEnteredCrewName()
			,GetName());
		break;
	case UMMU_RETURNED_TO_OUR_SHIP:
		sprintf(SendHudMessage(),"%s \"%s\" ingressed %s",
			Crew.GetCrewMiscIdByName(Crew.GetLastEnteredCrewName()),
			Crew.GetLastEnteredCrewName(),GetName());
		break;
	}

		int ActionAreaReturnCode=Crew.DetectActionAreaActivated();
	if(ActionAreaReturnCode>-1)
	{
		if(ActionAreaReturnCode==0)
		{
		// switch state
		Crew.SetAirlockDoorState(!Crew.GetAirlockDoorState());
		// display state
		if(Crew.GetAirlockDoorState()==TRUE)
			strcpy(SendHudMessage(),"Airlock open");	
		else
			strcpy(SendHudMessage(),"Airlock closed");	
		}
	}

		if (ChuteStatus >= OPENING) {				// For all of the complexity involved in writing it, all this does is to make sure the animation variable
		double da = simdt * PARACHUTE_SPEED;   // slides back & forth when asked to.
		if (ChuteStatus == OPENING) {
			if (Para > 0.0) Para = max (0.0, Para-da);
			else                ChuteStatus = OPENED;
		} else {
			if (Para < 1.0) Para = min (1.0, Para+da);
			else                ChuteStatus = STORED;
		}

	}

	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(),"Crashed into terrain");
		}
	}

		// Detect Atmospheric Entry-Function Courtesy of Hlynkacg
	if ( (GetDynPressure() > 300000) ) // It's about to get very hot in here...
	{
			int I;
			for(I=0;I<Crew.GetCrewTotalNumber();I++)
			{
				Crew.SetCrewMemberPulseBySlotNumber(I,0);	// set cardiac pulse to zero
			}
			strcpy(SendHudMessage(),"Hull Breach");
	}


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

{
	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(),"O2 Main Tank empty-All crew dead");
}

}



{

{
	if (Water>0)
	{
	Water = (Water - WaterConsumption*simdt);
	}
	else 
	{
	Water=0;
	}
}
	int I;
	if(Water == 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(),"Water Reserves empty-All crew dead");
}

}

	{


			sprintf(SendCargHudMessage(),"Current altitude  %.0f meters",
				AltitudeCheck());

			//sprintf(SendCarg2HudMessage(),"Current velocity  %.0f meters/second",
			//	VelocityCheck());

			sprintf(SendCarg2HudMessage(),"Current velocity  %.0f meters/second",
				ParaCheck());

			sprintf(SendCarg3HudMessage(),"Water reserves %.0f L, %.0f kg Oxygen remaining",
				WaterCheck (),O2Check ());


	}

if (simt<1)
{
	MeshControl ();
	ClassControl ();
}

		if (Chutes == 1)
	{

		if(GroundContact()==TRUE)
		{
			if (Chutes == 1);
			Chutes--;
			MeshControl ();
			ClassControl ();
			Chutesclose ();
		}

		
	}

	//ClearVariableDragElements ();
	CreateVariableDragElement (&Para, 2600,_V(0,0,22));


		Randomizer = (log(cos(sin(simdt*0.333))));

		AddUMmuToVessel();

		Crew.WarnUserUMMUNotInstalled("Phoenix");
		// At the very end of clbkPostStep or clbkPreStep
}


//=========================================================
// clbkConsumeBufferedKey
// Another important function, this particular section is used to execute functions whenever the Orbiter application detects a given keystroke by a user.
// Really not very complicated (usually), very similar to clbkVCMouseEvent. The ony complicated part is getting the structure right, as calls specific
// to a ctrl-keypress or shift-keypress have to be grouped under a separate heading. Best example of that will be under the Hubble Space Telescope sample
// also in the OrbiterSDK directory.
//=========================================================

int PhoenixASMN::clbkConsumeBufferedKey (DWORD key, bool down, char *kstate)
{

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

	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(),"%s transfered through main hatch",
				Crew.GetLastEvaedCrewName());SelectedUmmuMember=0;
			break;
		case EVA_OK:
			sprintf(SendHudMessage(),"%s on EVA",
				Crew.GetLastEvaedCrewName());SelectedUmmuMember=0;
			break;
		case ERROR_AIRLOCK_CLOSED:
			strcpy(SendHudMessage(),"Airlock closed. press A to open");
			break;
		case ERROR_DOCKED_SHIP_HAVE_AIRLOCK_CLOSED:
			strcpy(SendHudMessage(),"Docked vessel airlock closed");
			break;
		case ERROR_CREW_MEMBER_NOT_FOUND:
			strcpy(SendHudMessage(),"No crew by this name aboard");
			break;
		case ERROR_DOCKEDSHIP_DONOT_USE_UMMU:
			strcpy(SendHudMessage(),"Docked ship is not compatible with UMmu 2.0");
			break;
		case ERROR_MISC_ERROR_EVAFAILED:
			strcpy(SendHudMessage(),"Misc error with UMMU. Please reinstall");
			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(),"No crew aboard");	
			return 1;
		}

		// we test that we select existing member
		if(SelectedUmmuMember<Crew.GetCrewTotalNumber()-1)
			SelectedUmmuMember++;
		char * Name=Crew.GetCrewNameBySlotNumber(SelectedUmmuMember);
		sprintf(SendHudMessage(),"%i  %s \"%s\"Selected for EVA or Transfer",
			SelectedUmmuMember,Crew.GetCrewMiscIdBySlotNumber(SelectedUmmuMember),
			Name);
		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(),"No crew aboard");	
			return 1;
		}
		if(SelectedUmmuMember>0)
			SelectedUmmuMember--;
		char * Name=Crew.GetCrewNameBySlotNumber(SelectedUmmuMember);
		sprintf(SendHudMessage(),"Slot %i %s \"%s\" Selected for EVA or Transfer"
			", please press \"E\" to EVA",SelectedUmmuMember,
			Crew.GetCrewMiscIdBySlotNumber(SelectedUmmuMember),Name);
		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 open");	
		else
			strcpy(SendHudMessage(),"Airlock closed");	
		return 1;
	}

	//---------------------------------------------------------------------------
	// Get some infos Name of ship and total soul aboard
	if(key==OAPI_KEY_0)
	{
		sprintf(SendHudMessage(),"%i crew aboard %s",
			Crew.GetCrewTotalNumber(),GetName());
		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);
	}

		// THIS IS FOR ADDING CREW SEE PDF doc "Allow user to add crew to your ship 
	// without scenery editor"
	if(key==OAPI_KEY_N&&!KEYMOD_SHIFT(kstate)&&!KEYMOD_CONTROL (kstate))
	{
		RevertChutes ();
	}

	//---------------------------------------------------------------------------
	// Key "K" Deploy the parachutes
	if(key==OAPI_KEY_K)
	{

		if (SMJett == 0)
	{
	
		if (Chutes == 0)
		{
	Chutes++;
	Chutesopen ();
	MeshControl ();
	ClassControl ();
		}

	}
		return 0;
	}

	//---------------------------------------------------------------------------
	// Key "J" Jettison the service module
	if(key==OAPI_KEY_J&&!KEYMOD_SHIFT(kstate)&&!KEYMOD_CONTROL (kstate))

	if (SMJett == 1)
	{
	SMJettison();
	}

	else
	{
	MeshControl ();
	ClassControl ();
	}

return 0;
}

//=========================================================
// UMmuCrewAddCallback & AddUMmuToVessel
// Again, a Dansteph creation, so I dont know a great deal about it, but its used in adding crew directly to the ship without entering through the main
// hatch. Fairly usefull, Id say.
//=========================================================

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 PhoenixASMN::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 member name (or hit escape to cancel)",UMmuCrewAddCallback,0,30,(void*)cAddUMmuToVessel);
	}
	else if(cAddUMmuToVessel[0]==3){
		cAddUMmuToVessel[0]=4;
		oapiOpenInputBox ("Enter age",UMmuCrewAddCallback,0,30,(void*)cAddUMmuToVessel);
	}
	else if(cAddUMmuToVessel[0]==5){
		cAddUMmuToVessel[0]=6;
		oapiOpenInputBox ("Enter Crew ID - 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(),"\"%s\" aged %i added to vessel",&cAddUMmuToVessel[2],Age);
		}
		else{
			strcpy(SendHudMessage(),"Unable to add crew");
		}
	}
}



//=========================================================
// Load and Delete Module Stuff
// Apparenty used to load & delete special classes in the module. If theyre not deleted properly in ExitModule, they cause what I believe is called a
// memory leak, not good. So always remember to clean up after yourself!
//=========================================================
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
// Appears similar to the part above, only I think its involved when creating or deleting vessels via the scenario editor.
//=========================================================
DLLCLBK VESSEL *ovcInit (OBJHANDLE hvessel, int flightmodel)
{
	return new PhoenixASMN (hvessel, flightmodel);
}

DLLCLBK void ovcExit (VESSEL *vessel)
{
	if (vessel)
		delete (PhoenixASMN*)vessel;
}

//=========================================================
// clbkPostCreation
// This is usually Orbitersound territory. Im not terribly familiar with how it works in 3.5 or 4.0, so I wont say much here. Better just to look
// up Dantephs tutoials in the Orbitersound docs. He can explain a lot of things better than me ;)
//=========================================================

void PhoenixASMN::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)
	PHXASMN=ConnectToOrbiterSoundDLL(GetHandle());

	SetMyDefaultWaveDirectory("Sound\\_CustomVesselsSounds\\PhoenixASMN\\");

	// 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()")
	ReplaceStockSound(PHXASMN,"mainext.wav",	REPLACE_MAIN_THRUST);
	ReplaceStockSound(PHXASMN,"attfire.wav",		REPLACE_RCS_THRUST_ATTACK);
	ReplaceStockSound(PHXASMN,"attsustain.wav",	REPLACE_RCS_THRUST_SUSTAIN);
	ReplaceStockSound(PHXASMN,"aircond.wav",		REPLACE_AIR_CONDITIONNING);

	ReplaceStockSound(PHXASMN,"VCamb1.wav",		REPLACE_COCKPIT_AMBIENCE_1);
	ReplaceStockSound(PHXASMN,"VCamb2.wav",		REPLACE_COCKPIT_AMBIENCE_2);
	ReplaceStockSound(PHXASMN,"VCamb3.wav",		REPLACE_COCKPIT_AMBIENCE_3);
	ReplaceStockSound(PHXASMN,"VCamb4.wav",		REPLACE_COCKPIT_AMBIENCE_4);
	ReplaceStockSound(PHXASMN,"VCamb5.wav",		REPLACE_COCKPIT_AMBIENCE_5);
	ReplaceStockSound(PHXASMN,"VCamb6.wav",		REPLACE_COCKPIT_AMBIENCE_6);
	ReplaceStockSound(PHXASMN,"VCamb7.wav",		REPLACE_COCKPIT_AMBIENCE_7);
	ReplaceStockSound(PHXASMN,"aircond.wav",		REPLACE_COCKPIT_AMBIENCE_8);
	ReplaceStockSound(PHXASMN,"aircond.wav",		REPLACE_COCKPIT_AMBIENCE_9);

	SoundOptionOnOff(PHXASMN,PLAYRADIOATC,FALSE);
}

//=========================================================
// ~ShuttleD
// This is what I believe is called the destructor. A better name for it might be the Terminator, because Ill be back!!!
//=========================================================

PhoenixASMN::~PhoenixASMN() 
{

}

//=========================================================
// Hope the work I did commenting this source helped, please let me know what you think via email at [email protected] or on the Orbiter Forums
// at BruceJohnJennerLawso (or even my Shuttle-D development thread). This project has been about 10 months or so in the making & I
// hope you enjoy flying the Shuttle-D, as much as I enjoyed creating it. Stay tuned for 1.1, and
// 
// Hail the Probe!
//
//=========================================================

Like the man in the movie said "If the chutes dont open, whats the point?"

Edit, worked on the addforce method, worked great, but I encountered the same problem that Sorindafabico did, what works while going down works too well going up. Im going to search the VesselAPI for options, but does anyone know how to return the vertical speed value that the surface MFD lists?
 
Last edited:

Donamy

Addon Developer
Addon Developer
Donator
Beta Tester
Joined
Oct 16, 2007
Messages
6,907
Reaction score
205
Points
138
Location
Cape
Are you aware of the drag feature in SC3 ? I use it in my Shenzhou9 re-entry module.

I don't know if it will help you or not.

[ame="http://www.orbithangar.com/searchid.php?ID=5920"]Shenzhou 9[/ame]
 

Urwumpe

Not funny anymore
Addon Developer
Donator
Joined
Feb 6, 2008
Messages
37,616
Reaction score
2,336
Points
203
Location
Wolfsburg
Preferred Pronouns
Sire
Why do you CREATE the drag element in clbkPostStep? You just need to increase Para at the right time... your code looks generally extremely confusing, I doubt you understand your own source code. I couldn't in ten minutes.
 

BruceJohnJennerLawso

Dread Lord of the Idiots
Addon Developer
Joined
Apr 14, 2012
Messages
2,585
Reaction score
0
Points
36
Why do you CREATE the drag element in clbkPostStep? You just need to increase Para at the right time... your code looks generally extremely confusing, I doubt you understand your own source code. I couldn't in ten minutes.

My assumption was that it would need to be initialized every step in order to adjust with the control parameter (para). I also tried it in the parachute keypress, Classcontrol, and setclasscaps, none of which had any effect whatsoever.

Addforce is working, but I need to figure out how to return the vertical speed of the spacecraft in order to prevent that issue Sorindafabico mentioned.

And that is 1000 posts right there! Only 8999 more to go until I hit the next milestone :lol:
 

Urwumpe

Not funny anymore
Addon Developer
Donator
Joined
Feb 6, 2008
Messages
37,616
Reaction score
2,336
Points
203
Location
Wolfsburg
Preferred Pronouns
Sire
My assumption was that it would need to be initialized every step in order to adjust with the control parameter (para). I also tried it in the parachute keypress, Classcontrol, and setclasscaps, none of which had any effect whatsoever.

Addforce is working, but I need to figure out how to return the vertical speed of the spacecraft in order to prevent that issue Sorindafabico mentioned.

You define it only once AFTER the airfoil had been defined.

Then you only change the variable that you have linked to the drag element.
 

BruceJohnJennerLawso

Dread Lord of the Idiots
Addon Developer
Joined
Apr 14, 2012
Messages
2,585
Reaction score
0
Points
36
You define it only once AFTER the airfoil had been defined.

Then you only change the variable that you have linked to the drag element.

So variable drag elements needs an airfoil in order to work? In that case, see the issue with vessel axes I posted above.
 

Urwumpe

Not funny anymore
Addon Developer
Donator
Joined
Feb 6, 2008
Messages
37,616
Reaction score
2,336
Points
203
Location
Wolfsburg
Preferred Pronouns
Sire
So variable drag elements needs an airfoil in order to work? In that case, see the issue with vessel axes I posted above.

ah yes... there... you have not understood the principle there... you need BOTH functions for defining your aerodynamics.
 

BruceJohnJennerLawso

Dread Lord of the Idiots
Addon Developer
Joined
Apr 14, 2012
Messages
2,585
Reaction score
0
Points
36
ah yes... there... you have not understood the principle there... you need BOTH functions for defining your aerodynamics.

Hmm, I had thought that it was just a simple utility that could be used to simulate landing gear, doors, open, etc.

But, the problem does persist, because of the issue above (Orbiter wont allow me to define lift along my vessels Z-axis. Rewriting the code to fix this would take forever (need to redefine every thruster location on the vessel)

So, I see two further options:

-Define a dead airfoil that gives no lift, so I can define variable drag elements. Not sure if Orbiter will like this.

-Continue with that addforce idea. It seems that most of the options I have for getting vertical speed are returned in vector format. Im fairly comfortable with vectors on paper, but Im not sure how to break them down in C++, & specifically trying to get one parameter out of them.

(ie, in the output from Gethorizonairspeedvector, I only want to find the y component. Getting the velocity in the vessel reference frames z might make more sense though...)
 

Urwumpe

Not funny anymore
Addon Developer
Donator
Joined
Feb 6, 2008
Messages
37,616
Reaction score
2,336
Points
203
Location
Wolfsburg
Preferred Pronouns
Sire
Your lift vector has a vertical component and a horizontal component. Same for the drag vector, which you also return.

Lift and drag together... notice something? Also parachutes are drag devices
 

BruceJohnJennerLawso

Dread Lord of the Idiots
Addon Developer
Joined
Apr 14, 2012
Messages
2,585
Reaction score
0
Points
36
Your lift vector has a vertical component and a horizontal component. Same for the drag vector, which you also return.

Lift and drag together... notice something? Also parachutes are drag devices

Yes, but what Orbiter means by vertical is "vertical in the vessel reference frame". That means that I can only define airfoils that go side to side on the Phoenix, not up.

If you dont believe me create the code lines in your project and go to the definition of LIFT_VERTICAL in the OrbiterAPI. Martins designed airfoils with aircraft in mind, so he was only thinking of rudders & ailerons, aircraft never have lift surfaces that lift along the direction of travel ( at least none that Ive seen)

The dead airfoil idea didnt work either, anytime I have that airfoil defined I get increasing oscilations back & forth, probably because the airfoil is giving it lift horizontally.

So, I think my only option now is to try Sorindafabicos addforce idea, which actually works pretty well if its done right. I just need to find a way to return the velocity of the capsule along its z-axis. Once I have that, I should have a way to simulate drag external to the API.

But, I need to find out how to get values from a vector in C++ & transfer them to a single variable format (int, double, or whatever have you)

If I had to guess, I would imagine previous capsule designers oriented their vessels along the line of the heatshield, then rotated the camera angles to face users forwards. If I had only known that at the start of this project...
 

Urwumpe

Not funny anymore
Addon Developer
Donator
Joined
Feb 6, 2008
Messages
37,616
Reaction score
2,336
Points
203
Location
Wolfsburg
Preferred Pronouns
Sire
Lift in the direction of travel would be NEGATIVE drag. A physical impossibility.

If you mean lift at 180° AOA... that is possible. Don't you learn any aerodynamics at school?
 

BruceJohnJennerLawso

Dread Lord of the Idiots
Addon Developer
Joined
Apr 14, 2012
Messages
2,585
Reaction score
0
Points
36
Lift in the direction of travel would be NEGATIVE drag. A physical impossibility.

If you mean lift at 180° AOA... that is possible. Don't you learn any aerodynamics at school?

No aerodynamics at school no, I'll post a picture to explain what I mean

Having a bit of fun with this:



Orbiter airfoils are designed to lift in vessel coordinates vertically (the blue arrows, y positive direction), and horizontally (not shown because its perpendicular to the image, the lift from rotating that rudder left or right, x positive or negative directions)

What I need is shown in red, because the phoenix capsule is designed to fall backwards (z negative direction), while receiving a drag force that is applied forwards (z positive direction). Orbiter airfoils can only be defined as up or left/right, so I cant do that.

What compounds the situation is that any definition of an airfoil whatsoever starts to torque the vessel on startup. Even when I set the cl, cm, & cd parameters to 0, I still get that awful torque on the capsule for some reason.

So, instead of going to all the effort of redefining my vessels reference frame, moving every single thruster, airlock position, LES jett point, etc., I think it would be easier to create an addforce function that simulates what variabledragelements does without needing an airfoil. To do that, Im going to need to tweak things a little, because adding a force based on dynamic pressure will cause the vessel to rocket into the sky once its vertical speed is positive (faster it rises, dynp increases, & the sequence repeats itself until the atmosphere is thin again...)

That way, we can at least have a utility that will work for variable drag this regardless of whether a ship has an airfoil. Not every add-on will have one defined.

:hailprobe:
 
Last edited:

Urwumpe

Not funny anymore
Addon Developer
Donator
Joined
Feb 6, 2008
Messages
37,616
Reaction score
2,336
Points
203
Location
Wolfsburg
Preferred Pronouns
Sire
Yes... a drag force, not a lift force... And? What is the problem? Why can't you set cd to the needed value?
 

BruceJohnJennerLawso

Dread Lord of the Idiots
Addon Developer
Joined
Apr 14, 2012
Messages
2,585
Reaction score
0
Points
36
Yes... a drag force, not a lift force... And? What is the problem? Why can't you set cd to the needed value?

I can, but it wont stop the irritating rotation behaviour even when it is set to 0. I tried setting the wing aspect, wing area, & chord length to 0 as well, but the airfoil keeps torquing the Phoenix around like its in a hurricane...

The only thing that I'll need to do is figure out how to get my vessels airspeed velocity along its z-axis. I just dont know how to break the vector that the vessel API gives me into its components.

---------- Post added 03-13-13 at 01:49 PM ---------- Previous post was 03-12-13 at 07:05 PM ----------

Erm :shifty:

So can you help me with that vector decomposition issue Urwumpe, or should I start looking on my own? I only have about an hour to work on it today, so Ill have to move quickly.
 
Last edited:

Urwumpe

Not funny anymore
Addon Developer
Donator
Joined
Feb 6, 2008
Messages
37,616
Reaction score
2,336
Points
203
Location
Wolfsburg
Preferred Pronouns
Sire
I can, but it wont stop the irritating rotation behaviour even when it is set to 0. I tried setting the wing aspect, wing area, & chord length to 0 as well, but the airfoil keeps torquing the Phoenix around like its in a hurricane...

The only thing that I'll need to do is figure out how to get my vessels airspeed velocity along its z-axis. I just dont know how to break the vector that the vessel API gives me into its components.

---------- Post added 03-13-13 at 01:49 PM ---------- Previous post was 03-12-13 at 07:05 PM ----------

Erm :shifty:

So can you help me with that vector decomposition issue Urwumpe, or should I start looking on my own? I only have about an hour to work on it today, so Ill have to move quickly.


First of all: :facepalm:

Sorry, but I needed that. You are travelling into the inner circle of hell of reinventing centuries of physics for solving your problem.

Again: A aerodynamic force, that is pointing in direction of the airflow is a drag force. Like in your situation. The forces of a parachute are only drag.

You need no vector decomposition and other insanities there. What I had always told you more or less directly: You need to refresh your knowledge about airfoil theory and aerodynamics.

What is the AOA? What is drag? What is lift?

And your problem with rotations and everything else comes exactly from that misunderstanding of the aerodynamics. You are telling Orbiter confusing things and Orbiter reacts confused as such.

Don't make the parachute part of your vessel aerodynamic functions. Use the variable drag element there. It does work. Let me finish configuring my computer in the next days, and I will release a very simple example on O-H, ok?
 

BruceJohnJennerLawso

Dread Lord of the Idiots
Addon Developer
Joined
Apr 14, 2012
Messages
2,585
Reaction score
0
Points
36
First of all: :facepalm:

Sorry, but I needed that. You are travelling into the inner circle of hell of reinventing centuries of physics for solving your problem.

Again: A aerodynamic force, that is pointing in direction of the airflow is a drag force. Like in your situation. The forces of a parachute are only drag.

You need no vector decomposition and other insanities there. What I had always told you more or less directly: You need to refresh your knowledge about airfoil theory and aerodynamics.

What is the AOA? What is drag? What is lift?

And your problem with rotations and everything else comes exactly from that misunderstanding of the aerodynamics. You are telling Orbiter confusing things and Orbiter reacts confused as such.

Don't make the parachute part of your vessel aerodynamic functions. Use the variable drag element there. It does work. Let me finish configuring my computer in the next days, and I will release a very simple example on O-H, ok?

Alrighty, but I dont think that will work, given that I cant get the airfoil to stop shaking my ship. Variabledragelements works fine, its just a matter of convincing the airfoil to behave as well.

Can you at least show me how to decompose a vector? I would find that helpful for many other things as well.
 

Urwumpe

Not funny anymore
Addon Developer
Donator
Joined
Feb 6, 2008
Messages
37,616
Reaction score
2,336
Points
203
Location
Wolfsburg
Preferred Pronouns
Sire
Can you at least show me how to decompose a vector? I would find that helpful for many other things as well.

Decompose in what? Its components? Into its components in another coordinate system? Into beer?
 

BruceJohnJennerLawso

Dread Lord of the Idiots
Addon Developer
Joined
Apr 14, 2012
Messages
2,585
Reaction score
0
Points
36
Decompose in what? Its components? Into its components in another coordinate system? Into beer?

Nah, Im not thirsty :lol:

Into its component values. A lot of utilities in the OrbiterAPI return information in vector form, but I need to be able to get it into a more useable form ( flight displays, Gs of acceleration, etc.)
 
Top