예제 #1
0
        /// <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());
        }
예제 #2
0
        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));
            }
        }
예제 #3
0
        /// <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;
                }
            }
        }
예제 #4
0
        private bool HasFuel()
        {
            var res = Fuels[CurrentFuelIndex];

            return(broker.AmountAvailable(part, res.name, 1, "") > 1);
        }