示例#1
0
        /// <summary>
        /// Calculate the distance between the two points.
        /// </summary>
        public static Fixed PointToDist(Fixed fromX, Fixed fromY, Fixed toX, Fixed toY)
        {
            var dx = Fixed.Abs(toX - fromX);
            var dy = Fixed.Abs(toY - fromY);

            if (dy > dx)
            {
                var temp = dx;
                dx = dy;
                dy = temp;
            }

            // The code below to avoid division by zero is based on Chocolate Doom's implementation.
            Fixed frac;

            if (dx != Fixed.Zero)
            {
                frac = dy / dx;
            }
            else
            {
                frac = Fixed.Zero;
            }

            var angle = (Trig.TanToAngle((uint)frac.Data >> fracToSlopeShift) + Angle.Ang90);

            // Use as cosine.
            var dist = dx / Trig.Sin(angle);

            return(dist);
        }
示例#2
0
        private bool StompThing(Mobj thing)
        {
            if ((thing.Flags & MobjFlags.Shootable) == 0)
            {
                return(true);
            }

            var blockDist = thing.Radius + currentThing.Radius;
            var dx        = Fixed.Abs(thing.X - currentX);
            var dy        = Fixed.Abs(thing.Y - currentY);

            if (dx >= blockDist || dy >= blockDist)
            {
                // Didn't hit it.
                return(true);
            }

            // Don't clip against self.
            if (thing == currentThing)
            {
                return(true);
            }

            // Monsters don't stomp things except on boss level.
            if (currentThing.Player == null && world.Options.Map != 30)
            {
                return(false);
            }

            world.ThingInteraction.DamageMobj(thing, currentThing, currentThing, 10000);

            return(true);
        }
示例#3
0
        /// <summary>
        /// Gives an estimation of distance (not exact).
        /// </summary>
        public static Fixed AproxDistance(Fixed dx, Fixed dy)
        {
            dx = Fixed.Abs(dx);
            dy = Fixed.Abs(dy);

            if (dx < dy)
            {
                return(dx + dy - (dx >> 1));
            }
            else
            {
                return(dx + dy - (dy >> 1));
            }
        }
示例#4
0
        private bool VileCheck(Mobj thing)
        {
            if ((thing.Flags & MobjFlags.Corpse) == 0)
            {
                // Not a monster.
                return(true);
            }

            if (thing.Tics != -1)
            {
                // Not lying still yet.
                return(true);
            }

            if (thing.Info.Raisestate == MobjState.Null)
            {
                // Monster doesn't have a raise state.
                return(true);
            }

            var maxDist = thing.Info.Radius + DoomInfo.MobjInfos[(int)MobjType.Vile].Radius;

            if (Fixed.Abs(thing.X - vileTryX) > maxDist ||
                Fixed.Abs(thing.Y - vileTryY) > maxDist)
            {
                // Not actually touching.
                return(true);
            }

            vileTargetCorpse          = thing;
            vileTargetCorpse.MomX     = vileTargetCorpse.MomY = Fixed.Zero;
            vileTargetCorpse.Height <<= 2;

            var check = world.ThingMovement.CheckPosition(
                vileTargetCorpse,
                vileTargetCorpse.X,
                vileTargetCorpse.Y);

            vileTargetCorpse.Height >>= 2;

            if (!check)
            {
                // Doesn't fit here.
                return(true);
            }

            // Got one, so stop checking.
            return(false);
        }
        /// <summary>
        /// "bombSource" is the creature that caused the explosion at "bombSpot".
        /// </summary>
        private bool DoRadiusAttack(Mobj thing)
        {
            if ((thing.Flags & MobjFlags.Shootable) == 0)
            {
                return(true);
            }

            // Boss spider and cyborg take no damage from concussion.
            if (thing.Type == MobjType.Cyborg || thing.Type == MobjType.Spider)
            {
                return(true);
            }

            var dx = Fixed.Abs(thing.X - bombSpot.X);
            var dy = Fixed.Abs(thing.Y - bombSpot.Y);

            var dist = dx > dy ? dx : dy;

            dist = new Fixed((dist - thing.Radius).Data >> Fixed.FracBits);

            if (dist < Fixed.Zero)
            {
                dist = Fixed.Zero;
            }

            if (dist.Data >= bombDamage)
            {
                // Out of range.
                return(true);
            }

            if (world.VisibilityCheck.CheckSight(thing, bombSpot))
            {
                // Must be in direct path.
                DamageMobj(thing, bombSpot, bombSource, bombDamage - dist.Data);
            }

            return(true);
        }
