void RescanForTargets(Actor self) { targetCountdown = WormInfo.TargetRescanInterval; // If close enough, we don't care about other actors. var target = self.World.FindActorsInCircle(self.CenterPosition, WormInfo.IgnoreNoiseAttackRange) .FirstOrDefault(x => attackTrait.HasAnyValidWeapons(Target.FromActor(x))); if (target != null) { self.CancelActivity(); attackTrait.ResolveOrder(self, new Order("Attack", target, true) { TargetActor = target }); return; } Func <Actor, bool> isValidTarget = a => { if (!a.Info.HasTraitInfo <AttractsWormsInfo>()) { return(false); } return(mobile.CanEnterCell(a.Location, null, false)); }; var actorsInRange = self.World.FindActorsInCircle(self.CenterPosition, WormInfo.MaxSearchRadius) .Where(isValidTarget).SelectMany(a => a.TraitsImplementing <AttractsWorms>()); var noiseDirection = actorsInRange.Aggregate(WVec.Zero, (a, b) => a + b.AttractionAtPosition(self.CenterPosition)); // No target was found if (noiseDirection == WVec.Zero) { return; } var moveTo = self.World.Map.CellContaining(self.CenterPosition + noiseDirection); while (!self.World.Map.Contains(moveTo) || !mobile.CanEnterCell(moveTo, null, false)) { noiseDirection /= 2; moveTo = self.World.Map.CellContaining(self.CenterPosition + noiseDirection); } // Don't get stuck when the noise is distributed evenly! This will make the worm wander instead of trying to move to where it already is if (moveTo == self.Location) { self.CancelActivity(); return; } self.QueueActivity(false, mobile.MoveTo(moveTo, 3)); IsMovingTowardTarget = true; }