Difference between revisions of "Surveyor Source Code"

From OrbiterWiki
Jump to navigation Jump to search
m
m
Line 1: Line 1:
<pre><nowiki>
+
// ==============================================================
// ==============================================================
+
//                ORBITER MODULE: Surveyor
//                ORBITER MODULE: Surveyor
+
//                Copyright (C) 2005 Kwan3217
//                Copyright (C) 2005 Kwan3217
+
//      Released under the Gnu Free Documentation License
//      Released under the Gnu Free Documentation License
+
//
//
+
// Evolved from:
// Evolved from:
+
//                ORBITER MODULE: ShuttlePB
//                ORBITER MODULE: ShuttlePB
+
//                  Part of the ORBITER SDK
//                  Part of the ORBITER SDK
+
//          Copyright (C) 2002-2004 Martin Schweiger
//          Copyright (C) 2002-2004 Martin Schweiger
+
//                  All rights reserved
//                  All rights reserved
+
//
//
+
// Surveyor.cpp
// Surveyor.cpp
+
// Control module for Surveyor vessel class
// Control module for Surveyor vessel class
+
//
//
+
// ==============================================================
// ==============================================================
+
 
+
#define STRICT
#define STRICT
+
#define ORBITER_MODULE
#define ORBITER_MODULE
+
 
+
#include "orbitersdk.h"
#include "orbitersdk.h"
+
 
+
// ==============================================================
// ==============================================================
+
// Some vessel parameters
// Some vessel parameters
+
// ==============================================================
// ==============================================================
+
const double LANDER_EMPTY_MASS = 289.10; //Basic bus plus payload minus AMR minus retro case
const double LANDER_EMPTY_MASS = 289.10; //Basic bus plus payload minus AMR minus retro case
+
const double RETRO_EMPTY_MASS = 64.88;
const double RETRO_EMPTY_MASS = 64.88;
+
const double AMR_MASS = 3.82;
const double AMR_MASS = 3.82;
+
 
+
const double RETRO_PROP_MASS=560.64;
const double RETRO_PROP_MASS=560.64;
+
const double RETRO_THRUST = 39140;
const double RETRO_THRUST = 39140;
+
const double RETRO_BURNTIME = 40.5;
const double RETRO_BURNTIME = 40.5;
+
const double RETRO_ITOT  = RETRO_THRUST*RETRO_BURNTIME;
const double RETRO_ITOT  = RETRO_THRUST*RETRO_BURNTIME;
+
const double RETRO_ISP  = RETRO_ITOT/RETRO_PROP_MASS;
const double RETRO_ISP  = RETRO_ITOT/RETRO_PROP_MASS;
+
const double RETRO_STA  = -0.75;
const double RETRO_STA  = -0.75;
+
 
+
const double VERNIER_PROP_MASS = 70.98;
const double VERNIER_PROP_MASS = 70.98;
+
const double VERNIER_ISP = 3200;
const double VERNIER_ISP = 3200;
+
const double VERNIER_THRUST = 463;
const double VERNIER_THRUST = 463;
+
const double VERNIER_RAD = 0.86;
const double VERNIER_RAD = 0.86;
+
const double VERNIER_STA = -0.5;
const double VERNIER_STA = -0.5;
+
 
+
const double RCS_PROP_MASS=2;
const double RCS_PROP_MASS=2;
+
const double RCS_ISP = 630.0;
const double RCS_ISP = 630.0;
+
const double RCS_THRUST = 0.25;
const double RCS_THRUST = 0.25;
+
const double RCS_RAD = 1;
const double RCS_RAD = 1;
+
const double RCS_STA = -0.5;
const double RCS_STA = -0.5;
+
const double RCS_SPACE = 0.1;
const double RCS_SPACE = 0.1;
+
 
+
const double LEG_RAD = 1.5;
const double LEG_RAD = 1.5;
+
const double LEG_STA =-0.6;
const double LEG_STA =-0.6;
+
 
+
 
+
// ==============================================================
// ==============================================================
+
// Shuttle-PB class interface
// Shuttle-PB class interface
+
// ==============================================================
// ==============================================================
+
 
