• ORBITER-FORUM will be temporarily closed at 2026-07-23 18:00 UTC while we complete some OF maintenance tasks. The amount of downtime is expected to take up to one hour, but probably less.

Question Ranger (and other ships) from Interstellar?

Thanks. the issues seems to be in the hover thrust gauge.
initial setup of hover thrusters
Code:
//HOVER
	tank2 = CreatePropellantResource(FUELMASS2);

	th_hover[0] = CreateThruster(_V(5, 0, 5), _V(0, 1, 0), MAXHOVERTH / 4, tank2, ISP);
	th_hover[1] = CreateThruster(_V(-5, 0, -5), _V(0, 1, 0), MAXHOVERTH / 4, tank2, ISP);
	th_hover[2] = CreateThruster(_V(-5, 0, 5), _V(0, 1, 0), MAXHOVERTH / 4, tank2, ISP);
	th_hover[3] = CreateThruster(_V(5, 0, -5), _V(0, 1, 0), MAXHOVERTH / 4, tank2, ISP);

	thg_hover = CreateThrusterGroup(th_hover, 4, THGROUP_HOVER);
commented lines no ctd
Code:
 current_thrust_hover_level = GetThrusterGroupLevel(thg_hover);
if (current_thrust_hover_level != thrust_hover_last_drawn){
		thrust_hover_last_drawn = current_thrust_hover_level;
		redrawpanel = true;
	}
this tells how far to draw the bar
Code:
	hoverx2 = int(hoverx1 + current_thrust_hover_level * 284);
draws the bar
Code:
	Rectangle(hDC, hoverx1, hovery1, hoverx2,hovery2);//HOVERthrust
initialized
Code:
	current_thrust_hover_level = 0;
	thrust_hover_last_drawn = 0;
	hoverx1 = 60;
	hovery1 = 509;
	hoverx2 = 342;
	hovery2 = 534;


One thing I did notice it would draw the hover bar full till it refreshed. I was thinking I could just go to one hover thruster. The reason we have it that way is for the 4 exhaust?
 
How is th_hover defined?

And why are you not simply using

current_thrust_hover_level = GetThrusterGroupLevel(THGROUP_HOVER);
 
Last edited:
Bingo that was it I had changed it to
Code:
th_hover[1];
:blush:


now it is
Code:
th_hover[4];
 
Should have caused a minor annoyance there, but it is one code smell less.
 
On the lander. I have this code so if the lander is below 10 meters add exhaust stream to show dust. and then if above 10 meters delete exhaust stream.
Code:
if ((alt <10) && (smoke == 0))
	{

		th_hover[0] = AddExhaustStream(th_hover[0], _V(-3.421, 0, 2.43), &exhaust_hover);
		th_hover[1] = AddExhaustStream(th_hover[1], _V(3.421, 0, 2.43), &exhaust_hover);
		th_hover[2] = AddExhaustStream(th_hover[2], _V(-3.421, 0, -2.136), &exhaust_hover);
		th_hover[3] = AddExhaustStream(th_hover[3], _V(3.421, 0, -2.136), &exhaust_hover);
		smoke = 1;
	};
	if ((alt>10) && (smoke==1))
	{



		DelExhaustStream(th_hover[0]);
		DelExhaustStream(th_hover[1]);
		DelExhaustStream(th_hover[2]);
		DelExhaustStream(th_hover[3]);
		smoke = 0;
	}

So the lander using hovers rises. exhaust is seen. and 10 meters no exhaust, Good.
BUT then if the lander drops below 10 not exhaust is seen.

smoke is initialized. All that indicates isif the exhaust stream were added.
 
