Target FindNextResource(Actor actor, HarvesterTraitWrapper harv) { Func <CPos, bool> isValidResource = cell => 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])); }
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])); }
protected void OrderHarvesters(IBot bot) { var toRemove = harvesters.Keys.Where(unitCannotBeOrdered).ToList(); foreach (var a in toRemove) { harvesters.Remove(a); } // Find new harvesters // TODO: Look for a more performance-friendly way to update this list var newHarvesters = world.ActorsHavingTrait <Harvester>().Where(a => a.Owner == player && !harvesters.ContainsKey(a)); foreach (var a in newHarvesters) { harvesters[a] = new HarvesterTraitWrapper(a); } // Find idle harvesters and give them orders: foreach (var h in harvesters) { if (!h.Key.IsIdle) { var act = h.Key.CurrentActivity as FindAndDeliverResources; // Ignore this actor if FindAndDeliverResources is working fine or it is performing a different activity if (act == null || !act.LastSearchFailed) { continue; } } // Tell the idle harvester to quit slacking: var newSafeResourcePatch = FindNextResource(h.Key, h.Value); AIUtils.BotDebug("AI: Harvester {0} is idle. Ordering to {1} in search for new resources.".F(h.Key, newSafeResourcePatch)); bot.QueueOrder(new Order("Harvest", h.Key, newSafeResourcePatch, false)); } }
void IBotTick.BotTick(IBot bot) { if (resourceLayer == null || resourceLayer.IsEmpty) { return; } if (--scanForIdleHarvestersTicks > 0) { return; } var toRemove = harvesters.Keys.Where(unitCannotBeOrdered).ToList(); foreach (var a in toRemove) { harvesters.Remove(a); } scanForIdleHarvestersTicks = Info.ScanForIdleHarvestersInterval; // Find new harvesters // TODO: Look for a more performance-friendly way to update this list var newHarvesters = world.ActorsHavingTrait <Harvester>().Where(a => a.Owner == player && !harvesters.ContainsKey(a)); foreach (var a in newHarvesters) { harvesters[a] = new HarvesterTraitWrapper(a); } // Find idle harvesters and give them orders: foreach (var h in harvesters) { if (!h.Key.IsIdle) { // Ignore this actor if FindAndDeliverResources is working fine or it is performing a different activity if (!(h.Key.CurrentActivity is FindAndDeliverResources act) || !act.LastSearchFailed) { continue; } } if (h.Value.Parachutable != null && h.Value.Parachutable.IsInAir) { continue; } // Tell the idle harvester to quit slacking: var newSafeResourcePatch = FindNextResource(h.Key, h.Value); AIUtils.BotDebug("AI: Harvester {0} is idle. Ordering to {1} in search for new resources.".F(h.Key, newSafeResourcePatch)); bot.QueueOrder(new Order("Harvest", h.Key, newSafeResourcePatch, false)); } // Less harvesters than refineries - build a new harvester var unitBuilder = requestUnitProduction.FirstOrDefault(Exts.IsTraitEnabled); if (unitBuilder != null && Info.HarvesterTypes.Any()) { var harvInfo = AIUtils.GetInfoByCommonName(Info.HarvesterTypes, player); var harvCountTooLow = AIUtils.CountActorByCommonName(Info.HarvesterTypes, player) < AIUtils.CountBuildingByCommonName(Info.RefineryTypes, player); if (harvCountTooLow && unitBuilder.RequestedProductionCount(bot, harvInfo.Name) == 0) { unitBuilder.RequestUnitProduction(bot, harvInfo.Name); } } }