Beispiel #1
0
        public void Tick(World world)
        {
            if (--remaining <= 0)
                world.AddFrameEndTask(w => w.Remove(this));

            pos += velocity;
        }
Beispiel #2
0
        public NukeLaunch(Player firedBy, string weapon, WPos launchPos, WPos targetPos, WDist velocity, int delay, bool skipAscent, string flashType)
        {
            this.firedBy = firedBy;
            this.weapon = weapon;
            this.delay = delay;
            this.turn = delay / 2;
            this.flashType = flashType;

            var offset = new WVec(WDist.Zero, WDist.Zero, velocity * turn);
            ascendSource = launchPos;
            ascendTarget = launchPos + offset;
            descendSource = targetPos + offset;
            descendTarget = targetPos;

            anim = new Animation(firedBy.World, weapon);
            anim.PlayRepeating("up");

            pos = launchPos;
            var weaponRules = firedBy.World.Map.Rules.Weapons[weapon.ToLowerInvariant()];
            if (weaponRules.Report != null && weaponRules.Report.Any())
                Sound.Play(weaponRules.Report.Random(firedBy.World.SharedRandom), pos);

            if (skipAscent)
                ticks = turn;
        }
Beispiel #3
0
 public IEnumerable<Actor> ActorsInBox(WPos a, WPos b)
 {
     var left = Math.Min(a.X, b.X);
     var top = Math.Min(a.Y, b.Y);
     var right = Math.Max(a.X, b.X);
     var bottom = Math.Max(a.Y, b.Y);
     var region = BinRectangleCoveringWorldArea(left, top, right, bottom);
     var minCol = region.Left;
     var minRow = region.Top;
     var maxCol = region.Right;
     var maxRow = region.Bottom;
     for (var row = minRow; row <= maxRow; row++)
     {
         for (var col = minCol; col <= maxCol; col++)
         {
             foreach (var actor in BinAt(row, col).Actors)
             {
                 if (actor.IsInWorld)
                 {
                     var c = actor.CenterPosition;
                     if (left <= c.X && c.X <= right && top <= c.Y && c.Y <= bottom)
                         yield return actor;
                 }
             }
         }
     }
 }
Beispiel #4
0
        public SatelliteLaunch(Actor a)
        {
            doors.PlayThen("active",
                () => a.World.AddFrameEndTask(w => w.Remove(this)));

            pos = a.CenterPosition;
        }
Beispiel #5
0
		public SpriteEffect(WPos pos, World world, string sprite, string palette)
		{
			this.pos = pos;
			this.palette = palette;
			anim = new Animation(world, sprite);
			anim.PlayThen("idle", () => world.AddFrameEndTask(w => w.Remove(this)));
		}
Beispiel #6
0
        public IEnumerable<Actor> ActorsInBox(WPos a, WPos b)
        {
            var left = Math.Min(a.X, b.X);
            var top = Math.Min(a.Y, b.Y);
            var right = Math.Max(a.X, b.X);
            var bottom = Math.Max(a.Y, b.Y);
            var i1 = (left / info.BinSize).Clamp(0, cols - 1);
            var i2 = (right / info.BinSize).Clamp(0, cols - 1);
            var j1 = (top / info.BinSize).Clamp(0, rows - 1);
            var j2 = (bottom / info.BinSize).Clamp(0, rows - 1);

            for (var j = j1; j <= j2; j++)
            {
                for (var i = i1; i <= i2; i++)
                {
                    foreach (var actor in bins[j * cols + i].Actors)
                    {
                        if (actor.IsInWorld)
                        {
                            var c = actor.CenterPosition;
                            if (left <= c.X && c.X <= right && top <= c.Y && c.Y <= bottom)
                                yield return actor;
                        }
                    }
                }
            }
        }
Beispiel #7
0
        public GpsSatellite(World world, WPos pos)
        {
            this.pos = pos;

            anim = new Animation(world, "sputnik");
            anim.PlayRepeating("idle");
        }
Beispiel #8
0
        public Missile(MissileInfo info, ProjectileArgs args)
        {
            this.info = info;
            this.args = args;

            pos = args.Source;
            facing = args.Facing;

            targetPosition = args.PassiveTarget;

            var world = args.SourceActor.World;

            if (world.SharedRandom.Next(100) <= info.LockOnProbability)
                lockOn = true;

            if (info.Inaccuracy.Range > 0)
            {
                var inaccuracy = OpenRA.Traits.Util.ApplyPercentageModifiers(info.Inaccuracy.Range, args.InaccuracyModifiers);
                offset = WVec.FromPDF(world.SharedRandom, 2) * inaccuracy / 1024;
            }

            if (info.Image != null)
            {
                anim = new Animation(world, info.Image, () => facing);
                anim.PlayRepeating("idle");
            }

            if (info.ContrailLength > 0)
            {
                var color = info.ContrailUsePlayerColor ? ContrailRenderable.ChooseColor(args.SourceActor) : info.ContrailColor;
                trail = new ContrailRenderable(world, color, info.ContrailLength, info.ContrailDelay, 0);
            }
        }
Beispiel #9
0
		public List<CPos> FindUnitPathToRange(CPos source, SubCell srcSub, WPos target, WDist range, Actor self)
		{
			var mi = self.Info.TraitInfo<MobileInfo>();
			var targetCell = world.Map.CellContaining(target);

			// Correct for SubCell offset
			target -= world.Map.OffsetOfSubCell(srcSub);

			// Select only the tiles that are within range from the requested SubCell
			// This assumes that the SubCell does not change during the path traversal
			var tilesInRange = world.Map.FindTilesInCircle(targetCell, range.Length / 1024 + 1)
				.Where(t => (world.Map.CenterOfCell(t) - target).LengthSquared <= range.LengthSquared
							&& mi.CanEnterCell(self.World, self, t));

			// See if there is any cell within range that does not involve a cross-domain request
			// Really, we only need to check the circle perimeter, but it's not clear that would be a performance win
			var domainIndex = world.WorldActor.TraitOrDefault<DomainIndex>();
			if (domainIndex != null)
			{
				var passable = mi.GetMovementClass(world.TileSet);
				tilesInRange = new List<CPos>(tilesInRange.Where(t => domainIndex.IsPassable(source, t, (uint)passable)));
				if (!tilesInRange.Any())
					return EmptyPath;
			}

			using (var fromSrc = PathSearch.FromPoints(world, mi, self, tilesInRange, source, true))
			using (var fromDest = PathSearch.FromPoint(world, mi, self, source, targetCell, true).Reverse())
				return FindBidiPath(fromSrc, fromDest);
		}
