コード例 #1
0
        double GetMaxAccelFromAngleDeviation(float angle)
        {
            var DownAccel    = MaxDownThrust / shipMass;
            var LateralAccel = MaxLateralThrust / shipMass;
            var LiftAccel    = MaxLiftThrust / shipMass;

            return(Math.Min(LateralAccel - gravStr * TrigHelpers.FastSin(angle), Math.Min(LiftAccel - gravStr * TrigHelpers.FastCos(angle), DownAccel + gravStr * TrigHelpers.FastCos(angle))));
        }
コード例 #2
0
        void Attack(TimeSpan localTime)
        {
            FriendlyShipScratchpad.Clear();

            var intelItems = IntelProvider.GetFleetIntelligences(localTime);

            foreach (var kvp in intelItems)
            {
                if (kvp.Key.Item1 == IntelItemType.Friendly)
                {
                    var friendly = (FriendlyShipIntel)kvp.Value;
                    if (friendly.AgentClass == AgentClass.Fighter && (friendly.AgentStatus & AgentStatus.Docked) != 0 && (friendly.GetPositionFromCanonicalTime(localTime + IntelProvider.CanonicalTimeDiff) - Controller.GetPosition()).Length() < 100)
                    {
                        FriendlyShipScratchpad.Add(friendly);
                    }
                }
            }

            if (FriendlyShipScratchpad.Count == 0)
            {
                return;
            }

            for (int i = 0; i < FriendlyShipScratchpad.Count; i++)
            {
                var targetWaypoint = new Waypoint();

                var gravDir = Controller.GetNaturalGravity();
                targetWaypoint.Position = Controller.GetPosition();
                var angle = 2 * i * Math.PI / FriendlyShipScratchpad.Count;

                if (gravDir != Vector3D.Zero)
                {
                    gravDir.Normalize();
                    var flatForward = Controller.WorldMatrix.Forward - VectorHelpers.VectorProjection(Controller.WorldMatrix.Forward, gravDir);
                    flatForward.Normalize();
                    var flatLeftDir = Vector3D.Cross(flatForward, gravDir);
                    targetWaypoint.Position += (flatForward * TrigHelpers.FastCos(angle) + flatLeftDir * TrigHelpers.FastSin(angle)) * 500;
                    targetWaypoint.Position -= gravDir * 200;
                }
                else
                {
                    targetWaypoint.Position += (Controller.WorldMatrix.Forward * TrigHelpers.FastCos(angle) + Controller.WorldMatrix.Left * TrigHelpers.FastSin(angle)) * 500;
                }

                targetWaypoint.Position += Controller.GetShipVelocities().LinearVelocity * 3;
                IntelProvider.ReportFleetIntelligence(targetWaypoint, localTime);
                IntelProvider.ReportCommand(FriendlyShipScratchpad[i], TaskType.Attack, MyTuple.Create(IntelItemType.Waypoint, targetWaypoint.ID), localTime);
            }
        }
コード例 #3
0
        public void Turn(MatrixD Reference, Vector3D target)
        {
            if (Reference == MatrixD.Zero)
            {
                return;
            }
            MatrixD orientationMatrix = MatrixD.Identity;

            orientationMatrix.Translation = Reference.Translation;
            Vector3D orientationForward = Controller.WorldMatrix.Forward + Controller.WorldMatrix.Down + Controller.WorldMatrix.Left;

            orientationForward.Normalize();
            orientationMatrix.Forward = orientationForward;
            Vector3D orientationUp = Reference.Forward;

            orientationUp -= VectorHelpers.VectorProjection(orientationUp, orientationForward);
            orientationUp.Normalize();
            orientationMatrix.Up = orientationUp;
            Vector3D OrientationRight = orientationForward.Cross(orientationUp);

            orientationMatrix.Right = OrientationRight;
            var gravDir = Controller.GetNaturalGravity();

            gravDir.Normalize();

            double yawAngle, pitchAngle, spinAngle;

            GravAngle = VectorHelpers.VectorAngleBetween(gravDir, orientationMatrix.Forward);

            if (target != Vector3D.Zero && GravAngle < Math.PI * 0.1)
            {
                Vector3D TargetDir = target - orientationMatrix.Translation;
                TargetDir.Normalize();
                var projectedTargetUp = TargetDir - VectorHelpers.VectorProjection(TargetDir, orientationForward);
                spinAngle = -1 * VectorHelpers.VectorAngleBetween(orientationMatrix.Up, projectedTargetUp) * Math.Sign(orientationMatrix.Left.Dot(TargetDir));
            }
            else
            {
                spinAngle = 0;
                SpinPID.Reset();
            }
            TrigHelpers.GetRotationAngles(gravDir, orientationMatrix.Forward, orientationMatrix.Left, orientationMatrix.Up, out yawAngle, out pitchAngle);
            TrigHelpers.ApplyGyroOverride(PitchPID.Control(pitchAngle), YawPID.Control(yawAngle), SpinPID.Control(spinAngle), Gyros, orientationMatrix);
        }
コード例 #4
0
        double GetMaxAngleDeviationFromAcceleration(float accel)
        {
            var DownAccel    = MaxDownThrust / shipMass;
            var LateralAccel = MaxLateralThrust / shipMass;

            var MaxAngle = Math.PI * 0.5;

            var LateralFactor = (LateralAccel - accel) / gravStr;

            if (LateralFactor < 1)
            {
                MaxAngle = TrigHelpers.FastAsin(LateralFactor);
            }

            var DownFactor = (accel - MaxDownThrust) / gravStr;

            if (DownFactor < 1)
            {
                MaxAngle = Math.Min(MaxAngle, Math.Acos(DownFactor));
            }

            return(MaxAngle);
        }
