예제 #1
0
        /// <summary>
        /// Shoot a missile from the source.
        /// For players.
        /// </summary>
        public void SpawnPlayerMissile(Mobj source, MobjType type)
        {
            var hs = this.world.Hitscan;

            // See which target is to be aimed at.
            var angle = source.Angle;
            var slope = hs.AimLineAttack(source, angle, Fixed.FromInt(16 * 64));

            if (hs.LineTarget == null)
            {
                angle += new Angle(1 << 26);
                slope  = hs.AimLineAttack(source, angle, Fixed.FromInt(16 * 64));

                if (hs.LineTarget == null)
                {
                    angle -= new Angle(2 << 26);
                    slope  = hs.AimLineAttack(source, angle, Fixed.FromInt(16 * 64));
                }

                if (hs.LineTarget == null)
                {
                    angle = source.Angle;
                    slope = Fixed.Zero;
                }
            }

            var x = source.X;
            var y = source.Y;
            var z = source.Z + Fixed.FromInt(32);

            var missile = this.SpawnMobj(x, y, z, type);

            if (missile.Info.SeeSound != 0)
            {
                this.world.StartSound(missile, missile.Info.SeeSound, SfxType.Misc);
            }

            missile.Target = source;
            missile.Angle  = angle;
            missile.MomX   = new Fixed(missile.Info.Speed) * Trig.Cos(angle);
            missile.MomY   = new Fixed(missile.Info.Speed) * Trig.Sin(angle);
            missile.MomZ   = new Fixed(missile.Info.Speed) * slope;

            this.CheckMissileSpawn(missile);
        }
예제 #2
0
        /// <summary>
        /// Shoot a missile from the source to the destination.
        /// For monsters.
        /// </summary>
        public Mobj SpawnMissile(Mobj source, Mobj dest, MobjType type)
        {
            var missile = this.SpawnMobj(source.X, source.Y, source.Z + Fixed.FromInt(32), type);

            if (missile.Info.SeeSound != 0)
            {
                this.world.StartSound(missile, missile.Info.SeeSound, SfxType.Misc);
            }

            // Where it came from?
            missile.Target = source;

            var angle = Geometry.PointToAngle(source.X, source.Y, dest.X, dest.Y);

            // Fuzzy player.
            if ((dest.Flags & MobjFlags.Shadow) != 0)
            {
                var random = this.world.Random;
                angle += new Angle((random.Next() - random.Next()) << 20);
            }

            var speed = this.GetMissileSpeed(missile.Type);

            missile.Angle = angle;
            missile.MomX  = new Fixed(speed) * Trig.Cos(angle);
            missile.MomY  = new Fixed(speed) * Trig.Sin(angle);

            var dist = Geometry.AproxDistance(dest.X - source.X, dest.Y - source.Y);

            var num = (dest.Z - source.Z).Data;
            var den = (dist / speed).Data;

            if (den < 1)
            {
                den = 1;
            }

            missile.MomZ = new Fixed(num / den);

            this.CheckMissileSpawn(missile);

            return(missile);
        }
예제 #3
0
        /// <summary>
        /// Fire a hitscan bullet.
        /// If damage == 0, it is just a test trace that will leave linetarget set.
        /// </summary>
        public void LineAttack(Mobj shooter, Angle angle, Fixed range, Fixed slope, int damage)
        {
            this.currentShooter  = shooter;
            this.currentShooterZ = shooter.Z + (shooter.Height >> 1) + Fixed.FromInt(8);
            this.currentRange    = range;
            this.currentAimSlope = slope;
            this.currentDamage   = damage;

            var targetX = shooter.X + range.ToIntFloor() * Trig.Cos(angle);
            var targetY = shooter.Y + range.ToIntFloor() * Trig.Sin(angle);

            this.world.PathTraversal.PathTraverse(
                shooter.X,
                shooter.Y,
                targetX,
                targetY,
                PathTraverseFlags.AddLines | PathTraverseFlags.AddThings,
                this.shootTraverseFunc
                );
        }
예제 #4
0
        public void Cos()
        {
            for (var deg = -720; deg <= 720; deg++)
            {
                var angle     = Angle.FromDegree(deg);
                var fineAngle = (int)(angle.Data >> Trig.AngleToFineShift);

                var radian   = 2 * Math.PI * deg / 360;
                var expected = Math.Cos(radian);

                {
                    var actual = Trig.Cos(angle).ToDouble();
                    Assert.AreEqual(expected, actual, 1.0E-3);
                }

                {
                    var actual = Trig.Cos(fineAngle).ToDouble();
                    Assert.AreEqual(expected, actual, 1.0E-3);
                }
            }
        }
