1 # Properties under /consumables/fuel/tank[n]:
2 # + level-gal_us - Current fuel load. Can be set by user code.
3 # + level-lbs - OUTPUT ONLY property, do not try to set
4 # + selected - boolean indicating tank selection.
5 # + density-ppg - Fuel density, in lbs/gallon.
6 # + capacity-gal_us - Tank capacity
8 # Properties under /engines/engine[n]:
9 # + fuel-consumed-lbs - Output from the FDM, zeroed by this script
10 # + out-of-fuel - boolean, set by this code.
13 var UPDATE_PERIOD = 0.3;
16 var serviceable = nil;
17 var fuel_freeze = nil;
28 var update_loop = func {
29 # check for contact with tanker aircraft
32 var ac = aimodelsN.getChildren("tanker");
33 var mp = aimodelsN.getChildren("multiplayer");
35 foreach (var a; ac ~ mp) {
36 if (!a.getNode("valid", 1).getValue())
38 if (!a.getNode("tanker", 1).getValue())
40 if (!a.getNode("refuel/contact", 1).getValue())
42 foreach (var t; a.getNode("refuel", 1).getChildren("type")) {
43 var type = t.getValue();
44 if (contains(types, type) and types[type])
50 var refueling = serviceable and size(tankers) > 0;
52 if (refuelingN.getNode("report-contact", 1).getValue()) {
53 if (refueling and !contactN.getValue()) {
54 setprop("/sim/messages/copilot", "Engage");
57 if (!refueling and contactN.getValue()) {
58 setprop("/sim/messages/copilot", "Disengage");
62 contactN.setBoolValue(refueling);
65 return settimer(update_loop, UPDATE_PERIOD);
68 # sum up consumed fuel
70 foreach (var e; engines) {
71 var fuel = e.getNode("fuel-consumed-lbs");
72 consumed += fuel.getValue();
73 fuel.setDoubleValue(0);
78 # calculate fuel received
80 # Flow rate is the minimum of the tanker maxium rate
81 # and the aircraft maximum rate. Both are expressed
83 var fuel_rate = math.min(tankers[0].getNode("refuel/max-fuel-transfer-lbs-min", 1).getValue() or 6000,
84 refuelingN.getNode("max-fuel-transfer-lbs-min", 1).getValue());
85 var received = UPDATE_PERIOD * fuel_rate / 60;
90 # make list of selected tanks
91 var selected_tanks = [];
92 foreach (var t; tanks) {
93 var cap = t.getNode("capacity-gal_us", 1).getValue();
94 if (cap != nil and cap > 0.01 and t.getNode("selected", 1).getBoolValue())
95 append(selected_tanks, t);
100 if (size(selected_tanks) == 0) {
103 } elsif (consumed >= 0) {
104 var fuel_per_tank = consumed / size(selected_tanks);
105 foreach (var t; selected_tanks) {
106 var ppg = t.getNode("density-ppg").getValue();
107 var lbs = t.getNode("level-gal_us").getValue() * ppg;
108 lbs -= fuel_per_tank;
112 # Kill the engines if we're told to, otherwise simply
114 if (t.getNode("kill-when-empty", 1).getBoolValue())
117 t.getNode("selected", 1).setBoolValue(0);
120 var gals = lbs / ppg;
121 t.getNode("level-gal_us").setDoubleValue(gals);
122 t.getNode("level-lbs").setDoubleValue(lbs);
126 #find the number of tanks which can accept fuel
129 foreach (var t; selected_tanks) {
130 var ppg = t.getNode("density-ppg").getValue();
131 var capacity = t.getNode("capacity-gal_us").getValue() * ppg;
132 var lbs = t.getNode("level-gal_us").getValue() * ppg;
139 var fuel_per_tank = -consumed / available;
141 # add fuel to each available tank
142 foreach (var t; selected_tanks) {
143 var ppg = t.getNode("density-ppg").getValue();
144 var capacity = t.getNode("capacity-gal_us").getValue() * ppg;
145 var lbs = t.getNode("level-gal_us").getValue() * ppg;
147 lbs += fuel_per_tank;
151 t.getNode("level-gal_us").setDoubleValue(lbs / ppg);
152 t.getNode("level-lbs").setDoubleValue(lbs);
155 # print ("available ", available , " fuel_per_tank " , fuel_per_tank);
163 foreach (var t; tanks) {
164 gals += t.getNode("level-gal_us", 1).getValue();
165 lbs += t.getNode("level-lbs", 1).getValue();
166 cap += t.getNode("capacity-gal_us", 1).getValue();
169 setprop("/consumables/fuel/total-fuel-gals", gals);
170 setprop("/consumables/fuel/total-fuel-lbs", lbs);
172 setprop("/consumables/fuel/total-fuel-norm", 0);
174 setprop("/consumables/fuel/total-fuel-norm", gals / cap);
176 foreach (var e; engines)
177 e.getNode("out-of-fuel", 1).setBoolValue(out_of_fuel);
179 settimer(update_loop, UPDATE_PERIOD);
184 setlistener("/sim/signals/fdm-initialized", func {
185 if (contains(globals, "fuel") and typeof(fuel) == "hash")
186 fuel.loop = func nil; # kill $FG_ROOT/Nasal/fuel.nas' loop
188 contactN = props.globals.initNode("/systems/refuel/contact", 0, "BOOL");
189 refuelingN = props.globals.getNode("/systems/refuel", 1);
190 aimodelsN = props.globals.getNode("ai/models", 1);
191 engines = props.globals.getNode("engines", 1).getChildren("engine");
193 foreach (var e; engines) {
194 e.getNode("fuel-consumed-lbs", 1).setDoubleValue(0);
195 e.getNode("out-of-fuel", 1).setBoolValue(0);
198 foreach (var t; props.globals.getNode("consumables/fuel", 1).getChildren("tank")) {
199 if (!t.getAttribute("children"))
200 continue; # skip native_fdm.cxx generated zombie tanks
203 t.initNode("level-gal_us", 0.0);
204 t.initNode("level-lbs", 0.0);
205 t.initNode("capacity-gal_us", 0.01); # not zero (div/zero issue)
206 t.initNode("density-ppg", 6.0); # gasoline
207 t.initNode("selected", 1, "BOOL");
210 foreach (var t; props.globals.getNode("systems/refuel", 1).getChildren("type"))
211 types[t.getValue()] = 1;
213 setlistener("sim/freeze/fuel", func(n) fuel_freeze = n.getBoolValue(), 1);
214 setlistener("sim/ai/enabled", func(n) ai_enabled = n.getBoolValue(), 1);
215 setlistener("systems/refuel/serviceable", func(n) serviceable = n.getBoolValue(), 1);