Exemple #1
0
        /// <see cref="SCVBuildExecutionBase.ContinueMovingToTarget"/>
        protected override bool ContinueMovingToTarget()
        {
            /// First try to retrieve the target building from the scenario.
            TerranBuilding targetBuilding = this.Scenario.GetElementOnMap <TerranBuilding>(this.targetBuildingID.Read(), MapObjectLayerEnum.GroundObjects);

            if (targetBuilding == null)
            {
                /// Target building not found -> finish command execution.
                return(true);
            }

            /// Check the distance between the SCV and the target building.
            RCNumber distance = MapUtils.ComputeDistance(this.RecipientSCV.Area, targetBuilding.Area);

            if (distance > Weapon.NEARBY_DISTANCE)
            {
                /// Distance not reached yet -> continue execution if SCV is still moving.
                return(!this.RecipientSCV.MotionControl.IsMoving);
            }

            /// Check if the target building has an inactive construction job.
            if (targetBuilding.ConstructionJob == null || targetBuilding.ConstructionJob.AttachedSCV != null)
            {
                /// Target building doesn't have an inactive construction job -> finish command execution.
                return(true);
            }

            /// Attach the SCV to the construction job of the target building.
            targetBuilding.ConstructionJob.AttachSCV(this.RecipientSCV);
            this.Status = SCVBuildExecutionStatusEnum.Constructing;
            return(false);
        }
Exemple #2
0
        /// <summary>
        /// Creates command executions for undefined command type.
        /// </summary>
        /// <param name="scvsToHandle">The SCVs to order.</param>
        /// <param name="fullEntitySet">The set of selected entities.</param>
        /// <param name="targetPosition">The target position.</param>
        /// <param name="targetEntityID">The ID of the target entity or -1 if undefined.</param>
        private IEnumerable <CmdExecutionBase> CreateUndefinedExecutions(RCSet <SCV> scvsToHandle, RCSet <Entity> fullEntitySet, RCNumVector targetPosition, int targetEntityID)
        {
            Entity         targetEntity   = scvsToHandle.First().Scenario.GetElementOnMap <Entity>(targetEntityID, MapObjectLayerEnum.GroundObjects);
            TerranBuilding targetBuilding = targetEntity as TerranBuilding;

            MagicBox magicBox = new MagicBox(fullEntitySet, targetPosition);

            foreach (SCV scv in scvsToHandle.Where(scv => !scv.IsConstructing))
            {
                if (targetBuilding != null && targetBuilding.Owner == scv.Owner &&
                    targetBuilding.ConstructionJob != null && !targetBuilding.ConstructionJob.IsFinished &&
                    targetBuilding.ConstructionJob.AttachedSCV == null)
                {
                    /// The target entity is a friendly Terran building that is under construction but its construction is
                    /// not currently in progress -> start a continue build command.
                    yield return(new SCVContinueBuildExecution(scv, targetPosition, targetBuilding.ID.Read()));
                }
                else if (targetEntity != null && targetEntity.Owner == scv.Owner && this.IsValidTargetForRepair(targetEntity))
                {
                    /// The target entity is a friendly entity and is valid for a repair command -> start a repair command.
                    yield return(new SCVRepairExecution(scv, targetPosition, targetEntityID));
                }
                else if (targetEntity != null && targetEntity.Owner != null && targetEntity.Owner != scv.Owner)
                {
                    /// The target entity is an enemy entity -> start an attack execution.
                    yield return(new AttackExecution(scv, magicBox.GetTargetPosition(scv), targetEntityID));
                }
                else
                {
                    /// In any other cases -> start a move execution.
                    yield return(new MoveExecution(scv, magicBox.GetTargetPosition(scv), targetEntityID));
                }
                /// TODO: Handle the cases for Repair, Gather and Return commands!
            }
        }
Exemple #3
0
        /// <summary>
        /// Do SCV activities during construction.
        /// </summary>
        private void MakeScvActivityDuringConstruction()
        {
            /// Start using the build tool of the SCV and decrease the move-timer.
            TerranBuilding constructedBuilding = this.RecipientSCV.ConstructionJob.ConstructedBuilding;

            if (this.timeToNextScvMoveDuringConstruction.Read() > 0)
            {
                if (!this.recipientSCV.Read().MotionControl.IsMoving&& this.recipientSCV.Read().Armour.Target == null)
                {
                    this.recipientSCV.Read().Armour.StartAttack(constructedBuilding.ID.Read(), SCV.SCV_BUILD_TOOL_NAME);
                }
                this.timeToNextScvMoveDuringConstruction.Write(this.timeToNextScvMoveDuringConstruction.Read() - 1);
                return;
            }

            /// Generate a random position inside the building area and move the SCV there.
            /// TODO: do not use the default random generator because the engine shall be deterministic!
            RCIntRectangle buildingQuadRect = constructedBuilding.MapObject.QuadraticPosition;
            RCIntRectangle buildingCellRect = this.Scenario.Map.QuadToCellRect(buildingQuadRect);
            RCNumVector    movePosition     = new RCNumVector(
                RandomService.DefaultGenerator.Next(buildingCellRect.Left, buildingCellRect.Right),
                RandomService.DefaultGenerator.Next(buildingCellRect.Top, buildingCellRect.Bottom));

            this.recipientSCV.Read().MotionControl.StartMoving(movePosition);
            this.recipientSCV.Read().Armour.StopAttack();

            /// Reset the timer.
            this.timeToNextScvMoveDuringConstruction.Write(TIME_BETWEEN_SCV_MOVES);
        }
        /// <see cref="Weapon.CanTargetEntity"/>
        public override bool CanTargetEntity(Entity entityToCheck)
        {
            TerranBuilding terranBuilding = entityToCheck as TerranBuilding;

            return(terranBuilding != null &&
                   terranBuilding.ConstructionJob != null &&
                   !terranBuilding.ConstructionJob.IsFinished &&
                   terranBuilding.ConstructionJob.AttachedSCV == this.Owner);
        }
        /// <see cref="CmdExecutionBase.InitializeImpl"/>
        protected override void InitializeImpl()
        {
            TerranBuilding building = this.recipientSCV.Read().ConstructionJob.ConstructedBuilding;

            this.recipientSCV.Read().ConstructionJob.DetachSCV();

            /// Move the SCV to the bottom-left corner of the building.
            RCIntRectangle buildingQuadRect = building.MapObject.QuadraticPosition;
            RCIntRectangle buildingCellRect = this.Scenario.Map.QuadToCellRect(buildingQuadRect);

            this.recipientSCV.Read().MotionControl.StartMoving(new RCNumVector(buildingCellRect.Left, buildingCellRect.Bottom - 1));
        }
        private void Attack(GameState gameState, TerranBuilding commandCenter, List <TerranUnit> soldiers, List <Command> commands)
        {
            // Initially, await X idle soldiers and send them toward the enemy's starting location.
            // Once they're there and have no further orders, send them to attack any sighted enemy unit/structure.
            // Once we run out of those, send them to scout every resource deposit until we find more.
            var enemyStartLocation = gameState.MapData.Raw.StartLocations.OrderByDescending(point => commandCenter.GetDistance(point)).First();

            var idleSoldiers = soldiers.Where(s => s.Raw.Orders.Count == 0).ToList();

            if (!soldiers.Any(s => s.GetDistance(enemyStartLocation) < 5f) ||
                gameState.EnemyUnits.Any(e => e.GetDistance(enemyStartLocation) < 10f))
            {
                if (idleSoldiers.Count >= AttackThreshold)
                {
                    foreach (var soldier in idleSoldiers)
                    {
                        commands.Add(soldier.AttackMove(enemyStartLocation.X, enemyStartLocation.Y));
                    }
                }

                return;
            }

            if (gameState.EnemyUnits.Count > 0)
            {
                foreach (var soldier in idleSoldiers)
                {
                    commands.Add(soldier.AttackMove(gameState.EnemyUnits[0].X, gameState.EnemyUnits[0].Y));
                }

                return;
            }

            var unscoutedLocations = gameState.MapData.Deposits.Select(d => d.Center).ToList();

            foreach (var location in unscoutedLocations)
            {
                if (soldiers.Any(s => s.GetDistance(location) < 5f ||
                                 s.Raw.Orders.Any(o => o.TargetWorldSpacePos.GetDistance(location) < 5f)))
                {
                    continue;
                }

                if (idleSoldiers.Count == 0)
                {
                    break;
                }

                commands.Add(idleSoldiers[0].AttackMove(location));
                idleSoldiers.RemoveAt(0);
            }
        }
        private void BuildWorker(GameState gameState, TerranBuilding commandCenter, List <Command> commands)
        {
            if (commandCenter.IsBuildingSomething)
            {
                return;
            }

            if (workersByMineralDeposit.All(pair => pair.Value.Count >= 2))
            {
                return;
            }

            if (gameState.Observation.PlayerCommon.Minerals >= 50 &&
                gameState.Observation.PlayerCommon.FoodUsed < gameState.Observation.PlayerCommon.FoodCap)
            {
                commands.Add(commandCenter.Train(TerranUnitType.SCV));
            }
        }
        /// <see cref="ProductionJob.StartImpl"/>
        protected override bool StartImpl()
        {
            /// Create the building and begin its construction.
            bool success = this.ElementFactory.CreateElement(this.buildingProduct.Name, this.OwnerPlayer, this.topLeftQuadTile.Read(), this.starterSCV.Read());

            if (success)
            {
                TerranBuilding building = this.OwnerPlayer.Scenario.GetFixedEntity <TerranBuilding>(this.topLeftQuadTile.Read());
                if (building == null)
                {
                    throw new InvalidOperationException("Impossible case happened!");
                }
                this.constructedBuilding.Write(building);
                this.constructedBuilding.Read().OnAttachConstructionJob(this);
                this.AttachSCV(this.starterSCV.Read());
                this.starterSCV.Write(null);
            }
            return(success);
        }
        public IReadOnlyList <Command> Act(GameState gameState)
        {
            /* Detailed strategy:
             *
             * 1. If there are mineral deposits near a base and not being fully mined, supply is not maxed, the base is not currently building anything, and minerals are available, build a worker.
             * 2. If minerals and supply are available, and there is a Barracks or equivalent not building a basic military unit, start building one.
             * 3. If supply is maxed out, build a Supply Depot or equivalent.
             * 4. If minerals are available, build a Barracks or equivalent.
             *
             * No expansion. Once you hit the threshold of military units in existence, attack-move your opponent's base.
             *
             * Implement for Terran only initially (no Creep/Pylon placement concerns).
             *
             * Implement for maps with only two starting locations, so we don't scout.
             */
            var commands = new List <Command>();

            var controlledUnits = gameState.RawUnits.Where(u => u.Alliance == Alliance.Self).ToList();

            TerranBuilding commandCenter    = null;
            var            workers          = new List <TerranUnit>();
            var            soldiers         = new List <TerranUnit>();
            var            soldierProducers = new List <TerranBuilding>();

            if (sleep > 0)
            {
                sleep -= 1;
                return(commands);
            }

            foreach (var unit in gameState.Units)
            {
                if (unit is TerranBuilding terranBuilding)
                {
                    if (terranBuilding.TerranBuildingType == TerranBuildingType.CommandCenter ||
                        terranBuilding.TerranBuildingType == TerranBuildingType.OrbitalCommand ||
                        terranBuilding.TerranBuildingType == TerranBuildingType.PlanetaryFortress)
                    {
                        commandCenter = terranBuilding;
                    }
                    else if (terranBuilding.TerranBuildingType == TerranBuildingType.Barracks)
                    {
                        soldierProducers.Add(terranBuilding);
                    }
                }
                else if (unit is TerranUnit terranUnit)
                {
                    if (terranUnit.TerranUnitType == TerranUnitType.SCV)
                    {
                        workers.Add(terranUnit);
                    }
                    else if (terranUnit.TerranUnitType == TerranUnitType.Marine)
                    {
                        soldiers.Add(terranUnit);
                    }
                }
            }

            Deposit closestDeposit  = gameState.MapData.Deposits.OrderBy(d => commandCenter.GetDistance(d.Center)).First();
            var     mineralDeposits = closestDeposit.Resources.Where(u => u.IsMineralDeposit).ToList();



            // First update, ignore the default worker orders, which are to mass on the center mineral deposit
            // (this ends up causing problems since we have to keep track of who is harvesting what ourselves)
            if (first)
            {
                foreach (var worker in workers)
                {
                    worker.Raw.Orders.Clear();
                }

                workersByMineralDeposit = mineralDeposits.ToDictionary(m => m.Raw.Tag, m => new List <ulong>());
            }

            if (commandCenter == null)
            {
                // Accept death as inevitable.
                return(new List <Command>());

                // TODO: Surrender?
            }

            // Each possible behavior is implemented as a function that adds a command to the list
            // if the situation is appropriate. We will then execute whichever command was added first.
            BuildWorker(gameState, commandCenter, commands);
            BuildMarine(gameState, soldierProducers, commands);
            BuildSupplyDepot(gameState, workers, soldierProducers, commands);
            BuildBarracks(gameState, workers, commands);

            commands = commands.Take(1).ToList();

            // If we tell a worker to build something, make sure we don't think he's harvesting
            if (commands.Count == 1)
            {
                sleep = 1;
                RemoveWorkerFromHarvestAssignments(commands[0].Unit);
            }

            // No matter what else happens, we can always attack, and we should always set idle workers to harvest minerals
            Attack(gameState, commandCenter, soldiers, commands);
            SetIdleWorkerToHarvest(gameState, workers, mineralDeposits, commands);

            if (first)
            {
                first = false;

                // Make sure workers don't automatically harvest minerals, since we're managing assignments ourselves
                commands.Add(commandCenter.RallyWorkers(commandCenter.Raw.Pos.X, commandCenter.Raw.Pos.Y));
            }

            return(commands);
        }