Beispiel #10
0
        public NukeLaunch(Player firedBy, string name, WeaponInfo weapon, string weaponPalette, string upSequence, string downSequence,
			WPos launchPos, WPos targetPos, WDist velocity, int delay, bool skipAscent, string flashType)
        {
            this.firedBy = firedBy;
            this.weapon = weapon;
            this.weaponPalette = weaponPalette;
            this.downSequence = downSequence;
            this.delay = delay;
            turn = delay / 2;
            this.flashType = flashType;

            var offset = new WVec(WDist.Zero, WDist.Zero, velocity * turn);
            ascendSource = launchPos;
            ascendTarget = launchPos + offset;
            descendSource = targetPos + offset;
            descendTarget = targetPos;

            anim = new Animation(firedBy.World, name);
            anim.PlayRepeating(upSequence);

            pos = launchPos;
            if (weapon.Report != null && weapon.Report.Any())
                Game.Sound.Play(weapon.Report.Random(firedBy.World.SharedRandom), pos);

            if (skipAscent)
                ticks = turn;
        }
		public bool IsValidImpact(WPos pos, Actor firedBy)
		{
			var world = firedBy.World;
			var targetTile = world.Map.CellContaining(pos);
			if (!world.Map.Contains(targetTile))
				return false;

			var impactType = GetImpactType(world, targetTile, pos, firedBy);
			var validImpact = false;
			switch (impactType)
			{
				case ImpactType.TargetHit:
					validImpact = true;
					break;
				case ImpactType.Air:
					validImpact = IsValidTarget(new string[] { "Air" });
					break;
				case ImpactType.Ground:
					var tileInfo = world.Map.GetTerrainInfo(targetTile);
					validImpact = IsValidTarget(tileInfo.TargetTypes);
					break;
			}

			return validImpact;
		}
Beispiel #12
0
		public static ImpactType GetImpactType(World world, CPos cell, WPos pos)
		{
			// Missiles need a margin because they sometimes explode a little above ground
			// due to their explosion check triggering slightly too early (because of CloseEnough).
			// TODO: Base ImpactType on target altitude instead of explosion altitude.
			var airMargin = new WDist(128);

			var dat = world.Map.DistanceAboveTerrain(pos);
			var isAir = dat.Length > airMargin.Length;
			var isWater = dat.Length <= 0 && world.Map.GetTerrainInfo(cell).IsWater;
			var isDirectHit = GetDirectHit(world, cell, pos);

			if (isAir && !isDirectHit)
				return ImpactType.Air;
			else if (isWater && !isDirectHit)
				return ImpactType.Water;
			else if (isAir && isDirectHit)
				return ImpactType.AirHit;
			else if (isWater && isDirectHit)
				return ImpactType.WaterHit;
			else if (isDirectHit)
				return ImpactType.GroundHit;

			return ImpactType.Ground;
		}
 public FrozenActor(Actor self, IEnumerable<CPos> footprint)
 {
     actor = self;
     Footprint = footprint;
     CenterPosition = self.CenterPosition;
     Bounds = self.Bounds.Value;
 }
 public SelectionBoxRenderable(WPos pos, Rectangle bounds, float scale, Color color)
 {
     this.pos = pos;
     this.bounds = bounds;
     this.scale = scale;
     this.color = color;
 }
Beispiel #15
0
        /// <summary>
        /// Finds all the actors of which their health radius is intersected by a line (with a definable width) between two points.
        /// </summary>
        /// <param name="world">The engine world the line intersection is to be done in.</param>
        /// <param name="lineStart">The position the line should start at</param>
        /// <param name="lineEnd">The position the line should end at</param>
        /// <param name="lineWidth">How close an actor's health radius needs to be to the line to be considered 'intersected' by the line</param>
        /// <returns>A list of all the actors intersected by the line</returns>
        public static IEnumerable<Actor> FindActorsOnLine(this World world, WPos lineStart, WPos lineEnd, WDist lineWidth, WDist targetExtraSearchRadius)
        {
            // This line intersection check is done by first just finding all actors within a square that starts at the source, and ends at the target.
            // Then we iterate over this list, and find all actors for which their health radius is at least within lineWidth of the line.
            // For actors without a health radius, we simply check their center point.
            // The square in which we select all actors must be large enough to encompass the entire line's width.
            var xDir = Math.Sign(lineEnd.X - lineStart.X);
            var yDir = Math.Sign(lineEnd.Y - lineStart.Y);

            var dir = new WVec(xDir, yDir, 0);
            var overselect = dir * (1024 + lineWidth.Length + targetExtraSearchRadius.Length);
            var finalTarget = lineEnd + overselect;
            var finalSource = lineStart - overselect;

            var actorsInSquare = world.ActorMap.ActorsInBox(finalTarget, finalSource);
            var intersectedActors = new List<Actor>();

            foreach (var currActor in actorsInSquare)
            {
                var actorWidth = 0;
                var healthInfo = currActor.Info.TraitInfoOrDefault<HealthInfo>();
                if (healthInfo != null)
                    actorWidth = healthInfo.Shape.OuterRadius.Length;

                var projection = MinimumPointLineProjection(lineStart, lineEnd, currActor.CenterPosition);
                var distance = (currActor.CenterPosition - projection).HorizontalLength;
                var maxReach = actorWidth + lineWidth.Length;

                if (distance <= maxReach)
                    intersectedActors.Add(currActor);
            }

            return intersectedActors;
        }
Beispiel #16
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);
        }
Beispiel #17
0
        public TextRenderable(SpriteFont font, WPos pos, int zOffset, Color color, string text)
            : this(font, pos, zOffset, color,
			       ChromeMetrics.Get<Color>("TextContrastColorDark"),
			       ChromeMetrics.Get<Color>("TextContrastColorLight"),
			       text)
        {
        }
Beispiel #18
0
        public AreaBeam(AreaBeamInfo info, ProjectileArgs args, Color color)
        {
            this.info = info;
            this.args = args;
            this.color = color;
            actorAttackBase = args.SourceActor.Trait<AttackBase>();

            var 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];

            // Both the head and tail start at the source actor, but initially only the head is travelling.
            headPos = args.Source;
            tailPos = headPos;

            target = args.PassiveTarget;
            if (info.Inaccuracy.Length > 0)
            {
                var inaccuracy = Util.ApplyPercentageModifiers(info.Inaccuracy.Length, args.InaccuracyModifiers);
                var maxOffset = inaccuracy * (target - headPos).Length / args.Weapon.Range.Length;
                target += WVec.FromPDF(world.SharedRandom, 2) * maxOffset / 1024;
            }

            towardsTargetFacing = (target - headPos).Yaw.Facing;

            // Update the target position with the range we shoot beyond the target by
            // I.e. we can deliberately overshoot, so aim for that position
            var dir = new WVec(0, -1024, 0).Rotate(WRot.FromFacing(towardsTargetFacing));
            target += dir * info.BeyondTargetRange.Length / 1024;

            length = Math.Max((target - headPos).Length / speed.Length, 1);
        }
Beispiel #19
0
		public FallDown(Actor self, WPos dropPosition, int fallRate, Actor ignoreActor = null)
		{
			pos = self.TraitOrDefault<IPositionable>();
			IsInterruptible = false;
			fallVector = new WVec(0, 0, fallRate);
			this.dropPosition = dropPosition;
		}
Beispiel #20
0
        public IEnumerable<IRenderable> Render(WorldRenderer wr, World w, ActorInfo ai, WPos centerPosition)
        {
            var jamsMissiles = ai.TraitInfoOrDefault<JamsMissilesInfo>();
            if (jamsMissiles != null)
            {
                yield return new RangeCircleRenderable(
                    centerPosition,
                    jamsMissiles.Range,
                    0,
                    Color.FromArgb(128, Color.Red),
                    Color.FromArgb(96, Color.Black));
            }

            var jamsRadar = ai.TraitInfoOrDefault<JamsRadarInfo>();
            if (jamsRadar != null)
            {
                yield return new RangeCircleRenderable(
                    centerPosition,
                    jamsRadar.Range,
                    0,
                    Color.FromArgb(128, Color.Blue),
                    Color.FromArgb(96, Color.Black));
            }

            foreach (var a in w.ActorsWithTrait<RenderJammerCircle>())
                if (a.Actor.Owner.IsAlliedWith(w.RenderPlayer))
                    foreach (var r in a.Trait.RenderAfterWorld(wr))
                        yield return r;
        }
Beispiel #21
0
        public Missile(MissileInfo info, ProjectileArgs args)
        {
            this.info = info;
            this.args = args;

            pos = args.Source;
            facing = args.Facing;

            targetPosition = args.PassiveTarget;

            // Convert ProjectileArg definitions to world coordinates
            // TODO: Change the yaml definitions so we don't need this
            var inaccuracy = (int)(info.Inaccuracy * 1024 / Game.CellSize);
            speed = info.Speed * 1024 / (5 * Game.CellSize);

            if (info.Inaccuracy > 0)
                offset = WVec.FromPDF(args.SourceActor.World.SharedRandom, 2) * inaccuracy / 1024;

            if (info.Image != null)
            {
                anim = new Animation(info.Image, () => facing);
                anim.PlayRepeating("idle");
            }

            if (info.ContrailLength > 0)
            {
                var color = info.ContrailUsePlayerColor ? ContrailRenderable.ChooseColor(args.SourceActor) : info.ContrailColor;
                trail = new ContrailRenderable(args.SourceActor.World, color, info.ContrailLength, info.ContrailDelay, 0);
            }
        }
		public AirstrikePowerASEffect(World world, Player p, WPos pos, IEnumerable<Actor> planes, AirstrikePowerASInfo info)
		{
			this.info = info;
			this.world = world;
			this.Owner = p;
			this.pos = pos;
			this.planes = planes;

			if (info.DisplayBeacon)
			{
				var distance = (planes.First().OccupiesSpace.CenterPosition - pos).HorizontalLength;

				beacon = new Beacon(
					Owner,
					pos - new WVec(WDist.Zero, WDist.Zero, world.Map.DistanceAboveTerrain(pos)),
					info.BeaconPaletteIsPlayerPalette,
					info.BeaconPalette,
					info.BeaconImage,
					info.BeaconPoster,
					info.BeaconPosterPalette,
					info.ArrowSequence,
					info.CircleSequence,
					info.ClockSequence,
						() => 1 - ((planes.First().OccupiesSpace.CenterPosition - pos).HorizontalLength - info.BeaconDistanceOffset.Length) * 1f / distance);

				world.AddFrameEndTask(w => w.Add(beacon));
			}
		}
Beispiel #23
0
        public Parachute(Actor cargo, WPos dropPosition)
        {
            this.cargo = cargo;

            parachutableInfo = cargo.Info.Traits.GetOrDefault<ParachutableInfo>();

            if (parachutableInfo != null)
                fallVector = new WVec(0, 0, parachutableInfo.FallRate);

            var parachuteSprite = parachutableInfo != null ? parachutableInfo.ParachuteSequence : null;
            if (parachuteSprite != null)
            {
                parachute = new Animation(cargo.World, parachuteSprite);
                parachute.PlayThen("open", () => parachute.PlayRepeating("idle"));
            }

            var shadowSprite = parachutableInfo != null ? parachutableInfo.ShadowSequence : null;
            if (shadowSprite != null)
            {
                shadow = new Animation(cargo.World, shadowSprite);
                shadow.PlayRepeating("idle");
            }

            if (parachutableInfo != null)
                parachuteOffset = parachutableInfo.ParachuteOffset;

            // Adjust x,y to match the target subcell
            cargo.Trait<IPositionable>().SetPosition(cargo, cargo.World.Map.CellContaining(dropPosition));
            var cp = cargo.CenterPosition;
            pos = new WPos(cp.X, cp.Y, dropPosition.Z);
        }
Beispiel #24
0
        public Missile(MissileInfo info, ProjectileArgs args)
        {
            this.info = info;
            this.args = args;

            pos = args.Source;
            facing = args.Facing;

            targetPosition = args.PassiveTarget;

            if (info.Inaccuracy.Range > 0)
                offset = WVec.FromPDF(args.SourceActor.World.SharedRandom, 2) * info.Inaccuracy.Range / 1024;

            if (info.Image != null)
            {
                anim = new Animation(args.SourceActor.World, info.Image, () => facing);
                anim.PlayRepeating("idle");
            }

            if (info.ContrailLength > 0)
            {
                var color = info.ContrailUsePlayerColor ? ContrailRenderable.ChooseColor(args.SourceActor) : info.ContrailColor;
                trail = new ContrailRenderable(args.SourceActor.World, color, info.ContrailLength, info.ContrailDelay, 0);
            }
        }
		public RangeCircleRenderable(WPos centerPosition, WDist radius, int zOffset, Color color, Color contrastColor)
		{
			this.centerPosition = centerPosition;
			this.radius = radius;
			this.zOffset = zOffset;
			this.color = color;
			this.contrastColor = contrastColor;
		}
Beispiel #26
0
 public Explosion(World world, WPos pos, string style)
 {
     this.world = world;
     this.pos = pos;
     this.cell = pos.ToCPos();
     anim = new Animation("explosion");
     anim.PlayThen(style, () => world.AddFrameEndTask(w => w.Remove(this)));
 }
