Beispiel #1
0
        /// <summary>
        /// Finds the closest harvestable pos between the current position of the harvester
        /// and the last order location
        /// </summary>
        CPos?ClosestHarvestablePos(Actor self)
        {
            // Harvesters should respect an explicit harvest order instead of harvesting the current cell.
            if (orderLocation == null)
            {
                if (harv.CanHarvestCell(self, self.Location) && claimLayer.CanClaimCell(self, self.Location))
                {
                    return(self.Location);
                }
            }
            else
            {
                if (harv.CanHarvestCell(self, orderLocation.Value) && claimLayer.CanClaimCell(self, orderLocation.Value))
                {
                    return(orderLocation);
                }

                orderLocation = null;
            }

            // Determine where to search from and how far to search:
            var searchFromLoc       = lastHarvestedCell ?? GetSearchFromLocation(self);
            var searchRadius        = lastHarvestedCell.HasValue ? harvInfo.SearchFromOrderRadius : harvInfo.SearchFromProcRadius;
            var searchRadiusSquared = searchRadius * searchRadius;

            // Find any harvestable resources:
            List <CPos> path;

            using (var search = PathSearch.Search(self.World, locomotorInfo, self, true, loc =>
                                                  domainIndex.IsPassable(self.Location, loc, locomotorInfo) && harv.CanHarvestCell(self, loc) && claimLayer.CanClaimCell(self, loc))
                                .WithCustomCost(loc =>
            {
                if ((loc - searchFromLoc).LengthSquared > searchRadiusSquared)
                {
                    return(int.MaxValue);
                }

                return(0);
            })
                                .FromPoint(searchFromLoc)
                                .FromPoint(self.Location))
                path = pathFinder.FindPath(search);

            if (path.Count > 0)
            {
                return(path[0]);
            }

            return(null);
        }
Beispiel #2
0
        public override bool Tick(Actor self)
        {
            if (harv.IsTraitDisabled)
            {
                Cancel(self, true);
            }

            if (IsCanceling || harv.IsFull)
            {
                return(true);
            }

            // Move towards the target cell
            if (self.Location != targetCell)
            {
                foreach (var n in notifyHarvesterActions)
                {
                    n.MovingToResources(self, targetCell);
                }

                QueueChild(move.MoveTo(targetCell, 0));
                return(false);
            }

            if (!harv.CanHarvestCell(self, self.Location))
            {
                return(true);
            }

            // Turn to one of the harvestable facings
            if (harvInfo.HarvestFacings != 0)
            {
                var current = facing.Facing;
                var desired = body.QuantizeFacing(current, harvInfo.HarvestFacings);
                if (desired != current)
                {
                    QueueChild(new Turn(self, desired));
                    return(false);
                }
            }

            var resource = resourceLayer.GetResource(self.Location);

            if (resource.Type == null || resourceLayer.RemoveResource(resource.Type, self.Location) != 1)
            {
                return(true);
            }

            harv.AcceptResource(self, resource.Type);

            foreach (var t in notifyHarvesterActions)
            {
                t.Harvested(self, resource.Type);
            }

            QueueChild(new Wait(harvInfo.BaleLoadDelay));
            return(false);
        }
Beispiel #3
0
        CPos FindNextResource(Actor actor, Harvester harv)
        {
            var mobileInfo = actor.Info.TraitInfo <MobileInfo>();
            var passable   = (uint)mobileInfo.GetMovementClass(World.Map.Rules.TileSet);

            Func <CPos, bool> isValidResource = cell =>
                                                domainIndex.IsPassable(actor.Location, cell, mobileInfo, passable) &&
                                                harv.CanHarvestCell(actor, cell) &&
                                                claimLayer.CanClaimCell(actor, cell);
            var path = pathfinder.FindPath(
                PathSearch.Search(World, mobileInfo, actor, true, isValidResource)
                .WithCustomCost(loc => World.FindActorsInCircle(World.Map.CenterOfCell(loc), Info.HarvesterEnemyAvoidanceRadius)
                                .Where(u => !u.IsDead && actor.Owner.Stances[u.Owner] == Stance.Enemy)
                                .Sum(u => Math.Max(WDist.Zero.Length, Info.HarvesterEnemyAvoidanceRadius.Length - (World.Map.CenterOfCell(loc) - u.CenterPosition).Length))).FromPoint(actor.Location));

            if (path.Count == 0)
            {
                return(CPos.Zero);
            }
            return(path[0]);
        }
Beispiel #4
0
        /// <summary>
        /// Finds the closest harvestable pos between the current position of the harvester
        /// and the last order location
        /// </summary>
        CPos?ClosestHarvestablePos(Actor self)
        {
            if (harv.CanHarvestCell(self, self.Location) && claimLayer.CanClaimCell(self, self.Location))
            {
                return(self.Location);
            }

            // Determine where to search from and how far to search:
            var searchFromLoc       = GetSearchFromLocation(self);
            var searchRadius        = harv.LastOrderLocation.HasValue ? harvInfo.SearchFromOrderRadius : harvInfo.SearchFromProcRadius;
            var searchRadiusSquared = searchRadius * searchRadius;

            // Find any harvestable resources:
            var         passable = (uint)mobileInfo.GetMovementClass(self.World.Map.Rules.TileSet);
            List <CPos> path;

            using (var search = PathSearch.Search(self.World, mobileInfo, self, true, loc =>
                                                  domainIndex.IsPassable(self.Location, loc, mobileInfo, passable) && harv.CanHarvestCell(self, loc) && claimLayer.CanClaimCell(self, loc))
                                .WithCustomCost(loc =>
            {
                if ((avoidCell.HasValue && loc == avoidCell.Value) ||
                    (loc - self.Location).LengthSquared > searchRadiusSquared)
                {
                    return(int.MaxValue);
                }

                return(0);
            })
                                .FromPoint(self.Location)
                                .FromPoint(searchFromLoc))
                path = pathFinder.FindPath(search);

            if (path.Count > 0)
            {
                return(path[0]);
            }

            return(null);
        }
