Emesary damage system (passives)

This commit is contained in:
Nikolai V Chr
2020-10-29 00:29:46 +01:00
parent 852799aef7
commit 30ed82091b
247 changed files with 1798366 additions and 54074 deletions
File diff suppressed because it is too large Load Diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 192 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

File diff suppressed because it is too large Load Diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 181 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 549 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 267 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 724 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 KiB

File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 700 B

@@ -0,0 +1,74 @@
<?xml version="1.0"?>
<PropertyList>
<particlesystem>
<name>bombhit-smoke</name>
<texture>smoke.png</texture>
<emissive>false</emissive>
<lighting>false</lighting>
<align>billboard</align>
<attach>world</attach>
<placer>
<type>point</type>
</placer>
<shooter>
<theta-min-deg>30</theta-min-deg>
<theta-max-deg>60</theta-max-deg>
<phi-min-deg>-180</phi-min-deg>
<phi-max-deg> 180</phi-max-deg>
<speed-mps>
<value>5</value>
<spread>5</spread>
</speed-mps>
<rotation-speed>
<x-min-deg-sec>0</x-min-deg-sec>
<y-min-deg-sec>0</y-min-deg-sec>
<z-min-deg-sec>-60</z-min-deg-sec>
<x-max-deg-sec>0</x-max-deg-sec>
<y-max-deg-sec>0</y-max-deg-sec>
<z-max-deg-sec>60</z-max-deg-sec>
</rotation-speed>
</shooter>
<counter>
<particles-per-sec>
<value>3</value>
<spread>5</spread>
</particles-per-sec>
</counter>
<particle>
<start>
<color>
<red><value>0.0</value></red>
<green><value>0.0</value></green>
<blue><value>0.0</value></blue>
<alpha><value>0.2</value></alpha>
</color>
<size>
<value>12.0</value>
</size>
</start>
<end>
<color>
<red><value>0.0</value></red>
<green><value>0.0</value></green>
<blue><value>0.0</value></blue>
<alpha><value>0.05</value></alpha>
</color>
<size>
<value>80.0</value>
</size>
</end>
<life-sec>
<value>120</value>
</life-sec>
<mass-kg>0.025</mass-kg>
<radius-m>0.40</radius-m>
</particle>
<program>
<fluid>air</fluid>
<gravity>true</gravity>
<wind>true</wind>
</program>
</particlesystem>
</PropertyList>
File diff suppressed because it is too large Load Diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 143 KiB