Beispiel #27
0
 public Explosion(World world, WPos pos, string image, string sequence, string palette)
 {
     this.world = world;
     this.pos = pos;
     this.palette = palette;
     anim = new Animation(world, image);
     anim.PlayThen(sequence, () => world.AddFrameEndTask(w => w.Remove(this)));
 }
Beispiel #28
0
 public TextRenderable(SpriteFont font, WPos pos, int zOffset, Color color, string text)
 {
     this.font = font;
     this.pos = pos;
     this.zOffset = zOffset;
     this.color = color;
     this.text = text;
 }
Beispiel #29
0
 public FloatingText(WPos pos, Color color, string text, int duration)
 {
     this.font = Game.Renderer.Fonts["TinyBold"];
     this.pos = pos;
     this.color = color;
     this.text = text;
     this.remaining = duration;
 }
Beispiel #30
0
 public bool IsVisible(WPos pos)
 {
     return(IsVisible(map.ProjectedCellCovering(pos)));
 }
Beispiel #31
0
 public TintedCell(TintedCellsLayer layer, CPos location, WPos centeredLocation)
 {
     this.layer            = layer;
     this.location         = location;
     this.centeredLocation = centeredLocation;
 }
Beispiel #32
0
 void SaveBookmark(int index, WPos position)
 {
     viewPortBookmarkSlots[index] = position;
 }
Beispiel #33
0
        public void Tick(World world)
        {
            if (info.TrackTarget)
            {
                TrackTarget();
            }

            if (++headTicks >= length)
            {
                headPos          = target;
                isHeadTravelling = false;
            }
            else if (isHeadTravelling)
            {
                headPos = WPos.LerpQuadratic(args.Source, target, WAngle.Zero, headTicks, length);
            }

            if (tailTicks <= 0 && args.SourceActor.IsInWorld && !args.SourceActor.IsDead)
            {
                args.Source = args.CurrentSource();
                tailPos     = args.Source;
            }

            // Allow for leniency to avoid edge case stuttering (start firing and immediately stop again).
            var outOfWeaponRange = args.Weapon.Range + info.BeyondTargetRange < new WDist((args.PassiveTarget - args.Source).Length);

            // While the head is travelling, the tail must start to follow Duration ticks later.
            // Alternatively, also stop emitting the beam if source actor dies or is ordered to stop.
            if ((headTicks >= info.Duration && !isTailTravelling) || args.SourceActor.IsDead ||
                !actorAttackBase.IsAiming || outOfWeaponRange)
            {
                StopTargeting();
            }

            if (isTailTravelling)
            {
                if (++tailTicks >= length)
                {
                    tailPos          = target;
                    isTailTravelling = false;
                }
                else
                {
                    tailPos = WPos.LerpQuadratic(args.Source, target, WAngle.Zero, tailTicks, length);
                }
            }

            // Check for blocking actors
            if (info.Blockable && BlocksProjectiles.AnyBlockingActorsBetween(world, tailPos, headPos, info.Width, out var blockedPos))
            {
                headPos = blockedPos;
                target  = headPos;
                length  = Math.Min(headTicks, length);
            }

            // Damage is applied to intersected actors every DamageInterval ticks
            if (headTicks % info.DamageInterval == 0)
            {
                var actors = world.FindActorsOnLine(tailPos, headPos, info.Width);
                foreach (var a in actors)
                {
                    var adjustedModifiers = args.DamageModifiers.Append(GetFalloff((args.Source - a.CenterPosition).Length));

                    var warheadArgs = new WarheadArgs(args)
                    {
                        ImpactOrientation = new WRot(WAngle.Zero, Util.GetVerticalAngle(args.Source, target), args.CurrentMuzzleFacing()),

                        // Calculating an impact position is bogus for line damage.
                        // FindActorsOnLine guarantees that the beam touches the target's HitShape,
                        // so we just assume a center hit to avoid bogus warhead recalculations.
                        ImpactPosition  = a.CenterPosition,
                        DamageModifiers = adjustedModifiers.ToArray(),
                    };

                    args.Weapon.Impact(Target.FromActor(a), warheadArgs);
                }
            }

            if (IsBeamComplete)
            {
                world.AddFrameEndTask(w => w.Remove(this));
            }
        }
Beispiel #34
0
        public Bullet(BulletInfo info, ProjectileArgs args)
        {
            this.info = info;
            this.args = args;
            pos       = args.Source;
            source    = args.Source;

            var world = args.SourceActor.World;

            if (info.LaunchAngle.Length > 1)
            {
                angle = new WAngle(world.SharedRandom.Next(info.LaunchAngle[0].Angle, info.LaunchAngle[1].Angle));
            }
            else
            {
                angle = info.LaunchAngle[0];
            }

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

            target = args.PassiveTarget;
            if (info.Inaccuracy.Length > 0)
            {
                var inaccuracy = Util.ApplyPercentageModifiers(info.Inaccuracy.Length, args.InaccuracyModifiers);
                var range      = Util.ApplyPercentageModifiers(args.Weapon.Range.Length, args.RangeModifiers);
                var maxOffset  = inaccuracy * (target - pos).Length / range;
                target += WVec.FromPDF(world.SharedRandom, 2) * maxOffset / 1024;
            }

            if (info.AirburstAltitude > WDist.Zero)
            {
                target += new WVec(WDist.Zero, WDist.Zero, info.AirburstAltitude);
            }

            facing = (target - pos).Yaw.Facing;
            length = Math.Max((target - pos).Length / speed.Length, 1);

            if (!string.IsNullOrEmpty(info.Image))
            {
                anim = new Animation(world, info.Image, new Func <int>(GetEffectiveFacing));
                anim.PlayRepeating(info.Sequences.Random(world.SharedRandom));
            }

            if (info.ContrailLength > 0)
            {
                var color = info.ContrailUsePlayerColor ? ContrailRenderable.ChooseColor(args.SourceActor) : info.ContrailColor;
                contrail = new ContrailRenderable(world, color, info.ContrailWidth, info.ContrailLength, info.ContrailDelay, info.ContrailZOffset);
            }

            trailPalette = info.TrailPalette;
            if (info.TrailUsePlayerPalette)
            {
                trailPalette += args.SourceActor.Owner.InternalName;
            }

            smokeTicks       = info.TrailDelay;
            remainingBounces = info.BounceCount;
        }
Beispiel #35
0
        public Actor[] TargetParatroopers(WPos target, WAngle?facing = null)
        {
            var actors = pp.SendParatroopers(Self, target, facing);

            return(actors.Aircraft);
        }
