FSX I can't link switch with indicator and backlighting

#1
Hi!

I work on project of FSX's conversion of an excellent An-28 made by DPL for X-plane. Some of the switches and indicators have already been coded. I would like to link some of the switches with some of the indicators so that switching a switch on would produce switching an indicator ON, as well as switching the backlighting on. However I can not link all that three elements toghether. Example of such linked switch, indicator and backlighting below. I guess that the solution is trivial but I can not go through it so far... I need a modeldef.xml format of code for FSX.

Besides this I would like to say "thank you" for all of you, especially n4gix and a few others of the developers who share their knowledge and teaching us this kind of the 3D art. Without you I could not step further as I did. Thanks!


INDICATOR:


<PartInfo>
<Name>AN28_Vibration_needle_left</Name>
<AnimLength>100</AnimLength>
<Animation>
<Parameter>
<Code>
(A:TURB ENG VIBRATION:2, percent) 10 /
</Code>
</Parameter>
</Animation>
<MouseRect>
<TooltipText>Vibration (%((A:TURB ENG VIBRATION:2, percent))%!3d! %)</TooltipText>
<Cursor>Hand</Cursor>
</MouseRect>
</PartInfo>


SWITCH:


<PartInfo>
<Name>AN28_VibrInd_SW</Name>
<AnimLength>2</AnimLength>
<Animation>
<Parameter>
<Code>
(L:VibrInd_SW, enum)
</Code>
<Lag>400</Lag>
</Parameter>
<Animation>
<MouseRect>
<Cursor>Hand</Cursor>
<TooltipText>Left Fuel Indicator Switch</TooltipText>
<MouseFlags>LeftSingle+RightSingle+Wheel</MouseFlags>
<CallbackCode>
(M:Event) 'RightSingle' scmp 0 == if{ (L:VibrInd_SW, enum) -- 0 max (>L:VibrInd_SW, enum) }
(M:Event) 'LeftSingle' scmp 0 == if{ (L:VibrInd_SW, enum) ++ 1 min (>L:VibrInd_SW, enum) }
(M:Event) 'WheelUp' scmp 0 == if{ (L:VibrInd_SW, enum) ++ 0 max (>L:VibrInd_SW, enum) }
(M:Event) 'WheelDown' scmp 0 == if{ (L:VibrInd_SW, enum) -- 1 min (>L:VibrInd_SW, enum) }
</CallbackCode>
</MouseRect>
</PartInfo>


INDICATOR BACKLIGHTING:


<PartInfo>
<Name>AN28_VibrInd_BL</Name>
<Visibility>
<Parameter>
<Code>
(L:VibrInd_SW, enum) 0 &gt;
(A:LIGHT CABIN, bool) 0 &gt;
and
(A:CIRCUIT GENERAL PANEL ON, bool) 0 &gt;
and
if{ 1 } els{ 0 }
</Code>
</Parameter>
</Visibility>
</PartInfo>


Best Regards
IntruderPL
 
Last edited:
#2
I don't have time to check your code. but here is a tip!

Use visibility tags for showing the back lighting and then you only need to link up 2 codes.

DG:)
 
#3
Well, good idea! Thanks DG :) I will move the visibility part of backlighting to the code of the switch.
Now, I only need to get the indicator's needle move only when the switch is on.
I will appreciate any help/suggestions.
 

n4gix

Resource contributor
#4
All you need to do is add the condition to your needle's script to have the needle move only if the switch is active (set), and provide a keyframe number for the "parked (static) position" when the switch is off:

Code:
<PartInfo>
	<Name>AN28_Vibration_needle_left</Name>
	<AnimLength>100</AnimLength>
	<Animation>
		<Parameter>
			<Code>
			     (L:VibrInd_SW, enum) 1 ==
                              if{ (A:TURB ENG VIBRATION:2, percent) 10 / }
                              els{ 0 }
			</Code>
		</Parameter>
	</Animation>
	<MouseRect>
		<TooltipText>Vibration %((A:TURB ENG VIBRATION:2, percent))%!3d!</TooltipText>
		<Cursor>Hand</Cursor>
	</MouseRect>
</PartInfo>
BTW, I fixed the syntax on your <TooltipText> as well.
 
#5
So I assume that this line:

els{ 0 }

is that keyframe for needle's parked position and I am not about to do something more in needle 3D model's animation. Is that correct?

I will give it a try to see if I can use the model above.
Also I want to explain that I used many of your codes and explanations from here (the forum) to bring the life into the project of An-28. Thank you very much Bill! :)

EDIT:

I had to add a <Lag>200</Lag> tag just below CODE tag and it works perfectly! Again, THANKS A LOT Bill and DG!
 
Last edited:

n4gix

Resource contributor
#6
EDIT:

I had to add a <Lag>200</Lag> tag just below CODE tag and it works perfectly! Again, THANKS A LOT Bill and DG!
Great! Yes, the els{ 0 } will "park" the needle at the zero keyframe. If the "parked position" is mid-scale (such as an ammeter that has -/+ amps, then the keyframe would need to be 50... ;)

The <Lag> value determines how fast the needle (or other part) moves with respect to the sim variable. A value of 200 means "200 frames per second" so it's pretty quick. Some needles require more damping, so for those I lower the <Lag> value to 30 or thereabouts.
 
#7
The <Lag> value determines how fast the needle (or other part) moves with respect to the sim variable. A value of 200 means "200 frames per second" so it's pretty quick. Some needles require more damping, so for those I lower the <Lag> value to 30 or thereabouts.
Nice tip! Thanks Bill :)

I will post here another issue to avoid unnecessary posting.

I've got an 3-pos switch of 3D landing/taxi lights. Both the lights are off in neutral position of the switch. Landing lights ON should be in switch'es UP position (inc/dec by left click) and Taxi light in its DOWN position (dec/inc by right click). Unfortunately the switch doesn't work as intended for unknown reason. The code I use so far works but not strictly as I've described above. Keyframing is like: 0 (up/landing on) - 50 (middle/lights off) - 100 (down/taxi on). I can invert keyframing if needed.

Code:
	<PartInfo>
		<Name>AN28_switch_3Dlight</Name>
		<AnimLength>100</AnimLength>
		<Animation>
			<Parameter>
				<Code>50 (L:3DLight_Switch,enum) 50 * +</Code>
				<Lag>400</Lag>
			</Parameter>
		</Animation>
		<MouseRect>
			<Cursor>Hand</Cursor>
			<TooltipText>Landing / Taxi Light Switch</TooltipText>
			<MouseFlags>LeftSingle+RightSingle+LeftRelease+RightRelease</MouseFlags>
			<CallbackCode>
				(M:Event) 'LeftSingle' scmp 0 ==
				if{
				-1 (>L:3DLight_Switch, enum)
				(>K:LANDING_LIGHTS_TOGGLE)
				}
				(M:Event) 'RightSingle' scmp 0 ==
				if{
				1 (>L:3DLight_Switch, enum)
				(>K:TOGGLE_TAXI_LIGHTS)
				}
				(M:Event) 'LeftRelease' scmp 0 ==
				if{ 0 (>L:3DLight_Switch, enum) }
				(M:Event) 'RightRelease' scmp 0 ==
				if{ 0 (>L:3DLight_Switch, enum) }
				(L:VC_Click,bool) ! (>L:VC_Click,bool)
				1 (>L:XMLClick,enum)
			</CallbackCode>
		</MouseRect>
	</PartInfo>
Radek Koterbski
vel IntruderPL
 
Last edited:

n4gix

Resource contributor
#8
Okay, rather than deal with what's wrong with the mouse script above, other than mention that there is no way to turn OFF either landing or taxi lights...

I will instead post some "universal" script that I copy/paste/edit as required for all three position, center off switches. I've already edited it to use your L:variable:

Code:
<MouseFlags>LeftSingle+RightSingle+WheelUp+WheelDown</MouseFlags>
<CallbackCode>
  (M:Event) 'LeftSingle' scmp 0 ==
      if{ (L:3DLight_Switch, enum) -- -1 max (>L:3DLight_Switch, enum) }
  (M:Event) 'WheelDown' scmp 0 ==
      if{ (L:3DLight_Switch, enum) -- -1 max (>L:3DLight_Switch, enum) }
  (M:Event) 'RightSingle' scmp 0 ==
      if{ (L:3DLight_Switch, enum) ++ 1 min (>L:3DLight_Switch, enum) }
  (M:Event) 'WheelUp' scmp 0 ==
      if{ (L:3DLight_Switch, enum) ++ 1 min (>L:3DLight_Switch, enum) }
</CallbackCode>
This script will allow the user to use either the left/right mouse buttons, or the center wheel to roll the switch up/down.

Now, note that I've not specified any "action" in the above script to be taken when the switch is clicked or wheeled...

This is because I prefer to keep the script as "universal" as possible! I can easily add the "control logic" to either the <CallbackCode> itself, or in a separate <Update> logic section. I will show the first option in the example below.

In either case, note that all "toggle" type events are just that; click once ON, click again OFF. Not terribly easy to control! :mad:

So, the "safe" way to use them is to first check to see if they need to be changed. We do this by checking the state of the light circut, then sending the command event only if required.

Code:
<MouseFlags>LeftSingle+RightSingle+WheelUp+WheelDown</MouseFlags>
<CallbackCode>
  (M:Event) 'LeftSingle' scmp 0 ==
      if{ (L:3DLight_Switch, enum) -- -1 max (>L:3DLight_Switch, enum) }
  (M:Event) 'WheelDown' scmp 0 ==
      if{ (L:3DLight_Switch, enum) -- -1 max (>L:3DLight_Switch, enum) }
  (M:Event) 'RightSingle' scmp 0 ==
      if{ (L:3DLight_Switch, enum) ++ 1 min (>L:3DLight_Switch, enum) }
  (M:Event) 'WheelUp' scmp 0 ==
      if{ (L:3DLight_Switch, enum) ++ 1 min (>L:3DLight_Switch, enum) }

  (L:3DLight_Switch, enum) -1 == (A:LIGHT LANDING,bool) 0 == and if{ (>K:LANDING_LIGHTS_TOGGLE) }
  (L:3DLight_Switch, enum)  0 == (A:LIGHT LANDING,bool) 1 == and if{ (>K:LANDING_LIGHTS_TOGGLE) }
  (L:3DLight_Switch, enum)  0 == (A:LIGHT TAXI,bool)    1 == and if{ (>K:TOGGLE_TAXI_LIGHTS) }
  (L:3DLight_Switch, enum)  1 == (A:LIGHT TAXI,bool)    0 == and if{ (>K:TOGGLE_TAXI_LIGHTS) }
</CallbackCode>
Note that for each possible state of the (L:var), I'm first checking the state of the light circuit, then sending the command event.

I hope this is understandable, and will help you in the future as well! :teacher:
 
#9
Oushhhhhhh! :eek:
Are you a teacher in RL Bill? :) You explained me the whole thing in fully understandable way. I can understand the logic behind the code. The thing wich really going me crazy is the implementation of the XML RPN. I will check the solution and reply tomorow. Many thanks Bill!

IntruderPL
 

n4gix

Resource contributor
#10
Oushhhhhhh! :eek:
Are you a teacher in RL Bill? :) You explained me the whole thing in fully understandable way.
I used to teach "Introduction to Computer Science" at the University of Florida, Gainesville Campus back around a hundred years ago, or at least it seems that long... :D

As a priest, I've always been a teacher! :rotfl:
 
#11
I knew it! :)
Of course, your code works perfectly. I should never say like "I will give it a try", rather I should say "I will change my code as you suggest, Master!" ;)

The next issue I am gonna fight against is a blinking warning lights. I need two different codes - one for fire warning light and second one for general warning light activated when engine is reversed (plus pulsating sound when reverser is activated in the air). I saw similar problem (blinkning land. lights of a chooper?) here and I guess that there is something to do with time variable, but I didnt start yet. I hope both of the codes shouldn't be hard to write and will post them when I begin the fighting.

