I just read the UMMU SDK for tips and help on how to implement it in my .dll. It was a relatively easy procedure involving copy/paste. I did everything the document said to, but with only partial success. I know even if it compiles that it still doesn't mean it will work properly. Better than nothing though. I am going to post the code I have (most of it) to see if you guys can spot an error. Another useful note is that when Orbiter starts I do not get no response from UMMU. I tried pressing A for airlock then E for the EVA, but that didn't work either.
Here is the code.
Sorry for how long the code is, but it is relevant. :shrug:
Here is the code.
Code:
class Spacecraft: public VESSEL3 {
public:
Spacecraft (OBJHANDLE hObj, int fmodel);
void DefineAnimations (void);
void clbkPostCreation (void);
void clbkDrawHUD (int mode, const HUDPAINTSPEC *hps, HDC hDC);
void clbkSaveState(FILEHANDLE scn);
void clbkLoadStateEx (FILEHANDLE scn, void *status);
// Overloaded callback functions
void clbkSetClassCaps (FILEHANDLE cfg);
void clbkPostStep (double simt, double simdt, double mjd);
int clbkConsumeBufferedKey (DWORD key, bool down, char *kstate);
UINT anim_eng;
int MySoundID;
// 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.
// The HUD display method variable, see PDF doc
char cUmmuHudDisplay[255]; // UMmu hud char variable
double dHudMessageDelay; // UMmu hud display delay
char *SendHudMessage(void); // UMmu hud display function
// THIS IS FOR ADDING CREW SEE PDF doc "Allow user to add crew to your ship
// without scenery editor"
char cAddUMmuToVessel[255];
void AddUMmuToVessel(BOOL bStartAdding=FALSE);
};
Code:
void Spacecraft::clbkSaveState(FILEHANDLE scn)
{
// ORBITER, default vessel parameters
SaveDefaultState (scn);
// 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);
}
///////////////////////////////////////////////////////////////////////////////////////////
// clbkLoadStateEx function of Orbiter - Load Orbiter scenario !REQUIRED!
// ---------------
// Here we'll reload all crew member of our ship.
// notice the function will ERASE all defaults member set in clbkSetClassCaps.
// If you really want to add default crew add them also in this fonction after loading
// (when a ship is spawned by editor anyway this fonction below is never called)
///////////////////////////////////////////////////////////////////////////////////////////
void Spacecraft::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;
// ORBITER, unrecognised option - pass to Orbiter's generic parser
ParseScenarioLineEx (line, status);
}
// 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
}
Code:
void Spacecraft::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;
}
//----------------------------------------------------------------------------
// OPTIONAL OPTIONAL OPTIONAL OPTIONAL OPTIONAL OPTIONAL OPTIONAL
// DetectActionAreaActivated
// This function will detect one keypress of UMMU inside one action area (see "DeclareActionArea" above)
// It can be used to open doors, activate things, repair system etc. etc.
int ActionAreaReturnCode=Crew.DetectActionAreaActivated();
if(ActionAreaReturnCode>-1)
{
// this is just an example, we have four area declared
// action area ID 0 triggered
if(ActionAreaReturnCode==0)
{
// do something cool here
}
// action area ID 1 triggered
else if(ActionAreaReturnCode==1)
{
// As you can edit action area in real time: relocation, sound, text, state
// the possiblity are endless. you can for example order a UMMU to go to an external panel
// and open it, then go to engine exhaust and "repair" it then back to panel to close it etc.
if(iActionAreaDemoStep==0)
{
Crew.SetActionAreaText(1,"You are still on the right but this is 2nd keypress");
iActionAreaDemoStep++;
// do something cool here
}
else if(iActionAreaDemoStep==1)
{
// remember you change action area's parameter for the NEXT keypress of UMMU
Crew.SetActionAreaText(1,"You are still on the right but this is 3rd keypress");
iActionAreaDemoStep++;
// do something cool here
}
else
{
Crew.SetActionAreaText(1,"You are still on the right but this is last keypress");
// and of course you can change sound, location, state, text, here some examples:
//Crew.SetActionAreaPos(1,_V(5,0,5)); // change location
//Crew.SetActionAreaWav(1,"MyAddon\PlayRepaired.wav"); // change sound
//Crew.SetActionAreaWav(1,"MyAddon\DoorClosed.wav"); // change sound
//Crew.SetActionAreaText(1,NULL); // sound or text are not mandatory, here we set no text.
// etc. etc.
}
}
// action area ID 2 triggered
else if(ActionAreaReturnCode==2)
{
// do something cool here
}
// action area ID 3 triggered
else if(ActionAreaReturnCode==3)
{
// do something cool here
}
// THIS IS FOR ADDING CREW SEE PDF doc "Allow user to add crew to your ship
// without scenery editor"
AddUMmuToVessel();
}
Code:
//--------------------------------------------------------------
// 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(TRUE,-1,1,-1,3,-2,4); // 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,0,3),_V(0,0,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(8);
//----------------------------------------------------------------
// 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(-5,0,0),2.5,TRUE,"action_activated.wav","You are on the left of the ship");
Crew.DeclareActionArea(1,_V(5,0,0),2.5,TRUE, "action_repaired.wav","You are on the right of the ship");
Crew.DeclareActionArea(2,_V(0,0,5),2.5,TRUE, "action_activated.wav","You are in front of the ship");
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 A=Open/Close airlock S=info M=add crew");
// The Add mmu without scenery editor variable see PDF doc
cAddUMmuToVessel[0]=0;
Code:
int Spacecraft::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_A&&!KEYMOD_SHIFT(kstate)&&!KEYMOD_CONTROL (kstate))
{
// switch state
Crew.SetAirlockDoorState(!Crew.GetAirlockDoorState());
// display state
if(Crew.GetAirlockDoorState()==TRUE)
strcpy(SendHudMessage(),"Airlock is now open");
else
strcpy(SendHudMessage(),"Airlock is now closed");
return 1;
}
//---------------------------------------------------------------------------
// Get some infos Name of ship and total soul aboard
if(key==OAPI_KEY_S)
{
sprintf(SendHudMessage(),"%i souls aboard ship %s, %i seats available",
Crew.GetCrewTotalNumber(),GetName(),4-Crew.GetCrewTotalNumber());
return 1;
}
//---------------------------------------------------------------------------
// ADD some Fun, Eject the guy, No check of all return code here to keep listing small and clear.
// Notice eject function doesn't check airlock state at all.
// GOOD IDEA: Get the Object's handle after ejection with function "GetObjHandleOfLastEVACrew"
// and add to it one very small tank, thruster and smoke, then fire thruster (see pilot ejection of DGIV)
// BAD IDEA: Not testing the handle returned by "GetObjHandleOfLastEVACrew" before using may
// cause a CTD if by any bad luck the pointer is invalid (handle==NULL)
if(key==OAPI_KEY_ESCAPE&&!KEYMOD_SHIFT(kstate)&&!KEYMOD_CONTROL (kstate))
{
if(Crew.EjectCrewMember(Crew.GetCrewNameBySlotNumber(SelectedUmmuMember))==EVA_OK)
sprintf(SendHudMessage(),"%s EJECTED",Crew.GetLastEvaedCrewName());
SelectedUmmuMember=0;
return 1;
}
//---------------------------------------------------------------------------
// 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);
}
return 0;
}
//
// --------------------------------------------------------------
// Orbiter's HUD callback
// used to display UMMU's message see PDF doc:
// "Example of feedback method by HUD Display"
// --------------------------------------------------------------
void Spacecraft::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;
}
}
//------------------------------------------------------------------------------------------------------------------
// UTILITY FONCTION - UTILITY FONCTION - UTILITY FONCTION - UTILITY FONCTION - UTILITY FONCTION
//
// This below is not mandatory for UMmu to run, anyway such functions can help you to implement UMmu
// in your addon. A recommended read at least.
//
//------------------------------------------------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////////////////
// USING HUD INTERFACE FOR FEEDBACK DISPLAY
//
// This method is explained in the PDF tutorial, now if you want to use another method
// comment the "UMMU" display lines in clbkHudDraw above and use the char variable
// "cUmmuHudDisplay" wich will contain all the messages of UMMU to display it on VC or panel.
// No other change required in code.
///////////////////////////////////////////////////////////////////////////////////////////
char *Spacecraft::SendHudMessage()
{
dHudMessageDelay=15;
return cUmmuHudDisplay;
}
//-------------------------------------------------------------------------
// THIS IS FOR ADDING CREW SEE PDF doc "Allow user to add crew to your ship
// without scenery editor"
bool UMmuCrewAddCallback(void *id, char *str, void *data)
{
if(strlen(str)<2||strlen(str)>38)
return false;
char *cPtr=(char*)data; if(*cPtr==2){*cPtr=3;strcpy(cPtr+2,str);}
else if(*cPtr==4){*cPtr=5;strcpy(cPtr+42,str);}
else if(*cPtr==6){*cPtr=7;strcpy(cPtr+82,str);}return true;
}
void Spacecraft::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"
//-------------------------------------------------------------------------
Sorry for how long the code is, but it is relevant. :shrug: