Exemple #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)
        {
            var mobile = self.Trait <Mobile>();

            // Determine where to search from and how far to search:
            Func <CPos, bool> canHarvest = pos =>
            {
                var resType = resourceLayer.GetResourceType(pos);
                if (resType != null && string.Compare(resType.Info.Name, Info.TargetResourceType, StringComparison.OrdinalIgnoreCase) == 0)
                {
                    return(true);
                }

                return(false);
            };

            // 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) && canHarvest(loc) && claimLayer.CanClaimCell(self, loc))
                                .FromPoint(self.Location))
                path = pathFinder.FindPath(search);

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

            return(null);
        }
Exemple #2
0
        void UpdateInnerPath(Actor self)
        {
            var targetCells = Util.AdjacentCells(target);
            var searchCells = new List <CPos>();
            var loc         = self.Location;

            foreach (var cell in targetCells)
            {
                if (mobile.CanEnterCell(cell) && (domainIndex == null || domainIndex.IsPassable(loc, cell, movementClass)))
                {
                    searchCells.Add(cell);
                }
            }

            if (searchCells.Any())
            {
                var ps1 = new PathSearch(self.World, mobile.Info, self)
                {
                    checkForBlocked = true,
                    heuristic       = location => 0,
                    inReverse       = true
                };

                foreach (var cell in searchCells)
                {
                    ps1.AddInitialCell(cell);
                }

                ps1.heuristic = PathSearch.DefaultEstimator(mobile.toCell);
                var ps2 = PathSearch.FromPoint(self.World, mobile.Info, self, mobile.toCell, targetPosition, true);
                var ret = pathFinder.FindBidiPath(ps1, ps2);

                inner = mobile.MoveTo(() => ret);
            }
        }
Exemple #3
0
        List <CPos> CalculatePathToTarget(Actor self, BlockedByActor check)
        {
            var loc = self.Location;

            // PERF: Assume that CandidateMovementCells doesn't change within a tick to avoid repeated queries
            // when Move enumerates different BlockedByActor values
            if (searchCellsTick != self.World.WorldTick)
            {
                searchCells.Clear();
                searchCellsTick = self.World.WorldTick;
                foreach (var cell in CandidateMovementCells(self))
                {
                    if (domainIndex.IsPassable(loc, cell, Mobile.Info.LocomotorInfo) && Mobile.CanEnterCell(cell))
                    {
                        searchCells.Add(cell);
                    }
                }
            }

            if (!searchCells.Any())
            {
                return(NoPath);
            }

            using (var fromSrc = PathSearch.FromPoints(self.World, Mobile.Locomotor, self, searchCells, loc, check))
                using (var fromDest = PathSearch.FromPoint(self.World, Mobile.Locomotor, self, loc, lastVisibleTargetLocation, check).Reverse())
                    return(pathFinder.FindBidiPath(fromSrc, fromDest));
        }