Thank you very much Bill! :)
 

n4gix

Resource contributor
#12
I have this posted at the top of my modeldef.xml file as a reminder:

Code:
<!--
With this universal code it's very simple to control not only the length of the cycle but the frequency of the 
blink itself:
Pseudocode:<Visble>(P:Absolute time,seconds) "seed" % "blink lapse" > !</Visible>
The seed parameter is the total length of the blinking cycle. For example, if you want something to blink on every 
second, you use 1, if you want it blink every half a second, use 0.5 , every two seconds, 2 ,etc.

For each seed, you can determine how long would be the duration of both the visible and invisible part.
Then:
(P:Absolute time,seconds) 1 % 0.5 > ! 
this will make the visible and invisible parts of half a second both.
(P:Absolute time,seconds) 1 % 0.7 > ! 
this will make the visible part 70% of the cycle (0.7 secs) and invisible parts of 30 % (0.3 secs).
(P:Absolute time,seconds) 0.5 % 0.25 > ! 
this will make the visible and invisible parts a quarter of second both.
You can invert the cycle by removing the "!" char.
-->
As a practical example, here is the script I use to "double-flash" custom strobe lights for one of my current projects. Note that it uses two separate timers. The "outer timer" controls the frequency of the strobe. The "inner timer" causes the "strobe" to flash twice in quick succession.

Code:
    <!-- STROBE LIGHT FLASHER -->
    (A:LIGHT STROBE,bool)
    (A:ELECTRICAL MASTER BATTERY,bool)
    and
    if{
         (P:Absolute time,seconds) 2 % 0.4 > !
         if{
              (P:Absolute time,seconds) 0.2 % 0.1 > !
              if{ 1 (>L:B737_Strobe,bool) }
             els{ 0 (>L:B737_Strobe,bool) }
           }
      }
Here is script for a simpler beacon light:
Code:
    <!-- BEACON LIGHT FLASHER -->
    (A:LIGHT BEACON,bool)
    (A:ELECTRICAL MASTER BATTERY,bool)
    and
    if{
        (P:Absolute time,seconds) 2.0 % 1.0 > !
          if{ 1 (>L:B737_Beacon,bool) }
         els{ 0 (>L:B737_Beacon,bool) }
    }
 
Last edited:
#13
I will repeat myself - your code works perfect, Bill! Thanks a milion!
I've used an example from the remind notes, as below:


Code:
	<PartInfo>
		<Name>AN28_ANN_RightEngFire_Light</Name>
		<Visibility>
                                 <Parameter>
                                        <Code>
					(A:ENG ON FIRE:2, bool) 0 &gt;
					(A:CIRCUIT GENERAL PANEL ON, bool)
					(P:Absolute time,seconds) 0.5 % 0.25 >
					and
					and
					if{ 1 } els{ 0 }
                                         </Code>
                                </Parameter>
                           </Visibility>
		<MouseRect>
			<TooltipText>Right Eng Fire</TooltipText>
			<Cursor>Hand</Cursor>
		</MouseRect>
    </PartInfo>
By the way, do you think that closing if{ 1 } els{ 0 } is needed to avoid any problems? Would the simpler example works as well?

Code:
                <Code>
					(A:ENG ON FIRE:2, bool)
					(A:CIRCUIT GENERAL PANEL ON, bool)
					(P:Absolute time,seconds) 0.5 % 0.25 >

                </Code>
and last but not least question today - is anyone know which variable makes possible to detect turboprop engine being in reverse state? I have tried several but with no luck :/

Radek Koterbski
vel Intruder
 
Last edited:

n4gix

Resource contributor
#14
If including it works properly, why change? In any case your example would not work because you deleted the two joiner evaluators "and and" which tie the three conditions into a complete expression.

As for the reversed turboprop condition, I have no idea whatever if that's even possible. ;)
 
#16
As for the reversed turboprop condition, I have no idea whatever if that's even possible. ;)
I have found out a workaround here. You can determine under which condition the turboprop is running by checking at which angle its blades are at that moment. Example:

