// Find any MCV and deploy them at a sensible location.
        void DeployMcv(IBot bot, Actor mcv, bool move)
        {
            if (move)
            {
                // If we lack a base, we need to make sure we don't restrict deployment of the MCV to the base!
                var restrictToBase = Info.RestrictMCVDeploymentFallbackToBase && AIUtils.CountBuildingByCommonName(Info.ConstructionYardTypes, player) > 0;

                var transformsInfo  = mcv.Info.TraitInfo <TransformsInfo>();
                var desiredLocation = ChooseMcvDeployLocation(transformsInfo.IntoActor, transformsInfo.Offset, restrictToBase);
                if (desiredLocation == null)
                {
                    return;
                }

                bot.QueueOrder(new Order("Move", mcv, Target.FromCell(world, desiredLocation.Value), true));
            }

            // If the MCV has to move first, we can't be sure it reaches the destination alive, so we only
            // update base and defense center if the MCV is deployed immediately (i.e. at game start).
            // TODO: This could be adressed via INotifyTransform.
            foreach (var n in notifyPositionsUpdated)
            {
                n.UpdatedBaseCenter(mcv.Location);
                n.UpdatedDefenseCenter(mcv.Location);
            }

            bot.QueueOrder(new Order("DeployTransform", mcv, true));
        }
        public int NumBuildingsBuiltBuildingOrOrdered(ActorInfo building)
        {
            var nameComparisons = new HashSet <string>()
            {
                building.Name.ToLowerInvariant(), building.Name.ToLowerInvariant().Replace(".constructing", string.Empty)
            };
            var numBuildings = AIUtils.CountBuildingByCommonName(nameComparisons, player);

            return(numBuildings + NumBuildingsOrdered(building));
        }
        bool ShouldBuildMCV()
        {
            // Only build MCV if we don't already have one in the field.
            var allowedToBuildMCV = AIUtils.CountActorByCommonName(Info.McvTypes, player) == 0;

            if (!allowedToBuildMCV)
            {
                return(false);
            }

            // Build MCV if we don't have the desired number of construction yards, unless we have no factory (can't build it).
            return(AIUtils.CountBuildingByCommonName(Info.ConstructionYardTypes, player) < Info.MinimumConstructionYardCount &&
                   AIUtils.CountBuildingByCommonName(Info.McvFactoryTypes, player) > 0);
        }
        // Find any BEV and deploy them at a sensible location.
        void DeployBev(IBot bot, Actor bev, bool move)
        {
            if (move)
            {
                // If we lack a base, we need to make sure we don't restrict deployment of the MCV to the base!
                var restrictToBase = Info.RestrictBevDeploymentFallbackToBase && AIUtils.CountBuildingByCommonName(Info.ConstructionYardTypes, player) > 0;

                var transformsInfo  = bev.Info.TraitInfo <TransformsInfo>();
                var desiredLocation = ChooseBevDeployLocation(transformsInfo.IntoActor, transformsInfo.Offset, restrictToBase);
                if (desiredLocation == null)
                {
                    return;
                }

                bot.QueueOrder(new Order("Move", bev, Target.FromCell(world, desiredLocation.Value), true));
            }

            bot.QueueOrder(new Order("DeployTransform", bev, true));
        }
예제 #5
0
        protected void ProduceHarvesters(IBot bot)
        {
            // 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 numHarvesters = AIUtils.CountActorByCommonName(Info.HarvesterTypes, player);

                if (numHarvesters >= Info.MaxHarvesters)
                {
                    return;
                }

                var harvCountTooLow = numHarvesters < AIUtils.CountBuildingByCommonName(Info.RefineryTypes, player) * Info.HarvestersPerRefinery;
                if (harvCountTooLow && unitBuilder.RequestedProductionCount(bot, harvInfo.Name) == 0)
                {
                    unitBuilder.RequestUnitProduction(bot, harvInfo.Name);
                }
            }
        }
예제 #6
0
        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);
                }
            }
        }
        void IBotTick.BotTick(IBot bot)
        {
            if (resourceLayer == null || resourceLayer.IsResourceLayerEmpty)
            {
                return;
            }

            if (--scanForIdleMinersTicks > 0)
            {
                return;
            }

            scanForIdleMinersTicks = Info.MinimumScanDelay;

            var toRemove = miners.Keys.Where(unitCannotBeOrdered).ToList();

            foreach (var a in toRemove)
            {
                miners.Remove(a);
            }

            // TODO: Look for a more performance friendly way to update this list
            var newMiners = world.Actors.Where(a => Info.DeployableActorTypes.Contains(a.Info.Name) && a.Owner == player && !miners.ContainsKey(a));

            foreach (var a in newMiners)
            {
                miners[a] = new MinerTraitWrapper(a);
            }

            foreach (var miner in miners)
            {
                if (!miner.Key.IsIdle)
                {
                    continue;
                }

                if (Info.DeployableTerrainTypes.Contains(world.Map.GetTerrainInfo(miner.Key.Location).Type))
                {
                    bot.QueueOrder(new Order("DeployTransform", miner.Key, true));
                    continue;
                }

                // Tell the idle miner to quit slacking:
                var newSafeResourcePatch = FindNextResource(miner.Key, miner.Value);
                if (newSafeResourcePatch.Type == TargetType.Invalid)
                {
                    scanForIdleMinersTicks = Info.LastSearchFailedDelay;
                    return;
                }

                AIUtils.BotDebug("AI: Miner {0} is idle. Ordering to {1} in search for new resources.".F(miner.Key, newSafeResourcePatch));
                bot.QueueOrder(new Order("Move", miner.Key, newSafeResourcePatch, true));
            }

            // Keep the economy running before starving out.
            var unitBuilder = requestUnitProduction.FirstOrDefault(Exts.IsTraitEnabled);

            if (unitBuilder != null)
            {
                var minerInfo    = AIUtils.GetInfoByCommonName(Info.DeployableActorTypes, player);
                var miningTowers = AIUtils.CountBuildingByCommonName(Info.DeployedActorTypes, player);
                if (miningTowers < Info.MinimumDeployedActors && unitBuilder.RequestedProductionCount(bot, minerInfo.Name) == 0)
                {
                    unitBuilder.RequestUnitProduction(bot, minerInfo.Name);
                }
            }
        }