+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+//
+// The engine can tell us how much fuel it needs, but it is up to the propulsion
+// subsystem manager class FGPropulsion to manage fuel flow amongst tanks. Engines
+// May burn fuel from more than one tank at a time, and may burn from one tank
+// before another - that is, may burn from one tank until the tank is depleted,
+// then burn from the next highest priority tank. This can be accompished
+// by defining a fuel management system, but this way of specifying priorities
+// is more automatic from a user perspective.
+
+void FGPropulsion::ConsumeFuel(FGEngine* engine)
+{
+ if (FuelFreeze) return;
+ if (FDMExec->GetTrimStatus()) return;
+
+ unsigned int TanksWithFuel=0, CurrentFuelTankPriority=1;
+ unsigned int TanksWithOxidizer=0, CurrentOxidizerTankPriority=1;
+ vector <int> FeedListFuel, FeedListOxi;
+ bool Starved = true; // Initially set Starved to true. Set to false in code below.
+ bool hasOxTanks = false;
+
+ // For this engine,
+ // 1) Count how many fuel tanks with the current priority level have fuel
+ // 2) If there none, then try next lower priority (higher number) - that is,
+ // increment CurrentPriority.
+ // 3) Build the feed list.
+ // 4) Do the same for oxidizer tanks, if needed.
+
+ // Process fuel tanks, if any
+ while ((TanksWithFuel == 0) && (CurrentFuelTankPriority <= numTanks)) {
+ for (unsigned int i=0; i<engine->GetNumSourceTanks(); i++) {
+ unsigned int TankId = engine->GetSourceTank(i);
+ FGTank* Tank = Tanks[TankId];
+ unsigned int TankPriority = Tank->GetPriority();
+ if (TankPriority != 0) {
+ switch(Tank->GetType()) {
+ case FGTank::ttFUEL:
+ if ((Tank->GetContents() > 0.0) && Tank->GetSelected() && (TankPriority == CurrentFuelTankPriority)) {
+ TanksWithFuel++;
+ Starved = false;
+ FeedListFuel.push_back(TankId);
+ }
+ break;
+ case FGTank::ttOXIDIZER:
+ // Skip this here (done below)
+ break;
+ }
+ }
+ }
+ if (TanksWithFuel == 0) CurrentFuelTankPriority++; // No tanks at this priority, try next priority
+ }
+
+ bool FuelStarved = Starved;
+ Starved = true;
+
+ // Process Oxidizer tanks, if any
+ if (engine->GetType() == FGEngine::etRocket) {
+ while ((TanksWithOxidizer == 0) && (CurrentOxidizerTankPriority <= numTanks)) {
+ for (unsigned int i=0; i<engine->GetNumSourceTanks(); i++) {
+ unsigned int TankId = engine->GetSourceTank(i);
+ FGTank* Tank = Tanks[TankId];
+ unsigned int TankPriority = Tank->GetPriority();
+ if (TankPriority != 0) {
+ switch(Tank->GetType()) {
+ case FGTank::ttFUEL:
+ // Skip this here (done above)
+ break;
+ case FGTank::ttOXIDIZER:
+ hasOxTanks = true;
+ if (Tank->GetContents() > 0.0 && Tank->GetSelected() && TankPriority == CurrentOxidizerTankPriority) {
+ TanksWithOxidizer++;
+ if (TanksWithFuel > 0) Starved = false;
+ FeedListOxi.push_back(TankId);
+ }
+ break;
+ }
+ }
+ }
+ if (TanksWithOxidizer == 0) CurrentOxidizerTankPriority++; // No tanks at this priority, try next priority
+ }
+ }
+
+ bool OxiStarved = Starved;
+
+ engine->SetStarved(FuelStarved || (hasOxTanks && OxiStarved)); // Tanks can be refilled, so be sure to reset engine Starved flag here.
+
+ // No fuel or fuel/oxidizer found at any priority!
+// if (Starved) return;
+ if (FuelStarved || (hasOxTanks && OxiStarved)) return;
+
+ double FuelToBurn = engine->CalcFuelNeed(); // How much fuel does this engine need?
+ double FuelNeededPerTank = FuelToBurn / TanksWithFuel; // Determine fuel needed per tank.
+ for (unsigned int i=0; i<FeedListFuel.size(); i++) {
+ Tanks[FeedListFuel[i]]->Drain(FuelNeededPerTank);
+ }
+
+ if (engine->GetType() == FGEngine::etRocket) {
+ double OxidizerToBurn = engine->CalcOxidizerNeed(); // How much fuel does this engine need?
+ double OxidizerNeededPerTank = OxidizerToBurn / TanksWithOxidizer; // Determine fuel needed per tank.
+ for (unsigned int i=0; i<FeedListOxi.size(); i++) {
+ Tanks[FeedListOxi[i]]->Drain(OxidizerNeededPerTank);
+ }
+ }
+
+}
+