/// <see cref="SCVBuildExecutionBase.ContinueMovingToTarget"/>
        protected override bool ContinueMovingToTarget()
        {
            /// Check the distance between the SCV and the target area.
            RCNumber distance = MapUtils.ComputeDistance(this.RecipientSCV.Area, this.targetArea.Read());

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

            TerranBuildingConstructionJob job = new TerranBuildingConstructionJob(
                this.RecipientSCV,
                this.RecipientSCV.Owner.Metadata.GetBuildingType(this.buildingTypeName),
                this.topLeftQuadTile.Read());

            if (!job.LockResources())
            {
                /// Unable to lock the necessary resources -> abort the job and cancel.
                job.Dispose();
                return(true);
            }

            if (!job.Start())
            {
                /// Unable to start the job -> abort the job and cancel.
                job.Dispose();
                return(true);
            }

            this.Status = SCVBuildExecutionStatusEnum.Constructing;
            return(false);
        }
Пример #2
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);
        }
Пример #3
0
        /// <summary>
        /// Gets the list of all velocities that are admissible from the given velocity.
        /// </summary>
        /// <param name="currentVelocity">The given velocity.</param>
        /// <returns>All velocities that are admissible from the given velocity.</returns>
        public List <RCNumVector> GetAdmissibleVelocities(RCNumVector currentVelocity)
        {
            if (!this.velocityGraph.ContainsKey(currentVelocity))
            {
                /// Search the velocity that has a minimum difference to the current velocity.
                RCNumber    minDiff         = 0;
                RCNumVector closestVelocity = RCNumVector.Undefined;
                foreach (RCNumVector velocity in this.velocityGraph.Keys)
                {
                    RCNumber diff = MapUtils.ComputeDistance(currentVelocity, velocity);
                    if (closestVelocity == RCNumVector.Undefined || diff < minDiff)
                    {
                        minDiff         = diff;
                        closestVelocity = velocity;
                    }
                }

                if (closestVelocity == RCNumVector.Undefined)
                {
                    throw new InvalidOperationException("Impossible case!");
                }
                currentVelocity = closestVelocity;
            }

            return(new List <RCNumVector>(this.velocityGraph[currentVelocity]));
        }
Пример #4
0
        /// <summary>
        /// Updates this missile if it is in Launched state.
        /// </summary>
        private bool UpdateLaunchedState()
        {
            /// Update the target entity position and height if it is still on the map.
            if (this.targetEntity.Read().HasMapObject(MapObjectLayerEnum.GroundObjects, MapObjectLayerEnum.AirObjects))
            {
                this.lastKnownTargetEntityPos.Write(this.targetEntity.Read().MotionControl.PositionVector.Read());
                this.lastKnownTargetEntityIsFlying.Write(this.targetEntity.Read().MotionControl.IsFlying ? (byte)0x01 : (byte)0x00);
            }

            /// Move immediately to the Impacted state if this is an instant missile.
            /// Note: a missile is instant if it has no speed defined.
            if (this.missileData.MissileType.Speed == null)
            {
                if (this.Impact != null)
                {
                    this.Impact(this);
                }
                this.currentStatus.Write((byte)Status.Impacted);
                if (this.missileIndicator != null && !this.missileIndicator.IsDestroyed)
                {
                    this.DestroyMapObject(this.missileIndicator);
                }
                return(true);
            }

            /// Calculate the new position and velocity of the missile.
            this.UpdateVelocity();
            this.missilePosition.Write(this.missilePosition.Read() + this.missileVelocity.Read());

            /// Check if the missile impacts.
            if (MapUtils.ComputeDistance(this.missilePosition.Read(), this.lastKnownTargetEntityPos.Read()) <= this.missileData.MissileType.Speed.Read())
            {
                if (this.Impact != null)
                {
                    this.Impact(this);
                }
                this.currentStatus.Write((byte)Status.Impacted);
                if (this.missileIndicator != null && !this.missileIndicator.IsDestroyed)
                {
                    this.DestroyMapObject(this.missileIndicator);
                }
                return(true);
            }

            /// Create a missile indicator map object if it has not yet been created and the missile type defines a flying animation...
            if (this.missileIndicator == null && this.missileData.MissileType.FlyingAnimation != null)
            {
                this.missileIndicator = this.CreateMapObject(this.CalculateArea(this.missilePosition.Read()), this.lastKnownTargetEntityIsFlying.Read() == 0x01 ? MapObjectLayerEnum.AirMissiles : MapObjectLayerEnum.GroundMissiles);
                this.missileIndicator.StartAnimation(this.missileData.MissileType.FlyingAnimation, this.missileVelocity);
            }
            else if (this.missileIndicator != null && !this.missileIndicator.IsDestroyed)
            {
                /// ... or update its position if already exists.
                this.missileIndicator.SetLocation(this.CalculateArea(this.missilePosition.Read()));
            }
            return(true);
        }
Пример #5
0
        /// <summary>
        /// Checks whether the given target entity is in the attack range of this weapon.
        /// </summary>
        /// <param name="targetEntity">The target entity.</param>
        /// <returns>True if the given target entity is in the attack range of this weapon; otherwise false.</returns>
        public bool IsEntityInRange(Entity targetEntity)
        {
            if (!this.CanTargetEntity(targetEntity))
            {
                return(false);
            }

            RCNumRectangle ownerArea  = this.owner.Read().Area;
            RCNumRectangle targetArea = targetEntity.Area;

            return(this.IsInRange(MapUtils.ComputeDistance(ownerArea, targetArea)));
        }
Пример #6
0
        /// <summary>
        /// Selects an enemy that can be attacked by the owner.
        /// </summary>
        /// <returns>An enemy that can be attacked by the owner or null if no such enemy has been found.</returns>
        public Entity SelectEnemyForStandardWeapons()
        {
            if (this.standardWeapons.Count == 0)
            {
                /// The owner has no standard weapons -> no enemy can be attacked.
                return(null);
            }

            /// Select the nearest enemy.
            RCNumber nearestEnemyDistance = 0;
            Entity   nearestEnemy         = null;

            foreach (Entity locatedEntity in this.owner.Read().Locator.LocateEntities())
            {
                /// Check if the located entity is an enemy or not.
                if (locatedEntity.Owner == null || locatedEntity.Owner == this.owner.Read().Owner)
                {
                    continue;
                }

                /// Check if any of the standard weapons can target the located entity.
                bool hasWeaponCanTargetEntity = false;
                foreach (Weapon standardWeapon in this.standardWeapons)
                {
                    if (standardWeapon.CanTargetEntity(locatedEntity))
                    {
                        hasWeaponCanTargetEntity = true;
                        break;
                    }
                }
                if (!hasWeaponCanTargetEntity)
                {
                    /// The owner has no weapons that can attack the located enemy -> continue with the next located enemy.
                    continue;
                }

                if (nearestEnemy == null)
                {
                    nearestEnemy = locatedEntity;
                }
                else
                {
                    RCNumber distance = MapUtils.ComputeDistance(this.owner.Read().Area, locatedEntity.Area);
                    if (distance < nearestEnemyDistance)
                    {
                        nearestEnemy = locatedEntity;
                    }
                }
            }

            return(nearestEnemy);
        }
Пример #7
0
        /// <summary>
        /// Calculates the next position of the controlled entity from its current position and the next waypoint.
        /// </summary>
        /// <returns>The calculated next position of the controlled entity.</returns>
        private RCNumVector CalculateNextPosition()
        {
            RCNumVector currentPosition = this.controlledEntity.Read().MotionControl.PositionVector.Read();
            RCNumber    distToWP        = MapUtils.ComputeDistance(currentPosition, this.CurrentWaypoint);

            if (distToWP > this.controlledEntity.Read().ElementType.Speed.Read())
            {
                // Move towards the next waypoint.
                RCNumVector translationVect = (this.controlledEntity.Read().ElementType.Speed.Read() / distToWP) * (this.CurrentWaypoint - currentPosition);
                return(currentPosition + translationVect);
            }
            else
            {
                // Next waypoint can be reached in this step.
                return(this.CurrentWaypoint);
            }
        }
