public DetectionCircleRenderable(WPos centerPosition, WDist radius, int zOffset,
			int lineTrails, WAngle trailSeparation, WAngle trailAngle, Color color, Color contrastColor)
        {
            this.centerPosition = centerPosition;
            this.radius = radius;
            this.zOffset = zOffset;
            trailCount = lineTrails;
            this.trailSeparation = trailSeparation;
            this.trailAngle = trailAngle;
            this.color = color;
            this.contrastColor = contrastColor;
        }
示例#2
0
文件: Missile.cs 项目: pchote/OpenRA
        public Missile(MissileInfo info, ProjectileArgs args)
        {
            this.info = info;
            this.args = args;

            pos = args.Source;
            hFacing = args.Facing;
            gravity = new WVec(0, 0, -info.Gravity);
            targetPosition = args.PassiveTarget;
            rangeLimit = info.RangeLimit != WDist.Zero ? info.RangeLimit : args.Weapon.Range;
            minLaunchSpeed = info.MinimumLaunchSpeed.Length > -1 ? info.MinimumLaunchSpeed.Length : info.Speed.Length;
            maxLaunchSpeed = info.MaximumLaunchSpeed.Length > -1 ? info.MaximumLaunchSpeed.Length : info.Speed.Length;
            maxSpeed = info.Speed.Length;
            minLaunchAngle = info.MinimumLaunchAngle;
            maxLaunchAngle = info.MaximumLaunchAngle;

            var world = args.SourceActor.World;

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

            DetermineLaunchSpeedAndAngle(world, out speed, out vFacing);

            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)));

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

            if (!string.IsNullOrEmpty(info.Image))
            {
                anim = new Animation(world, info.Image, () => renderFacing);
                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;
        }
示例#3
0
文件: Bullet.cs 项目: pchote/OpenRA
        public Bullet(BulletInfo info, ProjectileArgs args)
        {
            this.info = info;
            this.args = args;
            pos = 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;
            }

            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;
        }
示例#4
0
        public VoxelPreview(VoxelAnimation[] components, WVec offset, int zOffset, float scale, WAngle lightPitch, WAngle lightYaw, float[] lightAmbientColor, float[] lightDiffuseColor, WAngle cameraPitch,
			PaletteReference colorPalette, PaletteReference normalsPalette, PaletteReference shadowPalette)
        {
            this.components = components;
            this.scale = scale;
            this.lightAmbientColor = lightAmbientColor;
            this.lightDiffuseColor = lightDiffuseColor;

            lightSource = new WRot(WAngle.Zero, new WAngle(256) - lightPitch, lightYaw);
            camera = new WRot(WAngle.Zero, cameraPitch - new WAngle(256), new WAngle(256));

            this.colorPalette = colorPalette;
            this.normalsPalette = normalsPalette;
            this.shadowPalette = shadowPalette;

            this.offset = offset;
            this.zOffset = zOffset;
        }
示例#5
0
        public Bullet(BulletInfo info, ProjectileArgs args)
        {
            this.info = info;
            this.args = args;
            this.pos = args.Source;

            var world = args.SourceActor.World;

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

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

            facing = OpenRA.Traits.Util.GetFacing(target - pos, 0);
            length = Math.Max((target - pos).Length / speed.Range, 1);

            if (info.Image != null)
            {
                anim = new Animation(world, info.Image, GetEffectiveFacing);
                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);
            }

            smokeTicks = info.TrailDelay;
        }
示例#6
0
        public Leap(Actor self, Actor target, WeaponInfo weapon, WRange speed, WAngle angle)
        {
            var targetMobile = target.TraitOrDefault<Mobile>();
            if (targetMobile == null)
                throw new InvalidOperationException("Leap requires a target actor with the Mobile trait");

            this.weapon = weapon;
            this.angle = angle;
            mobile = self.Trait<Mobile>();
            mobile.SetLocation(mobile.fromCell, mobile.fromSubCell, targetMobile.fromCell, targetMobile.fromSubCell);
            mobile.IsMoving = true;

            from = self.CenterPosition;
            to = targetMobile.fromCell.CenterPosition + MobileInfo.SubCellOffsets[targetMobile.fromSubCell];
            length = Math.Max((to - from).Length / speed.Range, 1);

            self.Trait<RenderInfantry>().Attacking(self, Target.FromActor(target));

            if (weapon.Report != null && weapon.Report.Any())
                Sound.Play(weapon.Report.Random(self.World.SharedRandom), self.CenterPosition);
        }
示例#7
0
        public Leap(Actor self, Actor target, WeaponInfo weapon, WDist speed, WAngle angle)
        {
            var targetMobile = target.TraitOrDefault<Mobile>();
            if (targetMobile == null)
                throw new InvalidOperationException("Leap requires a target actor with the Mobile trait");

            this.weapon = weapon;
            this.angle = angle;
            mobile = self.Trait<Mobile>();
            mobile.SetLocation(mobile.FromCell, mobile.FromSubCell, targetMobile.FromCell, targetMobile.FromSubCell);
            mobile.IsMoving = true;

            from = self.CenterPosition;
            to = self.World.Map.CenterOfSubCell(targetMobile.FromCell, targetMobile.FromSubCell);
            length = Math.Max((to - from).Length / speed.Length, 1);

            // HACK: why isn't this using the interface?
            self.Trait<WithInfantryBody>().Attacking(self, Target.FromActor(target));

            if (weapon.Report != null && weapon.Report.Any())
                Sound.Play(weapon.Report.Random(self.World.SharedRandom), self.CenterPosition);
        }
示例#8
0
        public Bullet(BulletInfo info, ProjectileArgs args)
        {
            this.info = info;
            this.args = args;
            this.pos = args.Source;

            // Convert ProjectileArg definitions to world coordinates
            // TODO: Change the yaml definitions so we don't need this
            var range = new WRange((int)(1024 * args.Weapon.Range)); // Range in world units
            var inaccuracy = new WRange((int)(info.Inaccuracy * 1024 / Game.CellSize)); // Offset in world units at max range
            var speed = (int)(info.Speed * 4 * 1024 / (10 * Game.CellSize)); // Speed in world units per tick
            angle = WAngle.ArcTan((int)(info.Angle * 4 * 1024), 1024); // Angle in world angle

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

            facing = Traits.Util.GetFacing(target - pos, 0);
            length = Math.Max((target - pos).Length / speed, 1);

            if (info.Image != null)
            {
                anim = new Animation(info.Image, GetEffectiveFacing);
                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);
            }

            smokeTicks = info.TrailDelay;
        }
示例#9
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,
                                                                             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);
            }
        }
示例#10
0
 void ITick.Tick(Actor self)
 {
     lineAngle += info.UpdateLineTick;
 }
示例#11
0
 // Orientation in unit-space
 public WRot LocalOrientation(Actor self)
 {
     // Hack: turretFacing is relative to the world, so subtract the body yaw
     return(WRot.FromYaw(WAngle.FromFacing(turretFacing) - self.Orientation.Yaw));
 }
 Sprite ISpriteSequence.GetSprite(int frame, WAngle facing)
 {
     throw exception;
 }
示例#13
0
        public IEnumerable <IActorPreview> RenderPreviewSprites(ActorPreviewInitializer init, RenderSpritesInfo rs, string image, int facings, PaletteReference p)
        {
            if (UpgradeMinEnabledLevel > 0)
            {
                yield break;
            }

            var body     = init.Actor.TraitInfo <BodyOrientationInfo>();
            var armament = init.Actor.TraitInfos <ArmamentInfo>()
                           .First(a => a.Name == Armament);
            var t = init.Actor.TraitInfos <TurretedInfo>()
                    .First(tt => tt.Turret == armament.Turret);

            var anim = new Animation(init.World, image, () => t.InitialFacing);

            anim.Play(RenderSprites.NormalizeSequence(anim, init.GetDamageState(), Sequence));

            var turretOrientation = body.QuantizeOrientation(new WRot(WAngle.Zero, WAngle.Zero, WAngle.FromFacing(t.InitialFacing)), facings);
            var turretOffset      = body.LocalToWorld(t.Offset.Rotate(turretOrientation));

            yield return(new SpriteActorPreview(anim, turretOffset, turretOffset.Y + turretOffset.Z, p, rs.Scale));
        }
 public Sprite GetSprite(int frame, WAngle facing)
 {
     return(GetSprite(Start, frame, facing));
 }
 protected virtual int GetFacingFrameOffset(WAngle facing)
 {
     return(Util.IndexFacing(facing, Facings));
 }