2 issues and the Lander will be done:)
We just want hover exhaust below 10 meters.
Code:
if (alt <10)//hover exhaust
	{

		th_hover[0] = AddExhaustStream(th_hover[0], _V(-3.421, 0, 2.43), &exhaust_hover);
		th_hover[1] = AddExhaustStream(th_hover[1], _V(3.421, 0, 2.43), &exhaust_hover);
		th_hover[2] = AddExhaustStream(th_hover[2], _V(-3.421, 0, -2.136), &exhaust_hover);
		th_hover[3] = AddExhaustStream(th_hover[3], _V(3.421, 0, -2.136), &exhaust_hover);
		//smoke = 1;
	};
	if (alt>10)  //no hover exhaust
	{	DelExhaustStream(th_hover[0]);
		DelExhaustStream(th_hover[1]);
		DelExhaustStream(th_hover[2]);
		DelExhaustStream(th_hover[3]);
		
	}

The exhaust keeps going past 10m.

The other is harder. It is getting the labels on the COpilot mfd's. The pilots are fine. All I see is the texture. No idea why?

defines the size and texture.
Code:
static DIMENSION const MFD_BUTTONS_FN_DIM = _D(50, 28, 2, 2);
static RECT const MFD_BUTTONS_FN_RECT[] = {
	_R(000, 000, 100, 168), _R(100, 000, 200, 168), _R(200, 000, 300, 168), _R(000, 169, 100, 333)
//	_R(000, 000, 100, 168), _R(200, 000, 300, 168), _R(300, 000, 400, 168), _R(400, 000, 500, 168)
};

Code:
void ClassicMfd::DefineMfdButtons(
	UINT const texId,
	UINT const fuctionAreaId, UINT const functionGroupId, RECT const functionRect,
	UINT const sysAreaId, UINT const sysGroupId
	)
{
	SURFHANDLE const texDyn = oapiGetTextureHandle(meshhg_VC, texId);
	oapiVCRegisterArea(fuctionAreaId, functionRect, PANEL_REDRAW_USER, PANEL_MOUSE_LBDOWN | PANEL_MOUSE_LBPRESSED | PANEL_MOUSE_ONREPLAY, PANEL_MAP_NONE, texDyn);
	DefineStaticClickArea(oapiMeshGroup(meshhg_VC, functionGroupId), fuctionAreaId, true);

	oapiVCRegisterArea(sysAreaId, PANEL_REDRAW_NEVER, PANEL_MOUSE_LBDOWN | PANEL_MOUSE_ONREPLAY);
	DefineStaticClickArea(oapiMeshGroup(meshhg_VC, sysGroupId), sysAreaId, true);
}

static int get_font_height(HDC const hDC)
{
	TEXTMETRIC tm;
	if (GetTextMetrics(hDC, &tm))
	{
		return abs(tm.tmAscent);
	}

	return 5; // Wild, crazy guessing
}

void ClassicMfd::RedrawMFDButtons(SURFHANDLE const surf, int const mfd)
{
	int const btnWidth = buttonFnDim->width;
	int const btnHeight = buttonFnDim->height;
	RECT const draw_area = _R(0, 0, buttonFnRect[mfd].right - buttonFnRect[mfd].left, buttonFnRect[mfd].bottom - buttonFnRect[mfd].top);

	HDC const hDC = oapiGetDC(surf);

	SelectObject(hDC, buttonBrush);
	SetBkMode(hDC, OPAQUE);
	Rectangle(hDC, draw_area.left, draw_area.top, draw_area.right, draw_area.bottom);

	HFONT pFont = (HFONT)SelectObject(hDC, labelFont);
	SetTextColor(hDC, labelColor);
	SetTextAlign(hDC, TA_CENTER);
	int const half_font_height = get_font_height(hDC) / 2;

	char const * label;
	int const label_x_offset = (btnWidth / 2);
	int const label_y_offset = (btnHeight / 2) - buttonFnDim->marginHeight - half_font_height;
	for (int i = 0; i < 12; i++) {
		int const x = i / 6;
		int const y = i % 6;
		if (label = oapiMFDButtonLabel(mfd, i)) {
			int const xwidth = (x * btnWidth);
			int const yheight = (y * btnHeight);

			SelectObject(hDC, buttonLabelBrush);
			SetBkMode(hDC, OPAQUE);
			Rectangle(hDC,
				draw_area.left + xwidth + buttonFnDim->marginWidth,
				draw_area.top + yheight + buttonFnDim->marginHeight,
				draw_area.left + xwidth + btnWidth - buttonFnDim->marginWidth,
				draw_area.top + yheight + btnHeight - buttonFnDim->marginHeight
				);
			SetBkMode(hDC, TRANSPARENT);
			TextOut(hDC, draw_area.left + xwidth + label_x_offset, draw_area.top + yheight + label_y_offset, label, strlen(label));
		}
		else break;
	}

	SelectObject(hDC, pFont);
	oapiReleaseDC(surf, hDC);
}