示例#6
0
        public bool PathTraverse(Fixed x1, Fixed y1, Fixed x2, Fixed y2, PathTraverseFlags flags, Func <Intercept, bool> trav)
        {
            earlyOut = (flags & PathTraverseFlags.EarlyOut) != 0;

            var validCount = world.GetNewValidCount();

            var bm = world.Map.BlockMap;

            interceptCount = 0;

            if (((x1 - bm.OriginX).Data & (BlockMap.MapBlockSize.Data - 1)) == 0)
            {
                // Don't side exactly on a line.
                x1 += Fixed.One;
            }

            if (((y1 - bm.OriginY).Data & (BlockMap.MapBlockSize.Data - 1)) == 0)
            {
                // Don't side exactly on a line.
                y1 += Fixed.One;
            }

            trace.X  = x1;
            trace.Y  = y1;
            trace.Dx = x2 - x1;
            trace.Dy = y2 - y1;

            x1 -= bm.OriginX;
            y1 -= bm.OriginY;

            var blockX1 = x1.Data >> BlockMap.MapBlockShift;
            var blockY1 = y1.Data >> BlockMap.MapBlockShift;

            x2 -= bm.OriginX;
            y2 -= bm.OriginY;

            var blockX2 = x2.Data >> BlockMap.MapBlockShift;
            var blockY2 = y2.Data >> BlockMap.MapBlockShift;

            Fixed stepX;
            Fixed stepY;

            Fixed partial;

            int blockStepX;
            int blockStepY;

            if (blockX2 > blockX1)
            {
                blockStepX = 1;
                partial    = new Fixed(Fixed.FracUnit - ((x1.Data >> BlockMap.MapBToFrac) & (Fixed.FracUnit - 1)));
                stepY      = (y2 - y1) / Fixed.Abs(x2 - x1);
            }
            else if (blockX2 < blockX1)
            {
                blockStepX = -1;
                partial    = new Fixed((x1.Data >> BlockMap.MapBToFrac) & (Fixed.FracUnit - 1));
                stepY      = (y2 - y1) / Fixed.Abs(x2 - x1);
            }
            else
            {
                blockStepX = 0;
                partial    = Fixed.One;
                stepY      = Fixed.FromInt(256);
            }

            var interceptY = new Fixed(y1.Data >> BlockMap.MapBToFrac) + (partial * stepY);


            if (blockY2 > blockY1)
            {
                blockStepY = 1;
                partial    = new Fixed(Fixed.FracUnit - ((y1.Data >> BlockMap.MapBToFrac) & (Fixed.FracUnit - 1)));
                stepX      = (x2 - x1) / Fixed.Abs(y2 - y1);
            }
            else if (blockY2 < blockY1)
            {
                blockStepY = -1;
                partial    = new Fixed((y1.Data >> BlockMap.MapBToFrac) & (Fixed.FracUnit - 1));
                stepX      = (x2 - x1) / Fixed.Abs(y2 - y1);
            }
            else
            {
                blockStepY = 0;
                partial    = Fixed.One;
                stepX      = Fixed.FromInt(256);
            }

            var interceptX = new Fixed(x1.Data >> BlockMap.MapBToFrac) + (partial * stepX);

            // Step through map blocks.
            // Count is present to prevent a round off error from skipping the break.
            var bx = blockX1;
            var by = blockY1;

            for (var count = 0; count < 64; count++)
            {
                if ((flags & PathTraverseFlags.AddLines) != 0)
                {
                    if (!bm.IterateLines(bx, by, lineInterceptFunc, validCount))
                    {
                        // Early out.
                        return(false);
                    }
                }

                if ((flags & PathTraverseFlags.AddThings) != 0)
                {
                    if (!bm.IterateThings(bx, by, thingInterceptFunc))
                    {
                        // Early out.
                        return(false);
                    }
                }

                if (bx == blockX2 && by == blockY2)
                {
                    break;
                }

                if ((interceptY.ToIntFloor()) == by)
                {
                    interceptY += stepY;
                    bx         += blockStepX;
                }
                else if ((interceptX.ToIntFloor()) == bx)
                {
                    interceptX += stepX;
                    by         += blockStepY;
                }
            }

            // Go through the sorted list.
            return(TraverseIntercepts(trav, Fixed.One));
        }