Beispiel #36
0
 public void Center(WPos pos)
 {
     CenterLocation = worldRenderer.ScreenPxPosition(pos).Clamp(mapBounds);
     cellsDirty     = true;
 }
Beispiel #37
0
        public void SendAirstrike(Actor self, WPos target, bool randomize = true, int attackFacing = 0)
        {
            var info = Info as AirstrikePowerInfo;

            if (randomize)
            {
                attackFacing = Util.QuantizeFacing(self.World.SharedRandom.Next(256), info.QuantizedFacings) * (256 / info.QuantizedFacings);
            }

            var altitude       = self.World.Map.Rules.Actors[info.UnitType].TraitInfo <AircraftInfo>().CruiseAltitude.Length;
            var attackRotation = WRot.FromFacing(attackFacing);
            var delta          = new WVec(0, -1024, 0).Rotate(attackRotation);

            target = target + new WVec(0, 0, altitude);
            var startEdge  = target - (self.World.Map.DistanceToEdge(target, -delta) + info.Cordon).Length * delta / 1024;
            var finishEdge = target + (self.World.Map.DistanceToEdge(target, delta) + info.Cordon).Length * delta / 1024;

            Actor  camera          = null;
            Beacon beacon          = null;
            var    aircraftInRange = new Dictionary <Actor, bool>();

            Action <Actor> onEnterRange = a =>
            {
                // Spawn a camera and remove the beacon when the first plane enters the target area
                if (info.CameraActor != null && !aircraftInRange.Any(kv => kv.Value))
                {
                    self.World.AddFrameEndTask(w =>
                    {
                        camera = w.CreateActor(info.CameraActor, new TypeDictionary
                        {
                            new LocationInit(self.World.Map.CellContaining(target)),
                            new OwnerInit(self.Owner),
                        });
                    });
                }

                if (beacon != null)
                {
                    self.World.AddFrameEndTask(w =>
                    {
                        w.Remove(beacon);
                        beacon = null;
                    });
                }

                aircraftInRange[a] = true;
            };

            Action <Actor> onExitRange = a =>
            {
                aircraftInRange[a] = false;

                // Remove the camera when the final plane leaves the target area
                if (!aircraftInRange.Any(kv => kv.Value))
                {
                    if (camera != null)
                    {
                        camera.QueueActivity(new Wait(info.CameraRemoveDelay));
                        camera.QueueActivity(new RemoveSelf());
                    }

                    camera = null;

                    if (beacon != null)
                    {
                        self.World.AddFrameEndTask(w =>
                        {
                            w.Remove(beacon);
                            beacon = null;
                        });
                    }
                }
            };

            self.World.AddFrameEndTask(w =>
            {
                var notification = self.Owner.IsAlliedWith(self.World.RenderPlayer) ? Info.LaunchSound : Info.IncomingSound;
                Game.Sound.Play(notification);

                Actor distanceTestActor = null;
                for (var i = -info.SquadSize / 2; i <= info.SquadSize / 2; i++)
                {
                    // Even-sized squads skip the lead plane
                    if (i == 0 && (info.SquadSize & 1) == 0)
                    {
                        continue;
                    }

                    // Includes the 90 degree rotation between body and world coordinates
                    var so           = info.SquadOffset;
                    var spawnOffset  = new WVec(i * so.Y, -Math.Abs(i) * so.X, 0).Rotate(attackRotation);
                    var targetOffset = new WVec(i * so.Y, 0, 0).Rotate(attackRotation);

                    var a = w.CreateActor(info.UnitType, new TypeDictionary
                    {
                        new CenterPositionInit(startEdge + spawnOffset),
                        new OwnerInit(self.Owner),
                        new FacingInit(attackFacing),
                    });

                    var attack = a.Trait <AttackBomber>();
                    attack.SetTarget(w, target + targetOffset);
                    attack.OnEnteredAttackRange += onEnterRange;
                    attack.OnExitedAttackRange  += onExitRange;
                    attack.OnRemovedFromWorld   += onExitRange;

                    a.QueueActivity(new Fly(a, Target.FromPos(target + spawnOffset)));
                    a.QueueActivity(new Fly(a, Target.FromPos(finishEdge + spawnOffset)));
                    a.QueueActivity(new RemoveSelf());
                    aircraftInRange.Add(a, false);
                    distanceTestActor = a;
                }

                if (Info.DisplayBeacon)
                {
                    var distance = (target - startEdge).HorizontalLength;

                    beacon = new Beacon(
                        self.Owner,
                        target - new WVec(0, 0, altitude),
                        Info.BeaconPalettePrefix,
                        Info.BeaconPoster,
                        Info.BeaconPosterPalette,
                        () => 1 - ((distanceTestActor.CenterPosition - target).HorizontalLength - info.BeaconDistanceOffset.Length) * 1f / distance);

                    w.Add(beacon);
                }
            });
        }
Beispiel #38
0
 public MoveFlash(WPos pos, World world)
 {
     this.pos = pos;
     anim     = new Animation(world, "moveflsh");
     anim.PlayThen("idle", () => world.AddFrameEndTask(w => w.Remove(this)));
 }