+103
View File
@@ -0,0 +1,103 @@
<?xml version="1.0"?>
<PropertyList>
<path>crater.ac</path>
<animation>
<type>scale</type>
<object-name>Sphere</object-name>
<x-offset>1.8</x-offset>
<y-offset>1.8</y-offset>
<z-offset>1.4</z-offset>
</animation>
<animation>
<object-name>Sphere</object-name>
<enable-hot type="bool">true</enable-hot>
</animation>
<particlesystem>
<name>explosion-smoke-longterm</name>
<texture>smoke.png</texture>
<emissive type="bool">false</emissive>
<lighting type="bool">false</lighting>
<attach>world</attach>
<placer>
<type>point</type>
</placer>
<shooter>
<theta-min-deg>0</theta-min-deg>
<theta-max-deg>20</theta-max-deg>
<phi-min-deg>-180</phi-min-deg>
<phi-max-deg>180</phi-max-deg>
<speed-mps>
<value>30</value>
<spread>10</spread>
</speed-mps>
<rotation-speed>
<x-min-deg-sec>0</x-min-deg-sec>
<y-min-deg-sec>0</y-min-deg-sec>
<z-min-deg-sec>0</z-min-deg-sec>
<x-max-deg-sec>0</x-max-deg-sec>
<y-max-deg-sec>0</y-max-deg-sec>
<z-max-deg-sec>5</z-max-deg-sec>
</rotation-speed>
</shooter>
<counter>
<particles-per-sec>
<value>2</value>
<spread>0</spread>
</particles-per-sec>
</counter>
<align>billboard</align>
<particle>
<start>
<color>
<red><value> 0.3 </value></red>
<green><value> 0.3 </value></green>
<blue><value> 0.25 </value></blue>
<alpha><value> 0.3 </value></alpha>
</color>
<size>
<value>6</value>
</size>
</start>
<end>
<color>
<red><value> 0.4 </value></red>
<green><value> 0.4 </value></green>
<blue><value> 0.4 </value></blue>
<alpha><value> 0.05 </value></alpha>
</color>
<size>
<value>12</value>
</size>
</end>
<life-sec>
<value>90</value>
</life-sec>
<mass-kg> 4.0 </mass-kg>
<radius-m> 0.4 </radius-m>
</particle>
<program>
<fluid> air </fluid>
<gravity type="bool"> true </gravity>
<wind typ="bool"> true </wind>
</program>
</particlesystem>
</PropertyList>
@@ -0,0 +1,95 @@
<?xml version="1.0"?>
<PropertyList>
<path>crater.ac</path>
<animation>
<object-name>Sphere</object-name>
<enable-hot type="bool">true</enable-hot>
</animation>
<particlesystem>
<name>explosion-smoke-longterm</name>
<texture>smoke.png</texture>
<emissive type="bool">false</emissive>
<lighting type="bool">false</lighting>
<attach>world</attach>
<placer>
<type>point</type>
</placer>
<shooter>
<theta-min-deg>0</theta-min-deg>
<theta-max-deg>20</theta-max-deg>
<phi-min-deg>-180</phi-min-deg>
<phi-max-deg>180</phi-max-deg>
<speed-mps>
<value>30</value>
<spread>10</spread>
</speed-mps>
<rotation-speed>
<x-min-deg-sec>0</x-min-deg-sec>
<y-min-deg-sec>0</y-min-deg-sec>
<z-min-deg-sec>0</z-min-deg-sec>
<x-max-deg-sec>0</x-max-deg-sec>
<y-max-deg-sec>0</y-max-deg-sec>
<z-max-deg-sec>5</z-max-deg-sec>
</rotation-speed>
</shooter>
<counter>
<particles-per-sec>
<value>2</value>
<spread>0</spread>
</particles-per-sec>
</counter>
<align>billboard</align>
<particle>
<start>
<color>
<red><value> 0.3 </value></red>
<green><value> 0.3 </value></green>
<blue><value> 0.25 </value></blue>
<alpha><value> 0.3 </value></alpha>
</color>
<size>
<value>6</value>
</size>
</start>
<end>
<color>
<red><value> 0.4 </value></red>
<green><value> 0.4 </value></green>
<blue><value> 0.4 </value></blue>
<alpha><value> 0.05 </value></alpha>
</color>
<size>
<value>10</value>
</size>
</end>
<life-sec>
<value>50</value>
</life-sec>
<mass-kg> 5.0 </mass-kg>
<radius-m> 0.4 </radius-m>
</particle>
<program>
<fluid> air </fluid>
<gravity type="bool"> true </gravity>
<wind typ="bool"> true </wind>
</program>
</particlesystem>
</PropertyList>
@@ -0,0 +1,87 @@
<PropertyList>
<path>aim-emesary.ac</path>
<particlesystem>
<name>emesary-heavy-smoke</name>
<texture>smoke.png</texture>
<emissive type="bool">false</emissive>
<lighting type="bool">false</lighting>
<attach>world</attach>
<placer>
<type>point</type>
</placer>
<shooter>
<theta-min-deg>-1.5</theta-min-deg>
<theta-max-deg>1.5</theta-max-deg>
<phi-min-deg>-1.5</phi-min-deg>
<phi-max-deg>1.5</phi-max-deg>
<speed-mps>
<value>0</value>
<spread>0</spread>
</speed-mps>
<rotation-speed>
<x-min-deg-sec>0</x-min-deg-sec>
<y-min-deg-sec>0</y-min-deg-sec>
<z-min-deg-sec>0</z-min-deg-sec>
<x-max-deg-sec>0</x-max-deg-sec>
<y-max-deg-sec>0</y-max-deg-sec>
<z-max-deg-sec>0</z-max-deg-sec>
</rotation-speed>
</shooter>
<counter>
<particles-per-sec>
<value>100</value>
<spread>0</spread>
</particles-per-sec>
</counter>
<align>billboard</align>
<particle>
<start>
<color>
<red><value> 0.3 </value></red>
<green><value> 0.3 </value></green>
<blue><value> 0.2 </value></blue>
<alpha><value> 0.5 </value></alpha>
</color>
<size>
<value>9</value>
</size>
</start>
<end>
<color>
<red><value> 0.2 </value></red>
<green><value> 0.2 </value></green>
<blue><value> 0.2 </value></blue>
<alpha><value> 0.1 </value></alpha>
</color>
<size>
<value>15</value>
</size>
</end>
<life-sec>
<value>50</value>
</life-sec>
<mass-kg> 0.5 </mass-kg>
<radius-m> 0.5 </radius-m>
</particle>
<program>
<fluid> air </fluid>
<gravity type="bool"> true </gravity>
<wind typ="bool"> true </wind>
</program>
</particlesystem>
</PropertyList>
@@ -0,0 +1,87 @@
<PropertyList>
<path>aim-emesary.ac</path>
<particlesystem>
<name>emesary-light-smoke</name>
<texture>smoke.png</texture>
<emissive type="bool">false</emissive>
<lighting type="bool">false</lighting>
<attach>world</attach>
<placer>
<type>point</type>
</placer>
<shooter>
<theta-min-deg>-1.5</theta-min-deg>
<theta-max-deg>1.5</theta-max-deg>
<phi-min-deg>-1.5</phi-min-deg>
<phi-max-deg>1.5</phi-max-deg>
<speed-mps>
<value>0</value>
<spread>0</spread>
</speed-mps>
<rotation-speed>
<x-min-deg-sec>0</x-min-deg-sec>
<y-min-deg-sec>0</y-min-deg-sec>
<z-min-deg-sec>0</z-min-deg-sec>
<x-max-deg-sec>0</x-max-deg-sec>
<y-max-deg-sec>0</y-max-deg-sec>
<z-max-deg-sec>0</z-max-deg-sec>
</rotation-speed>
</shooter>
<counter>
<particles-per-sec>
<value>100</value>
<spread>0</spread>
</particles-per-sec>
</counter>
<align>billboard</align>
<particle>
<start>
<color>
<red><value> 1.0 </value></red>
<green><value> 1.0 </value></green>
<blue><value> 0.9 </value></blue>
<alpha><value> 0.5 </value></alpha>
</color>
<size>
<value>1.5</value>
</size>
</start>
<end>
<color>
<red><value> 0.9 </value></red>
<green><value> 0.9 </value></green>
<blue><value> 0.9 </value></blue>
<alpha><value> 0.1 </value></alpha>
</color>
<size>
<value>3</value>
</size>
</end>
<life-sec>
<value>50</value>
</life-sec>
<mass-kg> 0.5 </mass-kg>
<radius-m> 0.5 </radius-m>
</particle>
<program>
<fluid> air </fluid>
<gravity type="bool"> true </gravity>
<wind typ="bool"> true </wind>
</program>
</particlesystem>
</PropertyList>
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,12 @@
<?xml version="1.0"?>
<PropertyList>
<path>parachutist.ac</path>
<offsets>
<x-m> 0.5</x-m>
<y-m> 0.000</y-m>
<z-m> 1.50</z-m>
</offsets>
</PropertyList>
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