Code:
void ClassicMfd::DefineMfdsButtons()
{
	// Pilot Left
	DefineMfdButtons(
		TEX_LANDER16VC_MFD_DYNAMIC_06,
		AID_PILOT_MFD_LEFT_BTNS_FN, GRP_LANDER16VC_PILOT_MFD_LEFT_BTNS_FN, buttonFnRect[MFD_PILOT_LEFT],
		AID_PILOT_MFD_LEFT_BTNS_SYS, GRP_LANDER16VC_PILOT_MFD_LEFT_BTNS_SYS
		);

	// Pilot Right
	DefineMfdButtons(
		TEX_LANDER16VC_MFD_DYNAMIC_06,
		AID_PILOT_MFD_RIGHT_BTNS_FN, GRP_LANDER16VC_PILOT_MFD_RIGHT_BTNS_FN, buttonFnRect[MFD_PILOT_RIGHT],
		AID_PILOT_MFD_RIGHT_BTNS_SYS, GRP_LANDER16VC_PILOT_MFD_RIGHT_BTNS_SYS
		);

	// CoPilot Left
	DefineMfdButtons(
		TEX_LANDER16VC_MFD_DYNAMIC_06,
		AID_COPILOT_MFD_LEFT_BTNS_FN, GRP_LANDER16VC_COPILOT_MFD_LEFT_BTNS_FN, buttonFnRect[MFD_COPILOT_LEFT],
		AID_COPILOT_MFD_LEFT_BTNS_SYS, GRP_LANDER16VC_COPILOT_MFD_LEFT_BTNS_SYS
		);

	// CoPilot Right
	DefineMfdButtons(
		TEX_LANDER16VC_MFD_DYNAMIC_06,
		AID_COPILOT_MFD_RIGHT_BTNS_FN, GRP_LANDER16VC_COPILOT_MFD_RIGHT_BTNS_FN, buttonFnRect[MFD_COPILOT_RIGHT],
		AID_COPILOT_MFD_RIGHT_BTNS_SYS, GRP_LANDER16VC_COPILOT_MFD_RIGHT_BTNS_SYS
		);


}
 
I don't know why this isn't working:(
Code:
	alt = GetAltitude();
	//level = GetThrusterGroupLevel(THGROUP_HOVER);

	if ((alt <10) && (smoke == 0)) //alt<10 and exhaust deleted
	{
			th_hover[0] = AddExhaustStream(th_hover[0], _V(-3.421, 0, 2.43), &exhaust_hover);
			th_hover[1] = AddExhaustStream(th_hover[1], _V(3.421, 0, 2.43), &exhaust_hover);
			th_hover[2] = AddExhaustStream(th_hover[2], _V(-3.421, 0, -2.136), &exhaust_hover);
			th_hover[3] = AddExhaustStream(th_hover[3], _V(3.421, 0, -2.136), &exhaust_hover);
			smoke = 1;// exhaust added
	};
	if ((alt>10) && (smoke == 1))  //alt>10 and exhausted added
	{
		SetThrusterGroupLevel(THGROUP_HOVER, 0.0);
			DelExhaustStream(th_hover[0]);
			DelExhaustStream(th_hover[1]);
			DelExhaustStream(th_hover[2]);
			DelExhaustStream(th_hover[3]);
			SetThrusterGroupLevel(THGROUP_HOVER, current_thrust_hover_level);
			smoke = 0;//del exhaust streams
		};

So if the alt is less than 10 add exhaust. If alt>10 then delete exhaust streams

If I run this the exhaust shows up , go above 10 no exhaust :)
but if I drop below 10 no exhaust smoke =1 in saved state.

