2006-08-26 17:47:53 +00:00
|
|
|
# Properties under /consumables/fuel/tank[n]:
|
|
|
|
# + level-gal_us - Current fuel load. Can be set by user code.
|
|
|
|
# + level-lbs - OUTPUT ONLY property, do not try to set
|
|
|
|
# + selected - boolean indicating tank selection.
|
|
|
|
# + density-ppg - Fuel density, in lbs/gallon.
|
2006-08-27 12:25:43 +00:00
|
|
|
# + capacity-gal_us - Tank capacity
|
2006-08-26 17:47:53 +00:00
|
|
|
#
|
|
|
|
# Properties under /engines/engine[n]:
|
|
|
|
# + fuel-consumed-lbs - Output from the FDM, zeroed by this script
|
|
|
|
# + out-of-fuel - boolean, set by this code.
|
|
|
|
|
2006-08-27 12:25:43 +00:00
|
|
|
var UPDATE_PERIOD = 0.3;
|
|
|
|
var enabled = nil;
|
2007-06-16 00:44:44 +00:00
|
|
|
var serviceable = nil;
|
2006-08-27 12:25:43 +00:00
|
|
|
var fuel_freeze = nil;
|
|
|
|
var ai_enabled = nil;
|
|
|
|
var engines = nil;
|
2008-08-13 22:03:59 +00:00
|
|
|
var tanks = [];
|
2006-08-27 12:25:43 +00:00
|
|
|
var refuelingN = nil;
|
2019-03-10 14:24:34 +00:00
|
|
|
var reportContactNode = nil;
|
|
|
|
var reportContact = 0;
|
2013-02-24 22:34:11 +00:00
|
|
|
var contactN = nil;
|
2006-08-27 12:25:43 +00:00
|
|
|
var aimodelsN = nil;
|
2008-08-13 22:56:21 +00:00
|
|
|
var types = {};
|
2018-12-20 02:46:55 +00:00
|
|
|
var update_model_list = 0;
|
2019-03-10 14:24:34 +00:00
|
|
|
var tankerNode = nil;
|
|
|
|
var tankerContactNode = nil;
|
2006-08-26 17:47:53 +00:00
|
|
|
|
2018-12-20 02:46:55 +00:00
|
|
|
setlistener("/ai/models/model-added", func(v){
|
|
|
|
update_model_list = 1;
|
|
|
|
});
|
2006-08-27 12:25:43 +00:00
|
|
|
|
2018-12-20 02:46:55 +00:00
|
|
|
setlistener("/ai/models/model-removed", func(v){
|
|
|
|
update_model_list = 1;
|
|
|
|
});
|
2006-08-27 12:25:43 +00:00
|
|
|
|
2018-12-20 02:46:55 +00:00
|
|
|
|
|
|
|
var tankers = [];
|
2007-03-29 14:46:00 +00:00
|
|
|
var update_loop = func {
|
2006-08-27 12:25:43 +00:00
|
|
|
# check for contact with tanker aircraft
|
|
|
|
if (ai_enabled) {
|
2018-12-20 02:46:55 +00:00
|
|
|
if (update_model_list) {
|
|
|
|
update_model_list=0;
|
|
|
|
tankers = [];
|
|
|
|
var ac = aimodelsN.getChildren("tanker");
|
|
|
|
var mp = aimodelsN.getChildren("multiplayer");
|
2006-08-27 12:25:43 +00:00
|
|
|
|
2018-12-20 02:46:55 +00:00
|
|
|
foreach (var a; ac ~ mp) {
|
|
|
|
if (!a.getNode("valid", 1).getValue())
|
|
|
|
continue ;
|
|
|
|
if (!a.getNode("tanker", 1).getValue())
|
|
|
|
continue ;
|
|
|
|
foreach (var t; a.getNode("refuel", 1).getChildren("type")) {
|
|
|
|
var type = t.getValue();
|
|
|
|
if (contains(types, type) and types[type])
|
|
|
|
append(tankers, a);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-03-10 14:24:34 +00:00
|
|
|
var foundTankerNode = nil;
|
2018-12-20 02:46:55 +00:00
|
|
|
if (serviceable) {
|
|
|
|
foreach (var t; tankers) {
|
|
|
|
if (t.getNode("refuel/contact", 1).getValue()){
|
2019-03-10 14:24:34 +00:00
|
|
|
foundTankerNode = t;
|
2018-12-20 02:46:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-03-10 14:24:34 +00:00
|
|
|
|
|
|
|
if (foundTankerNode != tankerNode){
|
|
|
|
tankerNode = foundTankerNode;
|
|
|
|
if (tankerNode != nil){
|
|
|
|
tankerContactNode = tankerNode.getNode("refuel/contact", 1);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
tankerContactNode = nil;
|
|
|
|
}
|
|
|
|
reportContact = reportContactNode.getValue();
|
|
|
|
if (tankerNode != nil and tankerContactNode != nil) {
|
|
|
|
var tankerContact = tankerContactNode.getValue();
|
|
|
|
if (tankerContact != contactN.getValue()) {
|
|
|
|
if (reportContactNode.getValue()) {
|
|
|
|
if (tankerContact)
|
|
|
|
setprop("/sim/messages/copilot", "Engage");
|
|
|
|
else
|
|
|
|
setprop("/sim/messages/copilot", "Disengage");
|
|
|
|
}
|
|
|
|
contactN.setBoolValue(tankerContact);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (reportContact and contactN.getValue())
|
|
|
|
setprop("/sim/messages/copilot", "Disengage");
|
|
|
|
contactN.setBoolValue(0);
|
|
|
|
}
|
2006-08-27 12:25:43 +00:00
|
|
|
|
2018-12-15 15:28:07 +00:00
|
|
|
if (fuel_freeze){
|
|
|
|
return;
|
|
|
|
}
|
2006-08-27 12:25:43 +00:00
|
|
|
|
|
|
|
# sum up consumed fuel
|
2007-02-04 20:20:45 +00:00
|
|
|
var consumed = 0;
|
2006-08-27 12:25:43 +00:00
|
|
|
foreach (var e; engines) {
|
2007-02-04 20:20:45 +00:00
|
|
|
var fuel = e.getNode("fuel-consumed-lbs");
|
|
|
|
consumed += fuel.getValue();
|
|
|
|
fuel.setDoubleValue(0);
|
2006-08-27 12:25:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-02-04 20:20:45 +00:00
|
|
|
|
2006-08-27 12:25:43 +00:00
|
|
|
# calculate fuel received
|
2018-12-20 02:46:55 +00:00
|
|
|
if (tankerNode != nil) {
|
2013-02-24 22:34:11 +00:00
|
|
|
# Flow rate is the minimum of the tanker maxium rate
|
|
|
|
# and the aircraft maximum rate. Both are expressed
|
|
|
|
# in lbs/min
|
2018-12-20 02:46:55 +00:00
|
|
|
var fuel_rate = math.min(tankerNode.getNode("refuel/max-fuel-transfer-lbs-min", 1).getValue() or 6000,
|
2013-04-10 22:11:12 +00:00
|
|
|
refuelingN.getNode("max-fuel-transfer-lbs-min", 1).getValue() or 6000);
|
2013-02-24 22:34:11 +00:00
|
|
|
var received = UPDATE_PERIOD * fuel_rate / 60;
|
2007-02-04 20:20:45 +00:00
|
|
|
consumed -= received;
|
2006-08-27 12:25:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# make list of selected tanks
|
|
|
|
var selected_tanks = [];
|
|
|
|
foreach (var t; tanks) {
|
|
|
|
var cap = t.getNode("capacity-gal_us", 1).getValue();
|
2007-06-16 00:44:44 +00:00
|
|
|
if (cap != nil and cap > 0.01 and t.getNode("selected", 1).getBoolValue())
|
2006-08-27 12:25:43 +00:00
|
|
|
append(selected_tanks, t);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var out_of_fuel = 0;
|
2007-03-29 14:46:00 +00:00
|
|
|
if (size(selected_tanks) == 0) {
|
2006-08-27 12:25:43 +00:00
|
|
|
out_of_fuel = 1;
|
|
|
|
|
2007-03-29 14:46:00 +00:00
|
|
|
} elsif (consumed >= 0) {
|
2007-02-04 22:09:43 +00:00
|
|
|
var fuel_per_tank = consumed / size(selected_tanks);
|
|
|
|
foreach (var t; selected_tanks) {
|
|
|
|
var ppg = t.getNode("density-ppg").getValue();
|
|
|
|
var lbs = t.getNode("level-gal_us").getValue() * ppg;
|
|
|
|
lbs -= fuel_per_tank;
|
|
|
|
|
|
|
|
if (lbs < 0) {
|
|
|
|
lbs = 0;
|
|
|
|
# Kill the engines if we're told to, otherwise simply
|
|
|
|
# deselect the tank.
|
2007-06-16 00:44:44 +00:00
|
|
|
if (t.getNode("kill-when-empty", 1).getBoolValue())
|
2007-02-04 22:09:43 +00:00
|
|
|
out_of_fuel = 1;
|
2007-06-16 00:44:44 +00:00
|
|
|
else
|
2007-02-04 22:09:43 +00:00
|
|
|
t.getNode("selected", 1).setBoolValue(0);
|
|
|
|
}
|
2006-08-27 12:25:43 +00:00
|
|
|
|
2007-02-04 22:09:43 +00:00
|
|
|
var gals = lbs / ppg;
|
|
|
|
t.getNode("level-gal_us").setDoubleValue(gals);
|
|
|
|
t.getNode("level-lbs").setDoubleValue(lbs);
|
|
|
|
}
|
|
|
|
|
2007-03-29 18:25:48 +00:00
|
|
|
} else {
|
2007-02-04 22:09:43 +00:00
|
|
|
#find the number of tanks which can accept fuel
|
|
|
|
var available = 0;
|
|
|
|
|
|
|
|
foreach (var t; selected_tanks) {
|
|
|
|
var ppg = t.getNode("density-ppg").getValue();
|
|
|
|
var capacity = t.getNode("capacity-gal_us").getValue() * ppg;
|
|
|
|
var lbs = t.getNode("level-gal_us").getValue() * ppg;
|
|
|
|
|
2007-06-16 00:44:44 +00:00
|
|
|
if (lbs < capacity)
|
2007-02-04 22:09:43 +00:00
|
|
|
available += 1;
|
|
|
|
}
|
2006-08-27 12:25:43 +00:00
|
|
|
|
2007-02-04 22:09:43 +00:00
|
|
|
if (available > 0) {
|
2007-03-29 18:25:48 +00:00
|
|
|
var fuel_per_tank = -consumed / available;
|
2006-08-27 12:25:43 +00:00
|
|
|
|
2007-02-04 22:09:43 +00:00
|
|
|
# add fuel to each available tank
|
2006-08-27 12:25:43 +00:00
|
|
|
foreach (var t; selected_tanks) {
|
|
|
|
var ppg = t.getNode("density-ppg").getValue();
|
|
|
|
var capacity = t.getNode("capacity-gal_us").getValue() * ppg;
|
|
|
|
var lbs = t.getNode("level-gal_us").getValue() * ppg;
|
|
|
|
|
2007-03-29 18:25:48 +00:00
|
|
|
lbs += fuel_per_tank;
|
2007-06-16 00:44:44 +00:00
|
|
|
if (lbs > capacity)
|
2007-02-04 22:09:43 +00:00
|
|
|
lbs = capacity;
|
2006-08-27 12:25:43 +00:00
|
|
|
|
2007-02-04 22:09:43 +00:00
|
|
|
t.getNode("level-gal_us").setDoubleValue(lbs / ppg);
|
|
|
|
t.getNode("level-lbs").setDoubleValue(lbs);
|
2006-08-27 12:25:43 +00:00
|
|
|
}
|
2007-02-04 22:09:43 +00:00
|
|
|
|
|
|
|
# print ("available ", available , " fuel_per_tank " , fuel_per_tank);
|
2006-08-27 12:25:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var gals = 0;
|
|
|
|
var lbs = 0;
|
|
|
|
var cap = 0;
|
|
|
|
foreach (var t; tanks) {
|
|
|
|
gals += t.getNode("level-gal_us", 1).getValue();
|
|
|
|
lbs += t.getNode("level-lbs", 1).getValue();
|
|
|
|
cap += t.getNode("capacity-gal_us", 1).getValue();
|
|
|
|
}
|
|
|
|
|
|
|
|
setprop("/consumables/fuel/total-fuel-gals", gals);
|
|
|
|
setprop("/consumables/fuel/total-fuel-lbs", lbs);
|
2011-01-12 19:13:57 +00:00
|
|
|
if (cap == 0)
|
|
|
|
setprop("/consumables/fuel/total-fuel-norm", 0);
|
|
|
|
else
|
|
|
|
setprop("/consumables/fuel/total-fuel-norm", gals / cap);
|
2006-08-27 12:25:43 +00:00
|
|
|
|
2007-06-16 00:44:44 +00:00
|
|
|
foreach (var e; engines)
|
2006-08-27 12:25:43 +00:00
|
|
|
e.getNode("out-of-fuel", 1).setBoolValue(out_of_fuel);
|
2007-06-16 00:44:44 +00:00
|
|
|
|
2006-08-27 12:25:43 +00:00
|
|
|
}
|
|
|
|
|
2018-09-14 20:50:47 +00:00
|
|
|
var aarTimer = maketimer(UPDATE_PERIOD, update_loop);
|
|
|
|
aarTimer.simulatedTime = 1;
|
2006-08-27 12:25:43 +00:00
|
|
|
|
2006-08-26 17:47:53 +00:00
|
|
|
|
2006-10-26 09:23:53 +00:00
|
|
|
setlistener("/sim/signals/fdm-initialized", func {
|
2007-06-16 00:44:44 +00:00
|
|
|
if (contains(globals, "fuel") and typeof(fuel) == "hash")
|
2008-08-13 22:03:59 +00:00
|
|
|
fuel.loop = func nil; # kill $FG_ROOT/Nasal/fuel.nas' loop
|
2006-08-27 12:25:43 +00:00
|
|
|
|
2013-02-24 22:34:11 +00:00
|
|
|
contactN = props.globals.initNode("/systems/refuel/contact", 0, "BOOL");
|
|
|
|
refuelingN = props.globals.getNode("/systems/refuel", 1);
|
2006-08-27 12:25:43 +00:00
|
|
|
aimodelsN = props.globals.getNode("ai/models", 1);
|
|
|
|
engines = props.globals.getNode("engines", 1).getChildren("engine");
|
2019-03-10 14:24:34 +00:00
|
|
|
reportContactNode = refuelingN.getNode("report-contact", 1);
|
2006-08-27 12:25:43 +00:00
|
|
|
|
|
|
|
foreach (var e; engines) {
|
|
|
|
e.getNode("fuel-consumed-lbs", 1).setDoubleValue(0);
|
|
|
|
e.getNode("out-of-fuel", 1).setBoolValue(0);
|
|
|
|
}
|
|
|
|
|
2008-08-13 22:03:59 +00:00
|
|
|
foreach (var t; props.globals.getNode("consumables/fuel", 1).getChildren("tank")) {
|
|
|
|
if (!t.getAttribute("children"))
|
|
|
|
continue; # skip native_fdm.cxx generated zombie tanks
|
|
|
|
|
|
|
|
append(tanks, t);
|
2008-11-20 20:00:26 +00:00
|
|
|
t.initNode("level-gal_us", 0.0);
|
|
|
|
t.initNode("level-lbs", 0.0);
|
|
|
|
t.initNode("capacity-gal_us", 0.01); # not zero (div/zero issue)
|
|
|
|
t.initNode("density-ppg", 6.0); # gasoline
|
|
|
|
t.initNode("selected", 1, "BOOL");
|
2006-08-27 12:25:43 +00:00
|
|
|
}
|
|
|
|
|
2008-08-14 21:38:32 +00:00
|
|
|
foreach (var t; props.globals.getNode("systems/refuel", 1).getChildren("type"))
|
2008-08-13 22:56:21 +00:00
|
|
|
types[t.getValue()] = 1;
|
2020-05-01 15:07:53 +00:00
|
|
|
if (size(types) == 0) {
|
|
|
|
gui.popupTip('No items in systems/refuel/type[], air-to-air refueling will not work', 10);
|
|
|
|
}
|
2008-08-13 22:03:59 +00:00
|
|
|
setlistener("sim/freeze/fuel", func(n) fuel_freeze = n.getBoolValue(), 1);
|
|
|
|
setlistener("sim/ai/enabled", func(n) ai_enabled = n.getBoolValue(), 1);
|
|
|
|
setlistener("systems/refuel/serviceable", func(n) serviceable = n.getBoolValue(), 1);
|
2018-09-14 20:50:47 +00:00
|
|
|
aarTimer.restart(UPDATE_PERIOD);
|
2006-10-26 09:23:53 +00:00
|
|
|
});
|
2006-08-27 12:25:43 +00:00
|
|
|
|
|
|
|
|