private void SelectPositionCallbackMove(TimeSpan timestamp) { IFleetIntelligence selected; var intels = IntelProvider.GetFleetIntelligences(timestamp); if (intels.TryGetValue(SelectedItems[0], out selected)) { var waypoint = new Waypoint(); waypoint.Position = SelectedPosition; IntelProvider.ReportFleetIntelligence(waypoint, timestamp); IntelProvider.ReportCommand((FriendlyShipIntel)selected, TaskType.Move, MyTuple.Create(IntelItemType.Waypoint, waypoint.ID), timestamp); } }
public void Update(TimeSpan timestamp, UpdateFrequency updateFlags) { if (timestamp.TotalSeconds < 2) { return; // We just started up, wait up to two seconds to receive intel } if (IntelProvider != null && HomeID != -1) { var intelItems = IntelProvider.GetFleetIntelligences(timestamp); var intelKey = MyTuple.Create(IntelItemType.Dock, HomeID); if (!intelItems.ContainsKey(intelKey)) { HomeID = -1; return; } var dock = (DockIntel)intelItems[intelKey]; if (dock.OwnerID != Context.Reference.CubeGrid.EntityId) { HomeID = -1; } } }
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++; }
public void Update(TimeSpan timestamp, UpdateFrequency updateFlags) { runs++; if (WCAPI == null && runs % 12 == 0) { WCAPI = new WcPbApi(); if (WCAPI.Activate(Context.Program.Me)) { GetParts(); } else { WCAPI = null; } } TargetIntel = null; var canonicalTime = timestamp + IntelProvider.CanonicalTimeDiff; foreach (var turret in Turrets) { if (!turret.HasTarget) { continue; } var target = turret.GetTargetedEntity(); if (target.IsEmpty()) { continue; } if (target.Type != MyDetectedEntityType.SmallGrid && target.Type != MyDetectedEntityType.LargeGrid) { continue; } if (target.Relationship != MyRelationsBetweenPlayerAndBlock.Enemies) { continue; } var intelDict = IntelProvider.GetFleetIntelligences(timestamp); var key = MyTuple.Create(IntelItemType.Enemy, target.EntityId); if (intelDict.ContainsKey(key)) { turret.ResetTargetingToDefault(); continue; } TargetIntel = intelDict.ContainsKey(key) ? (EnemyShipIntel)intelDict[key] : new EnemyShipIntel(); } if (fireCounter > 0) { fireCounter--; } if (fireCounter == 0) { HoldFire(); } if (engageCounter > 0) { engageCounter--; } }
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; }
public void AddTask(TaskType taskType, MyTuple <IntelItemType, long> intelKey, CommandType commandType, int arguments, TimeSpan canonicalTime) { if (commandType == CommandType.Override) { TaskQueue.Clear(); } if (TaskGenerators.ContainsKey(taskType)) { ITask Task = TaskGenerators[taskType].GenerateTask(taskType, intelKey, IntelProvider.GetFleetIntelligences(canonicalTime - IntelProvider.CanonicalTimeDiff), canonicalTime, Context.Reference.CubeGrid.EntityId); if (Task is NullTask) { return; } TaskQueue.Enqueue(Task); } }
public void Update(TimeSpan timestamp, UpdateFrequency updateFlags) { runs++; if (runs % RotorHingeTurret.TURRET_TIMESTEP == 0 && runs > 60) { if (Context.WCAPI == null) { return; } statusBuilder.Clear(); var target = Context.WCAPI.GetAiFocus(Context.Reference.CubeGrid.EntityId); statusBuilder.AppendLine(target == null ? "NULL" : target.Value.Name); // Get ordered list of targets var intelItems = IntelProvider.GetFleetIntelligences(timestamp); OrderedTargets.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); if (target != null && target.Value.EntityId == intelItem.Key.Item2) { score = int.MaxValue; } EnemyToScore[esi] = score; for (int i = 0; i <= OrderedTargets.Count; i++) { if (i == OrderedTargets.Count || score > EnemyToScore[OrderedTargets[i]]) { OrderedTargets.Insert(i, esi); break; } } } } // Each turret gets target solution foreach (var turret in TurretsDict.Values) { turret.SelectTarget(OrderedTargets, timestamp); turret.AimAndFire(); if (turret.WeaponGroup.WCAPI == null) { turret.WeaponGroup.WCAPI = Context.WCAPI; } turret.WeaponGroup.Update(RotorHingeTurret.TURRET_TIMESTEP); statusBuilder.AppendLine($"{turret.Azimuth.CustomName}: {turret.GetStatus()}"); } } }
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(); }