Beispiel #39
0
        public override void DoImpact(Target target, Actor firedBy, IEnumerable <int> damageModifiers)
        {
            if (!target.IsValidFor(firedBy))
            {
                return;
            }

            var random     = firedBy.World.SharedRandom;
            var pos        = target.CenterPosition + new WVec(Radius.X == 0 ? 0 : random.Next(-Radius.X, Radius.X), Radius.Y == 0 ? 0 : random.Next(-Radius.Y, Radius.Y), 0);
            var world      = firedBy.World;
            var targetTile = world.Map.CellContaining(pos);
            var isValid    = IsValidImpact(pos, firedBy);

            if ((!world.Map.Contains(targetTile)) || (!isValid))
            {
                return;
            }

            var palette = ExplosionPalette;

            if (UsePlayerPalette)
            {
                palette += firedBy.Owner.InternalName;
            }

            if (ForceDisplayAtGroundLevel)
            {
                var dat = world.Map.DistanceAboveTerrain(pos);
                pos = new WPos(pos.X, pos.Y, pos.Z - dat.Length);
            }

            var explosion = Explosions.RandomOrDefault(Game.CosmeticRandom);

            if (Image != null && explosion != null)
            {
                world.AddFrameEndTask(w => w.Add(new SpriteEffect(pos, w, Image, explosion, palette)));
            }

            if (ShrapnelWeapon != null)
            {
                WeaponInfo weaponInfo;
                var        weaponToLower = ShrapnelWeapon.ToLowerInvariant();

                if (!Game.ModData.DefaultRules.Weapons.TryGetValue(weaponToLower, out weaponInfo))
                {
                    throw new YamlException("Weapons Ruleset does not contain an entry '{0}'".F(weaponToLower));
                }

                var rotation      = WRot.FromFacing(world.SharedRandom.Next(1024));
                var range         = world.SharedRandom.Next(ShrapnelRange[0].Length, ShrapnelRange[1].Length);
                var passiveTarget = pos + new WVec(range, 0, 0).Rotate(rotation);

                var args = new ProjectileArgs
                {
                    Weapon              = weaponInfo,
                    DamageModifiers     = new int[0],
                    InaccuracyModifiers = new int[0],
                    RangeModifiers      = new int[0],
                    Source              = pos,
                    CurrentSource       = () => pos,
                    SourceActor         = firedBy,
                    PassiveTarget       = passiveTarget,
                    GuidedTarget        = target
                };

                world.AddFrameEndTask(x =>
                {
                    if (args.Weapon.Projectile != null)
                    {
                        var projectile = args.Weapon.Projectile.Create(args);
                        if (projectile != null)
                        {
                            world.Add(projectile);
                        }
                    }
                    else
                    {
                        foreach (var warhead in args.Weapon.Warheads.Keys)
                        {
                            var wh = warhead;                             // force the closure to bind to the current warhead

                            if (wh.Delay > 0)
                            {
                                firedBy.World.AddFrameEndTask(w => w.Add(new DelayedImpact(wh.Delay, wh, Target.FromPos(args.PassiveTarget), args.SourceActor, new int[0])));
                            }
                            else
                            {
                                wh.DoImpact(Target.FromPos(args.PassiveTarget), args.SourceActor, new int[0]);
                            }
                        }
                    }
                });
            }

            var impactSound = ImpactSounds.RandomOrDefault(Game.CosmeticRandom);

            if (impactSound != null && Game.CosmeticRandom.Next(0, 100) < ImpactSoundChance)
            {
                Game.Sound.Play(SoundType.World, impactSound, pos);
            }
        }
Beispiel #40
0
 public Drag(WPos start, WPos end, int length)
 {
     this.start  = start;
     this.end    = end;
     this.length = length;
 }
Beispiel #41
0
        public ISound Play2D(ISoundSource sound, bool loop, bool relative, WPos pos, float volume, bool attenuateVolume)
        {
            if (sound == null)
            {
                Log.Write("sound", "Attempt to Play2D a null `ISoundSource`");
                return(null);
            }

            var currFrame = Game.LocalTick;
            var atten     = 1f;

            // Check if max # of instances-per-location reached:
            if (attenuateVolume)
            {
                int instances = 0, activeCount = 0;
                foreach (var s in sourcePool.Values)
                {
                    if (!s.IsActive)
                    {
                        continue;
                    }
                    if (s.IsRelative != relative)
                    {
                        continue;
                    }

                    ++activeCount;
                    if (s.Sound != sound)
                    {
                        continue;
                    }
                    if (currFrame - s.FrameStarted >= 5)
                    {
                        continue;
                    }

                    // Too far away to count?
                    var lensqr = (s.Pos - pos).LengthSquared;
                    if (lensqr >= GroupDistanceSqr)
                    {
                        continue;
                    }

                    // If we are starting too many instances of the same sound within a short time then stop this one:
                    if (++instances == MaxInstancesPerFrame)
                    {
                        return(null);
                    }
                }

                // Attenuate a little bit based on number of active sounds:
                atten = 0.66f * ((PoolSize - activeCount * 0.5f) / PoolSize);
            }

            uint source;

            if (!TryGetSourceFromPool(out source))
            {
                return(null);
            }

            var slot = sourcePool[source];

            slot.Pos          = pos;
            slot.FrameStarted = currFrame;
            slot.Sound        = sound;
            slot.IsRelative   = relative;
            return(new OpenAlSound(source, ((OpenAlSoundSource)sound).Buffer, loop, relative, pos, volume * atten));
        }
Beispiel #42
0
        public void Tick(World world)
        {
            if (anim != null)
            {
                anim.Tick();
            }

            var lastPos = pos;

            pos = WPos.LerpQuadratic(source, target, angle, ticks, length);

            // Check for walls or other blocking obstacles
            var  shouldExplode = false;
            WPos blockedPos;

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

            if (!string.IsNullOrEmpty(info.TrailImage) && --smokeTicks < 0)
            {
                var delayedPos = WPos.LerpQuadratic(source, target, angle, ticks - info.TrailDelay, length);
                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(pos);
            }

            var flightLengthReached = ticks++ >= length;
            var shouldBounce        = remainingBounces > 0;

            if (flightLengthReached && shouldBounce)
            {
                shouldExplode |= AnyValidTargetsInRadius(world, pos, info.Width, args.SourceActor, true);
                target        += (pos - source) * info.BounceRangeModifier / 100;
                var dat = world.Map.DistanceAboveTerrain(target);
                target += new WVec(0, 0, -dat.Length);
                length  = Math.Max((target - pos).Length / speed.Length, 1);
                ticks   = 0;
                source  = pos;
                remainingBounces--;
            }

            // Flight length reached / exceeded
            shouldExplode |= flightLengthReached && !shouldBounce;

            // Driving into cell with higher height level
            shouldExplode |= world.Map.DistanceAboveTerrain(pos).Length < 0;

            // After first bounce, check for targets each tick
            if (remainingBounces < info.BounceCount)
            {
                shouldExplode |= AnyValidTargetsInRadius(world, pos, info.Width, args.SourceActor, true);
            }

            if (shouldExplode)
            {
                Explode(world);
            }
        }
Beispiel #43
0
        public Actor[] ActorsInBox(WPos topLeft, WPos bottomRight, LuaFunction filter = null)
        {
            var actors = Context.World.ActorMap.ActorsInBox(topLeft, bottomRight);

            return(FilteredObjects(actors, filter).ToArray());
        }