コード例 #5
0
        public void Update()
        {
            LifeTimeTicks++;

            // Startup Subroutine
            if (LifeTimeTicks == 1)
            {
                foreach (var engine in Drive.HoverEngines)
                {
                    engine.AltitudeMin = 1;
                    engine.PushOnly    = true;
                }
            }

            if (LifeTimeTicks == 60)
            {
                foreach (var engine in Drive.HoverEngines)
                {
                    engine.AltitudeMin = 2;
                }
            }

            if (LifeTimeTicks == 120)
            {
                foreach (var engine in Drive.HoverEngines)
                {
                    engine.AltitudeMin = 7;
                }
            }

            if (LifeTimeTicks % kRunEveryXUpdates == 0)
            {
                Vector3D PlanetDir = PlanetPos - Controller.WorldMatrix.Translation;
                PlanetDir.Normalize();

                // Orient Self
                Drive.Turn(Gats.Count > 0 ? Gats[0].WorldMatrix : Controller.WorldMatrix, target);

                // Aim Turret
                if (TurretRotor != null)
                {
                    if (target != Vector3D.Zero && Drive.GravAngle < Math.PI * 0.1)
                    {
                        var TurretAngle = TrigHelpers.FastAsin(Gats[0].WorldMatrix.Forward.Dot(PlanetDir));

                        Vector3D TargetDir  = target - Gats[0].WorldMatrix.Translation;
                        var      targetDist = TargetDir.Length();
                        TargetDir.Normalize();
                        var TargetAngle = TrigHelpers.FastAsin(TargetDir.Dot(PlanetDir));

                        var angleDiff = TargetAngle - TurretAngle;

                        if (VectorHelpers.VectorAngleBetween(Gats[0].WorldMatrix.Forward, TargetDir) < 0.05 && targetDist < 800)
                        {
                            Fire();
                        }

                        TurretRotor.TargetVelocityRPM = (float)TurretPID.Control(angleDiff);
                    }
                    else
                    {
                        TurretPID.Reset();
                        TurretRotor.TargetVelocityRPM = 0;
                    }
                }

                // Check your fire
                fireTicks--;
                if (fireTicks == -1)
                {
                    foreach (var gat in Gats)
                    {
                        TerminalPropertiesHelper.SetValue(gat, "Shoot", false);
                    }
                }

                // Check Movement
                if (Destination != Vector3D.Zero)
                {
                    Drive.Drive(Destination);
                    if (Drive.Arrived)
                    {
                        Destination = Vector3D.Zero;
                        Drive.Flush();
                    }
                }
            }
        }
コード例 #6
0
        public void Main(string argument, UpdateType updateSource)
        {
            subsystemManager.UpdateTime();

            if (argument == "descend")
            {
                Mode       = 1;
                lockMatrix = Drive.Controller.WorldMatrix;
            }
            else if (argument == "ascend")
            {
                Mode       = 2;
                lockMatrix = Drive.Controller.WorldMatrix;
            }
            else if (argument == "stop")
            {
                Mode       = 0;
                lockMatrix = MatrixD.Zero;
                Drive.Clear();
            }
            else if (commandLine.TryParse(argument))
            {
                subsystemManager.Command(commandLine.Argument(0), commandLine.Argument(1), commandLine.ArgumentCount > 2 ? commandLine.Argument(2) : null);
            }
            else
            {
                try
                {
                    subsystemManager.Update(updateSource);

                    runs++;
                    if (runs % 5 == 0)
                    {
                        OutputBuilder.Clear();

                        OutputBuilder.Append($"STATUS: ").AppendLine(Mode == 0 ? "STOP" : (Mode == 1 ? "DESC" : "ASCE"));

                        foreach (var screen in Displays)
                        {
                            screen.ContentType = ContentType.TEXT_AND_IMAGE;
                            screen.WriteText(OutputBuilder.ToString());
                        }

                        var destination = new Waypoint();

                        if (Mode == 0)
                        {
                            Drive.Clear();
                        }
                        else if (Mode == 1)
                        {
                            destination.MaxSpeed = DescendSpeed;
                            var gravdir = Cockpit.GetNaturalGravity();
                            if (gravdir == Vector3D.Zero)
                            {
                                gravdir.Normalize();

                                destination.Position = gravdir * 10 + Cockpit.GetPosition();

                                var flatForward = Cockpit.WorldMatrix.Forward - VectorHelpers.VectorProjection(Cockpit.WorldMatrix.Forward, gravdir);
                                flatForward.Normalize();
                                var flatLeft = Cockpit.WorldMatrix.Left - VectorHelpers.VectorProjection(Cockpit.WorldMatrix.Forward, gravdir);
                                flatLeft.Normalize();

                                destination.Direction = flatForward * TrigHelpers.FastCos(0.02 * RotateSpeed) + flatLeft * TrigHelpers.FastSin(0.02 * RotateSpeed);
                            }
                            else
                            {
                                destination.Position    = lockMatrix.Down * 10 + Cockpit.GetPosition();
                                destination.DirectionUp = lockMatrix.Up;

                                var flatForward = Cockpit.WorldMatrix.Forward - VectorHelpers.VectorProjection(Cockpit.WorldMatrix.Forward, lockMatrix.Down);
                                flatForward.Normalize();
                                var flatLeft = Cockpit.WorldMatrix.Left - VectorHelpers.VectorProjection(Cockpit.WorldMatrix.Forward, lockMatrix.Down);
                                flatLeft.Normalize();

                                destination.Direction = flatForward * TrigHelpers.FastCos(0.02 * RotateSpeed) + flatLeft * TrigHelpers.FastSin(0.02 * RotateSpeed);
                            }
                        }
                        else if (Mode == 2)
                        {
                            destination.MaxSpeed = AscendSpeed;
                            if (Drive.Controller == Cockpit)
                            {
                                var gravdir = Cockpit.GetNaturalGravity();
                                gravdir.Normalize();

                                destination.Position = -gravdir * 10 + Cockpit.GetPosition();
                            }
                            else
                            {
                                destination.Position  = lockMatrix.Down * 10 + Cockpit.GetPosition();
                                destination.Direction = lockMatrix.Forward;
                            }
                        }

                        Drive.Move(destination.Position);
                        Drive.Turn(destination.Direction);
                        Drive.Spin(destination.DirectionUp);
                        Drive.SetMaxSpeed(destination.MaxSpeed);
                    }
                }
                catch (Exception e)
                {
                    Me.GetSurface(0).WriteText(e.Message);
                    Me.GetSurface(0).WriteText("\n", true);
                    Me.GetSurface(0).WriteText(e.StackTrace);
                    Me.GetSurface(0).WriteText("\n", true);
                    Me.GetSurface(0).WriteText(e.ToString());
                }
                var s = subsystemManager.GetStatus();
                if (!string.IsNullOrEmpty(s))
                {
                    Echo(s);
                }
                else
                {
                    Echo(((int)subsystemManager.OutputMode).ToString());
                }
            }
        }