예제 #5
0
        /// <summary>
        /// Adjusts the x and y movement so that the next move will
        /// slide along the wall.
        /// </summary>
        private void HitSlideLine(LineDef line)
        {
            if (line.SlopeType == SlopeType.Horizontal)
            {
                this.slideMoveY = Fixed.Zero;

                return;
            }

            if (line.SlopeType == SlopeType.Vertical)
            {
                this.slideMoveX = Fixed.Zero;

                return;
            }

            var side = Geometry.PointOnLineSide(this.slideThing.X, this.slideThing.Y, line);

            var lineAngle = Geometry.PointToAngle(Fixed.Zero, Fixed.Zero, line.Dx, line.Dy);

            if (side == 1)
            {
                lineAngle += Angle.Ang180;
            }

            var moveAngle = Geometry.PointToAngle(Fixed.Zero, Fixed.Zero, this.slideMoveX, this.slideMoveY);

            var deltaAngle = moveAngle - lineAngle;

            if (deltaAngle > Angle.Ang180)
            {
                deltaAngle += Angle.Ang180;
            }

            var moveDist = Geometry.AproxDistance(this.slideMoveX, this.slideMoveY);
            var newDist  = moveDist * Trig.Cos(deltaAngle);

            this.slideMoveX = newDist * Trig.Cos(lineAngle);
            this.slideMoveY = newDist * Trig.Sin(lineAngle);
        }
예제 #6
0
    Vector3F rotatePointAroundPivot(Vector3F point, Vector3F angles)
    {
        Fix32 x = point.x;
        Fix32 y = point.y;
        Fix32 z = point.z;

        Fix32 a = angles.z * Fix32.Deg2Rad;
        Fix32 b = angles.y * Fix32.Deg2Rad;
        Fix32 c = angles.x * Fix32.Deg2Rad;

        Fix32 x1 = x * Trig.Cos(a) - y * Trig.Sin(a);
        Fix32 y1 = x * Trig.Sin(a) + y * Trig.Cos(a);

        Fix32 x2 = x * Trig.Cos(b) - z * Trig.Sin(b);
        Fix32 z2 = x * Trig.Sin(b) + z * Trig.Cos(b);

        Fix32 y3 = y * Trig.Cos(c) - z * Trig.Sin(c);
        Fix32 z3 = y * Trig.Sin(c) + z * Trig.Cos(c);

        var ret = new Vector3F(x2, y3, z3);

        return(ret);
    }
예제 #7
0
        private void Func()
        {
            DataContext = null;
            int    N = Convert.ToInt32(Ntext.Text);
            double ax = -1, bx = 1;
            double h = (bx - ax) / (N);

            double[]      x = new double[N + 1];
            List <double> y = new List <double>();

            double[,] ACB = new double[N, N];
            double[] F = new double[N];
            double   a = Convert.ToDouble(Atext.Text);

            double YAnalytic(double x) => (Trig.Cos(Math.PI * x) + x + ((x * SpecialFunctions.Erf(x / Math.Sqrt(2 * a)) + Math.Sqrt((2 * a) / Math.PI) * Math.Exp(-(x * x) / (2 * a))) / (SpecialFunctions.Erf(1 / Math.Sqrt(2 * a)) + Math.Sqrt(2 * a / Math.PI) * Math.Exp(-1 / (2 * a)))));


            for (int i = 0; i <= N; i++)
            {
                x[i] = ax + i * h;
            }

            for (int i = 0; i <= N; i++)
            {
                y.Add(YAnalytic(x[i]));
            }



            var ACBmatrix = MathNet.Numerics.LinearAlgebra.Matrix <double> .Build.DenseOfArray(new double[, ]
            {
                { a *Math.PI *Math.PI + 1, Math.PI },
                { a *Math.PI *Math.PI + Math.PI / 4 - 1, (-8 * a *Math.PI *Math.PI) / Math.Sqrt(2) - 1 }
            });

            var Fvector = MathNet.Numerics.LinearAlgebra.Vector <double> .Build.DenseOfArray(new double[]
            {
                -Math.PI / 2,
                //  -Math.PI/2+((a*Math.PI*Math.PI/8)*Math.Sin(Math.PI/8))+(Math.PI/4)*Math.Cos(Math.PI/8)-1+2*Math.Sin(Math.PI/8),
                -(1 + a *Math.PI *Math.PI) - Math.PI / 4
                // -(1+a*Math.PI*Math.PI)-Math.PI/4+Math.Sqrt(2)*(((a*Math.PI*Math.PI)/8)*Math.Sin(5*Math.PI/16)-(Math.PI/8)*Math.Cos(5*Math.PI/16)-1+2*Math.Sin(5*Math.PI/16))
            });

            var Cvector = ACBmatrix.Solve(Fvector);

            double c1 = Cvector[0];
            double c2 = Cvector[1];


            List <double> yres = new List <double>();

            for (int i = 0; i <= N; i++)
            {
                yres.Add(x[i] + c1 * (1 - Math.Pow(x[i], 2)) + c2 * (1 + x[i] - Math.Pow(x[i], 2) - Math.Pow(x[i], 3)));
            }

            SeriesCollection = new SeriesCollection
            {
                new LineSeries
                {
                    Title  = "Analytic Y",
                    Values = new ChartValues <double>(y.ToList <double>())
                },
                new LineSeries
                {
                    Title  = "Gilerkin",
                    Values = new ChartValues <double>(yres)
                }
            };
            Labels      = x.Select(x => x.ToString("F2")).ToArray();
            YFormatter  = value => value.ToString("F2");
            DataContext = this;
            List <MyTable> result = new List <MyTable>();

            for (int i = 0; i <= N; i++)
            {
                result.Add(new MyTable(x[i], y[i], yres[i]));
            }

            grid.ItemsSource = result;
        }
