1
0
Fork 0
fgdata/Nasal/fuel.nas
andy aa2686c0b9 Support a "kill-when-empty" flag on tanks to enable the strict
"engines die when any tank is empty" behavior.  Otherwise, just
deselect the empty tank.  This matches the "both" behavior many
lightplane fuel selectors have.
2004-04-30 14:42:42 +00:00

131 lines
4.4 KiB
Text

# 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.
# + capacity-gal_us - Tank capacity
#
# Properties under /engines/engine[n]:
# + fuel-consumed-lbs - Output from the FDM, zeroed by this script
# + out-of-fuel - boolean, set by this code.
UPDATE_PERIOD = 0.3;
fuelUpdate = func {
if(getprop("/sim/freeze/fuel")) { return registerTimer(); }
AllEngines = props.globals.getNode("engines").getChildren("engine");
# Sum the consumed fuel
total = 0;
foreach(e; AllEngines) {
fuel = e.getNode("fuel-consumed-lbs", 1);
consumed = fuel.getValue();
if(consumed == nil) { consumed = 0; }
total = total + consumed;
fuel.setDoubleValue(0);
}
# Unfortunately, FDM initialization hasn't happened when we start
# running. Wait for the FDM to start running before we set any output
# properties. This also prevents us from mucking with FDMs that
# don't support this fuel scheme.
if(total == 0) { return registerTimer(); }
if(!initialized) { initialize(); }
AllTanks = props.globals.getNode("consumables/fuel").getChildren("tank");
# Build a list of selected tanks. Note the filtering for
# "zero-capacity" tanks. The FlightGear code likes to define
# zombie tanks that have no meaning to the FDM, so we have to take
# measures to ignore them here.
selectedTanks = [];
foreach(t; AllTanks) {
cap = t.getNode("capacity-gal_us", 1).getValue();
if(cap != nil and cap > 0.01) {
if(t.getNode("selected", 1).getBoolValue()) {
append(selectedTanks, t);
}
}
}
# Subtract fuel from tanks, set auxilliary properties. Set out-of-fuel
# when any one tank is dry.
outOfFuel = 0;
if(size(selectedTanks) == 0) {
outOfFuel = 1;
} else {
fuelPerTank = total / size(selectedTanks);
foreach(t; selectedTanks) {
ppg = t.getNode("density-ppg").getValue();
lbs = t.getNode("level-gal_us").getValue() * ppg;
lbs = lbs - fuelPerTank;
if(lbs < 0) {
lbs = 0;
# Kill the engines if we're told to, otherwise simply
# deselect the tank.
if(t.getBoolValue("kill-when-empty")) { outOfFuel = 1; }
else { t.setBoolValue("selected", 0); }
}
gals = lbs / ppg;
t.getNode("level-gal_us").setDoubleValue(gals);
t.getNode("level-lbs").setDoubleValue(lbs);
}
}
# Total fuel properties
gals = lbs = cap = 0;
foreach(t; AllTanks) {
cap = cap + t.getNode("capacity-gal_us").getValue();
gals = gals + t.getNode("level-gal_us").getValue();
lbs = lbs + t.getNode("level-lbs").getValue();
}
setprop("/consumables/fuel/total-fuel-gals", gals);
setprop("/consumables/fuel/total-fuel-lbs", lbs);
setprop("/consumables/fuel/total-fuel-norm", gals/cap);
foreach(e; AllEngines) {
e.getNode("out-of-fuel").setBoolValue(outOfFuel);
}
registerTimer();
}
# Initalize: Make sure all needed properties are present and accounted
# for, and that they have sane default values.
initialized = 0;
initialize = func {
AllEngines = props.globals.getNode("engines").getChildren("engine");
AllTanks = props.globals.getNode("consumables/fuel").getChildren("tank");
foreach(e; AllEngines) {
e.getNode("fuel-consumed-lbs", 1).setDoubleValue(0);
e.getNode("out-of-fuel", 1).setBoolValue(0);
}
foreach(t; AllTanks) {
initDoubleProp(t, "level-gal_us", 0);
initDoubleProp(t, "level-lbs", 0);
initDoubleProp(t, "capacity-gal_us", 0.01); # Not zero (div/zero issue)
initDoubleProp(t, "density-ppg", 6.0); # gasoline
if(t.getNode("selected") == nil) {
t.getNode("selected", 1).setBoolValue(1);
}
}
initialized = 1;
}
initDoubleProp = func {
node = arg[0]; prop = arg[1]; val = arg[2];
if(node.getNode(prop) != nil) {
val = num(node.getNode(prop).getValue());
}
node.getNode(prop, 1).setDoubleValue(val);
}
# Fire it up
registerTimer = func {
settimer(fuelUpdate, UPDATE_PERIOD);
}
registerTimer();