예제 #1
0
파일: Drag.cs 프로젝트: epicelite/OpenRA
        public override Activity Tick(Actor self)
        {
            var positionable = self.Trait <IPositionable>();
            var mobile       = positionable as Mobile;

            var pos = length > 1
                                ? WPos.Lerp(start, end, ticks, length - 1)
                                : end;

            positionable.SetVisualPosition(self, pos);
            if (++ticks >= length)
            {
                if (mobile != null)
                {
                    mobile.IsMoving = false;
                }

                return(NextActivity);
            }

            if (mobile != null)
            {
                mobile.IsMoving = true;
            }

            return(this);
        }
예제 #2
0
        /// <summary>
        /// Find the point (D) on a line (A-B) that is closest to the target point (C).
        /// </summary>
        /// <param name="lineStart">The source point (tail) of the line</param>
        /// <param name="lineEnd">The target point (head) of the line</param>
        /// <param name="point">The target point that the minimum distance should be found to</param>
        /// <returns>The WPos that is the point on the line that is closest to the target point</returns>
        public static WPos MinimumPointLineProjection(WPos lineStart, WPos lineEnd, WPos point)
        {
            var squaredLength = (lineEnd - lineStart).HorizontalLengthSquared;

            // Line has zero length, so just use the lineEnd position as the closest position.
            if (squaredLength == 0)
            {
                return(lineEnd);
            }

            // Consider the line extending the segment, parameterized as target + t (source - target).
            // We find projection of point onto the line.
            // It falls where t = [(point - target) . (source - target)] / |source - target|^2
            // The normal DotProduct math would be (xDiff + yDiff) / dist, where dist = (target - source).LengthSquared;
            // But in order to avoid floating points, we do not divide here, but rather work with the large numbers as far as possible.
            // We then later divide by dist, only AFTER we have multiplied by the dotproduct.
            var xDiff = ((long)point.X - lineEnd.X) * (lineStart.X - lineEnd.X);
            var yDiff = ((long)point.Y - lineEnd.Y) * (lineStart.Y - lineEnd.Y);
            var t     = xDiff + yDiff;

            // Beyond the 'target' end of the segment
            if (t < 0)
            {
                return(lineEnd);
            }

            // Beyond the 'source' end of the segment
            if (t > squaredLength)
            {
                return(lineStart);
            }

            // Projection falls on the segment
            return(WPos.Lerp(lineEnd, lineStart, t, squaredLength));
        }
예제 #3
0
        // gets where main projectile should fly to
        WPos GetTargetPos()
        {
            var targetpos = args.PassiveTarget;
            var actorpos  = args.SourceActor.CenterPosition;

            return(WPos.Lerp(actorpos, targetpos, args.Weapon.Range.Length, (targetpos - actorpos).Length));
        }
예제 #4
0
            void UpdateCenterLocation(Actor self, Mobile mobile)
            {
                // Avoid division through zero
                if (MoveFractionTotal != 0)
                {
                    WPos pos;
                    if (EnableArc)
                    {
                        var angle  = WAngle.Lerp(ArcFromAngle, ArcToAngle, moveFraction, MoveFractionTotal);
                        var length = int2.Lerp(ArcFromLength, ArcToLength, moveFraction, MoveFractionTotal);
                        var height = int2.Lerp(From.Z, To.Z, moveFraction, MoveFractionTotal);
                        pos = ArcCenter + new WVec(0, length, height).Rotate(WRot.FromYaw(angle));
                    }
                    else
                    {
                        pos = WPos.Lerp(From, To, moveFraction, MoveFractionTotal);
                    }

                    pos -= new WVec(WDist.Zero, WDist.Zero, self.World.Map.DistanceAboveTerrain(pos));
                    mobile.SetVisualPosition(self, pos);
                }
                else
                {
                    mobile.SetVisualPosition(self, To);
                }

                if (moveFraction >= MoveFractionTotal)
                {
                    mobile.Facing = ToFacing;
                }
                else
                {
                    mobile.Facing = WAngle.Lerp(FromFacing, ToFacing, moveFraction, MoveFractionTotal);
                }
            }
예제 #5
0
        public static WPos MinimumPointLineProjection(WPos lineStart, WPos lineEnd, WPos point)
        {
            var squaredLength = (lineEnd - lineStart).HorizontalLengthSquared;

            if (squaredLength == 0)
            {
                return(lineEnd);
            }

            var xDiff = ((long)point.X - lineEnd.X) * (lineStart.X - lineEnd.X);
            var yDiff = ((long)point.Y - lineEnd.Y) * (lineStart.Y - lineEnd.Y);

            var t = xDiff + yDiff;

            if (t < 0)
            {
                return(lineEnd);
            }

            if (t > squaredLength)
            {
                return(lineStart);
            }

            return(WPos.Lerp(lineEnd, lineStart, t, squaredLength));
        }
예제 #6
0
파일: Drag.cs 프로젝트: cjshmyr/OpenRA
        public override Activity Tick(Actor self)
        {
            if (disableable != null && disableable.IsTraitDisabled)
            {
                return(this);
            }

            var pos = length > 1
                                ? WPos.Lerp(start, end, ticks, length - 1)
                                : end;

            positionable.SetVisualPosition(self, pos);
            if (++ticks >= length)
            {
                if (movement != null)
                {
                    movement.IsMoving = false;
                }

                return(NextActivity);
            }

            if (movement != null)
            {
                movement.IsMoving = true;
            }

            return(this);
        }
예제 #7
0
파일: Move.cs 프로젝트: hadow/Commander
            void UpdateCenterLocation(Actor self, Mobile mobile)
            {
                //Avoid division through zero
                if (MoveFractionTotal != 0)
                {
                    WPos pos = WPos.Zero;
                    if (EnableArc)
                    {
                        var angle  = WAngle.Lerp(ArcFromAngle, ArcToAngle, moveFraction, MoveFractionTotal);
                        var length = Int2.Lerp(ArcFromLength, ArcToLength, moveFraction, MoveFractionTotal);
                        var height = Int2.Lerp(From.Z, To.Z, moveFraction, MoveFractionTotal);
                        pos = ArcCenter + new WVec(0, length, length).Rotate(WRot.FromYaw(angle));
                    }
                    else
                    {
                        pos = WPos.Lerp(From, To, moveFraction, MoveFractionTotal);
                    }

                    mobile.SetVisualPosition(self, pos);
                }
                else
                {
                    mobile.SetVisualPosition(self, To);
                }

                if (moveFraction >= MoveFractionTotal)
                {
                    mobile.Facing = ToFacing & 0xFF;
                }
                else
                {
                    mobile.Facing = Int2.Lerp(FromFacing, ToFacing, moveFraction, MoveFractionTotal) & 0xFF;
                }
            }
예제 #8
0
        public static WPos BetweenCells(World w, CPos from, CPos to)
        {
            var fromPos = from.Layer == 0 ? w.Map.CenterOfCell(from) : w.GetCustomMovementLayers()[from.Layer].CenterOfCell(from);

            var toPos = to.Layer == 0 ? w.Map.CenterOfCell(to) : w.GetCustomMovementLayers()[to.Layer].CenterOfCell(to);

            return(WPos.Lerp(fromPos, toPos, 1, 2));
        }
예제 #9
0
        public void Tick(World world)
        {
            ticks++;
            if (anim != null)
            {
                anim.Tick();
            }

            var lastPos = projectilepos;

            projectilepos = WPos.Lerp(source, targetpos, ticks, estimatedlifespan);

            // Check for walls or other blocking obstacles.
            WPos blockedPos;

            if (info.Blockable && BlocksProjectiles.AnyBlockingActorsBetween(world, lastPos, projectilepos, info.Width, out blockedPos))
            {
                projectilepos = blockedPos;
                DetonateSelf  = true;
            }

            if (!string.IsNullOrEmpty(info.TrailImage) && --smokeTicks < 0)
            {
                var delayedPos = WPos.Lerp(source, targetpos, ticks - info.TrailDelay, estimatedlifespan);
                world.AddFrameEndTask(w => w.Add(new SpriteEffect(delayedPos, w, info.TrailImage, info.TrailSequences.Random(world.SharedRandom),
                                                                  trailPalette, false, false, GetEffectiveFacing())));

                smokeTicks = info.TrailInterval;
            }

            if (info.ContrailLength > 0)
            {
                contrail.Update(projectilepos);
            }

            var flightLengthReached = ticks >= lifespan;

            if (flightLengthReached)
            {
                DetonateSelf = true;
            }

            // Driving into cell with higher height level
            DetonateSelf |= world.Map.DistanceAboveTerrain(projectilepos) < info.ExplodeUnderThisAltitude;

            if (DetonateSelf)
            {
                Explode(world);
            }
        }
예제 #10
0
        public override Activity Tick(Actor self)
        {
            if (canceled)
            {
                return(NextActivity);
            }

            // Correct the visual position after we jumped
            if (jumpComplete)
            {
                if (ChildActivity == null)
                {
                    return(NextActivity);
                }

                ChildActivity = ActivityUtils.RunActivity(self, ChildActivity);
                return(this);
            }

            if (target.Type != TargetType.Invalid)
            {
                targetPosition = target.CenterPosition;
            }

            var position = length > 1 ? WPos.Lerp(origin, targetPosition, ticks, length - 1) : targetPosition;

            mobile.SetVisualPosition(self, position);

            // We are at the destination
            if (++ticks >= length)
            {
                // Revoke the run condition
                attack.IsAiming = false;

                // Move to the correct subcells, if our target actor uses subcells
                // (This does not update the visual position!)
                mobile.SetLocation(destinationCell, destinationSubCell, destinationCell, destinationSubCell);

                // Revoke the condition before attacking, as it is usually used to pause the attack trait
                attack.RevokeLeapCondition(self);
                attack.DoAttack(self, target);

                jumpComplete = true;
                QueueChild(self, mobile.VisualMove(self, position, self.World.Map.CenterOfSubCell(destinationCell, destinationSubCell)), true);

                return(this);
            }

            return(this);
        }
예제 #11
0
파일: Drag.cs 프로젝트: reaperrr/OpenRA
        public override bool Tick(Actor self)
        {
            if (disableable != null && disableable.IsTraitDisabled)
            {
                return(false);
            }

            var pos = length > 1
                                ? WPos.Lerp(start, end, ticks, length - 1)
                                : end;

            positionable.SetVisualPosition(self, pos);
            if (++ticks >= length)
            {
                return(true);
            }

            return(false);
        }
예제 #12
0
        public override bool Tick(Actor self)
        {
            // Correct the visual position after we jumped
            if (canceled || jumpComplete)
            {
                return(true);
            }

            if (target.Type != TargetType.Invalid)
            {
                targetPosition = target.CenterPosition;
            }

            var position = length > 1 ? WPos.Lerp(origin, targetPosition, ticks, length - 1) : targetPosition;

            mobile.SetVisualPosition(self, position);

            // We are at the destination
            if (++ticks >= length)
            {
                // Revoke the run condition
                attack.IsAiming = false;

                // Move to the correct subcells, if our target actor uses subcells
                // (This does not update the visual position!)
                mobile.SetLocation(destinationCell, destinationSubCell, destinationCell, destinationSubCell);

                // Update movement which results in movementType set to MovementType.None.
                // This is needed to prevent the move animation from playing.
                mobile.UpdateMovement(self);

                // Revoke the condition before attacking, as it is usually used to pause the attack trait
                attack.RevokeLeapCondition(self);
                attack.DoAttack(self, target);

                jumpComplete = true;
                QueueChild(mobile.VisualMove(self, position, self.World.Map.CenterOfSubCell(destinationCell, destinationSubCell)));
            }

            return(false);
        }
예제 #13
0
            void UpdateCenterLocation(Actor self, Mobile mobile)
            {
                // avoid division through zero
                if (MoveFractionTotal != 0)
                {
                    mobile.SetVisualPosition(self, WPos.Lerp(From, To, moveFraction, MoveFractionTotal));
                }
                else
                {
                    mobile.SetVisualPosition(self, To);
                }

                if (moveFraction >= MoveFractionTotal)
                {
                    mobile.Facing = ToFacing & 0xFF;
                }
                else
                {
                    mobile.Facing = int2.Lerp(FromFacing, ToFacing, moveFraction, MoveFractionTotal) & 0xFF;
                }
            }
예제 #14
0
        public virtual WVec GetRepulsionForce()
        {
            if (!Info.Repulsable)
            {
                return(WVec.Zero);
            }

            if (reservation != null)
            {
                var distanceFromReservationActor = (ReservedActor.CenterPosition - self.CenterPosition).HorizontalLength;
                if (distanceFromReservationActor < Info.WaitDistanceFromResupplyBase.Length)
                {
                    return(WVec.Zero);
                }
            }

            // Repulsion only applies when we're flying at CruiseAltitude!
            if (!cruising)
            {
                return(WVec.Zero);
            }

            // PERF: Avoid LINQ.
            var repulsionForce = WVec.Zero;

            foreach (var actor in self.World.FindActorsInCircle(self.CenterPosition, Info.IdealSeparation))
            {
                if (actor.IsDead)
                {
                    continue;
                }

                var ai = actor.Info.TraitInfoOrDefault <AircraftInfo>();
                if (ai == null || !ai.Repulsable || ai.CruiseAltitude != Info.CruiseAltitude)
                {
                    continue;
                }

                repulsionForce += GetRepulsionForce(actor);
            }

            // Actors outside the map bounds receive an extra nudge towards the center of the map
            if (!self.World.Map.Contains(self.Location))
            {
                // The map bounds are in projected coordinates, which is technically wrong for this,
                // but we avoid the issues in practice by guessing the middle of the map instead of the edge
                var center = WPos.Lerp(self.World.Map.ProjectedTopLeft, self.World.Map.ProjectedBottomRight, 1, 2);
                repulsionForce += new WVec(1024, 0, 0).Rotate(WRot.FromYaw((self.CenterPosition - center).Yaw));
            }

            if (Info.CanHover)
            {
                return(repulsionForce);
            }

            // Non-hovering actors mush always keep moving forward, so they need extra calculations.
            var currentDir = FlyStep(Facing);
            var length     = currentDir.HorizontalLength * repulsionForce.HorizontalLength;

            if (length == 0)
            {
                return(WVec.Zero);
            }

            var dot = WVec.Dot(currentDir, repulsionForce) / length;

            // avoid stalling the plane
            return(dot >= 0 ? repulsionForce : WVec.Zero);
        }
예제 #15
0
        public void Tick(World world)
        {
            ticks++;
            if (anim != null)
            {
                anim.Tick();
            }

            var lastPos = projectilepos;

            var dx     = projectilepos.X - source.X;
            var dy     = projectilepos.Y - source.Y;
            var normal = new WVec(dy, -dx, 0);

            targetpos = projectilepos;
            var originalVec = projectilepos - source;

            if (dx != 0 || dy != 0)
            {
                int circSpeed = 1 + (ticks * 3);
                int maxSpeed  = 200;
                if (circSpeed > maxSpeed)
                {
                    circSpeed = maxSpeed;
                }

                normal     = WVec.Lerp(WVec.Zero, normal, circSpeed, normal.Length);
                targetpos -= normal;
                targetpos += WVec.Lerp(WVec.Zero, originalVec, 30, originalVec.Length);
            }
            else
            {
                targetpos += args.VecNormalized;
            }

            projectilepos = targetpos;

            if (ticks > 90)
            {
                DetonateSelf = true;
            }

            // Check for walls or other blocking obstacles.
            WPos blockedPos;

            if (info.Blockable && BlocksProjectiles.AnyBlockingActorsBetween(world, lastPos, projectilepos, info.Width, out blockedPos))
            {
                projectilepos = blockedPos;
                DetonateSelf  = true;
            }

            if (!string.IsNullOrEmpty(info.TrailImage) && --smokeTicks < 0)
            {
                var delayedPos = WPos.Lerp(lastPos, targetpos, ticks - info.TrailDelay, estimatedlifespan);
                world.AddFrameEndTask(w => w.Add(new SpriteEffect(delayedPos, w, info.TrailImage, info.TrailSequences.Random(world.SharedRandom),
                                                                  trailPalette, false, GetEffectiveFacing().Angle)));

                smokeTicks = info.TrailInterval;
            }

            if (info.ContrailLength > 0)
            {
                contrail.Update(projectilepos);
            }

            var flightLengthReached = ticks >= lifespan;

            if (flightLengthReached)
            {
                DetonateSelf = true;
            }

            // Driving into cell with higher height level
            DetonateSelf |= world.Map.DistanceAboveTerrain(projectilepos) < info.ExplodeUnderThisAltitude;

            if (DetonateSelf)
            {
                Explode(world);
            }
        }
예제 #16
0
        // gets where main projectile should fly to
        WPos GetTargetPos()
        {
            var targetpos = args.PassiveTarget;

            return(WPos.Lerp(sourcepos, targetpos, args.Weapon.Range.Length, (targetpos - sourcepos).Length));
        }
예제 #17
0
 public static WPos BetweenCells(World w, CPos from, CPos to)
 {
     return(WPos.Lerp(w.Map.CenterOfCell(from), w.Map.CenterOfCell(to), 1, 2));
 }
예제 #18
0
        public virtual WVec GetRepulsionForce()
        {
            if (!Info.Repulsable)
            {
                return(WVec.Zero);
            }

            if (reservation != null)
            {
                var distanceFromReservationActor = (ReservedActor.CenterPosition - self.CenterPosition).HorizontalLength;
                if (distanceFromReservationActor < Info.WaitDistanceFromResupplyBase.Length)
                {
                    return(WVec.Zero);
                }
            }


            var altitude = self.World.Map.DistanceAboveTerrain(CenterPosition).Length;

            if (altitude != Info.CruiseAltitude.Length)
            {
                return(WVec.Zero);
            }

            var repulsionForce = WVec.Zero;

            foreach (var actor in self.World.FindActorsInCircle(self.CenterPosition, Info.IdealSeparation))
            {
                if (actor.IsDead)
                {
                    continue;
                }

                var ai = actor.Info.TraitInfoOrDefault <AircraftInfo>();

                if (ai == null || !ai.Repulsable || ai.CruiseAltitude != Info.CruiseAltitude)
                {
                    continue;
                }

                repulsionForce += GetRepulsionForce(actor);
            }

            if (!self.World.Map.Contains(self.Location))
            {
                var center = WPos.Lerp(self.World.Map.ProjectedTopLeft, self.World.Map.ProjectedBottomRight, 1, 2);
                repulsionForce += new WVec(1024, 0, 0).Rotate(WRot.FromYaw((self.CenterPosition - center).Yaw));
            }

            if (Info.CanHover)
            {
                return(repulsionForce);
            }

            var currentDir = FlyStep(Facing);

            var length = currentDir.HorizontalLength * repulsionForce.HorizontalLength;

            if (length == 0)
            {
                return(WVec.Zero);
            }

            var dot = WVec.Dot(currentDir, repulsionForce) / length;

            //avoid stalling the plane
            return(dot >= 0 ? repulsionForce : WVec.Zero);
        }
예제 #19
0
 public static WPos BetweenCells(CPos from, CPos to)
 {
     return(WPos.Lerp(from.CenterPosition, to.CenterPosition, 1, 2));
 }
예제 #20
0
        public ShockWaveProjectile(ShockWaveProjectileInfo info, ProjectileArgs args)
        {
            this.info = info;
            this.args = args;

            sourcepos = args.Source;

            var firedBy = args.SourceActor;

            world = args.SourceActor.World;

            if (info.Speed.Length > 1)
            {
                speed = new WDist(world.SharedRandom.Next(info.Speed[0].Length, info.Speed[1].Length));
            }
            else
            {
                speed = info.Speed[0];
            }

            targetpos = GetTargetPos();

            mindelay = args.Weapon.MinRange.Length / speed.Length;

            projectiles = new ShockWaveProjectileEffect[info.NumProjectiles];

            var mainFacing = (targetpos - sourcepos).Yaw.Facing;

            // used for lerping projectiles at the same pace
            var estimatedLifespan = Math.Max(args.Weapon.Range.Length / speed.Length, 1);

            // target that will be assigned
            Target target;

            // subprojectiles facing
            WAngle facing;

            var convergePoint = WPos.Lerp(sourcepos, targetpos, info.SpreadUntilDistance.Length, (targetpos - sourcepos).Length);
            var dx            = targetpos.X - sourcepos.X;
            var dy            = targetpos.Y - sourcepos.Y;
            var normal        = new WVec(-dy, dx, 0);

            for (int i = 0; i < info.NumProjectiles; i++)
            {
                target = Target.FromPos(targetpos);

                // If it's true then lifespan is counted from source position to target instead of max range.
                lifespan = info.KillProjectilesWhenReachedTargetLocation
                                        ? Math.Max((args.PassiveTarget - args.Source).Length / speed.Length, 1)
                                        : estimatedLifespan;

                facing = (targetpos - sourcepos).Yaw;

                int shiftIndex    = (i - (info.NumProjectiles / 2)) * info.Splay;
                var newRotation   = WRot.FromFacing(shiftIndex);
                var rotatedTarget = (targetpos - sourcepos).Rotate(newRotation);

                target = Target.FromPos(sourcepos + rotatedTarget);

                var projectileArgs = new ShockwaveProjectileArgs
                {
                    Weapon            = args.Weapon,
                    DamageModifiers   = args.DamageModifiers,
                    Facing            = facing,
                    Source            = sourcepos,
                    CurrentSource     = () => sourcepos,
                    SourceActor       = firedBy,
                    GuidedTarget      = target,
                    PassiveTarget     = sourcepos + rotatedTarget,
                    ConvergePoint     = convergePoint,
                    OriginalTargetVec = targetpos - sourcepos,
                    Normal            = normal
                };

                projectiles[i] = new ShockWaveProjectileEffect(info, projectileArgs, lifespan, estimatedLifespan);
            }

            foreach (var p in projectiles)
            {
                world.AddFrameEndTask(w => w.Add(p));
            }
        }