예제 #8
0
        static void Main(string[] args)
        {
            // A simple accelerometer is constructed by suspending a
            // mass m from a string of length L that is tied to the top
            // of a cart. As the cart is accelerated the string-mass
            // system makes a constant angle th with the vertical.
            // (a) Assuming that the string mass is negligible compared
            // with m, derive an expression for the cart’s acceleration
            // in terms of and show that it is independent of
            // the mass mand the length L.
            // (b) Determine the acceleration of the cart when th = 23.0°.

            var F1 = new Symbol("F1"); // force of string
            var F2 = new Symbol("F2"); // force of gravity

            var th1 = new Symbol("th1");
            var th2 = new Symbol("th2");;

            var _F1 = new Point()
            {
                angle = th1
            };
            var _F2 = new Point()
            {
                angle = th2, magnitude = F2
            };

            var m = new Symbol("m");

            var g = new Symbol("g");

            var obj = new Obj()
            {
                mass = m
            };

            obj.acceleration.y = 0;

            obj.forces.Add(_F1);
            obj.forces.Add(_F2);

            _F1.magnitude = obj.ForceMagnitude(_F1);

            ("Derive an expression for the cart’s acceleration in terms " +
             "of and show that it is independent of the mass mand the length L:").Disp();

            "".Disp();

            obj.AccelerationX()
            .Substitute(F2, m * g)
            .Substitute(Trig.Cos(th2), 0)
            .Substitute(Trig.Sin(th2), -1)
            .Disp();

            "".Disp();

            "Determine the acceleration of the cart when th = 23.0°".Disp(); "".Disp();

            obj.AccelerationX()
            .Substitute(F2, m * g)
            .Substitute(Trig.Cos(th2), 0)
            .Substitute(Trig.Sin(th2), -1)
            .Substitute(th1, (90 - 23).ToRadians())
            .Substitute(Trig.Pi, Math.PI)
            .Substitute(g, 9.8)
            .Disp();

            Console.ReadLine();
        }
예제 #9
0
        /// <summary>
        /// Creating the multiplier for each x,y,z movement by the amplitude , aimuth , elevtion and tilt.
        /// </summary>
        /// <param name="amplitude">Amplitude (degree).</param>
        /// <param name="azimuth">Azimuth (degree).</param>
        /// <param name="elevation">Elevation (degree).</param>
        /// <param name="tilt">Tilt (degree).</param>
        /// <returns></returns>
        public Tuple <double, double, double> CreateMultiplyTuple(double amplitude, double azimuth, double elevation, double tilt)
        {
            //converting the angles to radian.
            amplitude = amplitude * Math.PI / 180;
            azimuth   = azimuth * Math.PI / 180;
            elevation = elevation * Math.PI / 180;
            tilt      = tilt * Math.PI / 180;

            //making the multipliers vector.
            double xM = -Trig.Sin(amplitude) * Trig.Sin(azimuth) * Trig.Cos(tilt) +
                        Trig.Cos(amplitude) *
                        (Trig.Cos(azimuth) * Trig.Cos(elevation) + Trig.Sin(azimuth) * Trig.Sin(tilt) * Trig.Sin(elevation));

            double yM = Trig.Sin(amplitude) * Trig.Cos(azimuth) * Trig.Cos(tilt) +
                        Trig.Cos(amplitude) *
                        (Trig.Sin(azimuth) * Trig.Cos(elevation) +
                         -Trig.Cos(azimuth) * Trig.Sin(tilt) * Trig.Sin(elevation));

            //the axis for y and z are opposite in the Moog.
            yM = -yM;

            double zM = -Trig.Sin(amplitude) * Trig.Sin(tilt) - Trig.Cos(amplitude) * Trig.Sin(elevation) * Trig.Cos(tilt);

            //the axis for y and z are opposite in the Moog.
            zM = -zM;

            //return the requested vector.
            return(new Tuple <double, double, double>(xM, yM, zM));
        }
예제 #10
0
 /// <summary>
 /// Moves the given origin along a given angle.
 /// </summary>
 public void Thrust(Player player, Angle angle, Fixed move)
 {
     player.Mobj.MomX += move * Trig.Cos(angle);
     player.Mobj.MomY += move * Trig.Sin(angle);
 }
예제 #11
0
 /// <summary>
 ///     Returns the cosine of an <paramref name="angle" /> in radians.
 /// </summary>
 /// <param name="absoluteValue">Return absolute values? (default: false).</param>
 public static double Cos(this double angle, bool absoluteValue = false) =>
 absoluteValue
                         ? Trig.Cos(angle).CoerceZero(1E-6).Abs()
                         : Trig.Cos(angle).CoerceZero(1E-6);