示例#16
0
        int HomingInnerTick(int predClfDist, int diffClfMslHgt, int relTarHorDist, int lastHtChg, int lastHt,
                            int nxtRelTarHorDist, int relTarHgt, int vFacing, bool targetPassedBy)
        {
            int desiredVFacing = vFacing;

            // Incline coming up -> attempt to reach the incline so that after predClfDist
            // the height above the terrain is positive but as close to 0 as possible
            // Also, never change horizontal facing and never travel backwards
            // Possible techniques to avoid close cliffs are deceleration, turning
            // as sharply as possible to travel directly upwards and then returning
            // to zero vertical facing as low as possible while still not hitting the
            // high terrain. A last technique (and the preferred one, normally used when
            // the missile hasn't been fired near a cliff) is simply finding the smallest
            // vertical facing that allows for a smooth climb to the new terrain's height
            // and coming in at predClfDist at exactly zero vertical facing
            if (info.TerrainHeightAware && diffClfMslHgt >= 0 && !allowPassBy)
            {
                desiredVFacing = IncreaseAltitude(predClfDist, diffClfMslHgt, relTarHorDist, vFacing);
            }
            else if (relTarHorDist <= 3 * loopRadius || state == States.Hitting)
            {
                // No longer travel at cruise altitude
                state = States.Hitting;

                if (lastHt >= targetPosition.Z)
                {
                    allowPassBy = true;
                }

                if (!allowPassBy && (lastHt < targetPosition.Z || targetPassedBy))
                {
                    // Aim for the target
                    var vDist = new WVec(-relTarHgt, -relTarHorDist, 0);
                    desiredVFacing = (sbyte)vDist.HorizontalLengthSquared != 0 ? vDist.Yaw.Facing : vFacing;

                    // Do not accept -1  as valid vertical facing since it is usually a numerical error
                    // and will lead to premature descent and crashing into the ground
                    if (desiredVFacing == -1)
                    {
                        desiredVFacing = 0;
                    }

                    // If the target has been passed by, limit the absolute value of
                    // vertical facing by the maximum vertical rate of turn
                    // Do this because the missile will be looping horizontally
                    // and thus needs smaller vertical facings so as not
                    // to hit the ground prematurely
                    if (targetPassedBy)
                    {
                        desiredVFacing = desiredVFacing.Clamp(-info.VerticalRateOfTurn.Facing, info.VerticalRateOfTurn.Facing);
                    }
                    else if (lastHt == 0)
                    {                     // Before the target is passed by, missile speed should be changed
                        // Target's height above loop's center
                        var tarHgt = (loopRadius * WAngle.FromFacing(vFacing).Cos() / 1024 - System.Math.Abs(relTarHgt)).Clamp(0, loopRadius);

                        // Target's horizontal distance from loop's center
                        var tarDist = Exts.ISqrt(loopRadius * loopRadius - tarHgt * tarHgt);

                        // Missile's horizontal distance from loop's center
                        var missDist = loopRadius * WAngle.FromFacing(vFacing).Sin() / 1024;

                        // If the current height does not permit the missile
                        // to hit the target before passing it by, lower speed
                        // Otherwise, increase speed
                        if (relTarHorDist <= tarDist - System.Math.Sign(relTarHgt) * missDist)
                        {
                            ChangeSpeed(-1);
                        }
                        else
                        {
                            ChangeSpeed();
                        }
                    }
                }
                else if (allowPassBy || (lastHt != 0 && relTarHorDist - lastHtChg < loopRadius))
                {
                    // Only activate this part if target too close to cliff
                    allowPassBy = true;

                    // Vector from missile's current position pointing to the loop's center
                    var radius = new WVec(loopRadius, 0, 0)
                                 .Rotate(new WRot(WAngle.Zero, WAngle.Zero, WAngle.FromFacing(64 - vFacing)));

                    // Vector from loop's center to incline top hardcoded in height buffer zone
                    var edgeVector = new WVec(lastHtChg, lastHt - pos.Z, 0) - radius;

                    if (!targetPassedBy)
                    {
                        // Climb to critical height
                        if (relTarHorDist > 2 * loopRadius)
                        {
                            // Target's distance from cliff
                            var d1 = relTarHorDist - lastHtChg;
                            if (d1 < 0)
                            {
                                d1 = 0;
                            }
                            if (d1 > 2 * loopRadius)
                            {
                                return(0);
                            }

                            // Find critical height at which the missile must be once it is at one loopRadius
                            // away from the target
                            var h1 = loopRadius - Exts.ISqrt(d1 * (2 * loopRadius - d1)) - (pos.Z - lastHt);

                            if (h1 > loopRadius * (1024 - WAngle.FromFacing(vFacing).Cos()) / 1024)
                            {
                                desiredVFacing = WAngle.ArcTan(Exts.ISqrt(h1 * (2 * loopRadius - h1)), loopRadius - h1).Angle >> 2;
                            }
                            else
                            {
                                desiredVFacing = 0;
                            }

                            // TODO: deceleration checks!!!
                        }
                        else
                        {
                            // Avoid the cliff edge
                            if (info.TerrainHeightAware && edgeVector.Length > loopRadius && lastHt > targetPosition.Z)
                            {
                                int vFac;
                                for (vFac = vFacing + 1; vFac <= vFacing + info.VerticalRateOfTurn.Facing - 1; vFac++)
                                {
                                    // Vector from missile's current position pointing to the loop's center
                                    radius = new WVec(loopRadius, 0, 0)
                                             .Rotate(new WRot(WAngle.Zero, WAngle.Zero, WAngle.FromFacing(64 - vFac)));

                                    // Vector from loop's center to incline top + 64 hardcoded in height buffer zone
                                    edgeVector = new WVec(lastHtChg, lastHt - pos.Z, 0) - radius;
                                    if (edgeVector.Length <= loopRadius)
                                    {
                                        break;
                                    }
                                }

                                desiredVFacing = vFac;
                            }
                            else
                            {
                                // Aim for the target
                                var vDist = new WVec(-relTarHgt, -relTarHorDist, 0);
                                desiredVFacing = (sbyte)vDist.HorizontalLengthSquared != 0 ? vDist.Yaw.Facing : vFacing;
                                if (desiredVFacing < 0 && info.VerticalRateOfTurn.Facing < (sbyte)vFacing)
                                {
                                    desiredVFacing = 0;
                                }
                            }
                        }
                    }
                    else
                    {
                        // Aim for the target
                        var vDist = new WVec(-relTarHgt, relTarHorDist, 0);
                        desiredVFacing = (sbyte)vDist.HorizontalLengthSquared != 0 ? vDist.Yaw.Facing : vFacing;
                        if (desiredVFacing < 0 && info.VerticalRateOfTurn.Facing < (sbyte)vFacing)
                        {
                            desiredVFacing = 0;
                        }
                    }
                }
                else
                {
                    // Aim to attain cruise altitude as soon as possible while having the absolute value
                    // of vertical facing bound by the maximum vertical rate of turn
                    var vDist = new WVec(-diffClfMslHgt - info.CruiseAltitude.Length, -speed, 0);
                    desiredVFacing = (sbyte)vDist.HorizontalLengthSquared != 0 ? vDist.Yaw.Facing : vFacing;

                    // If the missile is launched above CruiseAltitude, it has to descend instead of climbing
                    if (-diffClfMslHgt > info.CruiseAltitude.Length)
                    {
                        desiredVFacing = -desiredVFacing;
                    }

                    desiredVFacing = desiredVFacing.Clamp(-info.VerticalRateOfTurn.Facing, info.VerticalRateOfTurn.Facing);

                    ChangeSpeed();
                }
            }
            else
            {
                // Aim to attain cruise altitude as soon as possible while having the absolute value
                // of vertical facing bound by the maximum vertical rate of turn
                var vDist = new WVec(-diffClfMslHgt - info.CruiseAltitude.Length, -speed, 0);
                desiredVFacing = (sbyte)vDist.HorizontalLengthSquared != 0 ? vDist.Yaw.Facing : vFacing;

                // If the missile is launched above CruiseAltitude, it has to descend instead of climbing
                if (-diffClfMslHgt > info.CruiseAltitude.Length)
                {
                    desiredVFacing = -desiredVFacing;
                }

                desiredVFacing = desiredVFacing.Clamp(-info.VerticalRateOfTurn.Facing, info.VerticalRateOfTurn.Facing);

                ChangeSpeed();
            }

            return(desiredVFacing);
        }