Пример #8
0
 /// <summary>
 /// Calculates the list of visible quadratic coordinates from the last known value of the sight range.
 /// </summary>
 private void CalculateRelativeQuadCoordsInSight()
 {
     if (this.lastKnownSightRange == -1)
     {
         this.relativeQuadCoordsInSight = null;
     }
     else
     {
         RCIntVector nullVector = new RCIntVector(0, 0);
         this.relativeQuadCoordsInSight = new RCSet <RCIntVector>();
         for (int x = -this.lastKnownSightRange; x <= this.lastKnownSightRange; x++)
         {
             for (int y = -this.lastKnownSightRange; y <= this.lastKnownSightRange; y++)
             {
                 RCIntVector quadCoord = new RCIntVector(x, y);
                 if (MapUtils.ComputeDistance(nullVector, quadCoord) < this.lastKnownSightRange)
                 {
                     this.relativeQuadCoordsInSight.Add(quadCoord);
                 }
             }
         }
     }
 }
Пример #9
0
        /// <summary>
        /// Continue the execution in case of a follow command.
        /// </summary>
        /// <returns>True if execution is finished; otherwise false.</returns>
        private void ContinueFollow()
        {
            /// Check if target entity still can be located.
            this.targetEntity.Write(this.LocateEntity(this.targetEntityID.Read()));
            if (!this.HasToFollowTarget)
            {
                return;
            }

            /// Calculate its distance from the recipient entity.
            RCNumber distance = MapUtils.ComputeDistance(this.recipientEntity.Read().Area, this.targetEntity.Read().Area);

            if (distance > MAX_DISTANCE)
            {
                /// Too far -> start approaching again.
                this.recipientEntity.Read().MotionControl.StartMoving(this.targetEntity.Read().MotionControl.PositionVector.Read());
            }
            //else
            //{
            //    /// Close enough -> stop the recipient entity.
            //    this.recipientEntity.Read().MotionControl.StopMoving();
            //}
        }
Пример #10
0
        /// <summary>
        /// Sets the sight range of the corresponding element type.
        /// </summary>
        public void SetSightRange(int sightRange)
        {
            if (this.metadata.IsFinalized)
            {
                throw new InvalidOperationException("Already finalized!");
            }
            this.sightRange = new ConstValue <int>(sightRange);

            RCIntVector nullVector = new RCIntVector(0, 0);

            this.relativeQuadCoordsInSight = new RCSet <RCIntVector>();
            for (int x = -this.sightRange.Read(); x <= this.sightRange.Read(); x++)
            {
                for (int y = -this.sightRange.Read(); y <= this.sightRange.Read(); y++)
                {
                    RCIntVector quadCoord = new RCIntVector(x, y);
                    if (MapUtils.ComputeDistance(nullVector, quadCoord) < this.sightRange.Read())
                    {
                        this.relativeQuadCoordsInSight.Add(quadCoord);
                    }
                }
            }
        }
Пример #11
0
        /// <summary>
        /// Updates the velocity of this missile.
        /// </summary>
        private void UpdateVelocity()
        {
            RCNumVector vectorToTarget = this.lastKnownTargetEntityPos.Read() - this.missilePosition.Read();

            if (this.missileData.MissileType.Speed == null)
            {
                this.missileVelocity.Write(vectorToTarget);
                return;
            }

            int                currVelocityIndex    = 0;
            int                bestVelocityIndex    = -1;
            RCNumber           minDistanceToTarget  = 0;
            List <RCNumVector> admissibleVelocities =
                new List <RCNumVector>(
                    this.velocityGraph.GetAdmissibleVelocities(this.missileVelocity.Read() != RCNumVector.Undefined
                        ? this.missileVelocity.Read()
                        : vectorToTarget));

            foreach (RCNumVector admissibleVelocity in admissibleVelocities)
            {
                RCNumber distanceToTarget = MapUtils.ComputeDistance(vectorToTarget, admissibleVelocity);
                if (bestVelocityIndex == -1 || distanceToTarget < minDistanceToTarget)
                {
                    minDistanceToTarget = distanceToTarget;
                    bestVelocityIndex   = currVelocityIndex;
                }
                currVelocityIndex++;
            }

            if (bestVelocityIndex == -1)
            {
                throw new InvalidOperationException("Unable to select best velocity for missile!");
            }
            this.missileVelocity.Write(admissibleVelocities[bestVelocityIndex]);
        }