Beispiel #44
0
        public void SendAirstrike(Actor self, WPos target, bool randomize = true, int attackFacing = 0)
        {
            if (randomize)
            {
                attackFacing = 256 * self.World.SharedRandom.Next(info.QuantizedFacings) / info.QuantizedFacings;
            }

            Actor  camera          = null;
            Beacon beacon          = null;
            var    aircraftInRange = new Dictionary <Actor, bool>();

            Action <Actor> onEnterRange = a =>
            {
                // Spawn a camera and remove the beacon when the first plane enters the target area
                if (info.CameraActor != null && camera == null && !aircraftInRange.Any(kv => kv.Value))
                {
                    self.World.AddFrameEndTask(w =>
                    {
                        camera = w.CreateActor(info.CameraActor, new TypeDictionary
                        {
                            new LocationInit(self.World.Map.CellContaining(target)),
                            new OwnerInit(self.Owner),
                        });
                    });
                }

                RemoveBeacon(beacon);

                aircraftInRange[a] = true;
            };

            Action <Actor> onExitRange = a =>
            {
                aircraftInRange[a] = false;

                // Remove the camera when the final plane leaves the target area
                if (!aircraftInRange.Any(kv => kv.Value))
                {
                    RemoveCamera(camera);
                }
            };

            Action <Actor> onRemovedFromWorld = a =>
            {
                aircraftInRange[a] = false;

                // Checking for attack range is not relevant here because
                // aircraft may be shot down before entering. Thus we remove
                // the camera and beacon only if the whole squad is dead.
                if (aircraftInRange.All(kv => kv.Key.IsDead))
                {
                    RemoveCamera(camera);
                    RemoveBeacon(beacon);
                }
            };

            self.World.AddFrameEndTask(w =>
            {
                WPos?startPos = null;
                foreach (var squadMember in info.Squad)
                {
                    var altitude       = self.World.Map.Rules.Actors[squadMember.UnitType].TraitInfo <AircraftInfo>().CruiseAltitude.Length;
                    var attackRotation = WRot.FromFacing(attackFacing);
                    var delta          = new WVec(0, -1024, 0).Rotate(attackRotation);
                    var targetPos      = target + new WVec(0, 0, altitude);
                    var startEdge      = targetPos - (self.World.Map.DistanceToEdge(targetPos, -delta) + info.Cordon).Length * delta / 1024;
                    var finishEdge     = targetPos + (self.World.Map.DistanceToEdge(targetPos, delta) + info.Cordon).Length * delta / 1024;

                    startPos = startEdge;

                    PlayLaunchSounds();

                    var spawnOffset  = squadMember.SpawnOffset.Rotate(attackRotation);
                    var targetOffset = squadMember.TargetOffset.Rotate(attackRotation);

                    var a = w.CreateActor(squadMember.UnitType, new TypeDictionary
                    {
                        new CenterPositionInit(startEdge + spawnOffset),
                        new OwnerInit(self.Owner),
                        new FacingInit(attackFacing),
                        new CreationActivityDelayInit(squadMember.SpawnDelay)
                    });

                    var attack = a.Trait <AttackBomber>();
                    attack.SetTarget(w, targetPos + targetOffset);
                    attack.OnEnteredAttackRange += onEnterRange;
                    attack.OnExitedAttackRange  += onExitRange;
                    attack.OnRemovedFromWorld   += onRemovedFromWorld;

                    for (var strikes = 0; strikes < info.Strikes; strikes++)
                    {
                        a.QueueActivity(new Fly(a, Target.FromPos(target + spawnOffset)));
                        if (info.Strikes > 1)
                        {
                            a.QueueActivity(new FlyTimed(info.CircleDelay, a));
                        }
                    }

                    a.QueueActivity(new Fly(a, Target.FromPos(finishEdge + spawnOffset)));
                    a.QueueActivity(new RemoveSelf());
                    aircraftInRange.Add(a, false);
                }

                if (Info.DisplayBeacon && startPos.HasValue)
                {
                    var distance = (target - startPos.Value).HorizontalLength;

                    beacon = new Beacon(
                        self.Owner,
                        new WPos(target.X, target.Y, 0),
                        Info.BeaconPaletteIsPlayerPalette,
                        Info.BeaconPalette,
                        Info.BeaconImage,
                        Info.BeaconPoster,
                        Info.BeaconPosterPalette,
                        Info.BeaconSequence,
                        Info.ArrowSequence,
                        Info.CircleSequence,
                        Info.ClockSequence,
                        () =>
                    {
                        // To account for different spawn times and potentially different movement speeds.
                        var closestActor = aircraftInRange.Keys.MinBy(x => (x.CenterPosition - target).HorizontalLengthSquared);
                        return(1 - ((closestActor.CenterPosition - target).HorizontalLength - info.BeaconDistanceOffset.Length) * 1f / distance);
                    },
                        Info.BeaconDelay);

                    w.Add(beacon);
                }
            });
        }
Beispiel #45
0
        public Actor[] ActorsInCircle(WPos location, WDist radius, LuaFunction filter = null)
        {
            var actors = Context.World.FindActorsInCircle(location, radius);

            return(FilteredObjects(actors, filter).ToArray());
        }
 protected override void TraitEnabled(Actor self)
 {
     cachedPosition = self.CenterPosition;
 }
Beispiel #47
0
 public WDist DistanceFromEdge(WPos pos, Actor actor)
 {
     return(DistanceFromEdge((pos - actor.CenterPosition).Rotate(-actor.Orientation)));
 }
Beispiel #48
0
 public static Target FromPos(WPos p)
 {
     return(new Target {
         pos = p, type = TargetType.Terrain
     });
 }
Beispiel #49
0
        public IEnumerable <IRenderable> Render(WorldRenderer wr, World w, ActorInfo ai, WPos centerPosition)
        {
            var findactors = w.FindActorsInCircle(centerPosition, Distance + ExtraSearchDistance)
                             .Where(a =>
            {
                if (a.IsDead || !a.IsInWorld)
                {
                    return(false);
                }

                if (!Actors.Contains(a.Info.Name))
                {
                    return(false);
                }

                if (CellDistanceBetweenCenterpositions(a.CenterPosition, centerPosition) <= CellLengthOfDistance(Distance))
                {
                    return(true);
                }

                var cells = w.Map.FindTilesInCircle(w.Map.CellContaining(centerPosition), CellLengthOfDistance(ExtraSearchDistance))
                            .Where(c => w.WorldActor.Trait <ResourceLayer>().GetResourceDensity(c) > 0 && w.WorldActor.Trait <ResourceLayer>().GetRenderedResource(c) != null)
                            .Where(ce => ce.X <= Math.Max(w.Map.CellContaining(centerPosition).X, a.Location.X) && ce.X >= Math.Min(w.Map.CellContaining(centerPosition).X, a.Location.X) &&
                                   ce.Y <= Math.Max(w.Map.CellContaining(centerPosition).Y, a.Location.Y) && ce.Y >= Math.Min(w.Map.CellContaining(centerPosition).Y, a.Location.Y));

                if (cells.Any())
                {
                    var cell = cells.MinByOrDefault(c => (w.Map.CellContaining(centerPosition) - c).LengthSquared);

                    var extradistance = CellDistanceBetweenCenterpositions(w.Map.CenterOfCell(cell), a.CenterPosition);

                    if (CellDistanceBetweenCenterpositions(a.CenterPosition, centerPosition) <= CellLengthOfDistance(Distance) + extradistance)
                    {
                        return(true);
                    }
                }

                return(false);
            }).ToList();

            if (findactors.Any())
            {
                foreach (var act in findactors)
                {
                    yield return(new ArcRenderable(
                                     centerPosition + Offset,
                                     act.CenterPosition + TargetOffset,
                                     ZOffset, Angle, Color, Width, QuantizedSegments));
                }
            }
        }