コード例 #7
0
        public void Update(TimeSpan timestamp, UpdateFrequency updateFlags)
        {
            if (runs % 240 == 0)
            {
                statusBuilder.Clear();
                foreach (var tube in LandpedoTubes)
                {
                    tube.CheckLandpedo();
                    // statusBuilder.AppendLine(tube.GetStatus());
                }
            }

            if (runs % 10 == 0)
            {
                statusBuilder.Clear();
                var targets       = IntelProvider.GetFleetIntelligences(timestamp);
                var canonicalTime = IntelProvider.CanonicalTimeDiff + timestamp;
                DeadLandpedos.Clear();
                foreach (var landpedo in Landpedos)
                {
                    statusBuilder.AppendLine("LANDPEDO===");

                    if (landpedo.Fired)
                    {
                        landpedo.DeadCount--;
                    }

                    if (!landpedo.IsOK())
                    {
                        DeadLandpedos.Add(landpedo);
                        continue;
                    }
                    landpedo.runs++;
                    var landpedoPosition = landpedo.Controller.WorldMatrix.Translation;
                    var landpedoVelocity = landpedo.Controller.GetShipVelocities().LinearVelocity;
                    var gravDir          = landpedo.Controller.GetNaturalGravity();
                    var gravStr          = gravDir.Normalize();
                    var planarVelocity   = landpedoVelocity - VectorHelpers.VectorProjection(landpedoVelocity, gravDir);

                    if (landpedo.TargetID != -1)
                    {
                        var key = MyTuple.Create(IntelItemType.Enemy, landpedo.TargetID);
                        if (targets.ContainsKey(key))
                        {
                            var target = targets[key];
                            landpedo.TargetPosition = target.GetPositionFromCanonicalTime(canonicalTime);
                            landpedo.TargetVelocity = target.GetVelocity();
                        }
                    }

                    statusBuilder.AppendLine(landpedo.TargetPosition.ToString());

                    if (landpedo.TargetPosition != Vector3D.Zero)
                    {
                        var relativeVector = landpedo.TargetPosition - landpedoPosition;
                        var planarVector   = relativeVector - VectorHelpers.VectorProjection(relativeVector, gravDir);

                        var targetPoint = AttackHelpers.GetAttackPoint(landpedo.TargetVelocity, landpedo.TargetPosition - landpedoPosition, landpedo.lastSpeed);
                        if (targetPoint == Vector3D.Zero)
                        {
                            targetPoint = landpedo.TargetPosition - landpedoPosition;
                        }
                        var targetPointDist = targetPoint.Length();

                        var planarDist = planarVector.Length();
                        var velocity   = landpedo.Controller.GetShipVelocities().LinearVelocity;

                        var verticalVelocity = VectorHelpers.VectorProjection(velocity, gravDir);

                        var planarLeft = landpedo.Controller.WorldMatrix.Left - VectorHelpers.VectorProjection(landpedo.Controller.WorldMatrix.Left, gravDir);
                        planarLeft.Normalize();

                        var planarForward = landpedo.Controller.WorldMatrix.Forward - VectorHelpers.VectorProjection(landpedo.Controller.WorldMatrix.Forward, gravDir);
                        planarForward.Normalize();

                        double altitude;
                        landpedo.Controller.TryGetPlanetElevation(MyPlanetElevation.Surface, out altitude);

                        if (targetPointDist > 350 || landpedo.Launchers.Count == 0)
                        {
                            landpedo.desiredAltitude = planarVector.Length() > 200 ? 10 : 50;
                            planarVector.Normalize();

                            MatrixD orientationMatrix = MatrixD.Identity;
                            orientationMatrix.Translation = landpedo.Controller.WorldMatrix.Translation;

                            orientationMatrix.Up      = -gravDir;
                            orientationMatrix.Left    = planarLeft;
                            orientationMatrix.Forward = planarForward;

                            var spinAngle = VectorHelpers.VectorAngleBetween(planarForward, planarVector) * Math.Sign(-planarLeft.Dot(planarVector));

                            // var planarVelocity = velocity - verticalVelocity;
                            // var velocityAdjust = planarVelocity - VectorHelpers.VectorProjection(velocity, planarVector);
                            // velocityAdjust.Normalize();
                            // planarVector -= velocityAdjust;
                            // var MoveIndicator = Vector3D.TransformNormal(planarVector, MatrixD.Transpose(orientationMatrix));

                            var rangeVector    = planarVector;
                            var waypointVector = rangeVector;
                            var distTargetSq   = rangeVector.LengthSquared();

                            var targetPlanarVelocity = landpedo.TargetVelocity - VectorHelpers.VectorProjection(landpedo.TargetVelocity, gravDir);


                            Vector3D velocityVector = targetPlanarVelocity - planarVelocity;
                            var      speed          = planarVelocity.Length();

                            Vector3D AccelerationVector;

                            double alignment = planarVelocity.Dot(ref waypointVector);
                            if (alignment > 0)
                            {
                                Vector3D rangeDivSqVector = waypointVector / waypointVector.LengthSquared();
                                Vector3D compensateVector = velocityVector - (velocityVector.Dot(ref waypointVector) * rangeDivSqVector);

                                Vector3D targetANVector;
                                var      targetAccel = (landpedo.lastTargetVelocity - targetPlanarVelocity) * 0.16667;

                                targetANVector = targetAccel - (targetAccel.Dot(ref waypointVector) * rangeDivSqVector);

                                bool accelerating = speed > landpedo.lastSpeed + 1;
                                if (accelerating)
                                {
                                    AccelerationVector = planarVelocity + (10 * 1.5 * (compensateVector + (0.5 * targetANVector)));
                                }
                                else
                                {
                                    AccelerationVector = planarVelocity + (10 * (compensateVector + (0.5 * targetANVector)));
                                }
                            }
                            // going backwards or perpendicular
                            else
                            {
                                AccelerationVector = (waypointVector * 0.1) + velocityVector;
                            }

                            landpedo.lastTargetVelocity = landpedo.TargetVelocity;
                            landpedo.lastSpeed          = speed;

                            var MoveIndicator = Vector3D.TransformNormal(AccelerationVector, MatrixD.Transpose(orientationMatrix));

                            MoveIndicator.Y = 0;
                            MoveIndicator.Normalize();

                            statusBuilder.AppendLine(MoveIndicator.ToString());

                            landpedo.Drive.MoveIndicators     = MoveIndicator;
                            landpedo.Drive.RotationIndicators = new Vector3(0, spinAngle, 0);

                            landpedo.Drive.Drive();

                            if (verticalVelocity.Length() > 10 && verticalVelocity.Dot(gravDir) > 0)
                            {
                                landpedo.Drive.maxFlightPitch = 20;
                                landpedo.Drive.maxFlightRoll  = 20;
                            }
                            else
                            {
                                landpedo.Drive.maxFlightPitch = 60;
                                landpedo.Drive.maxFlightRoll  = 60;
                            }

                            if (targetPointDist < 1000)
                            {
                                landpedo.Drive.maxFlightPitch = 20;
                            }
                        }
                        else if (landpedo.TargetID != -1)
                        {
                            var key = MyTuple.Create(IntelItemType.Enemy, landpedo.TargetID);
                            if (!targets.ContainsKey(key))
                            {
                                return;
                            }
                            var target = targets[key];

                            var posDiff = target.GetPositionFromCanonicalTime(canonicalTime) - landpedoPosition;

                            var avgVel = 400 * Math.Sqrt(posDiff.Length() / 400);

                            var relativeAttackPoint = AttackHelpers.GetAttackPoint(landpedo.TargetVelocity - velocity, posDiff, avgVel);
                            targetPointDist = relativeAttackPoint.Length();

                            double yawAngle, pitchAngle;

                            TrigHelpers.GetRotationAngles(relativeAttackPoint, landpedo.Controller.WorldMatrix.Forward, landpedo.Controller.WorldMatrix.Left, landpedo.Controller.WorldMatrix.Up, out yawAngle, out pitchAngle);
                            TrigHelpers.ApplyGyroOverride(landpedo.PitchPID.Control(pitchAngle), landpedo.YawPID.Control(yawAngle), 0, landpedo.Gyros, landpedo.Controller.WorldMatrix);

                            if ((targetPointDist < 125 || landpedo.minDist < planarDist))
                            {
                                foreach (var weapon in landpedo.Launchers)
                                {
                                    weapon.Enabled = true;
                                }
                                landpedo.Fired = true;
                            }

                            landpedo.minDist = Math.Min(landpedo.minDist, planarDist);
                        }

                        var verticalThrustRatio = TrigHelpers.FastCos(VectorHelpers.VectorAngleBetween(landpedo.Controller.WorldMatrix.Down, gravDir));
                        var desiredThrust       = ((landpedo.desiredAltitude - altitude) + verticalVelocity.LengthSquared() * 0.1 + gravStr) * landpedo.Controller.CalculateShipMass().PhysicalMass / verticalThrustRatio;
                        var individualThrust    = desiredThrust / landpedo.Thrusters.Count();
                        if (individualThrust <= 0)
                        {
                            individualThrust = 0.001;
                        }

                        foreach (var thruster in landpedo.Thrusters)
                        {
                            thruster.Enabled        = ((verticalVelocity.Length() > 20 && verticalVelocity.Dot(gravDir) < 0) || ((verticalVelocity.Length() > 2 && verticalVelocity.Dot(gravDir) < 0) && targetPointDist < 1000)) ? false : true;
                            thruster.ThrustOverride = (float)individualThrust;
                        }

                        statusBuilder.AppendLine($"{landpedo.Drive.thrustController.CalculateThrustToHover()}");
                        statusBuilder.AppendLine($"{landpedo.Drive.thrustController.upThrusters.Count} : {landpedo.Drive.thrustController.downThrusters.Count}");
                    }
                }

                foreach (var landpedo in DeadLandpedos)
                {
                    Landpedos.Remove(landpedo);
                }
            }
            runs++;
        }