+
class Surveyor: public VESSEL2 {
class Surveyor: public VESSEL2 {
+
public:
public:
+
  Surveyor (OBJHANDLE hVessel, int flightmodel)
  Surveyor (OBJHANDLE hVessel, int flightmodel)
+
    : VESSEL2 (hVessel, flightmodel) {}
    : VESSEL2 (hVessel, flightmodel) {}
+
  void clbkSetClassCaps (FILEHANDLE cfg);
  void clbkSetClassCaps (FILEHANDLE cfg);
+
  void clbkPreStep(double SimT, double SimDT, double MJD);
  void clbkPreStep(double SimT, double SimDT, double MJD);
+
  int  clbkConsumeBufferedKey(DWORD key, bool down, char *kstate);
  int  clbkConsumeBufferedKey(DWORD key, bool down, char *kstate);
+
  THRUSTER_HANDLE th_vernier[3], th_retro, th_rcs[6], th_group[2];
  THRUSTER_HANDLE th_vernier[3], th_retro, th_rcs[6], th_group[2];
+
  double CalcEmptyMass();
  double CalcEmptyMass();
+
  PROPELLANT_HANDLE ph_vernier, ph_rcs, ph_retro;
  PROPELLANT_HANDLE ph_vernier, ph_rcs, ph_retro;
+
  void SpawnObject(char* classname, char* ext, VECTOR3 ofs);
  void SpawnObject(char* classname, char* ext, VECTOR3 ofs);
+
  void Jettison();
  void Jettison();
+
  int status;
  int status;
+
 
+
  void SetupMeshes();
  void SetupMeshes();
+
  void AddLanderMesh();
  void AddLanderMesh();
+
  void AddRetroMesh();
  void AddRetroMesh();
+
  void AddAMRMesh();
  void AddAMRMesh();
+
};
};
+
 
+
double Surveyor::CalcEmptyMass() {
double Surveyor::CalcEmptyMass() {
 
 
   double EmptyMass=0;
 
   double EmptyMass=0;
  if(GetPropellantMass(ph_retro)>0.999*RETRO_PROP_MASS) {
+
  if(GetPropellantMass(ph_retro)>0.999*RETRO_PROP_MASS) {
    EmptyMass+=AMR_MASS;
+
    EmptyMass+=AMR_MASS;
  }
+
  }
  if(GetPropellantMass(ph_retro)>1) {
+
  if(GetPropellantMass(ph_retro)>1) {
    EmptyMass+=RETRO_EMPTY_MASS;
+
    EmptyMass+=RETRO_EMPTY_MASS;
  }
+
  }
  EmptyMass+=LANDER_EMPTY_MASS;
+
  EmptyMass+=LANDER_EMPTY_MASS;
  return EmptyMass;
+
  return EmptyMass;
}
+
}
 
+
// ==============================================================
+
// ==============================================================
// Overloaded callback functions
+
// Overloaded callback functions
// ==============================================================
+
// ==============================================================
 