예제 #12
0
        private void Func()
        {
            DataContext = null;
            int    N = Convert.ToInt32(Ntext.Text);
            double ax = -1, bx = 1;
            double h = (bx - ax) / (N);

            double[]      x = new double[N + 1];
            List <double> y = new List <double>();

            double[,] ACB = new double[N, N];
            double[] F = new double[N];
            double   a = Convert.ToDouble(Atext.Text);

            double YAnalytic(double x) => (Trig.Cos(Math.PI * x) + x + ((x * SpecialFunctions.Erf(x / Math.Sqrt(2 * a)) + Math.Sqrt((2 * a) / Math.PI) * Math.Exp(-(x * x) / (2 * a))) / (SpecialFunctions.Erf(1 / Math.Sqrt(2 * a)) + Math.Sqrt(2 * a / Math.PI) * Math.Exp(-1 / (2 * a)))));


            for (int i = 0; i <= N; i++)
            {
                x[i] = ax + i * h;
            }

            for (int i = 0; i <= N; i++)
            {
                y.Add(YAnalytic(x[i]));
            }

            ACB[0, 0] = -a + ((x[0] * h) / 2);
            ACB[0, 1] = 2 * a - ((-1) * h * h);
            F[0]      = -(1 + a * Math.Pow(Math.PI, 2)) * Math.Cos(Math.PI * x[0]) - Math.PI * x[0] * Math.Sin(Math.PI * x[0]) + (((-a + ((x[0] * h) / 2)) * (-1)) / (h * h));

            for (int i = 1; i < N - 1; i++)
            {
                ACB[i, i - 1] = -a + ((x[i] * h) / 2);
                ACB[i, i]     = 2 * a - ((-1) * h * h);
                ACB[i, i + 1] = -a - ((x[i] * h) / 2);
                F[i]          = -(1 + a * Math.Pow(Math.PI, 2)) * Math.Cos(Math.PI * x[i]) - Math.PI * x[i] * Math.Sin(Math.PI * x[i]);
            }

            ACB[N - 1, N - 2] = 2 * a - ((-1) * h * h);
            ACB[N - 1, N - 1] = -a - ((x[N - 1] * h) / 2);
            F[N - 1]          = -(1 + a * Math.Pow(Math.PI, 2)) * Math.Cos(Math.PI * x[N - 1]) - Math.PI * x[N - 1] * Math.Sin(Math.PI * x[N - 1]) + (((-a - ((x[N - 1] * h) / 2)) * (1)) / (h * h));


            for (int i = 0; i < N; i++)
            {
                for (int j = 0; j < N; j++)
                {
                    Console.Write(ACB[i, j].ToString("f3") + "  ");
                }
                Console.WriteLine(" = " + F[i]);
            }

            var ACBmatrix = MathNet.Numerics.LinearAlgebra.Matrix <double> .Build.DenseOfArray(ACB);

            var Fvector = MathNet.Numerics.LinearAlgebra.Vector <double> .Build.DenseOfArray(F);

            Fvector = Fvector * -Math.Pow(h, 2);
            var Yvector = ACBmatrix.Solve(Fvector);


            List <double> yres = new List <double>();

            for (int i = 0; i < N; i++)
            {
                yres.Add(Yvector[i]);
            }
            yres.Insert(0, -1);
            yres[N] = 1;

            SeriesCollection = new SeriesCollection
            {
                new LineSeries
                {
                    Title  = "Analytic Y",
                    Values = new ChartValues <double>(y.ToList <double>())
                },
                new LineSeries
                {
                    Title  = "Y method",
                    Values = new ChartValues <double>(yres)
                }
            };
            Labels      = x.Select(x => x.ToString("F2")).ToArray();
            YFormatter  = value => value.ToString("F2");
            DataContext = this;
            List <MyTable> result = new List <MyTable>();

            result.Add(new MyTable(x[0], y[0], -1));
            for (int i = 1; i < N; i++)
            {
                result.Add(new MyTable(x[i], y[i], yres[i]));
            }
            result.Add(new MyTable(x[N], y[N], 1));

            grid.ItemsSource = result;
        }
예제 #13
0
        static void Main(string[] args)
        {
            // Two people pull as hard as they can on ropes attached
            // to a boat that has a mass of 200 kg. If they pull in the
            // same direction, the boat has an acceleration of
            // 1.52 m/s^2 to the right. If they pull in opposite directions,
            // the boat has an acceleration of 0.518 m/s^2
            // to the left. What is the force exerted by each person on the
            // boat? (Disregard any other forces on the boat.)

            // Trig.Cos(new DoubleFloat(Math.PI)).Disp();

            var m = new Symbol("m");

            var aAx = new Symbol("aAx");
            var aBx = new Symbol("aBx");

            var objA = new Obj()
            {
                mass = m
            };

            objA.acceleration.x = aAx;

            var _F1A = new Point()
            {
                angle = 0
            };
            var _F2A = new Point()
            {
                angle = 0
            };

            objA.forces.Add(_F1A);
            objA.forces.Add(_F2A);


            var objB = new Obj()
            {
                mass = m
            };

            objB.acceleration.x = aBx;

            var _F1B = new Point()
            {
                angle = 0
            };
            var _F2B = new Point()
            {
                angle = new DoubleFloat(Math.PI)
            };

            objB.forces.Add(_F1B);
            objB.forces.Add(_F2B);

            "force 1 magnitude (symbolic):".Disp(); "".Disp();

            Calc.ForceMagnitude(objA, objB, _F1A, _F1B)
            .Substitute(Trig.Cos(0), 1)
            .Disp();

            "force 1 magnitude (numeric):".Disp(); "".Disp();

            Calc.ForceMagnitude(objA, objB, _F1A, _F1B)
            .Substitute(Trig.Cos(0), 1)
            .Substitute(m, 200)
            .Substitute(aAx, 1.52)
            .Substitute(aBx, -0.518)
            .Disp();

            "".Disp();

            "force 2 magnitude (symbolic):".Disp(); "".Disp();

            Calc.ForceMagnitude(objA, objB, _F2A, _F2B)
            .Substitute(Trig.Cos(0), 1)
            .Disp();

            "force 2 magnitude (numeric):".Disp(); "".Disp();

            Calc.ForceMagnitude(objA, objB, _F2A, _F2B)
            .Substitute(Trig.Cos(0), 1)
            .Substitute(m, 200)
            .Substitute(aAx, 1.52)
            .Substitute(aBx, -0.518)
            .Disp();

            "".Disp();



            Console.ReadLine();
        }
