예제 #1
0
        /// <summary>
        /// Returns true if the traverser function returns true for all lines.
        /// </summary>
        private bool TraverseIntercepts(Func <Intercept, bool> func, Fixed maxFrac)
        {
            var count = this.interceptCount;

            Intercept intercept = null;

            while (count-- > 0)
            {
                var dist = Fixed.MaxValue;

                for (var i = 0; i < this.interceptCount; i++)
                {
                    if (this.intercepts[i].Frac < dist)
                    {
                        dist      = this.intercepts[i].Frac;
                        intercept = this.intercepts[i];
                    }
                }

                if (dist > maxFrac)
                {
                    // Checked everything in range.
                    return(true);
                }

                if (!func(intercept))
                {
                    // Don't bother going farther.
                    return(false);
                }

                intercept.Frac = Fixed.MaxValue;
            }

            // Everything was traversed.
            return(true);
        }
예제 #2
0
        /// <summary>
        /// Find a thing or wall which is on the aiming line.
        /// Sets lineTaget and aimSlope when a target is aimed at.
        /// </summary>
        private bool AimTraverse(Intercept intercept)
        {
            if (intercept.Line != null)
            {
                var line = intercept.Line;

                if ((line.Flags & LineFlags.TwoSided) == 0)
                {
                    // Stop.
                    return(false);
                }

                var mc = this.world.MapCollision;

                // Crosses a two sided line.
                // A two sided line will restrict the possible target ranges.
                mc.LineOpening(line);

                if (mc.OpenBottom >= mc.OpenTop)
                {
                    // Stop.
                    return(false);
                }

                var dist = this.currentRange * intercept.Frac;

                if (line.FrontSector.FloorHeight != line.BackSector.FloorHeight)
                {
                    var slope = (mc.OpenBottom - this.currentShooterZ) / dist;

                    if (slope > this.bottomSlope)
                    {
                        this.bottomSlope = slope;
                    }
                }

                if (line.FrontSector.CeilingHeight != line.BackSector.CeilingHeight)
                {
                    var slope = (mc.OpenTop - this.currentShooterZ) / dist;

                    if (slope < this.topSlope)
                    {
                        this.topSlope = slope;
                    }
                }

                if (this.topSlope <= this.bottomSlope)
                {
                    // Stop.
                    return(false);
                }

                // Shot continues.
                return(true);
            }

            // Shoot a thing.
            var thing = intercept.Thing;

            if (thing == this.currentShooter)
            {
                // Can't shoot self.
                return(true);
            }

            {
                if ((thing.Flags & MobjFlags.Shootable) == 0)
                {
                    // Corpse or something.
                    return(true);
                }

                // Check angles to see if the thing can be aimed at.
                var dist          = this.currentRange * intercept.Frac;
                var thingTopSlope = (thing.Z + thing.Height - this.currentShooterZ) / dist;

                if (thingTopSlope < this.bottomSlope)
                {
                    // Shot over the thing.
                    return(true);
                }

                var thingBottomSlope = (thing.Z - this.currentShooterZ) / dist;

                if (thingBottomSlope > this.topSlope)
                {
                    // Shot under the thing.
                    return(true);
                }

                // This thing can be hit!
                if (thingTopSlope > this.topSlope)
                {
                    thingTopSlope = this.topSlope;
                }

                if (thingBottomSlope < this.bottomSlope)
                {
                    thingBottomSlope = this.bottomSlope;
                }

                this.currentAimSlope = (thingTopSlope + thingBottomSlope) / 2;
                this.lineTarget      = thing;

                // Don't go any farther.
                return(false);
            }
        }
예제 #3
0
        /// <summary>
        /// Fire a hitscan bullet along the aiming line.
        /// </summary>
        private bool ShootTraverse(Intercept intercept)
        {
            var mi = this.world.MapInteraction;
            var pt = this.world.PathTraversal;

            if (intercept.Line != null)
            {
                var line = intercept.Line;

                if (line.Special != 0)
                {
                    mi.ShootSpecialLine(this.currentShooter, line);
                }

                if ((line.Flags & LineFlags.TwoSided) == 0)
                {
                    goto hitLine;
                }

                var mc = this.world.MapCollision;

                // Crosses a two sided line.
                mc.LineOpening(line);

                var dist = this.currentRange * intercept.Frac;

                if (line.FrontSector.FloorHeight != line.BackSector.FloorHeight)
                {
                    var slope = (mc.OpenBottom - this.currentShooterZ) / dist;

                    if (slope > this.currentAimSlope)
                    {
                        goto hitLine;
                    }
                }

                if (line.FrontSector.CeilingHeight != line.BackSector.CeilingHeight)
                {
                    var slope = (mc.OpenTop - this.currentShooterZ) / dist;

                    if (slope < this.currentAimSlope)
                    {
                        goto hitLine;
                    }
                }

                // Shot continues.
                return(true);

                // Hit line.
hitLine:

                // Position a bit closer.
                var frac = intercept.Frac - Fixed.FromInt(4) / this.currentRange;
                var x = pt.Trace.X + pt.Trace.Dx * frac;
                var y = pt.Trace.Y + pt.Trace.Dy * frac;
                var z = this.currentShooterZ + this.currentAimSlope * (frac * this.currentRange);

                if (line.FrontSector.CeilingFlat == this.world.Map.SkyFlatNumber)
                {
                    // Don't shoot the sky!
                    if (z > line.FrontSector.CeilingHeight)
                    {
                        return(false);
                    }

                    // It's a sky hack wall.
                    if (line.BackSector != null && line.BackSector.CeilingFlat == this.world.Map.SkyFlatNumber)
                    {
                        return(false);
                    }
                }

                // Spawn bullet puffs.
                this.SpawnPuff(x, y, z);

                // Don't go any farther.
                return(false);
            }

            {
                // Shoot a thing.
                var thing = intercept.Thing;

                if (thing == this.currentShooter)
                {
                    // Can't shoot self.
                    return(true);
                }

                if ((thing.Flags & MobjFlags.Shootable) == 0)
                {
                    // Corpse or something.
                    return(true);
                }

                // Check angles to see if the thing can be aimed at.
                var dist          = this.currentRange * intercept.Frac;
                var thingTopSlope = (thing.Z + thing.Height - this.currentShooterZ) / dist;

                if (thingTopSlope < this.currentAimSlope)
                {
                    // Shot over the thing.
                    return(true);
                }

                var thingBottomSlope = (thing.Z - this.currentShooterZ) / dist;

                if (thingBottomSlope > this.currentAimSlope)
                {
                    // Shot under the thing.
                    return(true);
                }

                // Hit thing.
                // Position a bit closer.
                var frac = intercept.Frac - Fixed.FromInt(10) / this.currentRange;

                var x = pt.Trace.X + pt.Trace.Dx * frac;
                var y = pt.Trace.Y + pt.Trace.Dy * frac;
                var z = this.currentShooterZ + this.currentAimSlope * (frac * this.currentRange);

                // Spawn bullet puffs or blod spots, depending on target type.
                if ((intercept.Thing.Flags & MobjFlags.NoBlood) != 0)
                {
                    this.SpawnPuff(x, y, z);
                }
                else
                {
                    this.SpawnBlood(x, y, z, this.currentDamage);
                }

                if (this.currentDamage != 0)
                {
                    this.world.ThingInteraction.DamageMobj(thing, this.currentShooter, this.currentShooter, this.currentDamage);
                }

                // Don't go any farther.
                return(false);
            }
        }