public override Activity Tick(Actor self) { if (NextActivity != null) { return(NextActivity); } var movement = self.Trait <IMove>(); var harv = self.Trait <Harvester>(); // Find the nearest best refinery if not explicitly ordered to a specific refinery: if (harv.OwnerLinkedProc == null || !harv.OwnerLinkedProc.IsInWorld) { // Maybe we lost the owner-linked refinery: harv.OwnerLinkedProc = null; if (self.World.WorldTick - chosenTicks > NextChooseTime) { harv.ChooseNewProc(self, null); chosenTicks = self.World.WorldTick; } } else { harv.LinkProc(self, harv.OwnerLinkedProc); } if (harv.LinkedProc == null || !harv.LinkedProc.IsInWorld) { harv.ChooseNewProc(self, null); } if (harv.LinkedProc == null) // no procs exist; check again in 1s. { return(Util.SequenceActivities(new Wait(25), this)); } var proc = harv.LinkedProc; var iao = proc.Trait <IAcceptResources>(); self.SetTargetLine(Target.FromActor(proc), Color.Green, false); if (self.Location != proc.Location + iao.DeliveryOffset) { var notify = self.TraitsImplementing <INotifyHarvesterAction>(); var next = new DeliverResources(); foreach (var n in notify) { n.MovingToRefinery(self, proc.Location + iao.DeliveryOffset, next); } return(Util.SequenceActivities(movement.MoveTo(proc.Location + iao.DeliveryOffset, 0), this)); } if (!isDocking) { isDocking = true; iao.OnDock(self, this); } return(Util.SequenceActivities(new Wait(10), this)); }
public override Activity Tick(Actor self) { if (IsCanceled || NextActivity != null) return NextActivity; var deliver = new DeliverResources(self); if (harv.IsFull) return Util.SequenceActivities(deliver, NextActivity); var closestHarvestablePosition = ClosestHarvestablePos(self); // If no harvestable position could be found, either deliver the remaining resources // or get out of the way and do not disturb. if (!closestHarvestablePosition.HasValue) { if (!harv.IsEmpty) return deliver; var cachedPosition = self.Location; harv.UnblockRefinery(self); // Only do this if UnblockRefinery did nothing. if (self.Location == cachedPosition) { var unblockCell = harv.LastHarvestedCell ?? (self.Location + harvInfo.UnblockCell); var moveTo = mobile.NearestMoveableCell(unblockCell, 2, 5); self.QueueActivity(mobile.MoveTo(moveTo, 1)); self.SetTargetLine(Target.FromCell(self.World, moveTo), Color.Gray, false); } var randFrames = self.World.SharedRandom.Next(100, 175); return Util.SequenceActivities(NextActivity, new Wait(randFrames), this); } else { var next = this; // Attempt to claim a resource as ours if (territory != null) { if (!territory.ClaimResource(self, closestHarvestablePosition.Value)) return Util.SequenceActivities(new Wait(25), next); } // If not given a direct order, assume ordered to the first resource location we find: if (!harv.LastOrderLocation.HasValue) harv.LastOrderLocation = closestHarvestablePosition; self.SetTargetLine(Target.FromCell(self.World, closestHarvestablePosition.Value), Color.Red, false); var notify = self.TraitsImplementing<INotifyHarvesterAction>(); foreach (var n in notify) n.MovingToResources(self, closestHarvestablePosition.Value, next); return Util.SequenceActivities(mobile.MoveTo(closestHarvestablePosition.Value, 1), new HarvestResource(self), next); } }
public override Activity Tick(Actor self) { if (IsCanceled || NextActivity != null) return NextActivity; var deliver = new DeliverResources(self); if (harv.IsFull) return ActivityUtils.SequenceActivities(deliver, NextActivity); var closestHarvestablePosition = ClosestHarvestablePos(self); // If no harvestable position could be found, either deliver the remaining resources // or get out of the way and do not disturb. if (!closestHarvestablePosition.HasValue) { if (!harv.IsEmpty) return deliver; var unblockCell = harv.LastHarvestedCell ?? (self.Location + harvInfo.UnblockCell); var moveTo = mobile.NearestMoveableCell(unblockCell, 2, 5); self.QueueActivity(mobile.MoveTo(moveTo, 1)); self.SetTargetLine(Target.FromCell(self.World, moveTo), Color.Gray, false); // TODO: The harvest-deliver-return sequence is a horrible mess of duplicated code and edge-cases var notify = self.TraitsImplementing<INotifyHarvesterAction>(); foreach (var n in notify) n.MovingToResources(self, moveTo, this); var randFrames = self.World.SharedRandom.Next(100, 175); // Avoid creating an activity cycle var next = NextActivity; NextActivity = null; return ActivityUtils.SequenceActivities(next, new Wait(randFrames), this); } else { // Attempt to claim a resource as ours if (territory != null && !territory.ClaimResource(self, closestHarvestablePosition.Value)) return ActivityUtils.SequenceActivities(new Wait(25), this); // If not given a direct order, assume ordered to the first resource location we find: if (!harv.LastOrderLocation.HasValue) harv.LastOrderLocation = closestHarvestablePosition; self.SetTargetLine(Target.FromCell(self.World, closestHarvestablePosition.Value), Color.Red, false); // TODO: The harvest-deliver-return sequence is a horrible mess of duplicated code and edge-cases var notify = self.TraitsImplementing<INotifyHarvesterAction>(); foreach (var n in notify) n.MovingToResources(self, closestHarvestablePosition.Value, this); return ActivityUtils.SequenceActivities(mobile.MoveTo(closestHarvestablePosition.Value, 1), new HarvestResource(self), this); } }
public override Activity Tick(Actor self) { if (NextActivity != null) return NextActivity; var movement = self.Trait<IMove>(); var harv = self.Trait<Harvester>(); // Find the nearest best refinery if not explicitly ordered to a specific refinery: if (harv.OwnerLinkedProc == null || !harv.OwnerLinkedProc.IsInWorld) { // Maybe we lost the owner-linked refinery: harv.OwnerLinkedProc = null; if (self.World.WorldTick - chosenTicks > NextChooseTime) { harv.ChooseNewProc(self, null); chosenTicks = self.World.WorldTick; } } else harv.LinkProc(self, harv.OwnerLinkedProc); if (harv.LinkedProc == null || !harv.LinkedProc.IsInWorld) harv.ChooseNewProc(self, null); if (harv.LinkedProc == null) // no procs exist; check again in 1s. return Util.SequenceActivities(new Wait(25), this); var proc = harv.LinkedProc; var iao = proc.Trait<IAcceptResources>(); self.SetTargetLine(Target.FromActor(proc), Color.Green, false); if (self.Location != proc.Location + iao.DeliveryOffset) { var notify = self.TraitsImplementing<INotifyHarvesterAction>(); var next = new DeliverResources(); foreach (var n in notify) n.MovingToRefinery(self, proc.Location + iao.DeliveryOffset, next); return Util.SequenceActivities(movement.MoveTo(proc.Location + iao.DeliveryOffset, 0), this); } if (!isDocking) { isDocking = true; iao.OnDock(self, this); } return Util.SequenceActivities(new Wait(10), this); }
public override Activity Tick(Actor self) { if (IsCanceled) { return(NextActivity); } if (NextInQueue != null) { return(NextInQueue); } var deliver = new DeliverResources(self); if (harv.IsFull) { return(ActivityUtils.SequenceActivities(deliver, NextActivity)); } var closestHarvestablePosition = ClosestHarvestablePos(self); // If no harvestable position could be found, either deliver the remaining resources // or get out of the way and do not disturb. if (!closestHarvestablePosition.HasValue) { if (!harv.IsEmpty) { return(deliver); } harv.LastSearchFailed = true; var unblockCell = harv.LastHarvestedCell ?? (self.Location + harvInfo.UnblockCell); var moveTo = mobile.NearestMoveableCell(unblockCell, 2, 5); self.QueueActivity(mobile.MoveTo(moveTo, 1)); self.SetTargetLine(Target.FromCell(self.World, moveTo), Color.Gray, false); // TODO: The harvest-deliver-return sequence is a horrible mess of duplicated code and edge-cases var notify = self.TraitsImplementing <INotifyHarvesterAction>(); foreach (var n in notify) { n.MovingToResources(self, moveTo, this); } var randFrames = self.World.SharedRandom.Next(100, 175); // Avoid creating an activity cycle var next = NextInQueue; NextInQueue = null; return(ActivityUtils.SequenceActivities(next, new Wait(randFrames), this)); } else { // Attempt to claim the target cell if (!claimLayer.TryClaimCell(self, closestHarvestablePosition.Value)) { return(ActivityUtils.SequenceActivities(new Wait(25), this)); } harv.LastSearchFailed = false; // If not given a direct order, assume ordered to the first resource location we find: if (!harv.LastOrderLocation.HasValue) { harv.LastOrderLocation = closestHarvestablePosition; } self.SetTargetLine(Target.FromCell(self.World, closestHarvestablePosition.Value), Color.Red, false); // TODO: The harvest-deliver-return sequence is a horrible mess of duplicated code and edge-cases var notify = self.TraitsImplementing <INotifyHarvesterAction>(); foreach (var n in notify) { n.MovingToResources(self, closestHarvestablePosition.Value, this); } return(ActivityUtils.SequenceActivities(mobile.MoveTo(closestHarvestablePosition.Value, 1), new HarvestResource(self), this)); } }
public void OnDock(Actor harv, DeliverResources dockOrder) { if (!preventDock) { harv.QueueActivity(new CallFunc(() => dockedHarv = harv, false)); harv.QueueActivity(DockSequence(harv, self)); harv.QueueActivity(new CallFunc(() => dockedHarv = null, false)); } harv.QueueActivity(new CallFunc(() => harv.Trait<Harvester>().ContinueHarvesting(harv))); }
public override Activity Tick(Actor self) { if (IsCanceled || NextActivity != null) { return(NextActivity); } var deliver = new DeliverResources(self); if (harv.IsFull) { return(Util.SequenceActivities(deliver, NextActivity)); } var closestHarvestablePosition = ClosestHarvestablePos(self); // If no harvestable position could be found, either deliver the remaining resources // or get out of the way and do not disturb. if (!closestHarvestablePosition.HasValue) { if (!harv.IsEmpty) { return(deliver); } var cachedPosition = self.Location; harv.UnblockRefinery(self); // Only do this if UnblockRefinery did nothing. if (self.Location == cachedPosition) { var unblockCell = harv.LastHarvestedCell ?? (self.Location + harvInfo.UnblockCell); var moveTo = mobile.NearestMoveableCell(unblockCell, 2, 5); self.QueueActivity(mobile.MoveTo(moveTo, 1)); self.SetTargetLine(Target.FromCell(self.World, moveTo), Color.Gray, false); } var randFrames = self.World.SharedRandom.Next(100, 175); return(Util.SequenceActivities(NextActivity, new Wait(randFrames), this)); } else { var next = this; // Attempt to claim a resource as ours if (territory != null) { if (!territory.ClaimResource(self, closestHarvestablePosition.Value)) { return(Util.SequenceActivities(new Wait(25), next)); } } // If not given a direct order, assume ordered to the first resource location we find: if (!harv.LastOrderLocation.HasValue) { harv.LastOrderLocation = closestHarvestablePosition; } self.SetTargetLine(Target.FromCell(self.World, closestHarvestablePosition.Value), Color.Red, false); var notify = self.TraitsImplementing <INotifyHarvesterAction>(); foreach (var n in notify) { n.MovingToResources(self, closestHarvestablePosition.Value, next); } return(Util.SequenceActivities(mobile.MoveTo(closestHarvestablePosition.Value, 1), new HarvestResource(self), next)); } }
public override Activity Tick(Actor self) { if (IsCanceled || NextActivity != null) return NextActivity; var deliver = new DeliverResources(self); if (harv.IsFull) return Util.SequenceActivities(deliver, NextActivity); // 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 = pathFinder.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)); var next = this; if (path.Count == 0) { if (!harv.IsEmpty) return deliver; else { // Get out of the way if we are: harv.UnblockRefinery(self); var randFrames = self.World.SharedRandom.Next(90, 160); if (NextActivity != null) return Util.SequenceActivities(NextActivity, new Wait(randFrames), next); else return Util.SequenceActivities(new Wait(randFrames), next); } } // Attempt to claim a resource as ours: if (territory != null) { if (!territory.ClaimResource(self, path[0])) return Util.SequenceActivities(new Wait(25), next); } // 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>(); foreach (var n in notify) n.MovingToResources(self, path[0], next); return Util.SequenceActivities(mobile.MoveTo(path[0], 1), new HarvestResource(self), next); }
public override Activity Tick(Actor self) { if (IsCanceled || NextActivity != null) { return(NextActivity); } var deliver = new DeliverResources(self); if (harv.IsFull) { return(Util.SequenceActivities(deliver, NextActivity)); } // 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 = pathFinder.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)); var next = this; if (path.Count == 0) { if (!harv.IsEmpty) { return(deliver); } else { // Get out of the way if we are: harv.UnblockRefinery(self); var randFrames = self.World.SharedRandom.Next(90, 160); if (NextActivity != null) { return(Util.SequenceActivities(NextActivity, new Wait(randFrames), next)); } else { return(Util.SequenceActivities(new Wait(randFrames), next)); } } } // Attempt to claim a resource as ours: if (territory != null) { if (!territory.ClaimResource(self, path[0])) { return(Util.SequenceActivities(new Wait(25), next)); } } // 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>(); foreach (var n in notify) { n.MovingToResources(self, path[0], next); } return(Util.SequenceActivities(mobile.MoveTo(path[0], 1), new HarvestResource(self), next)); }
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; } }