コード例 #8
0
        public void Update(TimeSpan timestamp, UpdateFrequency updateFlags)
        {
            runs++;

            if (runs % 30 == 0)
            {
                MaxLiftThrust    = 0;
                MaxLateralThrust = 0;
                MaxDownThrust    = 0;
                foreach (var kvp in Thrusters)
                {
                    if (kvp.Key == Base6Directions.Direction.Down)
                    {
                        foreach (var thruster in kvp.Value)
                        {
                            MaxLiftThrust += thruster.MaxEffectiveThrust;
                        }
                    }
                    else if (kvp.Key == Base6Directions.Direction.Forward)
                    {
                        foreach (var thruster in kvp.Value)
                        {
                            MaxLateralThrust += thruster.MaxEffectiveThrust;
                        }
                    }
                    else if (kvp.Key == Base6Directions.Direction.Up)
                    {
                        foreach (var thruster in kvp.Value)
                        {
                            MaxDownThrust += thruster.MaxEffectiveThrust;
                        }
                    }

                    ThrusterManagers[kvp.Key].RecalculateThrust();
                }
            }

            if (runs % 5 == 0)
            {
                StatusBuilder.Clear();

                shipMass = Controller.CalculateShipMass().PhysicalMass;
                gravDir  = Controller.GetNaturalGravity();

                double yawAngle, pitchAngle, spinAngle;
                yawAngle = pitchAngle = spinAngle = 0;
                MatrixD orientationMatrix = new MatrixD();

                var flatCurrentDir = Controller.WorldMatrix.Forward - VectorHelpers.VectorProjection(Controller.WorldMatrix.Forward, gravDir);
                flatCurrentDir.Normalize();

                var flatLeftDir = Vector3D.Cross(flatCurrentDir, gravDir);

                if (gravDir != Vector3D.Zero)
                {
                    gravStr = gravDir.Length();
                    gravDir.Normalize();
                    // Rotational Control
                    var targetDir = Vector3D.Zero;
                    if (ForwardDir != Vector3D.Zero)
                    {
                        targetDir = ForwardDir;
                    }
                    else if (FullAuto)
                    {
                        targetDir = Controller.WorldMatrix.Forward - VectorHelpers.VectorProjection(Controller.WorldMatrix.Forward, gravDir);
                    }

                    if (targetDir != Vector3D.Zero)
                    {
                        if (UpDir == Vector3D.Zero)
                        {
                            var angleFromVertical    = VectorHelpers.VectorAngleBetween(targetDir, gravDir) - Math.PI * 0.5;
                            var maxAngleFromVertical = GetMaxAngleConstraint();
                            angleFromVertical = Math.Max(Math.Min(angleFromVertical, maxAngleFromVertical), -maxAngleFromVertical);
                            var flatAimDir = targetDir - VectorHelpers.VectorProjection(targetDir, gravDir);
                            flatAimDir.Normalize();

                            var downDir = TrigHelpers.FastCos(angleFromVertical) * gravDir + TrigHelpers.FastSin(angleFromVertical) * flatAimDir;

                            orientationMatrix.Forward = Controller.WorldMatrix.Down;
                            orientationMatrix.Left    = Controller.WorldMatrix.Left;
                            orientationMatrix.Up      = Controller.WorldMatrix.Forward;

                            spinAngle = -VectorHelpers.VectorAngleBetween(flatAimDir, flatCurrentDir) * Math.Sign(Controller.WorldMatrix.Left.Dot(flatAimDir));
                            TrigHelpers.GetRotationAngles(downDir, orientationMatrix.Forward, orientationMatrix.Left, orientationMatrix.Up, out yawAngle, out pitchAngle);
                        }
                        else
                        {
                            orientationMatrix = reference.WorldMatrix;
                            TrigHelpers.GetRotationAngles(ForwardDir, reference.WorldMatrix.Forward, reference.WorldMatrix.Left, reference.WorldMatrix.Up, out yawAngle, out pitchAngle);
                            var projectedTargetUp = UpDir - reference.WorldMatrix.Forward.Dot(UpDir) * reference.WorldMatrix.Forward;
                            spinAngle = -1 * VectorHelpers.VectorAngleBetween(reference.WorldMatrix.Up, projectedTargetUp) * Math.Sign(reference.WorldMatrix.Left.Dot(UpDir));
                        }
                    }
                }
                else if (ForwardDir != Vector3D.Zero)
                {
                    orientationMatrix = reference.WorldMatrix;
                    TrigHelpers.GetRotationAngles(ForwardDir, reference.WorldMatrix.Forward, reference.WorldMatrix.Left, reference.WorldMatrix.Up, out yawAngle, out pitchAngle);

                    if (UpDir != Vector3D.Zero)
                    {
                        var projectedTargetUp = UpDir - reference.WorldMatrix.Forward.Dot(UpDir) * reference.WorldMatrix.Forward;
                        spinAngle = -1 * VectorHelpers.VectorAngleBetween(reference.WorldMatrix.Up, projectedTargetUp) * Math.Sign(reference.WorldMatrix.Left.Dot(UpDir));
                    }
                }

                if (yawAngle != 0 || pitchAngle != 0 || spinAngle != 0)
                {
                    TrigHelpers.ApplyGyroOverride(PitchPID.Control(pitchAngle), YawPID.Control(yawAngle), gravDir == Vector3D.Zero ? spinAngle : SpinPID.Control(spinAngle), Gyros, orientationMatrix);
                }
                else
                {
                    foreach (var gyro in Gyros)
                    {
                        if (gyro.GyroOverride)
                        {
                            gyro.GyroOverride = false;
                        }
                    }
                }

                // Translational Control

                if (Destination == Vector3D.Zero && TargetDrift == Vector3D.Zero)
                {
                    foreach (var kvp in ThrusterManagers)
                    {
                        kvp.Value.SetThrust(0);
                    }

                    if (FullAuto)
                    {
                        Controller.DampenersOverride = true;
                    }
                }
                else
                {
                    Controller.DampenersOverride = false;

                    // Compute direction of motion
                    var destinationDir  = Destination - Reference.GetPosition();
                    var destinationDist = destinationDir.Length();
                    destinationDir.Normalize();

                    // Compute current motion to find desired acceleration
                    var currentVel = Controller.GetShipVelocities().LinearVelocity;

                    if (destinationDist < 0.25 && currentVel.Length() < 0.25 && TargetDrift == Vector3D.Zero)
                    {
                        foreach (var kvp in ThrusterManagers)
                        {
                            kvp.Value.SetThrust(0);
                        }
                        Controller.DampenersOverride = true;
                        Destination = Vector3D.Zero;
                    }
                    else
                    {
                        Vector3D desiredVel = Vector3D.Zero;
                        if (Destination != Vector3D.Zero)
                        {
                            var maxSpeed = Math.Min(MaxSpeed, GetMaxSpeedFromBrakingDistance(destinationDist, GetMaxAccelFromAngleDeviation((float)GetMaxAngleConstraint() * MaxAngleTolerance)) * 0.9);
                            maxSpeed   = Math.Min(maxSpeed, destinationDist * destinationDist + 0.5);
                            desiredVel = destinationDir * maxSpeed;
                        }
                        desiredVel += TargetDrift;
                        var adjustVector = currentVel - VectorHelpers.VectorProjection(currentVel, desiredVel);
                        var desiredAccel = desiredVel - currentVel - adjustVector * 2;

                        // Transform desired acceleration into remote control frame
                        var gridDesiredAccel = Vector3D.TransformNormal(desiredAccel, MatrixD.Transpose(Controller.WorldMatrix));

                        double accelMagnitude = gridDesiredAccel.Length();
                        if (accelMagnitude < PrecisionThreshold)
                        {
                            gridDesiredAccel *= Math.Max(accelMagnitude / PrecisionThreshold, .1);
                        }

                        gridDesiredAccel.X = XPID.Control(gridDesiredAccel.X);
                        gridDesiredAccel.Y = YPID.Control(gridDesiredAccel.Y);
                        gridDesiredAccel.Z = ZPID.Control(gridDesiredAccel.Z);

                        double MinScale    = 10;
                        var    gridGravDir = Vector3D.TransformNormal(gravDir, MatrixD.Transpose(Controller.WorldMatrix));
                        foreach (var kvp in ThrusterManagers)
                        {
                            var desiredDirectionalThrust = -1 * Base6Directions.GetVector(kvp.Key).Dot(gridDesiredAccel) * shipMass;
                            var gravAssist = Base6Directions.GetVector(kvp.Key).Dot(gridGravDir) * shipMass;
                            if (desiredDirectionalThrust > 0)
                            {
                                MinScale = Math.Min((kvp.Value.MaxThrust - gravAssist) / desiredDirectionalThrust, MinScale);
                            }
                        }

                        gridDesiredAccel *= MinScale;
                        gridDesiredAccel -= gridGravDir * gravStr;

                        foreach (var kvp in ThrusterManagers)
                        {
                            kvp.Value.SetThrust(-1 * Base6Directions.GetVector(kvp.Key).Dot(gridDesiredAccel + gridGravDir) * shipMass);
                        }
                    }
                }
            }
        }
