// ==============================================================
// ORBITER MODULE: EAGLE3
// Part of the ORBITER SDK
// Copyright (C) 2002-2004 Martin Schweiger
// All rights reserved
//
// EAGLE3.cpp
// Control module for EAGLE3 vessel class
//
// ==============================================================
#define ORBITER_MODULE
#define ENG 1
#define START 2
#define STOP 3
#define CANNON 4
#include "orbitersdk.h"
#include "EAGLE3.h"
#include "EAGLE3MESH.h"
#include "OrbiterSoundSDK35.h"
VISHANDLE MainExternalMeshVisual = 0;
static PARTICLESTREAMSPEC contrail_main = {
0, 8.0, 5, 150, 0.3, 4.0, 4, 2.0, PARTICLESTREAMSPEC::DIFFUSE,
PARTICLESTREAMSPEC::LVL_SQRT, 0, 1,
PARTICLESTREAMSPEC::ATM_PLOG, 1e-4, 1
};
static PARTICLESTREAMSPEC exhaust_main = {
0, 2.0, 20, 150, 0.1, 0.2, 16, 2.0, PARTICLESTREAMSPEC::EMISSIVE,
PARTICLESTREAMSPEC::LVL_SQRT, 0, 1,
PARTICLESTREAMSPEC::ATM_PLOG, 1e-5, 0.1
};
static PARTICLESTREAMSPEC exhaust_hover = {
0, 1.0, 5, 50, 0.3, 2.0, 3, 2.0, PARTICLESTREAMSPEC::DIFFUSE,
PARTICLESTREAMSPEC::LVL_SQRT, 0, 1,
PARTICLESTREAMSPEC::ATM_PLOG, -0.1, 0.1
};
void EAGLE3::SetUMMUAirlockPos(void)
{//{
int AirlockStatus=Crew.GetAirlockDoorState();
Crew.SetActiveDockForTransfer(iActiveDockNumber);
switch(iActiveDockNumber)
{
case 0: //front
Crew.DefineAirLockShape(AirlockStatus,-3,3,-4,3,3,6);
Crew.SetMembersPosRotOnEVA(_V(0,-1.948,5),_V(0,3,0));
doorselected=0;
break;
case 1: //rear
Crew.DefineAirLockShape(AirlockStatus,-3,3,-4,3,-8,-4);
Crew.SetMembersPosRotOnEVA(_V(0,-1.948,-5),_V(0,0,0));
doorselected=1;
break;
case 2: //tpadl
Crew.DefineAirLockShape(AirlockStatus,-45,-33,-10,13,-4,4);
Crew.SetMembersPosRotOnEVA(_V(-39,-3.85,-1),_V(0,0,0));
doorselected=2;
break;
case 3: //tpadright
Crew.DefineAirLockShape(AirlockStatus,33,42,-10,13,-4,4);
Crew.SetMembersPosRotOnEVA(_V(39,-3.85,-1),_V(0,0,0));
// Crew.DefineAirLockShape(AirlockStatus,-45,-33,-10,13,-4,4);
//Crew.SetMembersPosRotOnEVA(_V(-39,-3.85,-1),_V(0,0,0));
doorselected=3;
break;
case 4:
Crew.DefineAirLockShape(AirlockStatus,-20,20,-20,13,0,200);
Crew.SetMembersPosRotOnEVA(_V(12,-11.234,89),_V(0,0,0));
doorselected=4;
break;
case 5:
Crew.DefineAirLockShape(AirlockStatus,-20,20,-20,13,-200,0);
Crew.SetMembersPosRotOnEVA(_V(-12,-11.234,-89),_V(0,0,0));
doorselected=5;
break;
}
}
void EAGLE3::clbkPostCreation (void)
{
JohnSoundID=ConnectToOrbiterSoundDLL3(GetHandle());
SoundOptionOnOff3(JohnSoundID,PLAYMAINTHRUST,TRUE);
SoundOptionOnOff3(JohnSoundID,PLAYHOVERTHRUST,TRUE);
SoundOptionOnOff3(JohnSoundID,PLAYATTITUDETHRUST,TRUE);
SoundOptionOnOff3(JohnSoundID,PLAYCOUNTDOWNWHENTAKEOFF,FALSE);
SoundOptionOnOff3(JohnSoundID,PLAYCABINAIRCONDITIONING,FALSE);
SoundOptionOnOff3(JohnSoundID,PLAYCABINRANDOMAMBIANCE,FALSE);
SoundOptionOnOff3(JohnSoundID,PLAYRADIOATC,FALSE);
SoundOptionOnOff3(JohnSoundID,DISPLAYTIMER,FALSE);
}// Constructor
EAGLE3::EAGLE3 (OBJHANDLE hObj, int fmodel)
: VESSEL2 (hObj, fmodel)
{
MAX_GRAP_DIST =10;
MAX_GRAP_DISTHEAD =30;
DOOR_status = DOOR_UP;
BUG_status = DOOR_UP;
BUGHATCH_status = DOOR_UP;
DOOR1_status = DOOR_UP;
DOOR2_status = DOOR_UP;
DOOR3_status = DOOR_UP;
GEAR_status = GEAR_UP;
IGNITION = 0;
GEAR_proc = 0;
BUG_proc = 0;
BUGHATCH_proc = 0;
LIFT_SPEED =.25;
light_SPEED =.5;
radar_speed=.5;
CAM=0;
DefineAnimations ();
stage=1;
BUG_pos.x = 0;
BUG_pos.y = -.591;
BUG_pos.z = -6.792;
// Localización de los motores principales
MainEngineOfs[0]=_V( 0,-0.76,-15.9);
MainEngineOfs[1]=_V( 0, 1.89,-15.9);
MainEngineOfs[2]=_V( 2.45, 0.57,-15.9);
MainEngineOfs[3]=_V(-2.45, 0.57,-15.9);
//Motores elevadores
// Los de la estructura principal
HoverEngineOfs[0]=_V( 0.64,-1.5,9.378);
HoverEngineOfs[1]=_V(-0.64,-1.5,9.378);
HoverEngineOfs[2]=_V(-0.64,-1.5,-9.399);
HoverEngineOfs[3]=_V( 0.64,-1.5,-9.399);
// Los del módulo de carga
HoverEngineOfs[4]=_V( 1.077,-1.5, 4.122);
HoverEngineOfs[5]=_V(-1.077,-1.5,4.122);
HoverEngineOfs[6]=_V(-1.077,-1.5,-4.14);
HoverEngineOfs[7]=_V( 1.077,-1.5,-4.14);
// Impulsores de control de posición del cuerpo principal
RCSTransporterOfs[0]=_V(6.236659,-0.3,7.873591);
RCSTransporterOfs[1]=_V(-6.236659,-0.3,7.873591);
RCSTransporterOfs[2]=_V(6.236659,-0.3,-7.955545);
RCSTransporterOfs[3]=_V(-6.236659,-0.3,-7.955545);
// Creación del tanque de combustible
ph_main=CreatePropellantResource(MAX_FUEL);
}
////////////////////////////////////////////////////////
// SendHudMessage
////////////////////////////////////////////////////////
char *EAGLE3::SendHudMessage()
{
dHudMessageDelay=15;
return cUmmuHudDisplay;
}
void EAGLE3::SelectCockpitView (int CAM)
{
switch (CAM) {
case 0: //COCKPIT
SetCameraDefaultDirection (_V(0,0,1));
SetCameraOffset (_V(2.186,2.9,13));
//SetCameraOffset (_V(-1.362,1.633,11.752));
break;
case 1: //COCKPIT
SetCameraDefaultDirection (_V(0,0,1));
SetCameraOffset (_V(-2.186,2.9,13));
//SetCameraOffset (_V(-1.362,1.633,11.752));
break;
case 2: //ABOVE
SetCameraDefaultDirection (_V(0,-1,0));
SetCameraOffset (_V(0,7,-1.061));
break;
}
}
//void EAGLE3::clbkSetClassCaps (FILEHANDLE cfg)
void EAGLE3::SetTransporter()
{
// physical specs
SetSize(EAGLE_SIZE);
SetPMI (PMI);
SetCrossSections (CROSS_SECTION);
SetCW (0.2, 0.2, 1.5, 1.5);
SetRotDrag (ROT_DRAG);
SetPitchMomentScale(PITCH_MOMENT_SCALE);
SetBankMomentScale (BANK_MOMENT_SCALE);
SetTrimScale (0.05);
//SetCameraOffset (_V(-1.362,1.633,11.752));
SetCameraOffset (_V(-2.18532,2.9,13));
SetClipRadius(0.1);
SetTouchdownPoints (_V(0,-3.124,8.7), _V(-5.45,-3.124,-9.6), _V(5.45,-3.124,-9.6));;
AddTransporterExhaust();
DOCKHANDLE main1=CreateDock (_V(0,0.8,15.8), _V(0,0,1), _V(0,1,0));
ATTACHMENTHANDLE MAIN;
MAIN = CreateAttachment (true, _V(0,-3.131,0),_V(0,-1,0),_V(0,0,1),"APR",false);
P1 = CreateAttachment (false, _V(0,1.68,0),_V(0,1,0),_V(1,0,0),"TOP",false);
BUG = CreateAttachment (false, _V(0,-.591,-6.792),_V(0,-1,0),_V(1,0,0),"EGLEB",false);
//TOP = CreateAttachment (true, _V(0,2.806,0),_V(0,-1,0),_V(0,0,1),"EGLETP",false);
EnableTransponder (true);
EnableIDS (main1, true);
SetIDSChannel(main1,8);
if (GetAltitude()<10)
// Esta llamada fuerza los humos a activos
HoverSmoke=PasarLosHumos(false);
else
// En caso contrario, se fuerzan los humos a inactivos
HoverSmoke=PasarLosHumos(true);
static VECTOR3 beaconpos[4] = {{-4.373, 1.07, 8}, //red
{ -4.373, 1.07, -8}, //red
{4.434, 1.07, 8}, //red
{ 4.434, 1.07, -8}, //blue
};
static VECTOR3 beaconcol[4] = {{1,0,0}, //red
{1,0,0}, //red
{0,1,0}, //Green
{0, 1, 0},//Green
};
for (int i = 0; i < 4; i++) {
beacon[i].shape = BEACONSHAPE_STAR;
beacon[i].pos = beaconpos+i;
beacon[i].col = beaconcol+i;
beacon[i].size = 0.2;
beacon[i].falloff = 0.3;
beacon[i].period = 0.8;
beacon[i].duration = 0.3;
beacon[i].tofs = (6-i)*0.2;
beacon[i].active = true;
AddBeacon (beacon+i);
}
// Call clbkSetClassCaps_UMMU and select a member
SelectedUmmuMember=0;
clbkSetClassCaps_UMMu();
// visual specs
SetMeshVisibilityMode (AddMesh (oapiLoadMeshGlobal ("EAGLEBUGGY4B")), MESHVIS_EXTERNAL | MESHVIS_EXTPASS); //Main ship mesh | MESHVIS_EXTPASS
SetMeshVisibilityMode (AddMesh (oapiLoadMeshGlobal ("EAGLEVC1")), MESHVIS_COCKPIT ); //Main ship mesh
SetMeshVisibilityMode (AddMesh (oapiLoadMeshGlobal ("EAGLEVC1")), MESHVIS_VC ); //Main ship mesh
}
DLLCLBK void ovcTimestep (VESSEL *vessel, double simt)
{
((EAGLE3*)vessel)->Estado();
}
void EAGLE3::AddTransporterExhaust()
{
int i,NumHover;
//Se crean los motores principales y sus escapes con humo
for (i=0; i<4; i++)
{
th_main[i] = CreateThruster (_V(0,0,0), _V(0,0,1), MAX_MAIN_THRUST, ph_main, ISP_FUS);
AddExhaust (th_main[i],2,0.5,_V(MainEngineOfs[i].x,MainEngineOfs[i].y,MainEngineOfs[i].z+1),_V(0,0,-1));
AddExhaustStream (th_main[i], MainEngineOfs[i], &exhaust_main);
};
AddExhaustStream (th_main[1],_V(0,0,-24),&contrail_main);
// Se crea el grupo motor principal
thg_main = CreateThrusterGroup (th_main, 4, THGROUP_MAIN);
for (i=0; i<4; i++)
{
// th_retro[i] = CreateThruster (_V(0,0,0), _V(0,0,1), MAX_MAIN_THRUST, ph_main, ISP_QUI);
// AddExhaust (th_retro[0],2,0.1,_V(6.234,-0.34,8.432),_V(0,0,1));
// AddExhaust (th_retro[1],2,0.1,_V(-6.234,-0.34,8.432),_V(0,0,1));
// AddExhaust (th_retro[2],2,0.1,_V(6.234,-0.34,-7.384),_V(0,0,1));
// AddExhaust (th_retro[3],2,0.1,_V(-6.234,-0.34,-7.384),_V(0,0,1));
};
//thg_retro=CreateThrusterGroup(th_retro,4,THGROUP_RETRO);
//{
// th_retro[4]=CreateThruster(_V(0,0,0),_V(0,0,-1), MAX_RETRO_THRUST, ph_main, ISP_QUI);
// AddExhaust (th_retro[0],2,0.1,_V(6.234,-0.34,8.432),_V(0,0,1));
// AddExhaust (th_retro[1],2,0.1,_V(-6.234,-0.34,8.432),_V(0,0,1));
// AddExhaust (th_retro[2],2,0.1,_V(6.234,-0.34,-7.384),_V(0,0,1));
// AddExhaust (th_retro[3],2,0.1,_V(-6.234,-0.34,-7.384),_V(0,0,1));
// }
// Se crea el grupo motor retropropulsor
// thg_retro=CreateThrusterGroup(th_retro,4,THGROUP_RETRO);
//Motores elevadores
if (stage==1)
{
SetEngineLevel(ENGINE_HOVER,0.0);
for (i=3; i<8; i++)
DelThruster (th_hover[i]);
NumHover=4;
}
else
NumHover=8;
for (i=0; i<NumHover; i++)
{
th_hover[i] = CreateThruster (_V(0,0,0), _V(0,1,0), MAX_HOVER_THRUST, ph_main, ISP_QUI);
AddExhaust (th_hover[i], 0.3, 0.5,_V(HoverEngineOfs[i].x,HoverEngineOfs[i].y+1.3,HoverEngineOfs[i].z),_V(0,-1,1));
}
// Se crea el grupo motor elevador
thg_hover = CreateThrusterGroup (th_hover, NumHover, THGROUP_HOVER);
// Impulsores de control de posición
// Para mejorar la navegabilidad, los motores están ubicados en posiciones diferentes a los escapes
// Grupo delantero derecho
// Delantero derecho superior
th_rcs[0]=CreateThruster(_V(6,0,10),_V(0,-1,0),MAX_RCS_THRUST,ph_main,ISP_QUI);
AddExhaust (th_rcs[0],1,0.1,_V(6.253,.05,7.891),_V(0,1,0));
// Delantero derecho inferior
th_rcs[1]=CreateThruster(_V(6,0,10),_V(0,1,0),MAX_RCS_THRUST,ph_main,ISP_QUI);
AddExhaust (th_rcs[1],1,0.1,_V(6.253,-.713,7.891),_V(0,-1,0));
// Delantero derecho proa
th_rcs[2]=CreateThruster(_V(6,0,10),_V(0,0,-1),MAX_RCS_THRUST,ph_main,ISP_QUI);
AddExhaust (th_rcs[2],1,0.1,_V(6.234,-0.34,8.432),_V(0,0,1));
// Delantero derecho popa
th_rcs[3]=CreateThruster(_V(6,0,10),_V(0,0,1),MAX_RCS_THRUST,ph_main,ISP_QUI);
AddExhaust (th_rcs[3],1,0.1,_V(6.234,-0.34,7.375),_V(0,0,-1));
// Delantero derecho exterior
th_rcs[4]=CreateThruster(_V(6,0,10),_V(-1,0,0),MAX_RCS_THRUST,ph_main,ISP_QUI);
AddExhaust (th_rcs[4],1,0.1,_V(6.563,-.34,7.891),_V(1,0,0));
// Grupo delantero izquierdo
// Delantero izquierdo superior
th_rcs[5]=CreateThruster(_V(-6,0,10),_V(0,-1,0),MAX_RCS_THRUST,ph_main,ISP_QUI);
AddExhaust (th_rcs[5],1,0.1,_V(-6.253,.05,7.891),_V(0,1,0));
// Delantero izquierdo inferior
th_rcs[6]=CreateThruster(_V(-6,0,10),_V(0,1,0),MAX_RCS_THRUST,ph_main,ISP_QUI);
AddExhaust (th_rcs[6],1,0.1,_V(-6.253,-.713,7.891),_V(0,-1,0));
// Delantero izquierdo proa
th_rcs[7]=CreateThruster(_V(-6,0,10),_V(0,0,-1),MAX_RCS_THRUST,ph_main,ISP_QUI);
AddExhaust (th_rcs[7],1,0.1,_V(-6.234,-0.34,8.432),_V(0,0,1));
// Delantero izquierdo popa
th_rcs[8]=CreateThruster(_V(-6,0,10),_V(0,0,1),MAX_RCS_THRUST,ph_main,ISP_QUI);
AddExhaust (th_rcs[8],1,0.1,_V(-6.234,-0.34,7.375),_V(0,0,-1));
// Delantero izquierdo exterior
th_rcs[9]=CreateThruster(_V(-6,0,10),_V(1,0,0),MAX_RCS_THRUST,ph_main,ISP_QUI);
AddExhaust (th_rcs[9],1,0.1,_V(-6.563,-.34,7.891),_V(-1,0,0));
// Grupo trasero derecho
// Trasero derecho superior
th_rcs[10]=CreateThruster(_V(6,0,-10),_V(0,-1,0),MAX_RCS_THRUST,ph_main,ISP_QUI);
AddExhaust (th_rcs[10],1,0.1,_V(6.253,.05,-7.917),_V(0,1,0));
// Trasero derecho inferior
th_rcs[11]=CreateThruster(_V(6,0,-10),_V(0,1,0),MAX_RCS_THRUST,ph_main,ISP_QUI);
AddExhaust (th_rcs[11],1,0.1,_V(6.253,-.713,-7.917),_V(0,-1,0));
// Trasero derecho proa
th_rcs[12]=CreateThruster(_V(6,0,-10),_V(0,0,-1),MAX_RCS_THRUST,ph_main,ISP_QUI);
AddExhaust (th_rcs[12],1,0.1,_V(6.234,-0.34,-7.384),_V(0,0,1));
// Trasero derecho popa
th_rcs[13]=CreateThruster(_V(6,0,-10),_V(0,0,1),MAX_RCS_THRUST,ph_main,ISP_QUI);
AddExhaust (th_rcs[13],1,0.1,_V(6.234,-0.34,-8.45),_V(0,0,-1));
// Trasero derecho exterior
th_rcs[14]=CreateThruster(_V(6,0,-10),_V(-1,0,0),MAX_RCS_THRUST,ph_main,ISP_QUI);
AddExhaust (th_rcs[14],1,0.1,_V(6.563,-.34,-7.917),_V(1,0,0));
// Grupo trasero izquierdo
// Trasero izquierdo superior
th_rcs[15]=CreateThruster(_V(-6,0,-10),_V(0,-1,0),MAX_RCS_THRUST,ph_main,ISP_QUI);
AddExhaust (th_rcs[15],1,0.1,_V(-6.253,.05,-7.917),_V(0,1,0));
// Trasero izquierdo inferior
th_rcs[16]=CreateThruster(_V(-6,0,-10),_V(0,1,0),MAX_RCS_THRUST,ph_main,ISP_QUI);
AddExhaust (th_rcs[16],1,0.1,_V(-6.253,-.713,-7.917),_V(0,-1,0));
// Trasero izquierdo proa
th_rcs[17]=CreateThruster(_V(-6,0,-10),_V(0,0,-1),MAX_RCS_THRUST,ph_main,ISP_QUI);
AddExhaust (th_rcs[17],1,0.1,_V(-6.234,-0.34,-7.384),_V(0,0,1));
// Trasero izquierdo popa
th_rcs[18]=CreateThruster(_V(-6,0,-10),_V(0,0,1),MAX_RCS_THRUST,ph_main,ISP_QUI);
AddExhaust (th_rcs[18],1,0.1,_V(-6.234,-0.34,-8.45),_V(0,0,-1));
// Trasero izquierdo exterior
th_rcs[19]=CreateThruster(_V(-6,0,-10),_V(1,0,0),MAX_RCS_THRUST,ph_main,ISP_QUI);
AddExhaust (th_rcs[19],1,0.1,_V(-6.563,-.34,-7.917),_V(-1,0,0));
// Se crean los grupos motores para los diferentes movimientos de la nave
// 1-Movimientos rotacionales
// Grupo motor de cabeceo hacia arriba "PITCH-UP"
th_group[0]=th_rcs[1];
th_group[1]=th_rcs[6];
th_group[2]=th_rcs[10];
th_group[3]=th_rcs[15];
CreateThrusterGroup(th_group,4,THGROUP_ATT_PITCHUP);
// Grupo motor de cabeceo hacia abajo "PITCH-DOWN"
th_group[0]=th_rcs[0];
th_group[1]=th_rcs[5];
th_group[2]=th_rcs[11];
th_group[3]=th_rcs[16];
CreateThrusterGroup(th_group,4,THGROUP_ATT_PITCHDOWN);
// Grupo motor de balanceo izquierda "YAW-RIGHT"
th_group[0]=th_rcs[8];
th_group[1]=th_rcs[18];
th_group[2]=th_rcs[2];
th_group[3]=th_rcs[12];
CreateThrusterGroup(th_group,4,THGROUP_ATT_YAWRIGHT);
// Grupo motor de balanceo derecha "YAW-LEFT"
th_group[0]=th_rcs[3];
th_group[1]=th_rcs[13];
th_group[2]=th_rcs[7];
th_group[3]=th_rcs[17];
CreateThrusterGroup(th_group,4,THGROUP_ATT_YAWLEFT);
// Grupo motor de alabeo derecho "BANK-RIGHT"
th_group[0]=th_rcs[0];
th_group[1]=th_rcs[6];
th_group[2]=th_rcs[10];
th_group[3]=th_rcs[16];
CreateThrusterGroup(th_group,4,THGROUP_ATT_BANKRIGHT);
// Grupo motor de alabeo izquierdo "BANK-LEFT"
th_group[0]=th_rcs[1];
th_group[1]=th_rcs[5];
th_group[2]=th_rcs[11];
th_group[3]=th_rcs[15];
CreateThrusterGroup(th_group,4,THGROUP_ATT_BANKLEFT);
// 2-Movimientos traslacionales
// Grupo motor de traslación derecha "RIGHT"
// Este grupo lo podían formar los impulsores izquierdos delantero de proa y trasero de popa
th_group[0]=th_rcs[9];
th_group[1]=th_rcs[19];
CreateThrusterGroup(th_group,2,THGROUP_ATT_RIGHT);
// Grupo motor de traslación izquierda "LEFT"
// Este grupo lo podían formar los impulsores derechos delantero de proa y trasero de popa
th_group[0]=th_rcs[4];
th_group[1]=th_rcs[14];
CreateThrusterGroup(th_group,2,THGROUP_ATT_LEFT);
// Grupo motor de traslación arriba "DOWN"
th_group[0]=th_rcs[0];
th_group[1]=th_rcs[5];
th_group[2]=th_rcs[10];
th_group[3]=th_rcs[15];
CreateThrusterGroup(th_group,4,THGROUP_ATT_DOWN);
// Grupo motor de traslación abajo "UP"
th_group[0]=th_rcs[1];
th_group[1]=th_rcs[6];
th_group[2]=th_rcs[11];
th_group[3]=th_rcs[16];
CreateThrusterGroup(th_group,4,THGROUP_ATT_UP);
// Grupo motor de traslación adelante "FORWARD"
th_group[0]=th_rcs[3];
th_group[1]=th_rcs[8];
th_group[2]=th_rcs[13];
th_group[3]=th_rcs[18];
CreateThrusterGroup(th_group,4,THGROUP_ATT_FORWARD);
// Grupo motor de traslación atrás "BACK"
th_group[0]=th_rcs[2];
th_group[1]=th_rcs[7];
th_group[2]=th_rcs[12];
th_group[3]=th_rcs[17];
CreateThrusterGroup(th_group,4,THGROUP_ATT_BACK);
}
void EAGLE3::SetRetros(bool ban)
{
int i;
double MAX_RETRO_THRUST;
if (ban)
MAX_RETRO_THRUST=160000.0;
else
MAX_RETRO_THRUST=0.0;
//Se crean los motores retropropulsores
for (i=0; i<4; i++)
{
th_retro[4]=CreateThruster(_V(0,0,0),_V(0,0,-1), MAX_RETRO_THRUST, ph_main, ISP_QUI);
AddExhaust (th_retro[0],2,0.1,_V(6.234,-0.34,8.432),_V(0,0,1));
AddExhaust (th_retro[1],2,0.1,_V(-6.234,-0.34,8.432),_V(0,0,1));
AddExhaust (th_retro[2],2,0.1,_V(6.234,-0.34,-7.384),_V(0,0,1));
AddExhaust (th_retro[3],2,0.1,_V(-6.234,-0.34,-7.384),_V(0,0,1));
}
// Se crea el grupo motor retropropulsor
thg_retro=CreateThrusterGroup(th_retro,4,THGROUP_RETRO);
}
bool EAGLE3::PasarLosHumos(bool humo)
{
// PARTICLESTREAMSPEC contrail_hover = {
// 0, 1.0, 5, 50, 0.3, 2.0, 3, 2.0, PARTICLESTREAMSPEC::DIFFUSE,
// PARTICLESTREAMSPEC::LVL_SQRT, 0, 1,
// PARTICLESTREAMSPEC::ATM_PLOG, -0.1, 0.1
// };
int NumHover, i;
double level, alt;
level=GetThrusterGroupLevel(THGROUP_HOVER);
alt=GetAltitude();
// If stage=1 only 4 hovers, here's no cargo module
if (stage==1)
NumHover=4;
else
NumHover=8;
// Conditions to add smoke to hovers:
// 1: Altitude below 10m
// 2: Here's no previous defined smoke for hovers (humo flag in false condition)
if ((alt <10) && (!humo))
{
for (i=0; i<NumHover; i++)
hover_humo[i]=AddExhaustStream (th_hover[i], _V(HoverEngineOfs[i].x,HoverEngineOfs[i].y-7.5,HoverEngineOfs[i].z), &exhaust_hover);
return true;
};
// Conditions to delete smoke to hovers:
// 1: Altitude above 10m
// 2: Previosly defined smoke for hovers (humo flag in true condition)
if ((alt>10) && (humo))
{
SetThrusterGroupLevel(THGROUP_HOVER,0.0);
for (i=0; i<NumHover; i++)
DelExhaustStream (hover_humo[i]);
SetThrusterGroupLevel(THGROUP_HOVER,level);
return false;
}
return humo;
}
void EAGLE3::clbkSetClassCaps_UMMu(void)
{
//--------------------------------------------------------------
// InitUmmu
// initialisation of Ummu must be done first ! return of 1 mean OK
// return of -999 mean Ummu addon is not installed in user's Orbiter, return of -1
// mean misc error. If error simply all function will fail silently
// and there will be no MMu. It's a good idea to warn the user.
// (see function "WarnUserUMMUNotInstalled" below)
Crew.InitUmmu(GetHandle());
//--------------------------------------------------------------
//--------------------------------------------------------------
// GetUserUMmuVersion
// this check wich version of UMmu addon the user have in his orbiter directory.
// this may be usefull for future version with more function so you can check
// if user installation support the new functions. Return -1 on error (not installed, version cannot be read)
// or version number in float value (ie: 2.0="2.0" version etc etc)
float UMmuVersion=Crew.GetUserUMmuVersion();
//--------------------------------------------------------------
// DefineAirLockShape
// We set the airlock shape and state, this virtual box will be the one
// into were a Ummu asking to reenter will be taken in account
// first parameter is airlock door state (OPEN=TRUE) and other are X,X1,Y,Y1 and Z,Z1
// min and max coordinate for this virtual box (vessel local coordinate)
// Pay attention to reenter when landed (if suitable) and make the box large enough so
// it's not a pain for the user to find airlock's entry. (See PDF doc)
Crew.DefineAirLockShape(FALSE,-3,3,-4,3,3,6); // Airlock open, 2 meter large 4 meter high 6 meter long (vessel local coordinate)
//--------------------------------------------------------------
// SetMembersPositionOrientationOnEVA
// We define here were the Ummu will appear when they make an EVA
// first parameter is position second is orientation, take care not to make
// them appear to high on ground (will fall and die) or to low (Orbiter "light speed" bug)
Crew.SetMembersPosRotOnEVA(_V(0,-1.948,5),_V(0,3,0)); // 3 meters in front of ship (z) facing direction of ship (vessel local coordinate)
//---------------------------------------------------------------
// finally set the maximum seat available in this ship, default is
// 8 but it can go from 1 to 100
// BAD IDEA: using this to "close" your ship, use "SetAirlockDoorState" instead.
Crew.SetMaxSeatAvailableInShip(2);
//----------------------------------------------------------------
// OPTIONAL OPTIONAL OPTIONAL OPTIONAL OPTIONAL OPTIONAL OPTIONAL
// DeclareActionArea
// Ever wanted to be able to open a door, repair a system or trigger something in your vessel from an UMMU ?
// Here come a new feature of UMMU 2.0: Action area. See UMmuSDK.h and PDF doc for complete explanation and see
// "DetectActionAreaActivated" below.
//Crew.DeclareActionArea(0,_V(-28,0,32.8),10,TRUE,"action_door.wav","Open/Close Travel Tube Doors");
//Crew.DeclareActionArea(1,_V(54,0,0),5,TRUE, "action_door.wav","Open/Close Travel Tube Doors");
//Crew.DeclareActionArea(2,_V(61,0,-11.75),2,TRUE, "action_door.wav","Inner AIrlock Active");
//Crew.DeclareActionArea(3,_V(65.5,0,-11.75),2,TRUE, "action_door.wav","Outer AIrlock Active");
//Crew.DeclareActionArea(3,_V(0,0,-5),2.5,TRUE,"action_activated.wav","You are behind the ship");
//iActionAreaDemoStep=0; // this is just to show a feature of action area, see below "DetectActionAreaActivated"
//--------------------------------------------------------------
// AddCrewMember
// We'll add four default members for when the ship is spawned by Orbiter's scenario editor.
// parameters are name, age, cardiac pulse,weight (in kilogramm) and Function (Misc ID)
// max four characters wich define the spacesuit used. (see UmmuMiscID in UMuSDK.h header)
// Return 1 on success -1 on error (probably vessel full, name>25 char
// age, pulse or weight out of realistic range or MiscID>4 char)
Crew.AddCrewMember("Peter Falcon",41,65,74,"Capt"); //(for name and id a-z A-Z 0-9 characters only)
Crew.AddCrewMember("Fanny Gorgeous",27,67,55,"Eng"); //(for name and id a-z A-Z 0-9 characters only)
Crew.AddCrewMember("George HealGood",15,70,45,"Doc"); //(for name and id a-z A-Z 0-9 characters only)
Crew.AddCrewMember("Albert Jr Falcon",15,70,45); //(for name and id a-z A-Z 0-9 characters only)
SelectedUmmuMember =0; // our current selected member
// The HUD display method variables, see PDF doc
cUmmuHudDisplay[0] =0; // Initialisation of UMmu hud char variable
dHudMessageDelay =0; // Initialisation of UMmu delay variable
strcpy(SendHudMessage(),"Welcome aboard ! E=EVA 1,2=select UMmu D=Open/Close airlock S=info M=add crew");
// The Add mmu without scenery editor variable see PDF doc
cAddUMmuToVessel[0]=0;
}
DLLCLBK void ovcSetClassCaps (VESSEL *vessel, FILEHANDLE cfg)
{
((EAGLE3*)vessel)->SetTransporter();
}
void EAGLE3::clbkPostStep(double simt, double simdt, double mjd)
{
//---------------------------------------------------------------------------
// ProcessUniversalMMu
// Here the routine that detect if someone entered the ship (eva or transfer)
// No need to manage anything here all is automatic, crew is added to your ship, ship's weight is updated,
// and UMmu vessel is automatically deleted from Orbiter. You may just look the return
// code to see if someone entered and display wathewer message on panel or other.
// notice it's FPS friendly, function process only 4 time per second not each frame
// and return immediately if airlock closed or no Ummu is detected in vincinity.
int ReturnCode=Crew.ProcessUniversalMMu();
switch(ReturnCode)
{
case UMMU_TRANSFERED_TO_OUR_SHIP:
sprintf(SendHudMessage(),"%s \"%s\" aged %i was transfered to our ship",
Crew.GetCrewMiscIdByName(Crew.GetLastEnteredCrewName()),Crew.GetLastEnteredCrewName()
,Crew.GetCrewAgeByName(Crew.GetLastEnteredCrewName()));
break;
case UMMU_RETURNED_TO_OUR_SHIP:
sprintf(SendHudMessage(),"%s \"%s\" aged %i entered into our ship",
Crew.GetCrewMiscIdByName(Crew.GetLastEnteredCrewName()),
Crew.GetLastEnteredCrewName(),Crew.GetCrewAgeByName(Crew.GetLastEnteredCrewName()));
break;
}
if(GroundContact()==TRUE)
{
// we check vertical speed
//int I;
VECTOR3 vHorizonAirspeedVector={0};
GetHorizonAirspeedVector (vHorizonAirspeedVector);
double VertSpeed =vHorizonAirspeedVector.y;
if(VertSpeed<-3)
{
// we touched ground with more than -3 m/s, sorry dude, time to kill you all :(
//for(I=0;I<Crew.GetCrewTotalNumber();I++)
//{
// Crew.SetCrewMemberPulseBySlotNumber(I,0); // set cardiac pulse to zero
// }
// strcpy(SendHudMessage(),"Oooh no ! Crash - All crew aboard killed");
}
// TIPS: the vertical speed is often reset to zero when there is ground contact
// this may bug somewhat the death of your crew.
// to have an accurate VertSpeed at touchdown I recommand to record it at very END
// of timestep and use this "old" value. The next frame you'll have the vertspeed value
// of *last frame* just before the crash (GroundContact). This ensure an accurate
// verticalspeed value. (keep this value in your vessel class and don't forget to
// initialize it at zero in setclasscap)
}
sprintf(oapiDebugString(),"anim %2.2f", stage);
//---------------------------------------------------------------------------
// WarnUserUMMUNotInstalled - IMPORTANT helper
// Put here this function and users will be automatically warned if they don't have
// UMMU installed or if it's outdated. Warning text duration is 20 seconds and text is:
// [AddonName] require "Universal MMU" ver 2.0 or higher. Download at www.orbiter.dansteph.com (message countdown in seconds)
// an additonal "your version of UMMU is outdated" is displayed the last 5 seconds if they have version lower than 2.0
Crew.WarnUserUMMUNotInstalled("EAGLE3");
// THIS IS FOR ADDING CREW SEE PDF doc "Allow user to add crew to your ship
// without scenery editor"
AddUMmuToVessel();
if (GEAR_status >= GEAR_RAISING) {
double da = simdt * LIFT_SPEED;
if (GEAR_status == GEAR_RAISING) {
if (GEAR_proc > 0.0) GEAR_proc = max (0.0, GEAR_proc-da);
else GEAR_status = GEAR_UP;
} else {
if (GEAR_proc < 1.0) GEAR_proc = min (1.0, GEAR_proc+da);
else GEAR_status = GEAR_DOWN;
}
SetAnimation (anim_gear, GEAR_proc);
}
if (DOOR_status >= DOOR_RAISING) {
double da = simdt * LIFT_SPEED;
if (DOOR_status == DOOR_RAISING) {
if (DOOR_proc > 0.0) DOOR_proc = max (0.0, DOOR_proc-da);
else DOOR_status = DOOR_UP;
} else {
if (DOOR_proc < 1.0) DOOR_proc = min (1.0, DOOR_proc+da);
else DOOR_status = DOOR_DOWN;
}
SetAnimation (anim_adoor, DOOR_proc);
SetAnimation (anim_adoor1, DOOR_proc);
}
if (BUGHATCH_proc==1){
if (BUG_status >= DOOR_RAISING) {
double da = simdt * LIFT_SPEED;
if (BUG_status == DOOR_RAISING) {
if (BUG_proc > 0.0) BUG_proc = max (0.0, BUG_proc-da);
else BUG_status = DOOR_UP;
} else {
if (BUG_proc < 1.0) BUG_proc = min (1.0, BUG_proc+da);
else BUG_status = DOOR_DOWN;
}
SetAnimation (anim_BUG, BUG_proc);
}
}
if (BUG_proc==0){
if (BUGHATCH_status >= DOOR_RAISING) {
double da = simdt * LIFT_SPEED;
if (BUGHATCH_status == DOOR_RAISING) {
if (BUGHATCH_proc > 0.0) BUGHATCH_proc = max (0.0, BUGHATCH_proc-da);
else BUGHATCH_status = DOOR_UP;
} else {
if (BUGHATCH_proc < 1.0) BUGHATCH_proc = min (1.0, BUGHATCH_proc+da);
else BUGHATCH_status = DOOR_DOWN;
}
SetAnimation (anim_BUGdoor, BUGHATCH_proc);
}}
if (DOOR1_status >= DOOR_RAISING) {
double da = simdt * LIFT_SPEED;
if (DOOR1_status == DOOR_RAISING) {
if (DOOR1_proc > 0.0) DOOR1_proc = max (0.0, DOOR1_proc-da);
else DOOR1_status = DOOR_UP;
} else {
if (DOOR1_proc < 1.0) DOOR1_proc = min (1.0, DOOR1_proc+da);
else DOOR1_status = DOOR_DOWN;
}
SetAnimation (anim_adoor2, DOOR1_proc);
SetAnimation (anim_adoor3, DOOR1_proc);
}
//if (DOOR3_status >= DOOR_RAISING) {
// double da = simdt * LIFT_SPEED;
// if (DOOR3_status == DOOR_RAISING) {
// if (DOOR3_proc > 0.0) DOOR3_proc = max (0.0, DOOR3_proc-da);
// else DOOR3_status = DOOR_UP;
// } else {
// if (DOOR3_proc < 1.0) DOOR3_proc = min (1.0, DOOR3_proc+da);
// else DOOR3_status = DOOR_DOWN;
// }
//SetAnimation (anim_adoor6, DOOR3_proc);
//SetAnimation (anim_adoor7, DOOR3_proc);
//SetAnimation (anim_fdoor6, DOOR3_proc);
//SetAnimation (anim_fdoor7, DOOR3_proc);
//}
//
SetTouchdownPoints (_V(0,-3.124+GEAR_proc*1.5,8.7), _V(-2,-3.124+GEAR_proc*1.5,-9.6), _V(2,-3.124+GEAR_proc*1.5,-9.6));
//radar
double db = simdt * radar_speed;
radar_proc += db;
if( radar_proc > 1.0 )
radar_proc = 0;
// SetAnimation( anim_radar, radar_proc );
double dc = simdt * light_SPEED;
light_proc += dc;
if( light_proc > 1.0 )
light_proc = 0;
SetAnimation( anim_light, light_proc );
{BUG_pos.y=BUG_INT_POS-((BUG_proc)*2.533);
SetAttachmentParams(BUG,BUG_pos,_V(0,-1,0),_V(1,0,0));
}
//if (GetAttachmentStatus(P1))
//{
// const char *id = GetAttachmentId (GetAttachmentStatus(P1));
//if(!strcmp (id, "XS" ))POD=1;
//}
//else{
//something already attached
//}
if (GetAttachmentStatus(P1)){
// Get the handle and vessel pointer for the other ship
OBJHANDLE hOtherShip = GetAttachmentStatus(P1);
VESSEL * pOtherShip = oapiGetVesselInterface(hOtherShip);
// loop over all to-parent attachments on the other ship
for (int i = 0; i < pOtherShip->AttachmentCount(true); i++)
{
ATTACHMENTHANDLE hCurAttachment = pOtherShip->GetAttachmentHandle(true, i);
// skip any attach point that isn't attached to us
if (pOtherShip->GetAttachmentStatus(hCurAttachment) != GetHandle())
continue;
// check for the attachment ID and set stage = 3 if it starts with "XS"
const char *id = pOtherShip->GetAttachmentId (hCurAttachment);
if(!strncmp (id, "XS", 2))
stage=3;
}
}
}
void EAGLE3::DefineAnimations(void)
{
static UINT EGrp33[3] = {GRP_elevpad1,GRP_elevpad2,GRP_eaglebugrods};//landing gear
static MGROUP_TRANSLATE BUG(0,EGrp33, 3, _V(0,-2.5,0));
anim_BUG = CreateAnimation (0);
AddAnimationComponent (anim_BUG, 0, 1, &BUG);
static UINT EGrp43[2] = {GRP_innerhatch,GRP_outerbuggyhatch};
static MGROUP_ROTATE BUGH (0,EGrp43, 2, _V(-1.12,-.875,-7.599
), _V(1,0,0), (float)(90*RAD));
anim_BUGdoor = CreateAnimation (0);
AddAnimationComponent (anim_BUGdoor, 0, 1, &BUGH);
static UINT EGrp1[7] = {GRP_gear1,GRP_gear2,GRP_gear3,GRP_gear4,GRP_pad1a,GRP_pad2,GRP_gear7};//landing gear
static MGROUP_TRANSLATE gear(0,EGrp1, 7, _V(0,1.52,0));
anim_gear = CreateAnimation (0);
AddAnimationComponent (anim_gear, 0, 1, &gear);
static UINT EGrp2[2] = {GRP_door3a,GRP_door3b};//door3
static MGROUP_TRANSLATE adoor(0,EGrp2, 2, _V(-.5,0,0));
anim_adoor = CreateAnimation (0);
AddAnimationComponent (anim_adoor, 0, 1, &adoor);
static UINT EGrp3[2] = {GRP_door4a,GRP_door4b};//door4
static MGROUP_TRANSLATE adoor1(0,EGrp3, 2, _V(.5,0,0));
anim_adoor1 = CreateAnimation (0);
AddAnimationComponent (anim_adoor1, 0, 1, &adoor1);
static UINT EGrp6[2] = {GRP_door5a,GRP_door5b};//door5
static MGROUP_TRANSLATE adoor2(0,EGrp6, 2, _V(.5,0,0));
anim_adoor2 = CreateAnimation (0);
AddAnimationComponent (anim_adoor2, 0, 1, &adoor2);
static UINT EGrp7[2] = {GRP_door6a,GRP_door6b};//door6
static MGROUP_TRANSLATE adoor3(0,EGrp7, 2, _V(-.5,0,0));
anim_adoor3 = CreateAnimation (0);
AddAnimationComponent (anim_adoor3, 0, 1, &adoor3);
//static UINT EGrp10[4] = {GRP_door1,GRP_door1b,GRP_Edoor2a,GRP_Edoor2b};//door1
// static MGROUP_TRANSLATE adoor6(4,EGrp10, 2, _V(.5,0,0));//
// anim_adoor6 = CreateAnimation (0);
// AddAnimationComponent (anim_adoor6, 0, 1, &adoor6);
// static UINT EGrp11[4] = {GRP_door2,GRP_door2b,GRP_Edoor1a,GRP_Edoor1b};//door2
// static MGROUP_TRANSLATE adoor7(4,EGrp11, 3, _V(-.5,0,0));
// anim_adoor7 = CreateAnimation (0);
// AddAnimationComponent (anim_adoor7, 0, 1, &adoor7);
static UINT EGrp4[2] = {GRP_light1,GRP_light};
static MGROUP_ROTATE light (0,EGrp4, 2, _V(.007,0,-.616), _V(0,1,0), (float)(360*RAD));
anim_light = CreateAnimation (0);
AddAnimationComponent (anim_light, 0, 1, &light);
// static UINT EGrp5[1] = {GRP_radar};
// static MGROUP_ROTATE radar (0,EGrp5, 1, _V(0,0,6.661), _V(0,1,0), (float)(360*RAD));
// anim_radar = CreateAnimation (0);
// AddAnimationComponent (anim_radar, 0, 1, &radar);
}
DLLCLBK VESSEL *ovcInit (OBJHANDLE hvessel, int flightmodel)
{
return new EAGLE3 (hvessel, flightmodel);
}
DLLCLBK void ovcExit (VESSEL *vessel)
{
if (vessel) delete (EAGLE3*)vessel;
}
// --------------------------------------------------------------
// Keyboard interface handler (buffered key events)
// --------------------------------------------------------------
int EAGLE3::clbkConsumeBufferedKey(DWORD key, bool down, char *kstate)
{
// only process keydown events
if (!down)
return 0;
//---------------------------------------------------------------------------
// Ummu Key "E" perform the EVA of the selected member
//
// ADD REALISM: It's your responsabilities also to set ship's control accordingly to crew aboard.
// If you want to disable control if no one is aboard have a look at "SetADCtrlMode()"
// and "SetAttitudeMode()" functions of Orbiter. To disable thrusters set their fuel
// ressource to NULL.
if(key==OAPI_KEY_E&&!KEYMOD_SHIFT(kstate)&&!KEYMOD_CONTROL (kstate))
{
// PERFORM THE EVA, first we get is name with "GetCrewNameBySlotNumber" then we perform EVA with "EvaCrewMember"
int Returned=Crew.EvaCrewMember(Crew.GetCrewNameBySlotNumber(SelectedUmmuMember));
// we provide feedback to user (You can display a message on panel or wathewer)
// here below all the return code possible:
switch(Returned)
{
case TRANSFER_TO_DOCKED_SHIP_OK:
sprintf(SendHudMessage(),"Transfer to docked ship Ok - %s transfered",
Crew.GetLastEvaedCrewName());SelectedUmmuMember=0;
break;
case EVA_OK:
sprintf(SendHudMessage(),"EVA OK - %s left the ship",
Crew.GetLastEvaedCrewName());SelectedUmmuMember=0;
break;
case ERROR_NO_ONE_ON_BOARD:
strcpy(SendHudMessage(),"Error, no one on board, unable to EVA");
break;
case ERROR_AIRLOCK_CLOSED:
strcpy(SendHudMessage(),"Error, airlock is closed, unable to EVA");
break;
case ERROR_DOCKED_SHIP_HAVE_AIRLOCK_CLOSED:
strcpy(SendHudMessage(),"Error, docked ship's airlock is closed, unable to transfer");
break;
case ERROR_DOCKED_SHIP_IS_FULL:
strcpy(SendHudMessage(),"Error, docked ship is already full transfer failed");
break;
case ERROR_CREW_MEMBER_NOT_FOUND:
strcpy(SendHudMessage(),"Error, no crew by this name in ship");
break;
case ERROR_DOCKEDSHIP_DONOT_USE_UMMU:
strcpy(SendHudMessage(),"Error, docked ship do not use UMmu 2.0, ask author to add it");
break;
case ERROR_MISC_ERROR_EVAFAILED:
strcpy(SendHudMessage(),"Misc error with UMMU install it again");
break;
}
return TRUE;
}
//---------------------------------------------------------------------------
// Ummu Key "1" Select next member This is just internal to the demo
// you may do your own selection system by panel button, name etc etc
if(key==OAPI_KEY_1&&!KEYMOD_SHIFT(kstate)&&!KEYMOD_CONTROL (kstate))
{
// we test there is someone aboard
if(Crew.GetCrewTotalNumber()==0)
{
strcpy(SendHudMessage(),"Sorry no one aboard unable to select");
return 1;
}
// we test that we select existing member
if(SelectedUmmuMember<Crew.GetCrewTotalNumber()-1)
SelectedUmmuMember++;
char * Name=Crew.GetCrewNameBySlotNumber(SelectedUmmuMember);
sprintf(SendHudMessage(),"Slot %i %s \"%s\" aged %i Selected for EVA or Transfer, please press \"E\" to EVA",
SelectedUmmuMember,Crew.GetCrewMiscIdBySlotNumber(SelectedUmmuMember),
Name,Crew.GetCrewAgeBySlotNumber(SelectedUmmuMember));
return 1;
}
//---------------------------------------------------------------------------
// Ummu Key "2" Select previous member This is just internal to the demo
// you may do your own selection system by panel button
if(key==OAPI_KEY_2&&!KEYMOD_SHIFT(kstate)&&!KEYMOD_CONTROL (kstate))
{
// we test there is someone aboard
if(Crew.GetCrewTotalNumber()==0)
{
strcpy(SendHudMessage(),"Sorry no one aboard unable to select");
return 1;
}
if(SelectedUmmuMember>0)
SelectedUmmuMember--;
char * Name=Crew.GetCrewNameBySlotNumber(SelectedUmmuMember);
sprintf(SendHudMessage(),"Slot %i %s \"%s\" aged %i Selected for EVA or Transfer"
", please press \"E\" to EVA",SelectedUmmuMember,
Crew.GetCrewMiscIdBySlotNumber(SelectedUmmuMember),Name,
Crew.GetCrewAgeBySlotNumber(SelectedUmmuMember));
return 1;
}
//---------------------------------------------------------------------------
// Ummu Key "A" Switch the virtual UMMU airlock door on/off
if(key==OAPI_KEY_D&&!KEYMOD_SHIFT(kstate)&&!KEYMOD_CONTROL (kstate))
{
//
Crew.SetAirlockDoorState(!Crew.GetAirlockDoorState());
// display state
if (doorselected==0)
{RevertDOOR ();
if(Crew.GetAirlockDoorState()==TRUE)
strcpy(SendHudMessage(),"Forward Airlock is now open");
else
strcpy(SendHudMessage(),"Forward Airlock is now closed");
}
if (doorselected==1)
{RevertDOOR1();
if(Crew.GetAirlockDoorState()==TRUE)
strcpy(SendHudMessage(),"Rear Airlock is now open");
else
strcpy(SendHudMessage(),"Rear Airlock is now closed");
}
if (doorselected==2)
{
if(Crew.GetAirlockDoorState()==TRUE)
strcpy(SendHudMessage(),"TPADL Airlock is now open");
else
strcpy(SendHudMessage(),"TPADL Airlock is now closed");
}
if (doorselected==3)
{
if(Crew.GetAirlockDoorState()==TRUE)
strcpy(SendHudMessage(),"TPADR Airlock is now open");
else
strcpy(SendHudMessage(),"TPADR Airlock is now closed");
}
if (doorselected==4)
{
if(Crew.GetAirlockDoorState()==TRUE)
strcpy(SendHudMessage(),"APADL Airlock is now open");
else
strcpy(SendHudMessage(),"APADL Airlock is now closed");
}
if (doorselected==5)
{
if(Crew.GetAirlockDoorState()==TRUE)
strcpy(SendHudMessage(),"APADR Airlock is now open");
else
strcpy(SendHudMessage(),"APADR Airlock is now closed");
}
}
//---------------------------------------------------------------------------
// Get some infos Name of ship and total soul aboard
if(key==OAPI_KEY_S)
{
sprintf(SendHudMessage(),"%i souls aboard ship %s, %i seats available",
Crew.GetCrewTotalNumber(),GetName(),2-Crew.GetCrewTotalNumber());
return 1;
}
//---------------------------------------------------------------------------
// ADD some Fun, Eject the guy, No check of all return code here to keep listing small and clear.
// Notice eject function doesn't check airlock state at all.
// GOOD IDEA: Get the Object's handle after ejection with function "GetObjHandleOfLastEVACrew"
// and add to it one very small tank, thruster and smoke, then fire thruster (see pilot ejection of DGIV)
// BAD IDEA: Not testing the handle returned by "GetObjHandleOfLastEVACrew" before using may
// cause a CTD if by any bad luck the pointer is invalid (handle==NULL)
if(key==OAPI_KEY_ESCAPE&&!KEYMOD_SHIFT(kstate)&&!KEYMOD_CONTROL (kstate))
{
if(Crew.EjectCrewMember(Crew.GetCrewNameBySlotNumber(SelectedUmmuMember))==EVA_OK)
sprintf(SendHudMessage(),"%s EJECTED",Crew.GetLastEvaedCrewName());
SelectedUmmuMember=0;
return 1;
}
//---------------------------------------------------------------------------
// Use a different Mesh (type "C" then EVA someone)
// better idea is to use the new UMMU Id definition
// look readme.txt in folder "config/UMMUIdConfig"
if(key==OAPI_KEY_C)
{
Crew.SetAlternateMeshToUseForEVASpacesuit("mmu"); // the stock mmu of orbiter located in "meshes/mmu.msh"
strcpy(SendHudMessage(),"Mesh changed");
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);
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// Get some infos Name of ship and total soul aboard
// change active dock
if(key==OAPI_KEY_9)
{
if(iActiveDockNumber>0)
iActiveDockNumber--;
// sprintf(SendHudMessage(),"Active dock number changed to: %i",iActiveDockNumber);
if(iActiveDockNumber==0) sprintf(SendHudMessage(),"Front Airlock Selected");
if(iActiveDockNumber==1) sprintf(SendHudMessage(),"Rear Airlock Selected");
if(iActiveDockNumber==2) sprintf(SendHudMessage(),"TPADL Airlock Selected");
if(iActiveDockNumber==3) sprintf(SendHudMessage(),"TPADR Airlock Selected");
if(iActiveDockNumber==4) sprintf(SendHudMessage(),"APADL Airlock Selected");
if(iActiveDockNumber==5) sprintf(SendHudMessage(),"APADR Airlock Selected");
SetUMMUAirlockPos();
return 1;
}
//---------------------------------------------------------------------------
// change active dock
if(key==OAPI_KEY_0)
{
if(iActiveDockNumber<5)
iActiveDockNumber++;
// sprintf(SendHudMessage(),"Active dock number changed to: %i",iActiveDockNumber);
if(iActiveDockNumber==0) sprintf(SendHudMessage(),"Front Airlock Selected");
if(iActiveDockNumber==1) sprintf(SendHudMessage(),"Rear Airlock Selected");
if(iActiveDockNumber==2) sprintf(SendHudMessage(),"TPADL Airlock Selected");
if(iActiveDockNumber==3) sprintf(SendHudMessage(),"TPADR Airlock Selected");
if(iActiveDockNumber==4) sprintf(SendHudMessage(),"APADL Airlock Selected");
if(iActiveDockNumber==5) sprintf(SendHudMessage(),"APADR Airlock Selected");
SetUMMUAirlockPos();
return 1;
}
if(key==OAPI_KEY_G)
{// hatch
RevertGEAR();
return 1;
}
if(key==OAPI_KEY_7)
{// hatch
//if (BUG_proc==0)
{
RevertBUGHATCH();
}
return 1;
}
if(key==OAPI_KEY_8)
{
//if (BUGHATCH_proc==1)
{
RevertBUGELEV();
}
return 1;
}
if(key==OAPI_KEY_K)
{do_attach = 1;
AttachCargo();
return 1;
}
if(key==OAPI_KEY_J)
// "Jettison"
{ DetachCargo();
return 1;
}
if(key==OAPI_KEY_N)
{do_attach = 1;
AttachBUGGY();
return 1;
}
if(key==OAPI_KEY_B)
// "Jettison"
{ DetachBUGGY();
return 1;
}
if(key==OAPI_KEY_V)
{
{SelectCockpitView(CAM);
CAM = CAM + 1;
if(CAM > 2) CAM = 0;
}
return 1;
}
return 0;
}
// ====================================================================
// clbkVisualCreated used to display UMMU initialisation message
// because oapiDebugString() doesn't work in clbkSetClassCap
// ====================================================================
void EAGLE3::clbkVisualCreated (VISHANDLE vis, int refcount)
{
MainExternalMeshVisual = GetMesh(vis,0);
}
// ==============================================================
// Visual destroyed
// ==============================================================
void EAGLE3::clbkVisualDestroyed (VISHANDLE vis, int refcount)
{
MainExternalMeshVisual = 0;
}
void EAGLE3::RevertGEAR (void)
{
GEAR_status = ((GEAR_status == GEAR_UP || GEAR_status == GEAR_RAISING) ?
GEAR_LOWERING : GEAR_RAISING);
}
void EAGLE3::RevertDOOR (void)
{
DOOR_status = ((DOOR_status == DOOR_UP || DOOR_status == DOOR_RAISING) ?
DOOR_LOWERING : DOOR_RAISING);
}
void EAGLE3::RevertDOOR1 (void)
{
DOOR1_status = ((DOOR1_status == DOOR_UP || DOOR1_status == DOOR_RAISING) ?
DOOR_LOWERING : DOOR_RAISING);
}
void EAGLE3::RevertDOOR2 (void)
{
DOOR2_status = ((DOOR2_status == DOOR_UP || DOOR2_status == DOOR_RAISING) ?
DOOR_LOWERING : DOOR_RAISING);
}
void EAGLE3::RevertBUGHATCH (void)
{
BUGHATCH_status = ((BUGHATCH_status == DOOR_UP || BUGHATCH_status == DOOR_RAISING) ?
DOOR_LOWERING : DOOR_RAISING);
}
void EAGLE3::RevertBUGELEV (void)
{
BUG_status = ((BUG_status == DOOR_UP || BUG_status == DOOR_RAISING) ?
DOOR_LOWERING : DOOR_RAISING);
}
void EAGLE3::RevertDOOR3 (void)
{
DOOR3_status = ((DOOR3_status == DOOR_UP || DOOR3_status == DOOR_RAISING) ?
DOOR_LOWERING : DOOR_RAISING);
}
void EAGLE3::AttachCargo(){
VECTOR3 aphpos, aphdir, aphrot, gaph;
VECTOR3 shippos, shipdir, shiprot, gpship;
// get attachment point positions based on selected point
{
GetAttachmentParams(P1,aphpos, aphdir, aphrot);
}
// change the position to a global one rather then a local one. This will allow me to offset it from the local center.
// the local position is stored in gaph
Local2Global (aphpos, gaph);
//I now know were the attach point is in the global world
//Now lets find out if there is a skid in range
// Search the complete vessel list for a grappling candidate.
// Not very scalable ...
for (DWORD i = 0; i < oapiGetVesselCount(); i++) {
OBJHANDLE hV = oapiGetVesselByIndex (i); //get handle for ship
// if (strncmp (hV->GetClassName(), "QJFFS", 5)!=0 ){ //restrict to only QuadJ ships to make it easy.
// Look for any ship with a child attach point. This allows the Mule to grap any object
if (hV == GetHandle()) continue; // If self then continue onward because we don't want to grapple ourselves ...
oapiGetGlobalPos (hV, &gpship); // get global postion of ship and put into gpship
VESSEL *v = oapiGetVesselInterface (hV);
// Only look for child attach point
DWORD nAttach = v->AttachmentCount (true); //Get attachment count. I do this so that I can grap any child point.
if (nAttach > 0){ // Only continue if ship has a child attach point
for (DWORD j = 0; j < nAttach; j++) { // now scan all attachment points of the candidate and check how far away from the attach point it is
ATTACHMENTHANDLE hAtt = v->GetAttachmentHandle (true, j);
/* this would allow me to filter out all but QJ ships but I don't want to right now
const char *id = v->GetAttachmentId (hAtt);
if (strncmp (id, "GS", 2)) continue; // attachment point not compatible
*/
v->GetAttachmentParams (hAtt, shippos, shipdir, shiprot); //lets get the attach point position
v->Local2Global (shippos, gpship); // and change it to a global position Recycle of gpship cause I can
if (dist (gpship, gaph) < MAX_GRAP_DIST) { // Is it close enough to grab?
apd = dist(gpship, gaph);
// Yes! Then lets grab the little bugger and get out of here
const char *id = v->GetAttachmentId (hAtt);
(do_attach=0);
if(!strncmp (id, "TOP", 3))
{do_attach=1;}
if(!strncmp (id, "XS", 2))
{do_attach=1;
}
if(do_attach > 0){
do_attach = 0;
if ((v->GetAttachmentStatus(hAtt))||(GetAttachmentStatus(P1))) {
// do nothing;
}else{
AttachChild (hV, P1, hAtt);
break;
}
return;
}
}// <-- removed return from here
}}
} // End of for j
}
void EAGLE3::DetachCargo ()
{
DetachChild(P1,0);
stage=1;
}
void EAGLE3::AttachBUGGY(){
VECTOR3 aphpos, aphdir, aphrot, gaph;
VECTOR3 shippos, shipdir, shiprot, gpship;
// get attachment point positions based on selected point
{
GetAttachmentParams(P1,aphpos, aphdir, aphrot);
}
// change the position to a global one rather then a local one. This will allow me to offset it from the local center.
// the local position is stored in gaph
Local2Global (aphpos, gaph);
//I now know were the attach point is in the global world
//Now lets find out if there is a skid in range
// Search the complete vessel list for a grappling candidate.
// Not very scalable ...
for (DWORD i = 0; i < oapiGetVesselCount(); i++) {
OBJHANDLE hV = oapiGetVesselByIndex (i); //get handle for ship
// if (strncmp (hV->GetClassName(), "QJFFS", 5)!=0 ){ //restrict to only QuadJ ships to make it easy.
// Look for any ship with a child attach point. This allows the Mule to grap any object
if (hV == GetHandle()) continue; // If self then continue onward because we don't want to grapple ourselves ...
oapiGetGlobalPos (hV, &gpship); // get global postion of ship and put into gpship
VESSEL *v = oapiGetVesselInterface (hV);
// Only look for child attach point
DWORD nAttach = v->AttachmentCount (true); //Get attachment count. I do this so that I can grap any child point.
if (nAttach > 0){ // Only continue if ship has a child attach point
for (DWORD j = 0; j < nAttach; j++) { // now scan all attachment points of the candidate and check how far away from the attach point it is
ATTACHMENTHANDLE hAtt = v->GetAttachmentHandle (true, j);
/* this would allow me to filter out all but QJ ships but I don't want to right now
const char *id = v->GetAttachmentId (hAtt);
if (strncmp (id, "GS", 2)) continue; // attachment point not compatible
*/
v->GetAttachmentParams (hAtt, shippos, shipdir, shiprot); //lets get the attach point position
v->Local2Global (shippos, gpship); // and change it to a global position Recycle of gpship cause I can
if (dist (gpship, gaph) < MAX_GRAP_DIST) { // Is it close enough to grab?
apd = dist(gpship, gaph);
// Yes! Then lets grab the little bugger and get out of here
const char *id = v->GetAttachmentId (hAtt);
(do_attach=0);
if(!strncmp (id, "BUG", 3))
{do_attach=1;}
if(do_attach > 0){
do_attach = 0;
if ((v->GetAttachmentStatus(hAtt))||(GetAttachmentStatus(BUG))) {
// do nothing;
}else{
AttachChild (hV, BUG, hAtt);
break;
}
return;
}
}// <-- removed return from here
}}
} // End of for j
}
void EAGLE3::DetachBUGGY ()
{
DetachChild(BUG,0);
}
// --------------------------------------------------------------
// Orbiter's HUD callback
// used to display UMMU's message see PDF doc:
// "Example of feedback method by HUD Display"
// --------------------------------------------------------------
void EAGLE3::clbkDrawHUD (int mode, const HUDPAINTSPEC *hps, HDC hDC)
{
// draw the default HUD
VESSEL2::clbkDrawHUD (mode, hps, hDC);
// UMmu display messages
if(dHudMessageDelay>0)
{
TextOut (hDC,5,hps->H/60*15,cUmmuHudDisplay,strlen(cUmmuHudDisplay));
dHudMessageDelay-=oapiGetSimStep();
if(dHudMessageDelay<0)
dHudMessageDelay=0;
}
}
void EAGLE3::clbkSaveState(FILEHANDLE scn)
{
char cbuf[256];
// ORBITER, default vessel parameters
SaveDefaultState (scn);
sprintf (cbuf, "%d %0.4f", GEAR_status, GEAR_proc);
oapiWriteScenario_string (scn, "GEAR", cbuf);
sprintf (cbuf, "%d %0.4f", BUGHATCH_status, BUGHATCH_proc);
oapiWriteScenario_string (scn, "BUGHATCH", cbuf);
sprintf (cbuf, "%d %0.4f", BUG_status, BUG_proc);
oapiWriteScenario_string (scn, "BUG", cbuf);
// UMmu, this will save all our members of crew in scenario
// as airlock state depend of your ship (you may have a real animated airlock)
// it's your responsabilites to save and reload UMmu's airlock state.
Crew.SaveAllMembersInOrbiterScenarios(scn);
}
void EAGLE3::clbkLoadStateEx (FILEHANDLE scn, void *status)
{
char *line;
while (oapiReadScenario_nextline (scn, line))
{
// UMMU, Load all saved member from scenario.
// Return TRUE when a "UMMUCREW" line is encountered
// FALSE when it must pass this line to you or default parser
if(Crew.LoadAllMembersFromOrbiterScenario(line)==TRUE)
continue;
if (!_strnicmp (line, "GEAR", 4)) {
sscanf (line+4, "%d%lf", &GEAR_status, &GEAR_proc);
}
if (!_strnicmp (line, "BUGHATCH", 8)) {
sscanf (line+8, "%d%lf", &BUGHATCH_status, &BUGHATCH_proc);
}
if (!_strnicmp (line, "BUG", 3)) {
sscanf (line+3, "%d%lf", &BUG_status, &BUG_proc);
}
// ORBITER, unrecognised option - pass to Orbiter's generic parser
ParseScenarioLineEx (line, status);
}
SetAnimation (anim_gear, GEAR_proc);
SetAnimation (anim_BUG, BUG_proc);
SetAnimation (anim_BUGdoor, BUGHATCH_proc);
// as airlock state depend of your ship (you may have a real animated airlock)
// it's your responsabilites to save and reload UMmu airlock state and set it accordingly
// to your airlock. IE: call here "SetAirlockDoorState" TRUE of FALSE depend
// of your animated airlock
}
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 EAGLE3::AddUMmuToVessel(BOOL bStartAdding)
{
if(bStartAdding==FALSE&&cAddUMmuToVessel[0]==0)
return;
if(bStartAdding==TRUE){
int salut=sizeof(cAddUMmuToVessel);
memset(cAddUMmuToVessel,0,sizeof(cAddUMmuToVessel));
cAddUMmuToVessel[0]=1;
}
else if(cAddUMmuToVessel[0]==1){
cAddUMmuToVessel[0]=2;
oapiOpenInputBox ("Enter new crew's name (or escape)",UMmuCrewAddCallback,0,30,(void*)cAddUMmuToVessel);
}
else if(cAddUMmuToVessel[0]==3){
cAddUMmuToVessel[0]=4;
oapiOpenInputBox ("Enter crew's age",UMmuCrewAddCallback,0,30,(void*)cAddUMmuToVessel);
}
else if(cAddUMmuToVessel[0]==5){
cAddUMmuToVessel[0]=6;
oapiOpenInputBox ("Enter function (Capt,Sec,Vip,Sci,Doc,Tech,Crew,Pax)",UMmuCrewAddCallback,0,30,(void*)cAddUMmuToVessel);
}
else if(cAddUMmuToVessel[0]==7){
cAddUMmuToVessel[0]=0;
int Age=max(5,min(100,atoi(&cAddUMmuToVessel[42])));
if(Crew.AddCrewMember(&cAddUMmuToVessel[2],Age,70,70,&cAddUMmuToVessel[82])==TRUE){
sprintf(SendHudMessage(),"Crew \"%s\" aged %i added to vessel",&cAddUMmuToVessel[2],Age);
}
else{
strcpy(SendHudMessage(),"ERROR: Crew not added (vessel full?)");
}
}
}
// END of "Allow user to add crew to your ship without scenery editor"
//-------------------------------------------------------------------------
void EAGLE3::Estado()
{
HoverSmoke=PasarLosHumos(HoverSmoke);
}