示例#17
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 maxInaccuracyOffset = Util.GetProjectileInaccuracy(info.Inaccuracy.Length, info.InaccuracyType, args);
                target += WVec.FromPDF(world.SharedRandom, 2) * maxInaccuracyOffset / 1024;
            }

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

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

            if (!string.IsNullOrEmpty(info.Image))
            {
                anim = new Animation(world, info.Image, new Func <WAngle>(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;
        }
示例#18
0
 // This function checks if the missile's vertical facing is
 // nonnegative, and the incline top's horizontal distance from the missile is
 // less than loopRadius * (1024 - WAngle.FromFacing(vFacing).Sin()) / 1024
 static bool IsNearInclineTop(int vFacing, int loopRadius, int predClfDist)
 {
     return(vFacing >= 0 && predClfDist <= loopRadius * (1024 - WAngle.FromFacing(vFacing).Sin()) / 1024);
 }
示例#19
0
        int IncreaseAltitude(int predClfDist, int diffClfMslHgt, int relTarHorDist, int vFacing)
        {
            var desiredVFacing = vFacing;

            // If missile is below incline top height and facing downwards, bring back
            // its vertical facing above zero as soon as possible
            if ((sbyte)vFacing < 0)
            {
                desiredVFacing = info.VerticalRateOfTurn.Facing;
            }

            // Missile will climb around incline top if bringing vertical facing
            // down to zero on an arc of radius loopRadius
            else if (IsNearInclineTop(vFacing, loopRadius, predClfDist) &&
                     WillClimbAroundInclineTop(vFacing, loopRadius, predClfDist, diffClfMslHgt, speed))
            {
                desiredVFacing = 0;
            }

            // Missile will not climb terrAltDiff w-units within hHeightChange w-units
            // all the while ending the ascent with vertical facing 0
            else if (!WillClimbWithinDistance(vFacing, loopRadius, predClfDist, diffClfMslHgt))
            {
                // Find smallest vertical facing, attainable in the next tick,
                // for which the missile will be able to climb terrAltDiff w-units
                // within hHeightChange w-units all the while ending the ascent
                // with vertical facing 0
                for (var vFac = System.Math.Min(vFacing + info.VerticalRateOfTurn.Facing - 1, 63); vFac >= vFacing; vFac--)
                {
                    if (!WillClimbWithinDistance(vFac, loopRadius, predClfDist, diffClfMslHgt) &&
                        !(predClfDist <= loopRadius * (1024 - WAngle.FromFacing(vFac).Sin()) / 1024 &&
                          WillClimbAroundInclineTop(vFac, loopRadius, predClfDist, diffClfMslHgt, speed)))
                    {
                        desiredVFacing = vFac + 1;
                        break;
                    }
                }
            }

            // Attained height after ascent as predicted from upper part of incline surmounting manoeuvre
            var predAttHght = loopRadius * (1024 - WAngle.FromFacing(vFacing).Cos()) / 1024 - diffClfMslHgt;

            // Should the missile be slowed down in order to make it more maneuverable
            var slowDown = info.Acceleration.Length != 0 &&          // Possible to decelerate
                           ((desiredVFacing != 0 // Lower part of incline surmounting manoeuvre

                                                 // Incline will be hit before vertical facing attains 64
                             && (predClfDist <= loopRadius * (1024 - WAngle.FromFacing(vFacing).Sin()) / 1024

                                 // When evaluating this the incline will be *not* be hit before vertical facing attains 64
                                 // At current speed target too close to hit without passing it by
                                 || relTarHorDist <= 2 * loopRadius * (2048 - WAngle.FromFacing(vFacing).Sin()) / 1024 - predClfDist))

                            || (desiredVFacing == 0 &&          // Upper part of incline surmounting manoeuvre
                                relTarHorDist <= loopRadius * WAngle.FromFacing(vFacing).Sin() / 1024
                                + Exts.ISqrt(predAttHght * (2 * loopRadius - predAttHght))));                         // Target too close to hit at current speed

            if (slowDown)
            {
                ChangeSpeed(-1);
            }

            return(desiredVFacing);
        }
示例#20
0
        void DetermineLaunchSpeedAndAngleForIncline(int predClfDist, int diffClfMslHgt, int relTarHorDist,
                                                    out int speed, out int vFacing)
        {
            speed = maxLaunchSpeed;

            // Find smallest vertical facing, for which the missile will be able to climb terrAltDiff w-units
            // within hHeightChange w-units all the while ending the ascent with vertical facing 0
            vFacing = maxLaunchAngle.Angle >> 2;

            // Compute minimum speed necessary to both be able to face directly upwards and have enough space
            // to hit the target without passing it by (and thus having to do horizontal loops)
            var minSpeed = ((System.Math.Min(predClfDist * 1024 / (1024 - WAngle.FromFacing(vFacing).Sin()),
                                             (relTarHorDist + predClfDist) * 1024 / (2 * (2048 - WAngle.FromFacing(vFacing).Sin())))
                             * info.VerticalRateOfTurn.Facing * 157) / 6400).Clamp(minLaunchSpeed, maxLaunchSpeed);

            if ((sbyte)vFacing < 0)
            {
                speed = minSpeed;
            }
            else if (!WillClimbWithinDistance(vFacing, loopRadius, predClfDist, diffClfMslHgt) &&
                     !WillClimbAroundInclineTop(vFacing, loopRadius, predClfDist, diffClfMslHgt, speed))
            {
                // Find highest speed greater than the above minimum that allows the missile
                // to surmount the incline
                var vFac = vFacing;
                speed = BisectionSearch(minSpeed, maxLaunchSpeed, spd =>
                {
                    var lpRds = LoopRadius(spd, info.VerticalRateOfTurn.Facing);
                    return(WillClimbWithinDistance(vFac, lpRds, predClfDist, diffClfMslHgt) ||
                           WillClimbAroundInclineTop(vFac, lpRds, predClfDist, diffClfMslHgt, spd));
                });
            }
            else
            {
                // Find least vertical facing that will allow the missile to climb
                // terrAltDiff w-units within hHeightChange w-units
                // all the while ending the ascent with vertical facing 0
                vFacing = BisectionSearch(System.Math.Max((sbyte)(minLaunchAngle.Angle >> 2), (sbyte)0),
                                          (sbyte)(maxLaunchAngle.Angle >> 2),
                                          vFac => !WillClimbWithinDistance(vFac, loopRadius, predClfDist, diffClfMslHgt)) + 1;
            }
        }
示例#21
0
        public IEnumerable <VoxelAnimation> RenderPreviewVoxels(ActorPreviewInitializer init, RenderVoxelsInfo rv, string image, WRot orientation, int facings, PaletteReference p)
        {
            var body     = init.Actor.Traits.Get <BodyOrientationInfo>();
            var armament = init.Actor.Traits.WithInterface <ArmamentInfo>()
                           .First(a => a.Name == Armament);
            var t = init.Actor.Traits.WithInterface <TurretedInfo>()
                    .First(tt => tt.Turret == armament.Turret);

            var voxel             = VoxelProvider.GetVoxel(image, Sequence);
            var turretOrientation = body.QuantizeOrientation(new WRot(WAngle.Zero, WAngle.Zero, WAngle.FromFacing(t.InitialFacing) - orientation.Yaw), facings);
            var turretOffset      = body.LocalToWorld(t.Offset.Rotate(orientation));

            yield return(new VoxelAnimation(voxel, () => turretOffset, () => new [] { turretOrientation, orientation },
                                            () => false, () => 0));
        }
示例#22
0
        public void SendAirstrike(Actor self, WPos target, bool randomize = true, int attackFacing = 0)
        {
            var info = Info as AirstrikePowerASInfo;

            if (randomize)
            {
                attackFacing = 256 * self.World.SharedRandom.Next(info.QuantizedFacings) / 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 startPos = target - (self.World.Map.DistanceToEdge(target, -delta) + info.Cordon).Length * delta / 1024;

            self.World.AddFrameEndTask(w =>
            {
                PlayLaunchSounds();

                var aircrafts = new HashSet <Actor>();

                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 a = w.CreateActor(info.UnitType, new TypeDictionary
                    {
                        new CenterPositionInit(startPos + spawnOffset),
                        new OwnerInit(self.Owner),
                        new FacingInit(WAngle.FromFacing(attackFacing)),
                    });

                    delta = new WVec(WDist.Zero, info.BeaconDistanceOffset, WDist.Zero).Rotate(attackRotation);

                    if (info.Mission == AirstrikeMission.Attack)
                    {
                        var height = self.World.Map.DistanceAboveTerrain(target + spawnOffset);
                        a.QueueActivity(new FlyAttack(a, AttackSource.Default, Target.FromPos(target + spawnOffset - new WVec(WDist.Zero, WDist.Zero, height)), true, Color.OrangeRed));
                    }
                    else
                    {
                        a.QueueActivity(new Fly(a, Target.FromPos(target + spawnOffset)));
                        a.QueueActivity(new AttackMoveActivity(a, () => new FlyIdle(a, info.GuardDuration, false)));
                    }

                    a.QueueActivity(new FlyOffMap(a));
                    a.QueueActivity(new RemoveSelf());

                    aircrafts.Add(a);
                }
                ;

                var effect = new AirstrikePowerASEffect(self.World, self.Owner, target, aircrafts, this, info);
                self.World.Add(effect);
            });
        }
示例#23
0
        public IEnumerable <VoxelAnimation> RenderPreviewVoxels(
            ActorPreviewInitializer init, RenderVoxelsInfo rv, string image, Func <WRot> orientation, int facings, PaletteReference p)
        {
            if (!EnabledByDefault)
            {
                yield break;
            }

            var body     = init.Actor.TraitInfo <BodyOrientationInfo>();
            var armament = init.Actor.TraitInfos <ArmamentInfo>()
                           .First(a => a.Name == Armament);
            var t = init.Actor.TraitInfos <TurretedInfo>()
                    .First(tt => tt.Turret == armament.Turret);

            var voxel = VoxelProvider.GetVoxel(image, Sequence);

            var         turretFacing      = Turreted.TurretFacingFromInit(init, t.InitialFacing, t.Turret);
            Func <WRot> turretOrientation = () => body.QuantizeOrientation(WRot.FromYaw(WAngle.FromFacing(turretFacing()) - orientation().Yaw), facings);

            Func <WRot> quantizedTurret = () => body.QuantizeOrientation(turretOrientation(), facings);
            Func <WRot> quantizedBody   = () => body.QuantizeOrientation(orientation(), facings);
            Func <WVec> barrelOffset    = () => body.LocalToWorld((t.Offset + LocalOffset.Rotate(quantizedTurret())).Rotate(quantizedBody()));

            yield return(new VoxelAnimation(voxel, barrelOffset, () => new[] { turretOrientation(), orientation() },
                                            () => false, () => 0, ShowShadow));
        }
示例#24
0
        public LuaTable ReinforceWithTransport(Player owner, string actorType, string[] cargoTypes, CPos[] entryPath, CPos[] exitPath = null,
                                               LuaFunction actionFunc = null, LuaFunction exitFunc = null, int dropRange = 3)
        {
            var transport = CreateActor(owner, actorType, true, entryPath[0], entryPath.Length > 1 ? entryPath[1] : (CPos?)null);
            var cargo     = transport.TraitOrDefault <Cargo>();

            var passengers = new List <Actor>();

            if (cargo != null && cargoTypes != null)
            {
                foreach (var cargoType in cargoTypes)
                {
                    var passenger = CreateActor(owner, cargoType, false, entryPath[0]);
                    passengers.Add(passenger);
                    cargo.Load(transport, passenger);
                }
            }

            for (var i = 1; i < entryPath.Length; i++)
            {
                Move(transport, entryPath[i]);
            }

            if (actionFunc != null)
            {
                var af = (LuaFunction)actionFunc.CopyReference();
                transport.QueueActivity(new CallFunc(() =>
                {
                    using (af)
                        using (LuaValue t = transport.ToLuaValue(Context), p = passengers.ToArray().ToLuaValue(Context))
                            af.Call(t, p);
                }));
            }
            else
            {
                var aircraft = transport.TraitOrDefault <Aircraft>();

                // Scripted cargo aircraft must turn to default position before unloading.
                // TODO: pass facing through UnloadCargo instead.
                if (aircraft != null)
                {
                    transport.QueueActivity(new Land(transport, Target.FromCell(transport.World, entryPath.Last()), WDist.FromCells(dropRange), WAngle.FromFacing(aircraft.Info.InitialFacing)));
                }

                if (cargo != null)
                {
                    transport.QueueActivity(new UnloadCargo(transport, WDist.FromCells(dropRange)));
                }
            }

            if (exitFunc != null)
            {
                var ef = (LuaFunction)exitFunc.CopyReference();
                transport.QueueActivity(new CallFunc(() =>
                {
                    using (ef)
                        using (var t = transport.ToLuaValue(Context))
                            ef.Call(t);
                }));
            }
            else if (exitPath != null)
            {
                foreach (var wpt in exitPath)
                {
                    Move(transport, wpt);
                }

                transport.QueueActivity(new RemoveSelf());
            }

            var ret = Context.CreateTable();

            using (LuaValue
                   tKey = 1,
                   tValue = transport.ToLuaValue(Context),
                   pKey = 2,
                   pValue = passengers.ToArray().ToLuaValue(Context))
            {
                ret.Add(tKey, tValue);
                ret.Add(pKey, pValue);
            }

            return(ret);
        }
示例#25
0
 public static void FlyTick(Actor self, Aircraft aircraft, WAngle desiredFacing, WDist desiredAltitude, bool idleTurn = false)
 {
     FlyTick(self, aircraft, desiredFacing, desiredAltitude, WVec.Zero, idleTurn);
 }
示例#26
0
        public VoxelPreview(VoxelAnimation[] components, WVec offset, int zOffset, float scale, WAngle lightPitch, WAngle lightYaw,
                            float[] lightAmbientColor, float[] lightDiffuseColor, WAngle cameraPitch,
                            PaletteReference colorPalette, PaletteReference normalsPalette, PaletteReference shadowPalette)
        {
            this.components        = components;
            this.scale             = scale;
            this.lightAmbientColor = lightAmbientColor;
            this.lightDiffuseColor = lightDiffuseColor;

            lightSource = new WRot(WAngle.Zero, new WAngle(256) - lightPitch, lightYaw);
            camera      = new WRot(WAngle.Zero, cameraPitch - new WAngle(256), new WAngle(256));

            this.colorPalette   = colorPalette;
            this.normalsPalette = normalsPalette;
            this.shadowPalette  = shadowPalette;

            this.offset  = offset;
            this.zOffset = zOffset;
        }
 public Sprite GetShadow(int frame, WAngle facing)
 {
     return(ShadowStart >= 0 ? GetSprite(ShadowStart, frame, facing) : null);
 }
示例#28
0
        public int[] AsQuarternion()
        {
            // Angles increase clockwise
            var r = new WAngle(-Roll.Angle / 2);
            var p = new WAngle(-Pitch.Angle / 2);
            var y = new WAngle(-Yaw.Angle / 2);
            var cr = (long)r.Cos();
            var sr = (long)r.Sin();
            var cp = (long)p.Cos();
            var sp = (long)p.Sin();
            var cy = (long)y.Cos();
            var sy = (long)y.Sin();

            // Normalized to 1024 == 1.0
            return new int[4]
            {
                (int)((sr*cp*cy - cr*sp*sy) / 1048576), // x
                (int)((cr*sp*cy + sr*cp*sy) / 1048576), // y
                (int)((cr*cp*sy - sr*sp*cy) / 1048576), // z
                (int)((cr*cp*cy + sr*sp*sy) / 1048576)  // w
            };
        }
示例#29
0
        public IEnumerable <IActorPreview> RenderPreviewSprites(ActorPreviewInitializer init, RenderSpritesInfo rs, string image, int facings, PaletteReference p)
        {
            var body   = init.Actor.TraitInfo <BodyOrientationInfo>();
            var facing = init.Contains <FacingInit>() ? init.Get <FacingInit, int>() : 0;
            var anim   = new Animation(init.World, image, () => facing);

            anim.PlayRepeating(RenderSprites.NormalizeSequence(anim, init.GetDamageState(), Sequence));

            var orientation = body.QuantizeOrientation(new WRot(WAngle.Zero, WAngle.Zero, WAngle.FromFacing(facing)), facings);
            var offset      = body.LocalToWorld(Offset.Rotate(orientation));

            yield return(new SpriteActorPreview(anim, offset, offset.Y + offset.Z + 1, p, rs.Scale));
        }
示例#30
0
 public WRot(WAngle roll, WAngle pitch, WAngle yaw)
 {
     Roll = roll; Pitch = pitch; Yaw = yaw;
 }
示例#31
0
文件: Missile.cs 项目: nofelt/OpenRA
        void Explode(World world)
        {
            if (info.ContrailLength > 0)
            {
                world.AddFrameEndTask(w => w.Add(new ContrailFader(pos, contrail)));
            }

            world.AddFrameEndTask(w => w.Remove(this));

            // Don't blow up in our launcher's face!
            if (ticks <= info.Arm)
            {
                return;
            }

            var warheadArgs = new WarheadArgs(args)
            {
                ImpactOrientation = new WRot(WAngle.Zero, WAngle.FromFacing(vFacing), WAngle.FromFacing(hFacing)),
                ImpactPosition    = pos,
            };

            args.Weapon.Impact(Target.FromPos(pos), warheadArgs);
        }
示例#32
0
        public Laser(ProjectileArgs args, LaserInfo info)
        {
            this.info = info;

            colors = new Color[info.Radius];
            for (var i = 0; i < info.Radius; i++)
            {
                var color = info.Color == Color.Transparent ? args.SourceActor.Owner.Color.RGB : info.Color;
                var bw    = (float)((info.InnerLightness - info.OuterLightness) * i / (info.Radius - 1) + info.OuterLightness) / 0xff;
                var dstR  = bw > .5 ? 1 - (1 - 2 * (bw - .5)) * (1 - (float)color.R / 0xff) : 2 * bw * ((float)color.R / 0xff);
                var dstG  = bw > .5 ? 1 - (1 - 2 * (bw - .5)) * (1 - (float)color.G / 0xff) : 2 * bw * ((float)color.G / 0xff);
                var dstB  = bw > .5 ? 1 - (1 - 2 * (bw - .5)) * (1 - (float)color.B / 0xff) : 2 * bw * ((float)color.B / 0xff);
                colors[i] = Color.FromArgb((int)(dstR * 0xff), (int)(dstG * 0xff), (int)(dstB * 0xff));
            }

            var direction = args.PassiveTarget - args.Source;

            if (info.Distortion != 0 || info.DistortionAnimation != 0)
            {
                leftVector = new WVec(direction.Y, -direction.X, 0);
                if (leftVector.Length != 0)
                {
                    leftVector = 1024 * leftVector / leftVector.Length;
                }

                upVector = new WVec(
                    -direction.X * direction.Z,
                    -direction.Z * direction.Y,
                    direction.X * direction.X + direction.Y * direction.Y);
                if (upVector.Length != 0)
                {
                    upVector = 1024 * upVector / upVector.Length;
                }

                random = args.SourceActor.World.SharedRandom;
            }

            if (this.info.SegmentLength == WDist.Zero)
            {
                offsets = new[] { args.Source, args.PassiveTarget };
            }
            else
            {
                var numSegments = (direction.Length - 1) / info.SegmentLength.Length + 1;
                offsets    = new WPos[numSegments + 1];
                offsets[0] = args.Source;
                offsets[offsets.Length - 1] = args.PassiveTarget;

                for (var i = 1; i < numSegments; i++)
                {
                    var segmentStart = direction / numSegments * i;
                    offsets[i] = args.Source + segmentStart;

                    if (info.Distortion != 0)
                    {
                        var angle      = WAngle.FromDegrees(random.Next(360));
                        var distortion = random.Next(info.Distortion);

                        var offset = distortion * angle.Cos() * leftVector / (1024 * 1024)
                                     + distortion * angle.Sin() * upVector / (1024 * 1024);

                        offsets[i] += offset;
                    }
                }
            }

            args.Weapon.Impact(Target.FromPos(args.PassiveTarget), args.SourceActor, args.DamageModifiers);
        }
示例#33
0
        public IEnumerable <IActorPreview> RenderPreviewSprites(ActorPreviewInitializer init, RenderSpritesInfo rs, string image, int facings, PaletteReference p)
        {
            if (UpgradeMinEnabledLevel > 0)
            {
                yield break;
            }

            if (image == null)
            {
                yield break;
            }

            // For this, image must not be null
            if (Palette != null)
            {
                p = init.WorldRenderer.Palette(Palette);
            }

            var anim = new Animation(init.World, image);

            anim.PlayThen(OpeningSequence, () => anim.PlayRepeating(Sequence));

            var body        = init.Actor.TraitInfo <BodyOrientationInfo>();
            var facing      = init.Contains <FacingInit>() ? init.Get <FacingInit, int>() : 0;
            var orientation = body.QuantizeOrientation(new WRot(WAngle.Zero, WAngle.Zero, WAngle.FromFacing(facing)), facings);
            var offset      = body.LocalToWorld(Offset.Rotate(orientation));

            yield return(new SpriteActorPreview(anim, offset, offset.Y + offset.Z + 1, p, rs.Scale));
        }
示例#34
0
        void ITick.Tick(Actor self)
        {
            if (IsTraitDisabled)
            {
                return;
            }

            wasStationary = !isMoving;
            isMoving      = self.CenterPosition != cachedPosition;
            if ((isMoving && !Info.TrailWhileMoving) || (!isMoving && !Info.TrailWhileStationary))
            {
                return;
            }

            if (isMoving == wasStationary && (Info.StartDelay > -1))
            {
                cachedInterval = Info.StartDelay;
                ticks          = 0;
            }

            if (++ticks >= cachedInterval)
            {
                var spawnCell = Info.SpawnAtLastPosition ? self.World.Map.CellContaining(cachedPosition) : self.World.Map.CellContaining(self.CenterPosition);
                if (!self.World.Map.Contains(spawnCell))
                {
                    return;
                }

                var type = self.World.Map.GetTerrainInfo(spawnCell).Type;

                if (++offset >= Info.Offsets.Length)
                {
                    offset = 0;
                }

                if (!Info.TerrainTypes.Any() || Info.TerrainTypes.Contains(type))
                {
                    var spawnFacing = Info.SpawnAtLastPosition ? cachedFacing : facing?.Facing ?? WAngle.Zero;

                    if (previouslySpawned && previousSpawnCell == spawnCell)
                    {
                        spawnFacing = previousSpawnFacing;
                    }

                    var offsetRotation = Info.Offsets[offset].Rotate(body.QuantizeOrientation(self, self.Orientation));
                    var spawnPosition  = Info.SpawnAtLastPosition ? cachedPosition : self.CenterPosition;
                    var pos            = Info.Type == TrailType.CenterPosition ? spawnPosition + body.LocalToWorld(offsetRotation) :
                                         self.World.Map.CenterOfCell(spawnCell);

                    self.World.AddFrameEndTask(w => w.Add(new SpriteEffect(pos, spawnFacing, self.World, Info.Image,
                                                                           Info.Sequences.Random(Game.CosmeticRandom), Info.Palette, Info.VisibleThroughFog)));

                    previouslySpawned   = true;
                    previousSpawnCell   = spawnCell;
                    previousSpawnFacing = spawnFacing;
                }

                cachedPosition = self.CenterPosition;
                cachedFacing   = facing?.Facing ?? WAngle.Zero;
                ticks          = 0;

                cachedInterval = isMoving ? Info.MovingInterval : Info.StationaryInterval;
            }
        }
示例#35
0
 public WRot WithYaw(WAngle yaw)
 {
     return new WRot(Roll, Pitch, yaw);
 }
示例#36
0
 public WAngle GetInitialFacing()
 {
     return(WAngle.FromFacing(InitialFacing));
 }
示例#37
0
 public static WRot FromYaw(WAngle yaw)
 {
     return new WRot(WAngle.Zero, WAngle.Zero, yaw);
 }
示例#38
0
        void Calculate(Actor self)
        {
            if (dest == null || Reservable.IsReserved(dest))
            {
                dest = ChooseAirfield(self, true);
            }

            if (dest == null)
            {
                return;
            }

            var res = dest.TraitOrDefault <Reservable>();

            if (res != null)
            {
                plane.UnReserve();
                plane.Reservation = res.Reserve(dest, self, plane);
            }

            var landPos  = dest.CenterPosition;
            var altitude = planeInfo.CruiseAltitude.Length;

            // Distance required for descent.
            var landDistance = altitude * 1024 / planeInfo.MaximumPitch.Tan();

            // Land towards the east
            var approachStart = landPos + new WVec(-landDistance, 0, altitude);

            // Add 10% to the turning radius to ensure we have enough room
            var speed      = plane.MovementSpeed * 32 / 35;
            var turnRadius = (int)(141 * speed / planeInfo.ROT / (float)Math.PI);

            // Find the center of the turning circles for clockwise and counterclockwise turns
            var angle = WAngle.FromFacing(plane.Facing);
            var fwd   = -new WVec(angle.Sin(), angle.Cos(), 0);

            // Work out whether we should turn clockwise or counter-clockwise for approach
            var side           = new WVec(-fwd.Y, fwd.X, fwd.Z);
            var approachDelta  = self.CenterPosition - approachStart;
            var sideTowardBase = new[] { side, -side }
            .MinBy(a => WVec.Dot(a, approachDelta));

            // Calculate the tangent line that joins the turning circles at the current and approach positions
            var cp               = self.CenterPosition + turnRadius * sideTowardBase / 1024;
            var posCenter        = new WPos(cp.X, cp.Y, altitude);
            var approachCenter   = approachStart + new WVec(0, turnRadius * Math.Sign(self.CenterPosition.Y - approachStart.Y), 0);
            var tangentDirection = approachCenter - posCenter;
            var tangentOffset    = new WVec(-tangentDirection.Y, tangentDirection.X, 0) * turnRadius / tangentDirection.Length;

            // TODO: correctly handle CCW <-> CW turns
            if (tangentOffset.X > 0)
            {
                tangentOffset = -tangentOffset;
            }

            w1 = posCenter + tangentOffset;
            w2 = approachCenter + tangentOffset;
            w3 = approachStart;
            plane.RTBPathHash = w1 + (WVec)w2 + (WVec)w3;

            isCalculated = true;
        }
示例#39
0
 protected override int GetFacingFrameOffset(WAngle facing)
 {
     return(useClassicFacings ? Util.ClassicIndexFacing(facing, Facings) : Common.Util.IndexFacing(facing, Facings));
 }
示例#40
0
        public IEnumerable <VoxelAnimation> RenderPreviewVoxels(ActorPreviewInitializer init, RenderVoxelsInfo rv, string image, WRot orientation, int facings, PaletteReference p)
        {
            if (UpgradeMinEnabledLevel > 0)
            {
                yield break;
            }

            var body     = init.Actor.TraitInfo <BodyOrientationInfo>();
            var armament = init.Actor.TraitInfos <ArmamentInfo>()
                           .First(a => a.Name == Armament);
            var t = init.Actor.TraitInfos <TurretedInfo>()
                    .First(tt => tt.Turret == armament.Turret);

            var voxel = VoxelProvider.GetVoxel(image, Sequence);

            var turretFacing      = Turreted.GetInitialTurretFacing(init, t.InitialFacing, t.Turret);
            var turretOrientation = body.QuantizeOrientation(new WRot(WAngle.Zero, WAngle.Zero, WAngle.FromFacing(turretFacing) - orientation.Yaw), facings);

            var quantizedTurret = body.QuantizeOrientation(turretOrientation, facings);
            var quantizedBody   = body.QuantizeOrientation(orientation, facings);
            var barrelOffset    = body.LocalToWorld((t.Offset + LocalOffset.Rotate(quantizedTurret)).Rotate(quantizedBody));

            yield return(new VoxelAnimation(voxel, () => barrelOffset, () => new[] { turretOrientation, orientation },
                                            () => false, () => 0));
        }
示例#41
0
 IEnumerable <ActorInit> IActorPreviewInitInfo.ActorPreviewInits(ActorInfo ai, ActorPreviewType type)
 {
     yield return(new FacingInit(WAngle.FromFacing(PreviewFacing)));
 }
示例#42
0
        WVec HomingTick(World world, WVec tarDistVec, int relTarHorDist)
        {
            int predClfHgt  = 0;
            int predClfDist = 0;
            int lastHtChg   = 0;
            int lastHt      = 0;

            if (info.TerrainHeightAware)
            {
                InclineLookahead(world, relTarHorDist, out predClfHgt, out predClfDist, out lastHtChg, out lastHt);
            }

            // Height difference between the incline height and missile height
            var diffClfMslHgt = predClfHgt - pos.Z;

            // Get underestimate of distance from target in next tick
            var nxtRelTarHorDist = (relTarHorDist - speed - info.Acceleration.Length).Clamp(0, relTarHorDist);

            // Target height relative to the missile
            var relTarHgt = tarDistVec.Z;

            // Compute which direction the projectile should be facing
            var velVec         = tarDistVec + predVel;
            var desiredHFacing = velVec.HorizontalLengthSquared != 0 ? velVec.Yaw.Facing : hFacing;

            var delta = Util.NormalizeFacing(hFacing - desiredHFacing);

            if (allowPassBy && delta > 64 && delta < 192)
            {
                desiredHFacing = (desiredHFacing + 128) & 0xFF;
                targetPassedBy = true;
            }
            else
            {
                targetPassedBy = false;
            }

            var desiredVFacing = HomingInnerTick(predClfDist, diffClfMslHgt, relTarHorDist, lastHtChg, lastHt,
                                                 nxtRelTarHorDist, relTarHgt, vFacing, targetPassedBy);

            // The target has been passed by
            if (tarDistVec.HorizontalLength < speed * WAngle.FromFacing(vFacing).Cos() / 1024)
            {
                targetPassedBy = true;
            }

            // Check whether the homing mechanism is jammed
            var jammed = info.Jammable && world.ActorsWithTrait <JamsMissiles>().Any(JammedBy);

            if (jammed)
            {
                desiredHFacing = hFacing + world.SharedRandom.Next(-info.JammedDiversionRange, info.JammedDiversionRange + 1);
                desiredVFacing = vFacing + world.SharedRandom.Next(-info.JammedDiversionRange, info.JammedDiversionRange + 1);
            }
            else if (!args.GuidedTarget.IsValidFor(args.SourceActor))
            {
                desiredHFacing = hFacing;
            }

            // Compute new direction the projectile will be facing
            hFacing = Util.TickFacing(hFacing, desiredHFacing, info.HorizontalRateOfTurn);
            vFacing = Util.TickFacing(vFacing, desiredVFacing, info.VerticalRateOfTurn);

            // Compute the projectile's guided displacement
            return(new WVec(0, -1024 * speed, 0)
                   .Rotate(new WRot(WAngle.FromFacing(vFacing), WAngle.Zero, WAngle.Zero))
                   .Rotate(new WRot(WAngle.Zero, WAngle.Zero, WAngle.FromFacing(hFacing)))
                   / 1024);
        }