Exemple #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)
        {
            // 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);
        }
        /// <summary>
        /// Using LastOrderLocation and self.Location as starting points,
        /// perform A* search to find the nearest accessible and harvestable cell.
        /// </summary>
        CPos?ClosestHarvestablePos(Actor self, int searchRadius)
        {
            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       = harv.LastOrderLocation ?? self.Location;
            var searchRadiusSquared = searchRadius * searchRadius;

            BaseSpawnerSlaveEntry choosenSlave = null;
            var slaves = harv.GetSlaves();

            if (slaves.Length > 0)
            {
                choosenSlave = slaves[0];

                var mobile     = choosenSlave.Actor.Trait <Mobile>();
                var mobileInfo = choosenSlave.Actor.Info.TraitInfo <MobileInfo>();
                // Find any harvestable resources:
                // var passable = (uint)mobileInfo.GetMovementClass(self.World.Map.Rules.TileSet);
                List <CPos> path;
                using (var search = PathSearch.Search(self.World, mobile.Locomotor, self, true,
                                                      loc => domainIndex.IsPassable(self.Location, loc, mobileInfo.LocomotorInfo) &&
                                                      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);
        }
Exemple #6
0
        Target FindNextResource(Actor actor, HarvesterTraitWrapper harv)
        {
            bool IsValidResource(CPos cell) =>
            domainIndex.IsPassable(actor.Location, cell, harv.Mobile.Locomotor) &&
            harv.Harvester.CanHarvestCell(cell) &&
            claimLayer.CanClaimCell(actor, cell);

            var path = harv.Mobile.PathFinder.FindUnitPathToTargetCellByPredicate(
                actor, new[] { actor.Location }, IsValidResource, BlockedByActor.Stationary,
                loc => world.FindActorsInCircle(world.Map.CenterOfCell(loc), Info.HarvesterEnemyAvoidanceRadius)
                .Where(u => !u.IsDead && actor.Owner.RelationshipWith(u.Owner) == PlayerRelationship.Enemy)
                .Sum(u => Math.Max(WDist.Zero.Length, Info.HarvesterEnemyAvoidanceRadius.Length - (world.Map.CenterOfCell(loc) - u.CenterPosition).Length)));

            if (path.Count == 0)
            {
                return(Target.Invalid);
            }

            return(Target.FromCell(world, path[0]));
        }
Exemple #7
0
        CPos FindNextResource(Actor harvester)
        {
            var harvInfo   = harvester.Info.TraitInfo <HarvesterInfo>();
            var mobileInfo = harvester.Info.TraitInfo <MobileInfo>();
            var passable   = (uint)mobileInfo.GetMovementClass(World.Map.Rules.TileSet);

            var path = pathfinder.FindPath(
                PathSearch.Search(World, mobileInfo, harvester, true,
                                  loc => domainIndex.IsPassable(harvester.Location, loc, passable) && harvester.CanHarvestAt(loc, resLayer, harvInfo, territory))
                .WithCustomCost(loc => World.FindActorsInCircle(World.Map.CenterOfCell(loc), Info.HarvesterEnemyAvoidanceRadius)
                                .Where(u => !u.IsDead && harvester.Owner.Stances[u.Owner] == Stance.Enemy)
                                .Sum(u => Math.Max(WDist.Zero.Length, Info.HarvesterEnemyAvoidanceRadius.Length - (World.Map.CenterOfCell(loc) - u.CenterPosition).Length)))
                .FromPoint(harvester.Location));

            if (path.Count == 0)
            {
                return(CPos.Zero);
            }

            return(path[0]);
        }
Exemple #8
0
        Target FindNextResource(Actor actor, HarvesterTraitWrapper harv)
        {
            Func <CPos, bool> isValidResource = cell =>
                                                domainIndex.IsPassable(actor.Location, cell, harv.Locomotor) &&
                                                harv.Harvester.CanHarvestCell(actor, cell) &&
                                                claimLayer.CanClaimCell(actor, cell);

            var path = pathfinder.FindPath(
                PathSearch.Search(world, harv.Locomotor, actor, BlockedByActor.Stationary, isValidResource)
                .WithCustomCost(loc => world.FindActorsInCircle(world.Map.CenterOfCell(loc), Info.HarvesterEnemyAvoidanceRadius)
                                .Where(u => !u.IsDead && actor.Owner.RelationshipWith(u.Owner) == PlayerRelationship.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(Target.Invalid);
            }

            return(Target.FromCell(world, path[0]));
        }
Exemple #9
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]);
        }
Exemple #10
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);
        }
Exemple #11
0
        List <CPos> CalculatePathToTarget(Actor self)
        {
            var targetCells = CandidateMovementCells(self);
            var searchCells = new List <CPos>();
            var loc         = self.Location;

            foreach (var cell in targetCells)
            {
                if (domainIndex.IsPassable(loc, cell, Mobile.Info, movementClass) && Mobile.CanEnterCell(cell))
                {
                    searchCells.Add(cell);
                }
            }

            if (!searchCells.Any())
            {
                return(NoPath);
            }

            using (var fromSrc = PathSearch.FromPoints(self.World, Mobile.Info, self, searchCells, loc, true))
                using (var fromDest = PathSearch.FromPoint(self.World, Mobile.Info, self, loc, targetPosition, true).Reverse())
                    return(pathFinder.FindBidiPath(fromSrc, fromDest));
        }
