/// <summary> /// Returns true if a straight line between the looker and target is unobstructed. /// </summary> public bool CheckSight(Mobj looker, Mobj target) { var map = world.Map; // First check for trivial rejection. // Check in REJECT table. if (map.Reject.Check(looker.Subsector.Sector, target.Subsector.Sector)) { // Can't possibly be connected. return(false); } // An unobstructed LOS is possible. // Now look from eyes of t1 to any part of t2. sightZStart = looker.Z + looker.Height - (looker.Height >> 2); topSlope = (target.Z + target.Height) - sightZStart; bottomSlope = (target.Z) - sightZStart; trace.X = looker.X; trace.Y = looker.Y; trace.Dx = target.X - looker.X; trace.Dy = target.Y - looker.Y; targetX = target.X; targetY = target.Y; // The head node is the last node output. return(CrossBspNode(map.Nodes.Length - 1, world.GetNewValidCount())); }
private void NoiseAlert(Mobj target, Mobj emmiter) { RecursiveSound( emmiter.Subsector.Sector, 0, target, world.GetNewValidCount()); }
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)); }
/// <summary> /// This is purely informative, nothing is modified /// (except things picked up). /// /// In: /// A Mobj (can be valid or invalid) /// A position to be checked /// (doesn't need to be related to the mobj.X and Y) /// /// During: /// Special things are touched if MobjFlags.PickUp /// Early out on solid lines? /// /// Out: /// New subsector /// CurrentFloorZ /// CurrentCeilingZ /// CurrentDropoffZ /// The lowest point contacted /// (monsters won't move to a dropoff) /// crossedSpecials[] /// crossedSpecialCount /// </summary> public bool CheckPosition(Mobj thing, Fixed x, Fixed y) { var map = world.Map; var bm = map.BlockMap; currentThing = thing; currentFlags = thing.Flags; currentX = x; currentY = y; currentBox[Box.Top] = y + currentThing.Radius; currentBox[Box.Bottom] = y - currentThing.Radius; currentBox[Box.Right] = x + currentThing.Radius; currentBox[Box.Left] = x - currentThing.Radius; var newSubsector = Geometry.PointInSubsector(x, y, map); currentCeilingLine = null; // The base floor / ceiling is from the subsector that contains the point. // Any contacted lines the step closer together will adjust them. currentFloorZ = currentDropoffZ = newSubsector.Sector.FloorHeight; currentCeilingZ = newSubsector.Sector.CeilingHeight; var validCount = world.GetNewValidCount(); crossedSpecialCount = 0; if ((currentFlags & MobjFlags.NoClip) != 0) { return(true); } // Check things first, possibly picking things up. // The bounding box is extended by MaxThingRadius because mobj_ts are grouped into // mapblocks based on their origin point, and can overlap into adjacent blocks by up // to MaxThingRadius units. { var blockX1 = bm.GetBlockX(currentBox[Box.Left] - GameConst.MaxThingRadius); var blockX2 = bm.GetBlockX(currentBox[Box.Right] + GameConst.MaxThingRadius); var blockY1 = bm.GetBlockY(currentBox[Box.Bottom] - GameConst.MaxThingRadius); var blockY2 = bm.GetBlockY(currentBox[Box.Top] + GameConst.MaxThingRadius); for (var bx = blockX1; bx <= blockX2; bx++) { for (var by = blockY1; by <= blockY2; by++) { if (!map.BlockMap.IterateThings(bx, by, checkThingFunc)) { return(false); } } } } // Check lines. { var blockX1 = bm.GetBlockX(currentBox[Box.Left]); var blockX2 = bm.GetBlockX(currentBox[Box.Right]); var blockY1 = bm.GetBlockY(currentBox[Box.Bottom]); var blockY2 = bm.GetBlockY(currentBox[Box.Top]); for (var bx = blockX1; bx <= blockX2; bx++) { for (var by = blockY1; by <= blockY2; by++) { if (!map.BlockMap.IterateLines(bx, by, checkLineFunc, validCount)) { return(false); } } } } return(true); }