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)))); }
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()); } } }
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); } }
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); } } } } }
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(); }