diff --git a/Aircraft/Generic/aar.nas b/Aircraft/Generic/aar.nas
index 114d96bf8..c5bf8039c 100644
--- a/Aircraft/Generic/aar.nas
+++ b/Aircraft/Generic/aar.nas
@@ -19,6 +19,7 @@ var ai_enabled = nil;
var engines = nil;
var tanks = [];
var refuelingN = nil;
+var contactN = nil;
var aimodelsN = nil;
var types = {};
@@ -47,7 +48,18 @@ var update_loop = func {
}
var refueling = serviceable and size(tankers) > 0;
- refuelingN.setBoolValue(refueling);
+
+ if (refuelingN.getNode("report-contact", 1).getValue()) {
+ if (refueling and !contactN.getValue()) {
+ setprop("/sim/messages/copilot", "Engage");
+ }
+
+ if (!refueling and contactN.getValue()) {
+ setprop("/sim/messages/copilot", "Disengage");
+ }
+ }
+
+ contactN.setBoolValue(refueling);
if (fuel_freeze)
return settimer(update_loop, UPDATE_PERIOD);
@@ -65,8 +77,12 @@ var update_loop = func {
# calculate fuel received
if (refueling) {
- # assume max flow rate is 6000 lbs/min (for KC135)
- var received = 100 * UPDATE_PERIOD;
+ # Flow rate is the minimum of the tanker maxium rate
+ # and the aircraft maximum rate. Both are expressed
+ # in lbs/min
+ var fuel_rate = math.min(tankers[0].getNode("refuel/max-fuel-transfer-lbs-min", 1).getValue() or 6000,
+ refuelingN.getNode("max-fuel-transfer-lbs-min", 1).getValue());
+ var received = UPDATE_PERIOD * fuel_rate / 60;
consumed -= received;
}
@@ -169,7 +185,8 @@ setlistener("/sim/signals/fdm-initialized", func {
if (contains(globals, "fuel") and typeof(fuel) == "hash")
fuel.loop = func nil; # kill $FG_ROOT/Nasal/fuel.nas' loop
- refuelingN = props.globals.initNode("/systems/refuel/contact", 0, "BOOL");
+ contactN = props.globals.initNode("/systems/refuel/contact", 0, "BOOL");
+ refuelingN = props.globals.getNode("/systems/refuel", 1);
aimodelsN = props.globals.getNode("ai/models", 1);
engines = props.globals.getNode("engines", 1).getChildren("engine");
diff --git a/Nasal/tanker.nas b/Nasal/tanker.nas
index 54d718386..420d09fd2 100644
--- a/Nasal/tanker.nas
+++ b/Nasal/tanker.nas
@@ -6,11 +6,6 @@ if (globals["tanker"] != nil) {
}
#--------------------------------------------------------------------------------------------------
-
-var boom_tanker = "Models/Geometry/KC135/KC135.xml";
-var probe_tanker = "Models/Geometry/KA6-D/KA6-D.xml";
-
-
var oclock = func(bearing) int(0.5 + geo.normdeg(bearing) / 30) or 12;
@@ -75,7 +70,7 @@ var identity = {
var Tanker = {
- new: func(aiid, callsign, tacan, type, kias, heading, coord) {
+ new: func(aiid, callsign, tacan, type, model, kias, maxfuel, pattern, heading, coord) {
var m = { parents: [Tanker] };
m.callsign = callsign;
m.tacan = tacan;
@@ -83,7 +78,7 @@ var Tanker = {
m.heading = m.course = m.track_course = heading;
m.out_of_range_time = 0;
m.interval = 10;
- m.length = (getprop("tanker/pattern-length-nm") or 50) * NM2M;
+ m.length = pattern;
m.roll = 0;
m.coord = geo.Coord.new(coord);
m.anchor = geo.Coord.new(coord).apply_course_distance(m.track_course, m.length); # ARCP
@@ -111,6 +106,7 @@ var Tanker = {
m.ai.getNode("valid", 1).setBoolValue(1);
m.ai.getNode("navaids/tacan/channel-ID", 1).setValue(m.tacan);
m.ai.getNode("refuel/type", 1).setValue(type);
+ m.ai.getNode("refuel/max-fuel-transfer-lbs-min", 1).setValue(maxfuel);
m.ai.getNode("refuel/contact", 1).setBoolValue(0);
m.ai.getNode("radar/in-range", 1).setBoolValue(1);
@@ -130,7 +126,8 @@ var Tanker = {
m.vOffsetN = m.ai.getNode("radar/v-offset", 1);
m.update();
- m.model.getNode("path", 1).setValue(type == "boom" ? boom_tanker : probe_tanker);
+
+ m.model.getNode("path", 1).setValue(model);
m.model.getNode("latitude-deg-prop", 1).setValue(m.latN.getPath());
m.model.getNode("longitude-deg-prop", 1).setValue(m.lonN.getPath());
m.model.getNode("elevation-ft-prop", 1).setValue(m.altN.getPath());
@@ -206,6 +203,7 @@ var Tanker = {
var dalt = alt - me.ac.alt();
var ac_hdg = getprop("/orientation/heading-deg");
var ac_pitch = getprop("/orientation/pitch-deg");
+ var ac_contact_dist = getprop("/systems/refuel/contact-radius-m");
var elev = math.atan2(dalt, me.distance) * R2D;
me.latN.setDoubleValue(me.coord.lat());
@@ -219,11 +217,13 @@ var Tanker = {
me.rangeN.setDoubleValue(me.distance * M2NM);
me.brgN.setDoubleValue(me.bearing);
me.elevN.setDoubleValue(elev);
- me.contactN.setBoolValue(me.distance < 76 and dalt > 0 # 250 ft
- and abs(view.normdeg(me.bearing - ac_hdg)) < 20);
+
+ me.contactN.setBoolValue(me.distance < ac_contact_dist and
+ dalt > 0 and
+ abs(view.normdeg(me.bearing - ac_hdg)) < 20);
- me.hOffsetN.setDoubleValue(me.bearing - ac_hdg);
- me.vOffsetN.setDoubleValue(elev - ac_pitch);
+ me.hOffsetN.setDoubleValue(me.bearing - ac_hdg);
+ me.vOffsetN.setDoubleValue(elev - ac_pitch);
var droll = me.roll_target - me.roll;
if (droll > 0) {
@@ -268,47 +268,80 @@ var Tanker = {
active: {},
};
+# Factory methods
+# Create a tanker based on a given /sim/ai/tankers/tanker property node
+var create_tanker = func(tanker_node, course) {
+ var (aiid, callsign, tacanid) =_= identity.get();
+ var model = tanker_node.getNode("model", 1).getValue();
+ var type = tanker_node.getNode("type", 1).getValue();
+ var spd = tanker_node.getNode("speed-kts", 1).getValue() or 250;
+ var pattern = (tanker_node.getNode("pattern-length-nm", 1).getValue() or 50) * NM2M;
+ var maxfuel = tanker_node.getNode("max-fuel-transfer-lbs-min", 1).getValue() or 6000;
-var request = func {
+ var alt = int(10 + rand() * 15) * 1000; # FL100--FL250
+ alt = skip_cloud_layer(alt * FT2M);
+ var dist = 6000 + rand() * 4000;
+ var coord = geo.aircraft_position().apply_course_distance(course, dist).set_alt(alt);
+
+ Tanker.new(aiid, callsign, tacanid, type, model, spd, maxfuel, pattern, course, coord);
+}
+
+# Request a new tanker
+var request_new = func(tanker_node=nil) {
+ var tanker = values(Tanker.active);
+ if (size(tanker)) tanker[0].del();
+ request(tanker_node);
+}
+
+var request = func(tanker_node=nil) {
+ var tanker = values(Tanker.active);
+ if (size(tanker))
+ return tanker[0].identify();
+
+ if (tanker_node == nil) {
+ var type = props.globals.getNode("systems/refuel", 1).getChildren("type");
+ if (!size(type))
+ return;
+ type = type[rand() * size(type)].getValue();
+
+ var tankers = props.globals.getNode("/sim/ai/tankers", 1).getChildren("tanker");
+ foreach (var tanker; tankers) {
+ if (tanker.getNode("type", 1).getValue() == type) {
+ tanker_node = tanker;
+ break;
+ }
+ }
+ }
+
+ var hdg = getprop("orientation/heading-deg");
+ var course = hdg + (rand() - 0.5) * 60;
+
+ create_tanker(tanker_node, course);
+}
+
+var request_random = func(tanker_node=nil) {
var tanker = values(Tanker.active);
if (size(tanker))
return tanker[0].identify();
- var type = props.globals.getNode("systems/refuel", 1).getChildren("type");
- if (!size(type))
- return;
- type = type[rand() * size(type)].getValue();
+ if (tanker_node == nil) {
+ var type = props.globals.getNode("systems/refuel", 1).getChildren("type");
+ if (!size(type))
+ return;
+ type = type[rand() * size(type)].getValue();
+
+ var tankers = props.globals.getNode("/sim/ai/tankers", 1).getChildren("tanker");
+ foreach (var tanker; tankers) {
+ if (tanker.getNode("type", 1).getValue() == type) {
+ tanker_node = tanker;
+ break;
+ }
+ }
+ }
- var (aiid, callsign, tacanid) =_= identity.get();
- var hdg = getprop("orientation/heading-deg");
- var course = hdg + (rand() - 0.5) * 60;
- var dist = 6000 + rand() * 4000;
- var alt = int(10 + rand() * 15) * 1000; # FL100--FL250
- alt = skip_cloud_layer(alt * FT2M);
- var coord = geo.aircraft_position().apply_course_distance(course, dist).set_alt(alt);
- Tanker.new(aiid, callsign, tacanid, type, 250, hdg, coord);
-}
-
-
-var request_random = func {
- var tanker = values(Tanker.active);
- if (size(tanker))
- return tanker[0].identify();
-
- var type = props.globals.getNode("systems/refuel", 1).getChildren("type");
- if (!size(type))
- return;
- type = type[rand() * size(type)].getValue();
-
- var (aiid, callsign, tacanid) =_= identity.get();
- var hdg = rand() * 360;
- var course = rand() * 360;
- var dist = 6000 + rand() * 4000;
- var alt = int(10 + rand() * 15) * 1000; # FL100--FL250
- alt = skip_cloud_layer(alt * FT2M);
- var coord = geo.aircraft_position().apply_course_distance(course, dist).set_alt(alt);
- Tanker.new(aiid, callsign, tacanid, type, 250, hdg, coord);
+ var course = rand() * 360;
+ create_tanker(tanker_node, course);
}
diff --git a/gui/dialogs/tanker.xml b/gui/dialogs/tanker.xml
index 73e1c18d1..d16d0526a 100644
--- a/gui/dialogs/tanker.xml
+++ b/gui/dialogs/tanker.xml
@@ -5,12 +5,63 @@
-10
vbox
+
+
+ var dlgRoot = cmdarg();
+
+ var tankers = props.globals.getNode("/sim/ai/tankers/", 1).getChildren("tanker");
+ var types = props.globals.getNode("/systems/refuel/", 1).getChildren("type");
+ var tanker_node = props.globals.getNode("/sim/gui/dialogs/tanker/tanker", 1);
+
+ # Force default speed of 250kts
+ setprop("/sim/gui/dialogs/tanker/tanker/speed-kts", 250.0);
+
+ if (size(types) == 0) {
+ # This really shouldn't happen, as Nasal/tanker.nas disables this menu item
+ # if no refueling type is available.
+ gui.popupTip("Air to air refueling unavailable in this aircraft", 5);
+ fgcommand("dialog-close", props.Node.new({ "dialog-name" : "tanker"}));
+ }
+
+
+ if (size(tankers) > 0) {
+ var combo = gui.findElementByName(dlgRoot, "tanker-combo");
+ var idx = 0;
+ foreach (var t; tankers) {
+ foreach(var type; types) {
+ if (type.getValue() == t.getNode("type", 1).getValue()) {
+ combo.getChild("value", idx, 1).setValue(t.getNode("name", 1).getValue());
+ idx += 1;
+ }
+ }
+ }
+ }
+
+ var select_tanker = func() {
+ var name = getprop("/sim/gui/dialogs/tanker/selected-tanker");
+
+ foreach (var t; tankers) {
+ if (name == t.getNode("name", 1).getValue()) {
+ props.copy(t, tanker_node);
+ }
+ }
+ }
+
+ var generate_tanker = func() {
+ if (tanker_node.getNode("name", 1).getValue()) {
+ tanker.request_new(tanker_node);
+ }
+ }
+
+
+
+
hbox
1
-
+
1
@@ -30,21 +81,195 @@
-
+
+ table
+
+
+ 0
+ 0
+ right
+
+
+
+
+ tanker-combo
+ 0
+ 1
+ 2
+ left
+ /sim/gui/dialogs/tanker/selected-tanker
+ false
+ 200
+ fill
+
+ dialog-apply
+ tanker-combo
+
+
+ nasal
+
+
+
-
+
+ 1
+ 0
+ right
+
+
+
+
+ 1
+ 1
+
+
+ /sim/gui/dialogs/tanker/tanker/type
+ probe
+
+
+ 3
+ left
+
+
+
+
+ 1
+ 1
+
+
+ /sim/gui/dialogs/tanker/tanker/type
+ boom
+
+
+ 3
+ left
+
+
+
+
+ 2
+ 0
+ right
+
+
+
+
+ tanker-speed
+ 2
+ 1
+ fill
+ 100
+ 350
+ true
+ /sim/gui/dialogs/tanker/tanker/speed-kts
+
+ dialog-apply
+ tanker-speed
+
+
+
+
+ 2
+ 2
+ left
+ %2.0fkts
+
+ /sim/gui/dialogs/tanker/tanker/speed-kts
+ true
+
+
+
+ 3
+ 0
+ right
+
+
+
+
+ contact-radius
+ 3
+ 1
+ fill
+ 1
+ 100
+ /systems/refuel/contact-radius-m
+
+ dialog-apply
+ contact-radius
+
+
+
+
+ 3
+ 2
+ left
+ %2.0fm
+ /systems/refuel/contact-radius-m
+ true
+
+
+
+ 4
+ 0
+ right
+
+
+
+
+ report-contact
+ 4
+ 1
+ left
+ /systems/refuel/report-contact
+
+ dialog-apply
+ report-contact
+
+
+
+
+
+
+
+
+ hbox
+ 5
+
+ true
+
+
+
+ true
+
+
+
+ true
+
+
+
+ true
+
+
+
diff --git a/preferences.xml b/preferences.xml
index 6405ebd6c..6b8e59e85 100644
--- a/preferences.xml
+++ b/preferences.xml
@@ -757,6 +757,7 @@ Started September 2000 by David Megginson, david@megginson.com
true
nimitz_demo
true
+
@@ -1202,6 +1203,9 @@ Started September 2000 by David Megginson, david@megginson.com
true
+ 76
+ false
+ 6000