She works in 2016:)
 
th_hover[0] = AddExhaustStream(th_hover[0], _V(-3.421, 0, 2.43), &exhaust_hover);

Could it be that you're overwriting the thruster handle? Doesn't a warning show up on compilation?
 
No errors on compilation. I first thought it was making more thrust exhaust than it was deleting.
As I understand the exhaust should be made once. Then is above 10 delete 0-3.
 
No errors on compilation. I first thought it was making more thrust exhaust than it was deleting.
As I understand the exhaust should be made once. Then is above 10 delete 0-3.

What about warnings? Are you using /W3? (project properties > C/C++ > General > Warning Level)

You should create the thrusters once, and initially assume that either you are above 10m and don't add plumes, or assume you are below and add plumes. And then you have that piece of code that should add, or delete, the plumes when pass 10m. Right now you are mixing thruster handles with exhaust handles... not good.

BTW: in Orbiter2016 use the correct altitude measurement so get altitude above ground and not the mean radius.
 
Thanks. I see the issue.
So like this:
Code:
	alt = GetAltitude();
	//level = GetThrusterGroupLevel(THGROUP_HOVER);

	if ((alt <10) && (smoke == 0)) //alt<10 and exhaust deleted
	{
			AddExhaustStream(th_hover[0], _V(-3.421, 0, 2.43), &exhaust_hover);
			AddExhaustStream(th_hover[1], _V(3.421, 0, 2.43), &exhaust_hover);
			AddExhaustStream(th_hover[2], _V(-3.421, 0, -2.136), &exhaust_hover);
			AddExhaustStream(th_hover[3], _V(3.421, 0, -2.136), &exhaust_hover);
			smoke = 1;// exhaust added
	};
	if ((alt>10) && (smoke == 1))  //alt>10 and exhausted added
	{
		SetThrusterGroupLevel(THGROUP_HOVER, 0.0);
			DelExhaustStream(th_hover[0]);
			DelExhaustStream(th_hover[1]);
			DelExhaustStream(th_hover[2]);
			DelExhaustStream(th_hover[3]);
			SetThrusterGroupLevel(THGROUP_HOVER, current_thrust_hover_level);
			smoke = 0;//del exhaust streams
		};
 
No. Please read the API Reference about the functions before you use them.

Code:
/**
	 * \brief Delete an existing particle stream.
	 * \param ch particle stream handle
	 * \return \e false indicates failure (particle stream not found)
	 * \note If a thruster is deleted (with ref DelThruster), any attached
	 *   particle streams are deleted automatically.
	 * \note A deleted particle stream will no longer emit particles, but
	 *   existing particles persist until they expire.
	 * \sa AddParticleStream, AddExhaustStream, AddReentryStream
	 */
	bool DelExhaustStream (PSTREAM_HANDLE ch) const;

You should store the return value of AddExhaustStream in a new variable and use this PSTREAM_HANDLE for DelExhaustStream then.
 
I am away for computer. But basically have a variable to tell if added or not added exhaust stream, right

Then if added and alt is above 10 del exhaust stream?
 
I am away for computer. But basically have a variable to tell if added or not added exhaust stream, right

Then if added and alt is above 10 del exhaust stream?

You need some variables, not all are necessary, but they really make your live easier.

Lets start at the design phase:

What you describe is a typical DFA in computer science, a deterministic finite automate, a type of state machine.