+
// --------------------------------------------------------------
+
// --------------------------------------------------------------
// Set the capabilities of the vessel class
+
// Set the capabilities of the vessel class
// --------------------------------------------------------------
+
// --------------------------------------------------------------
void Surveyor::clbkSetClassCaps (FILEHANDLE cfg) {
+
void Surveyor::clbkSetClassCaps (FILEHANDLE cfg) {
 
+
  // physical specs
+
  // physical specs
  SetSize (1.0);
+
  SetSize (1.0);
  SetPMI (_V(0.5,0.5,0.5));
+
  SetPMI (_V(0.5,0.5,0.5));
  SetCameraOffset (_V(0,0.8,0));
+
  SetCameraOffset (_V(0,0.8,0));
  SetTouchdownPoints( _V( 0,LEG_RAD,LEG_STA), _V( sqrt(3.0)/2*LEG_RAD,-0.5*LEG_RAD,LEG_STA), _V(-sqrt(3.0)/2*LEG_RAD,-0.5*LEG_RAD,LEG_STA));
+
  SetTouchdownPoints( _V( 0,LEG_RAD,LEG_STA), _V( sqrt(3.0)/2*LEG_RAD,-0.5*LEG_RAD,LEG_STA), _V(-sqrt(3.0)/2*LEG_RAD,-0.5*LEG_RAD,LEG_STA));
 
+
  status=0;
+
  status=0;
 
+
  // propellant resources
+
  // propellant resources
  ph_vernier = CreatePropellantResource(VERNIER_PROP_MASS);
+
  ph_vernier = CreatePropellantResource(VERNIER_PROP_MASS);
  ph_rcs    = CreatePropellantResource(RCS_PROP_MASS);
+
  ph_rcs    = CreatePropellantResource(RCS_PROP_MASS);
  ph_retro  = CreatePropellantResource(RETRO_PROP_MASS);
+
  ph_retro  = CreatePropellantResource(RETRO_PROP_MASS);
 
+
  th_retro = CreateThruster(_V(0.0,0.0,RETRO_STA), _V(0,0,1), RETRO_THRUST, ph_retro, RETRO_ISP);
+
  th_retro = CreateThruster(_V(0.0,0.0,RETRO_STA), _V(0,0,1), RETRO_THRUST, ph_retro, RETRO_ISP);
  AddExhaust(th_retro, 2, 0.3);
+
  AddExhaust(th_retro, 2, 0.3);
 
+
  th_vernier[0] = CreateThruster(_V(        0.0*VERNIER_RAD, 1.0*VERNIER_RAD,VERNIER_STA), _V(0,0,1), VERNIER_THRUST, ph_vernier, VERNIER_ISP);
+
  th_vernier[0] = CreateThruster(_V(        0.0*VERNIER_RAD, 1.0*VERNIER_RAD,VERNIER_STA), _V(0,0,1), VERNIER_THRUST, ph_vernier, VERNIER_ISP);
  th_vernier[1] = CreateThruster(_V( sqrt(3.0)/2*VERNIER_RAD,-0.5*VERNIER_RAD,VERNIER_STA), _V(0,0,1), VERNIER_THRUST, ph_vernier, VERNIER_ISP);
+
  th_vernier[1] = CreateThruster(_V( sqrt(3.0)/2*VERNIER_RAD,-0.5*VERNIER_RAD,VERNIER_STA), _V(0,0,1), VERNIER_THRUST, ph_vernier, VERNIER_ISP);
  th_vernier[2] = CreateThruster(_V(-sqrt(3.0)/2*VERNIER_RAD,-0.5*VERNIER_RAD,VERNIER_STA), _V(0,0,1), VERNIER_THRUST, ph_vernier, VERNIER_ISP);
+
  th_vernier[2] = CreateThruster(_V(-sqrt(3.0)/2*VERNIER_RAD,-0.5*VERNIER_RAD,VERNIER_STA), _V(0,0,1), VERNIER_THRUST, ph_vernier, VERNIER_ISP);
  CreateThrusterGroup(th_vernier, 3, THGROUP_MAIN);
+
  CreateThrusterGroup(th_vernier, 3, THGROUP_MAIN);
  for(int i=0;i<3;i++) {
+
  for(int i=0;i<3;i++) {
    AddExhaust(th_vernier[i], 1, 0.1);
+
    AddExhaust(th_vernier[i], 1, 0.1);
  }
+
  }
 
+
  //Roll (Leg1) jets
+
  //Roll (Leg1) jets
  th_rcs[ 0] = CreateThruster (_V(-RCS_SPACE,RCS_RAD,RCS_STA), _V( 1,0,0), RCS_THRUST, ph_rcs, RCS_ISP);
+
  th_rcs[ 0] = CreateThruster (_V(-RCS_SPACE,RCS_RAD,RCS_STA), _V( 1,0,0), RCS_THRUST, ph_rcs, RCS_ISP);
 
   th_rcs[ 1] = CreateThruster (_V( RCS_SPACE,RCS_RAD,RCS_STA), _V(-1,0,0), RCS_THRUST, ph_rcs, RCS_ISP);
 
   th_rcs[ 1] = CreateThruster (_V( RCS_SPACE,RCS_RAD,RCS_STA), _V(-1,0,0), RCS_THRUST, ph_rcs, RCS_ISP);
  //Leg2 jets
+
  //Leg2 jets
  th_rcs[ 2] = CreateThruster (_V( sqrt(3.0)/2*RCS_RAD,-0.5*RCS_RAD,RCS_STA-RCS_SPACE), _V(0, 0, 1), RCS_THRUST, ph_rcs, RCS_ISP);
+
  th_rcs[ 2] = CreateThruster (_V( sqrt(3.0)/2*RCS_RAD,-0.5*RCS_RAD,RCS_STA-RCS_SPACE), _V(0, 0, 1), RCS_THRUST, ph_rcs, RCS_ISP);
  th_rcs[ 3] = CreateThruster (_V( sqrt(3.0)/2*RCS_RAD,-0.5*RCS_RAD,RCS_STA+RCS_SPACE), _V(0, 0,-1), RCS_THRUST, ph_rcs, RCS_ISP);
+
  th_rcs[ 3] = CreateThruster (_V( sqrt(3.0)/2*RCS_RAD,-0.5*RCS_RAD,RCS_STA+RCS_SPACE), _V(0, 0,-1), RCS_THRUST, ph_rcs, RCS_ISP);
  //Leg3 jets
+
  //Leg3 jets
  th_rcs[ 4] = CreateThruster (_V(-sqrt(3.0)/2*RCS_RAD,-0.5*RCS_RAD,RCS_STA-RCS_SPACE), _V(0, 0, 1), RCS_THRUST, ph_rcs, RCS_ISP);
+
  th_rcs[ 4] = CreateThruster (_V(-sqrt(3.0)/2*RCS_RAD,-0.5*RCS_RAD,RCS_STA-RCS_SPACE), _V(0, 0, 1), RCS_THRUST, ph_rcs, RCS_ISP);
  th_rcs[ 5] = CreateThruster (_V(-sqrt(3.0)/2*RCS_RAD,-0.5*RCS_RAD,RCS_STA+RCS_SPACE), _V(0, 0,-1), RCS_THRUST, ph_rcs, RCS_ISP);
+
  th_rcs[ 5] = CreateThruster (_V(-sqrt(3.0)/2*RCS_RAD,-0.5*RCS_RAD,RCS_STA+RCS_SPACE), _V(0, 0,-1), RCS_THRUST, ph_rcs, RCS_ISP);
 
+
  th_group[0] = th_rcs[3];
+
  th_group[0] = th_rcs[3];
  th_group[1] = th_rcs[5];
+
  th_group[1] = th_rcs[5];
  CreateThrusterGroup (th_group, 2, THGROUP_ATT_PITCHDOWN);
+
  CreateThrusterGroup (th_group, 2, THGROUP_ATT_PITCHDOWN);
  th_group[0] = th_rcs[2];
+
  th_group[0] = th_rcs[2];
  th_group[1] = th_rcs[4];
+
  th_group[1] = th_rcs[4];
  CreateThrusterGroup (th_group, 2, THGROUP_ATT_PITCHUP);
+
  CreateThrusterGroup (th_group, 2, THGROUP_ATT_PITCHUP);
  th_group[0] = th_rcs[0];
+
  th_group[0] = th_rcs[0];
  CreateThrusterGroup (th_group, 1, THGROUP_ATT_BANKRIGHT);
+
  CreateThrusterGroup (th_group, 1, THGROUP_ATT_BANKRIGHT);
  th_group[0] = th_rcs[1];
+
  th_group[0] = th_rcs[1];
  CreateThrusterGroup (th_group, 1, THGROUP_ATT_BANKLEFT);
+
  CreateThrusterGroup (th_group, 1, THGROUP_ATT_BANKLEFT);
  th_group[0] = th_rcs[3];
+
  th_group[0] = th_rcs[3];
  th_group[1] = th_rcs[4];
+
  th_group[1] = th_rcs[4];
  CreateThrusterGroup (th_group, 2, THGROUP_ATT_YAWRIGHT);
+
  CreateThrusterGroup (th_group, 2, THGROUP_ATT_YAWRIGHT);
  th_group[0] = th_rcs[2];
+
  th_group[0] = th_rcs[2];
  th_group[1] = th_rcs[5];
+
  th_group[1] = th_rcs[5];
  CreateThrusterGroup (th_group, 2, THGROUP_ATT_YAWLEFT);
+
  CreateThrusterGroup (th_group, 2, THGROUP_ATT_YAWLEFT);
 
+
  for (int i=0;i<6;i++) {
+
  for (int i=0;i<6;i++) {
    AddExhaust(th_rcs[i],0.1,0.05);
+
    AddExhaust(th_rcs[i],0.1,0.05);
  }
+
  }
 
+
  // visual specs
+
  // visual specs
  SetupMeshes();
+
  SetupMeshes();
}
+
}
 
