diff --git a/Nasal/fuel.nas b/Nasal/fuel.nas new file mode 100644 index 000000000..2d615a998 --- /dev/null +++ b/Nasal/fuel.nas @@ -0,0 +1,119 @@ +# 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 + selectedTanks = []; + foreach(t; AllTanks) { + 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; outOfFuel = 1; } + 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", 1); # 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(); diff --git a/Nasal/props.nas b/Nasal/props.nas index 1e59db113..fe9dcf27f 100644 --- a/Nasal/props.nas +++ b/Nasal/props.nas @@ -29,8 +29,8 @@ Node = { getNode : func { wrap(_getNode(me._g, arg)) }, getBoolValue : func { - val = getValue(); - if(getType() == "STRING" and val == "false") { 0 } + val = me.getValue(); + if(me.getType() == "STRING" and val == "false") { 0 } else { val } } };