override public void afterOnFixedUpdate()
 {
     if (!this.isExecuted() && this.isStarted() && startTime == 0f)
     {
         startTime = Time.time;
     }
     if (!this.isExecuted() && this.isStarted() && startTime > 0)
     {
         spendTime = initTime - (int)(Math.Round(Time.time - startTime));
         if (spendTime <= 0)
         {
             if (!this.saved)
             {
                 //Wait 5s before save so FlightsGlobals are clear to save
                 this.scriptModule.setActiveSavepoint(this.actionIndex);
                 if (FlightGlobals.ClearToSave() == ClearToSaveStatus.CLEAR)
                 {
                     QuickSaveLoad.QuickSave();
                 }
                 this.saved = true;
                 startTime  = Time.time;
             }
             else
             {
                 //Then wait 5s after save to let the time to save
                 this.endAction();
             }
         }
     }
 }
Example #2
0
        public bool isSwitchAllowed(Vessel target)
        {
            if (FlightGlobals.ActiveVessel == target)
            {
                errorMsg = "This is the active vessel.";
                return(false);
            }
            if (MapView.MapIsEnabled)
            {
                errorMsg = "Can't switch while in map.";
                return(false);
            }
            if (InputLockManager.IsLocked(ControlTypes.VESSEL_SWITCHING))
            {
                errorMsg = "Switching is disabled.";
                return(false);
            }

            if (target.packed && FlightGlobals.ClearToSave() != ClearToSaveStatus.CLEAR)
            {
                errorMsg = "Game states forbids switching.";
                return(false);
            }

            errorMsg = null;
            return(true);
        }
        public void StopSpectating()
        {
            VesselCommon.IsSpectating = false;

            //Unlock all vessel controls
            InputLockManager.RemoveControlLock(SpectateLock);

            if (LockSystem.LockQuery.SpectatorLockExists(SettingsSystem.CurrentSettings.PlayerName))
            {
                LockSystem.Singleton.ReleaseSpectatorLock();
            }

            //We are not spectating anymore so try to get as many unloaded update locks as possible
            foreach (var vessel in FlightGlobals.Vessels)
            {
                if (!LockSystem.LockQuery.UnloadedUpdateLockExists(vessel.id))
                {
                    LockSystem.Singleton.AcquireUnloadedUpdateLock(vessel.id);
                }
            }

            if (HighLogic.CurrentGame?.Parameters?.Flight != null)
            {
                HighLogic.CurrentGame.Parameters.Flight.CanEVA = true;
            }

            if (PauseMenu.exists && PauseMenu.isOpen)
            {
                PauseMenu.canSaveAndExit = FlightGlobals.ClearToSave();
            }

            SpectateEvent.onFinishedSpectating.Fire();
        }
Example #4
0
 public BooleanValue CanQuicksave()
 {
     if (HighLogic.CurrentGame.Parameters.Flight.CanQuickSave && FlightGlobals.ClearToSave() == ClearToSaveStatus.CLEAR)
     {
         return(true);
     }
     return(false);
 }
Example #5
0
        bool can_restore()
        {
            //if hangar is not ready, return
            if (hangar_state == HangarState.Inactive)
            {
                ScreenMessager.showMessage("Activate the hangar first", 3);
                return(false);
            }
            if (hangar_gates.State != AnimatorState.Opened)
            {
                ScreenMessager.showMessage("Open hangar gates first", 3);
                return(false);
            }
            //if something is docked to the hangar docking port (if its present)
            ModuleDockingNode dport = part.Modules.OfType <ModuleDockingNode>().SingleOrDefault();

            if (dport != null && dport.vesselInfo != null)
            {
                ScreenMessager.showMessage("Cannot launch a vessel while another is docked", 3);
                return(false);
            }
            //if in orbit or on the ground and not moving
            switch (FlightGlobals.ClearToSave())
            {
            case ClearToSaveStatus.NOT_IN_ATMOSPHERE:
            {
                ScreenMessager.showMessage("Cannot launch a vessel while flying in atmosphere", 3);
                return(false);
            }

            case ClearToSaveStatus.NOT_UNDER_ACCELERATION:
            {
                ScreenMessager.showMessage("Cannot launch a vessel hangar is under accelleration", 3);
                return(false);
            }

            case ClearToSaveStatus.NOT_WHILE_ABOUT_TO_CRASH:
            {
                ScreenMessager.showMessage("Cannot launch a vessel while about to crush", 3);
                return(false);
            }

            case ClearToSaveStatus.NOT_WHILE_MOVING_OVER_SURFACE:
            {
                ScreenMessager.showMessage("Cannot launch a vessel while moving over the surface", 3);
                return(false);
            }
            }
            if (vessel.angularVelocity.magnitude > 0.003)
            {
                ScreenMessager.showMessage("Cannot launch a vessel while rotating", 3);
                return(false);
            }
            return(true);
        }
Example #6
0
        IEnumerator tryExit()
        {
            if (needToSavegame)
            {
                if (CanSavegame)
                {
                    if (GamePersistence.SaveGame("persistent", HighLogic.SaveFolder, SaveMode.OVERWRITE) != string.Empty)
                    {
                        saveDone = true;
                        ScreenMessages.PostScreenMessage(Localizer.Format("quickexit_gameSaved", RegisterToolbar.MOD), 5);
                        Log("Game saved.", "QExit");
                    }
                    else
                    {
                        count = 10;
                        Log("Can't save game.", "QExit");
                        ScreenMessages.PostScreenMessage(Localizer.Format("quickexit_cantSave", RegisterToolbar.MOD), 10);
                    }
                    if (HighLogic.LoadedSceneIsEditor)
                    {
                        List <Part> parts = EditorLogic.fetch.ship != null ? EditorLogic.fetch.ship.Parts : new List <Part>();

                        if (parts.Count > 0)
                        {
                            ShipConstruction.SaveShip(shipFilename);
                            Log("Ship saved.", "QExit");
                            ScreenMessages.PostScreenMessage(Localizer.Format("quickexit_shipSaved", RegisterToolbar.MOD), 5);
                        }
                    }
                }
                else
                {
                    count = 10;
                    ClearToSaveStatus clearToSaveStatus = FlightGlobals.ClearToSave();
                    string            _status           = FlightGlobals.GetNotClearToSaveStatusReason(clearToSaveStatus, string.Empty);
                    Log("Can't game saved: " + _status, "QExit");
                    ScreenMessages.PostScreenMessage(Localizer.Format("quickexit_cantSave", RegisterToolbar.MOD) + ": " + _status, 10);
                }
            }
            while (count >= 0)
            {
                yield return(new WaitForSecondsRealtime(1f));

                Log("Exit in " + count, "QExit");
                count--;
            }
            if (!IsTryExit)
            {
                Log("tryExit stopped", "QExit");
                yield break;
            }
            Application.Quit();
            Log("tryExit ended", "QExit");
        }