+
void Surveyor::clbkPreStep(double SimT, double SimDT, double MJD) {
+
void Surveyor::clbkPreStep(double SimT, double SimDT, double MJD) {
  SetEmptyMass(CalcEmptyMass());
+
  SetEmptyMass(CalcEmptyMass());
  double P,Y,R;
+
  double P,Y,R;
  P=GetThrusterGroupLevel(THGROUP_ATT_PITCHUP)-GetThrusterGroupLevel(THGROUP_ATT_PITCHDOWN);
+
  P=GetThrusterGroupLevel(THGROUP_ATT_PITCHUP)-GetThrusterGroupLevel(THGROUP_ATT_PITCHDOWN);
  Y=GetThrusterGroupLevel(THGROUP_ATT_YAWRIGHT)-GetThrusterGroupLevel(THGROUP_ATT_YAWLEFT);
+
  Y=GetThrusterGroupLevel(THGROUP_ATT_YAWRIGHT)-GetThrusterGroupLevel(THGROUP_ATT_YAWLEFT);
  R=GetThrusterGroupLevel(THGROUP_ATT_BANKRIGHT)-GetThrusterGroupLevel(THGROUP_ATT_BANKLEFT);
+
  R=GetThrusterGroupLevel(THGROUP_ATT_BANKRIGHT)-GetThrusterGroupLevel(THGROUP_ATT_BANKLEFT);
  sprintf(oapiDebugString(),"Pitch %f Yaw %f Roll %f",P,Y,R);
+
  sprintf(oapiDebugString(),"Pitch %f Yaw %f Roll %f",P,Y,R);
 
+
  SetThrusterDir(th_vernier[0],_V(0.087*R,0,1));
+
  SetThrusterDir(th_vernier[0],_V(0.087*R,0,1));
  SetThrusterDir(th_vernier[1],_V(0,0,1.0+0.05*P-0.05*Y));
+
  SetThrusterDir(th_vernier[1],_V(0,0,1.0+0.05*P-0.05*Y));
  SetThrusterDir(th_vernier[2],_V(0,0,1.0+0.05*P+0.05*Y));
+
  SetThrusterDir(th_vernier[2],_V(0,0,1.0+0.05*P+0.05*Y));
  if(status == 1 && GetPropellantMass(ph_retro)<1) {
+
  if(status == 1 && GetPropellantMass(ph_retro)<1) {
    //Jettison the spent main retro
+
    //Jettison the spent main retro
 
     Jettison();
 
     Jettison();
  }
+
  }
  if(status == 0 && GetPropellantMass(ph_retro)<0.999*RETRO_PROP_MASS) {
+
  if(status == 0 && GetPropellantMass(ph_retro)<0.999*RETRO_PROP_MASS) {
    //Jettison the AMR if the retro has started burning
+
    //Jettison the AMR if the retro has started burning
    Jettison();
+
    Jettison();
    //Relight the retro if needed
+
    //Relight the retro if needed
    SetThrusterLevel(th_retro,1);
+
    SetThrusterLevel(th_retro,1);
  }
+
  }
}
+
}
 
