/// <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); }
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 res = self.World.WorldActor.Trait <ResourceLayer>(); var path = self.World.WorldActor.Trait <PathFinder>().FindPath(PathSearch.Search(self.World, mobileInfo, self.Owner, true) .WithHeuristic(loc => (res.GetResource(loc) != null && harvInfo.Resources.Contains(res.GetResource(loc).info.Name)) ? 0 : 1) .FromPoint(self.Location)); if (path.Count == 0) { return(NextActivity); } self.SetTargetLine(Target.FromCell(path[0]), Color.Red, false); return(Util.SequenceActivities(mobile.MoveTo(path[0], 1), new HarvestResource(), this)); }
/// <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); }
static CPos?FindNextResourceForBot(Actor self) { // NOTE: This is only used for the AI to find the next available resource to harvest. var harvInfo = self.Info.Traits.Get <HarvesterInfo>(); var mobileInfo = self.Info.Traits.Get <MobileInfo>(); var resLayer = self.World.WorldActor.Trait <ResourceLayer>(); var territory = self.World.WorldActor.TraitOrDefault <ResourceClaimLayer>(); // Find any harvestable resources: var path = self.World.WorldActor.Trait <PathFinder>().FindPath( PathSearch.Search(self.World, mobileInfo, self, true) .WithHeuristic(loc => { // Get the resource at this location: var resType = resLayer.GetResource(loc); if (resType == null) { return(1); } // Can the harvester collect this kind of resource? if (!harvInfo.Resources.Contains(resType.Info.Name)) { return(1); } // Another harvester has claimed this resource: if (territory != null) { ResourceClaim claim; if (territory.IsClaimedByAnyoneElse(self, loc, out claim)) { return(1); } } return(0); }) .FromPoint(self.Location) ); if (path.Count == 0) { return((CPos?)null); } return(path[0]); }
/// <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); }
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])); }
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]); }
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]); }
/// <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); }
/// <summary> /// Finds the closest harvestable pos between the current position of the harvester /// and the last order location /// </summary> CPos?ClosestHarvestablePos(Actor self) { if (IsHarvestable(self, self.Location)) { return(self.Location); } // 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; var search = PathSearch.Search(self.World, mobileInfo, self, true, loc => IsHarvestable(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); // Find any harvestable resources: var path = pathFinder.FindPath(search); if (path.Count > 0) { return(path[0]); } return(null); }
CPos?ClosestGroundCell() { var above = new CPos(TopLeft.X, TopLeft.Y); if (CanEnterCell(above)) { return(above); } var pathFinder = self.World.WorldActor.Trait <IPathFinder>(); List <CPos> path; using (var search = PathSearch.Search(self.World, Info, self, true, loc => loc.Layer == 0 && CanEnterCell(loc)) .FromPoint(self.Location)) path = pathFinder.FindPath(search); if (path.Count > 0) { return(path[0]); } return(null); }
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])); }
/// <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); }
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; int searchRadius = harv.LastOrderLocation.HasValue ? harvInfo.SearchFromOrderRadius : harvInfo.SearchFromProcRadius; int searchRadiusSquared = searchRadius * searchRadius; // Find harvestable resources nearby: // Avoid enemy territory: // TODO: calculate weapons ranges of units and factor those in instead of hard-coding 8. var path = self.World.WorldActor.Trait <PathFinder>().FindPath( PathSearch.Search(self.World, mobileInfo, self, true) .WithCustomCost(loc => self.World.FindActorsInCircle(loc.CenterPosition, WRange.FromCells(8)) .Where(u => !u.Destroyed && self.Owner.Stances[u.Owner] == Stance.Enemy) .Sum(u => Math.Max(0, 64 - (loc - u.Location).LengthSquared))) .WithHeuristic(loc => { // Avoid this cell: if (avoidCell.HasValue && loc == avoidCell.Value) { return(1); } // Don't harvest out of range: int distSquared = (loc - searchFromLoc).LengthSquared; if (distSquared > searchRadiusSquared) { return(int.MaxValue); } // Get the resource at this location: var resType = resLayer.GetResource(loc); if (resType == null) { return(1); } // Can the harvester collect this kind of resource? if (!harvInfo.Resources.Contains(resType.Info.Name)) { return(1); } if (territory != null) { // Another harvester has claimed this resource: ResourceClaim claim; if (territory.IsClaimedByAnyoneElse(self, loc, out claim)) { return(1); } } 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); int 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(path[0]), Color.Red, false); return(Util.SequenceActivities(mobile.MoveTo(path[0], 1), new HarvestResource(), new FindResources())); }
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())); }