#### MJR

##### C++ developer in the mix
Tutorial Publisher
Donator
I was wondering if anyone is interested or at least willing to help me with the development of a custom .dll module of a warhead. I have seen others do it in SDK, but it way to confusing considering how much stuff their header file implies. I want something unique that could stand above other designs.

Also, how does Orbiter know how to "Explode" and things like that. Is it in the API?

All I really need help with is making that one module and animating an explosion with maybe some of effects. It is really lame seeing my mesh flying at 5k/s and hitting the ground uncontrollably doing nothing. It would be way more playable if it was as interactive as something like the Project R-7 warhead missions. Plus, I do not want to copy someones code and act like it is mine because there is no satisfaction in that.

Last edited:

#### Wishbone

##### Clueless developer
Two things any warhead (more or less) needs: zero-AoA re-entry and spin-stabilization. Small aft air control surface will suffice, but without zero-AoA the RV is kinda useless. I'm leafing through AeroBrake MFD source code to try to predict impact point before separation.

#### MJR

##### C++ developer in the mix
Tutorial Publisher
Donator
Most definitively. I need to add that to my code. My main thing as of now is the explosion animation. Maybe after that make the blast affect meshes around it and etc. If you got anymore tips like that do tell. :thumbup:

#### jedidia

##### shoemaker without legs
To trigger the explosion, I think you'll be best off checking for altitude, and detonate it as soon as you've gone beneath a trigger altitude.

#### Urwumpe

##### Not funny anymore
Donator
To trigger the explosion, I think you'll be best off checking for altitude, and detonate it as soon as you've gone beneath a trigger altitude.

As well as arm the warhead on vehicle computer command.

#### RisingFury

##### OBSP developer
To trigger the explosion, I think you'll be best off checking for altitude, and detonate it as soon as you've gone beneath a trigger altitude.

That was how escapetomsfate did it in OBSP at first, but it's not 100% reliable. Now we check for ground contact of touchdown points or something like that...

#### jedidia

##### shoemaker without legs
That was how escapetomsfate did it in OBSP at first, but it's not 100% reliable. Now we check for ground contact of touchdown points or something like that...

Interesting... I supposed that altitude checking should be more reliable, because it's a less momentual event and has greater chances of being detected, while ground contact at high speeds can be rather momentarily (with all that jumping back to solar orbit and stuff). Seems like I was wrong.

#### MJR

##### C++ developer in the mix
Tutorial Publisher
Donator
My question is though, how does Orbiter know how to do those types of commands? I understand a lot of the Orbiter related code, but do I just put something like void MIRV: Detonate()......

#### RisingFury

##### OBSP developer
Interesting... I supposed that altitude checking should be more reliable, because it's a less momentual event and has greater chances of being detected, while ground contact at high speeds can be rather momentarily (with all that jumping back to solar orbit and stuff). Seems like I was wrong.

It might work well for a single model, but in our case you need to consider that we're planning to allow weapons to be added through SC3 config style. That means you can have events where the ground contact points would always force the vessel to be above a detonation altitude.

My question is though, how does Orbiter know how to do those types of commands? I understand a lot of the Orbiter related code, but do I just put something like void MIRV: Detonate()......

Ok, let's say you have a vessel:
Code:
class MyVessel : public VESSEL3