+
void Surveyor::AddLanderMesh() {
+
void Surveyor::AddLanderMesh() {
  VECTOR3 ofs = _V(0,0.3,0);
+
  VECTOR3 ofs = _V(0,0.3,0);
  AddMesh("Surveyor-Lander",&ofs);
+
  AddMesh("Surveyor-Lander",&ofs);
}
+
}
void Surveyor::AddRetroMesh() {
+
void Surveyor::AddRetroMesh() {
  VECTOR3 ofs = _V(0,0,-0.5);
+
  VECTOR3 ofs = _V(0,0,-0.5);
  AddMesh("Surveyor-Retro",&ofs);
+
  AddMesh("Surveyor-Retro",&ofs);
}
+
}
void Surveyor::AddAMRMesh() {
+
void Surveyor::AddAMRMesh() {
  VECTOR3 ofs = _V(0,0,-0.8);
+
  VECTOR3 ofs = _V(0,0,-0.8);
  AddMesh("Surveyor-AMR",&ofs);
+
  AddMesh("Surveyor-AMR",&ofs);
}
+
}
 
+
void Surveyor::SetupMeshes() {
+
void Surveyor::SetupMeshes() {
  ClearMeshes();
+
  ClearMeshes();
  switch(status) {
+
  switch(status) {
    case 0:
+
    case 0:
      AddAMRMesh();
+
      AddAMRMesh();
    case 1:
+
    case 1:
      AddRetroMesh();
+
      AddRetroMesh();
    case 2:
+
    case 2:
      AddLanderMesh();
+
      AddLanderMesh();
  }
+
  }
}
+
}
 
+
void Surveyor::SpawnObject(char* classname, char* ext, VECTOR3 ofs) {
+
void Surveyor::SpawnObject(char* classname, char* ext, VECTOR3 ofs) {
  VESSELSTATUS vs;
+
  VESSELSTATUS vs;
  char name[256];
+
  char name[256];
  GetStatus(vs);
+
  GetStatus(vs);
  Local2Rel (ofs, vs.rpos);
+
  Local2Rel (ofs, vs.rpos);
  vs.eng_main = vs.eng_hovr = 0.0;
+
  vs.eng_main = vs.eng_hovr = 0.0;
  vs.status = 0;
+
  vs.status = 0;
  strcpy (name, GetName()); strcat (name, ext);
+
  strcpy (name, GetName()); strcat (name, ext);
  oapiCreateVessel (name, classname, vs);
+
  oapiCreateVessel (name, classname, vs);
}
+
}
 
+
void Surveyor::Jettison() {
+
void Surveyor::Jettison() {
 
   switch(status) {
 
   switch(status) {
    case 0:
+
    case 0:
      status=1;
+
      status=1;
      SpawnObject("Surveyor_AMR","-AMR",_V(0,0,-0.8));
+
      SpawnObject("Surveyor_AMR","-AMR",_V(0,0,-0.8));
      break;
+
      break;
    case 1:
+
    case 1:
      status=2;
+
      status=2;
      SpawnObject("Surveyor_Retro","-Retro",_V(0,0,-0.5));
+
      SpawnObject("Surveyor_Retro","-Retro",_V(0,0,-0.5));
      break;
+
      break;
  }
+
  }
  SetupMeshes();
+
  SetupMeshes();
}
+
}
 
