public FloorType HitFloor(Mobj thing) { if (thing.FloorZ != thing.Subsector.Sector.FloorHeight) { // don't splash if landing on the edge above water return(FloorType.Solid); } switch (world.ThingAllocation.GetThingFloorType(thing)) { case FloorType.Water: world.ThingAllocation.SpawnMobj(thing.X, thing.Y, Mobj.OnFloorZ, MobjType.SplashBase); var mo = world.ThingAllocation.SpawnMobj(thing.X, thing.Y, Mobj.OnFloorZ, MobjType.Splash); mo.Target = thing; mo.MomX = Fixed.FromInt((world.Random.Next() - world.Random.Next()) << 8); mo.MomY = Fixed.FromInt((world.Random.Next() - world.Random.Next()) << 8); mo.MomZ = Fixed.FromInt(2) * Fixed.One + (Fixed.FromInt(world.Random.Next()) << 8); world.StartSound(thing, Sfx.GLOOP, SfxType.Misc); return(FloorType.Water); case FloorType.Lava: break; case FloorType.Sludge: break; } return(FloorType.Solid); }
private static int UnArchiveLine(LineDef line, byte[] data, int p) { line.Flags = (LineFlags)BitConverter.ToInt16(data, p); line.Special = (LineSpecial)BitConverter.ToInt16(data, p + 2); line.Tag = BitConverter.ToInt16(data, p + 4); p += 6; if (line.FrontSide != null) { var side = line.FrontSide; side.TextureOffset = Fixed.FromInt(BitConverter.ToInt16(data, p)); side.RowOffset = Fixed.FromInt(BitConverter.ToInt16(data, p + 2)); side.TopTexture = BitConverter.ToInt16(data, p + 4); side.BottomTexture = BitConverter.ToInt16(data, p + 6); side.MiddleTexture = BitConverter.ToInt16(data, p + 8); p += 10; } if (line.BackSide != null) { var side = line.BackSide; side.TextureOffset = Fixed.FromInt(BitConverter.ToInt16(data, p)); side.RowOffset = Fixed.FromInt(BitConverter.ToInt16(data, p + 2)); side.TopTexture = BitConverter.ToInt16(data, p + 4); side.BottomTexture = BitConverter.ToInt16(data, p + 6); side.MiddleTexture = BitConverter.ToInt16(data, p + 8); p += 10; } return(p); }
/// <summary> /// Find a target on the aiming line. /// Sets LineTaget when a target is aimed at. /// </summary> public Fixed AimLineAttack(Mobj shooter, Angle angle, Fixed range) { currentShooter = shooter; currentShooterZ = shooter.Z + (shooter.Height >> 1) + Fixed.FromInt(8); currentRange = range; var targetX = shooter.X + range.ToIntFloor() * Trig.Cos(angle); var targetY = shooter.Y + range.ToIntFloor() * Trig.Sin(angle); // Can't shoot outside view angles. topSlope = Fixed.FromInt(100) / 160; bottomSlope = Fixed.FromInt(-100) / 160; lineTarget = null; world.PathTraversal.PathTraverse( shooter.X, shooter.Y, targetX, targetY, PathTraverseFlags.AddLines | PathTraverseFlags.AddThings, aimTraverseFunc); if (lineTarget != null) { return(currentAimSlope); } return(Fixed.Zero); }
public static BlockMap FromWad(Wad wad, int lump, LineDef[] lines) { var data = wad.ReadLump(lump); var table = new short[data.Length / 2]; for (var i = 0; i < table.Length; i++) { var offset = 2 * i; table[i] = BitConverter.ToInt16(data, offset); } var originX = Fixed.FromInt(table[0]); var originY = Fixed.FromInt(table[1]); var width = table[2]; var height = table[3]; return(new BlockMap( originX, originY, width, height, table, lines)); }
/// <summary> /// Spawn blood. /// </summary> public void SpawnBlood(Fixed x, Fixed y, Fixed z, int damage) { var random = world.Random; z += new Fixed((random.Next() - random.Next()) << 10); var thing = world.ThingAllocation.SpawnMobj(x, y, z, MobjType.Blood); thing.MomZ = Fixed.FromInt(2); thing.Tics -= random.Next() & 3; if (thing.Tics < 1) { thing.Tics = 1; } if (damage <= 12 && damage >= 9) { thing.SetState(MobjState.Blood2); } else if (damage < 9) { thing.SetState(MobjState.Blood3); } }
public static Vertex FromData(byte[] data, int offset) { var x = BitConverter.ToInt16(data, offset); var y = BitConverter.ToInt16(data, offset + 2); return(new Vertex(Fixed.FromInt(x), Fixed.FromInt(y))); }
public static Node FromData(byte[] data, int offset) { var x = BitConverter.ToInt16(data, offset); var y = BitConverter.ToInt16(data, offset + 2); var dx = BitConverter.ToInt16(data, offset + 4); var dy = BitConverter.ToInt16(data, offset + 6); var frontBoundingBoxTop = BitConverter.ToInt16(data, offset + 8); var frontBoundingBoxBottom = BitConverter.ToInt16(data, offset + 10); var frontBoundingBoxLeft = BitConverter.ToInt16(data, offset + 12); var frontBoundingBoxRight = BitConverter.ToInt16(data, offset + 14); var backBoundingBoxTop = BitConverter.ToInt16(data, offset + 16); var backBoundingBoxBottom = BitConverter.ToInt16(data, offset + 18); var backBoundingBoxLeft = BitConverter.ToInt16(data, offset + 20); var backBoundingBoxRight = BitConverter.ToInt16(data, offset + 22); var frontChild = BitConverter.ToInt16(data, offset + 24); var backChild = BitConverter.ToInt16(data, offset + 26); return(new Node( Fixed.FromInt(x), Fixed.FromInt(y), Fixed.FromInt(dx), Fixed.FromInt(dy), Fixed.FromInt(frontBoundingBoxTop), Fixed.FromInt(frontBoundingBoxBottom), Fixed.FromInt(frontBoundingBoxLeft), Fixed.FromInt(frontBoundingBoxRight), Fixed.FromInt(backBoundingBoxTop), Fixed.FromInt(backBoundingBoxBottom), Fixed.FromInt(backBoundingBoxLeft), Fixed.FromInt(backBoundingBoxRight), frontChild, backChild)); }
public void Fire(Mobj actor) { var dest = actor.Tracer; if (dest == null) { return; } // Don't move it if the vile lost sight. if (!world.VisibilityCheck.CheckSight(actor.Target, dest)) { return; } world.ThingMovement.UnsetThingPosition(actor); var angle = dest.Angle; actor.X = dest.X + Fixed.FromInt(24) * Trig.Cos(angle); actor.Y = dest.Y + Fixed.FromInt(24) * Trig.Sin(angle); actor.Z = dest.Z; world.ThingMovement.SetThingPosition(actor); }
public void VileAttack(Mobj actor) { if (actor.Target == null) { return; } FaceTarget(actor); if (!world.VisibilityCheck.CheckSight(actor, actor.Target)) { return; } world.StartSound(actor, Sfx.BAREXP); world.ThingInteraction.DamageMobj(actor.Target, actor, actor, 20); actor.Target.MomZ = Fixed.FromInt(1000) / actor.Target.Info.Mass; var fire = actor.Tracer; if (fire == null) { return; } var angle = actor.Angle; // Move the fire between the vile and the player. fire.X = actor.Target.X - Fixed.FromInt(24) * Trig.Cos(angle); fire.Y = actor.Target.Y - Fixed.FromInt(24) * Trig.Sin(angle); world.ThingInteraction.RadiusAttack(fire, actor, 70); }
private bool SlideTraverse(Intercept intercept) { var mc = world.MapCollision; if (intercept.Line == null) { throw new Exception("ThingMovement.SlideTraverse: Not a line?"); } var line = intercept.Line; if ((line.Flags & LineFlags.TwoSided) == 0) { if (Geometry.PointOnLineSide(slideThing.X, slideThing.Y, line) != 0) { // Don't hit the back side. return(true); } goto isBlocking; } // Set openrange, opentop, openbottom. mc.LineOpening(line); if (mc.OpenRange < slideThing.Height) { // Doesn't fit. goto isBlocking; } if (mc.OpenTop - slideThing.Z < slideThing.Height) { // Mobj is too high. goto isBlocking; } if (mc.OpenBottom - slideThing.Z > Fixed.FromInt(24)) { // Too big a step up. goto isBlocking; } // This line doesn't block movement. return(true); // The line does block movement, see if it is closer than best so far. isBlocking: if (intercept.Frac < bestSlideFrac) { secondSlideFrac = bestSlideFrac; secondSlideLine = bestSlideLine; bestSlideFrac = intercept.Frac; bestSlideLine = line; } // Stop. return(false); }
/// <summary> /// Fall on your face when dying. /// Decrease POV height to floor height. /// </summary> private void DeathThink(Player player) { MovePlayerSprites(player); // Fall to the ground. if (player.ViewHeight > Fixed.FromInt(6)) { player.ViewHeight -= Fixed.One; } if (player.ViewHeight < Fixed.FromInt(6)) { player.ViewHeight = Fixed.FromInt(6); } player.DeltaViewHeight = Fixed.Zero; onGround = (player.Mobj.Z <= player.Mobj.FloorZ); CalcHeight(player); if (player.Attacker != null && player.Attacker != player.Mobj) { var angle = Geometry.PointToAngle( player.Mobj.X, player.Mobj.Y, player.Attacker.X, player.Attacker.Y); var delta = angle - player.Mobj.Angle; if (delta < ang5 || delta.Data > (-ang5).Data) { // Looking at killer, so fade damage flash down. player.Mobj.Angle = angle; if (player.DamageCount > 0) { player.DamageCount--; } } else if (delta < Angle.Ang180) { player.Mobj.Angle += ang5; } else { player.Mobj.Angle -= ang5; } } else if (player.DamageCount > 0) { player.DamageCount--; } if ((player.Cmd.Buttons & TicCmdButtons.Use) != 0) { player.PlayerState = PlayerState.Reborn; } }
private bool AddLineIntercepts(LineDef line) { int s1; int s2; // Avoid precision problems with two routines. if (trace.Dx > Fixed.FromInt(16) || trace.Dy > Fixed.FromInt(16) || trace.Dx < -Fixed.FromInt(16) || trace.Dy < -Fixed.FromInt(16)) { s1 = Geometry.PointOnDivLineSide(line.Vertex1.X, line.Vertex1.Y, trace); s2 = Geometry.PointOnDivLineSide(line.Vertex2.X, line.Vertex2.Y, trace); } else { s1 = Geometry.PointOnLineSide(trace.X, trace.Y, line); s2 = Geometry.PointOnLineSide(trace.X + trace.Dx, trace.Y + trace.Dy, line); } if (s1 == s2) { // Line isn't crossed. return(true); } // Hit the line. target.MakeFrom(line); var frac = InterceptVector(trace, target); if (frac < Fixed.Zero) { // Behind source. return(true); } // Try to early out the check. if (earlyOut && frac < Fixed.One && line.BackSector == null) { // Stop checking. return(false); } intercepts[interceptCount].Frac = frac; intercepts[interceptCount].Line = line; intercepts[interceptCount].Thing = null; interceptCount++; // Continue. return(true); }
private static int UnArchiveSector(Sector sector, byte[] data, int p) { sector.FloorHeight = Fixed.FromInt(BitConverter.ToInt16(data, p)); sector.CeilingHeight = Fixed.FromInt(BitConverter.ToInt16(data, p + 2)); sector.FloorFlat = BitConverter.ToInt16(data, p + 4); sector.CeilingFlat = BitConverter.ToInt16(data, p + 6); sector.LightLevel = BitConverter.ToInt16(data, p + 8); sector.Special = (SectorSpecial)BitConverter.ToInt16(data, p + 10); sector.Tag = BitConverter.ToInt16(data, p + 12); sector.SpecialData = null; sector.SoundTarget = null; return(p + 14); }
public Mobj SpawnMissile(Mobj source, Mobj dest, MobjType type) { var missile = SpawnMobj( source.X, source.Y, source.Z + Fixed.FromInt(32), type); if (missile.Info.SeeSound != 0) { world.StartSound(missile, missile.Info.SeeSound); } // 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 = world.Random; angle += new Angle((random.Next() - random.Next()) << 20); } var speed = 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); CheckMissileSpawn(missile); return(missile); }
public static MapThing FromData(byte[] data, int offset) { var x = BitConverter.ToInt16(data, offset); var y = BitConverter.ToInt16(data, offset + 2); var angle = BitConverter.ToInt16(data, offset + 4); var type = BitConverter.ToInt16(data, offset + 6); var flags = BitConverter.ToInt16(data, offset + 8); return(new MapThing( Fixed.FromInt(x), Fixed.FromInt(y), new Angle(ManagedDoom.Angle.Ang45.Data * (uint)(angle / 45)), type, (ThingFlags)flags)); }
public static SideDef FromData(byte[] data, int offset, TextureLookup textures, Sector[] sectors) { var textureOffset = BitConverter.ToInt16(data, offset); var rowOffset = BitConverter.ToInt16(data, offset + 2); var topTextureName = DoomInterop.ToString(data, offset + 4, 8); var bottomTextureName = DoomInterop.ToString(data, offset + 12, 8); var middleTextureName = DoomInterop.ToString(data, offset + 20, 8); var sectorNum = BitConverter.ToInt16(data, offset + 28); return(new SideDef( Fixed.FromInt(textureOffset), Fixed.FromInt(rowOffset), textures.GetNumber(topTextureName), textures.GetNumber(bottomTextureName), textures.GetNumber(middleTextureName), sectorNum != -1 ? sectors[sectorNum] : null)); }
/// <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) { currentShooter = shooter; currentShooterZ = shooter.Z + (shooter.Height >> 1) + Fixed.FromInt(8); currentRange = range; currentAimSlope = slope; currentDamage = damage; var targetX = shooter.X + range.ToIntFloor() * Trig.Cos(angle); var targetY = shooter.Y + range.ToIntFloor() * Trig.Sin(angle); world.PathTraversal.PathTraverse( shooter.X, shooter.Y, targetX, targetY, PathTraverseFlags.AddLines | PathTraverseFlags.AddThings, shootTraverseFunc); }
public void SpawnPlayerMissile(Mobj source, MobjType type) { var hs = 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 = SpawnMobj(x, y, z, type); if (missile.Info.SeeSound != 0) { world.StartSound(missile, missile.Info.SeeSound); } 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; CheckMissileSpawn(missile); }
public void PainShootSkull(Mobj actor, Angle angle) { // Count total number of skull currently on the level. var count = 0; foreach (var thinker in world.Thinkers) { var mobj = thinker as Mobj; if (mobj != null && mobj.Type == MobjType.Skull) { count++; } } // If there are allready 20 skulls on the level, // don't spit another one. if (count > 20) { return; } // Okay, there's playe for another one. var preStep = Fixed.FromInt(4) + 3 * (actor.Info.Radius + DoomInfo.MobjInfos[(int)MobjType.Skull].Radius) / 2; var x = actor.X + preStep * Trig.Cos(angle); var y = actor.Y + preStep * Trig.Sin(angle); var z = actor.Z + Fixed.FromInt(8); var skull = world.ThingAllocation.SpawnMobj(x, y, z, MobjType.Skull); // Check for movements. if (!world.ThingMovement.TryMove(skull, skull.X, skull.Y)) { // Kill it immediately. world.ThingInteraction.DamageMobj(skull, actor, actor, 10000); return; } skull.Target = actor.Target; SkullAttack(skull); }
private void BulletSlope(Mobj mo) { var hs = world.Hitscan; // See which target is to be aimed at. var angle = mo.Angle; currentBulletSlope = hs.AimLineAttack(mo, angle, Fixed.FromInt(1024)); if (hs.LineTarget == null) { angle += new Angle(1 << 26); currentBulletSlope = hs.AimLineAttack(mo, angle, Fixed.FromInt(1024)); if (hs.LineTarget == null) { angle -= new Angle(2 << 26); currentBulletSlope = hs.AimLineAttack(mo, angle, Fixed.FromInt(1024)); } } }
public static Sector FromData(byte[] data, int offset, int number, FlatLookup flats) { var floorHeight = BitConverter.ToInt16(data, offset); var ceilingHeight = BitConverter.ToInt16(data, offset + 2); var floorFlatName = DoomInterop.ToString(data, offset + 4, 8); var ceilingFlatName = DoomInterop.ToString(data, offset + 12, 8); var lightLevel = BitConverter.ToInt16(data, offset + 20); var special = BitConverter.ToInt16(data, offset + 22); var tag = BitConverter.ToInt16(data, offset + 24); return(new Sector( number, Fixed.FromInt(floorHeight), Fixed.FromInt(ceilingHeight), flats.GetNumber(floorFlatName), flats.GetNumber(ceilingFlatName), lightLevel, (SectorSpecial)special, tag)); }
public void SkelMissile(Mobj actor) { if (actor.Target == null) { return; } FaceTarget(actor); // Missile spawns higher. actor.Z += Fixed.FromInt(16); var missile = world.ThingAllocation.SpawnMissile(actor, actor.Target, MobjType.Tracer); // Back to normal. actor.Z -= Fixed.FromInt(16); missile.X += missile.MomX; missile.Y += missile.MomY; missile.Tracer = actor.Target; }
/// <summary> /// Change the player's weapon sprite. /// </summary> public void SetPlayerSprite(Player player, PlayerSprite position, MobjState state) { var psp = player.PlayerSprites[(int)position]; do { if (state == MobjState.Null) { // Object removed itself. psp.State = null; break; } var stateDef = DoomInfo.States[(int)state]; psp.State = stateDef; psp.Tics = stateDef.Tics; // Could be 0. if (stateDef.Misc1 != 0) { // Coordinate set. psp.Sx = Fixed.FromInt(stateDef.Misc1); psp.Sy = Fixed.FromInt(stateDef.Misc2); } // Call action routine. // Modified handling. if (stateDef.PlayerAction != null) { stateDef.PlayerAction(world, player, psp); if (psp.State == null) { break; } } state = psp.State.Next; } while (psp.Tics == 0); // An initial state of 0 could cycle through. }
public static Seg FromData(byte[] data, int offset, Vertex[] vertices, LineDef[] lines) { var vertex1Number = BitConverter.ToInt16(data, offset); var vertex2Number = BitConverter.ToInt16(data, offset + 2); var angle = BitConverter.ToInt16(data, offset + 4); var lineNumber = BitConverter.ToInt16(data, offset + 6); var side = BitConverter.ToInt16(data, offset + 8); var segOffset = BitConverter.ToInt16(data, offset + 10); var lineDef = lines[lineNumber]; var frontSide = side == 0 ? lineDef.Side0 : lineDef.Side1; var backSide = side == 0 ? lineDef.Side1 : lineDef.Side0; return(new Seg( vertices[vertex1Number], vertices[vertex2Number], Fixed.FromInt(segOffset), new Angle((uint)angle << 16), frontSide, lineDef, frontSide.Sector, (lineDef.Flags & LineFlags.TwoSided) != 0 ? backSide?.Sector : null)); }
private bool CheckMeleeRange(Mobj actor) { if (actor.Target == null) { return(false); } var target = actor.Target; var dist = Geometry.AproxDistance(target.X - actor.X, target.Y - actor.Y); if (dist >= World.MELEERANGE - Fixed.FromInt(20) + target.Info.Radius) { return(false); } if (!world.VisibilityCheck.CheckSight(actor, actor.Target)) { return(false); } return(true); }
/// <summary> /// Source is the creature that caused the explosion at spot. /// </summary> public void RadiusAttack(Mobj spot, Mobj source, int damage) { var bm = world.Map.BlockMap; var dist = Fixed.FromInt(damage + GameConst.MaxThingRadius.Data); var blockY1 = bm.GetBlockY(spot.Y - dist); var blockY2 = bm.GetBlockY(spot.Y + dist); var blockX1 = bm.GetBlockX(spot.X - dist); var blockX2 = bm.GetBlockX(spot.X + dist); bombSpot = spot; bombSource = source; bombDamage = damage; for (var by = blockY1; by <= blockY2; by++) { for (var bx = blockX1; bx <= blockX2; bx++) { bm.IterateThings(bx, by, radiusAttackFunc); } } }
public void BFGSpray(Mobj bfgBall) { var hs = world.Hitscan; var random = world.Random; // Offset angles from its attack angle. for (var i = 0; i < 40; i++) { var an = bfgBall.Angle - Angle.Ang90 / 2 + Angle.Ang90 / 40 * (uint)i; // bfgBall.Target is the originator (player) of the missile. hs.AimLineAttack(bfgBall.Target, an, Fixed.FromInt(16 * 64)); if (hs.LineTarget == null) { continue; } //* world.ThingAllocation.SpawnMobj( // hs.LineTarget.X, // hs.LineTarget.Y, // hs.LineTarget.Z + (hs.LineTarget.Height >> 2), // MobjType.Extrabfg); var damage = 0; for (var j = 0; j < 15; j++) { damage += (random.Next() & 7) + 1; } world.ThingInteraction.DamageMobj( hs.LineTarget, bfgBall.Target, bfgBall.Target, damage); } }
public static Node FromData(byte[] data, int offset) { var x = BitConverter.ToInt16(data, offset); var y = BitConverter.ToInt16(data, offset + 2); var dx = BitConverter.ToInt16(data, offset + 4); var dy = BitConverter.ToInt16(data, offset + 6); var bbox0Top = BitConverter.ToInt16(data, offset + 8); var bbox0Bottom = BitConverter.ToInt16(data, offset + 10); var bbox0Left = BitConverter.ToInt16(data, offset + 12); var bbox0Right = BitConverter.ToInt16(data, offset + 14); var bbox1Top = BitConverter.ToInt16(data, offset + 16); var bbox1Bottom = BitConverter.ToInt16(data, offset + 18); var bbox1Left = BitConverter.ToInt16(data, offset + 20); var bbox1Right = BitConverter.ToInt16(data, offset + 22); var children0 = BitConverter.ToInt16(data, offset + 24); var children1 = BitConverter.ToInt16(data, offset + 26); return(new Node( Fixed.FromInt(x), Fixed.FromInt(y), Fixed.FromInt(dx), Fixed.FromInt(dy), Fixed.FromInt(bbox0Top), Fixed.FromInt(bbox0Bottom), Fixed.FromInt(bbox0Left), Fixed.FromInt(bbox0Right), Fixed.FromInt(bbox1Top), Fixed.FromInt(bbox1Bottom), Fixed.FromInt(bbox1Left), Fixed.FromInt(bbox1Right), children0, children1)); }
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> /// Check for item pickup. /// </summary> public void TouchSpecialThing(Mobj special, Mobj toucher) { var delta = special.Z - toucher.Z; if (delta > toucher.Height || delta < Fixed.FromInt(-8)) { // Out of reach. return; } var sound = Sfx.ITEMUP; var player = toucher.Player; // Dead thing touching. // Can happen with a sliding player corpse. if (toucher.Health <= 0) { return; } // Identify by sprite. switch (special.Sprite) { // Armor. //* case Sprite.ARM1: // if (!GiveArmor(player, DoomInfo.DeHackEdConst.GreenArmorClass)) // { // return; // } // player.SendMessage(DoomInfo.Strings.GOTARMOR); // break; // case Sprite.ARM2: // if (!GiveArmor(player, DoomInfo.DeHackEdConst.BlueArmorClass)) // { // return; // } // player.SendMessage(DoomInfo.Strings.GOTMEGA); // break; // // Bonus items. // case Sprite.BON1: // // Can go over 100%. // player.Health++; // if (player.Health > DoomInfo.DeHackEdConst.MaxHealth) // { // player.Health = DoomInfo.DeHackEdConst.MaxHealth; // } // player.Mobj.Health = player.Health; // player.SendMessage(DoomInfo.Strings.GOTHTHBONUS); // break; // case Sprite.BON2: // // Can go over 100%. // player.ArmorPoints++; // if (player.ArmorPoints > DoomInfo.DeHackEdConst.MaxArmor) // { // player.ArmorPoints = DoomInfo.DeHackEdConst.MaxArmor; // } // if (player.ArmorType == 0) // { // player.ArmorType = DoomInfo.DeHackEdConst.GreenArmorClass; // } // player.SendMessage(DoomInfo.Strings.GOTARMBONUS); // break; // case Sprite.SOUL: // player.Health += DoomInfo.DeHackEdConst.SoulsphereHealth; // if (player.Health > DoomInfo.DeHackEdConst.MaxSoulsphere) // { // player.Health = DoomInfo.DeHackEdConst.MaxSoulsphere; // } // player.Mobj.Health = player.Health; // player.SendMessage(DoomInfo.Strings.GOTSUPER); // sound = Sfx.GETPOW; // break; // case Sprite.MEGA: // if (world.Options.GameMode != GameMode.Commercial) // { // return; // } // player.Health = DoomInfo.DeHackEdConst.MegasphereHealth; // player.Mobj.Health = player.Health; // GiveArmor(player, DoomInfo.DeHackEdConst.BlueArmorClass); // player.SendMessage(DoomInfo.Strings.GOTMSPHERE); // sound = Sfx.GETPOW; // break; // // Cards. // // Leave cards for everyone. // case Sprite.BKEY: // if (!player.Cards[(int)CardType.BlueCard]) // { // player.SendMessage(DoomInfo.Strings.GOTBLUECARD); // } // GiveCard(player, CardType.BlueCard); // if (!world.Options.NetGame) // { // break; // } // return; case Sprite.CKYY: if (!player.Cards[(int)CardType.YellowCard]) { player.SendMessage(DoomInfo.Strings.GOTYELWCARD); } GiveCard(player, CardType.YellowCard); if (!world.Options.NetGame) { break; } return; // case Sprite.RKEY: // if (!player.Cards[(int)CardType.RedCard]) // { // player.SendMessage(DoomInfo.Strings.GOTREDCARD); // } // GiveCard(player, CardType.RedCard); // if (!world.Options.NetGame) // { // break; // } // return; // case Sprite.BSKU: // if (!player.Cards[(int)CardType.BlueSkull]) // { // player.SendMessage(DoomInfo.Strings.GOTBLUESKUL); // } // GiveCard(player, CardType.BlueSkull); // if (!world.Options.NetGame) // { // break; // } // return; // case Sprite.YSKU: // if (!player.Cards[(int)CardType.YellowSkull]) // { // player.SendMessage(DoomInfo.Strings.GOTYELWSKUL); // } // GiveCard(player, CardType.YellowSkull); // if (!world.Options.NetGame) // { // break; // } // return; // case Sprite.RSKU: // if (!player.Cards[(int)CardType.RedSkull]) // { // player.SendMessage(DoomInfo.Strings.GOTREDSKULL); // } // GiveCard(player, CardType.RedSkull); // if (!world.Options.NetGame) // { // break; // } // return; // // Medikits, heals. // case Sprite.STIM: // if (!GiveHealth(player, 10)) // { // return; // } // player.SendMessage(DoomInfo.Strings.GOTSTIM); // break; // case Sprite.MEDI: // if (!GiveHealth(player, 25)) // { // return; // } // if (player.Health < 25) // { // player.SendMessage(DoomInfo.Strings.GOTMEDINEED); // } // else // { // player.SendMessage(DoomInfo.Strings.GOTMEDIKIT); // } // break; // // Power ups. // case Sprite.PINV: // if (!GivePower(player, PowerType.Invulnerability)) // { // return; // } // player.SendMessage(DoomInfo.Strings.GOTINVUL); // sound = Sfx.GETPOW; // break; // case Sprite.PSTR: // if (!GivePower(player, PowerType.Strength)) // { // return; // } // player.SendMessage(DoomInfo.Strings.GOTBERSERK); // if (player.ReadyWeapon != WeaponType.Fist) // { // player.PendingWeapon = WeaponType.Fist; // } // sound = Sfx.GETPOW; // break; // case Sprite.PINS: // if (!GivePower(player, PowerType.Invisibility)) // { // return; // } // player.SendMessage(DoomInfo.Strings.GOTINVIS); // sound = Sfx.GETPOW; // break; // case Sprite.SUIT: // if (!GivePower(player, PowerType.IronFeet)) // { // return; // } // player.SendMessage(DoomInfo.Strings.GOTSUIT); // sound = Sfx.GETPOW; // break; // case Sprite.PMAP: // if (!GivePower(player, PowerType.AllMap)) // { // return; // } // player.SendMessage(DoomInfo.Strings.GOTMAP); // sound = Sfx.GETPOW; // break; // case Sprite.PVIS: // if (!GivePower(player, PowerType.Infrared)) // { // return; // } // player.SendMessage(DoomInfo.Strings.GOTVISOR); // sound = Sfx.GETPOW; // break; // // Ammo. // case Sprite.CLIP: // if ((special.Flags & MobjFlags.Dropped) != 0) // { // if (!GiveAmmo(player, AmmoType.Clip, 0)) // { // return; // } // } // else // { // if (!GiveAmmo(player, AmmoType.Clip, 1)) // { // return; // } // } // player.SendMessage(DoomInfo.Strings.GOTCLIP); // break; // case Sprite.AMMO: // if (!GiveAmmo(player, AmmoType.Clip, 5)) // { // return; // } // player.SendMessage(DoomInfo.Strings.GOTCLIPBOX); // break; // case Sprite.ROCK: // if (!GiveAmmo(player, AmmoType.Missile, 1)) // { // return; // } // player.SendMessage(DoomInfo.Strings.GOTROCKET); // break; // case Sprite.BROK: // if (!GiveAmmo(player, AmmoType.Missile, 5)) // { // return; // } // player.SendMessage(DoomInfo.Strings.GOTROCKBOX); // break; // case Sprite.CELL: // if (!GiveAmmo(player, AmmoType.Cell, 1)) // { // return; // } // player.SendMessage(DoomInfo.Strings.GOTCELL); // break; // case Sprite.CELP: // if (!GiveAmmo(player, AmmoType.Cell, 5)) // { // return; // } // player.SendMessage(DoomInfo.Strings.GOTCELLBOX); // break; // case Sprite.SHEL: // if (!GiveAmmo(player, AmmoType.Shell, 1)) // { // return; // } // player.SendMessage(DoomInfo.Strings.GOTSHELLS); // break; // case Sprite.SBOX: // if (!GiveAmmo(player, AmmoType.Shell, 5)) // { // return; // } // player.SendMessage(DoomInfo.Strings.GOTSHELLBOX); // break; // case Sprite.BPAK: // if (!player.Backpack) // { // for (var i = 0; i < (int)AmmoType.Count; i++) // { // player.MaxAmmo[i] *= 2; // } // player.Backpack = true; // } // for (var i = 0; i < (int)AmmoType.Count; i++) // { // GiveAmmo(player, (AmmoType)i, 1); // } // player.SendMessage(DoomInfo.Strings.GOTBACKPACK); // break; // // Weapons. // case Sprite.BFUG: // if (!GiveWeapon(player, WeaponType.Bfg, false)) // { // return; // } // player.SendMessage(DoomInfo.Strings.GOTBFG9000); // sound = Sfx.WPNUP; // break; // case Sprite.MGUN: // if (!GiveWeapon(player, WeaponType.Chaingun, (special.Flags & MobjFlags.Dropped) != 0)) // { // return; // } // player.SendMessage(DoomInfo.Strings.GOTCHAINGUN); // sound = Sfx.WPNUP; // break; // case Sprite.CSAW: // if (!GiveWeapon(player, WeaponType.Chainsaw, false)) // { // return; // } // player.SendMessage(DoomInfo.Strings.GOTCHAINSAW); // sound = Sfx.WPNUP; // break; // case Sprite.LAUN: // if (!GiveWeapon(player, WeaponType.Missile, false)) // { // return; // } // player.SendMessage(DoomInfo.Strings.GOTLAUNCHER); // sound = Sfx.WPNUP; // break; // case Sprite.PLAS: // if (!GiveWeapon(player, WeaponType.Plasma, false)) // { // return; // } // player.SendMessage(DoomInfo.Strings.GOTPLASMA); // sound = Sfx.WPNUP; // break; // case Sprite.SHOT: // if (!GiveWeapon(player, WeaponType.Shotgun, (special.Flags & MobjFlags.Dropped) != 0)) // { // return; // } // player.SendMessage(DoomInfo.Strings.GOTSHOTGUN); // sound = Sfx.WPNUP; // break; // case Sprite.SGN2: // if (!GiveWeapon(player, WeaponType.SuperShotgun, (special.Flags & MobjFlags.Dropped) != 0)) // { // return; // } // player.SendMessage(DoomInfo.Strings.GOTSHOTGUN2); // sound = Sfx.WPNUP; // break; default: throw new Exception("Unknown gettable thing!"); } if ((special.Flags & MobjFlags.CountItem) != 0) { player.ItemCount++; } world.ThingAllocation.RemoveMobj(special); player.BonusCount += bonusAdd; if (player == world.ConsolePlayer) { world.StartSound(player.Mobj, sound, SfxType.Misc); } }