コード例 #9
0
        public void Update(TimeSpan timestamp, UpdateFrequency updateFlags)
        {
            runs++;

            OnRelease = OnRelease || LastFrameMouseDown & !Turret.IsShooting;

            var a            = Turret.Azimuth;
            var b            = Turret.Elevation;
            var TurretAimRay = Math.Sin(a) * Math.Cos(b) * Turret.WorldMatrix.Left + Math.Cos(a) * Math.Cos(b) * Turret.WorldMatrix.Forward + Math.Sin(b) * Turret.WorldMatrix.Up;

            var     WallPlane = new Plane(Panels[Vector2I.Zero].GetPosition() - Panels[Vector2I.Zero].WorldMatrix.Backward, Panels[Vector2I.Zero].WorldMatrix.Backward);
            Vector3 Intersection;

            TrigHelpers.PlaneIntersection(WallPlane, Turret.GetPosition() + Turret.WorldMatrix.Up * 0.579 + Turret.WorldMatrix.Backward * 0.068, TurretAimRay, out Intersection);

            var CursorDirection = Intersection - Panels[Vector2I.Zero].GetPosition() + Panels[Vector2I.Zero].WorldMatrix.Backward * 1.25 + Panels[Vector2I.Zero].WorldMatrix.Right * 1.25;
            var CursorDist      = CursorDirection.Length();

            CursorDirection.Normalize();

            // LCD wall configuration:
            // |  |    |
            // |  |    |
            // |  |    |

            // Cursor position, originating in the middle of the LCD wall, with unit in meters
            CursorPos   = Vector3D.TransformNormal(CursorDirection, MatrixD.Transpose(Panels[Vector2I.Zero].WorldMatrix)) * CursorDist;
            CursorPos2D = new Vector2((float)CursorPos.X, (float)CursorPos.Y);

            if (runs % 10 == 0)
            {
                DebugBuilder.Clear();
                SinViewDegree = Math.Sin(ViewAngleDegrees * Math.PI / 180);
                CosViewDegree = Math.Cos(ViewAngleDegrees * Math.PI / 180);

                SpriteScratchpad.Clear();
                int i;
                AddSprite("CircleHollow", new Vector2(0, 0), new Vector2(5, 5 * (float)CosViewDegree));
                for (i = 10000; i <= MapSize; i += 10000)
                {
                    var CircleSize = MapOnScreenSizeMeters * PixelsPerMeter * i / MapSize;
                    AddSprite("CircleHollow", new Vector2(0, 0), new Vector2(CircleSize, CircleSize * (float)CosViewDegree), new Color(1f, 0.4f, 0f, 0.005f));
                }

                var gravDir = Controller.GetNaturalGravity();

                // Create map matrix
                if (gravDir != Vector3D.Zero)
                {
                    // Within gravity, align with gravity = down
                    // Either use controller's forward direction or north as forward
                    gravDir.Normalize();
                    var flatNorthDir = new Vector3D(0, 1, 0) - VectorHelpers.VectorProjection(new Vector3D(0, 1, 0), gravDir);
                    flatNorthDir.Normalize();
                    var flatForwardDir = AlignWithNorth ? flatNorthDir : (Controller.WorldMatrix.Forward - VectorHelpers.VectorProjection(AlignWithNorth ? new Vector3D(0, 1, 0) : Controller.WorldMatrix.Forward, gravDir));
                    flatForwardDir.Normalize();
                    var flatLeftDir = Vector3D.Cross(flatForwardDir, gravDir);

                    MapMatrix.Up      = -gravDir;
                    MapMatrix.Forward = flatForwardDir;
                    MapMatrix.Left    = flatLeftDir;

                    var localNorthDir = Vector3D.TransformNormal(flatNorthDir, MatrixD.Transpose(MapMatrix));
                    var localWestDir  = Vector3D.Cross(localNorthDir, new Vector3D(0, -1, 0));

                    AddTextSprite("N", LocalCoordsToMapPosition(localNorthDir * MapSize * 0.5, true), 4);
                    AddTextSprite("S", LocalCoordsToMapPosition(-localNorthDir * MapSize * 0.5, true), 4);
                    AddTextSprite("W", LocalCoordsToMapPosition(localWestDir * MapSize * 0.5, true), 4);
                    AddTextSprite("E", LocalCoordsToMapPosition(-localWestDir * MapSize * 0.5, true), 4);
                }
                else
                {
                    // Else... idk just align with world axis?
                    MapMatrix = MatrixD.Identity;
                }

                var intelItems = IntelProvider.GetFleetIntelligences(timestamp);
                DebugBuilder.AppendLine(intelItems.Count.ToString());

                SelectionCandidates.Clear();

                ClosestItemKey  = MyTuple.Create(IntelItemType.NONE, (long)0);
                ClosestItemDist = 0.3f;

                LocalCoordsScratchpad.Clear();
                ScreenCoordsScratchpad.Clear();

                if (ActionMode == ActionSelectPosition)
                {
                    AddTextSprite("><", CursorPos2D, 1, "Debug");
                    if (OnRelease)
                    {
                        if (SelectFlatPos == Vector2.PositiveInfinity)
                        {
                            SelectFlatPos = CursorPos2D;
                        }
                        else
                        {
                            SelectedPosition = FlatPosToGlobalPos(SelectFlatPos, CursorPos2D);

                            SelectPositionCallback(timestamp);

                            SelectFlatPos = Vector2.PositiveInfinity;
                            ActionMode    = ActionNone;
                        }
                        OnRelease = false;
                    }

                    if (SelectFlatPos != Vector2.PositiveInfinity)
                    {
                        var selectAltitudePos = SelectFlatPos;
                        selectAltitudePos.Y = CursorPos2D.Y;
                        var midPosition = (selectAltitudePos + SelectFlatPos) * 0.5f;
                        var lineLength  = Math.Abs(selectAltitudePos.Y - SelectFlatPos.Y);
                        AddSprite("CircleHollow", selectAltitudePos, new Vector2(20, 20));

                        AddSprite("CircleHollow", SelectFlatPos, new Vector2(30, 30 * (float)CosViewDegree));
                        AddSprite("SquareSimple", midPosition, new Vector2(2, lineLength * PixelsPerMeter));
                    }
                }

                foreach (var kvp in intelItems)
                {
                    Vector3D localCoords;
                    Vector2  flatPosition, altitudePosition;

                    GetMapCoordsFromIntel(kvp.Value, timestamp, out localCoords, out flatPosition, out altitudePosition);

                    ScreenCoordsScratchpad.Add(flatPosition);
                    ScreenCoordsScratchpad.Add(altitudePosition);
                    LocalCoordsScratchpad.Add(localCoords);

                    DebugBuilder.AppendLine(localCoords.ToString());

                    var distToItem = (altitudePosition - CursorPos2D).Length();
                    if (distToItem < ClosestItemDist)
                    {
                        ClosestItemDist = distToItem;
                        ClosestItemKey  = kvp.Key;
                    }
                }

                DrawContextMenu();

                if (ActionMode == ActionNone)
                {
                    SelectionCandidates.Add(ClosestItemKey);
                    if (OnRelease)
                    {
                        if (ClosestItemKey.Item1 == IntelItemType.NONE)
                        {
                            SelectedItems.Clear();
                        }
                        else if (ClosestItemKey.Item1 != IntelItemType.Waypoint)
                        {
                            if (SelectedItems.Count > 0 && SelectedItems[0].Item2 != ClosestItemKey.Item2)
                            {
                                SelectedItems.Clear();
                            }
                            SelectedItems.Add(ClosestItemKey);
                        }
                    }
                }

                i = 0;
                foreach (var kvp in intelItems)
                {
                    AddFleetIntelToMap(kvp.Value, timestamp, LocalCoordsScratchpad[i], ScreenCoordsScratchpad[2 * i], ScreenCoordsScratchpad[2 * i + 1]);
                    i++;
                }

                // var text = Turret.IsShooting ? "[><]" : "><";
                // AddTextSprite(text, CursorPos2D, 2, "Debug");

                foreach (var kvp in Panels)
                {
                    DrawSpritesForPanel(kvp.Key);
                }

                OnRelease = false;
            }

            LastFrameMouseDown = Turret.IsShooting;
        }