예제 #14
0
        /// <summary>
        /// Returns false if the player cannot be respawned at the given
        /// mapthing spot because something is occupying it.
        /// </summary>
        public bool CheckSpot(int playernum, MapThing mthing)
        {
            var players = this.world.Options.Players;

            if (players[playernum].Mobj == null)
            {
                // First spawn of level, before corpses.
                for (var i = 0; i < playernum; i++)
                {
                    if (players[i].Mobj.X == mthing.X && players[i].Mobj.Y == mthing.Y)
                    {
                        return(false);
                    }
                }

                return(true);
            }

            var x = mthing.X;
            var y = mthing.Y;

            if (!this.world.ThingMovement.CheckPosition(players[playernum].Mobj, x, y))
            {
                return(false);
            }

            // Flush an old corpse if needed.
            if (this.bodyQueSlot >= ThingAllocation.bodyQueSize)
            {
                this.RemoveMobj(this.bodyQue[this.bodyQueSlot % ThingAllocation.bodyQueSize]);
            }

            this.bodyQue[this.bodyQueSlot % ThingAllocation.bodyQueSize] = players[playernum].Mobj;
            this.bodyQueSlot++;

            // Spawn a teleport fog.
            var subsector = Geometry.PointInSubsector(x, y, this.world.Map);

            var angle = (Angle.Ang45.Data >> Trig.AngleToFineShift) * ((int)Math.Round(mthing.Angle.ToDegree()) / 45);

            //
            // The code below to reproduce respawn fog bug in deathmath
            // is based on Chocolate Doom's implementation.
            //

            Fixed xa;
            Fixed ya;

            switch (angle)
            {
            case 4096:                     // -4096:
                xa = Trig.Tan(2048);       // finecosine[-4096]
                ya = Trig.Tan(0);          // finesine[-4096]

                break;

            case 5120:                     // -3072:
                xa = Trig.Tan(3072);       // finecosine[-3072]
                ya = Trig.Tan(1024);       // finesine[-3072]

                break;

            case 6144:                     // -2048:
                xa = Trig.Sin(0);          // finecosine[-2048]
                ya = Trig.Tan(2048);       // finesine[-2048]

                break;

            case 7168:                     // -1024:
                xa = Trig.Sin(1024);       // finecosine[-1024]
                ya = Trig.Tan(3072);       // finesine[-1024]

                break;

            case 0:
            case 1024:
            case 2048:
            case 3072:
                xa = Trig.Cos((int)angle);
                ya = Trig.Sin((int)angle);

                break;

            default:
                throw new Exception("Unexpected angle: " + angle);
            }

            var mo = this.SpawnMobj(x + 20 * xa, y + 20 * ya, subsector.Sector.FloorHeight, MobjType.Tfog);

            if (!this.world.FirstTicIsNotYetDone)
            {
                // Don't start sound on first frame.
                this.world.StartSound(mo, Sfx.TELEPT, SfxType.Misc);
            }

            return(true);
        }
예제 #15
0
        public void CanComputeCosine(double value, double expected)
        {
            var actual = Trig.Cos(value);

            AssertHelpers.AlmostEqual(expected, actual, 14);
        }