Beispiel #50
0
 public int CellDistanceBetweenCenterpositions(WPos c1, WPos c2)
 {
     return((int)Math.Round((c1 - c2).Length / 1024.0));
 }
 internal Actor FindClosestEnemy(WPos pos, WDist radius)
 {
     return(World.FindActorsInCircle(pos, radius).Where(isEnemyUnit).ClosestTo(pos));
 }
Beispiel #52
0
        public void Tick(World world)
        {
            ticks++;
            if (anim != null)
            {
                anim.Tick();
            }

            // Switch from freefall mode to homing mode
            if (ticks == info.HomingActivationDelay + 1)
            {
                state = States.Homing;
                speed = velocity.Length;

                // Compute the vertical loop radius
                loopRadius = LoopRadius(speed, info.VerticalRateOfTurn);
            }

            // Switch from homing mode to freefall mode
            if (rangeLimit >= WDist.Zero && distanceCovered > rangeLimit)
            {
                state    = States.Freefall;
                velocity = new WVec(0, -speed, 0)
                           .Rotate(new WRot(WAngle.FromFacing(vFacing), WAngle.Zero, WAngle.Zero))
                           .Rotate(new WRot(WAngle.Zero, WAngle.Zero, WAngle.FromFacing(hFacing)));
            }

            // Check if target position should be updated (actor visible & locked on)
            var newTarPos = targetPosition;

            if (args.GuidedTarget.IsValidFor(args.SourceActor) && lockOn)
            {
                newTarPos = (args.Weapon.TargetActorCenter ? args.GuidedTarget.CenterPosition : args.GuidedTarget.Positions.PositionClosestTo(args.Source))
                            + new WVec(WDist.Zero, WDist.Zero, info.AirburstAltitude);
            }

            // Compute target's predicted velocity vector (assuming uniform circular motion)
            var yaw1 = tarVel.HorizontalLengthSquared != 0 ? tarVel.Yaw : WAngle.FromFacing(hFacing);

            tarVel = newTarPos - targetPosition;
            var yaw2 = tarVel.HorizontalLengthSquared != 0 ? tarVel.Yaw : WAngle.FromFacing(hFacing);

            predVel        = tarVel.Rotate(WRot.FromYaw(yaw2 - yaw1));
            targetPosition = newTarPos;

            // Compute current distance from target position
            var tarDistVec    = targetPosition + offset - pos;
            var relTarDist    = tarDistVec.Length;
            var relTarHorDist = tarDistVec.HorizontalLength;

            WVec move;

            if (state == States.Freefall)
            {
                move = FreefallTick();
            }
            else
            {
                move = HomingTick(world, tarDistVec, relTarHorDist);
            }

            renderFacing = new WVec(move.X, move.Y - move.Z, 0).Yaw.Facing;

            // Move the missile
            var lastPos = pos;

            if (info.AllowSnapping && state != States.Freefall && relTarDist < move.Length)
            {
                pos = targetPosition + offset;
            }
            else
            {
                pos += move;
            }

            // Check for walls or other blocking obstacles
            var  shouldExplode = false;
            WPos blockedPos;

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

            // Create the sprite trail effect
            if (!string.IsNullOrEmpty(info.TrailImage) && --ticksToNextSmoke < 0 && (state != States.Freefall || info.TrailWhenDeactivated))
            {
                world.AddFrameEndTask(w => w.Add(new SpriteEffect(pos - 3 * move / 2, w, info.TrailImage, info.TrailSequences.Random(world.SharedRandom),
                                                                  trailPalette, false, false, renderFacing)));

                ticksToNextSmoke = info.TrailInterval;
            }

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

            distanceCovered += new WDist(speed);
            var cell   = world.Map.CellContaining(pos);
            var height = world.Map.DistanceAboveTerrain(pos);

            shouldExplode |= height.Length < 0 ||          // Hit the ground
                             relTarDist < info.CloseEnough.Length ||    // Within range
                             (info.ExplodeWhenEmpty && rangeLimit >= WDist.Zero && distanceCovered > rangeLimit) ||    // Ran out of fuel
                             !world.Map.Contains(cell) ||    // This also avoids an IndexOutOfRangeException in GetTerrainInfo below.
                             (!string.IsNullOrEmpty(info.BoundToTerrainType) && world.Map.GetTerrainInfo(cell).Type != info.BoundToTerrainType) ||    // Hit incompatible terrain
                             (height.Length < info.AirburstAltitude.Length && relTarHorDist < info.CloseEnough.Length);       // Airburst

            if (shouldExplode)
            {
                Explode(world);
            }
        }
 internal Actor FindClosestEnemy(WPos pos)
 {
     return(World.Actors.Where(isEnemyUnit).ClosestTo(pos));
 }
Beispiel #54
0
 public IRenderable[] Render(WPos pos, PaletteReference palette)
 {
     return(Render(pos, WVec.Zero, 0, palette, 1f));
 }
Beispiel #55
0
 public bool IsExplored(WPos pos)
 {
     return(IsExplored(map.ProjectedCellCovering(pos)));
 }
Beispiel #56
0
 public void SetVisualPosition(Actor self, WPos pos)
 {
     SetPosition(self, pos);
 }
 public MoveSecondHalf(MoveUnderground move, WPos from, WPos to, int fromFacing, int toFacing, int startingFraction)
     : base(move, from, to, fromFacing, toFacing, startingFraction)
 {
 }
Beispiel #58
0
 public Activity VisualMove(Actor self, WPos fromPos, WPos toPos)
 {
     return(null);
 }
Beispiel #59
0
 public IEnumerable <Rectangle> ScreenBounds(WorldRenderer wr, WPos pos)
 {
     yield return(animation.ScreenBounds(wr, pos, offset(), scale));
 }
Beispiel #60
-2
 public CashTick(WPos pos, Color color, int value)
 {
     this.font = Game.Renderer.Fonts["TinyBold"];
     this.pos = pos;
     this.color = color;
     this.text = "{0}${1}".F(value < 0 ? "-" : "+", Math.Abs(value));
 }