Example #1
0
        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));
        }
Example #2
0
        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);
            }
        }
Example #3
0
        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);
            }
        }
Example #4
0
        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);
        }
Example #5
0
        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));
            }
        }
Example #6
0
        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)));
        }
Example #7
0
        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));
            }
        }
Example #8
0
        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);
        }
Example #9
0
        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));
        }
Example #10
0
        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;
            }
        }