Beispiel #5
0
        /// <summary>
        /// Finds the closest harvestable pos between the current position of the harvester
        /// and the last order location
        /// </summary>
        CPos?ClosestHarvestablePos(Actor self)
        {
            // Harvesters should respect an explicit harvest order instead of harvesting the current cell.
            if (orderLocation == null)
            {
                if (harv.CanHarvestCell(self, self.Location) && claimLayer.CanClaimCell(self, self.Location))
                {
                    return(self.Location);
                }
            }
            else
            {
                if (harv.CanHarvestCell(self, orderLocation.Value) && claimLayer.CanClaimCell(self, orderLocation.Value))
                {
                    return(orderLocation);
                }

                orderLocation = null;
            }

            // Determine where to search from and how far to search:
            var procLoc       = GetSearchFromProcLocation(self);
            var searchFromLoc = lastHarvestedCell ?? procLoc ?? self.Location;
            var searchRadius  = lastHarvestedCell.HasValue ? harvInfo.SearchFromHarvesterRadius : harvInfo.SearchFromProcRadius;

            var searchRadiusSquared = searchRadius * searchRadius;

            var map     = self.World.Map;
            var procPos = procLoc.HasValue ? (WPos?)map.CenterOfCell(procLoc.Value) : null;
            var harvPos = self.CenterPosition;

            // Find any harvestable resources:
            List <CPos> path;

            using (var search = PathSearch.Search(self.World, mobile.Locomotor, self, BlockedByActor.Stationary, loc =>
                                                  domainIndex.IsPassable(self.Location, loc, mobile.Locomotor) && harv.CanHarvestCell(self, loc) && claimLayer.CanClaimCell(self, loc))
                                .WithCustomCost(loc =>
            {
                if ((loc - searchFromLoc).LengthSquared > searchRadiusSquared)
                {
                    return(PathGraph.PathCostForInvalidPath);
                }

                // Add a cost modifier to harvestable cells to prefer resources that are closer to the refinery.
                // This reduces the tendency for harvesters to move in straight lines
                if (procPos.HasValue && harvInfo.ResourceRefineryDirectionPenalty > 0 && harv.CanHarvestCell(self, loc))
                {
                    var pos = map.CenterOfCell(loc);

                    // Calculate harv-cell-refinery angle (cosine rule)
                    var b = pos - procPos.Value;

                    if (b != WVec.Zero)
                    {
                        var c = pos - harvPos;
                        if (c != WVec.Zero)
                        {
                            var a = harvPos - procPos.Value;
                            var cosA = (int)(512 * (b.LengthSquared + c.LengthSquared - a.LengthSquared) / b.Length / c.Length);

                            // Cost modifier varies between 0 and ResourceRefineryDirectionPenalty
                            return(Math.Abs(harvInfo.ResourceRefineryDirectionPenalty / 2) + harvInfo.ResourceRefineryDirectionPenalty * cosA / 2048);
                        }
                    }
                }

                return(0);
            })
                                .FromPoint(searchFromLoc)
                                .FromPoint(self.Location))
                path = mobile.Pathfinder.FindPath(search);

            if (path.Count > 0)
            {
                return(path[0]);
            }

            return(null);
        }
Beispiel #6
0
        public override Activity Tick(Actor self)
        {
            if (ChildActivity != null)
            {
                ChildActivity = ActivityUtils.RunActivityTick(self, ChildActivity);
                if (ChildActivity != null)
                {
                    return(this);
                }
            }

            if (IsCanceling || harv.IsFull)
            {
                return(NextActivity);
            }

            // Move towards the target cell
            if (self.Location != targetCell)
            {
                foreach (var n in self.TraitsImplementing <INotifyHarvesterAction>())
                {
                    n.MovingToResources(self, targetCell, new FindAndDeliverResources(self));
                }

                self.SetTargetLine(Target.FromCell(self.World, targetCell), Color.Red, false);
                QueueChild(self, move.MoveTo(targetCell, 2), true);
                return(this);
            }

            if (!harv.CanHarvestCell(self, self.Location))
            {
                return(NextActivity);
            }

            // Turn to one of the harvestable facings
            if (harvInfo.HarvestFacings != 0)
            {
                var current = facing.Facing;
                var desired = body.QuantizeFacing(current, harvInfo.HarvestFacings);
                if (desired != current)
                {
                    QueueChild(self, new Turn(self, desired), true);
                    return(this);
                }
            }

            var resource = resLayer.Harvest(self.Location);

            if (resource == null)
            {
                return(NextActivity);
            }

            harv.AcceptResource(self, resource);

            foreach (var t in self.TraitsImplementing <INotifyHarvesterAction>())
            {
                t.Harvested(self, resource);
            }

            QueueChild(self, new Wait(harvInfo.BaleLoadDelay), true);
            return(this);
        }