Example #7
0
 private void SaveGame(string name)
 {
     if (HighLogic.CurrentGame.Parameters.Flight.CanQuickSave && FlightGlobals.ClearToSave() == ClearToSaveStatus.CLEAR)
     {
         var game = HighLogic.CurrentGame.Updated();
         game.startScene = GameScenes.FLIGHT;
         GamePersistence.SaveGame(game, name, HighLogic.SaveFolder, SaveMode.OVERWRITE);
         game.startScene = GameScenes.SPACECENTER;
     }
     else
     {
         throw new KOSException("KSP prevents using quicksave currently.");
     }
 }
Example #8
0
        IEnumerator tryExit()
        {
            if (needToSavegame)
            {
                if (CanSavegame)
                {
                    if (GamePersistence.SaveGame("persistent", HighLogic.SaveFolder, SaveMode.OVERWRITE) != string.Empty)
                    {
                        saveDone = true;
                        ScreenMessages.PostScreenMessage(string.Format("[{0}] Game saved.", MOD), 5);
                        Log("Game saved.", "QExit");
                    }
                    else
                    {
                        count = 10;
                        Log("Can't save game.", "QExit");
                        ScreenMessages.PostScreenMessage(string.Format("[{0}] Can't save game.", MOD), 10);
                    }
                    if (HighLogic.LoadedSceneIsEditor)
                    {
                        ShipConstruction.SaveShip(shipFilename);
                        Log("Ship saved.", "QExit");
                        ScreenMessages.PostScreenMessage(string.Format("[{0}] Ship saved.", MOD), 5);
                    }
                }
                else
                {
                    count = 10;
                    ClearToSaveStatus clearToSaveStatus = FlightGlobals.ClearToSave();
                    string            _status           = FlightGlobals.GetNotClearToSaveStatusReason(clearToSaveStatus, string.Empty);
                    Log("Can't game saved: " + _status, "QExit");
                    ScreenMessages.PostScreenMessage(string.Format("[{0}] Can't save game: {1}", MOD, _status.ToString()), 10);
                }
            }
            while (count >= 0)
            {
                yield return(new WaitForSecondsRealtime(1f));

                Log("Exit in " + count, "QExit");
                count--;
            }
            if (!IsTryExit)
            {
                Log("tryExit stopped", "QExit");
                yield break;
            }
            Application.Quit();
            Log("tryExit ended", "QExit");
        }
Example #9
0
        IEnumerator tryExit()
        {
            Log.Info("tryExit");

            if (CanSavegame)
            {
                if (GamePersistence.SaveGame("persistent", HighLogic.SaveFolder, SaveMode.OVERWRITE) != string.Empty)
                {
                    //saveDone = true;
                    ScreenMessages.PostScreenMessage(Localizer.Format("pm_gameSaved", MOD), 5);
                    MyLog("Game saved.", "QExit");
                }
                else
                {
                    count = 10;
                    MyLog("Can't save game.", "QExit");
                    ScreenMessages.PostScreenMessage(Localizer.Format("pm_cantSave", MOD), 10);
                }
            }
            else
            {
                count = 10;
                ClearToSaveStatus clearToSaveStatus = FlightGlobals.ClearToSave();
                string            _status           = FlightGlobals.GetNotClearToSaveStatusReason(clearToSaveStatus, string.Empty);
                MyLog("Can't game saved: " + _status, "QExit");
                ScreenMessages.PostScreenMessage(Localizer.Format("pm_cantSave", MOD) + ": " + _status, 10);
            }

            while (count >= 0)
            {
                yield return(new WaitForSecondsRealtime(1f));

                MyLog("Exit in " + count, "QExit");
                count--;
            }
            Log.Info("tryExit, ready to exit");
            if (!IsTryExit)
            {
                MyLog("tryExit stopped", "QExit");
                yield break;
            }
            Log.Info("tryExit, before ApplicationQuit");
            Application.Quit();
            MyLog("tryExit ended", "QExit");
        }
Example #10
0
        private void StartSimulation()
        {
            if (FlightDriver.PreLaunchState == null)
            {
                GameEvents.onGameAboutToQuicksave.Fire();
                Game game = HighLogic.CurrentGame.Updated();
                game.startScene = GameScenes.FLIGHT;
                GamePersistence.SaveGame(game, "simulation", HighLogic.SaveFolder, SaveMode.BACKUP);
                if (FlightGlobals.ClearToSave() == ClearToSaveStatus.CLEAR)
                {
                    GamePersistence.SaveGame(game, "persistent", HighLogic.SaveFolder, SaveMode.OVERWRITE);
                    Debug.Log($"[QuickIronMan]({name}) It's clear, I save your game");
                }
                Debug.Log($"[QuickIronMan]({name}) Backup simulation");
            }

            sim.SetSimulation(true);
        }