示例#7
0
        private bool CheckThing(Mobj thing)
        {
            if ((thing.Flags & (MobjFlags.Solid | MobjFlags.Special | MobjFlags.Shootable)) == 0)
            {
                return(true);
            }

            var blockDist = thing.Radius + currentThing.Radius;

            if (Fixed.Abs(thing.X - currentX) >= blockDist ||
                Fixed.Abs(thing.Y - currentY) >= blockDist)
            {
                // Didn't hit it.
                return(true);
            }

            // Don't clip against self.
            if (thing == currentThing)
            {
                return(true);
            }

            // Check for skulls slamming into things.
            if ((currentThing.Flags & MobjFlags.SkullFly) != 0)
            {
                var damage = ((world.Random.Next() % 8) + 1) * currentThing.Info.Damage;

                world.ThingInteraction.DamageMobj(thing, currentThing, currentThing, damage);

                currentThing.Flags &= ~MobjFlags.SkullFly;
                currentThing.MomX   = currentThing.MomY = currentThing.MomZ = Fixed.Zero;

                currentThing.SetState(currentThing.Info.SpawnState);

                // Stop moving.
                return(false);
            }

            // Missiles can hit other things.
            if ((currentThing.Flags & MobjFlags.Missile) != 0)
            {
                // See if it went over / under.
                if (currentThing.Z > thing.Z + thing.Height)
                {
                    // Overhead.
                    return(true);
                }

                if (currentThing.Z + currentThing.Height < thing.Z)
                {
                    // Underneath.
                    return(true);
                }

                if (currentThing.Target != null &&
                    (currentThing.Target.Type == thing.Type
                     //(||
                     //(currentThing.Target.Type == MobjType.Knight && thing.Type == MobjType.Bruiser) ||
                     //(currentThing.Target.Type == MobjType.Bruiser && thing.Type == MobjType.Knight))
                    ))
                {
                    // Don't hit same species as originator.
                    if (thing == currentThing.Target)
                    {
                        return(true);
                    }

                    if (thing.Type != MobjType.Player && !DoomInfo.DeHackEdConst.MonstersInfight)
                    {
                        // Explode, but do no damage.
                        // Let players missile other players.
                        return(false);
                    }
                }

                if ((thing.Flags & MobjFlags.Shootable) == 0)
                {
                    // Didn't do any damage.
                    return((thing.Flags & MobjFlags.Solid) == 0);
                }

                // Damage / explode.
                var damage = ((world.Random.Next() % 8) + 1) * currentThing.Info.Damage;
                world.ThingInteraction.DamageMobj(thing, currentThing, currentThing.Target, damage);

                // Don't traverse any more.
                return(false);
            }

            // Check for special pickup.
            if ((thing.Flags & MobjFlags.Special) != 0)
            {
                var solid = (thing.Flags & MobjFlags.Solid) != 0;
                if ((currentFlags & MobjFlags.PickUp) != 0)
                {
                    // Can remove thing.
                    world.ItemPickup.TouchSpecialThing(thing, currentThing);
                }
                return(!solid);
            }

            return((thing.Flags & MobjFlags.Solid) == 0);
        }
示例#8
0
        private void NewChaseDir(Mobj actor)
        {
            if (actor.Target == null)
            {
                throw new Exception("Called with no target.");
            }

            var oldDir     = actor.MoveDir;
            var turnAround = opposite[(int)oldDir];

            var deltaX = actor.Target.X - actor.X;
            var deltaY = actor.Target.Y - actor.Y;

            if (deltaX > Fixed.FromInt(10))
            {
                choices[1] = Direction.East;
            }
            else if (deltaX < Fixed.FromInt(-10))
            {
                choices[1] = Direction.west;
            }
            else
            {
                choices[1] = Direction.None;
            }

            if (deltaY < Fixed.FromInt(-10))
            {
                choices[2] = Direction.South;
            }
            else if (deltaY > Fixed.FromInt(10))
            {
                choices[2] = Direction.North;
            }
            else
            {
                choices[2] = Direction.None;
            }

            // Try direct route.
            if (choices[1] != Direction.None && choices[2] != Direction.None)
            {
                var a = (deltaY < Fixed.Zero) ? 1 : 0;
                var b = (deltaX > Fixed.Zero) ? 1 : 0;
                actor.MoveDir = diags[(a << 1) + b];

                if (actor.MoveDir != turnAround && TryWalk(actor))
                {
                    return;
                }
            }

            // Try other directions.
            if (world.Random.Next() > 200 || Fixed.Abs(deltaY) > Fixed.Abs(deltaX))
            {
                var temp = choices[1];
                choices[1] = choices[2];
                choices[2] = temp;
            }

            if (choices[1] == turnAround)
            {
                choices[1] = Direction.None;
            }

            if (choices[2] == turnAround)
            {
                choices[2] = Direction.None;
            }

            if (choices[1] != Direction.None)
            {
                actor.MoveDir = choices[1];

                if (TryWalk(actor))
                {
                    // Either moved forward or attacked.
                    return;
                }
            }

            if (choices[2] != Direction.None)
            {
                actor.MoveDir = choices[2];

                if (TryWalk(actor))
                {
                    return;
                }
            }

            // There is no direct path to the player, so pick another direction.
            if (oldDir != Direction.None)
            {
                actor.MoveDir = oldDir;

                if (TryWalk(actor))
                {
                    return;
                }
            }

            // Randomly determine direction of search.
            if ((world.Random.Next() & 1) != 0)
            {
                for (var dir = (int)Direction.East; dir <= (int)Direction.Southeast; dir++)
                {
                    if ((Direction)dir != turnAround)
                    {
                        actor.MoveDir = (Direction)dir;

                        if (TryWalk(actor))
                        {
                            return;
                        }
                    }
                }
            }
            else
            {
                for (var dir = (int)Direction.Southeast; dir != ((int)Direction.East - 1); dir--)
                {
                    if ((Direction)dir != turnAround)
                    {
                        actor.MoveDir = (Direction)dir;

                        if (TryWalk(actor))
                        {
                            return;
                        }
                    }
                }
            }

            if (turnAround != Direction.None)
            {
                actor.MoveDir = turnAround;

                if (TryWalk(actor))
                {
                    return;
                }
            }

            // Can not move.
            actor.MoveDir = Direction.None;
        }