+144
View File
@@ -0,0 +1,144 @@
<?xml version="1.0"?>
<PropertyList>
<path>Models/Effects/procedural_light.ac</path>
<animation>
<type>scale</type>
<object-name>procedural_light</object-name>
<x-offset>1000</x-offset>
<y-offset>1000</y-offset>
<z-offset>1000</z-offset>
</animation>
<effect>
<inherits-from>Effects/procedural-light</inherits-from>
<object-name>procedural_light</object-name>
<parameters>
<light_color_base_r type="float">0.84</light_color_base_r>
<light_color_base_g type="float">0.55</light_color_base_g>
<light_color_base_b type="float">0.42</light_color_base_b>
<light_color_center_r type="float">1.0</light_color_center_r>
<light_color_center_g type="float">0.9</light_color_center_g>
<light_color_center_b type="float">0.7</light_color_center_b>
<intensity_scale type="float">1.0</intensity_scale>
<is_directional type="bool">false</is_directional>
<is_strobe type="bool">false</is_strobe>
<outer_gain type="float">1</outer_gain>
</parameters>
</effect>
<animation>
<type>dist-scale</type>
<object-name>procedural_light</object-name>
<interpolation>
<entry><ind>0</ind> <dep>0.0075</dep></entry>
<entry><ind>3750</ind> <dep>0.750</dep></entry>
<entry><ind>10000</ind><dep>1.000</dep></entry>
</interpolation>
</animation>
<particlesystem>
<name>flare-smoke</name>
<texture>smoke.png</texture>
<emissive>false</emissive>
<lighting>false</lighting>
<offsets>
<x-m>0</x-m>
<y-m>0</y-m>
<z-m>0</z-m>
<pitch-deg>90</pitch-deg>
<roll-deg>90</roll-deg>
</offsets>
<attach>world</attach>
<placer>
<type>point</type>
</placer>
<shooter>
<theta-min-deg>-5</theta-min-deg>
<theta-max-deg>5</theta-max-deg>
<phi-min-deg>-5</phi-min-deg>
<phi-max-deg>5</phi-max-deg>
<speed-mps>
<value>0</value>
<spread>2</spread>
</speed-mps>
<rotation-speed>
<x-min-deg-sec>10</x-min-deg-sec>
<y-min-deg-sec>10</y-min-deg-sec>
<z-min-deg-sec>10</z-min-deg-sec>
<x-max-deg-sec>40</x-max-deg-sec>
<y-max-deg-sec>40</y-max-deg-sec>
<z-max-deg-sec>40</z-max-deg-sec>
</rotation-speed>
</shooter>
<counter>
<particles-per-sec>
<value>25</value>
<spread>5</spread>
</particles-per-sec>
</counter>
<align>billboard</align>
<particle>
<start>
<color>
<red>
<expression><product><value>0.9</value><property>/rendering/scene/diffuse/red</property></product></expression>
</red>
<green>
<expression><product><value>0.9</value><property>/rendering/scene/diffuse/red</property></product></expression>
</green>
<blue>
<expression><product><value>0.9</value><property>/rendering/scene/diffuse/red</property></product></expression>
</blue>
<alpha>
<value>1</value>
</alpha>
</color>
<size>
<value>0.6</value>
</size>
</start>
<end>
<color>
<red>
<expression><product><value>0.9</value><property>/rendering/scene/diffuse/red</property></product></expression>
</red>
<green>
<expression><product><value>0.9</value><property>/rendering/scene/diffuse/red</property></product></expression>
</green>
<blue>
<expression><product><value>0.9</value><property>/rendering/scene/diffuse/red</property></product></expression>
</blue>
<alpha>
<value>0.05</value>
</alpha>
</color>
<size>
<value>6.0</value>
</size>
</end>
<life-sec>
<value>2.75</value>
</life-sec>
<mass-kg>0.00001</mass-kg>
<radius-m>0.015</radius-m>
</particle>
<program>
<fluid>air</fluid>
<gravity type="bool">false</gravity>
<wind type="bool">true</wind>
</program>
</particlesystem>
</PropertyList>
+260
View File
@@ -0,0 +1,260 @@
#
#
# Use to transmit events that happen at a specific place; can be used to make
# models that are simulated locally (e.g. tankers) appear on other player's MP sessions.
var ArmamentNotification_Id = 19;
var ArmamentNotification =
{
# new:
# _ident - the identifier for the notification. not bridged.
# _name - name of the notification, bridged.
# _kind - created, moved, deleted, impact (see notifications.nas)
# _secondary_kind - This is the entity on which the activity is being performed. See below for predefined types.
##
new: func(_ident="none", _kind=0, _secondary_kind=0)
{
var new_class = emesary.Notification.new("ArmamentNotification", _ident, ArmamentNotification_Id);
new_class.Kind = _kind;
new_class.SecondaryKind = _secondary_kind;
new_class.RelativeAltitude = 0;
new_class.IsDistinct = 0;
new_class.Distance = 0;
new_class.Bearing = 0;
new_class.RemoteCallsign = ""; # associated remote callsign.
new_class.bridgeProperties = func
{
return
[
{
getValue:func{return emesary.TransferByte.encode(new_class.Kind);},
setValue:func(v,root,pos){var dv=emesary.TransferByte.decode(v,pos);new_class.Kind=dv.value;return dv},
},
{
getValue:func{return emesary.TransferByte.encode(new_class.SecondaryKind);},
setValue:func(v,root,pos){var dv=emesary.TransferByte.decode(v,pos);new_class.SecondaryKind=dv.value;return dv},
},
{
getValue:func{return emesary.TransferFixedDouble.encode(new_class.RelativeAltitude,2,1/10);},
setValue:func(v,root,pos){var dv=emesary.TransferFixedDouble.decode(v,2,1/10,pos);new_class.RelativeAltitude=dv.value;return dv},
},
{
getValue:func{return emesary.TransferFixedDouble.encode(new_class.Distance,2,1/10);},
setValue:func(v,root,pos){var dv=emesary.TransferFixedDouble.decode(v,2,1/10,pos);new_class.Distance=dv.value;return dv},
},
{
getValue:func{return emesary.TransferFixedDouble.encode(geo.normdeg180(new_class.Bearing),1,1.54);},
setValue:func(v,root,pos){var dv=emesary.TransferFixedDouble.decode(v,1,1.54,pos);new_class.Bearing=geo.normdeg(dv.value);return dv},
},
{
getValue:func{return emesary.TransferString.encode(new_class.RemoteCallsign);},
setValue:func(v,root,pos){var dv=emesary.TransferString.decode(v,pos);new_class.RemoteCallsign=dv.value;return dv},
},
];
};
return new_class;
},
};
var ArmamentInFlightNotification_Id = 21;
var ArmamentInFlightNotification =
{
# new:
# _ident - the identifier for the notification. not bridged.
# _name - name of the notification, bridged.
# _kind - created, moved, deleted (see below). This is the activity that the notification represents, called kind to avoid confusion with notification type.
# _secondary_kind - This is the entity on which the activity is being performed. See below for predefined types.
#
# UniqueIdentity - an identity that is unique to the sending instance of FG. Can be combined with the callsign to create an MP unique ID.
##
new: func(_ident="none", _unique=0, _kind=0, _secondary_kind=0)
{
var new_class = emesary.Notification.new("ArmamentInFlightNotification", _ident, ArmamentInFlightNotification_Id);
new_class.Kind = _kind;
new_class.SecondaryKind = _secondary_kind;
new_class.Position = geo.aircraft_position();
new_class.UniqueIndex = 0;
new_class.Heading = 360;
new_class.Pitch = 90;
new_class.u_fps = 0;
new_class.IsDistinct = 0;
new_class.Callsign = nil; # populated automatically by the incoming bridge when routed
new_class.RemoteCallsign = ""; # associated remote callsign.
new_class.Flags = 0; # 8 bits for whatever.
new_class.UniqueIdentity = _unique;
new_class.GetBridgeMessageNotificationTypeKey = func {
return new_class.NotificationType~"."~new_class.Ident~"."~new_class.UniqueIndex;
};
new_class.bridgeProperties = func
{
return
[
{
getValue:func{return emesary.TransferCoord.encode(new_class.Position);},
setValue:func(v,root,pos){var dv=emesary.TransferCoord.decode(v, pos);new_class.Position=dv.value;return dv},
},
{
getValue:func{return emesary.TransferByte.encode(new_class.Kind);},
setValue:func(v,root,pos){var dv=emesary.TransferByte.decode(v,pos);new_class.Kind=dv.value;return dv},
},
{
getValue:func{return emesary.TransferByte.encode(new_class.SecondaryKind);},
setValue:func(v,root,pos){var dv=emesary.TransferByte.decode(v,pos);new_class.SecondaryKind=dv.value;return dv},
},
{
#0..6696 fps (3967kts), mach 6.1 (SL) - factor 0.03703
getValue:func{return emesary.TransferFixedDouble.encode(new_class.u_fps-3348,1,1/0.03703);},
setValue:func(v,root,pos){var dv=emesary.TransferFixedDouble.decode(v,1,1/0.03703,pos);new_class.u_fps=dv.value+3348;return dv},
},
{
getValue:func{return emesary.TransferFixedDouble.encode(geo.normdeg180(new_class.Heading),1,1.54);},#1.0/0.65
setValue:func(v,root,pos){var dv=emesary.TransferFixedDouble.decode(v,1,1.54,pos);new_class.Heading=geo.normdeg(dv.value);return dv},
},
{
getValue:func{return emesary.TransferFixedDouble.encode(new_class.Pitch, 1, 1/1.38);},
setValue:func(v,root,pos){var dv=emesary.TransferFixedDouble.decode(v,1, 1/1.38, pos);new_class.Pitch=dv.value;return dv},
},
{
getValue:func{return emesary.TransferString.encode(new_class.RemoteCallsign);},
setValue:func(v,root,pos){var dv=emesary.TransferString.decode(v,pos);new_class.RemoteCallsign=dv.value;return dv},
},
{
getValue:func{return emesary.TransferByte.encode(new_class.Flags);},
setValue:func(v,root,pos){var dv=emesary.TransferByte.decode(v,pos);new_class.Flags=dv.value;return dv},
},
{
getValue:func{return emesary.TransferByte.encode(new_class.UniqueIdentity);},
setValue:func(v,root,pos){var dv=emesary.TransferByte.decode(v,pos);new_class.UniqueIdentity=dv.value;return dv},
},
];
};
return new_class;
},
};
var StaticNotification_Id = 25;
var StaticNotification =
{
# new:
# _ident - the identifier for the notification. not bridged.
# _kind - created, moved, deleted (see below). This is the activity that the notification represents, called kind to avoid confusion with notification type.
# _secondary_kind - This is the entity on which the activity is being performed. See below for predefined types.
#
# UniqueIdentity - an identity that is unique to the sending instance of FG. Can be combined with the callsign to create an MP unique ID.
##
new: func(_ident="stat", _unique=0, _kind=0, _secondary_kind=0)
{
var new_class = emesary.Notification.new("StaticNotification", _ident, StaticNotification_Id);
# _ident -> "stat"
new_class.UniqueIdentity = _unique; # random from 0 to 15000000 that identifies each static object
new_class.Kind = _kind; # 1=create, 2=move, 3=delete, 4=request_all
new_class.SecondaryKind = _secondary_kind; # 0 = small crater, 1 = big crater, 2 = smoke
new_class.IsDistinct = 0; # keep it 0
new_class.Callsign = nil; # populated automatically by the incoming bridge when routed
new_class.Position = geo.aircraft_position(); # position
new_class.Heading = 360; # heading
new_class.Flags1 = 0; # 7 bits for whatever.
new_class.Flags2 = 0; # 7 bits for whatever.
new_class.GetBridgeMessageNotificationTypeKey = func {
return new_class.NotificationType~"."~new_class.Ident~"."~new_class.UniqueIdentity;
};
new_class.bridgeProperties = func
{
return
[
{
getValue:func{return emesary.TransferCoord.encode(new_class.Position);},
setValue:func(v,root,pos){var dv=emesary.TransferCoord.decode(v, pos);new_class.Position=dv.value;return dv},
},
{
getValue:func{return emesary.TransferByte.encode(new_class.Kind);},
setValue:func(v,root,pos){var dv=emesary.TransferByte.decode(v,pos);new_class.Kind=dv.value;return dv},
},
{
getValue:func{return emesary.TransferByte.encode(new_class.SecondaryKind);},
setValue:func(v,root,pos){var dv=emesary.TransferByte.decode(v,pos);new_class.SecondaryKind=dv.value;return dv},
},
{
getValue:func{return emesary.TransferFixedDouble.encode(geo.normdeg180(new_class.Heading),1,1.54);},#1.0/0.65
setValue:func(v,root,pos){var dv=emesary.TransferFixedDouble.decode(v,1,1.54,pos);new_class.Heading=geo.normdeg(dv.value);return dv},
},
{
getValue:func{return emesary.TransferByte.encode(new_class.Flags1);},
setValue:func(v,root,pos){var dv=emesary.TransferByte.decode(v,pos);new_class.Flags1=dv.value;return dv},
},
{
getValue:func{return emesary.TransferByte.encode(new_class.Flags2);},
setValue:func(v,root,pos){var dv=emesary.TransferByte.decode(v,pos);new_class.Flags2=dv.value;return dv},
},
{
getValue:func{return emesary.TransferInt.encode(new_class.UniqueIdentity,3);},
setValue:func(v,root,pos){var dv=emesary.TransferInt.decode(v,3,pos);new_class.UniqueIdentity=dv.value;return dv},
},
];
};
return new_class;
},
};
var ObjectInFlightNotification_Id = 22;
var ObjectInFlightNotification =
{
# new:
# _ident - the identifier for the notification. not bridged.
# _name - name of the notification, bridged.
# _kind - created, moved, deleted (see below). This is the activity that the notification represents, called kind to avoid confusion with notification type.
# _secondary_kind - This is the entity on which the activity is being performed. See below for predefined types.
#
# UniqueIdentity - an identity that is unique to the sending instance of FG. Can be combined with the callsign to create an MP unique ID.
##
new: func(_ident="none", _unique=0, _kind=0, _secondary_kind=0)
{
var new_class = emesary.Notification.new("ObjectInFlightNotification", _ident, ObjectInFlightNotification_Id);
new_class.Kind = _kind;
new_class.SecondaryKind = _secondary_kind;
new_class.Position = geo.aircraft_position();
new_class.UniqueIndex = 0;
new_class.IsDistinct = 1;
new_class.Callsign = nil; # populated automatically by the incoming bridge when routed
new_class.UniqueIdentity = _unique;
new_class.GetBridgeMessageNotificationTypeKey = func {
return new_class.NotificationType~"."~new_class.Ident~"."~new_class.UniqueIndex;
};
new_class.bridgeProperties = func
{
return
[
{
getValue:func{return emesary.TransferCoord.encode(new_class.Position);},
setValue:func(v,root,pos){var dv=emesary.TransferCoord.decode(v, pos);new_class.Position=dv.value;return dv},
},
{
getValue:func{return emesary.TransferByte.encode(new_class.Kind);},
setValue:func(v,root,pos){var dv=emesary.TransferByte.decode(v,pos);new_class.Kind=dv.value;return dv},
},
{
getValue:func{return emesary.TransferByte.encode(new_class.SecondaryKind);},
setValue:func(v,root,pos){var dv=emesary.TransferByte.decode(v,pos);new_class.SecondaryKind=dv.value;return dv},
},
{
getValue:func{return emesary.TransferByte.encode(new_class.UniqueIdentity);},
setValue:func(v,root,pos){var dv=emesary.TransferByte.decode(v,pos);new_class.UniqueIdentity=dv.value;return dv},
},
];
};
return new_class;
},
};
@@ -0,0 +1,53 @@
# Emesary bridged transmitter for armament notifications.
#
# Richard Harrison 2017
#
# NOTES:
# 1.The incoming bridges that is defined here will apply to all models that
# are loaded over MP; it is better to create the bridges here rather than in the model.xml
# So given that we don't want a bridge on all MP models only those that are on OPRF
# aircraft that want to receive notifications we will create the incoming bridge here
# and thus only an OPRF model will receive notifications from another OPRF model.
#
# 2. The Emesary MP bridge requires two sides; the outgoing and incoming.
# - The outgoing aircraft will forwards all received notifications via MP;
# and these will be received by a similarly equipped craft.
# - The receiving aircraft will receive all notifications from other MP craft via
# the globalTransmitter - which is bridged via property #18 /sim/multiplay/emesary/bridge[18]
#------------------------------------------------------------------------------------------
# Setup the bridge
# armament notification 24 bytes
# geoEventNotification - 34 bytes + the length of the RemoteCallsign and Name fields.
#NOTE: due to bug in Emesary MP Bridge (fixed in 2019.2 after 24/3/2020) we can only
# reliably send one message type per bridge - so for the maximum compatibility
# we will use two bridges.
# If at some point in the future we target 2019.2 as a min ver we can use a single
# bridge and setup the notification list to contain all of the armament hit/flying notifications
#i.e. change to [notifications.ArmamentInFlightNotification.new(nil), notifications.ArmamentNotification.new(nil)];
var geoRoutedNotifications = [notifications.ArmamentInFlightNotification.new()];
var geoBridgedTransmitter = emesary.Transmitter.new("geoOutgoingBridge");
var geooutgoingBridge = emesary_mp_bridge.OutgoingMPBridge.new("mp.geo",geoRoutedNotifications, 18, "", geoBridgedTransmitter);
# bridge should be tuned to be around 90% of the packet size full.
geooutgoingBridge.TransmitFrequencySeconds = 0.75;
geooutgoingBridge.MPStringMaxLen = 150;
emesary_mp_bridge.IncomingMPBridge.startMPBridge(geoRoutedNotifications, 18, emesary.GlobalTransmitter);
#----- bridge hit (armament) notifications
var hitRoutedNotifications = [notifications.ArmamentNotification.new(),notifications.StaticNotification.new()];
var hitBridgedTransmitter = emesary.Transmitter.new("armamentNotificationBridge");
var hitoutgoingBridge = emesary_mp_bridge.OutgoingMPBridge.new("mp.hit",hitRoutedNotifications, 19, "", hitBridgedTransmitter);
hitoutgoingBridge.TransmitFrequencySeconds = 1.5;
hitoutgoingBridge.MPStringMaxLen = 120;
emesary_mp_bridge.IncomingMPBridge.startMPBridge(hitRoutedNotifications, 19, emesary.GlobalTransmitter);
#----- bridge object notifications
var objectRoutedNotifications = [notifications.ObjectInFlightNotification.new()];
var objectBridgedTransmitter = emesary.Transmitter.new("objectNotificationBridge");
var objectoutgoingBridge = emesary_mp_bridge.OutgoingMPBridge.new("mp.object",objectRoutedNotifications, 17, "", objectBridgedTransmitter);
objectoutgoingBridge.TransmitFrequencySeconds = 0.2;
objectoutgoingBridge.MessageLifeTime = 1;
objectoutgoingBridge.MPStringMaxLen = 150;
emesary_mp_bridge.IncomingMPBridge.startMPBridge(objectRoutedNotifications, 17, emesary.GlobalTransmitter);
File diff suppressed because it is too large Load Diff
+338
View File
@@ -0,0 +1,338 @@
var Math = {
#
# Authors: Nikolai V. Chr, Axel Paccalin.
#
# Version 1.93
#
# When doing euler coords. to cartesian: +x = forw, +y = left, +z = up.
# FG struct. coords: +x = back, +y = right, +z = up.
#
# If euler to cartesian (with inverted heading) then:
# cartesian vector will be x: north, y: west, z: skyward
#
# When doing euler angles (from pilots point of view): yaw = yaw left, pitch = rotate up, roll = roll right.
# FG rotations: heading = yaw right, pitch = rotate up, roll = roll right.
#
clamp: func(v, min, max) { v < min ? min : v > max ? max : v },
convertCoords: func (x,y,z) {
return [-x, -y, z];
},
convertAngles: func (heading,pitch,roll) {
return [-heading, pitch, roll];
},
# returns direction in geo coordinate system
vectorToGeoVector: func (a, coord) {
me.handp = me.cartesianToEuler(a);
me.end_dist_m = 100;# not too low for floating point precision. Not too high to get into earth curvature stuff.
me.tgt_coord = geo.Coord.new(coord);
if (me.handp[0] != nil) {
me.tgt_coord.apply_course_distance(me.handp[0],me.end_dist_m);
me.upamount = me.end_dist_m * math.tan(me.handp[1]*D2R);
} elsif (me.handp[1] == 90) {
me.upamount = me.end_dist_m;
} else {
me.upamount = -me.end_dist_m;
}
me.tgt_coord.set_alt(coord.alt()+me.upamount);
return {"x":me.tgt_coord.x()-coord.x(), "y":me.tgt_coord.y()-coord.y(), "z":me.tgt_coord.z()-coord.z()};
},
# When observing another MP aircraft the groundspeed velocity info is in body frame, this method will convert it to cartesian vector.
getCartesianVelocity: func (yaw_deg, pitch_deg, roll_deg, uBody_fps, vBody_fps, wBody_fps) {
me.bodyVelocity = [uBody_fps, -vBody_fps, -wBody_fps];
return me.yawPitchRollVector(yaw_deg, pitch_deg, roll_deg, me.bodyVelocity);
},
# angle between 2 vectors. Returns 0-180 degrees.
angleBetweenVectors: func (a,b) {
a = me.normalize(a);
b = me.normalize(b);
me.value = me.clamp((me.dotProduct(a,b)/me.magnitudeVector(a))/me.magnitudeVector(b),-1,1);#just to be safe in case some floating point error makes it out of bounds
return R2D * math.acos(me.value);
},
# length of vector
magnitudeVector: func (a) {
return math.sqrt(math.pow(a[0],2)+math.pow(a[1],2)+math.pow(a[2],2));
},
# dot product of 2 vectors
dotProduct: func (a,b) {
return a[0]*b[0]+a[1]*b[1]+a[2]*b[2];
},
# rotate a vector. Order: roll, pitch, yaw
rollPitchYawVector: func (roll, pitch, yaw, vector) {
me.rollM = me.rollMatrix(roll);
me.pitchM = me.pitchMatrix(pitch);
me.yawM = me.yawMatrix(yaw);
me.rotation = me.multiplyMatrices(me.rollM, me.multiplyMatrices(me.pitchM, me.yawM));
return me.multiplyMatrixWithVector(me.rotation, vector);
},
# rotate a vector. Order: yaw, pitch, roll (like an aircraft)
yawPitchRollVector: func (yaw, pitch, roll, vector) {
me.rollM = me.rollMatrix(roll);
me.pitchM = me.pitchMatrix(pitch);
me.yawM = me.yawMatrix(yaw);
me.rotation = me.multiplyMatrices(me.yawM, me.multiplyMatrices(me.pitchM, me.rollM));
return me.multiplyMatrixWithVector(me.rotation, vector);
},
# multiply 3x3 matrix with vector
multiplyMatrixWithVector: func (matrix, vector) {
return [matrix[0]*vector[0]+matrix[1]*vector[1]+matrix[2]*vector[2],
matrix[3]*vector[0]+matrix[4]*vector[1]+matrix[5]*vector[2],
matrix[6]*vector[0]+matrix[7]*vector[1]+matrix[8]*vector[2]];
},
# multiply 2 3x3 matrices
multiplyMatrices: func (a,b) {
return [a[0]*b[0]+a[1]*b[3]+a[2]*b[6], a[0]*b[1]+a[1]*b[4]+a[2]*b[7], a[0]*b[2]+a[1]*b[5]+a[2]*b[8],
a[3]*b[0]+a[4]*b[3]+a[5]*b[6], a[3]*b[1]+a[4]*b[4]+a[5]*b[7], a[3]*b[2]+a[4]*b[5]+a[5]*b[8],
a[6]*b[0]+a[7]*b[3]+a[8]*b[6], a[6]*b[1]+a[7]*b[4]+a[8]*b[7], a[6]*b[2]+a[7]*b[5]+a[8]*b[8]];
},
# matrix for rolling
rollMatrix: func (roll) {
roll = roll * D2R;
return [1,0,0,
0,math.cos(roll),-math.sin(roll),
0,math.sin(roll), math.cos(roll)];
},
# matrix for pitching
pitchMatrix: func (pitch) {
pitch = pitch * D2R;
return [math.cos(pitch),0,-math.sin(pitch),
0,1,0,
math.sin(pitch),0,math.cos(pitch)];
},
# matrix for yawing
yawMatrix: func (yaw) {
yaw = yaw * D2R;
return [math.cos(yaw),-math.sin(yaw),0,
math.sin(yaw),math.cos(yaw),0,
0,0,1];
},
# vector to heading/pitch
cartesianToEuler: func (vector) {
me.horz = math.sqrt(vector[0]*vector[0]+vector[1]*vector[1]);
if (me.horz != 0) {
me.pitch = math.atan2(vector[2],me.horz)*R2D;
me.hdg = math.asin(-vector[1]/me.horz)*R2D;
if (vector[0] < 0) {
# south
if (me.hdg >= 0) {
me.hdg = 180-me.hdg;
} else {
me.hdg = -180-me.hdg;
}
}
me.hdg = geo.normdeg(me.hdg);
} else {
me.pitch = vector[2]>=0?90:-90;
me.hdg = nil;
}
return [me.hdg, me.pitch];
},
# gives an vector that points up from fuselage
eulerToCartesian3Z: func (yaw_deg, pitch_deg, roll_deg) {
me.yaw = yaw_deg * D2R;
me.pitch = pitch_deg * D2R;
me.roll = roll_deg * D2R;
me.x = -math.cos(me.yaw)*math.sin(me.pitch)*math.cos(me.roll) + math.sin(me.yaw)*math.sin(me.roll);
me.y = -math.sin(me.yaw)*math.sin(me.pitch)*math.cos(me.roll) - math.cos(me.yaw)*math.sin(me.roll);
me.z = math.cos(me.pitch)*math.cos(me.roll);#roll changed from sin to cos, since the rotation matrix is wrong
return [me.x,me.y,me.z];
},
# gives an vector that points forward from fuselage
eulerToCartesian3X: func (yaw_deg, pitch_deg, roll_deg) {
me.yaw = yaw_deg * D2R;
me.pitch = pitch_deg * D2R;
me.roll = roll_deg * D2R;
me.x = math.cos(me.yaw)*math.cos(me.pitch);
me.y = math.sin(me.yaw)*math.cos(me.pitch);
me.z = math.sin(me.pitch);
return [me.x,me.y,me.z];
},
# gives an vector that points left from fuselage
eulerToCartesian3Y: func (yaw_deg, pitch_deg, roll_deg) {
me.yaw = yaw_deg * D2R;
me.pitch = pitch_deg * D2R;
me.roll = roll_deg * D2R;
me.x = -math.cos(me.yaw)*math.sin(me.pitch)*math.sin(me.roll) - math.sin(me.yaw)*math.cos(me.roll);
me.y = -math.sin(me.yaw)*math.sin(me.pitch)*math.sin(me.roll) + math.cos(me.yaw)*math.cos(me.roll);
me.z = math.cos(me.pitch)*math.sin(me.roll);
return [me.x,me.y,me.z];
},
# same as eulerToCartesian3X, except it needs no roll
eulerToCartesian2: func (yaw_deg, pitch_deg) {
me.yaw = yaw_deg * D2R;
me.pitch = pitch_deg * D2R;
me.x = math.cos(me.pitch) * math.cos(me.yaw);
me.y = math.cos(me.pitch) * math.sin(me.yaw);
me.z = math.sin(me.pitch);
return [me.x,me.y,me.z];
},
#pitch from coord1 to coord2 in degrees (takes curvature of earth into effect.)
getPitch: func (coord1, coord2) {
if (coord1.lat() == coord2.lat() and coord1.lon() == coord2.lon()) {
if (coord2.alt() > coord1.alt()) {
return 90;
} elsif (coord2.alt() < coord1.alt()) {
return -90;
} else {
return 0;
}
}
if (coord1.alt() != coord2.alt()) {
me.d12 = coord1.direct_distance_to(coord2);
me.coord3 = geo.Coord.new(coord1);
me.coord3.set_alt(coord1.alt()-me.d12*0.5);# this will increase the area of the triangle so that rounding errors dont get in the way.
me.d13 = coord1.alt()-me.coord3.alt();
if (me.d12 == 0) {
# on top of each other, maybe rounding error..
return 0;
}
me.d32 = me.coord3.direct_distance_to(coord2);
if (math.abs(me.d13)+me.d32 < me.d12) {
# rounding errors somewhere..one triangle side is longer than other 2 sides combined.
return 0;
}
# standard formula for a triangle where all 3 side lengths are known:
me.len = (math.pow(me.d12, 2)+math.pow(me.d13,2)-math.pow(me.d32, 2))/(2 * me.d12 * math.abs(me.d13));
if (me.len < -1 or me.len > 1) {
# something went wrong, maybe rounding error..
return 0;
}
me.angle = R2D * math.acos(me.len);
me.pitch = -1* (90 - me.angle);
#printf("d12 %.4f d32 %.4f d13 %.4f len %.4f pitch %.4f angle %.4f", me.d12, me.d32, me.d13, me.len, me.pitch, me.angle);
return me.pitch;
} else {
# same altitude
me.nc = geo.Coord.new();
me.nc.set_xyz(0,0,0); # center of earth
me.radiusEarth = coord1.direct_distance_to(me.nc);# current distance to earth center
me.d12 = coord1.direct_distance_to(coord2);
# standard formula for a triangle where all 3 side lengths are known:
me.len = (math.pow(me.d12, 2)+math.pow(me.radiusEarth,2)-math.pow(me.radiusEarth, 2))/(2 * me.d12 * me.radiusEarth);
if (me.len < -1 or me.len > 1) {
# something went wrong, maybe rounding error..
return 0;
}
me.angle = R2D * math.acos(me.len);
me.pitch = -1* (90 - me.angle);
return me.pitch;
}
},
# supply a normal to the plane, and a vector. The vector will be projected onto the plane, and that projection is returned as a vector.
projVectorOnPlane: func (planeNormal, vector) {
return me.minus(vector, me.product(me.dotProduct(vector,planeNormal)/math.pow(me.magnitudeVector(planeNormal),2), planeNormal));
},
# unary - vector
opposite: func (v){
# author: Paccalin
return [-v[0], -v[1], -v[2]];
},
# vector a - vector b
minus: func (a, b) {
return [a[0]-b[0], a[1]-b[1], a[2]-b[2]];
},
# vector a + vector b
plus: func (a, b) {
return [a[0]+b[0], a[1]+b[1], a[2]+b[2]];
},
# float * vector
product: func (scalar, vector) {
return [scalar*vector[0], scalar*vector[1], scalar*vector[2]]
},
# print vector to console
format: func (v) {
return sprintf("(%.1f, %.1f, %.1f)",v[0],v[1],v[2]);
},
# make vector length 1.0
normalize: func (v) {
me.mag = me.magnitudeVector(v);
return [v[0]/me.mag, v[1]/me.mag, v[2]/me.mag];
},
crossProduct: func (a,b) {
return [a[1]*b[2]-a[2]*b[1], a[2]*b[0]-a[0]*b[2], a[0]*b[1]-a[1]*b[0]];
},
distance_from_point_to_line: func (coordP, coordL1, coordL2) {
var P = [coordP.x(), coordP.y(), coordP.z()];
var L1 = [coordL1.x(), coordL1.y(), coordL1.z()];
var L2 = [coordL2.x(), coordL2.y(), coordL2.z()];
return me.magnitudeVector(me.crossProduct(me.minus(L2,L1), me.minus(L1,P)))/me.magnitudeVector(me.minus(L2,L1));
},
# Orthogonal projection of a vector `vec` onto another `ref` !!can throw an exception if the referential vector is null!!.
orthogonalProjection: func(vec, ref){
# author: Paccalin
me.op_refMag = me.magnitudeVector(ref);
if(me.op_refMag == 0)
die("Orthogonal projection on a null vector referential");
return me.dotProduct(vec, ref) / me.op_refMag;
},
# Time at which two particles will be at shortest distance !!can throw an exception if the relative speed is null!!
particleShortestDistTime: func (orig1, speed1, orig2, speed2) {
# author: Paccalin
# Compute the origin of the second particle in a referential positionally centered on the first particle.
me.psdt_tgtOrig = me.minus(orig2, orig1);
# Compute the speed of the second particle in a referential inertially based on the first particle.
me.psdt_tgtSpeed = me.minus(speed2, speed1);
# Project the origin of the particle1 referential onto the line supported by the particle2 trajectory in 1 unit of time.
# And divide the result by the magnitude of the speed to have it normalized relative to the time.
return me.orthogonalProjection(me.opposite(me.psdt_tgtOrig), me.psdt_tgtSpeed) / me.magnitudeVector(me.psdt_tgtSpeed);
},
# rotation matrices
#
#
#| 1 0 0 |
#| 0 cos(roll) -sin(roll) |
#| 0 sin(roll) cos(roll) |
#
#| cos(pitch) 0 -sin(pitch) |
#| 0 1 0 |
#| sin(pitch) 0 cos(pitch) |
#
#| cos(yaw) -sin(yaw) 0 |
#| sin(yaw) cos(yaw) 0 |
#| 0 0 1 |
#
# combined matrix from yaw, pitch, roll:
#
#| cos(yaw)cos(pitch) -cos(yaw)sin(pitch)sin(roll)-sin(yaw)cos(roll) -cos(yaw)sin(pitch)cos(roll)+sin(yaw)sin(roll)|
#| sin(yaw)cos(pitch) -sin(yaw)sin(pitch)sin(roll)+cos(yaw)cos(roll) -sin(yaw)sin(pitch)cos(roll)-cos(yaw)sin(roll)|
#| sin(pitch) cos(pitch)sin(roll) cos(pitch)cos(roll)|
#
#
};
+91
View File
@@ -0,0 +1,91 @@
<?xml version="1.0"?>
<PropertyList>
<name>flightlog</name>
<modal>false</modal>
<layout>vbox</layout>
<draggable>true</draggable>
<resizable>true</resizable>
<group>
<layout>hbox</layout>
<empty><stretch>1</stretch></empty>
<text>
<label>Event log</label>
</text>
<empty><stretch>1</stretch></empty>
<button>
<pref-width>16</pref-width>
<pref-height>16</pref-height>
<legend></legend>
<default>1</default>
<keynum>27</keynum>
<border>2</border>
<binding>
<command>dialog-close</command>
</binding>
<binding>
<command>dialog-apply</command>
</binding>
</button>
</group>
<nasal>
<open>
<![CDATA[
setprop("sim/model/mig21/event-log", "Click refresh to see the event log..");
]]>
</open>
<close>
<![CDATA[
setprop("sim/model/mig21/event-log", "");
]]>
</close>
</nasal>
<button>
<!--<x>0</x>
<y>0</y>-->
<legend>Refresh</legend>
<binding>
<command>nasal</command>
<script><![CDATA[
var str = "";
if (1) {
var buffer = damage.damageLog.get_buffer();
foreach(entry; buffer) {
str = str~""~entry.time~" "~entry.message~"\n";
}
} else {
str = "The aircraft must be still to read the event log.";
}
setprop("sim/model/mig21/event-log", str);
]]></script>
</binding>
</button>
<text>
<label>Log:</label>
</text>
<textbox>
<!-- position -->
<!--<x>100</x>
<y>100</y>-->
<!-- dimensions -->
<pref-width>500</pref-width>
<pref-height>500</pref-height>
<property>/sim/model/mig21/event-log</property>
<live>true</live>
<slider>15</slider> <!--width for slider -->
<wrap>false</wrap> <!-- don't wrap text; default: true -->
<top-line>0</top-line> <!-- line to show at top, -ve numbers show last line -->
<editable>false</editable> <!-- if the puLargeInput is supposed to be editable -->
</textbox>
</PropertyList>
+21
View File
@@ -126,15 +126,36 @@
<path>Systems/views.xml</path>
</property-rule>
</systems>
<menubar>
<default>
<menu n="100">
<label>Truck</label>
<enabled type="bool">true</enabled>
<item>
<label>Event Log</label>
<binding>
<command>dialog-show</command>
<dialog-name>flightlog</dialog-name>
</binding>
</item>
</menu>
</default>
</menubar>
</sim>
<payload>
<armament>
<models type="string">Aircraft/groundtarget/Models/emesary/</models>
<msg type="bool">true</msg>
</armament>
</payload>
<nasal>
<notifications>
<file>Aircraft/groundtarget/Nasal/ArmamentNotification.nas</file>
<file>Aircraft/groundtarget/Nasal/GeoBridgedTransmitter.nas</file>
</notifications>
<carrier>
<file>Aircraft/groundtarget/Nasal/fdm.nas</file>
</carrier>