Compare commits

...
10 Commits
19 changed files with 526 additions and 81 deletions
+11 -3
View File
@@ -1,15 +1,23 @@
# CHANGELOG # CHANGELOG
## 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 ## v.1.4.1
- Fix carsh by missing parameter - Fix crash by missing parameter
## v.1.4.0 ## 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 possibility to take off in the bush
- Add a separate engine sound for the DR400 - 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 - Add possibility to save/load route waypoints with description
## v.1.3.0 ## v.1.3.0
@@ -2,11 +2,39 @@
<PropertyList> <PropertyList>
<fx> <fx>
<engine> <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> <mode>looped</mode>
<path>Croisiere_ext_2.wav</path> <path>Croisiere_ext_2.wav</path>
<condition> <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> </condition>
<volume> <volume>
<offset>-0.80</offset> <offset>-0.80</offset>
+1
View File
@@ -42,6 +42,7 @@ var main = func(addon) {
# #
var loadExtraNasalFiles = func (addon) { var loadExtraNasalFiles = func (addon) {
var modules = [ var modules = [
"nasal/timer",
"nasal/aircraft", "nasal/aircraft",
"nasal/message", "nasal/message",
"nasal/dialogs/route", "nasal/dialogs/route",
+8 -3
View File
@@ -36,6 +36,13 @@
<dialog-name>route-aerotow</dialog-name> <dialog-name>route-aerotow</dialog-name>
</binding> </binding>
</item> </item>
<item>
<label>Towrope Configuration</label>
<binding>
<command>dialog-show</command>
<dialog-name>towrope-config</dialog-name>
</binding>
</item>
<item> <item>
<label>Call for Piper J3 Cub aircraft</label> <label>Call for Piper J3 Cub aircraft</label>
<binding> <binding>
@@ -79,11 +86,9 @@
<command>nasal</command> <command>nasal</command>
<script><![CDATA[ <script><![CDATA[
# Run stopAerotow() with a delay to ensure that the engine sound turns off # 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(); aerotow.g_Aerotow.stopAerotow();
}); });
timer.singleShot = 1;
timer.start();
]]></script> ]]></script>
</binding> </binding>
</item> </item>
+1 -1
View File
@@ -21,7 +21,7 @@
<addon> <addon>
<identifier type="string">org.flightgear.addons.Aerotow</identifier> <identifier type="string">org.flightgear.addons.Aerotow</identifier>
<name type="string">Aerotow Everywhere</name> <name type="string">Aerotow Everywhere</name>
<version type="string">1.4.1</version> <version type="string">1.6.0</version>
<authors> <authors>
<author> <author>
+10
View File
@@ -9,6 +9,16 @@
# under the GNU Public License v3 (GPLv3) # 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; var g_Aerotow = nil;
# #
+1 -1
View File
@@ -45,7 +45,7 @@
<hrule/> <hrule/>
<text> <text>
<label>Aerotow Everywhere version 1.4.1 - 20th August 2022</label> <label>Aerotow Everywhere version 1.6.0 - 23nd August 2022</label>
</text> </text>
<text> <text>
+342
View 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>
+9 -15
View File
@@ -10,7 +10,7 @@
# #
# #
# Aerotow object # Class Aerotow for enable and disable scenario with aerotow aircraft.
# #
var Aerotow = { var Aerotow = {
# #
@@ -51,20 +51,16 @@ var Aerotow = {
# #
# Function for restart AI scenario with delay when the sound has to stop. # Function for restart AI scenario with delay when the sound has to stop.
# #
# Return 1 on successful, otherwise 0.
#
restartAerotow: func () { restartAerotow: func () {
me.message.success("Aerotow on the way"); me.message.success("Aerotow on the way");
# Stop playing engine sound # 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 # Wait a second for the engine sound to turn off
var timer = maketimer(1, func () { Timer.new().singleShot(1, me, func () {
me.unloadScenario(); me.unloadScenario();
}); });
timer.singleShot = 1;
timer.start();
}, },
# #
@@ -76,25 +72,23 @@ var Aerotow = {
} }
# Start aerotow with delay to avoid duplicate engine sound playing # Start aerotow with delay to avoid duplicate engine sound playing
var timer = maketimer(1, func () { Timer.new().singleShot(1, me, func () {
me.startAerotow(); me.startAerotow();
}); });
timer.singleShot = 1;
timer.start();
}, },
# #
# Main function to prepare AI scenario and run it. # Main function to prepare AI scenario and run it.
# #
# Return 1 on successful, otherwise 0. # Return true on successful, otherwise false.
# #
startAerotow: func () { startAerotow: func () {
if (!me.scenario.unload()) { if (!me.scenario.unload()) {
return 0; return false;
} }
if (!me.scenario.generateXml()) { if (!me.scenario.generateXml()) {
return 0; return false;
} }
return me.scenario.load(); return me.scenario.load();
@@ -103,10 +97,10 @@ var Aerotow = {
# #
# Function for unload our AI scenario. # Function for unload our AI scenario.
# #
# Return 1 on successful, otherwise 0. # Return true on successful, otherwise false.
# #
stopAerotow: func () { stopAerotow: func () {
var withMessages = 1; var withMessages = true;
return me.scenario.unload(withMessages); return me.scenario.unload(withMessages);
}, },
}; };
+7 -7
View File
@@ -10,7 +10,7 @@
# #
# #
# Parent object of Aircraft # Parent class of Aircraft
# #
var Aircraft = { var Aircraft = {
# #
@@ -50,7 +50,7 @@ var Aircraft = {
# #
# name - Name of aircraft to check. # name - Name of aircraft to check.
# #
# Return 1 when match, otherwise 0. # Return true when match, otherwise false.
# #
isModelName: func (name) { isModelName: func (name) {
return name == me.name or name == me.nameMenuCall; return name == me.name or name == me.nameMenuCall;
@@ -69,8 +69,8 @@ var Aircraft = {
# Return selected Aircraft object # Return selected Aircraft object
# #
# addon - Addon object # addon - Addon object
# isRouteMode - Use 1 to get the plane for the "Aerotow Route" dialog, # isRouteMode - Use true to get the plane for the "Aerotow Route" dialog,
# use 0 (default) for call the airplane for towing. # use false (default) for call the airplane for towing.
# #
getSelected: func (addon, isRouteMode = 0) { getSelected: func (addon, isRouteMode = 0) {
var name = Aircraft.getSelectedAircraftName(addon, isRouteMode); var name = Aircraft.getSelectedAircraftName(addon, isRouteMode);
@@ -89,10 +89,10 @@ var Aircraft = {
# #
# #
# addon - Addon object # addon - Addon object
# isRouteMode - Use 1 to get the plane for the "Aerotow Route" dialog, # isRouteMode - Use true to get the plane for the "Aerotow Route" dialog,
# use 0 (default) for call the airplane for towing. # use false (default) for call the airplane for towing.
# #
getSelectedAircraftName: func (addon, isRouteMode = 0) { getSelectedAircraftName: func (addon, isRouteMode) {
if (isRouteMode) { if (isRouteMode) {
return getprop(addon.node.getPath() ~ "/addon-devel/route/ai-model") or g_Aircrafts[0].name; return getprop(addon.node.getPath() ~ "/addon-devel/route/ai-model") or g_Aircrafts[0].name;
} }
+4 -4
View File
@@ -10,7 +10,7 @@
# #
# #
# Object for hande Route Dialog # Class for hande Route Dialog
# #
var RouteDialog = { var RouteDialog = {
# #
@@ -64,9 +64,9 @@ var RouteDialog = {
calculateAltChangeAndTotals: func () { calculateAltChangeAndTotals: func () {
var totalDistance = 0.0; var totalDistance = 0.0;
var totalAlt = 0.0; var totalAlt = 0.0;
var isEnd = 0; var isEnd = false;
var isRouteMode = 1; var isRouteMode = true;
var aircraft = Aircraft.getSelected(me.addon, isRouteMode); var aircraft = Aircraft.getSelected(me.addon, isRouteMode);
for (var i = 0; i < me.maxRouteWaypoints; i += 1) { for (var i = 0; i < me.maxRouteWaypoints; i += 1) {
@@ -84,7 +84,7 @@ var RouteDialog = {
totalAlt += altChange; totalAlt += altChange;
} }
else { else {
isEnd = 1; isEnd = true;
} }
} }
} }
+6 -3
View File
@@ -9,6 +9,9 @@
# under the GNU Public License v3 (GPLv3) # under the GNU Public License v3 (GPLv3)
# #
#
# Class Thermal for handle add new thermal.
#
var Thermal = { var Thermal = {
# #
# Constructor # Constructor
@@ -59,7 +62,7 @@ var Thermal = {
# #
# Add thermal 300 m before glider position. # Add thermal 300 m before glider position.
# #
# Return 1 on successful, otherwise 0. # Return true on successful, otherwise false.
# #
add: func () { add: func () {
var heading = getprop("/orientation/heading-deg") or 0; var heading = getprop("/orientation/heading-deg") or 0;
@@ -84,10 +87,10 @@ var Thermal = {
if (fgcommand("add-aiobject", args)) { if (fgcommand("add-aiobject", args)) {
me.message.success("The thermal has been added"); me.message.success("The thermal has been added");
return 1; return true;
} }
me.message.error("Adding thermal failed"); me.message.error("Adding thermal failed");
return 0; return false;
}, },
}; };
+27 -16
View File
@@ -10,7 +10,7 @@
# #
# #
# Flight Plan object # Class FlightPlan for crate and save as XML file the flight plan for AI scenario.
# #
var FlightPlan = { var FlightPlan = {
# #
@@ -93,7 +93,7 @@ var FlightPlan = {
"lat" : rwyResult.runway.lat, "lat" : rwyResult.runway.lat,
"lon" : rwyResult.runway.lon, "lon" : rwyResult.runway.lon,
"heading" : rwyResult.runway.heading, "heading" : rwyResult.runway.heading,
} };
}, },
# #
@@ -124,17 +124,17 @@ var FlightPlan = {
# #
# Initialize flight plan and set it to property tree # Initialize flight plan and set it to property tree
# #
# Return 1 on successful, otherwise 0. # Return true on successful, otherwise false.
# #
initial: func () { initial: func () {
var location = me.getLocation(); var location = me.getLocation();
if (location == nil) { if (location == nil) {
return 0; return false;
} }
var aircraft = Aircraft.getSelected(me.addon); var aircraft = Aircraft.getSelected(me.addon);
var isGliderPos = 0; var isGliderPos = false;
me.initAircraftVariable(location, isGliderPos); me.initAircraftVariable(location, isGliderPos);
# inittial readonly waypoint # inittial readonly waypoint
@@ -189,28 +189,28 @@ var FlightPlan = {
setprop(me.addonNodePath ~ "/addon-devel/route/wpts/description", "Default route around the start location"); 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. # 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 () { generateXml: func () {
me.wptCount = 0; me.wptCount = 0;
var location = me.getLocation(); var location = me.getLocation();
if (location == nil) { if (location == nil) {
return 0; return false;
} }
me.flightPlanWriter.open(); me.flightPlanWriter.open();
var aircraft = Aircraft.getSelected(me.addon); var aircraft = Aircraft.getSelected(me.addon);
var isGliderPos = 1; var isGliderPos = true;
me.initAircraftVariable(location, isGliderPos); me.initAircraftVariable(location, isGliderPos);
# Start at 2 o'clock from the glider... # Start at 2 o'clock from the glider...
@@ -218,13 +218,13 @@ var FlightPlan = {
me.addWptGround({"hdgChange": 60, "dist": 25}, {"altChange": 0, "ktas": 5}); me.addWptGround({"hdgChange": 60, "dist": 25}, {"altChange": 0, "ktas": 5});
# Reset coord and heading # Reset coord and heading
isGliderPos = 0; isGliderPos = false;
me.initAircraftVariable(location, isGliderPos); me.initAircraftVariable(location, isGliderPos);
var gliderOffsetM = me.getGliderOffsetFromRunwayThreshold(location); var gliderOffsetM = me.getGliderOffsetFromRunwayThreshold(location);
# ... and line up with the runway # ... 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 # Rolling
me.addWptGround({"hdgChange": 0, "dist": 10}, {"altChange": 0, "ktas": 5}); me.addWptGround({"hdgChange": 0, "dist": 10}, {"altChange": 0, "ktas": 5});
@@ -268,16 +268,27 @@ var FlightPlan = {
me.flightPlanWriter.close(); 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 # Initialize AI aircraft variable
# #
# location - Object of location from which the glider start. # 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(); var gliderCoord = geo.aircraft_position();
# Set coordinates as glider position or runway threshold # Set coordinates as glider position or runway threshold
@@ -307,7 +318,7 @@ var FlightPlan = {
return rwyThreshold.distance_to(gliderCoord); return rwyThreshold.distance_to(gliderCoord);
} }
# We are not on runway # We are not on the runway, return 0 distance
return 0; return 0;
}, },
+1 -1
View File
@@ -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 = { var FlightPlanWriter = {
# #
+1 -1
View File
@@ -10,7 +10,7 @@
# #
# #
# Object for display messages # Class Message for display messages on the screen with read by speech synthesizer.
# #
var Message = { var Message = {
# #
+26 -24
View File
@@ -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 = { var Scenario = {
# #
# Constants # Constants
# #
SCENARIO_ID: "aerotow_addon", SCENARIO_ID: "aerotow_addon",
SCENARIO_NAME: "Aerotow Add-on", 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.", 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", FILENAME_SCENARIO: "aerotown-addon.xml",
# #
# Constructor # Constructor
@@ -38,7 +38,7 @@ var Scenario = {
obj.listeners = []; obj.listeners = [];
obj.routeDialog = RouteDialog.new(addon, message); obj.routeDialog = RouteDialog.new(addon, message);
obj.flightPlan = FlightPlan.new(addon, message, obj.routeDialog); obj.flightPlan = FlightPlan.new(addon, message, obj.routeDialog);
obj.isScenarioLoaded = 0; obj.isScenarioLoaded = false;
obj.scenarioPath = addon.storagePath ~ "/" ~ Scenario.FILENAME_SCENARIO; obj.scenarioPath = addon.storagePath ~ "/" ~ Scenario.FILENAME_SCENARIO;
obj.flightPlan.initial(); obj.flightPlan.initial();
@@ -64,11 +64,13 @@ var Scenario = {
# #
# Generate the XML file with the AI 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 () { generateXml: func () {
if (!me.flightPlan.generateXml()) { if (!me.flightPlan.generateXml()) {
return 0; return false;
} }
var scenarioXml = { var scenarioXml = {
@@ -82,7 +84,7 @@ var Scenario = {
"class": "aerotow-dragger", "class": "aerotow-dragger",
"model": Aircraft.getSelected(me.addon).modelPath, "model": Aircraft.getSelected(me.addon).modelPath,
"flightplan": FlightPlan.FILENAME_FLIGHTPLAN, "flightplan": FlightPlan.FILENAME_FLIGHTPLAN,
"repeat": 1, "repeat": true, # start again indefinitely
} }
} }
} }
@@ -93,7 +95,7 @@ var Scenario = {
me.addScenarioToPropertyList(); 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 () { isAlreadyAdded: func () {
foreach (var scenario; props.globals.getNode("/sim/ai/scenarios").getChildren("scenario")) { foreach (var scenario; props.globals.getNode("/sim/ai/scenarios").getChildren("scenario")) {
var id = scenario.getChild("id"); var id = scenario.getChild("id");
if (id != nil and id.getValue() == Scenario.SCENARIO_ID) { if (id != nil and id.getValue() == Scenario.SCENARIO_ID) {
return 1; return true;
} }
} }
return 0; return false;
}, },
# #
# Load scenario # Load scenario
# #
# Return 1 on successful, otherwise 0. # Return true on successful, otherwise false.
# #
load: func () { load: func () {
var args = props.Node.new({ "name": Scenario.SCENARIO_ID }); var args = props.Node.new({ "name": Scenario.SCENARIO_ID });
if (fgcommand("load-scenario", args)) { if (fgcommand("load-scenario", args)) {
me.isScenarioLoaded = 1; me.isScenarioLoaded = true;
me.message.success("Let's fly!"); me.message.success("Let's fly!");
# Enable engine sound # Enable engine sound
setprop(me.addonNodePath ~ "/addon-devel/sound/enable", 1); setprop(me.addonNodePath ~ "/addon-devel/sound/enable", true);
return 1; return true;
} }
me.message.error("Tow failed!"); me.message.error("Tow failed!");
return 0; return false;
}, },
# #
# Unload scenario # 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) { unload: func (withMessages = 0) {
if (me.isScenarioLoaded) { if (me.isScenarioLoaded) {
var args = props.Node.new({ "name": Scenario.SCENARIO_ID }); var args = props.Node.new({ "name": Scenario.SCENARIO_ID });
if (fgcommand("unload-scenario", args)) { if (fgcommand("unload-scenario", args)) {
me.isScenarioLoaded = 0; me.isScenarioLoaded = false;
if (withMessages) { if (withMessages) {
me.message.success("Aerotown disabled"); me.message.success("Aerotown disabled");
} }
return 1; return true;
} }
if (withMessages) { if (withMessages) {
me.message.error("Aerotown disable failed"); me.message.error("Aerotown disable failed");
} }
return 0; return false;
} }
if (withMessages) { if (withMessages) {
me.message.success("Aerotown already disabled"); me.message.success("Aerotown already disabled");
} }
return 1; return true;
}, },
}; };
+41
View 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;
},
};