예제 #16
0
        /// <summary>
        /// Damages both enemies and players.
        /// "inflictor" is the thing that caused the damage creature
        /// or missile, can be null (slime, etc).
        /// "source" is the thing to target after taking damage creature
        /// or null.
        /// Source and inflictor are the same for melee attacks.
        /// Source can be null for slime, barrel explosions and other
        /// environmental stuff.
        /// </summary>
        public void DamageMobj(Mobj target, Mobj inflictor, Mobj source, int damage)
        {
            if ((target.Flags & MobjFlags.Shootable) == 0)
            {
                // Shouldn't happen...
                return;
            }

            if (target.Health <= 0)
            {
                return;
            }

            if ((target.Flags & MobjFlags.SkullFly) != 0)
            {
                target.MomX = target.MomY = target.MomZ = Fixed.Zero;
            }

            var player = target.Player;

            if (player != null && this.world.Options.Skill == GameSkill.Baby)
            {
                // Take half damage in trainer mode.
                damage >>= 1;
            }

            // Some close combat weapons should not inflict thrust and
            // push the victim out of reach, thus kick away unless using the chainsaw.
            var notChainsawAttack = source == null || source.Player == null || !(source.Player.ReadyWeapon.Info is WeaponChainsaw);

            if (inflictor != null && (target.Flags & MobjFlags.NoClip) == 0 && notChainsawAttack)
            {
                var ang = Geometry.PointToAngle(inflictor.X, inflictor.Y, target.X, target.Y);

                var thrust = new Fixed(damage * (Fixed.FracUnit >> 3) * 100 / target.Info.Mass);

                // Make fall forwards sometimes.
                if (damage < 40 && damage > target.Health && target.Z - inflictor.Z > Fixed.FromInt(64) && (this.world.Random.Next() & 1) != 0)
                {
                    ang    += Angle.Ang180;
                    thrust *= 4;
                }

                target.MomX += thrust * Trig.Cos(ang);
                target.MomY += thrust * Trig.Sin(ang);
            }

            // Player specific.
            if (player != null)
            {
                // End of game hell hack.
                if (target.Subsector.Sector.Special == (SectorSpecial)11 && damage >= target.Health)
                {
                    damage = target.Health - 1;
                }

                // Below certain threshold, ignore damage in GOD mode, or with INVUL power.
                if (damage < 1000 && ((player.Cheats & CheatFlags.GodMode) != 0 || player.Powers[(int)PowerType.Invulnerability] > 0))
                {
                    return;
                }

                int saved;

                if (player.ArmorType != 0)
                {
                    if (player.ArmorType == 1)
                    {
                        saved = damage / 3;
                    }
                    else
                    {
                        saved = damage / 2;
                    }

                    if (player.ArmorPoints <= saved)
                    {
                        // Armor is used up.
                        saved            = player.ArmorPoints;
                        player.ArmorType = 0;
                    }

                    player.ArmorPoints -= saved;
                    damage             -= saved;
                }

                // Mirror mobj health here for Dave.
                player.Health -= damage;

                if (player.Health < 0)
                {
                    player.Health = 0;
                }

                player.Attacker = source;

                // Add damage after armor / invuln.
                player.DamageCount += damage;

                if (player.DamageCount > 100)
                {
                    // Teleport stomp does 10k points...
                    player.DamageCount = 100;
                }
            }

            // Do the damage.
            target.Health -= damage;

            if (target.Health <= 0)
            {
                this.KillMobj(source, target);

                return;
            }

            if ((this.world.Random.Next() < target.Info.PainChance) && (target.Flags & MobjFlags.SkullFly) == 0)
            {
                // Fight back!
                target.Flags |= MobjFlags.JustHit;

                target.SetState(target.Info.PainState);
            }

            // We're awake now...
            target.ReactionTime = 0;

            if ((target.Threshold == 0 || target.Type == MobjType.Vile) && source != null && source != target && source.Type != MobjType.Vile)
            {
                // If not intent on another player, chase after this one.
                target.Target    = source;
                target.Threshold = ThingInteraction.baseThreshold;

                if (target.State == DoomInfo.States[(int)target.Info.SpawnState] && target.Info.SeeState != MobjState.Null)
                {
                    target.SetState(target.Info.SeeState);
                }
            }
        }
예제 #17
0
 private static double ObjectiveFunction(double x)
 {
     return(-x *Trig.Cos(-2 *x) * Math.Exp(-x / 3));
 }