Code:
	<PartInfo>
		<Name>AN28_ANN_LeftEngReversed_WarnLight</Name>
		<Visibility>
            		<Parameter>
                		<Code>
					(A:PROP BETA:1, degrees) -5 &lt;
					(A:CIRCUIT GENERAL PANEL ON, bool)
					(P:Absolute time,seconds) 0.5 % 0.25 >
					and
					and
					if{ 1 } els{ 0 }
                		</Code>
            		</Parameter>
        	</Visibility>
		<MouseRect>
			<TooltipText>Reverse Eng</TooltipText>
			<Cursor>Hand</Cursor>
		</MouseRect>
    	</PartInfo>
Radek Koterbski
vel IntruderPL


PS. I'm gonna love this "ah-ha" moments ;) Thanks Bill, surprisingly you pushed me into right track in this one.
 
Last edited:
#17
Well, I met another issue. This time it's related to ADI. Whenever I lean (bank?) the AC from left to right the ADI's ball doesn't do the same. Instead of it go opposite. Below the code of the ADI I use and a switch that activate the ADI.


Code:
	<PartInfo>
		<Name>AN28_CPADI_bank</Name>
		<AnimLength>360</AnimLength>
		<Animation>
			<Parameter>
				<Code>
					(L:CP_ADIInd_SW, enum) 1 ==
					if{ (A:ATTITUDE CAGE,bool) 1 &lt; (A:ATTITUDE INDICATOR BANK DEGREES, degrees) dnor }
					els{ 90 }
				</Code>				
				<Lag>100</Lag>				
			</Parameter>
		</Animation>
		<MouseRect>
			<TooltipID>TOOLTIPTEXT_BACKUP_ATTITUDE_INDICATOR_BANK_PITCH</TooltipID>
		</MouseRect>
	</PartInfo>
Switch code:

Code:
	<PartInfo>
		<Name>AN28_OVR_CPADI_SW</Name>
		<AnimLength>2</AnimLength>
		<Animation>
			<Parameter>
				<Code>
					(L:CP_ADIInd_SW, enum)
				</Code>
				<Lag>200</Lag>
			</Parameter>
		</Animation>
		<Visibility>
			<Parameter>
				<Code>
					(L:RightPanelLight_SW, enum) 0 &gt;
					(A:CIRCUIT GENERAL PANEL ON, bool) 0 &gt;
					and
					(L:CP_ADIInd_SW, enum) 1 ==
					and
					if{ 1 } els{ 0 }
				</Code>
			</Parameter>			
		</Visibility>
		<MouseRect>
			<Cursor>Hand</Cursor>
			<TooltipText>Right Main ADI Switch</TooltipText>
			<MouseFlags>LeftSingle+RightSingle+Wheel</MouseFlags>
			<CallbackCode>
				(M:Event) 'RightSingle' scmp 0 == if{ (L:CP_ADIInd_SW, enum) -- 0 max (>L:CP_ADIInd_SW, enum) } 
				(M:Event) 'LeftSingle' scmp 0 ==  if{ (L:CP_ADIInd_SW, enum) ++ 1 min (>L:CP_ADIInd_SW, enum) } 
				(M:Event) 'WheelUp' scmp 0 == if{ (L:CP_ADIInd_SW, enum) ++ 0 max (>L:CP_ADIInd_SW, enum) } 
				(M:Event) 'WheelDown' scmp 0 == if{ (L:CP_ADIInd_SW, enum) -- 1 min (>L:CP_ADIInd_SW, enum) }
			</CallbackCode>
		</MouseRect>
	</PartInfo>
EDIT: I should add that ADI pitch animation is attached to the ball, which is linked to small tiny poly (parent) positioned inside the ball. The ADI bank animation is attached to the poly. The bank animation is keyframed every 90 degrees, from 0 degrees (level position) CW up to 359 degrees.

I will apreciate any help.

Radek Koterbski
vel IntruderPL

EDIT: Problem solved. Probably the solution was removing a switch linked with ball by code (Attitude cage, bool). Everything works nicely.
 
Last edited:
Top