public void UnblockRefinery(Actor self) { // Check that we're not in a critical location and being useless (refinery drop-off): var lastproc = LastLinkedProc ?? LinkedProc; if (lastproc != null && !lastproc.Destroyed) { var deliveryLoc = lastproc.Location + lastproc.Trait<IAcceptResources>().DeliveryOffset; if (self.Location == deliveryLoc) { // Get out of the way: var mobile = self.Trait<Mobile>(); var harv = self.Trait<Harvester>(); var moveTo = harv.LastHarvestedCell ?? (deliveryLoc + new CVec(0, 4)); self.QueueActivity(mobile.MoveTo(moveTo, 1)); self.SetTargetLine(Target.FromCell(self.World, moveTo), Color.Gray, false); var territory = self.World.WorldActor.TraitOrDefault<ResourceClaimLayer>(); if (territory != null) territory.ClaimResource(self, moveTo); var notify = self.TraitsImplementing<INotifyHarvesterAction>(); var next = new FindResources(); foreach (var n in notify) n.MovingToResources(self, moveTo, next); self.QueueActivity(new FindResources()); return; } } }
public override Activity Tick(Actor self) { if (IsCanceled || NextActivity != null) { return(NextActivity); } var harv = self.Trait <Harvester>(); if (harv.IsFull) { return(Util.SequenceActivities(new DeliverResources(), NextActivity)); } var harvInfo = self.Info.Traits.Get <HarvesterInfo>(); var mobile = self.Trait <Mobile>(); var mobileInfo = self.Info.Traits.Get <MobileInfo>(); var resLayer = self.World.WorldActor.Trait <ResourceLayer>(); var territory = self.World.WorldActor.TraitOrDefault <ResourceClaimLayer>(); // Determine where to search from and how far to search: var searchFromLoc = harv.LastOrderLocation ?? (harv.LastLinkedProc ?? harv.LinkedProc ?? self).Location; var searchRadius = harv.LastOrderLocation.HasValue ? harvInfo.SearchFromOrderRadius : harvInfo.SearchFromProcRadius; var searchRadiusSquared = searchRadius * searchRadius; // Find harvestable resources nearby: var path = self.World.WorldActor.Trait <IPathFinder>().FindPath( PathSearch.Search(self.World, mobileInfo, self, true) .WithHeuristic(loc => { // Avoid this cell: if (avoidCell.HasValue && loc == avoidCell.Value) { return(EstimateDistance(loc, searchFromLoc) + Constants.CellCost); } // Don't harvest out of range: var distSquared = (loc - searchFromLoc).LengthSquared; if (distSquared > searchRadiusSquared) { return(EstimateDistance(loc, searchFromLoc) + Constants.CellCost * 2); } // Get the resource at this location: var resType = resLayer.GetResource(loc); if (resType == null) { return(EstimateDistance(loc, searchFromLoc) + Constants.CellCost); } // Can the harvester collect this kind of resource? if (!harvInfo.Resources.Contains(resType.Info.Name)) { return(EstimateDistance(loc, searchFromLoc) + Constants.CellCost); } if (territory != null) { // Another harvester has claimed this resource: ResourceClaim claim; if (territory.IsClaimedByAnyoneElse(self, loc, out claim)) { return(EstimateDistance(loc, searchFromLoc) + Constants.CellCost); } } return(0); }) .FromPoint(self.Location)); if (path.Count == 0) { if (!harv.IsEmpty) { return(new DeliverResources()); } else { // Get out of the way if we are: harv.UnblockRefinery(self); var randFrames = 125 + self.World.SharedRandom.Next(-35, 35); if (NextActivity != null) { return(Util.SequenceActivities(NextActivity, new Wait(randFrames), new FindResources())); } else { return(Util.SequenceActivities(new Wait(randFrames), new FindResources())); } } } // Attempt to claim a resource as ours: if (territory != null) { if (!territory.ClaimResource(self, path[0])) { return(Util.SequenceActivities(new Wait(25), new FindResources())); } } // If not given a direct order, assume ordered to the first resource location we find: if (harv.LastOrderLocation == null) { harv.LastOrderLocation = path[0]; } self.SetTargetLine(Target.FromCell(self.World, path[0]), Color.Red, false); var notify = self.TraitsImplementing <INotifyHarvesterAction>(); var next = new FindResources(); foreach (var n in notify) { n.MovingToResources(self, path[0], next); } return(Util.SequenceActivities(mobile.MoveTo(path[0], 1), new HarvestResource(), new FindResources())); }
public void ResolveOrder(Actor self, Order order) { if (order.OrderString == "Harvest") { // NOTE: An explicit harvest order allows the harvester to decide which refinery to deliver to. LinkProc(self, OwnerLinkedProc = null); idleSmart = true; self.CancelActivity(); var mobile = self.Trait<Mobile>(); if (order.TargetLocation != CPos.Zero) { var loc = order.TargetLocation; var territory = self.World.WorldActor.TraitOrDefault<ResourceClaimLayer>(); if (territory != null) { // Find the nearest claimable cell to the order location (useful for group-select harvest): loc = mobile.NearestCell(loc, p => mobile.CanEnterCell(p) && territory.ClaimResource(self, p), 1, 6); } else { // Find the nearest cell to the order location (useful for group-select harvest): var taken = new HashSet<CPos>(); loc = mobile.NearestCell(loc, p => mobile.CanEnterCell(p) && taken.Add(p), 1, 6); } self.QueueActivity(mobile.MoveTo(loc, 0)); self.SetTargetLine(Target.FromCell(self.World, loc), Color.Red); var notify = self.TraitsImplementing<INotifyHarvesterAction>(); var next = new FindResources(); foreach (var n in notify) n.MovingToResources(self, loc, next); LastOrderLocation = loc; } else { // A bot order gives us a CPos.Zero TargetLocation, so find some good resources for him: var loc = FindNextResourceForBot(self); // No more resources? Oh well. if (!loc.HasValue) return; self.QueueActivity(mobile.MoveTo(loc.Value, 0)); self.SetTargetLine(Target.FromCell(self.World, loc.Value), Color.Red); LastOrderLocation = loc; } // This prevents harvesters returning to an empty patch when the player orders them to a new patch: LastHarvestedCell = LastOrderLocation; self.QueueActivity(new FindResources()); } else if (order.OrderString == "Deliver") { // NOTE: An explicit deliver order forces the harvester to always deliver to this refinery. var iao = order.TargetActor.TraitOrDefault<IAcceptResources>(); if (iao == null || !iao.AllowDocking || !IsAcceptableProcType(order.TargetActor)) return; if (order.TargetActor != OwnerLinkedProc) LinkProc(self, OwnerLinkedProc = order.TargetActor); if (IsEmpty) return; idleSmart = true; self.SetTargetLine(Target.FromOrder(self.World, order), Color.Green); self.CancelActivity(); self.QueueActivity(new DeliverResources()); var notify = self.TraitsImplementing<INotifyHarvesterAction>(); var next = new DeliverResources(); foreach (var n in notify) n.MovingToRefinery(self, order.TargetLocation, next); } else if (order.OrderString == "Stop" || order.OrderString == "Move") { var notify = self.TraitsImplementing<INotifyHarvesterAction>(); foreach (var n in notify) n.MovementCancelled(self); // Turn off idle smarts to obey the stop/move: idleSmart = false; } }