public override IEnumerable <TargetLineNode> TargetLineNodes(Actor self) { if (returnToBase) { yield return(new TargetLineNode(Target.FromActor(rearmTarget), moveInfo.GetTargetLineColor())); } if (minefield == null || minefield.Count == 0) { yield break; } var nextCell = NextValidCell(self); if (nextCell != null) { yield return(new TargetLineNode(Target.FromCell(self.World, nextCell.Value), minelayer.Info.TargetLineColor)); } foreach (var c in minefield) { yield return(new TargetLineNode(Target.FromCell(self.World, c), minelayer.Info.TargetLineColor, tile: minelayer.Tile)); } }
public override bool Tick(Actor self) { // Wait for the cooldown to expire before releasing the unit if this was cancelled if (IsCanceling && remainingTicks > 0) { remainingTicks--; return(false); } var isHostInvalid = host.Type != TargetType.Actor || !host.Actor.IsInWorld; var isCloseEnough = false; if (!isHostInvalid) { // Negative means there's no distance limit. // If RepairableNear, use TargetablePositions instead of CenterPosition // to ensure the actor moves close enough to the host. // Otherwise check against host CenterPosition. if (closeEnough < WDist.Zero) { isCloseEnough = true; } else if (repairableNear != null) { isCloseEnough = host.IsInRange(self.CenterPosition, closeEnough); } else { isCloseEnough = (host.CenterPosition - self.CenterPosition).HorizontalLengthSquared <= closeEnough.LengthSquared; } } // This ensures transports are also cancelled when the host becomes invalid if (!IsCanceling && isHostInvalid) { Cancel(self, true); } if (IsCanceling || isHostInvalid) { // Only tick host INotifyResupply traits one last time if host is still alive if (!isHostInvalid) { foreach (var notifyResupply in notifyResupplies) { notifyResupply.ResupplyTick(host.Actor, self, ResupplyType.None); } } // HACK: If the activity is cancelled while we're on the host resupplying (or about to start resupplying), // move actor outside the resupplier footprint to prevent it from blocking other actors. // Additionally, if the host is no longer valid, make aircaft take off. if (isCloseEnough || isHostInvalid) { OnResupplyEnding(self, isHostInvalid); } return(true); } else if (activeResupplyTypes != 0 && aircraft == null && !isCloseEnough) { var targetCell = self.World.Map.CellContaining(host.Actor.CenterPosition); QueueChild(move.MoveWithinRange(host, closeEnough, targetLineColor: moveInfo.GetTargetLineColor())); // HACK: Repairable needs the actor to move to host center. // TODO: Get rid of this or at least replace it with something less hacky. if (repairableNear == null) { QueueChild(move.MoveTo(targetCell, targetLineColor: moveInfo.GetTargetLineColor())); } var delta = (self.CenterPosition - host.CenterPosition).LengthSquared; transportCallers.FirstOrDefault(t => t.MinimumDistance.LengthSquared < delta)?.RequestTransport(self, targetCell); return(false); } // We don't want to trigger this until we've reached the resupplier and can start resupplying if (!actualResupplyStarted && activeResupplyTypes > 0) { actualResupplyStarted = true; foreach (var notifyResupply in notifyResupplies) { notifyResupply.BeforeResupply(host.Actor, self, activeResupplyTypes); } foreach (var br in notifyBeingResupplied) { br.StartingResupply(self, host.Actor); } } if (activeResupplyTypes.HasFlag(ResupplyType.Repair)) { RepairTick(self); } if (activeResupplyTypes.HasFlag(ResupplyType.Rearm)) { RearmTick(self); } foreach (var notifyResupply in notifyResupplies) { notifyResupply.ResupplyTick(host.Actor, self, activeResupplyTypes); } if (activeResupplyTypes == 0) { OnResupplyEnding(self); return(true); } return(false); }