Example #11
0
        /// <summary>
        /// Checks if a vessel can be stored in the hangar right now.
        /// </summary>
        /// <param name="vsl">A vessel to check</param>
        bool can_store(Vessel vsl)
        {
            if (vsl == null || vsl == vessel || !vsl.enabled || vsl.isEVA)
            {
                return(false);
            }
            //if hangar is not ready, return
            if (hangar_state == HangarState.Inactive)
            {
                ScreenMessager.showMessage("Activate the hangar first", 3);
                return(false);
            }
            //check self state first
            switch (FlightGlobals.ClearToSave())
            {
            case ClearToSaveStatus.NOT_WHILE_ABOUT_TO_CRASH:
            {
                ScreenMessager.showMessage("Cannot accept the vessel while about to crush", 3);
                return(false);
            }
            }
            //always check relative velocity and acceleration
            Vector3 rv = vessel.GetObtVelocity() - vsl.GetObtVelocity();

            if (rv.magnitude > 1f)
            {
                ScreenMessager.showMessage("Cannot accept a vessel with a relative speed higher than 1m/s", 3);
                return(false);
            }
            Vector3 ra = vessel.acceleration - vsl.acceleration;

            if (ra.magnitude > 0.1)
            {
                ScreenMessager.showMessage("Cannot accept an accelerating vessel", 3);
                return(false);
            }
            return(true);
        }
        public override void Drive(FlightCtrlState s) // TODO put the brake in when running out of power to prevent nighttime solar failures on hills, or atleast try to
        {                                             // TODO make distance calculation for 'reached' determination consider the rover and waypoint on sealevel to prevent height differences from messing it up -- should be done now?
            if (orbit.referenceBody != lastBody)
            {
                WaypointIndex = -1; Waypoints.Clear();
            }
            MechJebWaypoint wp = (WaypointIndex > -1 && WaypointIndex < Waypoints.Count ? Waypoints[WaypointIndex] : null);

            var brake = vessel.ActionGroups[KSPActionGroup.Brakes];             // keep brakes locked if they are

            curSpeed = Vector3d.Dot(vessel.srf_velocity, vesselState.forward);

            CalculateTraction();
            speedIntAcc = speedPID.intAccum;

            if (wp != null && wp.Body == orbit.referenceBody)
            {
                if (ControlHeading)
                {
                    heading = Math.Round(HeadingToPos(vessel.CoM, wp.Position), 1);
                }
                if (ControlSpeed)
                {
                    var nextWP   = (WaypointIndex < Waypoints.Count - 1 ? Waypoints[WaypointIndex + 1] : (LoopWaypoints ? Waypoints[0] : null));
                    var distance = Vector3.Distance(vessel.CoM, wp.Position);
                    if (wp.Target != null)
                    {
                        distance += (float)(wp.Target.srfSpeed * curSpeed) / 2;
                    }
                    //var maxSpeed = (wp.MaxSpeed > 0 ? Math.Min((float)speed, wp.MaxSpeed) : speed); // use waypoints maxSpeed if set and smaller than set the speed or just stick with the set speed
                    var maxSpeed = (wp.MaxSpeed > 0 ? wp.MaxSpeed : speed);                     // speed used to go towards the waypoint, using the waypoints maxSpeed if set or just stick with the set speed
                    var minSpeed = (wp.MinSpeed > 0 ? wp.MinSpeed :
                                    (nextWP != null ? TurningSpeed((nextWP.MaxSpeed > 0 ? nextWP.MaxSpeed : speed), heading - HeadingToPos(wp.Position, nextWP.Position)) :
                                     (distance - wp.Radius > 50 ? turnSpeed.val : 1)));
                    minSpeed = (wp.Quicksave ? 1 : minSpeed);
                    // ^ speed used to go through the waypoint, using half the set speed or maxSpeed as minSpeed for routing waypoints (all except the last)
                    var brakeFactor = Math.Max((curSpeed - minSpeed) * 1, 3);
                    var newSpeed    = Math.Min(maxSpeed, Math.Max((distance - wp.Radius) / brakeFactor, minSpeed));        // brake when getting closer
                    newSpeed = (newSpeed > turnSpeed ? TurningSpeed(newSpeed, headingErr) : newSpeed);                     // reduce speed when turning a lot
                    if (LimitAcceleration)
                    {
                        newSpeed = curSpeed + Mathf.Clamp((float)(newSpeed - curSpeed), -1.5f, 0.5f);
                    }
//					newSpeed = tgtSpeed + Mathf.Clamp((float)(newSpeed - tgtSpeed), -Time.deltaTime * 8f, Time.deltaTime * 2f);
                    var radius = Math.Max(wp.Radius, 10);
                    if (distance < radius)
                    {
                        if (WaypointIndex + 1 >= Waypoints.Count)                         // last waypoint
                        {
                            newSpeed = new [] { newSpeed, (distance < radius * 0.8 ? 0 : 1) }.Min();
                            // ^ limit speed so it'll only go from 1m/s to full stop when braking to prevent accidents on moons
                            if (LoopWaypoints)
                            {
                                WaypointIndex = 0;
                            }
                            else
                            {
                                newSpeed = 0;
//								tgtSpeed.force(newSpeed);
                                if (curSpeed < brakeSpeedLimit)
                                {
                                    if (wp.Quicksave)
                                    {
                                        //if (s.mainThrottle > 0) { s.mainThrottle = 0; }
                                        if (FlightGlobals.ClearToSave() == ClearToSaveStatus.CLEAR)
                                        {
                                            WaypointIndex  = -1;
                                            ControlHeading = ControlSpeed = false;
                                            QuickSaveLoad.QuickSave();
                                        }
                                    }
                                    else
                                    {
                                        WaypointIndex  = -1;
                                        ControlHeading = ControlSpeed = false;
                                    }
                                }
//								else {
//									Debug.Log("Is this even getting called?");
//									WaypointIndex++;
//								}
                            }
                        }
                        else
                        {
                            if (wp.Quicksave)
                            {
                                //if (s.mainThrottle > 0) { s.mainThrottle = 0; }
                                newSpeed = 0;
//								tgtSpeed.force(newSpeed);
                                if (curSpeed < brakeSpeedLimit)
                                {
                                    if (FlightGlobals.ClearToSave() == ClearToSaveStatus.CLEAR)
                                    {
                                        WaypointIndex++;
                                        QuickSaveLoad.QuickSave();
                                    }
                                }
                            }
                            else
                            {
                                WaypointIndex++;
                            }
                        }
                    }
                    brake = brake || ((s.wheelThrottle == 0 || !vessel.isActiveVessel) && curSpeed < brakeSpeedLimit && newSpeed < brakeSpeedLimit);
                    // ^ brake if needed to prevent rolling, hopefully
                    tgtSpeed = (newSpeed >= 0 ? newSpeed : 0);
                }
            }

            if (ControlHeading)
            {
                headingPID.intAccum = Mathf.Clamp((float)headingPID.intAccum, -1, 1);

                double instantaneousHeading = vesselState.rotationVesselSurface.eulerAngles.y;
                headingErr = MuUtils.ClampDegrees180(instantaneousHeading - heading);
                if (s.wheelSteer == s.wheelSteerTrim || FlightGlobals.ActiveVessel != vessel)
                {
                    float  spd   = Mathf.Min((float)speed, (float)turnSpeed);                  // if a slower speed than the turnspeed is used also be more careful with the steering
                    float  limit = (Mathf.Abs((float)curSpeed) <= turnSpeed ? 1 : Mathf.Clamp((float)(spd / Mathf.Abs((float)curSpeed)), 0.35f, 1f));
                    double act   = headingPID.Compute(headingErr);
                    s.wheelSteer = Mathf.Clamp((float)act, -limit, limit);
                }
            }

            // Brake if there is no controler (Pilot eject from seat)
            if (BrakeOnEject && vessel.GetReferenceTransformPart() == null)
            {
                s.wheelThrottle = 0;
//				vessel.ActionGroups.SetGroup(KSPActionGroup.Brakes, true);
                brake = true;
            }
            else if (ControlSpeed)
            {
                speedPID.intAccum = Mathf.Clamp((float)speedPID.intAccum, -5, 5);

                speedErr = (WaypointIndex == -1 ? speed.val : tgtSpeed) - Vector3d.Dot(vessel.srf_velocity, vesselState.forward);
                if (s.wheelThrottle == s.wheelThrottleTrim || FlightGlobals.ActiveVessel != vessel)
                {
                    float act = (float)speedPID.Compute(speedErr);
                    s.wheelThrottle = !LimitAcceleration?Mathf.Clamp((float)act, -1, 1) :                       // I think I'm using these ( ? : ) a bit too much
                                          (traction == 0 ? 0 : (act < 0 ? Mathf.Clamp(act, -1f, 1f) : (lastThrottle + Mathf.Clamp(act - lastThrottle, -0.005f, 0.005f)) * (traction < tractionLimit ? -1 : 1)));

                    if (curSpeed < 0 & s.wheelThrottle < 0)
                    {
                        s.wheelThrottle = 0;
                    }                                                                                                        // don't go backwards
//					if (Mathf.Sign(act) + Mathf.Sign(s.wheelThrottle) == 0) { s.wheelThrottle = Mathf.Clamp(act, -1f, 1f); }
                    if (speedErr < -1 && StabilityControl && Mathf.Sign(s.wheelThrottle) + Mathf.Sign((float)curSpeed) == 0) // StabilityControl && traction > 50 &&
//						vessel.ActionGroups.SetGroup(KSPActionGroup.Brakes, true);
                    {
                        brake = true;
                    }
//					else if (!stabilityControl || traction <= 50 || speedErr > -0.2 || Mathf.Sign(s.wheelThrottle) + Mathf.Sign((float)curSpeed) != 0) {
//						vessel.ActionGroups.SetGroup(KSPActionGroup.Brakes, (GameSettings.BRAKES.GetKey() && vessel.isActiveVessel));
//					}
                    lastThrottle = s.wheelThrottle;
                }
            }

            if (StabilityControl)
            {
                if (!core.attitude.users.Contains(this))
                {
                    core.attitude.users.Add(this);
//					line.enabled = true;
                }
//				float scale = Vector3.Distance(FlightCamera.fetch.mainCamera.transform.position, vessel.CoM) / 900f;
//				line.SetPosition(0, vessel.CoM);
//				line.SetPosition(1, vessel.CoM + hit.normal * 5);
//				line.SetWidth(0, scale + 0.1f);
                var fSpeed = (float)curSpeed;
//				if (Mathf.Abs(fSpeed) >= turnSpeed * 0.75) {
                Vector3 fwd = (Vector3)(traction > 0 ?                 // V when the speed is low go for the vessels forward, else with a bit of velocity
//				                        ((Mathf.Abs(fSpeed) <= turnSpeed ? vesselState.forward : vessel.srf_velocity / 4) - vessel.transform.right * s.wheelSteer) * Mathf.Sign(fSpeed) :
//				                        // ^ and then add the steering
                                        vesselState.forward * 4 - vessel.transform.right * s.wheelSteer * Mathf.Sign(fSpeed) : // and then add the steering
                                        vessel.srf_velocity);                                                                  // in the air so follow velocity
                Vector3.OrthoNormalize(ref norm, ref fwd);
                var quat = Quaternion.LookRotation(fwd, norm);

//				if (traction > 0 || speed <= turnSpeed) {
//					var u = new Vector3(0, 1, 0);
//
//					var q = FlightGlobals.ship_rotation;
//					var q_s = quat;
//
//					var q_u = new Quaternion(u.x, u.y, u.z, 0);
//					var a = Quaternion.Dot(q, q_s * q_u);
//					var q_qs = Quaternion.Dot(q, q_s);
//					var b = (a == 0) ? Math.Sign(q_qs) : (q_qs / a);
//					var g = b / Mathf.Sqrt((b * b) + 1);
//					var gu = Mathf.Sqrt(1 - (g * g)) * u;
//					var q_d = new Quaternion() { w = g, x = gu.x, y = gu.y, z = gu.z };
//					var n = q_s * q_d;
//
//					quat = n;
//				}

                core.attitude.attitudeTo(quat, AttitudeReference.INERTIAL, this);
//				}
            }

            if (BrakeOnEnergyDepletion)
            {
                var batteries  = vessel.Parts.FindAll(p => p.Resources.Contains("ElectricCharge") && p.Resources["ElectricCharge"].flowState);
                var energyLeft = batteries.Sum(p => p.Resources["ElectricCharge"].amount) / batteries.Sum(p => p.Resources["ElectricCharge"].maxAmount);
                var openSolars = vessel.mainBody.atmosphere &&                 // true if in atmosphere and there are breakable solarpanels that aren't broken nor retracted
                                 vessel.FindPartModulesImplementing <ModuleDeployableSolarPanel>().FindAll(p => p.isBreakable && p.panelState != ModuleDeployableSolarPanel.panelStates.BROKEN &&
                                                                                                           p.panelState != ModuleDeployableSolarPanel.panelStates.RETRACTED).Count > 0;

                if (openSolars && energyLeft > 0.99)
                {
                    vessel.FindPartModulesImplementing <ModuleDeployableSolarPanel>().FindAll(p => p.isBreakable &&
                                                                                              p.panelState == ModuleDeployableSolarPanel.panelStates.EXTENDED).ForEach(p => p.Retract());
                }

                if (energyLeft < 0.05 && Mathf.Sign(s.wheelThrottle) + Mathf.Sign((float)curSpeed) != 0)
                {
                    s.wheelThrottle = 0;
                }                                                                                                                                 // save remaining energy by not using it for acceleration
                if (openSolars || energyLeft < 0.03)
                {
                    tgtSpeed = 0;
                }

                if (curSpeed < brakeSpeedLimit && (energyLeft < 0.05 || openSolars))
                {
                    brake = true;
                }

                if (curSpeed < 0.1 && energyLeft < 0.05 && !waitingForDaylight &&
                    vessel.FindPartModulesImplementing <ModuleDeployableSolarPanel>().FindAll(p => p.panelState == ModuleDeployableSolarPanel.panelStates.EXTENDED).Count > 0)
                {
                    waitingForDaylight = true;
                }
            }

//			brake = brake && (s.wheelThrottle == 0); // release brake if the user or AP want to drive
            if (s.wheelThrottle != 0 && Mathf.Sign(s.wheelThrottle) + Mathf.Sign((float)curSpeed) != 0)
            {
                brake = false;                 // the AP or user want to drive into the direction of momentum so release the brake
            }

            if (vessel.isActiveVessel)
            {
                if (GameSettings.BRAKES.GetKeyUp())
                {
                    brake = false;                     // release the brakes if the user lets go of them
                }
                if (GameSettings.BRAKES.GetKey())
                {
                    brake = true;                     // brake if the user brakes and we aren't about to flip
                }
            }

            tractionLimit = (double)Mathf.Clamp((float)tractionLimit, 0, 100);
            vessel.ActionGroups.SetGroup(KSPActionGroup.Brakes, brake && (StabilityControl && curSpeed > brakeSpeedLimit ? traction >= tractionLimit : true));
            // ^ brake but hopefully prevent flipping over, assuming the user set up the limit right
            if (brake && curSpeed < 0.1)
            {
                s.wheelThrottle = 0;
            }
        }