예제 #18
0
        /// <summary>
        /// Spawns cubes upon an arc of an ellipse.
        /// </summary>
        /// <param name="n"> The number of cubes. </param>
        /// <param name="center"> The center of the ellipse. </param>
        /// <param name="sectorChordLength"> The length of the arc's chord. </param>
        /// <param name="semiMinorAxisLength"> Half the length of the minor axis. </param>
        /// <param name="sectorAngleDeg"> The angular length of the arc in degrees. </param>
        /// <param name="cubePrefab"> The template for the cubes. </param>
        /// <param name="parent"> The parent of the cubes structure. </param>
        /// <returns> Returns the GameObject containing the cubes, whose parent is 'parent'. </returns>
        /// <remarks> This function is definitely very time-expensive. Use sparingly. </remarks>
        private static GameObject SpawnEllipseCubes(int n, Vector3 center, float sectorChordLength, float semiMinorAxisLength, float sectorAngleDeg, GameObject cubePrefab, Transform parent = null)
        {
            // TODO: Find constraints for every parameter and variable (minimum and maximum values)
            //       Problem: for some combination of input parameters, the FindRoots.OfFunction method fails with an exception:
            //                "ArithmeticException: Function does not accept floating point Not-a-Number values."
            //       Sample parameters: (16,, 12.0f, 6.0f, 90°,,)

            #region Maths

            /*
             * C: center of the ellipse
             * R: sectorChordLength, the length of the chord
             * a: half the length of the major axis of the ellipse
             * b: semiMinorAxisLength, half the length of the minor axis of the ellipse
             * α: sectorAngleDeg, the sector extension in degrees, from (90° - α/2) to (90° + α/2) counterclock-wise
             * n: number of cubes
             *
             *
             * § 1) ELLIPSE'S EQUATIONS
             *
             * ξ(ϑ): ellipse's parametric equations [-180° ≤ ϑ ≤ 180°]
             *     where ϑ is the angle of (ξˣ(ϑ), ξʸ(ϑ)) with the major axis of the ellipse itself
             *                       ___________________________
             *   ξˣ(ϑ) = a b cos(ϑ) √(a² sin²(ϑ) + b² cos²(ϑ))⁻¹
             *                       ___________________________
             *   ξʸ(ϑ) = a b sin(ϑ) √(a² sin²(ϑ) + b² cos²(ϑ))⁻¹
             *
             * A = ξ(90° + α/2)
             * B = ξ(90° - α/2)
             *
             *     __                   _______________________________
             * R = AB = 2 a b sin(α/2) √(a² cos²(α/2) + b² sin²(α/2))⁻¹
             *      _________________________________________                   _______________________
             * a = √(b² R² tan²(α/2)) / (4 b² tan²(α/2) - R²) = (b R tan(α/2)) √(4 b² tan²(α/2) - R²)⁻¹
             *
             *
             * § 2) CUBES PLACEMENT
             *      A _____________________
             * L = ∫(√D[ξˣ(ϑ)]² + D[ξʸ(ϑ)]²)dϑ: length of arc AB
             *    B
             * l = L/n: distance between each cube's center on the arc
             *
             * θᵢ: angle of the iᵗʰ arc segment; arc length to the iᵗʰ arc segment = i l
             * θᵢ = FindRoot[∫(D[ξˣ(ϑ)]² + D[ξʸ(ϑ)]²)dϑ = i l]   😭
             *
             * Pᵢ = ξ(θᵢ): position of the iᵗʰ cube
             *
             *
             * § 3) CUBES' SIDE LENGTH
             * Let Pᵢ and Pⱼ be the positions of two consecutive cubes (j = i + 1) with angles θᵢ and θⱼ.
             * Let Pₖ be a third point placed at the same arc-distance from both Pᵢ and Pⱼ; the angle of Pₖ is θₖ.
             *
             * rₖ: line from C to Pₖ
             * rᵢ: line from C to Pᵢ
             * rⱼ: line from C to Pⱼ
             *
             * M: parametric point on rₖ
             * dᵢ: segment MPᵢ
             * dⱼ: segment MPⱼ
             *
             *
             * M = (mˣ, mʸ) = (mˣ, mˣ tan(θₖ))
             *       ____________________________________
             * dᵢ = √(x(Pᵢ) - mˣ)² + (y(Pᵢ) - mˣ tan(θₖ))²
             *       ____________________________________
             * dⱼ = √(x(Pⱼ) - mˣ)² + (y(Pⱼ) - mˣ tan(θₖ))²
             *
             * ASSERTION
             * dᵢ = dⱼ = d: dᵢ and dⱼ are the semi-diagonals of the two squares
             *
             * (x(Pᵢ) - mˣ)² + (y(Pᵢ) - mˣ tan(θₖ))² = (x(Pⱼ) - mˣ)² + (y(Pⱼ) - mˣ tan(θₖ))²
             * x(Pᵢ)² + (mˣ)² - 2 x(Pᵢ) mˣ + y(Pᵢ)² + (mˣ tan(θₖ))² - 2 y(Pᵢ) mˣ tan(θₖ)  =  x(Pⱼ)² + (mˣ)² - 2 x(Pⱼ) mˣ + y(Pⱼ)² + (mˣ tan(θₖ))² - 2 y(Pⱼ) mˣ tan(θₖ)
             * x(Pᵢ)² - 2 x(Pᵢ) mˣ + y(Pᵢ)² - 2 y(Pᵢ) mˣ tan(θₖ)  =  x(Pⱼ)² - 2 x(Pⱼ) mˣ + y(Pⱼ)² - 2 y(Pⱼ) mˣ tan(θₖ)
             * 2 x(Pⱼ) mˣ + 2 y(Pⱼ) mˣ tan(θₖ) - 2 x(Pᵢ) mˣ - 2 y(Pᵢ) mˣ tan(θₖ)  =  x(Pⱼ)² + y(Pⱼ)² - x(Pᵢ)² - y(Pᵢ)²
             * 2 mˣ (x(Pⱼ) + y(Pⱼ) tan(θₖ) - x(Pᵢ) - y(Pᵢ) tan(θₖ))  =  x(Pⱼ)² + y(Pⱼ)² - x(Pᵢ)² - y(Pᵢ)²
             *
             *              x(Pⱼ)² + y(Pⱼ)² - x(Pᵢ)² - y(Pᵢ)²
             * mˣ = ——————————————————————————————————————————————————
             *       2 (x(Pⱼ) + y(Pⱼ) tan(θₖ) - x(Pᵢ) - y(Pᵢ) tan(θₖ))
             *
             * cube's side length = 2 (d/√2)
             *
             */

            #endregion Maths

            double R = sectorChordLength;
            double b = semiMinorAxisLength;

            #region § 1) ELLIPSE'S EQUATION

            double alphaRad      = Trig.DegreeToRadian(sectorAngleDeg);
            double bTanHalfAlpha = b * Trig.Tan(alphaRad / 2.0);
            double a             = (R * bTanHalfAlpha) / Math.Sqrt(4 * bTanHalfAlpha * bTanHalfAlpha - R * R);

            Func <double, double> EllipseX = t =>
            {
                double sin  = Trig.Sin(t);
                double cos  = Trig.Cos(t);
                double aSin = a * sin;
                double bCos = b * cos;
                return((a * bCos) / Math.Sqrt(aSin * aSin + bCos * bCos));
            };
            Func <double, double> EllipseY = t =>
            {
                double sin  = Trig.Sin(t);
                double cos  = Trig.Cos(t);
                double aSin = a * sin;
                double bCos = b * cos;
                return((b * aSin) / Math.Sqrt(aSin * aSin + bCos * bCos));
            };

            #endregion § 1) ELLIPSE'S EQUATION

            #region § 2) CUBES PLACEMENT

            Func <double, double> DEllipseX = Differentiate.FirstDerivativeFunc(EllipseX);
            Func <double, double> DEllipseY = Differentiate.FirstDerivativeFunc(EllipseY);

            Func <double, double> SqrtOfSumOfSquaredDerivatives = t =>
            {
                double x = DEllipseX(t);
                double y = DEllipseY(t);
                return(Math.Sqrt(x * x + y * y));
            };

            Func <double, double, double> AngleToArcLength = (fromRad, toRad) => Integrate.OnClosedInterval(SqrtOfSumOfSquaredDerivatives, fromRad, toRad);
            Func <double, double>         ArcLengthToAngle = arcLength => FindRoots.OfFunction(toRad => AngleToArcLength((Math.PI - alphaRad) / 2, toRad) - arcLength, 0, Math.PI);

            double L = AngleToArcLength((Math.PI - alphaRad) / 2, (Math.PI + alphaRad) / 2);
            double l = L / (n - 1);

            Func <int, object[]> CalculateCubePositionAndAngle = i =>
            {
                double  angle    = ArcLengthToAngle(i * l);
                Vector2 position = new Vector2((float)EllipseX(angle), (float)EllipseY(angle));
                return(new object[] { position, angle });
            };

            #endregion § 2) CUBES PLACEMENT

            #region § 3) CUBES' SIDE LENGTH

            Vector2[] positions    = new Vector2[n];
            double[]  angles       = new double[n];
            double[]  middleAngles = new double[n - 1];
            for (int i = 0; i < n; ++i)
            {
                object[] res = CalculateCubePositionAndAngle(i);
                positions[i] = (Vector2)res[0];
                angles[i]    = (double)res[1];

                if (i > 0)
                {
                    middleAngles[i - 1] = ArcLengthToAngle((2 * i - 1) * l / 2.0);
                }
            }

            double[]           sideLengths = new double[n - 1];
            Func <int, double> SideLength  = j =>
            {
                double xj   = positions[j].x;
                double yj   = positions[j].y;
                double xi   = positions[j - 1].x;
                double yi   = positions[j - 1].y;
                double tanK = Trig.Tan(middleAngles[j - 1]);
                double mx   = (xj * xj + yj * yj - (xi * xi + yi * yi)) / (2.0 * (xj + yj * tanK - (xi + yi * tanK)));
                return(Math.Sqrt((xi - mx) * (xi - mx) + (yi - mx * tanK) * (yi - mx * tanK)) * (2.0 / Math.Sqrt(2.0)));
            };
            for (int i = 1; i < n; ++i)
            {
                sideLengths[i - 1] = SideLength(i);
            }

            float squareSide = (float)sideLengths.Min();

            #endregion § 3) CUBES' SIDE LENGTH

            // Save parent's current local rotation and scale; it will be re-set later
            Quaternion parentRotation = parent?.localRotation ?? Quaternion.identity;
            Vector3    parentScale    = parent?.localScale ?? Vector3.one;
            if (parent != null)
            {
                parent.localRotation = Quaternion.identity;
                parent.localScale    = Vector3.one;
            }

            GameObject cubesContainer = parent?.gameObject ?? new GameObject();
            cubesContainer.name = $"Ellipse_{n}Cubes";
            cubesContainer.transform.localPosition = center;

            // Create the cubes
            for (int i = 0; i < n; ++i)
            {
                GameObject cube = Instantiate(cubePrefab);
                cube.name = $"Cube{i}";
                cube.SetActive(true); // Awake it now, to let it store the prefab's original scale
                cube.transform.localScale    = new Vector3(squareSide, squareSide, squareSide);
                cube.transform.position      = cubesContainer.transform.position + new Vector3(positions[i].x, 0.0f, positions[i].y);
                cube.transform.localRotation = Quaternion.Euler(0.0f, (float)(90.0 - Trig.RadianToDegree(angles[i])), 0.0f);
                cube.transform.parent        = cubesContainer.transform;
            }
            cubesContainer.transform.localRotation = Quaternion.identity;

            // Re-set parent's original local rotation
            if (parent != null)
            {
                parent.localRotation = parentRotation;
                parent.localScale    = parentScale;
            }

            return(cubesContainer);
        }