Example #1
0
        // In cases where we want to build a specific unit but don't know the queue name (because there's more than one possibility)
        void BuildUnit(IBot bot, string name)
        {
            var actorInfo = world.Map.Rules.Actors[name];

            if (actorInfo == null)
            {
                return;
            }

            var buildableInfo = actorInfo.TraitInfoOrDefault <BuildableInfo>();

            if (buildableInfo == null)
            {
                return;
            }

            ProductionQueue queue = null;

            foreach (var pq in buildableInfo.Queue)
            {
                queue = AIUtils.FindQueues(player, pq).FirstOrDefault(q => !q.AllQueued().Any());
                if (queue != null)
                {
                    break;
                }
            }

            if (queue != null)
            {
                bot.QueueOrder(Order.StartProduction(queue.Actor, name, 1));
                AIUtils.BotDebug("{0} decided to build {1} (external request)", queue.Actor.Owner, name);
            }
        }
Example #2
0
        void BuildUnit(IBot bot, string category, bool buildRandom)
        {
            // Pick a free queue
            var queue = AIUtils.FindQueues(player, category).FirstOrDefault(q => !q.AllQueued().Any());

            if (queue == null)
            {
                return;
            }

            var unit = buildRandom ?
                       ChooseRandomUnitToBuild(queue) :
                       ChooseUnitToBuild(queue);

            if (unit == null)
            {
                return;
            }

            var name = unit.Name;

            if (Info.UnitsToBuild != null && !Info.UnitsToBuild.ContainsKey(name))
            {
                return;
            }

            if (Info.UnitDelays != null &&
                Info.UnitDelays.ContainsKey(name) &&
                Info.UnitDelays[name] > world.WorldTick)
            {
                return;
            }

            if (Info.UnitLimits != null &&
                Info.UnitLimits.ContainsKey(name) &&
                world.Actors.Count(a => a.Owner == player && a.Info.Name == name) >= Info.UnitLimits[name])
            {
                return;
            }

            bot.QueueOrder(Order.StartProduction(queue.Actor, name, 1));
        }
Example #3
0
        public void Tick(IBot bot)
        {
            // If failed to place something N consecutive times, wait M ticks until resuming building production
            if (failCount >= baseBuilder.Info.MaximumFailedPlacementAttempts && --failRetryTicks <= 0)
            {
                var currentBuildings = world.ActorsHavingTrait <Building>().Count(a => a.Owner == player);
                var baseProviders    = world.ActorsHavingTrait <BaseProvider>().Count(a => a.Owner == player);

                // Only bother resetting failCount if either a) the number of buildings has decreased since last failure M ticks ago,
                // or b) number of BaseProviders (construction yard or similar) has increased since then.
                // Otherwise reset failRetryTicks instead to wait again.
                if (currentBuildings < cachedBuildings || baseProviders > cachedBases)
                {
                    failCount = 0;
                }
                else
                {
                    failRetryTicks = baseBuilder.Info.StructureProductionResumeDelay;
                }
            }

            if (waterState == WaterCheck.NotChecked)
            {
                if (AIUtils.IsAreaAvailable <BaseProvider>(world, player, world.Map, baseBuilder.Info.MaxBaseRadius, baseBuilder.Info.WaterTerrainTypes))
                {
                    waterState = WaterCheck.EnoughWater;
                }
                else
                {
                    waterState         = WaterCheck.NotEnoughWater;
                    checkForBasesTicks = baseBuilder.Info.CheckForNewBasesDelay;
                }
            }

            if (waterState == WaterCheck.NotEnoughWater && --checkForBasesTicks <= 0)
            {
                var currentBases = world.ActorsHavingTrait <BaseProvider>().Count(a => a.Owner == player);

                if (currentBases > cachedBases)
                {
                    cachedBases = currentBases;
                    waterState  = WaterCheck.NotChecked;
                }
            }

            // Only update once per second or so
            if (--waitTicks > 0)
            {
                return;
            }

            playerBuildings = world.ActorsHavingTrait <Building>().Where(a => a.Owner == player).ToArray();
            var excessPowerBonus = baseBuilder.Info.ExcessPowerIncrement * (playerBuildings.Count() / baseBuilder.Info.ExcessPowerIncreaseThreshold.Clamp(1, int.MaxValue));

            minimumExcessPower = (baseBuilder.Info.MinimumExcessPower + excessPowerBonus).Clamp(baseBuilder.Info.MinimumExcessPower, baseBuilder.Info.MaximumExcessPower);

            var active = false;

            foreach (var queue in AIUtils.FindQueues(player, category))
            {
                if (TickQueue(bot, queue))
                {
                    active = true;
                }
            }

            // Add a random factor so not every AI produces at the same tick early in the game.
            // Minimum should not be negative as delays in HackyAI could be zero.
            var randomFactor = world.LocalRandom.Next(0, baseBuilder.Info.StructureProductionRandomBonusDelay);

            // Needs to be at least 4 * OrderLatency because otherwise the AI frequently duplicates build orders (i.e. makes the same build decision twice)
            waitTicks = active ? 4 * world.OrderLatency + baseBuilder.Info.StructureProductionActiveDelay + randomFactor
                                : baseBuilder.Info.StructureProductionInactiveDelay + randomFactor;
        }