You have two states, that the customer/player will see: Particle stream visible and particle stream invisible.

You have the following transitions defined:

Initial --> Visible?
Visible: (Alt > 10) --> Invisible
Invisible: (Alt < 10) --> Visible

But since nothing really happens in each state and all important tasks actually happen during the transition, you can internally focus on the transition:

Initial -->Invisible_to_visible
Visible_to_invisible: (Alt > 10) --> Invisible_to_visible
Invisible_to_visible: (Alt < 10) --> Visible_to_invisible

So, now you have a fine design. You need one variable to track the current state and when the event happens, you execute a state transition, which also changes the variable at the end.

Now, to the implementation. You already have a state machine in your code, even if you did not make it visible.

For deleting a particle stream, you need to know which particle stream. This identification of the particle stream is the return value when you create it.

So, for each particle stream, you need a variable to identify it, so you can delete it.

Do you see the picture now?
 
Ok. So like this. Smoke tells me if exhaust is on (smoke=1) or exhaust is not on (smoke=0)
Code:
	//smoke =Particle stream visible (1) and particle stream invisible(0).
	if ((alt <10) && (smoke == 0)) //alt<10 and exhaust deleted
	{
			AddExhaustStream(th_hover[0], _V(-3.421, 0, 2.43), &exhaust_hover);
			AddExhaustStream(th_hover[1], _V(3.421, 0, 2.43), &exhaust_hover);
			AddExhaustStream(th_hover[2], _V(-3.421, 0, -2.136), &exhaust_hover);
			AddExhaustStream(th_hover[3], _V(3.421, 0, -2.136), &exhaust_hover);
			smoke = 1;// exhaust added
	};

So smoke is 0 at start so do not make exhaust stream.

If smoke =0 (not Seen) and ALt<10 then add exhaust.
 
You should still remember that you need the PSTREAM_HANDLE for each particle stream.
 
Thanks. this works. Now to get the mfd buttons and she is done:)
Code:
if ((alt <10) && (smoke == 0)) //alt<10 and exhaust deleted
	{
		hover_jet[0] = AddExhaustStream	(th_hover[0], _V(-3.421, 0, 2.43), &exhaust_hover);
		hover_jet[1] = AddExhaustStream(th_hover[1], _V(3.421, 0, 2.43), &exhaust_hover);
		hover_jet[2] = AddExhaustStream(th_hover[2], _V(-3.421, 0, -2.136), &exhaust_hover);
		hover_jet[3] = AddExhaustStream(th_hover[3], _V(3.421, 0, -2.136), &exhaust_hover);
			smoke = 1;// exhaust added
	};
	if ((alt>10) && (smoke == 1))  //alt>10 and exhausted added
	{
	//	SetThrusterGroupLevel(THGROUP_HOVER, 0.0);
		DelExhaustStream(hover_jet[0]);
		DelExhaustStream(hover_jet[1]);

		DelExhaustStream(hover_jet[2]);

		DelExhaustStream(hover_jet[3]);

		//	DelExhaustStream(th_hover[1]);
		//	DelExhaustStream(th_hover[2]);
		//	DelExhaustStream(th_hover[3]);
		//	SetThrusterGroupLevel(THGROUP_HOVER, current_thrust_hover_level);
			smoke = 0;//del exhaust streams
		};


---------- Post added 09-09-16 at 07:56 AM ---------- Previous post was 09-08-16 at 04:35 PM ----------

So is there a key that one can code to turn on/off a mfd. So like press CTRL 1 and the mfd comes on/off and is set to be only 1 mfd like surface?
 

So is there a key that one can code to turn on/off a mfd. So like press CTRL 1 and the mfd comes on/off and is set to be only 1 mfd like surface?

I am not sure what you mean by that. Can you explain your scenario in more detail?
 
Sure. I have a 2 mfd that I just want to be on/off and always surface. I know I can do that in scenario. But just wanted to know if I can by code
 
Back
Top