Example #13
0
        private void Update()
        {
            //destroy the old one
            VesselSwitching vesselSwitching = UnityEngine.Object.FindObjectOfType <VesselSwitching> ();

            if (vesselSwitching != null)
            {
                Destroy(vesselSwitching);
                Utils.Log("vesselSwitching destroyed.");
            }

            if (!MapView.MapIsEnabled)
            {
                if (!InputLockManager.IsLocked(ControlTypes.VESSEL_SWITCHING))
                {
                    if (!FlightDriver.Pause)
                    {
                        currentIndex = -1;
                        if (GameSettings.FOCUS_PREV_VESSEL.GetKeyDown())
                        {
                            if (HighLogic.CurrentGame != null && !HighLogic.CurrentGame.Parameters.Flight.CanSwitchVesselsNear)
                            {
                                PostMessage("Cannot switch vessels because it is disabled");
                                return;
                            }
                            if (HighLogic.LoadedSceneIsFlight)
                            {
                                CameraManager.Instance.SetCameraFlight();
                            }
                            this.vesselList.Clear();
                            currentIndex = FlightGlobals.Vessels.IndexOf(FlightGlobals.ActiveVessel);
                            do
                            {
                                currentIndex--;
                                if (currentIndex < 0)
                                {
                                    currentIndex += FlightGlobals.Vessels.Count;
                                }

                                currentVessel = FlightGlobals.Vessels [currentIndex];
                                if (currentVessel.loaded && currentVessel != FlightGlobals.ActiveVessel)
                                {
                                    //only allow switching to non-creature vessels
                                    if (!(currentVessel.rootPart is CreaturePart))
                                    {
                                        this.vesselList.Add(currentVessel);
                                    }
                                }
                            }while(currentVessel != FlightGlobals.ActiveVessel);
                        }
                        if (GameSettings.FOCUS_NEXT_VESSEL.GetKeyDown())
                        {
                            if (HighLogic.CurrentGame != null && !HighLogic.CurrentGame.Parameters.Flight.CanSwitchVesselsNear)
                            {
                                PostMessage("Cannot switch vessels because it is disabled");
                                return;
                            }
                            if (HighLogic.LoadedSceneIsFlight)
                            {
                                CameraManager.Instance.SetCameraFlight();
                            }
                            this.vesselList.Clear();
                            currentIndex = FlightGlobals.Vessels.IndexOf(FlightGlobals.ActiveVessel);
                            do
                            {
                                currentIndex++;
                                if (currentIndex >= FlightGlobals.Vessels.Count)
                                {
                                    currentIndex = 0;
                                }

                                currentVessel = FlightGlobals.Vessels [currentIndex];
                                if (currentVessel.loaded && currentVessel != FlightGlobals.ActiveVessel)
                                {
                                    //only allow switching to non-creature vessels
                                    if (!(currentVessel.rootPart is CreaturePart))
                                    {
                                        this.vesselList.Add(currentVessel);
                                    }
                                }
                            }while(currentVessel != FlightGlobals.ActiveVessel);
                        }
                        if (currentIndex != -1)
                        {
                            if (vesselList.Count <= 0)
                            {
                                PostMessage("No nearby objects to focus. Use the Map View to select distant ones.");
                            }
                            else
                            {
                                ClearToSaveStatus status = FlightGlobals.ClearToSave();
                                foreach (var vessel in vesselList)
                                {
                                    if (vessel.packed)
                                    {
                                        if (status != ClearToSaveStatus.CLEAR)
                                        {
                                            continue;
                                        }
                                    }
                                    FlightGlobals.ForceSetActiveVessel(vessel);
                                    FlightInputHandler.ResumeVesselCtrlState(vessel);
                                    return;
                                }
                            }
                        }
                    }
                }
            }
        }
        public override void Drive(FlightCtrlState s) // TODO put the brake in when running out of power to prevent nighttime solar failures on hills, or atleast try to
        {                                             // TODO make distance calculation for 'reached' determination consider the rover and waypoint on sealevel to prevent height differences from messing it up -- should be done now?
            if (orbit.referenceBody != lastBody)
            {
                WaypointIndex = -1; Waypoints.Clear();
            }
            MechJebWaypoint wp = (WaypointIndex > -1 && WaypointIndex < Waypoints.Count ? Waypoints[WaypointIndex] : null);

            var brake = vessel.ActionGroups[KSPActionGroup.Brakes];             // keep brakes locked if they are

            curSpeed = Vector3d.Dot(vesselState.surfaceVelocity, vesselState.forward);

            CalculateTraction();
            speedIntAcc = speedPID.intAccum;

            if (wp != null && wp.Body == orbit.referenceBody)
            {
                if (ControlHeading)
                {
                    heading.val = Math.Round(HeadingToPos(vessel.CoM, wp.Position), 1);
                }
                if (ControlSpeed)
                {
                    var nextWP   = (WaypointIndex < Waypoints.Count - 1 ? Waypoints[WaypointIndex + 1] : (LoopWaypoints ? Waypoints[0] : null));
                    var distance = Vector3.Distance(vessel.CoM, wp.Position);
                    if (wp.Target != null)
                    {
                        distance += (float)(wp.Target.srfSpeed * curSpeed) / 2;
                    }
                    // var maxSpeed = (wp.MaxSpeed > 0 ? Math.Min((float)speed, wp.MaxSpeed) : speed); // use waypoints maxSpeed if set and smaller than set the speed or just stick with the set speed
                    var maxSpeed = (wp.MaxSpeed > 0 ? wp.MaxSpeed : speed);                     // speed used to go towards the waypoint, using the waypoints maxSpeed if set or just stick with the set speed
                    var minSpeed = (wp.MinSpeed > 0 ? wp.MinSpeed :
                                    (nextWP != null ? TurningSpeed((nextWP.MaxSpeed > 0 ? nextWP.MaxSpeed : speed), heading - HeadingToPos(wp.Position, nextWP.Position)) :
                                     (distance - wp.Radius > 50 ? turnSpeed.val : 1)));
                    minSpeed = (wp.Quicksave ? 1 : minSpeed);
                    // ^ speed used to go through the waypoint, using half the set speed or maxSpeed as minSpeed for routing waypoints (all except the last)
                    var newSpeed = Math.Min(maxSpeed, Math.Max((distance - wp.Radius) / curSpeed, minSpeed));              // brake when getting closer
                    newSpeed = (newSpeed > turnSpeed ? TurningSpeed(newSpeed, headingErr) : newSpeed);                     // reduce speed when turning a lot
                    var radius = Math.Max(wp.Radius, 10);
                    if (distance < radius)
                    {
                        if (WaypointIndex + 1 >= Waypoints.Count)                         // last waypoint
                        {
                            newSpeed = new [] { newSpeed, (distance < radius * 0.8 ? 0 : 1) }.Min();
                            // ^ limit speed so it'll only go from 1m/s to full stop when braking to prevent accidents on moons
                            if (LoopWaypoints)
                            {
                                WaypointIndex = 0;
                            }
                            else
                            {
                                newSpeed = 0;
                                brake    = true;
                                if (curSpeed < brakeSpeedLimit)
                                {
                                    if (wp.Quicksave)
                                    {
                                        if (FlightGlobals.ClearToSave() == ClearToSaveStatus.CLEAR)
                                        {
                                            WaypointIndex  = -1;
                                            ControlHeading = ControlSpeed = false;
                                            QuickSaveLoad.QuickSave();
                                        }
                                    }
                                    else
                                    {
                                        WaypointIndex  = -1;
                                        ControlHeading = ControlSpeed = false;
                                    }
                                }
                            }
                        }
                        else
                        {
                            if (wp.Quicksave)
                            {
                                newSpeed = 0;
                                if (curSpeed < brakeSpeedLimit)
                                {
                                    if (FlightGlobals.ClearToSave() == ClearToSaveStatus.CLEAR)
                                    {
                                        WaypointIndex++;
                                        QuickSaveLoad.QuickSave();
                                    }
                                }
                            }
                            else
                            {
                                WaypointIndex++;
                            }
                        }
                    }
                    brake = brake || ((s.wheelThrottle == 0 || !vessel.isActiveVessel) && curSpeed < brakeSpeedLimit && newSpeed < brakeSpeedLimit);
                    // ^ brake if needed to prevent rolling, hopefully
                    tgtSpeed = (newSpeed >= 0 ? newSpeed : 0);
                }
            }

            if (ControlHeading)
            {
                headingPID.intAccum = Mathf.Clamp((float)headingPID.intAccum, -1, 1);

                double instantaneousHeading = vesselState.rotationVesselSurface.eulerAngles.y;
                headingErr = MuUtils.ClampDegrees180(instantaneousHeading - heading);
                if (s.wheelSteer == s.wheelSteerTrim || FlightGlobals.ActiveVessel != vessel)
                {
                    float limit = (Math.Abs(curSpeed) > turnSpeed ? Mathf.Clamp((float)((turnSpeed + 6) / Square(curSpeed)), 0.1f, 1f) : 1f);
                    // turnSpeed needs to be higher than curSpeed or it will never steer as much as it could even at 0.2m/s above it
                    double act = headingPID.Compute(headingErr);
                    if (traction >= tractionLimit)
                    {
                        s.wheelSteer = Mathf.Clamp((float)act, -limit, limit);
                        // prevents it from flying above a waypoint and landing with steering at max while still going fast
                    }
                }
            }

            // Brake if there is no controler (Pilot eject from seat)
            if (BrakeOnEject && vessel.GetReferenceTransformPart() == null)
            {
                s.wheelThrottle = 0;
                brake           = true;
            }
            else if (ControlSpeed)
            {
                speedPID.intAccum = Mathf.Clamp((float)speedPID.intAccum, -5, 5);

                speedErr = (WaypointIndex == -1 ? speed.val : tgtSpeed) - Vector3d.Dot(vesselState.surfaceVelocity, vesselState.forward);
                if (s.wheelThrottle == s.wheelThrottleTrim || FlightGlobals.ActiveVessel != vessel)
                {
                    float act = (float)speedPID.Compute(speedErr);
                    s.wheelThrottle = Mathf.Clamp(act, -1f, 1f);
                    if (curSpeed < 0 & s.wheelThrottle < 0)
                    {
                        s.wheelThrottle = 0;
                    }                                                                                    // don't go backwards
                    if (Mathf.Sign(act) + Mathf.Sign(s.wheelThrottle) == 0)
                    {
                        s.wheelThrottle = Mathf.Clamp(act, -1f, 1f);
                    }
                    if (speedErr < -1 && StabilityControl && Mathf.Sign(s.wheelThrottle) + Math.Sign(curSpeed) == 0)
                    {
                        brake = true;
                    }
                    lastThrottle = Mathf.Clamp(s.wheelThrottle, -1, 1);
                }
            }

            if (StabilityControl)
            {
                if (!core.attitude.users.Contains(this))
                {
                    core.attitude.users.Add(this);
                }
                var     fSpeed = (float)curSpeed;
                Vector3 fwd    = (Vector3)(traction > 0 ?                                                                         // V when the speed is low go for the vessels forward, else with a bit of velocity
                                           vesselState.forward * 4 - vessel.transform.right * s.wheelSteer * Mathf.Sign(fSpeed) : // and then add the steering
                                           vesselState.surfaceVelocity);                                                          // in the air so follow velocity
                Vector3.OrthoNormalize(ref norm, ref fwd);
                var quat = Quaternion.LookRotation(fwd, norm);

                if (vesselState.torqueAvailable.sqrMagnitude > 0)
                {
                    core.attitude.attitudeTo(quat, AttitudeReference.INERTIAL, this);
                }
            }

            if (BrakeOnEnergyDepletion)
            {
                var batteries  = vessel.Parts.FindAll(p => p.Resources.Contains(PartResourceLibrary.ElectricityHashcode) && p.Resources.Get(PartResourceLibrary.ElectricityHashcode).flowState);
                var energyLeft = batteries.Sum(p => p.Resources.Get(PartResourceLibrary.ElectricityHashcode).amount) / batteries.Sum(p => p.Resources.Get(PartResourceLibrary.ElectricityHashcode).maxAmount);
                var openSolars = vessel.mainBody.atmosphere &&                 // true if in atmosphere and there are breakable solarpanels that aren't broken nor retracted
                                 vessel.FindPartModulesImplementing <ModuleDeployableSolarPanel>().FindAll(p => p.isBreakable && p.deployState != ModuleDeployablePart.DeployState.BROKEN &&
                                                                                                           p.deployState != ModuleDeployablePart.DeployState.RETRACTED).Count > 0;

                if (openSolars && energyLeft > 0.99)
                {
                    vessel.FindPartModulesImplementing <ModuleDeployableSolarPanel>().FindAll(p => p.isBreakable &&
                                                                                              p.deployState == ModuleDeployablePart.DeployState.EXTENDED).ForEach(p => p.Retract());
                }

                if (energyLeft < 0.05 && Math.Sign(s.wheelThrottle) + Math.Sign(curSpeed) != 0)
                {
                    s.wheelThrottle = 0;
                }                                                                                                                        // save remaining energy by not using it for acceleration
                if (openSolars || energyLeft < 0.03)
                {
                    tgtSpeed = 0;
                }

                if (curSpeed < brakeSpeedLimit && (energyLeft < 0.05 || openSolars))
                {
                    brake = true;
                }

                if (curSpeed < 0.1 && energyLeft < 0.05 && !waitingForDaylight &&
                    vessel.FindPartModulesImplementing <ModuleDeployableSolarPanel>().FindAll(p => p.deployState == ModuleDeployablePart.DeployState.EXTENDED).Count > 0)
                {
                    waitingForDaylight = true;
                }
            }

            if (s.wheelThrottle != 0 && (Math.Sign(s.wheelThrottle) + Math.Sign(curSpeed) != 0 || curSpeed < 1))
            {
                brake = false;                 // the AP or user want to drive into the direction of momentum so release the brake
            }

            if (vessel.isActiveVessel)
            {
                if (GameSettings.BRAKES.GetKeyUp())
                {
                    brake = false;                     // release the brakes if the user lets go of them
                }
                if (GameSettings.BRAKES.GetKey())
                {
                    brake = true;                     // brake if the user brakes and we aren't about to flip
                }
            }

            tractionLimit = (double)Mathf.Clamp((float)tractionLimit, 0, 100);
            vessel.ActionGroups.SetGroup(KSPActionGroup.Brakes, brake && (StabilityControl && (ControlHeading || ControlSpeed) ? traction >= tractionLimit : true));
            // only let go of the brake when losing traction if the AP is driving, otherwise assume the player knows when to let go of it
            // also to not constantly turn off the parking brake from going over a small bump
            if (brake && curSpeed < 0.1)
            {
                s.wheelThrottle = 0;
            }
        }
