Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cbc1888425 | ||
|
|
ea72151d48 | ||
|
|
bcd7d3cca8 | ||
|
|
6cd64a486a | ||
|
|
93a0d6f46d | ||
|
|
f4356c079f | ||
|
|
9ed54d98b6 | ||
|
|
b12e139b2c | ||
|
|
b1403b3066 | ||
|
|
3376a6f35d | ||
|
|
1d22597d3f | ||
|
|
467336590b |
18
CHANGELOG.md
18
CHANGELOG.md
@@ -1,15 +1,27 @@
|
||||
# CHANGELOG
|
||||
|
||||
## v.1.7.0
|
||||
|
||||
- Add possibility to set max altitude in route dialog
|
||||
|
||||
## v.1.6.0
|
||||
|
||||
- Add sound support from internal and external view for C-74 aircraft (thanks to wlbragg)
|
||||
|
||||
## v.1.5.0
|
||||
|
||||
- Add Towrope Configuration dialog
|
||||
|
||||
## v.1.4.1
|
||||
|
||||
- Fix carsh by missing parameter
|
||||
- Fix crash by missing parameter
|
||||
|
||||
## v.1.4.0
|
||||
|
||||
- Add Douglas C-47 as a tow plane
|
||||
- Add Douglas C-47 as a tow plane (thanks to wlbragg)
|
||||
- Add possibility to take off in the bush
|
||||
- Add a separate engine sound for the DR400
|
||||
- Add French translation of meta data
|
||||
- Add French translation of meta data (thanks to Florent)
|
||||
- Add possibility to save/load route waypoints with description
|
||||
|
||||
## v.1.3.0
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -2,11 +2,39 @@
|
||||
<PropertyList>
|
||||
<fx>
|
||||
<engine>
|
||||
<name>engine</name>
|
||||
<name>engineINT</name>
|
||||
<mode>looped</mode>
|
||||
<path>Croisiere_int_2.wav</path>
|
||||
<condition>
|
||||
<and>
|
||||
<property>/addons/by-id/org.flightgear.addons.Aerotow/addon-devel/sound/enable</property>
|
||||
<property>/sim/current-view/internal</property>
|
||||
</and>
|
||||
</condition>
|
||||
<volume>
|
||||
<offset>-0.80</offset>
|
||||
</volume>
|
||||
<pitch>
|
||||
<property>velocities/true-airspeed-kt</property>
|
||||
<factor>0.012</factor>
|
||||
<offset>0.3</offset>
|
||||
<min>0.3</min>
|
||||
<max>1.0</max>
|
||||
</pitch>
|
||||
<reference-dist>150.0</reference-dist>
|
||||
<max-dist>5000.0</max-dist>
|
||||
</engine>
|
||||
<engine>
|
||||
<name>engineEXT</name>
|
||||
<mode>looped</mode>
|
||||
<path>Croisiere_ext_2.wav</path>
|
||||
<condition>
|
||||
<property>/addons/by-id/org.flightgear.addons.Aerotow/addon-devel/sound/enable</property>
|
||||
<and>
|
||||
<property>/addons/by-id/org.flightgear.addons.Aerotow/addon-devel/sound/enable</property>
|
||||
<not>
|
||||
<property>/sim/current-view/internal</property>
|
||||
</not>
|
||||
</and>
|
||||
</condition>
|
||||
<volume>
|
||||
<offset>-0.80</offset>
|
||||
|
||||
22
README.md
22
README.md
@@ -59,13 +59,15 @@ Default route
|
||||
This add-on add a new item to main menu named `Aerotow Everywhere` with following items:
|
||||
|
||||
1. `Aerotow Route` - display the dialog for change aerotow route.
|
||||
2. `Call for Piper J3 Cub aircraft` - load AI tow sceneraio with Piper J3 Cub.
|
||||
3. `Call for Robin DR400 aircraft` - load AI tow sceneraio with Robin DR400. This aircraft has better performance and can take you higher then Piper Cub.
|
||||
4. `Call for Cessna 182 aircraft` - load AI tow sceneraio with Cessna 182. This aircraft has little bit better performance than Robin.
|
||||
5. `Disable tow aircraft` - unload AI tow sceneraio.
|
||||
6. `Add thermal` - display the dialog for configuring and adding thermal.
|
||||
7. `Help` - display help dialog.
|
||||
8. `About` - display about dialog with add-on information.
|
||||
2. `Towrope Configuration` - display the dialog for change towrope parameters.
|
||||
3. `Call for Piper J3 Cub aircraft` - load AI tow sceneraio with Piper J3 Cub.
|
||||
4. `Call for Robin DR400 aircraft` - load AI tow sceneraio with Robin DR400. This aircraft has better performance and can take you higher then Piper Cub.
|
||||
5. `Call for Cessna 182 aircraft` - load AI tow sceneraio with Cessna 182. This aircraft has little bit better performance than Robin.
|
||||
6. `Call for Douglas C-47 aircraft` - load AI tow sceneraio with Douglas C-47.
|
||||
7. `Disable tow aircraft` - unload AI tow sceneraio.
|
||||
8. `Add thermal` - display the dialog for configuring and adding thermal.
|
||||
9. `Help` - display help dialog.
|
||||
10. `About` - display about dialog with add-on information.
|
||||
|
||||
## Aerotow Route
|
||||
|
||||
@@ -75,6 +77,10 @@ You can change the AI aircraft's default route, for this go to menu `Aerotow Eve
|
||||
|
||||
On the top of the "Aerotow Route" dialog you have selector to change aircraft type. It's only for calculate performance and display how the altitude will change.
|
||||
|
||||
### Max alt (AGL)
|
||||
|
||||
Here you can set limit of AGL altitude. 0 means without limits - the plane will always increase its altitude during its flight. AGL is always in terms of the place you are starting from.
|
||||
|
||||
### Route
|
||||
|
||||
Next you have initial heading, distance and altitude change. "Initial heading" depend of the runway where you are located. The aircraft will always take-off along the runway, a distance of 100 m, where it will gain 20 ft in altitude above the terrain. These parameters you cannot change unless you change the airport/runway.
|
||||
@@ -83,7 +89,7 @@ Next you can see a table with fields where you can change values. Each row repre
|
||||
|
||||
1. `Heading change (deg)` - information on how the heading of the aircraft should change in relation to the previous one. A value of `0` means no change, so continue with the same heading. And e.g. `-90` means a left turn of 90 degrees, `60` means a right turn of 60 degrees, etc.
|
||||
2. `Distance (m)` - distance in meters from the previous waypoint to the present one.
|
||||
3. `Alt change (AGL ft)` - information on how much the altitude on this leg of the route will increase (in feet above ground.) This information depend of selected airplane.
|
||||
3. `Alt change (AGL ft)` - information on how much the altitude on this leg of the route will increase (in feet above ground.) This information depend of selected airplane. AGL is always in terms of the place you are starting from (not the waypoint place).
|
||||
|
||||
If you enter a value less than or equal to `0` for `Distance (m)` field this means that here the route is end and the next rows will not be included to the flight plan.
|
||||
|
||||
|
||||
@@ -44,6 +44,10 @@
|
||||
<distance-m type="double">0</distance-m>
|
||||
<alt-change-agl-ft type="double">0</alt-change-agl-ft>
|
||||
</init-wpt>
|
||||
<wpts>
|
||||
<description type="string">Default route around the start location</description>
|
||||
<max-alt-agl type="double"></max-alt-agl>
|
||||
</wpts>
|
||||
<total>
|
||||
<distance>0</distance>
|
||||
<alt>0</alt>
|
||||
|
||||
@@ -42,6 +42,7 @@ var main = func(addon) {
|
||||
#
|
||||
var loadExtraNasalFiles = func (addon) {
|
||||
var modules = [
|
||||
"nasal/timer",
|
||||
"nasal/aircraft",
|
||||
"nasal/message",
|
||||
"nasal/dialogs/route",
|
||||
|
||||
@@ -36,6 +36,13 @@
|
||||
<dialog-name>route-aerotow</dialog-name>
|
||||
</binding>
|
||||
</item>
|
||||
<item>
|
||||
<label>Towrope Configuration</label>
|
||||
<binding>
|
||||
<command>dialog-show</command>
|
||||
<dialog-name>towrope-config</dialog-name>
|
||||
</binding>
|
||||
</item>
|
||||
<item>
|
||||
<label>Call for Piper J3 Cub aircraft</label>
|
||||
<binding>
|
||||
@@ -79,11 +86,9 @@
|
||||
<command>nasal</command>
|
||||
<script><![CDATA[
|
||||
# Run stopAerotow() with a delay to ensure that the engine sound turns off
|
||||
var timer = maketimer(1, func () {
|
||||
aerotow.Timer.new().singleShot(1, aerotow.g_Aerotow, func () {
|
||||
aerotow.g_Aerotow.stopAerotow();
|
||||
});
|
||||
timer.singleShot = 1;
|
||||
timer.start();
|
||||
]]></script>
|
||||
</binding>
|
||||
</item>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<addon>
|
||||
<identifier type="string">org.flightgear.addons.Aerotow</identifier>
|
||||
<name type="string">Aerotow Everywhere</name>
|
||||
<version type="string">1.4.1</version>
|
||||
<version type="string">1.7.0</version>
|
||||
|
||||
<authors>
|
||||
<author>
|
||||
|
||||
10
aerotow.nas
10
aerotow.nas
@@ -9,6 +9,16 @@
|
||||
# under the GNU Public License v3 (GPLv3)
|
||||
#
|
||||
|
||||
#
|
||||
# Global aliases for boolean types to distinguish the use of "int" from "bool".
|
||||
# NOTE: unfortunately, it doesn't work as an assignment of a default value for a function parameter!
|
||||
#
|
||||
var true = 1;
|
||||
var false = 0;
|
||||
|
||||
#
|
||||
# Global object of Aerotow
|
||||
#
|
||||
var g_Aerotow = nil;
|
||||
|
||||
#
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
<hrule/>
|
||||
|
||||
<text>
|
||||
<label>Aerotow Everywhere version 1.4.1 - 20th August 2022</label>
|
||||
<label>Aerotow Everywhere version 1.7.0 - 26th August 2022</label>
|
||||
</text>
|
||||
|
||||
<text>
|
||||
|
||||
@@ -75,14 +75,14 @@
|
||||
<row>0</row>
|
||||
<col>0</col>
|
||||
<halign>right</halign>
|
||||
<label>Aerotow</label>
|
||||
<label>Aerotow:</label>
|
||||
</text>
|
||||
|
||||
<combo>
|
||||
<row>0</row>
|
||||
<col>1</col>
|
||||
<halign>left</halign>
|
||||
<pref-width>150</pref-width>
|
||||
<pref-width>120</pref-width>
|
||||
<live>true</live>
|
||||
<property>/addons/by-id/org.flightgear.addons.Aerotow/addon-devel/route/ai-model</property>
|
||||
<value>Piper J3 Cub</value>
|
||||
@@ -93,6 +93,24 @@
|
||||
<command>dialog-apply</command>
|
||||
</binding>
|
||||
</combo>
|
||||
|
||||
<text>
|
||||
<row>0</row>
|
||||
<col>2</col>
|
||||
<halign>right</halign>
|
||||
<label>Max alt (AGL):</label>
|
||||
</text>
|
||||
|
||||
<input>
|
||||
<row>0</row>
|
||||
<col>3</col>
|
||||
<halign>left</halign>
|
||||
<property>/addons/by-id/org.flightgear.addons.Aerotow/addon-devel/route/wpts/max-alt-agl</property>
|
||||
<live>true</live>
|
||||
<binding>
|
||||
<command>dialog-apply</command>
|
||||
</binding>
|
||||
</input>
|
||||
</group>
|
||||
|
||||
<hrule/>
|
||||
@@ -501,7 +519,7 @@
|
||||
|
||||
<input>
|
||||
<halign>fill</halign>
|
||||
<halign>left</halign>
|
||||
<!-- <halign>left</halign> -->
|
||||
<property>/addons/by-id/org.flightgear.addons.Aerotow/addon-devel/route/wpts/description</property>
|
||||
<live>true</live>
|
||||
<binding>
|
||||
|
||||
342
gui/dialogs/towrope-configuration.xml
Normal file
342
gui/dialogs/towrope-configuration.xml
Normal file
@@ -0,0 +1,342 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<PropertyList>
|
||||
<name>towrope-config</name>
|
||||
<layout>vbox</layout>
|
||||
<default-padding>5</default-padding>
|
||||
<modal>false</modal>
|
||||
<width>680</width>
|
||||
|
||||
<!-- title bar -->
|
||||
<group>
|
||||
<layout>hbox</layout>
|
||||
<empty>
|
||||
<stretch>true</stretch>
|
||||
</empty>
|
||||
<text>
|
||||
<label>Towrope Configuration</label>
|
||||
</text>
|
||||
<empty>
|
||||
<stretch>true</stretch>
|
||||
</empty>
|
||||
<button>
|
||||
<legend/>
|
||||
<key>Esc</key>
|
||||
<pref-width>16</pref-width>
|
||||
<pref-height>16</pref-height>
|
||||
<border>2</border>
|
||||
<binding>
|
||||
<command>dialog-close</command>
|
||||
</binding>
|
||||
</button>
|
||||
</group>
|
||||
|
||||
<hrule/>
|
||||
|
||||
<!-- aerotow parameters -->
|
||||
<group>
|
||||
<layout>hbox</layout>
|
||||
|
||||
<group>
|
||||
<layout>table</layout>
|
||||
|
||||
<!-- tow length -->
|
||||
<text>
|
||||
<row>0</row>
|
||||
<col>0</col>
|
||||
<halign>right</halign>
|
||||
<label>Towrope Length</label>
|
||||
</text>
|
||||
<text>
|
||||
<row>0</row>
|
||||
<col>1</col>
|
||||
<halign>right</halign>
|
||||
<label></label>
|
||||
<live>true</live>
|
||||
<format>%.0f m </format>
|
||||
<property>/sim/hitches/aerotow/tow/length</property>
|
||||
<color>
|
||||
<red>0.2</red>
|
||||
<green>0.9</green>
|
||||
<blue>0.2</blue>
|
||||
</color>
|
||||
</text>
|
||||
|
||||
<!-- break force -->
|
||||
<text>
|
||||
<row>1</row>
|
||||
<col>0</col>
|
||||
<halign>right</halign>
|
||||
<label>Weak Link Break Force</label>
|
||||
</text>
|
||||
<text>
|
||||
<row>1</row>
|
||||
<col>1</col>
|
||||
<halign>right</halign>
|
||||
<label></label>
|
||||
<live>true</live>
|
||||
<format>%.0f N </format>
|
||||
<property>/sim/hitches/aerotow/tow/brake-force</property>
|
||||
<color>
|
||||
<red>0.2</red>
|
||||
<green>0.9</green>
|
||||
<blue>0.2</blue>
|
||||
</color>
|
||||
</text>
|
||||
|
||||
<!-- tow characteristic -->
|
||||
<text>
|
||||
<row>2</row>
|
||||
<col>0</col>
|
||||
<halign>right</halign>
|
||||
<label>Towrope Elastic Constant</label>
|
||||
</text>
|
||||
<text>
|
||||
<row>2</row>
|
||||
<col>1</col>
|
||||
<halign>right</halign>
|
||||
<label></label>
|
||||
<live>true</live>
|
||||
<format>%.0f N</format>
|
||||
<property>/sim/hitches/aerotow/tow/elastic-constant</property>
|
||||
<color>
|
||||
<red>0.2</red>
|
||||
<green>0.9</green>
|
||||
<blue>0.2</blue>
|
||||
</color>
|
||||
</text>
|
||||
|
||||
<!-- tow thickness -->
|
||||
<text>
|
||||
<row>3</row>
|
||||
<col>0</col>
|
||||
<halign>right</halign>
|
||||
<label>Towrope Diameter</label>
|
||||
</text>
|
||||
<text>
|
||||
<row>3</row>
|
||||
<col>1</col>
|
||||
<halign>right</halign>
|
||||
<label></label>
|
||||
<live>true</live>
|
||||
<format>%.0f mm</format>
|
||||
<property>/sim/hitches/aerotow/rope/rope-diameter-mm</property>
|
||||
<color>
|
||||
<red>0.2</red>
|
||||
<green>0.9</green>
|
||||
<blue>0.2</blue>
|
||||
</color>
|
||||
</text>
|
||||
|
||||
<!-- tow weight -->
|
||||
<text>
|
||||
<row>4</row>
|
||||
<col>0</col>
|
||||
<halign>right</halign>
|
||||
<label>Towrope Weight per Meter</label>
|
||||
</text>
|
||||
<text>
|
||||
<row>4</row>
|
||||
<col>1</col>
|
||||
<halign>right</halign>
|
||||
<label></label>
|
||||
<live>true</live>
|
||||
<format>%.3f kg/m</format>
|
||||
<property>/sim/hitches/aerotow/tow/weight-per-m-kg-m</property>
|
||||
<color>
|
||||
<red>0.2</red>
|
||||
<green>0.9</green>
|
||||
<blue>0.2</blue>
|
||||
</color>
|
||||
</text>
|
||||
</group>
|
||||
<empty>
|
||||
<stretch>true</stretch>
|
||||
</empty>
|
||||
|
||||
<vrule/>
|
||||
|
||||
<group>
|
||||
<layout>table</layout>
|
||||
|
||||
<!-- tow length -->
|
||||
<text>
|
||||
<row>0</row>
|
||||
<col>1</col>
|
||||
<halign>right</halign>
|
||||
<label>20 m</label>
|
||||
</text>
|
||||
<slider>
|
||||
<row>0</row>
|
||||
<col>2</col>
|
||||
<live>true</live>
|
||||
<halign>fill</halign>
|
||||
<pref-width>300</pref-width>
|
||||
<name>tow_length</name>
|
||||
<property>/sim/hitches/aerotow/tow/length</property>
|
||||
<min>20</min>
|
||||
<max>200</max>
|
||||
<step>5</step>
|
||||
<binding>
|
||||
<command>dialog-apply</command>
|
||||
</binding>
|
||||
</slider>
|
||||
<text>
|
||||
<row>0</row>
|
||||
<col>3</col>
|
||||
<halign>left</halign>
|
||||
<label>200 m</label>
|
||||
</text>
|
||||
|
||||
<!-- break force -->
|
||||
<text>
|
||||
<row>1</row>
|
||||
<col>1</col>
|
||||
<halign>right</halign>
|
||||
<label>100 N</label>
|
||||
</text>
|
||||
<slider>
|
||||
<row>1</row>
|
||||
<col>2</col>
|
||||
<live>true</live>
|
||||
<halign>fill</halign>
|
||||
<pref-width>300</pref-width>
|
||||
<name>break_force</name>
|
||||
<property>/sim/hitches/aerotow/tow/brake-force</property>
|
||||
<min>100</min>
|
||||
<max>100000</max>
|
||||
<step>100</step>
|
||||
<binding>
|
||||
<command>dialog-apply</command>
|
||||
</binding>
|
||||
</slider>
|
||||
<text>
|
||||
<row>1</row>
|
||||
<col>3</col>
|
||||
<halign>left</halign>
|
||||
<label>100,000 N</label>
|
||||
</text>
|
||||
|
||||
<!-- tow characteristic -->
|
||||
<text>
|
||||
<row>2</row>
|
||||
<col>1</col>
|
||||
<halign>right</halign>
|
||||
<label>0 N</label>
|
||||
</text>
|
||||
<slider>
|
||||
<row>2</row>
|
||||
<col>2</col>
|
||||
<live>true</live>
|
||||
<halign>fill</halign>
|
||||
<pref-width>300</pref-width>
|
||||
<name>elastic_constant</name>
|
||||
<property>/sim/hitches/aerotow/tow/elastic-constant</property>
|
||||
<min>0</min>
|
||||
<max>1500000</max>
|
||||
<step>200</step>
|
||||
<binding>
|
||||
<command>dialog-apply</command>
|
||||
</binding>
|
||||
</slider>
|
||||
<text>
|
||||
<row>2</row>
|
||||
<col>3</col>
|
||||
<halign>left</halign>
|
||||
<label>1,500,000 N</label>
|
||||
</text>
|
||||
|
||||
<!-- tow thickness -->
|
||||
<text>
|
||||
<row>3</row>
|
||||
<col>1</col>
|
||||
<halign>right</halign>
|
||||
<label>0 mm</label>
|
||||
</text>
|
||||
<slider>
|
||||
<row>3</row>
|
||||
<col>2</col>
|
||||
<live>true</live>
|
||||
<halign>fill</halign>
|
||||
<pref-width>300</pref-width>
|
||||
<name>rope_diameter</name>
|
||||
<property>/sim/hitches/aerotow/rope/rope-diameter-mm</property>
|
||||
<min>0</min>
|
||||
<max>50</max>
|
||||
<step>1</step>
|
||||
<binding>
|
||||
<command>dialog-apply</command>
|
||||
</binding>
|
||||
</slider>
|
||||
<text>
|
||||
<row>3</row>
|
||||
<col>3</col>
|
||||
<halign>left</halign>
|
||||
<label>50 mm</label>
|
||||
</text>
|
||||
|
||||
<!-- tow weight -->
|
||||
<text>
|
||||
<row>4</row>
|
||||
<col>1</col>
|
||||
<halign>right</halign>
|
||||
<label>0 kg/m</label>
|
||||
</text>
|
||||
<slider>
|
||||
<row>4</row>
|
||||
<col>2</col>
|
||||
<live>true</live>
|
||||
<halign>fill</halign>
|
||||
<pref-width>300</pref-width>
|
||||
<name>weight_per_m</name>
|
||||
<property>/sim/hitches/aerotow/tow/weight-per-m-kg-m</property>
|
||||
<min>0</min>
|
||||
<max>1</max>
|
||||
<step>0.001</step>
|
||||
<binding>
|
||||
<command>dialog-apply</command>
|
||||
</binding>
|
||||
</slider>
|
||||
<text>
|
||||
<row>4</row>
|
||||
<col>3</col>
|
||||
<halign>left</halign>
|
||||
<label>1 kg/m</label>
|
||||
</text>
|
||||
</group>
|
||||
</group>
|
||||
|
||||
<hrule/>
|
||||
|
||||
<!-- bottom line -->
|
||||
<group>
|
||||
<layout>hbox</layout>
|
||||
<empty>
|
||||
<stretch>true</stretch>
|
||||
</empty>
|
||||
<button>
|
||||
<legend>Close</legend>
|
||||
<equal>true</equal>
|
||||
<binding>
|
||||
<command>dialog-close</command>
|
||||
</binding>
|
||||
</button>
|
||||
<button>
|
||||
<legend>Default</legend>
|
||||
<equal>true</equal>
|
||||
<binding>
|
||||
<command>nasal</command>
|
||||
<script><![CDATA[
|
||||
setprop("/sim/hitches/aerotow/tow/length", 60.0); # hitch.nas 60.0
|
||||
setprop("/sim/hitches/aerotow/tow/brake-force", 100000.0); # hitch.nas 12345.0
|
||||
setprop("/sim/hitches/aerotow/tow/elastic-constant", 10000.0); # hitch.nas 9111.0
|
||||
setprop("/sim/hitches/aerotow/rope/rope-diameter-mm", 20); # hitch.nas 20
|
||||
setprop("/sim/hitches/aerotow/tow/weight-per-m-kg-m", 0.35); # hitch.nas 0.35
|
||||
]]></script>
|
||||
</binding>
|
||||
</button>
|
||||
<empty>
|
||||
<stretch>true</stretch>
|
||||
</empty>
|
||||
</group>
|
||||
</PropertyList>
|
||||
@@ -10,7 +10,7 @@
|
||||
#
|
||||
|
||||
#
|
||||
# Aerotow object
|
||||
# Class Aerotow for enable and disable scenario with aerotow aircraft.
|
||||
#
|
||||
var Aerotow = {
|
||||
#
|
||||
@@ -51,20 +51,16 @@ var Aerotow = {
|
||||
#
|
||||
# Function for restart AI scenario with delay when the sound has to stop.
|
||||
#
|
||||
# Return 1 on successful, otherwise 0.
|
||||
#
|
||||
restartAerotow: func () {
|
||||
me.message.success("Aerotow on the way");
|
||||
|
||||
# Stop playing engine sound
|
||||
setprop(me.addonNodePath ~ "/addon-devel/sound/enable", 0);
|
||||
setprop(me.addonNodePath ~ "/addon-devel/sound/enable", false);
|
||||
|
||||
# Wait a second for the engine sound to turn off
|
||||
var timer = maketimer(1, func () {
|
||||
Timer.new().singleShot(1, me, func () {
|
||||
me.unloadScenario();
|
||||
});
|
||||
timer.singleShot = 1;
|
||||
timer.start();
|
||||
},
|
||||
|
||||
#
|
||||
@@ -76,25 +72,23 @@ var Aerotow = {
|
||||
}
|
||||
|
||||
# Start aerotow with delay to avoid duplicate engine sound playing
|
||||
var timer = maketimer(1, func () {
|
||||
Timer.new().singleShot(1, me, func () {
|
||||
me.startAerotow();
|
||||
});
|
||||
timer.singleShot = 1;
|
||||
timer.start();
|
||||
},
|
||||
|
||||
#
|
||||
# Main function to prepare AI scenario and run it.
|
||||
#
|
||||
# Return 1 on successful, otherwise 0.
|
||||
# Return true on successful, otherwise false.
|
||||
#
|
||||
startAerotow: func () {
|
||||
if (!me.scenario.unload()) {
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!me.scenario.generateXml()) {
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
return me.scenario.load();
|
||||
@@ -103,10 +97,10 @@ var Aerotow = {
|
||||
#
|
||||
# Function for unload our AI scenario.
|
||||
#
|
||||
# Return 1 on successful, otherwise 0.
|
||||
# Return true on successful, otherwise false.
|
||||
#
|
||||
stopAerotow: func () {
|
||||
var withMessages = 1;
|
||||
var withMessages = true;
|
||||
return me.scenario.unload(withMessages);
|
||||
},
|
||||
};
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#
|
||||
|
||||
#
|
||||
# Parent object of Aircraft
|
||||
# Parent class of Aircraft
|
||||
#
|
||||
var Aircraft = {
|
||||
#
|
||||
@@ -50,7 +50,7 @@ var Aircraft = {
|
||||
#
|
||||
# name - Name of aircraft to check.
|
||||
#
|
||||
# Return 1 when match, otherwise 0.
|
||||
# Return true when match, otherwise false.
|
||||
#
|
||||
isModelName: func (name) {
|
||||
return name == me.name or name == me.nameMenuCall;
|
||||
@@ -69,8 +69,8 @@ var Aircraft = {
|
||||
# Return selected Aircraft object
|
||||
#
|
||||
# addon - Addon object
|
||||
# isRouteMode - Use 1 to get the plane for the "Aerotow Route" dialog,
|
||||
# use 0 (default) for call the airplane for towing.
|
||||
# isRouteMode - Use true to get the plane for the "Aerotow Route" dialog,
|
||||
# use false (default) for call the airplane for towing.
|
||||
#
|
||||
getSelected: func (addon, isRouteMode = 0) {
|
||||
var name = Aircraft.getSelectedAircraftName(addon, isRouteMode);
|
||||
@@ -89,10 +89,10 @@ var Aircraft = {
|
||||
#
|
||||
#
|
||||
# addon - Addon object
|
||||
# isRouteMode - Use 1 to get the plane for the "Aerotow Route" dialog,
|
||||
# use 0 (default) for call the airplane for towing.
|
||||
# isRouteMode - Use true to get the plane for the "Aerotow Route" dialog,
|
||||
# use false (default) for call the airplane for towing.
|
||||
#
|
||||
getSelectedAircraftName: func (addon, isRouteMode = 0) {
|
||||
getSelectedAircraftName: func (addon, isRouteMode) {
|
||||
if (isRouteMode) {
|
||||
return getprop(addon.node.getPath() ~ "/addon-devel/route/ai-model") or g_Aircrafts[0].name;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#
|
||||
|
||||
#
|
||||
# Object for hande Route Dialog
|
||||
# Class for hande Route Dialog
|
||||
#
|
||||
var RouteDialog = {
|
||||
#
|
||||
@@ -39,6 +39,11 @@ var RouteDialog = {
|
||||
obj.calculateAltChangeAndTotals();
|
||||
}));
|
||||
|
||||
# Set listener for Max altitude AGL value in route dialog for recalculate altitude change
|
||||
append(obj.listeners, setlistener(obj.addonNodePath ~ "/addon-devel/route/wpts/max-alt-agl", func () {
|
||||
obj.calculateAltChangeAndTotals();
|
||||
}));
|
||||
|
||||
# Set listeners for distance fields for calculate altitude change
|
||||
for (var i = 0; i < obj.maxRouteWaypoints; i += 1) {
|
||||
append(obj.listeners, setlistener(obj.addonNodePath ~ "/addon-devel/route/wpts/wpt[" ~ i ~ "]/distance-m", func () {
|
||||
@@ -64,18 +69,27 @@ var RouteDialog = {
|
||||
calculateAltChangeAndTotals: func () {
|
||||
var totalDistance = 0.0;
|
||||
var totalAlt = 0.0;
|
||||
var isEnd = 0;
|
||||
var isEnd = false;
|
||||
var isAltLimit = false;
|
||||
|
||||
var isRouteMode = 1;
|
||||
var isRouteMode = true;
|
||||
var aircraft = Aircraft.getSelected(me.addon, isRouteMode);
|
||||
|
||||
# 0 means without altitude limits
|
||||
var maxAltAgl = getprop(me.addonNodePath ~ "/addon-devel/route/wpts/max-alt-agl") or 0;
|
||||
|
||||
for (var i = 0; i < me.maxRouteWaypoints; i += 1) {
|
||||
var distance = getprop(me.addonNodePath ~ "/addon-devel/route/wpts/wpt[" ~ i ~ "]/distance-m");
|
||||
if (distance == nil) {
|
||||
break;
|
||||
var distance = getprop(me.addonNodePath ~ "/addon-devel/route/wpts/wpt[" ~ i ~ "]/distance-m") or 0;
|
||||
|
||||
# If we have reached the altitude limit, the altitude no longer changes (0)
|
||||
var altChange = isAltLimit ? 0 : aircraft.getAltChange(distance);
|
||||
if (maxAltAgl > 0 and altChange > 0 and totalAlt + altChange > maxAltAgl) {
|
||||
# We will exceed the altitude limit, so set the altChange to the altitude limit
|
||||
# and set isAltLimit flag that the limit is reached.
|
||||
altChange = maxAltAgl - totalAlt;
|
||||
isAltLimit = true;
|
||||
}
|
||||
|
||||
var altChange = aircraft.getAltChange(distance);
|
||||
setprop(me.addonNodePath ~ "/addon-devel/route/wpts/wpt[" ~ i ~ "]/alt-change-agl-ft", altChange);
|
||||
|
||||
if (!isEnd) {
|
||||
@@ -84,7 +98,7 @@ var RouteDialog = {
|
||||
totalAlt += altChange;
|
||||
}
|
||||
else {
|
||||
isEnd = 1;
|
||||
isEnd = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,9 @@
|
||||
# under the GNU Public License v3 (GPLv3)
|
||||
#
|
||||
|
||||
#
|
||||
# Class Thermal for handle add new thermal.
|
||||
#
|
||||
var Thermal = {
|
||||
#
|
||||
# Constructor
|
||||
@@ -59,7 +62,7 @@ var Thermal = {
|
||||
#
|
||||
# Add thermal 300 m before glider position.
|
||||
#
|
||||
# Return 1 on successful, otherwise 0.
|
||||
# Return true on successful, otherwise false.
|
||||
#
|
||||
add: func () {
|
||||
var heading = getprop("/orientation/heading-deg") or 0;
|
||||
@@ -84,10 +87,10 @@ var Thermal = {
|
||||
|
||||
if (fgcommand("add-aiobject", args)) {
|
||||
me.message.success("The thermal has been added");
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
me.message.error("Adding thermal failed");
|
||||
return 0;
|
||||
return false;
|
||||
},
|
||||
};
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#
|
||||
|
||||
#
|
||||
# Flight Plan object
|
||||
# Class FlightPlan for crate and save as XML file the flight plan for AI scenario.
|
||||
#
|
||||
var FlightPlan = {
|
||||
#
|
||||
@@ -47,7 +47,7 @@ var FlightPlan = {
|
||||
#
|
||||
# Get inital location of glider.
|
||||
#
|
||||
# Return object with "lat", "lon" and 'heading".
|
||||
# Return object with "lat", "lon" and "heading".
|
||||
#
|
||||
getLocation: func () {
|
||||
var icao = getprop("/sim/airport/closest-airport-id");
|
||||
@@ -93,7 +93,7 @@ var FlightPlan = {
|
||||
"lat" : rwyResult.runway.lat,
|
||||
"lon" : rwyResult.runway.lon,
|
||||
"heading" : rwyResult.runway.heading,
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
#
|
||||
@@ -124,19 +124,22 @@ var FlightPlan = {
|
||||
#
|
||||
# Initialize flight plan and set it to property tree
|
||||
#
|
||||
# Return 1 on successful, otherwise 0.
|
||||
# Return true on successful, otherwise false.
|
||||
#
|
||||
initial: func () {
|
||||
var location = me.getLocation();
|
||||
if (location == nil) {
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
var aircraft = Aircraft.getSelected(me.addon);
|
||||
|
||||
var isGliderPos = 0;
|
||||
var isGliderPos = false;
|
||||
me.initAircraftVariable(location, isGliderPos);
|
||||
|
||||
# Max altitude without limits
|
||||
setprop(me.addonNodePath ~ "/addon-devel/route/wpts/max-alt-agl", 0);
|
||||
|
||||
# inittial readonly waypoint
|
||||
setprop(me.addonNodePath ~ "/addon-devel/route/init-wpt/heading-change", me.heading);
|
||||
setprop(me.addonNodePath ~ "/addon-devel/route/init-wpt/distance-m", 100);
|
||||
@@ -189,28 +192,28 @@ var FlightPlan = {
|
||||
|
||||
setprop(me.addonNodePath ~ "/addon-devel/route/wpts/description", "Default route around the start location");
|
||||
|
||||
return 1;
|
||||
return true;
|
||||
},
|
||||
|
||||
#
|
||||
# Generate the XML file with the flight plane for our plane for AI scenario.
|
||||
# The file will be stored to $Fobj.HOME/Export/aerotown-addon-flightplan.xml.
|
||||
# The file will be stored to $FG_HOME/Export/Addons/org.flightgear.addons.Aerotow/AI/FlightPlans/aerotown-addon-flightplan.xml.
|
||||
#
|
||||
# Return 1 on successful, otherwise 0.
|
||||
# Return true on successful, otherwise false.
|
||||
#
|
||||
generateXml: func () {
|
||||
me.wptCount = 0;
|
||||
|
||||
var location = me.getLocation();
|
||||
if (location == nil) {
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
me.flightPlanWriter.open();
|
||||
|
||||
var aircraft = Aircraft.getSelected(me.addon);
|
||||
|
||||
var isGliderPos = 1;
|
||||
var isGliderPos = true;
|
||||
me.initAircraftVariable(location, isGliderPos);
|
||||
|
||||
# Start at 2 o'clock from the glider...
|
||||
@@ -218,13 +221,13 @@ var FlightPlan = {
|
||||
me.addWptGround({"hdgChange": 60, "dist": 25}, {"altChange": 0, "ktas": 5});
|
||||
|
||||
# Reset coord and heading
|
||||
isGliderPos = 0;
|
||||
isGliderPos = false;
|
||||
me.initAircraftVariable(location, isGliderPos);
|
||||
|
||||
var gliderOffsetM = me.getGliderOffsetFromRunwayThreshold(location);
|
||||
|
||||
# ... and line up with the runway
|
||||
me.addWptGround({"hdgChange": 0, "dist": 30 + gliderOffsetM}, {"altChange": 0, "ktas": 2.5});
|
||||
me.addWptGround({"hdgChange": 0, "dist": me.getInitialDistance() + gliderOffsetM}, {"altChange": 0, "ktas": 2.5});
|
||||
|
||||
# Rolling
|
||||
me.addWptGround({"hdgChange": 0, "dist": 10}, {"altChange": 0, "ktas": 5});
|
||||
@@ -245,39 +248,67 @@ var FlightPlan = {
|
||||
me.addWptAir({"hdgChange": 0, "dist": 100 * aircraft.rolling}, {"elevationPlus": 3, "ktas": aircraft.speed * 1.05});
|
||||
me.addWptAir({"hdgChange": 0, "dist": 100}, {"altChange": aircraft.vs / 10, "ktas": aircraft.speed * 1.025});
|
||||
|
||||
|
||||
# 0 means without altitude limits
|
||||
var maxAltAgl = getprop(me.addonNodePath ~ "/addon-devel/route/wpts/max-alt-agl") or 0;
|
||||
var totalAlt = 0.0;
|
||||
var isAltLimit = false;
|
||||
|
||||
# Add waypoints according to user settings
|
||||
var speedInc = 1.0;
|
||||
foreach (var wptNode; props.globals.getNode(me.addonNodePath ~ "/addon-devel/route/wpts").getChildren("wpt")) {
|
||||
var dist = wptNode.getChild("distance-m").getValue();
|
||||
if (dist <= 0.0) {
|
||||
var distance = wptNode.getChild("distance-m").getValue();
|
||||
if (distance <= 0.0) {
|
||||
break;
|
||||
}
|
||||
|
||||
var hdgChange = wptNode.getChild("heading-change").getValue();
|
||||
var altChange = aircraft.getAltChange(dist);
|
||||
|
||||
speedInc += ((dist / Aircraft.DISTANCE_DETERMINANT) * 0.025);
|
||||
# If we have reached the altitude limit, the altitude no longer changes (0)
|
||||
var altChange = isAltLimit ? 0 : aircraft.getAltChange(distance);
|
||||
if (maxAltAgl > 0 and altChange > 0 and totalAlt + altChange > maxAltAgl) {
|
||||
# We will exceed the altitude limit, so set the altChange to the altitude limit
|
||||
# and set isAltLimit flag that the limit is reached.
|
||||
altChange = maxAltAgl - totalAlt;
|
||||
isAltLimit = true;
|
||||
}
|
||||
|
||||
speedInc += ((distance / Aircraft.DISTANCE_DETERMINANT) * 0.025);
|
||||
var ktas = aircraft.speed * speedInc;
|
||||
if (ktas > aircraft.speedLimit) {
|
||||
ktas = aircraft.speedLimit;
|
||||
}
|
||||
|
||||
me.addWptAir({"hdgChange": hdgChange, "dist": dist}, {"altChange": altChange, "ktas": ktas});
|
||||
totalAlt += altChange;
|
||||
|
||||
me.addWptAir({"hdgChange": hdgChange, "dist": distance}, {"altChange": altChange, "ktas": ktas});
|
||||
}
|
||||
|
||||
me.addWptEnd();
|
||||
|
||||
me.flightPlanWriter.close();
|
||||
|
||||
return 1;
|
||||
return true;
|
||||
},
|
||||
|
||||
#
|
||||
# Get initial distance AI plane from the glider that the tow is nearly tautened.
|
||||
#
|
||||
# Return distance in meters.
|
||||
#
|
||||
getInitialDistance: func () {
|
||||
var ropeLengthM = getprop("/sim/hitches/aerotow/tow/length") or 60;
|
||||
var tautenRelative = 0.68;
|
||||
return ropeLengthM * tautenRelative;
|
||||
},
|
||||
|
||||
#
|
||||
# Initialize AI aircraft variable
|
||||
#
|
||||
# location - Object of location from which the glider start.
|
||||
# isGliderPos - Pass 1 for set AI aircraft's coordinates as glider position, 0 set coordinates as runway threshold.
|
||||
# isGliderPos - Pass true for set AI aircraft's coordinates as glider position, false set coordinates as runway threshold.
|
||||
#
|
||||
initAircraftVariable: func (location, isGliderPos = 1) {
|
||||
initAircraftVariable: func (location, isGliderPos) {
|
||||
var gliderCoord = geo.aircraft_position();
|
||||
|
||||
# Set coordinates as glider position or runway threshold
|
||||
@@ -307,7 +338,7 @@ var FlightPlan = {
|
||||
return rwyThreshold.distance_to(gliderCoord);
|
||||
}
|
||||
|
||||
# We are not on runway
|
||||
# We are not on the runway, return 0 distance
|
||||
return 0;
|
||||
},
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#
|
||||
|
||||
#
|
||||
# Object for write flight plan to the XML file
|
||||
# Class FlightPlanWriter for write flight plan to the XML file
|
||||
#
|
||||
var FlightPlanWriter = {
|
||||
#
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#
|
||||
|
||||
#
|
||||
# Object for display messages
|
||||
# Class Message for display messages on the screen with read by speech synthesizer.
|
||||
#
|
||||
var Message = {
|
||||
#
|
||||
|
||||
@@ -10,16 +10,16 @@
|
||||
#
|
||||
|
||||
#
|
||||
# Scenario object
|
||||
# Class Scenario for create AI scenario XML file and attach it to scenario property list for load it.
|
||||
#
|
||||
var Scenario = {
|
||||
#
|
||||
# Constants
|
||||
#
|
||||
SCENARIO_ID: "aerotow_addon",
|
||||
SCENARIO_NAME: "Aerotow Add-on",
|
||||
SCENARIO_DESC: "This scenario starts the towing plane at the airport where the pilot with the glider is located. Use Ctrl-o to hook the plane.",
|
||||
FILENAME_SCENARIO: "aerotown-addon.xml",
|
||||
SCENARIO_ID: "aerotow_addon",
|
||||
SCENARIO_NAME: "Aerotow Add-on",
|
||||
SCENARIO_DESC: "This scenario starts the towing plane at the airport where the pilot with the glider is located. Use Ctrl-o to hook the plane.",
|
||||
FILENAME_SCENARIO: "aerotown-addon.xml",
|
||||
|
||||
#
|
||||
# Constructor
|
||||
@@ -38,7 +38,7 @@ var Scenario = {
|
||||
obj.listeners = [];
|
||||
obj.routeDialog = RouteDialog.new(addon, message);
|
||||
obj.flightPlan = FlightPlan.new(addon, message, obj.routeDialog);
|
||||
obj.isScenarioLoaded = 0;
|
||||
obj.isScenarioLoaded = false;
|
||||
obj.scenarioPath = addon.storagePath ~ "/" ~ Scenario.FILENAME_SCENARIO;
|
||||
|
||||
obj.flightPlan.initial();
|
||||
@@ -64,11 +64,13 @@ var Scenario = {
|
||||
|
||||
#
|
||||
# Generate the XML file with the AI scenario.
|
||||
# The file will be stored to $FG_HOME/Export/aerotown-addon.xml.
|
||||
# The file will be stored to $FG_HOME/Export/Addons/org.flightgear.addons.Aerotow/aerotown-addon.xml.
|
||||
#
|
||||
# Return true on successful, otherwise false
|
||||
#
|
||||
generateXml: func () {
|
||||
if (!me.flightPlan.generateXml()) {
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
var scenarioXml = {
|
||||
@@ -82,7 +84,7 @@ var Scenario = {
|
||||
"class": "aerotow-dragger",
|
||||
"model": Aircraft.getSelected(me.addon).modelPath,
|
||||
"flightplan": FlightPlan.FILENAME_FLIGHTPLAN,
|
||||
"repeat": 1,
|
||||
"repeat": true, # start again indefinitely
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -93,7 +95,7 @@ var Scenario = {
|
||||
|
||||
me.addScenarioToPropertyList();
|
||||
|
||||
return 1;
|
||||
return true;
|
||||
},
|
||||
|
||||
#
|
||||
@@ -114,67 +116,67 @@ var Scenario = {
|
||||
},
|
||||
|
||||
#
|
||||
# Return 1 if scenario is already added to "/sim/ai/scenarios" property list, otherwise return 0.
|
||||
# Return true if scenario is already added to "/sim/ai/scenarios" property list, otherwise return false.
|
||||
#
|
||||
isAlreadyAdded: func () {
|
||||
foreach (var scenario; props.globals.getNode("/sim/ai/scenarios").getChildren("scenario")) {
|
||||
var id = scenario.getChild("id");
|
||||
if (id != nil and id.getValue() == Scenario.SCENARIO_ID) {
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return false;
|
||||
},
|
||||
|
||||
#
|
||||
# Load scenario
|
||||
#
|
||||
# Return 1 on successful, otherwise 0.
|
||||
# Return true on successful, otherwise false.
|
||||
#
|
||||
load: func () {
|
||||
var args = props.Node.new({ "name": Scenario.SCENARIO_ID });
|
||||
if (fgcommand("load-scenario", args)) {
|
||||
me.isScenarioLoaded = 1;
|
||||
me.isScenarioLoaded = true;
|
||||
me.message.success("Let's fly!");
|
||||
|
||||
# Enable engine sound
|
||||
setprop(me.addonNodePath ~ "/addon-devel/sound/enable", 1);
|
||||
return 1;
|
||||
setprop(me.addonNodePath ~ "/addon-devel/sound/enable", true);
|
||||
return true;
|
||||
}
|
||||
|
||||
me.message.error("Tow failed!");
|
||||
return 0;
|
||||
return false;
|
||||
},
|
||||
|
||||
#
|
||||
# Unload scenario
|
||||
#
|
||||
# withMessages - Set 1 to display messages.
|
||||
# withMessages - Set true to display messages.
|
||||
#
|
||||
# Return 1 on successful, otherwise 0.
|
||||
# Return true on successful, otherwise false.
|
||||
#
|
||||
unload: func (withMessages = 0) {
|
||||
if (me.isScenarioLoaded) {
|
||||
var args = props.Node.new({ "name": Scenario.SCENARIO_ID });
|
||||
if (fgcommand("unload-scenario", args)) {
|
||||
me.isScenarioLoaded = 0;
|
||||
me.isScenarioLoaded = false;
|
||||
|
||||
if (withMessages) {
|
||||
me.message.success("Aerotown disabled");
|
||||
}
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (withMessages) {
|
||||
me.message.error("Aerotown disable failed");
|
||||
}
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (withMessages) {
|
||||
me.message.success("Aerotown already disabled");
|
||||
}
|
||||
return 1;
|
||||
return true;
|
||||
},
|
||||
};
|
||||
|
||||
41
nasal/timer.nas
Normal file
41
nasal/timer.nas
Normal file
@@ -0,0 +1,41 @@
|
||||
#
|
||||
# Aerotow Everywhere - Add-on for FlightGear
|
||||
#
|
||||
# Written and developer by Roman Ludwicki (PlayeRom, SP-ROM)
|
||||
#
|
||||
# Copyright (C) 2022 Roman Ludwicki
|
||||
#
|
||||
# Aerotow Everywhere is an Open Source project and it is licensed
|
||||
# under the GNU Public License v3 (GPLv3)
|
||||
#
|
||||
|
||||
#
|
||||
# Class Timer for wrapping maketimer() function.
|
||||
#
|
||||
var Timer = {
|
||||
#
|
||||
# Constructor
|
||||
#
|
||||
new: func () {
|
||||
return { parents: [Timer] };
|
||||
},
|
||||
|
||||
#
|
||||
# Run timer as single shot
|
||||
#
|
||||
# delaySec - Delay in seconds for execute timer's callback.
|
||||
# self - Specifying what any "me" references in the function being called will refer to.
|
||||
# callback - Function to be called after given delay.
|
||||
#
|
||||
# Return timer handler object
|
||||
#
|
||||
singleShot: func (delaySec, self, callback) {
|
||||
var timer = maketimer(delaySec, self, func () {
|
||||
callback();
|
||||
});
|
||||
timer.singleShot = true;
|
||||
timer.start();
|
||||
|
||||
return timer;
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user