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