Ok I missed a step are you proposing two seperate functions for stage seperation?
A version that spawns the SM and a version that doesn't?
A version that spawns the SM and a version that doesn't?
Code:
// Key "J" Jettison the service module
if(key==OAPI_KEY_J&&!KEYMOD_SHIFT(kstate)&&!KEYMOD_CONTROL (kstate))
if (SMJett=1)
{
SMJettison();
SMJett--;
MeshControl ();
ClassControl ();
}
else
{
MeshControl ();
ClassControl ();
}
// Key "J" Jettison the service module
if(key==OAPI_KEY_J&&!KEYMOD_SHIFT(kstate)&&!KEYMOD_CONTROL (kstate))
{
SeperateSM();
return 1;
}
if (VesselStatus == ASCENT)
{
DelThruster (th_descent); // Delete descent stage engine
DelPropellantResource (ph_descentH2O); // Delete descent stage water tank
DelPropellantResource (ph_descentO2); // Delete descent stage O2 tank
DelPropellantResource (ph_descentFuel); // Delete descent stage propellant tank
DelMesh (mesh_Descent); // Delete descent stage mesh
}
#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 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_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 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 double CAPSULEMASS = 6400; //empty vessel mass in kg
const double SMMASS = 11000; //empty vessel mass in kg
const double EXP_MAINFUELMASS = 29000; //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 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;
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_group[4];
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 WaterCheck ();
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;
// 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... ;)
double O2Tank;
int SMJett;
double Altitude;
double Dv;
double M0;
double M1;
double Airspeed;
double Water;
double MSStime;
double Randomizer;
};
HINSTANCE hDLL;
HFONT hFont;
HPEN hPen;
HBRUSH hBrush;
//=========================================================
// 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;
// ==============================================================
// Airfoil/Aerodynamics definition
// Looks painfuly complicated at first, but gets a lot simpler once you realize that each column corresponds to a particular AOA value,
// and the parameters underneath give the aerodynamic behaviour of the vessel at the given AOA. An excellent tutorial on what these values mean
// is available on the Orbiterwiki website.
// ==============================================================
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)
// 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;
}
//=========================================================
// 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 massand=(O2Tank);
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 = vs.eng_hovr = 0.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::AltitudeCheck ()
{
Altitude = GetAltitude ();
return Altitude;
}
double PhoenixASMN::VelocityCheck ()
{
Airspeed = GetAirspeed ();
return Airspeed;
}
double PhoenixASMN::Checkint ()
{
return SMJett;
}
double PhoenixASMN::SMJettison ()
{
//SpawnObject( "PhoenixSMN", ("%s_SM", GetName()), ZEROVECTOR);
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);
return 1;
}
double PhoenixASMN::MeshControl ()
{
ClearMeshes();
if (SMJett == 1)
{
SetMeshVisibilityMode (AddMesh (PhoenixCapsule = oapiLoadMeshGlobal ("PhoenixAoffset")), MESHVIS_ALWAYS);
SetMeshVisibilityMode (AddMesh (PhoenixCapsule = oapiLoadMeshGlobal ("PhoenixSMN MKII")), MESHVIS_ALWAYS);
return 1;
}
else
{
SetMeshVisibilityMode (AddMesh (PhoenixCapsule = oapiLoadMeshGlobal ("PhoenixA")), 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_rcs[0], NULL);
//SetThrusterResource(th_rcs[1], NULL);
//SetThrusterResource(th_rcs[2], NULL);
//SetThrusterResource(th_rcs[3], NULL);
//SetThrusterResource(th_rcs[4], NULL);
//SetThrusterResource(th_rcs[5], NULL);
//SetThrusterResource(th_rcs[6], NULL);
//SetThrusterResource(th_rcs[7], NULL);
//SetThrusterResource(th_rcs[8], NULL);
//SetThrusterResource(th_rcs[9], NULL);
//SetThrusterResource(th_rcs[10], NULL);
//SetThrusterResource(th_rcs[11], NULL);
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);
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
// 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
// ************************ Airfoil ****************************
ClearAirfoilDefinitions();
CreateAirfoil (LIFT_VERTICAL, _V(0,0,0), Shuttle_MomentCoeff, 8, 140, 0.1);
// vessel caps definitions
SetCameraOffset (_V(0,1.707,6.753));
SetAlbedoRGB (_V(1,1,1));
MeshControl ();
ClassControl ();
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
// 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
SURFHANDLE texH2O2RCS = oapiRegisterExhaustTexture ("exhaust_atrcsShuttleD");
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];
CreateThrusterGroup (th_group, 2, THGROUP_ATT_PITCHUP);
th_group[0] = th_rcsCM[4];
th_group[1] = th_rcsCM[5];
CreateThrusterGroup (th_group, 2, THGROUP_ATT_PITCHDOWN);
th_group[0] = th_rcsCM[2];
th_group[1] = th_rcsCM[7];
CreateThrusterGroup (th_group, 2, THGROUP_ATT_BANKLEFT);
th_group[0] = th_rcsCM[3];
th_group[1] = th_rcsCM[6];
CreateThrusterGroup (th_group, 2, THGROUP_ATT_BANKRIGHT);
CreateThrusterGroup (th_group, 0, THGROUP_ATT_UP);
CreateThrusterGroup (th_group, 0, THGROUP_ATT_DOWN);
th_group[0] = th_rcsCM[10];
th_group[1] = th_rcsCM[11];
CreateThrusterGroup (th_group, 2, THGROUP_ATT_YAWLEFT);
th_group[0] = th_rcsCM[8];
th_group[1] = th_rcsCM[9];
CreateThrusterGroup (th_group, 2, THGROUP_ATT_YAWRIGHT);
th_group[0] = th_rcsCM[2];
th_group[1] = th_rcsCM[6];
CreateThrusterGroup (th_group, 2, THGROUP_ATT_LEFT);
th_group[0] = th_rcsCM[3];
th_group[1] = th_rcsCM[7];
CreateThrusterGroup (th_group, 2, THGROUP_ATT_RIGHT);
CreateThrusterGroup (th_group, 0, THGROUP_ATT_FORWARD);
CreateThrusterGroup (th_group, 0, 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", &O2Tank);
}
if (!_strnicmp (line, "SMJett", 6)) {
sscanf (line+6, "%d", &SMJett);
}
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);
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(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");
}
// MainTanks = GetPropellantMass(MainFuel);
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(SendCarg3HudMessage(),"Water reserves %.0f L, %.0f kg Oxygen remaining",
WaterCheck (),O2Check ());
}
if (simt<1)
{
MeshControl ();
ClassControl ();
}
Randomizer = 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);
}
//---------------------------------------------------------------------------
// 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!
//
//=========================================================