コード例 #10
0
        public void Update(TimeSpan timestamp, UpdateFrequency updateFlags)
        {
            if (timestamp == TimeSpan.Zero)
            {
                return;
            }
            foreach (var bird in Hummingbirds)
            {
                if (bird.IsAlive())
                {
                    bird.Update();
                }
                else
                {
                    DeadBirds.Add(bird);
                }
            }

            foreach (var bird in DeadBirds)
            {
                DeregisterBird(bird);
            }

            runs++;
            if (runs % 20 == 0)
            {
                var intelItems = IntelProvider.GetFleetIntelligences(timestamp);

                // Get the top targets
                TopEnemies.Clear();
                EnemyToScore.Clear();

                foreach (var intelItem in intelItems)
                {
                    if (intelItem.Key.Item1 == IntelItemType.Enemy)
                    {
                        var esi  = (EnemyShipIntel)intelItem.Value;
                        var dist = (esi.GetPositionFromCanonicalTime(timestamp + IntelProvider.CanonicalTimeDiff) - Context.Reference.WorldMatrix.Translation).Length();
                        if (dist > MaxEngagementDist)
                        {
                            continue;
                        }

                        var priority = IntelProvider.GetPriority(esi.ID);
                        var size     = esi.Radius;

                        if (size < MinEngagementSize && priority < 3)
                        {
                            continue;
                        }

                        if (priority < 2)
                        {
                            continue;
                        }

                        int score = (int)(priority * 10000 + size);

                        EnemyToScore[esi] = score;

                        for (int i = 0; i <= TopEnemies.Count; i++)
                        {
                            if (i == TopEnemies.Count || score > EnemyToScore[TopEnemies[i]])
                            {
                                TopEnemies.Insert(i, esi);
                                break;
                            }
                        }
                    }
                }

                // Determine how many birds should be assigned to each enemy
                EnemyToNumBirds.Clear();

                int totalNeededBirds = 0;

                for (int i = 0; i < TopEnemies.Count && i < 4; i++)
                {
                    EnemyToNumBirds[TopEnemies[i]]      = EnemyCountToNumBirdsPerEnemy[TopEnemies.Count][i];
                    EnemyToAssignedBirds[TopEnemies[i]] = 0;
                    totalNeededBirds += EnemyToNumBirds[TopEnemies[i]];
                }

                // Remove excess birds from enemies
                foreach (var bird in Hummingbirds)
                {
                    var birdTargetID = BirdToEnemy[bird];
                    if (birdTargetID == 0)
                    {
                        continue;
                    }

                    if (!bird.IsCombatCapable())
                    {
                        BirdToEnemy[bird] = 0;
                        continue;
                    }

                    var birdTargetKey = MyTuple.Create(IntelItemType.Enemy, birdTargetID);
                    if (!intelItems.ContainsKey(birdTargetKey))
                    {
                        BirdToEnemy[bird] = 0;
                        continue;
                    }

                    var birdTarget = (EnemyShipIntel)intelItems[birdTargetKey];
                    if (!EnemyToNumBirds.ContainsKey(birdTarget) || EnemyToNumBirds[birdTarget] == 0)
                    {
                        BirdToEnemy[bird] = 0;
                        continue;
                    }

                    EnemyToNumBirds[birdTarget]--;
                    totalNeededBirds--;
                }

                // Assign birds to enemies
                foreach (var bird in Hummingbirds)
                {
                    if (totalNeededBirds == 0)
                    {
                        break;
                    }

                    // Bird can't fight, keep looking
                    if (!bird.IsCombatCapable())
                    {
                        continue;
                    }

                    // Bird already has target, keep looking
                    if (BirdToEnemy[bird] != 0)
                    {
                        continue;
                    }

                    EnemyShipIntel targetEnemy = null;
                    foreach (var enemy in EnemyToNumBirds.Keys)
                    {
                        if (EnemyToNumBirds[enemy] > 0)
                        {
                            targetEnemy = enemy;
                            break;
                        }
                    }

                    BirdToEnemy[bird] = targetEnemy.ID;
                    EnemyToNumBirds[targetEnemy]--;
                    totalNeededBirds--;
                }

                NeedsMoreBirds = totalNeededBirds > 0;
                int birdIndex;

                // ASSUME birds are not far enough from main controller that gravity direction matters too much
                var gravDir = Controller.GetTotalGravity();
                gravDir.Normalize();

                // For each enemy, assign bird target and destination
                foreach (var enemy in TopEnemies)
                {
                    birdIndex = 0;
                    foreach (var bird in Hummingbirds)
                    {
                        if (BirdToEnemy[bird] != enemy.ID)
                        {
                            continue;
                        }

                        if (bird.Gats.Count == 0)
                        {
                            continue;
                        }
                        var birdAltitudeTheta = Math.PI * ((runs / (BirdSineConstantSeconds * 30) % 2) - 1);
                        var birdSwayTheta     = Math.PI * ((runs / (BirdPendulumConstantSeconds * 30) % 2) - 1);
                        var targetPos         = enemy.GetPositionFromCanonicalTime(timestamp + IntelProvider.CanonicalTimeDiff);

                        bird.SetTarget(targetPos, enemy.GetVelocity() - gravDir * (float)TrigHelpers.FastCos(birdAltitudeTheta) * 2);

                        var targetToBase = bird.Base.WorldMatrix.Translation - targetPos;
                        targetToBase -= VectorHelpers.VectorProjection(targetToBase, gravDir);
                        var targetToBaseDist = targetToBase.Length();
                        targetToBase.Normalize();

                        var engageLocationLocus    = targetToBase * Math.Min(600, targetToBaseDist + 400) + targetPos;
                        var engageLocationSwayDir  = targetToBase.Cross(gravDir);
                        var engageLocationSwayDist = (TrigHelpers.FastCos(birdSwayTheta) - EnemyToAssignedBirds[enemy] * 0.5 + birdIndex + 0.5) * 100;

                        bird.SetDest(engageLocationLocus + engageLocationSwayDist * engageLocationSwayDir);

                        var birdDir = bird.Controller.WorldMatrix.Translation - Controller.WorldMatrix.Translation;
                        birdDir -= VectorHelpers.VectorProjection(birdDir, gravDir);;
                        var birdDist = birdDir.Length();

                        bird.Drive.DesiredAltitude = birdDist < 100 ? Hummingbird.RecommendedServiceCeiling :
                                                     (float)TrigHelpers.FastSin(birdAltitudeTheta + Math.PI * 0.5) *
                                                     (Hummingbird.RecommendedServiceCeiling - Hummingbird.RecommendedServiceFloor) + Hummingbird.RecommendedServiceFloor;

                        birdIndex++;
                    }
                }

                // Assign orbit task for unassigned birds
                int numReserveBirds = 0;
                foreach (var bird in Hummingbirds)
                {
                    if (BirdToEnemy[bird] == 0 && bird.IsCombatCapable())
                    {
                        numReserveBirds++;
                    }
                }
                birdIndex = 0;
                var randomPoint = new Vector3D(190, 2862, 809);
                randomPoint -= VectorHelpers.VectorProjection(randomPoint, gravDir);
                randomPoint.Normalize();

                var randomPointCross = randomPoint.Cross(gravDir);

                foreach (var bird in Hummingbirds)
                {
                    if (BirdToEnemy[bird] != 0)
                    {
                        continue;
                    }
                    bird.SetTarget(Vector3D.Zero, Vector3D.Zero);
                    bird.Drive.DesiredAltitude = 30;

                    if (bird.IsCombatCapable() && !bird.IsRetiring)
                    {
                        var birdOrbitTheta = Math.PI * (((2 * birdIndex / (float)numReserveBirds) + runs / (BirdOrbitSeconds * 30)) % 2 - 1);

                        var birdOrbitDest = Controller.WorldMatrix.Translation +
                                            TrigHelpers.FastCos(birdOrbitTheta) * randomPoint * BirdOrbitDist +
                                            TrigHelpers.FastSin(birdOrbitTheta) * randomPointCross * BirdOrbitDist;

                        bird.SetDest(birdOrbitDest);

                        birdIndex++;
                    }
                    else if (!bird.IsRetiring)
                    {
                        RetireBird(bird);
                    }
                    else if (bird.IsRetiring)
                    {
                        if (!bird.IsLanding)
                        {
                            var birdDir = bird.Controller.WorldMatrix.Translation - bird.Destination;
                            birdDir -= VectorHelpers.VectorProjection(birdDir, gravDir);
                            var birdDist = birdDir.Length();
                            birdDir.Normalize();

                            if (birdDist < 50)
                            {
                                bird.SetDest(Vector3D.Zero);
                                bird.Drive.Flush();
                                foreach (var engine in bird.Drive.HoverEngines)
                                {
                                    engine.AltitudeMin = 0;
                                }
                                bird.IsLanding = true;
                            }
                        }
                        else
                        {
                            double altitude;
                            bird.Controller.TryGetPlanetElevation(MyPlanetElevation.Surface, out altitude);
                            if (altitude < 6)
                            {
                                foreach (var engine in bird.Drive.HoverEngines)
                                {
                                    engine.Block.Enabled = false;
                                    DeadBirds.Add(bird);
                                }
                            }
                        }
                    }
                }
            }

            foreach (var cradle in Cradles)
            {
                if (cradle == null)
                {
                    continue;
                }
                cradle.Update();
            }

            if (runs % 60 == 0)
            {
                BirdReleaseTimeout--;
                for (int i = 0; i < Cradles.Count(); i++)
                {
                    if (Cradles[i] == null)
                    {
                        continue;
                    }
                    if (Cradles[i].Hummingbird == null)
                    {
                        Cradles[i].CheckHummingbird();
                    }
                    else if (NeedsMoreBirds && BirdReleaseTimeout <= 0)
                    {
                        Hummingbird bird = Cradles[i].Release();
                        bird.Base = Context.Reference;
                        RegisterBird(bird);
                        BirdReleaseTimeout = 5;
                    }
                }
            }

            DeadBirds.Clear();
        }
