/// <summary> /// Activate autopilot /// </summary> internal override bool Activate() { if (vessel.situation != Vessel.Situations.LANDED && vessel.situation != Vessel.Situations.PRELAUNCH) { ScreenMessages.PostScreenMessage(Localizer.Format("#LOC_BV_Warning_Landed"), 5f).color = Color.yellow; return(false); } SystemCheck(); // No driving until at least 3 operable wheels are touching the ground - tricycles are allowed if ((wheelTestResult.inTheAir > 0) && (wheelTestResult.operable < 3)) { ScreenMessages.PostScreenMessage(Localizer.Format("#LOC_BV_Warning_WheelsNotTouching"), 5f).color = Color.yellow; return(false); } if (wheelTestResult.operable < 3) { ScreenMessages.PostScreenMessage(Localizer.Format("#LOC_BV_Warning_WheelsNotOperable"), 5f).color = Color.yellow; return(false); } // At least 2 wheels must be on if (wheelTestResult.online < 2) { ScreenMessages.PostScreenMessage(Localizer.Format("#LOC_BV_Warning_WheelsNotOnline"), 5f).color = Color.yellow; return(false); } // Get fuel amount if fuel cells are used if (fuelCells.Use && !CheatOptions.InfinitePropellant) { IResourceBroker broker = new ResourceBroker(); var iList = fuelCells.InputResources; for (int i = 0; i < iList.Count; i++) { iList[i].MaximumAmountAvailable = broker.AmountAvailable(vessel.rootPart, iList[i].Name, 1, ResourceFlowMode.ALL_VESSEL); if (iList[i].MaximumAmountAvailable == 0) { ScreenMessages.PostScreenMessage(Localizer.Format("#LOC_BV_Warning_NotEnoughFuel"), 5f).color = Color.yellow; return(false); } } } // Power production if (requiredPower > (electricPower_Solar + electricPower_Other)) { // If required power is greater than total power generated, then average speed can be lowered up to 75% double speedReduction = (requiredPower - (electricPower_Solar + electricPower_Other)) / requiredPower; if (speedReduction > 0.75) { ScreenMessages.PostScreenMessage(Localizer.Format("#LOC_BV_Warning_LowPowerRover"), 5f).color = Color.yellow; return(false); } } BonVoyageModule module = vessel.FindPartModuleImplementing <BonVoyageModule>(); if (module != null) { vesselHeightFromTerrain = vessel.radarAltitude; module.averageSpeed = averageSpeed; module.averageSpeedAtNight = averageSpeedAtNight; module.manned = manned; module.vesselHeightFromTerrain = vesselHeightFromTerrain; } return(base.Activate()); }
public void FixedUpdate() { if (!HighLogic.LoadedSceneIsFlight || vessel == null || !vessel.loaded) { return; } if (vessel.isEVA) { CheckEVA(vessel); return; } if (_partCount != vessel.parts.Count) { if (_partCount > 0) { _isStatusRefreshRequired = true; } _partCount = vessel.parts.Count; } if (_isDirty) { _isDirty = false; UpdateVesselInfo(); UpdateStatus(); } var now = Planetarium.GetUniversalTime(); if (_currentCrewCount == 0) { VesselStatus.VesselName = vessel.vesselName; VesselStatus.NumCrew = vessel.GetCrewCount(); VesselStatus.CrewCap = vessel.GetCrewCapacity(); VesselStatus.LastECCheck = now; VesselStatus.LastFeeding = now; VesselStatus.LastUpdate = now; LifeSupportManager.Instance.TrackVessel(VesselStatus); LastUpdateTime = now; return; } try { bool isLongLoop = false; var offKerbin = !LifeSupportManager.IsOnKerbin(vessel); CheckVesselId(); // Check our time double deltaTime = GetDeltaTime(); bool isCatchup = deltaTime / 2 > TimeWarp.fixedDeltaTime; if (deltaTime < ResourceUtilities.FLOAT_TOLERANCE * 10) { return; } if (now >= _lastProcessingTime + _checkInterval) { isLongLoop = true; _lastProcessingTime = now; } VesselStatus.LastUpdate = now; VesselStatus.VesselName = vessel.vesselName; VesselStatus.NumCrew = vessel.GetCrewCount(); VesselStatus.CrewCap = vessel.GetCrewCapacity(); if (isLongLoop) { CheckForDeadKerbals(); } if (_currentCrewCount > 0) { //Guard clause if (_crewPart == null) { UpdateVesselInfo(); } //we will add a bit of a fudge factor for supplies var tolerance = deltaTime / 2f; //nom nom nom! ConverterResults resultSupply = Converter.ProcessRecipe(deltaTime, SupplyRecipe, _crewPart, null, 1f); ConverterResults resultEC = Converter.ProcessRecipe(deltaTime, ECRecipe, _crewPart, null, 1f); #region Long Loop - Crew if (isLongLoop) { //Ensure status is current UpdateStatus(); var habTime = LifeSupportManager.GetTotalHabTime(VesselStatus, vessel); if (_oldHabChecksum < ResourceUtilities.FLOAT_TOLERANCE) { _oldHabChecksum = LifeSupportManager.GetHabChecksum(VesselStatus, vessel); } var newHabChecksum = LifeSupportManager.GetHabChecksum(VesselStatus, vessel); if (Math.Abs(_oldHabChecksum - newHabChecksum) > ResourceUtilities.FLOAT_TOLERANCE) { Debug.Log("[USI-LS] Vessel situation changed, refreshing life support"); _isStatusRefreshRequired = true; _oldHabChecksum = newHabChecksum; } var crewRoster = vessel.GetVesselCrew(); var count = crewRoster.Count; for (int i = 0; i < count; ++i) { var crewMember = crewRoster[i]; bool isGrouchyHab = false; bool isGrouchySupplies = false; bool isGrouchyEC = false; bool isScout = crewMember.HasEffect("ExplorerSkill") && habTime >= LifeSupportScenario.Instance.settings.GetSettings().ScoutHabTime; bool isPermaHab = habTime >= LifeSupportScenario.Instance.settings.GetSettings().PermaHabTime; bool isHomeWorld = CheckIfHomeWorld() && habTime >= LifeSupportScenario.Instance.settings.GetSettings().ScoutHabTime&& vessel.LandedOrSplashed; // Get the crew member's life support stats var trackedKerbal = LifeSupportManager.Instance.FetchKerbal(crewMember); // Update life support stats if (_isStatusRefreshRequired) { trackedKerbal.TimeEnteredVessel = now; _isStatusRefreshRequired = false; LifeSupportManager.Instance.TrackKerbal(trackedKerbal); } // Update Hab effects if (!offKerbin || isScout || isHomeWorld || isPermaHab) { trackedKerbal.TimeEnteredVessel = now; trackedKerbal.LastAtHome = now; trackedKerbal.MaxOffKerbinTime = habTime + trackedKerbal.LastAtHome; } else { if (vessel.id.ToString() != trackedKerbal.CurrentVesselId) { if (vessel.id.ToString() != trackedKerbal.PreviousVesselId) { trackedKerbal.TimeEnteredVessel = now; } trackedKerbal.PreviousVesselId = trackedKerbal.CurrentVesselId; trackedKerbal.CurrentVesselId = vessel.id.ToString(); LifeSupportManager.Instance.TrackKerbal(trackedKerbal); } isGrouchyHab = CheckHabSideEffects(trackedKerbal); } // Update Supplies effects if (offKerbin && (deltaTime - resultSupply.TimeFactor > tolerance)) { isGrouchySupplies = CheckSupplySideEffects(trackedKerbal); } else if (deltaTime >= ResourceUtilities.FLOAT_TOLERANCE) { //All is well trackedKerbal.LastMeal = LastUpdateTime; VesselStatus.LastFeeding = LastUpdateTime; } // Update ElectricCharge effects if (offKerbin && (deltaTime - resultEC.TimeFactor > tolerance)) { isGrouchyEC = CheckECSideEffects(trackedKerbal); } else if (deltaTime >= ResourceUtilities.FLOAT_TOLERANCE) { //All is well trackedKerbal.LastEC = LastUpdateTime; VesselStatus.LastECCheck = LastUpdateTime; } trackedKerbal.LastUpdate = now; var isAnyGrouch = isGrouchyEC || isGrouchyHab || isGrouchySupplies; if (isGrouchyEC && !isCatchup) { ApplyEffect( trackedKerbal, crewMember, LifeSupportManager.GetNoECEffect(trackedKerbal.KerbalName), "power loss"); } else if (isGrouchySupplies && !isCatchup) { ApplyEffect( trackedKerbal, crewMember, LifeSupportManager.GetNoSupplyEffect(trackedKerbal.KerbalName), "lack of supplies"); } else if (isGrouchyHab && !isCatchup) { ApplyEffect( trackedKerbal, crewMember, LifeSupportManager.GetNoHomeEffect(trackedKerbal.KerbalName), "homesickness"); } else if (crewMember.experienceTrait.Title != trackedKerbal.OldTrait && !isAnyGrouch) { RemoveGrouchiness(crewMember, trackedKerbal); } LifeSupportManager.Instance.TrackKerbal(trackedKerbal); } } #endregion - Crew var remainingSupplies = ResourceBroker.AmountAvailable( _crewPart, "Supplies", deltaTime, ResourceFlowMode.ALL_VESSEL); var remainingBattery = ResourceBroker.AmountAvailable( _crewPart, "ElectricCharge", deltaTime, ResourceFlowMode.ALL_VESSEL); var suppliesConsumption = LifeSupportScenario.Instance.settings.GetSettings().SupplyAmount; var electricityConsumption = LifeSupportScenario.Instance.settings.GetSettings().ECAmount; VesselStatus.SuppliesLeft = remainingSupplies / suppliesConsumption / _currentCrewCount / VesselStatus.RecyclerMultiplier; VesselStatus.ECLeft = remainingBattery / electricityConsumption / _currentCrewCount; } else { VesselStatus.LastECCheck = now; VesselStatus.LastFeeding = now; VesselStatus.LastUpdate = now; } LifeSupportManager.Instance.TrackVessel(VesselStatus); } catch (Exception ex) { print(string.Format("ERROR {0} IN ModuleLifeSupport", ex.Message)); } }
/// <summary> /// Check the systems /// </summary> internal override void SystemCheck() { base.SystemCheck(); // Test stock wheels WheelTestResult testResultStockWheels = CheckStockWheels(); // Test KSPWheels WheelTestResult testResultKSPkWheels = CheckKSPWheels(); // Sum it wheelTestResult.powerRequired = testResultStockWheels.powerRequired + testResultKSPkWheels.powerRequired; wheelTestResult.maxSpeedSum = testResultStockWheels.maxSpeedSum + testResultKSPkWheels.maxSpeedSum; wheelTestResult.inTheAir = testResultStockWheels.inTheAir + testResultKSPkWheels.inTheAir; wheelTestResult.operable = testResultStockWheels.operable + testResultKSPkWheels.operable; wheelTestResult.damaged = testResultStockWheels.damaged + testResultKSPkWheels.damaged; wheelTestResult.online = testResultStockWheels.online + testResultKSPkWheels.online; wheelTestResult.maxWheelRadius = testResultStockWheels.maxWheelRadius + testResultKSPkWheels.maxWheelRadius; // Generally, moving at high speed requires less power than wheels' max consumption. Maximum required power of controller will 35% of wheels power requirement requiredPower = wheelTestResult.powerRequired / 100 * 35; // Get available EC from batteries if (batteries.UseBatteries) { batteries.MaxAvailableEC = GetAvailableEC_Batteries(); } else { batteries.MaxAvailableEC = 0; } // Get available EC from fuell cells fuelCells.OutputValue = 0; fuelCells.InputResources.Clear(); if (fuelCells.Use) { List <ModuleResourceConverter> mrc = vessel.FindPartModulesImplementing <ModuleResourceConverter>(); for (int i = 0; i < mrc.Count; i++) { double ecRatio = 0; try { var ec = mrc[i].outputList.Find(x => x.ResourceName == "ElectricCharge"); // NullArgumentException when not found ecRatio = ec.Ratio; } catch { } if (ecRatio > 0) { // Add input resources var iList = mrc[i].inputList; for (int r = 0; r < iList.Count; r++) { // Check if we have fuel for converter. If not, then continue without adding output ratio. if (!CheatOptions.InfinitePropellant && r == 0) { IResourceBroker broker = new ResourceBroker(); if (broker.AmountAvailable(vessel.rootPart, iList[r].ResourceName, 1, ResourceFlowMode.ALL_VESSEL) == 0) { break; } } var ir = fuelCells.InputResources.Find(x => x.Name == iList[r].ResourceName); if (ir == null) { ir = new Resource(); ir.Name = iList[r].ResourceName; fuelCells.InputResources.Add(ir); } ir.Ratio += iList[r].Ratio; // Add EC ration to output if (r == 0) { fuelCells.OutputValue += ecRatio; } } } } } electricPower_Other += fuelCells.OutputValue; // Cheats if (CheatOptions.InfiniteElectricity) { electricPower_Other = requiredPower; } // Manned manned = (vessel.GetCrewCount() > 0); // Pilots and Scouts (USI) increase base average speed crewSpeedBonus = 0; if (manned) { int maxPilotLevel = -1; int maxScoutLevel = -1; int maxDriverLevel = -1; List <ProtoCrewMember> crewList = vessel.GetVesselCrew(); for (int i = 0; i < crewList.Count; i++) { switch (crewList[i].trait) { case "Pilot": if (maxPilotLevel < crewList[i].experienceLevel) { maxPilotLevel = crewList[i].experienceLevel; } break; case "Scout": if (maxScoutLevel < crewList[i].experienceLevel) { maxScoutLevel = crewList[i].experienceLevel; } break; default: if (crewList[i].HasEffect("AutopilotSkill")) { if (maxDriverLevel < crewList[i].experienceLevel) { maxDriverLevel = crewList[i].experienceLevel; } } break; } } if (maxPilotLevel > 0) { crewSpeedBonus = 6 * maxPilotLevel; // up to 30% for a Pilot } else if (maxDriverLevel > 0) { crewSpeedBonus = 4 * maxDriverLevel; // up to 20% for any driver (has AutopilotSkill skill) } else if (maxScoutLevel > 0) { crewSpeedBonus = 2 * maxScoutLevel; // up to 10% for a Scout (Scouts disregard safety) } } // Average speed will vary depending on number of wheels online and crew present from 50 to 95 percent of average wheels' max speed if (wheelTestResult.online != 0) { maxSpeedBase = wheelTestResult.maxSpeedSum / wheelTestResult.online; wheelsPercentualModifier = Math.Min(70, (40 + 5 * wheelTestResult.online)); averageSpeed = maxSpeedBase * Convert.ToDouble(wheelsPercentualModifier) / 100 * (1 + Convert.ToDouble(crewSpeedBonus) / 100); } else { averageSpeed = 0; } // Unmanned rovers drive with the speed penalty based on available tech if (!manned) { averageSpeed = averageSpeed * (100 - Convert.ToDouble(GetUnmannedSpeedPenalty())) / 100; } // Base average speed at night is the same as average speed, if there is other power source. Zero otherwise. if (electricPower_Other > 0.0) { averageSpeedAtNight = averageSpeed; } else { averageSpeedAtNight = 0; } // If required power is greater then total power generated, then average speed can be lowered up to 75% if (requiredPower > (electricPower_Solar + electricPower_Other)) { double speedReduction = (requiredPower - (electricPower_Solar + electricPower_Other)) / requiredPower; if (speedReduction <= 0.75) { averageSpeed = averageSpeed * (1 - speedReduction); } } // If required power is greater then other power generated, then average speed at night can be lowered up to 75% if (requiredPower > electricPower_Other) { double speedReduction = (requiredPower - electricPower_Other) / requiredPower; if (speedReduction <= 0.75) { averageSpeedAtNight = averageSpeedAtNight * (1 - speedReduction); } else { averageSpeedAtNight = 0; } } // If we are using batteries, compute for how long and how much EC we can use if (batteries.UseBatteries) { batteries.MaxUsedEC = 0; batteries.ECPerSecondConsumed = 0; batteries.ECPerSecondGenerated = 0; // We have enough of solar power to recharge batteries if (requiredPower < (electricPower_Solar + electricPower_Other)) { batteries.ECPerSecondConsumed = Math.Max(requiredPower - electricPower_Other, 0); // If there is more other power than required power, we don't need batteries batteries.MaxUsedEC = batteries.MaxAvailableEC / 2; // We are using only half of max available EC if (batteries.ECPerSecondConsumed > 0) { double halfday = vessel.mainBody.rotationPeriod / 2; // in seconds batteries.ECPerSecondGenerated = electricPower_Solar + electricPower_Other - requiredPower; batteries.MaxUsedEC = Math.Min(batteries.MaxUsedEC, batteries.ECPerSecondConsumed * halfday); // get lesser value of MaxUsedEC and EC consumed per night batteries.MaxUsedEC = Math.Min(batteries.MaxUsedEC, batteries.ECPerSecondGenerated * halfday); // get lesser value of MaxUsedEC and max EC available for recharge during a day } } if (batteries.MaxUsedEC > 0) { batteries.CurrentEC = batteries.MaxUsedEC; // We are starting at full available capacity } else { UseBatteriesChanged(false); ScreenMessages.PostScreenMessage(Localizer.Format("#LOC_BV_Warning_CantUseBatteries") + " " + Localizer.Format("#LOC_BV_Warning_LowPowerRover") + ".", 5f).color = Color.yellow; } } }
private bool HasFuel() { var res = Fuels[CurrentFuelIndex]; return(broker.AmountAvailable(part, res.name, 1, "") > 1); }