Code:
class MyVessel : public VESSEL3
{
public:
MyVessel() {Active = false};
~MyVessel();

void PreStep(double SimTime, double SimDeltaTime, double MJD);

private:
void Detonate();    // You don't want someone else to detonate you, right? ;)
bool Active;        // You want some sort of on-off switch, so you don't detonate before you get off the ground.

Now, let's say you go for altitude based trigger for detonation, then you'd define your PreStep like this:

Code:
void MyVessel::PreStep(double SimTime, double SimDeltaTime, double MJD)
{
// First off you figure out if you've *ever* left the ground.
// You don't wanna detonate before you launch.

if (Active == false)
{

if (GetAltitude() > 10)
{

Active = true;
}
}

// Now check if check if you've come under 10 meters, so you can detonate.

if ((Active == true) && (GetAltitude() < 10))
{
// Your warhead has been activated and you're now under 10 meters in altitude.
// Time to detonate.

Detonate();
}
}

That gives you a simple system that activates your warhead after launch, when it gets over 10 meters in altitude and then detonates it once it's active and under 10 meters. Once the conditions for detonation are met, the function Detonate() is called. Now you need to define that. I can't define the function in C++, but I will give you some comment hints on how I'd do it:

Code:
void MyVessel::Detonate()
{
// First thing you do is delete the existing mesh.
// Then define an exhaust stream with the exhaust that looks like an explosion. Delete it later, once the explosion is done.
// Also define an exhaust stream that acts as smoke from the crash site.
// Go into VESSELSTATUS and set status to inactive and latitude and longitute to where the vessel is right now, so your explosion won't move around...
// Play a sound...
// Anything you think would be cool...
}

I hope that gave you a general idea

#### MJR

##### C++ developer in the mix
Tutorial Publisher
Donator
It might work well for a single model, but in our case you need to consider that we're planning to allow weapons to be added through SC3 config style. That means you can have events where the ground contact points would always force the vessel to be above a detonation altitude.

Ok, let's say you have a vessel:
Code:
class MyVessel : public VESSEL3

Code:
class MyVessel : public VESSEL3
{
public:
MyVessel() {Active = false};
~MyVessel();

void PreStep(double SimTime, double SimDeltaTime, double MJD);

private:
void Detonate();    // You don't want someone else to detonate you, right? ;)
bool Active;        // You want some sort of on-off switch, so you don't detonate before you get off the ground.

Now, let's say you go for altitude based trigger for detonation, then you'd define your PreStep like this:

Code:
void MyVessel::PreStep(double SimTime, double SimDeltaTime, double MJD)
{
// First off you figure out if you've *ever* left the ground.
// You don't wanna detonate before you launch.

if (Active == false)
{

if (GetAltitude() > 10)
{

Active = true;
}
}

// Now check if check if you've come under 10 meters, so you can detonate.

if ((Active == true) && (GetAltitude() < 10))
{
// Your warhead has been activated and you're now under 10 meters in altitude.
// Time to detonate.

Detonate();
}
}
That gives you a simple system that activates your warhead after launch, when it gets over 10 meters in altitude and then detonates it once it's active and under 10 meters. Once the conditions for detonation are met, the function Detonate() is called. Now you need to define that. I can't define the function in C++, but I will give you some comment hints on how I'd do it:

Code:
void MyVessel::Detonate()
{
// First thing you do is delete the existing mesh.
// Then define an exhaust stream with the exhaust that looks like an explosion. Delete it later, once the explosion is done.
// Also define an exhaust stream that acts as smoke from the crash site.
// Go into VESSELSTATUS and set status to inactive and latitude and longitute to where the vessel is right now, so your explosion won't move around...
// Play a sound...
// Anything you think would be cool...
}
I hope that gave you a general idea
That was probably one of the most helpful things ever. Thank you. I think I can get it from here now.

---------- Post added at 10:47 AM ---------- Previous post was at 10:25 AM ----------

Ok. This is not my final code whatsoever. I am posting it to see if I am getting the concept. Here it is.

Code:
#include "Warhead.h"

class MIRV : public VESSEL3
{
public:
MIRV() {Active = false};
~MIRV();

void PreStep(double SimTime, double SimDeltaTime, double MJD);

private:
void Detonate();    // You don't want someone else to detonate you, right? ;)
bool Active;        // You want some sort of on-off switch, so you don't detonate before you get off the ground.

void MIRV::PreStep(double SimTime, double SimDeltaTime, double MJD)
{
// First off you figure out if you've *ever* left the ground.
// You don't wanna detonate before you launch.

if (Active == false)
{

if (GetAltitude() > 10)
{

Active = true;
}
}

// Now check if check if you've come under 10 meters, so you can detonate.

if ((Active == true) && (GetAltitude() < 300))
{
// Your warhead has been activated and you're now under 10 meters in altitude.
// Time to detonate.

Detonate();
}
}

void MIRV::Detonate()
{
// lose the bomb mesh and load the fireball mesh
ClearMeshes();
////EXAMPLE OF CLOUD??? (From TRINITY code)
uranium = CreatePropellantResource (1e6);
{
0, 1400.0, 10, 1.0, 0.3, 75.0, 40.0, 3.0, PARTICLESTREAMSPEC::DIFFUSE,
PARTICLESTREAMSPEC::LVL_PSQRT, 0, 2,
PARTICLESTREAMSPEC::ATM_PLOG, 1e-4, 1
};

PARTICLESTREAMSPEC glow_cloud =
{
0, 1200.0, 60, 1.0, 0.3, 90.0, 40.0, 3.0, PARTICLESTREAMSPEC::EMISSIVE,
PARTICLESTREAMSPEC::LVL_PSQRT, 0, 2,
PARTICLESTREAMSPEC::ATM_FLAT, 1e-4, 1
};
thfission[0] = CreateThruster (_V(0.0,  0.0,  10.5), _V(0,0,1), 0.0001, uranium,4e4,4e4);
thgfission = CreateThrusterGroup (thfission, 1, THGROUP_MAIN);

emissive_fire=AddExhaustStream (thfission[0], _V(0.0,  0.0,  10.5), &glow_cloud);
SetThrusterGroupLevel(THGROUP_MAIN,1.0);
}

// Go into VESSELSTATUS and set status to inactive and latitude and longitute to where the vessel is right now, so your explosion won't move around...
// Play a sound...
// Anything you think would be cool...
}

// Initialisation
DLLCLBK VESSEL *ovcInit (OBJHANDLE hvessel, int flightmodel)
{
return new MIRV( hvessel,flightmodel );
}

// Cleanup
DLLCLBK void ovcExit (VESSEL *vessel)
{
if (vessel)
delete (MIRV*)vessel;
}

Of course I got add the vessel properties and define the meshes.

Last edited:

#### RisingFury

##### OBSP developer
Yea, as far as I can see, you're getting it right. :thumbup:

One thing you might wanna add, that I didn't think of before:
Currently you have it set up so that in every frame that you're under 10 meters and active warhead, it'll call detonation function. That's a bad thing, cos it'll add new thruster exhaust every frame. You might wanna add another private variable called bool Detonated, which you initialize as false and then before calling Detonate, you check if Detonated is false. Inside the Detonate function, you add Detonated = true.

That'll prevent multiple detonations

#### MJR

##### C++ developer in the mix
Tutorial Publisher
Donator
Yea, as far as I can see, you're getting it right. :thumbup:

One thing you might wanna add, that I didn't think of before:
Currently you have it set up so that in every frame that you're under 10 meters and active warhead, it'll call detonation function. That's a bad thing, cos it'll add new thruster exhaust every frame. You might wanna add another private variable called bool Detonated, which you initialize as false and then before calling Detonate, you check if Detonated is false. Inside the Detonate function, you add Detonated = true.

That'll prevent multiple detonations
Would I need a header file for this? I am thinking so. BTW, how would define 'ACTIVE'?

Last edited:

#### Urwumpe

##### Not funny anymore
Donator
If I may suggest something: Spawn a new vessel for the explosion, make it a separate effect. After creating the explosion, self-delete the warhead. This prevents the need to check for only one explosion.

#### RisingFury

##### OBSP developer
If I may suggest something: Spawn a new vessel for the explosion, make it a separate effect. After creating the explosion, self-delete the warhead. This prevents the need to check for only one explosion.

Is it cheaper? Spawning a new vessel can cause some momentary lag...

Would I need a header file for this? I am thinking so. BTW, how would define 'ACTIVE'?

You don't *need* a header file for it, but it does make things look better if you use it. You'd usually break up your code into two files:
MyVessel.h and MyVessel.cpp

MyVessel.h would look like this:

Code:
#ifndef MYVESSEL_H
#define MYVESSEL_H

#include "Orbitersdk.h"

class MyVessel : public VESSEL3
{
public:
MyVessel();
~MyVessel();

void PreStep(double SimTime, double SimDeltaTime, double MJD);

private:
bool Active;
bool Detonated;

void Detonate();
};

#endif

If you're using a VisualC++ compiler, you can use #pragma once instead of #ifndef structure, but I prefer it this way.

The header file is basically a declaration of code elements. As an analogy, think of it as a list of things you'll be using when making your dinner. You basically "reserve" the names. Although a header file is usually used to reserve names, it's generally split away from definitions. Definitions are done in the MyVessel.cpp file:

Code:
#include "MyVessel.h
// Need to include the header, of course ;)

MyVessel::MyVessel()
{
// Constructor.

Active = false;
Detonated = false;
}

void MyVessel::PreStep(double SimTime, double SimDeltaTime, double MJD)
{
if ((Active == false) && (GetAltitude() > 10))
{
// Set warhead to active only after it leaves the ground.
// This will prevent detonation prior to liftoff.

Active = true;
}

if ((Active == true) && (Detonated == false) && (GetAltitude() < 10))
{
// Check that the warhead is below 10 meters, active and undetonated.
// Detonate if the conditions are met.

Detonate();
}
}

void MyVessel::Detonate()
{
// Set Detonate to true, because the warhead just detonated.

Detonated = true;

// Clear mesh, define exhausts, play sound,...
}

MyVessel::~MyVessel()
{
// Destructor.
}

The reason bool Active and bool Detonated are there is to prevent multiple detonations and to prevent detonations when the warhead is on the launchpad, waiting for liftoff (because it's below 10 meters, right? )

You can think of the variable Active as having the warhead safety on or off. The other one just makes sure that the next time PreStep gets called, Detonation() won't get called all over again and executing the code inside it.

#### MJR

##### C++ developer in the mix
Tutorial Publisher
Donator
How does this look?
Code:
#include "Warhead.h"
#include "Orbitersdk.h"
// Need to include the header, of course ;)

{
// Constructor.

Active = false;
Detonated = false;
}

void Warhead::PreStep(double SimTime, double SimDeltaTime, double MJD)
{
if ((Active == false) && (GetAltitude() > 10))
{
// Set warhead to active only after it leaves the ground.
// This will prevent detonation prior to liftoff.

Active = true;
}

if ((Active == true) && (Detonated == false) && (GetAltitude() < 10))
{
// Check that the warhead is below 10 meters, active and undetonated.
// Detonate if the conditions are met.

Detonate();
}
}

{
// Set Detonate to true, because the warhead just detonated.

Detonated = true;

// Clear mesh, define exhausts, play sound,...
ClearMeshes();

}

{
// physics and geometry
SetSize(19.0);
SetEmptyMass(3915);
SetCrossSections(_V(36.0, 36.0, 6.0));                // S=pi*D^2/4. m^2
SetPMI(_V(24.5, 24.5, 0.7));
SetCW (0.5, 1.0, 2.0, 2.0);
SetRotDrag (_V(6.7, 6.7, 0.1));
SetLiftCoeffFunc(0);
SetPitchMomentScale(1e-4);
SetBankMomentScale(1e-4);
SetSurfaceFrictionCoeff(1e5, 1e5);
SetTouchdownPoints (_V( 0, 0, 10), _V( 2, 1, -10), _V(-2, 2, -10));

// fuel tank
MainTank = CreatePropellantResource(38300);

{
// Destructor.

}

// Initialisation
DLLCLBK VESSEL *ovcInit (OBJHANDLE hvessel, int flightmodel)
{
}

// Cleanup
DLLCLBK void ovcExit (VESSEL *vessel)
{
if (vessel)
}

The .h file....
Code:
#ifndef Warhead_H

#include "Orbitersdk.h"

{
public:

void PreStep(double SimTime, double SimDeltaTime, double MJD);
void clbkSetClassCaps(FILEHANDLE);
void clbkPreStep(double, double, double);

private:
bool Active;
bool Detonated;

void Detonate();

};

#endif

#### RisingFury

##### OBSP developer
Actually, I made a terrible mistake of calling clbkPreStep just PreStep. No need to have both of them in, just implement the functionality in clbkPreStep

I'm just used to my version cos I defined it in a non-VESSEL3 derived class used for the OBSP AI...

#### Xyon

##### Puts the Fun in Dysfunctional
Moderator
Webmaster
GFX Staff
Donator
Beta Tester
Some confusion with that callback...
Code:
clbkPreStep (double simt, double simdt, double mjd);

Should work better than the "double, double, double" you have there.

#### RisingFury

##### OBSP developer
Some confusion with that callback...
Code:
clbkPreStep (double simt, double simdt, double mjd);
Should work better than the "double, double, double" you have there.

Just to explain Xyon's point (no offense there Xyon):

When declaring function members, you don't need to name the variables, but you do have to name them when defining. This code:
Code:
void oapiPreStep(double, double, double);
will compile and work fine, but it's generally a good idea to type out the names to avoid confusion.

Another trick when defining function members is the use of default values.

If you declare a function member like this:
Code:
void FooBar(double MyDouble, int MyInt = 1);
then you don't need to pass a value to the second parameter of FooBar when calling it. In it's place, the value of 1 will be assumed. Of course, if you want to override the default value, you can. Both of these will work:
Code:
FooBar(1.5);
FooBar(1.5, 2);

#### MJR

##### C++ developer in the mix
Tutorial Publisher
Donator
I am still tinkering with it although it still keeps saying that I didn't define Detonate, GetAltitude, and that stuff. Here are both files. The first one is the .h and the second is the .cpp.
Code:
#ifndef __WARHEAD_H

#define STRICT
#include "Orbitersdk.h"

{
public:

void clbkPreStep(double SimTime, double SimDeltaTime, double MJD);

private:
bool Active;
bool Detonated;

void Detonate();
};

#endif

Code:
#include "Warhead.h"
#include "Orbitersdk.h"
// Need to include the header, of course ;)

{
// Constructor.

Active = false;
Detonated = false;
}

void Warhead::clbkPreStep(double SimTime, double SimDeltaTime, double MJD)
{
if ((Active == false) && (GetAltitude() > 10))
{
// Set warhead to active only after it leaves the ground.
// This will prevent detonation prior to liftoff.

Active = true;
}

if ((Active == true) && (Detonated == false) && (GetAltitude() < 10))
{
// Check that the warhead is below 10 meters, active and undetonated.
// Detonate if the conditions are met.

Detonate();
}
}

{
// Set Detonate to true, because the warhead just detonated.

Detonated = true;

// Clear mesh, define exhausts, play sound,...
ClearMeshes();

}

{
// physics and geometry
SetSize(19.0);
SetEmptyMass(3915);
SetCrossSections(_V(36.0, 36.0, 6.0));                // S=pi*D^2/4. m^2
SetPMI(_V(24.5, 24.5, 0.7));
SetCW (0.5, 1.0, 2.0, 2.0);
SetRotDrag (_V(6.7, 6.7, 0.1));
SetLiftCoeffFunc(0);
SetPitchMomentScale(1e-4);
SetBankMomentScale(1e-4);
SetSurfaceFrictionCoeff(1e5, 1e5);
SetTouchdownPoints (_V( 0, 0, 10), _V( 2, 1, -10), _V(-2, 2, -10));

// fuel tank
MainTank = CreatePropellantResource(38300);

{
// Destructor.

}

// Initialisation
DLLCLBK VESSEL *ovcInit (OBJHANDLE hvessel, int flightmodel)
{
}

// Cleanup
DLLCLBK void ovcExit (VESSEL *vessel)
{
if (vessel)
}