+
int Surveyor::clbkConsumeBufferedKey(DWORD key, bool down, char *kstate) {
+
int Surveyor::clbkConsumeBufferedKey(DWORD key, bool down, char *kstate) {
  if (!down) return 0; // only process keydown events
+
  if (!down) return 0; // only process keydown events
 
+
  if (KEYMOD_SHIFT (kstate)) {
+
  if (KEYMOD_SHIFT (kstate)) {
 
+
  } else { // unmodified keys
+
  } else { // unmodified keys
    switch (key) {
+
    switch (key) {
      case OAPI_KEY_L:  // Fire Retro
+
      case OAPI_KEY_L:  // Fire Retro
        SetThrusterLevel(th_retro,1);
+
        SetThrusterLevel(th_retro,1);
        return 1;
+
        return 1;
    }
+
    }
  }
+
  }
  return 0;
+
  return 0;
}
+
}
 
+
// ==============================================================
+
// ==============================================================
// API callback interface
+
// API callback interface
// ==============================================================
+
// ==============================================================
 
+
// --------------------------------------------------------------
+
// --------------------------------------------------------------
// Vessel initialisation
+
// Vessel initialisation
// --------------------------------------------------------------
+
// --------------------------------------------------------------
DLLCLBK VESSEL *ovcInit (OBJHANDLE hvessel, int flightmodel)
+
DLLCLBK VESSEL *ovcInit (OBJHANDLE hvessel, int flightmodel)
{
+
{
  return new Surveyor (hvessel, flightmodel);
+
  return new Surveyor (hvessel, flightmodel);
}
+
}
 
+
// --------------------------------------------------------------
+
// --------------------------------------------------------------
// Vessel cleanup
+
// Vessel cleanup
// --------------------------------------------------------------
+
// --------------------------------------------------------------
DLLCLBK void ovcExit (VESSEL *vessel)
+
DLLCLBK void ovcExit (VESSEL *vessel)
{
+
{
  if (vessel) delete (Surveyor*)vessel;
+
  if (vessel) delete (Surveyor*)vessel;
}
+
}
</nowiki></pre>
 

Revision as of 02:20, 28 December 2005

// ==============================================================
//                 ORBITER MODULE: Surveyor
//                Copyright (C) 2005 Kwan3217
//       Released under the Gnu Free Documentation License
//
// Evolved from:
//                 ORBITER MODULE: ShuttlePB
//                  Part of the ORBITER SDK
//          Copyright (C) 2002-2004 Martin Schweiger
//                   All rights reserved
//
// Surveyor.cpp
// Control module for Surveyor vessel class
//
// ==============================================================

#define STRICT
#define ORBITER_MODULE

#include "orbitersdk.h"

// ==============================================================
// Some vessel parameters
// ==============================================================
const double LANDER_EMPTY_MASS = 289.10; //Basic bus plus payload minus AMR minus retro case
const double RETRO_EMPTY_MASS = 64.88;
const double AMR_MASS = 3.82;

const double RETRO_PROP_MASS=560.64;
const double RETRO_THRUST = 39140;
const double RETRO_BURNTIME = 40.5;
const double RETRO_ITOT   = RETRO_THRUST*RETRO_BURNTIME;
const double RETRO_ISP   = RETRO_ITOT/RETRO_PROP_MASS;
const double RETRO_STA   = -0.75;

const double VERNIER_PROP_MASS = 70.98;
const double VERNIER_ISP = 3200;
const double VERNIER_THRUST = 463;
const double VERNIER_RAD = 0.86;
const double VERNIER_STA = -0.5;

const double RCS_PROP_MASS=2;
const double RCS_ISP = 630.0;
const double RCS_THRUST = 0.25;
const double RCS_RAD = 1;
const double RCS_STA = -0.5;
const double RCS_SPACE = 0.1;

const double LEG_RAD = 1.5;
const double LEG_STA =-0.6;


// ==============================================================
// Shuttle-PB class interface
// ==============================================================

class Surveyor: public VESSEL2 {
public:
  Surveyor (OBJHANDLE hVessel, int flightmodel)
    : VESSEL2 (hVessel, flightmodel) {}
  void clbkSetClassCaps (FILEHANDLE cfg);
  void clbkPreStep(double SimT, double SimDT, double MJD);
  int  clbkConsumeBufferedKey(DWORD key, bool down, char *kstate);
  THRUSTER_HANDLE th_vernier[3], th_retro, th_rcs[6], th_group[2];
  double CalcEmptyMass();
  PROPELLANT_HANDLE ph_vernier, ph_rcs, ph_retro;
  void SpawnObject(char* classname, char* ext, VECTOR3 ofs);
  void Jettison();
  int status;

  void SetupMeshes();
  void AddLanderMesh();
  void AddRetroMesh();
  void AddAMRMesh();
};

double Surveyor::CalcEmptyMass() {
 double EmptyMass=0;
  if(GetPropellantMass(ph_retro)>0.999*RETRO_PROP_MASS) {
    EmptyMass+=AMR_MASS;
  }
  if(GetPropellantMass(ph_retro)>1) {
    EmptyMass+=RETRO_EMPTY_MASS;
  }
  EmptyMass+=LANDER_EMPTY_MASS;
  return EmptyMass;
}

// ==============================================================
// Overloaded callback functions
// ==============================================================

// --------------------------------------------------------------
// Set the capabilities of the vessel class
// --------------------------------------------------------------
void Surveyor::clbkSetClassCaps (FILEHANDLE cfg) {

  // physical specs
  SetSize (1.0);
  SetPMI (_V(0.5,0.5,0.5));
  SetCameraOffset (_V(0,0.8,0));
  SetTouchdownPoints( _V( 0,LEG_RAD,LEG_STA), _V( sqrt(3.0)/2*LEG_RAD,-0.5*LEG_RAD,LEG_STA), _V(-sqrt(3.0)/2*LEG_RAD,-0.5*LEG_RAD,LEG_STA));

  status=0;

  // propellant resources
  ph_vernier = CreatePropellantResource(VERNIER_PROP_MASS);
  ph_rcs     = CreatePropellantResource(RCS_PROP_MASS);
  ph_retro   = CreatePropellantResource(RETRO_PROP_MASS);

  th_retro = CreateThruster(_V(0.0,0.0,RETRO_STA), _V(0,0,1), RETRO_THRUST, ph_retro, RETRO_ISP);
  AddExhaust(th_retro, 2, 0.3);

  th_vernier[0] = CreateThruster(_V(         0.0*VERNIER_RAD, 1.0*VERNIER_RAD,VERNIER_STA), _V(0,0,1), VERNIER_THRUST, ph_vernier, VERNIER_ISP);
  th_vernier[1] = CreateThruster(_V( sqrt(3.0)/2*VERNIER_RAD,-0.5*VERNIER_RAD,VERNIER_STA), _V(0,0,1), VERNIER_THRUST, ph_vernier, VERNIER_ISP);
  th_vernier[2] = CreateThruster(_V(-sqrt(3.0)/2*VERNIER_RAD,-0.5*VERNIER_RAD,VERNIER_STA), _V(0,0,1), VERNIER_THRUST, ph_vernier, VERNIER_ISP);
  CreateThrusterGroup(th_vernier, 3, THGROUP_MAIN);
  for(int i=0;i<3;i++) {
    AddExhaust(th_vernier[i], 1, 0.1);
  }

  //Roll (Leg1) jets
  th_rcs[ 0] = CreateThruster (_V(-RCS_SPACE,RCS_RAD,RCS_STA), _V( 1,0,0), RCS_THRUST, ph_rcs, RCS_ISP);
 th_rcs[ 1] = CreateThruster (_V( RCS_SPACE,RCS_RAD,RCS_STA), _V(-1,0,0), RCS_THRUST, ph_rcs, RCS_ISP);
  //Leg2 jets
  th_rcs[ 2] = CreateThruster (_V( sqrt(3.0)/2*RCS_RAD,-0.5*RCS_RAD,RCS_STA-RCS_SPACE), _V(0, 0, 1), RCS_THRUST, ph_rcs, RCS_ISP);
  th_rcs[ 3] = CreateThruster (_V( sqrt(3.0)/2*RCS_RAD,-0.5*RCS_RAD,RCS_STA+RCS_SPACE), _V(0, 0,-1), RCS_THRUST, ph_rcs, RCS_ISP);
  //Leg3 jets
  th_rcs[ 4] = CreateThruster (_V(-sqrt(3.0)/2*RCS_RAD,-0.5*RCS_RAD,RCS_STA-RCS_SPACE), _V(0, 0, 1), RCS_THRUST, ph_rcs, RCS_ISP);
  th_rcs[ 5] = CreateThruster (_V(-sqrt(3.0)/2*RCS_RAD,-0.5*RCS_RAD,RCS_STA+RCS_SPACE), _V(0, 0,-1), RCS_THRUST, ph_rcs, RCS_ISP);

  th_group[0] = th_rcs[3];
  th_group[1] = th_rcs[5];
  CreateThrusterGroup (th_group, 2, THGROUP_ATT_PITCHDOWN);
  th_group[0] = th_rcs[2];
  th_group[1] = th_rcs[4];
  CreateThrusterGroup (th_group, 2, THGROUP_ATT_PITCHUP);
  th_group[0] = th_rcs[0];
  CreateThrusterGroup (th_group, 1, THGROUP_ATT_BANKRIGHT);
  th_group[0] = th_rcs[1];
  CreateThrusterGroup (th_group, 1, THGROUP_ATT_BANKLEFT);
  th_group[0] = th_rcs[3];
  th_group[1] = th_rcs[4];
  CreateThrusterGroup (th_group, 2, THGROUP_ATT_YAWRIGHT);
  th_group[0] = th_rcs[2];
  th_group[1] = th_rcs[5];
  CreateThrusterGroup (th_group, 2, THGROUP_ATT_YAWLEFT);

  for (int i=0;i<6;i++) {
    AddExhaust(th_rcs[i],0.1,0.05);
  }

  // visual specs
  SetupMeshes();
}