Exemple #12
0
        Target SafePath(Actor capturer, Actor target)
        {
            var locomotor = capturer.Trait <Mobile>().Locomotor;

            if (!domainIndex.IsPassable(capturer.Location, target.Location, locomotor))
            {
                return(Target.Invalid);
            }

            var path = pathfinder.FindPath(
                PathSearch.FromPoint(world, locomotor, capturer, capturer.Location, target.Location, BlockedByActor.None)
                .WithCustomCost(loc => world.FindActorsInCircle(world.Map.CenterOfCell(loc), Info.EnemyAvoidanceRadius)
                                .Where(u => !u.IsDead && capturer.Owner.RelationshipWith(u.Owner) == PlayerRelationship.Enemy && capturer.IsTargetableBy(u))
                                .Sum(u => Math.Max(WDist.Zero.Length, Info.EnemyAvoidanceRadius.Length - (world.Map.CenterOfCell(loc) - u.CenterPosition).Length)))
                .FromPoint(capturer.Location));

            if (path.Count == 0)
            {
                return(Target.Invalid);
            }

            return(Target.FromActor(target));
        }
        Target FindNextResource(Actor actor, MinerTraitWrapper miner)
        {
            var towerInfo    = AIUtils.GetInfoByCommonName(Info.DeployedActorTypes, player);
            var buildingInfo = towerInfo.TraitInfo <BuildingInfo>();
            Func <CPos, bool> isValidResource = cell =>
                                                domainIndex.IsPassable(actor.Location, cell, miner.Locomotor.Info) &&
                                                Info.DeployableTerrainTypes.Contains(world.Map.GetTerrainInfo(cell).Type) &&
                                                miner.Locomotor.CanStayInCell(cell) &&
                                                world.CanPlaceBuilding(cell + miner.Transforms.Info.Offset, towerInfo, buildingInfo, actor);

            var path = pathfinder.FindPath(
                PathSearch.Search(world, miner.Locomotor, actor, BlockedByActor.Stationary, isValidResource)
                .WithCustomCost(loc => world.FindActorsInCircle(world.Map.CenterOfCell(loc), Info.EnemyAvoidanceRadius)
                                .Where(u => !u.IsDead && actor.Owner.Stances[u.Owner] == Stance.Enemy)
                                .Sum(u => Math.Max(WDist.Zero.Length, Info.EnemyAvoidanceRadius.Length - (world.Map.CenterOfCell(loc) - u.CenterPosition).Length)))
                .FromPoint(actor.Location));

            if (path.Count == 0)
            {
                return(Target.Invalid);
            }

            return(Target.FromCell(world, path[0]));
        }
Exemple #14
0
        Target PathToNextcube(Actor collector, Actor cube)
        {
            var locomotor = collector.Trait <Mobile>().Locomotor;

            if (!domainIndex.IsPassable(collector.Location, cube.Location, locomotor))
            {
                return(Target.Invalid);
            }

            var path = pathfinder.FindPath(
                PathSearch.FromPoint(world, locomotor, collector, collector.Location, cube.Location, BlockedByActor.Stationary)
                .WithCustomCost(loc => world.FindActorsInCircle(world.Map.CenterOfCell(loc), Info.EnemyAvoidanceRadius)
                                .Where(u => !u.IsDead && collector.Owner.RelationshipWith(u.Owner) == PlayerRelationship.Enemy)
                                .Sum(u => Math.Max(WDist.Zero.Length, Info.EnemyAvoidanceRadius.Length - (world.Map.CenterOfCell(loc) - u.CenterPosition).Length)))
                .FromPoint(collector.Location));

            if (path.Count == 0)
            {
                return(Target.Invalid);
            }

            // Don't use the actor to avoid invalid targets when the cube disappears midway.
            return(Target.FromCell(world, cube.Location));
        }