Example #15
0
        public override void Drive(FlightCtrlState s) // TODO put the brake in when running out of power to prevent nighttime solar failures on hills, or atleast try to
        {                                             // TODO make distance calculation for 'reached' determination consider the rover and waypoint on sealevel to prevent height differences from messing it up
            if (orbit.referenceBody != lastBody)
            {
                WaypointIndex = -1; Waypoints.Clear();
            }
            MechJebRoverWaypoint wp = (WaypointIndex > -1 && WaypointIndex < Waypoints.Count ? Waypoints[WaypointIndex] : null);

            var curSpeed = vesselState.speedSurface;

            etaSpeed.value = curSpeed;

            if (wp != null && wp.Body == orbit.referenceBody)
            {
                if (controlHeading)
                {
                    heading = Math.Round(HeadingToPos(vessel.CoM, wp.Position), 1);
                }
                if (controlSpeed)
                {
                    var nextWP   = (WaypointIndex < Waypoints.Count - 1 ? Waypoints[WaypointIndex + 1] : (LoopWaypoints ? Waypoints[0] : null));
                    var distance = Vector3.Distance(vessel.CoM, wp.Position);
                    //var maxSpeed = (wp.MaxSpeed > 0 ? Math.Min((float)speed, wp.MaxSpeed) : speed); // use waypoints maxSpeed if set and smaller than set the speed or just stick with the set speed
                    var maxSpeed = (wp.MaxSpeed > 0 ? wp.MaxSpeed : speed);                     // speed used to go towards the waypoint, using the waypoints maxSpeed if set or just stick with the set speed
                    var minSpeed = (wp.MinSpeed > 0 ? wp.MinSpeed :
                                    (nextWP != null ? TurningSpeed((nextWP.MaxSpeed > 0 ? nextWP.MaxSpeed : speed), heading - HeadingToPos(wp.Position, nextWP.Position)) :
                                     (distance - wp.Radius > 50 ? turnSpeed.val : 1)));
                    minSpeed = (wp.Quicksave ? 0 : minSpeed);
                    // ^ speed used to go through the waypoint, using half the set speed or maxSpeed as minSpeed for routing waypoints (all except the last)
                    var brakeFactor = Math.Max((curSpeed - minSpeed) * 1, 3);
                    var newSpeed    = Math.Min(maxSpeed, Math.Max((distance - wp.Radius) / brakeFactor, minSpeed)); // brake when getting closer
                    newSpeed = (newSpeed > turnSpeed ? TurningSpeed(newSpeed, headingErr) : newSpeed);              // reduce speed when turning a lot
                    var radius = Math.Max(wp.Radius, 10 / 0.8);                                                     // alternative radius so negative radii can still make it go full speed through waypoints for navigation reasons
                    if (distance < radius)
                    {
                        if (WaypointIndex + 1 >= Waypoints.Count)                           // last waypoint
                        {
                            newSpeed = new [] { newSpeed, (distance < radius * 0.8 ? 0 : 1) }.Min();
                            // ^ limit speed so it'll only go from 1m/s to full stop when braking to prevent accidents on moons
                            if (LoopWaypoints)
                            {
                                WaypointIndex = 0;
                            }
                            else
                            {
                                newSpeed = -0.25;
                                tgtSpeed.force(newSpeed);
                                if (curSpeed < 0.85)
                                {
                                    if (wp.Quicksave)
                                    {
                                        if (FlightGlobals.ClearToSave() == ClearToSaveStatus.CLEAR)
                                        {
                                            WaypointIndex  = -1;
                                            controlHeading = controlSpeed = false;
                                            QuickSaveLoad.QuickSave();
                                        }
                                    }
                                    else
                                    {
                                        WaypointIndex  = -1;
                                        controlHeading = controlSpeed = false;
                                    }
                                }
//								else {
//									Debug.Log("Is this even getting called?");
//									WaypointIndex++;
//								}
                            }
                        }
                        else
                        {
                            if (wp.Quicksave)
                            {
                                newSpeed = -0.25;
                                tgtSpeed.force(newSpeed);
                                if (curSpeed < 0.85)
                                {
                                    if (FlightGlobals.ClearToSave() == ClearToSaveStatus.CLEAR)
                                    {
                                        WaypointIndex++;
                                        QuickSaveLoad.QuickSave();
                                    }
                                }
                            }
                            else
                            {
                                WaypointIndex++;
                            }
                        }
                    }
                    vessel.ActionGroups.SetGroup(KSPActionGroup.Brakes, (GameSettings.BRAKES.GetKey() && vessel.isActiveVessel) || ((s.wheelThrottle == 0 || !vessel.isActiveVessel) && curSpeed < 0.85 && newSpeed < 0.85));
                    // ^ brake if needed to prevent rolling, hopefully
                    tgtSpeed.value = Math.Round(newSpeed, 1);
                }
            }

            if (controlHeading)
            {
                if (heading != headingLast)
                {
                    headingPID.Reset();
                    headingLast = heading;
                }

                double instantaneousHeading = vesselState.rotationVesselSurface.eulerAngles.y;
                headingErr = MuUtils.ClampDegrees180(instantaneousHeading - heading);
                if (s.wheelSteer == s.wheelSteerTrim || FlightGlobals.ActiveVessel != vessel)
                {
                    float  spd   = Mathf.Min((float)speed, (float)turnSpeed);                  // if a slower speed than the turnspeed is used also be more careful with the steering
                    float  limit = (curSpeed <= turnSpeed ? 1 : Mathf.Clamp((float)((spd * spd) / (curSpeed * curSpeed)), 0.2f, 1f));
                    double act   = headingPID.Compute(headingErr);
                    s.wheelSteer = Mathf.Clamp((float)act, -limit, limit);
                }
            }
            // Brake if there is no controler (Pilot eject from seat)
            if (brakeOnEject && vessel.GetReferenceTransformPart() == null)
            {
                s.wheelThrottle = 0;
                vessel.ActionGroups.SetGroup(KSPActionGroup.Brakes, true);
            }
            else if (controlSpeed)
            {
                if (speed != speedLast)
                {
                    speedPID.Reset();
                    speedLast = speed;
                }

                speedErr = (WaypointIndex == -1 ? speed.val : tgtSpeed.value) - Vector3d.Dot(vesselState.velocityVesselSurface, vesselState.forward);
                if (s.wheelThrottle == s.wheelThrottleTrim || FlightGlobals.ActiveVessel != vessel)
                {
                    double act = speedPID.Compute(speedErr);
                    s.wheelThrottle = Mathf.Clamp((float)act, -1, 1);
                }
            }
        }