void Surveyor::clbkPreStep(double SimT, double SimDT, double MJD) {
  SetEmptyMass(CalcEmptyMass());
  double P,Y,R;
  P=GetThrusterGroupLevel(THGROUP_ATT_PITCHUP)-GetThrusterGroupLevel(THGROUP_ATT_PITCHDOWN);
  Y=GetThrusterGroupLevel(THGROUP_ATT_YAWRIGHT)-GetThrusterGroupLevel(THGROUP_ATT_YAWLEFT);
  R=GetThrusterGroupLevel(THGROUP_ATT_BANKRIGHT)-GetThrusterGroupLevel(THGROUP_ATT_BANKLEFT);
  sprintf(oapiDebugString(),"Pitch %f Yaw %f Roll %f",P,Y,R);

  SetThrusterDir(th_vernier[0],_V(0.087*R,0,1));
  SetThrusterDir(th_vernier[1],_V(0,0,1.0+0.05*P-0.05*Y));
  SetThrusterDir(th_vernier[2],_V(0,0,1.0+0.05*P+0.05*Y));
  if(status == 1 && GetPropellantMass(ph_retro)<1) {
    //Jettison the spent main retro
   Jettison();
  }
  if(status == 0 && GetPropellantMass(ph_retro)<0.999*RETRO_PROP_MASS) {
    //Jettison the AMR if the retro has started burning
    Jettison();
    //Relight the retro if needed
    SetThrusterLevel(th_retro,1);
  }
}

void Surveyor::AddLanderMesh() {
  VECTOR3 ofs = _V(0,0.3,0);
  AddMesh("Surveyor-Lander",&ofs);
}
void Surveyor::AddRetroMesh() {
  VECTOR3 ofs = _V(0,0,-0.5);
  AddMesh("Surveyor-Retro",&ofs);
}
void Surveyor::AddAMRMesh() {
  VECTOR3 ofs = _V(0,0,-0.8);
  AddMesh("Surveyor-AMR",&ofs);
}

void Surveyor::SetupMeshes() {
  ClearMeshes();
  switch(status) {
    case 0:
      AddAMRMesh();
    case 1:
      AddRetroMesh();
    case 2:
      AddLanderMesh();
  }
}

void Surveyor::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);
}

void Surveyor::Jettison() {
 switch(status) {
    case 0:
      status=1;
      SpawnObject("Surveyor_AMR","-AMR",_V(0,0,-0.8));
      break;
    case 1:
      status=2;
      SpawnObject("Surveyor_Retro","-Retro",_V(0,0,-0.5));
      break;
  }
  SetupMeshes();
}

int Surveyor::clbkConsumeBufferedKey(DWORD key, bool down, char *kstate) {
  if (!down) return 0; // only process keydown events

  if (KEYMOD_SHIFT (kstate)) {

  } else { // unmodified keys
    switch (key) {
      case OAPI_KEY_L:  // Fire Retro
        SetThrusterLevel(th_retro,1);
        return 1;
    }
  }
  return 0;
}

// ==============================================================
// API callback interface
// ==============================================================

// --------------------------------------------------------------
// Vessel initialisation
// --------------------------------------------------------------
DLLCLBK VESSEL *ovcInit (OBJHANDLE hvessel, int flightmodel)
{
  return new Surveyor (hvessel, flightmodel);
}

// --------------------------------------------------------------
// Vessel cleanup
// --------------------------------------------------------------
DLLCLBK void ovcExit (VESSEL *vessel)
{
  if (vessel) delete (Surveyor*)vessel;
}