コード例 #11
0
        public void Drive(Vector3D Destination)
        {
            if (Destination == Vector3D.Zero)
            {
                return;
            }

            if (GravAngle > Math.PI * 0.1)
            {
                foreach (var engine in HoverEngines)
                {
                    engine.Block.Enabled      = true;
                    engine.OverridePercentage = 0;
                    engine.AltitudeMin        = DesiredAltitude / VertiHoriForceRatio;
                }
                return;
            }

            var gravDir = Controller.GetNaturalGravity();
            var gravStr = gravDir.Length();

            gravDir.Normalize();
            var destDir = Destination - Controller.WorldMatrix.Translation;

            destDir -= VectorHelpers.VectorProjection(destDir, gravDir);
            var dist = destDir.Length();

            Arrived = dist < 20;
            destDir.Normalize();

            var maxSpeed   = SpeedLimit == 0 ? Math.Min(100, GetMaxSpeedFromBrakingDistance((float)dist)) : SpeedLimit;
            var currentVel = Controller.GetShipVelocities().LinearVelocity;
            var horiVel    = currentVel - VectorHelpers.VectorProjection(Controller.GetShipVelocities().LinearVelocity, gravDir);
            var vertiVel   = currentVel.Dot(-gravDir);
            var accelDir   = maxSpeed * destDir - horiVel;

            accelDir.Normalize();
            var mass      = Controller.CalculateShipMass().PhysicalMass;
            var gravForce = gravStr * mass;

            DirForces.Clear();
            Dirs.Clear();

            Dirs.Add(Controller.WorldMatrix.Forward);
            Dirs.Add(Controller.WorldMatrix.Down);
            Dirs.Add(Controller.WorldMatrix.Left);

            float  alpha = 0;
            double altitude;

            Controller.TryGetPlanetElevation(MyPlanetElevation.Surface, out altitude);
            DesiredVerticalVel = DesiredAltitude - altitude;
            var altAdjust = DesiredVerticalVel - vertiVel;

            Vector3D PrimaryDriveDir   = Vector3D.Zero;
            Vector3D SecondaryDriveDir = Vector3D.Zero;
            Vector3D OpposDriveDir     = Vector3D.Zero;

            foreach (var dir in Dirs)
            {
                var engineDir = dir;
                engineDir -= VectorHelpers.VectorProjection(engineDir, gravDir);
                engineDir.Normalize();

                var engineAngleDiff = VectorHelpers.VectorAngleBetween(engineDir, accelDir);
                if (engineAngleDiff < 0.3333333333333 * Math.PI)
                {
                    DirForces[dir] = 0;
                    OpposDriveDir  = dir;
                }
                else if (engineAngleDiff > 2 * 0.3333333333333 * Math.PI)
                {
                    DirForces[dir]  = 1f;
                    PrimaryDriveDir = dir;
                }
                else
                {
                    var aPrime = 1 / (TrigHelpers.fastTan(engineAngleDiff - Math.PI * 0.333333333) * sqrt3inv + 1);
                    DirForces[dir]    = (float)(1 - aPrime) * 2;
                    SecondaryDriveDir = dir;
                    alpha             = DirForces[dir];
                }
            }

            var primaryDriveForce   = MaxForce * VerticalForceRatio;
            var secondaryDriveForce = primaryDriveForce * alpha;

            var totalUpForce = primaryDriveForce + secondaryDriveForce;
            var multiplier   = (gravForce + altAdjust * mass) / totalUpForce;

            Status = $"{altAdjust}, {dist}";

            if (PrimaryDriveDir != Vector3D.Zero)
            {
                DirForces[PrimaryDriveDir] = Math.Max(0.01f, (float)multiplier);
            }
            if (SecondaryDriveDir != Vector3D.Zero)
            {
                DirForces[SecondaryDriveDir] = (float)Math.Max(0.01f, alpha * (float)multiplier);
            }

            var altMin = 1;

            if (altitude > 7)
            {
                altMin = 6;
            }
            if (altitude > 40)
            {
                altMin = 10;
            }

            foreach (var engine in HoverEngines)
            {
                engine.AltitudeMin        = altMin;
                engine.Block.Enabled      = OpposDriveDir != engine.Block.WorldMatrix.Forward;
                engine.OverridePercentage = DirForces[engine.Block.WorldMatrix.Forward];
            }
        }