Exemple #15
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);
        }
Exemple #16
0
        public LuaTable ReinforceWithTransport(Player owner, string actorType, string[] cargoTypes, CPos[] entryPath, CPos[] exitPath = null,
                                               LuaFunction actionFunc = null, LuaFunction exitFunc = null, int dropRange = 3)
        {
            var transport = CreateActor(owner, actorType, true, entryPath[0], entryPath.Length > 1 ? entryPath[1] : (CPos?)null);
            var cargo     = transport.TraitOrDefault <Cargo>();

            var passengers = new List <Actor>();

            if (cargo != null && cargoTypes != null)
            {
                foreach (var cargoType in cargoTypes)
                {
                    var passenger = CreateActor(owner, cargoType, false, entryPath[0]);
                    passengers.Add(passenger);
                    cargo.Load(transport, passenger);
                }
            }

            for (var i = 1; i < entryPath.Length; i++)
            {
                Move(transport, entryPath[i]);
            }

            if (actionFunc != null)
            {
                var af = (LuaFunction)actionFunc.CopyReference();
                transport.QueueActivity(new CallFunc(() =>
                {
                    using (af)
                        using (LuaValue t = transport.ToLuaValue(Context), p = passengers.ToArray().ToLuaValue(Context))
                            af.Call(t, p);
                }));
            }
            else
            {
                var aircraft = transport.TraitOrDefault <Aircraft>();
                if (aircraft != null)
                {
                    var destination = entryPath.Last();

                    // Try to find an alternative landing spot if we can't land at the current destination
                    if (!aircraft.CanLand(destination) && dropRange > 0)
                    {
                        var locomotors = cargo.Passengers
                                         .Select(a => a.Info.TraitInfoOrDefault <MobileInfo>())
                                         .Where(m => m != null)
                                         .Distinct()
                                         .Select(m => m.LocomotorInfo)
                                         .ToList();

                        foreach (var c in transport.World.Map.FindTilesInCircle(destination, dropRange))
                        {
                            if (!aircraft.CanLand(c))
                            {
                                continue;
                            }

                            if (!locomotors.All(m => domainIndex.IsPassable(destination, c, m)))
                            {
                                continue;
                            }

                            destination = c;
                            break;
                        }
                    }

                    if (aircraft.Info.VTOL)
                    {
                        if (destination != entryPath.Last())
                        {
                            Move(transport, destination);
                        }

                        transport.QueueActivity(new Turn(transport, aircraft.Info.InitialFacing));
                        transport.QueueActivity(new Land(transport));
                    }
                    else
                    {
                        transport.QueueActivity(new Land(transport, Target.FromCell(transport.World, destination)));
                    }

                    transport.QueueActivity(new Wait(15));
                }

                if (cargo != null)
                {
                    transport.QueueActivity(new UnloadCargo(transport, true));
                    transport.QueueActivity(new WaitFor(() => cargo.IsEmpty(transport)));
                }

                transport.QueueActivity(new Wait(aircraft != null ? 50 : 25));
            }

            if (exitFunc != null)
            {
                var ef = (LuaFunction)exitFunc.CopyReference();
                transport.QueueActivity(new CallFunc(() =>
                {
                    using (ef)
                        using (var t = transport.ToLuaValue(Context))
                            ef.Call(t);
                }));
            }
            else if (exitPath != null)
            {
                foreach (var wpt in exitPath)
                {
                    Move(transport, wpt);
                }

                transport.QueueActivity(new RemoveSelf());
            }

            var ret = Context.CreateTable();

            using (LuaValue
                   tKey = 1,
                   tValue = transport.ToLuaValue(Context),
                   pKey = 2,
                   pValue = passengers.ToArray().ToLuaValue(Context))
            {
                ret.Add(tKey, tValue);
                ret.Add(pKey, pValue);
            }

            return(ret);
        }