예제 #21
0
        public void Tick(Actor self)
        {
            if (world.FrameNumber % 100 == 0)
            {
                var actor = OffmapAttackers.Random(world.SharedRandom);
                var spawn = offmapAttackerSpawns.Random(world.SharedRandom);
                var u     = world.CreateActor(actor, soviets, spawn.Location, Traits.Util.GetFacing(attackLocation.Location - spawn.Location, 0));
                var cargo = u.TraitOrDefault <Cargo>();
                if (cargo != null)
                {
                    while (cargo.HasSpace(1))
                    {
                        cargo.Load(u, world.CreateActor(false, AttackerCargo.Random(world.SharedRandom), soviets, null, null));
                    }
                }
                u.QueueActivity(new AttackMove.AttackMoveActivity(u, new Move.Move(attackLocation.Location, 0)));
            }

            if (world.FrameNumber % 25 == 0)
            {
                foreach (var actor in world.Actors.Where(a => a.IsInWorld && a.IsIdle && !a.IsDead() &&
                                                         a.HasTrait <AttackBase>() && a.HasTrait <Mobile>()).Except(actors.Values))
                {
                    MissionUtils.AttackNearestLandActor(true, actor, actor.Owner == soviets ? allies : soviets);
                }

                MissionUtils.StartProduction(world, allies, "Infantry", InfantryProductionUnits.Random(world.SharedRandom));
                MissionUtils.StartProduction(world, allies, "Vehicle", VehicleProductionUnits.Random(world.SharedRandom));
            }

            if (world.FrameNumber % 20 == 0 && coastUnitsLeft-- > 0)
            {
                var u = world.CreateActor(CoastUnits.Random(world.SharedRandom), soviets, coastWP1.Location, null);
                u.QueueActivity(new Move.Move(coastWP2.Location, 0));
                u.QueueActivity(new AttackMove.AttackMoveActivity(u, new Move.Move(attackLocation.Location, 0)));
            }

            if (world.FrameNumber == nextCivilianMove)
            {
                var civilians = world.Actors.Where(a => !a.IsDead() && a.IsInWorld && a.Owner == neutral && a.HasTrait <Mobile>());
                if (civilians.Any())
                {
                    var civilian = civilians.Random(world.SharedRandom);
                    civilian.Trait <Mobile>().Nudge(civilian, civilian, true);
                    nextCivilianMove += world.SharedRandom.Next(1, 75);
                }
            }

            if (world.FrameNumber == 1)
            {
                MissionUtils.Paradrop(world, soviets, ParadropUnits, paradrop1Entry.Location, paradrop1LZ.Location);
                MissionUtils.Paradrop(world, soviets, ParadropUnits, paradrop2Entry.Location, paradrop2LZ.Location);
            }

            if (--waitTicks <= 0)
            {
                if (++mul <= div)
                {
                    worldRenderer.Viewport.Center(WPos.Lerp(viewportOrigin, viewportTarget, mul, div));
                }
                else
                {
                    mul            = 0;
                    viewportOrigin = viewportTarget;
                    viewportTarget = viewportTargets[(viewportTargetNumber = (viewportTargetNumber + 1) % viewportTargets.Length)];
                    waitTicks      = 100;

                    if (viewportTargetNumber == 0)
                    {
                        coastUnitsLeft = 15;
                        SendChinookReinforcements(chinook1Entry.Location, chinook1LZ);
                        SendChinookReinforcements(chinook2Entry.Location, chinook2LZ);
                    }
                    if (viewportTargetNumber == 1)
                    {
                        MissionUtils.Paradrop(world, soviets, ParadropUnits, paradrop1Entry.Location, paradrop1LZ.Location);
                        MissionUtils.Paradrop(world, soviets, ParadropUnits, paradrop2Entry.Location, paradrop2LZ.Location);
                    }
                    if (viewportTargetNumber == 2)
                    {
                        AttackWithHeavyTanks();
                        ChronoSpawnMediumTanks();
                    }
                    if (viewportTargetNumber == 4)
                    {
                        FlyMigs(mig1Waypoints);
                        FlyMigs(mig2Waypoints);
                    }
                }
            }

            MissionUtils.CapOre(soviets);
        }