private bool ShootTraverse(Intercept intercept) { var mi = world.MapInteraction; var pt = world.PathTraversal; if (intercept.Line != null) { var line = intercept.Line; if (line.Special != 0) { mi.ShootSpecialLine(currentShooter, line); } if ((line.Flags & LineFlags.TwoSided) == 0) { goto hitLine; } var mc = world.MapCollision; // Crosses a two sided line. mc.LineOpening(line); var dist = currentRange * intercept.Frac; if (line.FrontSector.FloorHeight != line.BackSector.FloorHeight) { var slope = (mc.OpenBottom - currentShooterZ) / dist; if (slope > currentAimSlope) { goto hitLine; } } if (line.FrontSector.CeilingHeight != line.BackSector.CeilingHeight) { var slope = (mc.OpenTop - currentShooterZ) / dist; if (slope < currentAimSlope) { goto hitLine; } } // Shot continues. return(true); // Hit line. hitLine: // Position a bit closer. var frac = intercept.Frac - Fixed.FromInt(4) / currentRange; var x = pt.Trace.X + pt.Trace.Dx * frac; var y = pt.Trace.Y + pt.Trace.Dy * frac; var z = currentShooterZ + currentAimSlope * (frac * currentRange); if (line.FrontSector.CeilingFlat == 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 == world.Map.SkyFlatNumber) { return(false); } } // Spawn bullet puffs. SpawnPuff(x, y, z); // Don't go any farther. return(false); } { // Shoot a thing. var thing = intercept.Thing; if (thing == 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 = currentRange * intercept.Frac; var thingTopSlope = (thing.Z + thing.Height - currentShooterZ) / dist; if (thingTopSlope < currentAimSlope) { // Shot over the thing. return(true); } var thingBottomSlope = (thing.Z - currentShooterZ) / dist; if (thingBottomSlope > currentAimSlope) { // Shot under the thing. return(true); } // Hit thing. // Position a bit closer. var frac = intercept.Frac - Fixed.FromInt(10) / currentRange; var x = pt.Trace.X + pt.Trace.Dx * frac; var y = pt.Trace.Y + pt.Trace.Dy * frac; var z = currentShooterZ + currentAimSlope * (frac * currentRange); // Spawn bullet puffs or blod spots, depending on target type. if ((intercept.Thing.Flags & MobjFlags.NoBlood) != 0) { SpawnPuff(x, y, z); } else { SpawnBlood(x, y, z, currentDamage); } if (currentDamage != 0) { world.ThingInteraction.DamageMobj(thing, currentShooter, currentShooter, currentDamage); } // Don't go any farther. return(false); } }
private void UnArchiveThinkers(World world) { var thinkers = world.Thinkers; var ta = world.ThingAllocation; // Remove all the current thinkers. foreach (var thinker in thinkers) { var mobj = thinker as Mobj; if (mobj != null) { ta.RemoveMobj(mobj); } } thinkers.Reset(); // Read in saved thinkers. while (true) { var tclass = (ThinkerClass)data[ptr++]; switch (tclass) { case ThinkerClass.End: // End of list. return; case ThinkerClass.Mobj: PadPointer(); var mobj = new Mobj(world); mobj.ThinkerState = ReadThinkerState(data, ptr + 8); mobj.X = new Fixed(BitConverter.ToInt32(data, ptr + 12)); mobj.Y = new Fixed(BitConverter.ToInt32(data, ptr + 16)); mobj.Z = new Fixed(BitConverter.ToInt32(data, ptr + 20)); mobj.Angle = new Angle(BitConverter.ToInt32(data, ptr + 32)); mobj.Sprite = (Sprite)BitConverter.ToInt32(data, ptr + 36); mobj.Frame = BitConverter.ToInt32(data, ptr + 40); mobj.FloorZ = new Fixed(BitConverter.ToInt32(data, ptr + 56)); mobj.CeilingZ = new Fixed(BitConverter.ToInt32(data, ptr + 60)); mobj.Radius = new Fixed(BitConverter.ToInt32(data, ptr + 64)); mobj.Height = new Fixed(BitConverter.ToInt32(data, ptr + 68)); mobj.MomX = new Fixed(BitConverter.ToInt32(data, ptr + 72)); mobj.MomY = new Fixed(BitConverter.ToInt32(data, ptr + 76)); mobj.MomZ = new Fixed(BitConverter.ToInt32(data, ptr + 80)); mobj.Type = (MobjType)BitConverter.ToInt32(data, ptr + 88); mobj.Info = DoomInfo.MobjInfos[(int)mobj.Type]; mobj.Tics = BitConverter.ToInt32(data, ptr + 96); mobj.State = DoomInfo.States[BitConverter.ToInt32(data, ptr + 100)]; mobj.Flags = (MobjFlags)BitConverter.ToInt32(data, ptr + 104); mobj.Health = BitConverter.ToInt32(data, ptr + 108); mobj.MoveDir = (Direction)BitConverter.ToInt32(data, ptr + 112); mobj.MoveCount = BitConverter.ToInt32(data, ptr + 116); mobj.ReactionTime = BitConverter.ToInt32(data, ptr + 124); mobj.Threshold = BitConverter.ToInt32(data, ptr + 128); var playerNumber = BitConverter.ToInt32(data, ptr + 132); if (playerNumber != 0) { mobj.Player = world.Options.Players[playerNumber - 1]; mobj.Player.Mobj = mobj; } mobj.LastLook = BitConverter.ToInt32(data, ptr + 136); mobj.SpawnPoint = new MapThing( Fixed.FromInt(BitConverter.ToInt16(data, ptr + 140)), Fixed.FromInt(BitConverter.ToInt16(data, ptr + 142)), new Angle(Angle.Ang45.Data * (uint)(BitConverter.ToInt16(data, ptr + 144) / 45)), BitConverter.ToInt16(data, ptr + 146), (ThingFlags)BitConverter.ToInt16(data, ptr + 148)); ptr += 154; world.ThingMovement.SetThingPosition(mobj); // mobj.FloorZ = mobj.Subsector.Sector.FloorHeight; // mobj.CeilingZ = mobj.Subsector.Sector.CeilingHeight; thinkers.Add(mobj); break; default: throw new Exception("Unknown thinker class in savegame!"); } } }
public void Reborn() { Mobj = null; PlayerState = PlayerState.Live; Cmd.Clear(); ViewZ = Fixed.Zero; ViewHeight = Fixed.Zero; DeltaViewHeight = Fixed.Zero; Bob = Fixed.Zero; Health = MAXHEALTH; ArmorPoints = 0; ArmorType = 0; Array.Clear(Powers, 0, Powers.Length); Array.Clear(Cards, 0, Cards.Length); Backpack = false; Array.Clear(Frags, 0, Frags.Length); ReadyWeapon = WeaponType.Pistol; PendingWeapon = WeaponType.Pistol; Array.Clear(WeaponOwned, 0, WeaponOwned.Length); Array.Clear(Ammo, 0, Ammo.Length); Array.Clear(MaxAmmo, 0, MaxAmmo.Length); WeaponOwned[(int)WeaponType.Fist] = true; WeaponOwned[(int)WeaponType.Pistol] = true; Ammo[(int)AmmoType.Clip] = 50; for (var i = 0; i < (int)AmmoType.Count; i++) { MaxAmmo[i] = DoomInfo.AmmoInfos.Max[i]; } // don't do anything immediately UseDown = true; AttackDown = true; Cheats = 0; Refire = 0; Message = null; DamageCount = 0; BonusCount = 0; Attacker = null; ExtraLight = 0; FixedColorMap = 0; ColorMap = 0; foreach (var psp in PlayerSprites) { psp.Clear(); } DidSecret = false; }
public void CalcHeight(Player player) { // Regular movement bobbing. // It needs to be calculated for gun swing even if not on ground. // // OPTIMIZE: // Tablify angle. // // Note: // A LUT allows for effects like a ramp with low health. player.Bob = player.Mobj.MomX * player.Mobj.MomX + player.Mobj.MomY * player.Mobj.MomY; player.Bob >>= 2; if (player.Bob > maxBob) { player.Bob = maxBob; } if ((player.Cheats & CheatFlags.NoMomentum) != 0 || !onGround) { player.ViewZ = player.Mobj.Z + Player.VIEWHEIGHT; if (player.ViewZ > player.Mobj.CeilingZ - Fixed.FromInt(4)) { player.ViewZ = player.Mobj.CeilingZ - Fixed.FromInt(4); } player.ViewZ = player.Mobj.Z + player.ViewHeight; return; } var angle = (Trig.FineAngleCount / 20 * world.levelTime) & Trig.FineMask; var bob = (player.Bob / 2) * Trig.Sin(angle); // Move viewheight. if (player.PlayerState == PlayerState.Live) { player.ViewHeight += player.DeltaViewHeight; if (player.ViewHeight > Player.VIEWHEIGHT) { player.ViewHeight = Player.VIEWHEIGHT; player.DeltaViewHeight = Fixed.Zero; } if (player.ViewHeight < Player.VIEWHEIGHT / 2) { player.ViewHeight = Player.VIEWHEIGHT / 2; if (player.DeltaViewHeight <= Fixed.Zero) { player.DeltaViewHeight = new Fixed(1); } } if (player.DeltaViewHeight != Fixed.Zero) { player.DeltaViewHeight += Fixed.One / 4; if (player.DeltaViewHeight == Fixed.Zero) { player.DeltaViewHeight = new Fixed(1); } } } player.ViewZ = player.Mobj.Z + player.ViewHeight + bob; if (player.ViewZ > player.Mobj.CeilingZ - Fixed.FromInt(4)) { player.ViewZ = player.Mobj.CeilingZ - Fixed.FromInt(4); } }
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)); }
/// <summary> /// Spawn a mobj at the mapthing. /// </summary> public void SpawnMapThing(MapThing mt) { // Count deathmatch start positions. if (mt.Type == 11) { if (deathmatchStarts.Count < 10) { deathmatchStarts.Add(mt); } return; } // Check for players specially. if (mt.Type <= 4) { var playerNumber = mt.Type - 1; // This check is neccesary in Plutonia MAP12, // which contains an unknown thing with type 0. if (playerNumber < 0) { return; } // Save spots for respawning in network games. playerStarts[playerNumber] = mt; if (world.Options.Deathmatch == 0) { SpawnPlayer(mt); } return; } if (mt.Type == 11 || mt.Type <= 4) { return; } // Check for apropriate skill level. if (!world.Options.NetGame && ((int)mt.Flags & 16) != 0) { return; } int bit; if (world.Options.Skill == GameSkill.Baby) { bit = 1; } else if (world.Options.Skill == GameSkill.Nightmare) { bit = 4; } else { bit = 1 << ((int)world.Options.Skill - 1); } if (((int)mt.Flags & bit) == 0) { return; } // Find which type to spawn. int i; for (i = 0; i < DoomInfo.MobjInfos.Length; i++) { if (mt.Type == DoomInfo.MobjInfos[i].DoomEdNum) { break; } } if (i == DoomInfo.MobjInfos.Length) { throw new Exception("Unknown type!"); } // Don't spawn keycards and players in deathmatch. if (world.Options.Deathmatch != 0 && (DoomInfo.MobjInfos[i].Flags & MobjFlags.NotDeathmatch) != 0) { return; } // Don't spawn any monsters if -nomonsters. if (world.Options.NoMonsters && (i == (int)MobjType.Skull || (DoomInfo.MobjInfos[i].Flags & MobjFlags.CountKill) != 0)) { return; } // Spawn it. Fixed x = mt.X; Fixed y = mt.Y; Fixed z; if ((DoomInfo.MobjInfos[i].Flags & MobjFlags.SpawnCeiling) != 0) { z = Mobj.OnCeilingZ; } else { z = Mobj.OnFloorZ; } var mobj = SpawnMobj(x, y, z, (MobjType)i); mobj.SpawnPoint = mt; if (mobj.Tics > 0) { mobj.Tics = 1 + (world.Random.Next() % mobj.Tics); } if ((mobj.Flags & MobjFlags.CountKill) != 0) { world.TotalKills++; } if ((mobj.Flags & MobjFlags.CountItem) != 0) { world.TotalItems++; } mobj.Angle = mt.Angle; if ((mt.Flags & ThingFlags.Ambush) != 0) { mobj.Flags |= MobjFlags.Ambush; } }
private void SlideMove(Mobj thing) { var pt = world.PathTraversal; slideThing = thing; var hitCount = 0; retry: // Don't loop forever. if (++hitCount == 3) { // The move most have hit the middle, so stairstep. StairStep(thing); return; } Fixed leadX; Fixed leadY; Fixed trailX; Fixed trailY; // Trace along the three leading corners. if (thing.MomX > Fixed.Zero) { leadX = thing.X + thing.Radius; trailX = thing.X - thing.Radius; } else { leadX = thing.X - thing.Radius; trailX = thing.X + thing.Radius; } if (thing.MomY > Fixed.Zero) { leadY = thing.Y + thing.Radius; trailY = thing.Y - thing.Radius; } else { leadY = thing.Y - thing.Radius; trailY = thing.Y + thing.Radius; } bestSlideFrac = new Fixed(Fixed.FracUnit + 1); pt.PathTraverse( leadX, leadY, leadX + thing.MomX, leadY + thing.MomY, PathTraverseFlags.AddLines, slideTraverseFunc); pt.PathTraverse( trailX, leadY, trailX + thing.MomX, leadY + thing.MomY, PathTraverseFlags.AddLines, slideTraverseFunc); pt.PathTraverse( leadX, trailY, leadX + thing.MomX, trailY + thing.MomY, PathTraverseFlags.AddLines, slideTraverseFunc); // Move up to the wall. if (bestSlideFrac == new Fixed(Fixed.FracUnit + 1)) { // The move most have hit the middle, so stairstep. StairStep(thing); return; } // Fudge a bit to make sure it doesn't hit. bestSlideFrac = new Fixed(bestSlideFrac.Data - 0x800); if (bestSlideFrac > Fixed.Zero) { var newX = thing.MomX * bestSlideFrac; var newY = thing.MomY * bestSlideFrac; if (!TryMove(thing, thing.X + newX, thing.Y + newY)) { // The move most have hit the middle, so stairstep. StairStep(thing); return; } } // Now continue along the wall. // First calculate remainder. bestSlideFrac = new Fixed(Fixed.FracUnit - (bestSlideFrac.Data + 0x800)); if (bestSlideFrac > Fixed.One) { bestSlideFrac = Fixed.One; } if (bestSlideFrac <= Fixed.Zero) { return; } slideMoveX = thing.MomX * bestSlideFrac; slideMoveY = thing.MomY * bestSlideFrac; // Clip the moves. HitSlideLine(bestSlideLine); thing.MomX = slideMoveX; thing.MomY = slideMoveY; if (!TryMove(thing, thing.X + slideMoveX, thing.Y + slideMoveY)) { goto retry; } }
public Vertex(Fixed x, Fixed y) { this.x = x; this.y = y; }
// Attempt to move to a new position, crossing special lines unless // MobjFlags.Teleport is set. public bool TryMove(Mobj thing, Fixed x, Fixed y) { floatOk = false; if (!CheckPosition(thing, x, y)) { // Solid wall or thing. return(false); } if ((thing.Flags & MobjFlags.NoClip) == 0) { if (currentCeilingZ - currentFloorZ < thing.Height) { // Doesn't fit. return(false); } floatOk = true; if ((thing.Flags & MobjFlags.Teleport) == 0 && currentCeilingZ - thing.Z < thing.Height) { // Mobj must lower itself to fit. return(false); } if ((thing.Flags & MobjFlags.Teleport) == 0 && currentFloorZ - thing.Z > Fixed.FromInt(24)) { // Too big a step up. return(false); } if ((thing.Flags & (MobjFlags.DropOff | MobjFlags.Float)) == 0 && currentFloorZ - currentDropoffZ > Fixed.FromInt(24)) { // Don't stand over a dropoff. return(false); } } // The move is ok, // so link the thing into its new position. UnsetThingPosition(thing); var oldx = thing.X; var oldy = thing.Y; thing.FloorZ = currentFloorZ; thing.CeilingZ = currentCeilingZ; thing.X = x; thing.Y = y; SetThingPosition(thing); // If any special lines were hit, do the effect. if ((thing.Flags & (MobjFlags.Teleport | MobjFlags.NoClip)) == 0) { while (crossedSpecialCount-- > 0) { // See if the line was crossed. var line = crossedSpecials[crossedSpecialCount]; var newSide = Geometry.PointOnLineSide(thing.X, thing.Y, line); var oldSide = Geometry.PointOnLineSide(oldx, oldy, line); if (newSide != oldSide) { if (line.Special != 0) { world.MapInteraction.CrossSpecialLine(line, oldSide, thing); } } } } return(true); }
public void XYMovement(Mobj thing) { if (thing.MomX == Fixed.Zero && thing.MomY == Fixed.Zero) { if ((thing.Flags & MobjFlags.SkullFly) != 0) { // The skull slammed into something. thing.Flags &= ~MobjFlags.SkullFly; thing.MomX = thing.MomY = thing.MomZ = Fixed.Zero; thing.SetState(thing.Info.SpawnState); } return; } var player = thing.Player; if (thing.MomX > maxMove) { thing.MomX = maxMove; } else if (thing.MomX < -maxMove) { thing.MomX = -maxMove; } if (thing.MomY > maxMove) { thing.MomY = maxMove; } else if (thing.MomY < -maxMove) { thing.MomY = -maxMove; } var moveX = thing.MomX; var moveY = thing.MomY; do { Fixed pMoveX; Fixed pMoveY; if (moveX > maxMove / 2 || moveY > maxMove / 2) { pMoveX = thing.X + moveX / 2; pMoveY = thing.Y + moveY / 2; moveX = new Fixed(moveX.Data >> 1); moveY = new Fixed(moveY.Data >> 1); } else { pMoveX = thing.X + moveX; pMoveY = thing.Y + moveY; moveX = moveY = Fixed.Zero; } if (!TryMove(thing, pMoveX, pMoveY)) { // Blocked move. if (thing.Player != null) { // Try to slide along it. SlideMove(thing); } else if ((thing.Flags & MobjFlags.Missile) != 0) { // Explode a missile. if (currentCeilingLine != null && currentCeilingLine.BackSector != null && currentCeilingLine.BackSector.CeilingFlat == world.Map.SkyFlatNumber) { // Hack to prevent missiles exploding against the sky. // Does not handle sky floors. world.ThingAllocation.RemoveMobj(thing); return; } world.ThingInteraction.ExplodeMissile(thing); } else { thing.MomX = thing.MomY = Fixed.Zero; } } }while (moveX != Fixed.Zero || moveY != Fixed.Zero); // Slow down. if (player != null && (player.Cheats & CheatFlags.NoMomentum) != 0) { // Debug option for no sliding at all. thing.MomX = thing.MomY = Fixed.Zero; return; } if ((thing.Flags & (MobjFlags.Missile | MobjFlags.SkullFly)) != 0) { // No friction for missiles ever. return; } if (thing.Z > thing.FloorZ) { // No friction when airborne. return; } if ((thing.Flags & MobjFlags.Corpse) != 0) { // Do not stop sliding if halfway off a step with some momentum. if (thing.MomX > Fixed.One / 4 || thing.MomX < -Fixed.One / 4 || thing.MomY > Fixed.One / 4 || thing.MomY < -Fixed.One / 4) { if (thing.FloorZ != thing.Subsector.Sector.FloorHeight) { return; } } } if (thing.MomX > -stopSpeed && thing.MomX < stopSpeed && thing.MomY > -stopSpeed && thing.MomY < stopSpeed && (player == null || (player.Cmd.ForwardMove == 0 && player.Cmd.SideMove == 0))) { // If in a walking frame, stop moving. if (player != null && (player.Mobj.State.Number - (int)MobjState.PlayRun1) < 4) { player.Mobj.SetState(MobjState.Play); } thing.MomX = Fixed.Zero; thing.MomY = Fixed.Zero; } else { thing.MomX = thing.MomX * friction; thing.MomY = thing.MomY * friction; } }
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 newsubsec = 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 = newsubsec.Sector.FloorHeight; currentCeilingZ = newsubsec.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] - GameConstants.MaxThingRadius); var blockX2 = bm.GetBlockX(currentBox[Box.Right] + GameConstants.MaxThingRadius); var blockY1 = bm.GetBlockY(currentBox[Box.Bottom] - GameConstants.MaxThingRadius); var blockY2 = bm.GetBlockY(currentBox[Box.Top] + GameConstants.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); }
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) { // 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 bool CheckLine(LineDef line) { var mc = world.MapCollision; if (currentBox.Right() <= line.Box.Left() || currentBox.Left() >= line.Box.Right() || currentBox.Top() <= line.Box.Bottom() || currentBox.Bottom() >= line.Box.Top()) { return(true); } if (Geometry.BoxOnLineSide(currentBox, line) != -1) { return(true); } // A line has been hit. // // The moving thing's destination position will cross the given line. // If this should not be allowed, return false. // If the line is special, keep track of it to process later if the move is proven ok. // // NOTE: // specials are NOT sorted by order, so two special lines that are only 8 pixels // apart could be crossed in either order. if (line.BackSector == null) { // One sided line. return(false); } if ((currentThing.Flags & MobjFlags.Missile) == 0) { if ((line.Flags & LineFlags.Blocking) != 0) { // Explicitly blocking everything. return(false); } if (currentThing.Player == null && (line.Flags & LineFlags.BlockMonsters) != 0) { // Block monsters only. return(false); } } // Set openrange, opentop, openbottom. mc.LineOpening(line); // Adjust floor / ceiling heights. if (mc.OpenTop < currentCeilingZ) { currentCeilingZ = mc.OpenTop; currentCeilingLine = line; } if (mc.OpenBottom > currentFloorZ) { currentFloorZ = mc.OpenBottom; } if (mc.LowFloor < currentDropoffZ) { currentDropoffZ = mc.LowFloor; } // If contacted a special line, add it to the list. if (line.Special != 0) { crossedSpecials[crossedSpecialCount] = line; crossedSpecialCount++; } return(true); }
/// <summary> /// Fire a hitscan bullet along the aiming line. /// </summary> private bool ShootTraverse(Intercept intercept) { var mi = world.MapInteraction; var pt = world.PathTraversal; if (intercept.Line != null) { var line = intercept.Line; if (line.Special != 0) { mi.ShootSpecialLine(currentShooter, line); } if ((line.Flags & LineFlags.TwoSided) == 0) { goto hitLine; } var mc = world.MapCollision; // Crosses a two sided line. mc.LineOpening(line); var dist = currentRange * intercept.Frac; // Similar to AimTraverse, the code below is imported from Chocolate Doom. if (line.BackSector == null) { { var slope = (mc.OpenBottom - currentShooterZ) / dist; if (slope > currentAimSlope) { goto hitLine; } } { var slope = (mc.OpenTop - currentShooterZ) / dist; if (slope < currentAimSlope) { goto hitLine; } } } else { if (line.FrontSector.FloorHeight != line.BackSector.FloorHeight) { var slope = (mc.OpenBottom - currentShooterZ) / dist; if (slope > currentAimSlope) { goto hitLine; } } if (line.FrontSector.CeilingHeight != line.BackSector.CeilingHeight) { var slope = (mc.OpenTop - currentShooterZ) / dist; if (slope < currentAimSlope) { goto hitLine; } } } // Shot continues. return(true); // Hit line. hitLine: // Position a bit closer. var frac = intercept.Frac - Fixed.FromInt(4) / currentRange; var x = pt.Trace.X + pt.Trace.Dx * frac; var y = pt.Trace.Y + pt.Trace.Dy * frac; var z = currentShooterZ + currentAimSlope * (frac * currentRange); if (line.FrontSector.CeilingFlat == 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 == world.Map.SkyFlatNumber) { return(false); } } // Spawn bullet puffs. SpawnPuff(x, y, z); // Don't go any farther. return(false); } { // Shoot a thing. var thing = intercept.Thing; if (thing == 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 = currentRange * intercept.Frac; var thingTopSlope = (thing.Z + thing.Height - currentShooterZ) / dist; if (thingTopSlope < currentAimSlope) { // Shot over the thing. return(true); } var thingBottomSlope = (thing.Z - currentShooterZ) / dist; if (thingBottomSlope > currentAimSlope) { // Shot under the thing. return(true); } // Hit thing. // Position a bit closer. var frac = intercept.Frac - Fixed.FromInt(10) / currentRange; var x = pt.Trace.X + pt.Trace.Dx * frac; var y = pt.Trace.Y + pt.Trace.Dy * frac; var z = currentShooterZ + currentAimSlope * (frac * currentRange); //* implement if(PuffType == MT_BLASTERPUFF1) // { // Make blaster big puff // mo = P_SpawnMobj(x, y, z, MT_BLASTERPUFF2); // S_StartSound(mo, sfx_blshit); // } // else // { SpawnPuff(x, y, z); // } if (currentDamage != 0) { //* implement if(!(in->d.thing->flags&MF_NOBLOOD) && P_Random() < 192) // { // P_BloodSplatter(x, y, z, in->d.thing); // } world.ThingInteraction.DamageMobj(thing, currentShooter, currentShooter, currentDamage); } // Don't go any farther. return(false); } }
/// <summary> /// Traces a line from x1, y1 to x2, y2, calling the traverser function for each. /// Returns true if the traverser function returns true for all lines. /// </summary> 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.BlockSize.Data - 1)) == 0) { // Don't side exactly on a line. x1 += Fixed.One; } if (((y1 - bm.OriginY).Data & (BlockMap.BlockSize.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.FracToBlockShift; var blockY1 = y1.Data >> BlockMap.FracToBlockShift; x2 -= bm.OriginX; y2 -= bm.OriginY; var blockX2 = x2.Data >> BlockMap.FracToBlockShift; var blockY2 = y2.Data >> BlockMap.FracToBlockShift; Fixed stepX; Fixed stepY; Fixed partial; int blockStepX; int blockStepY; if (blockX2 > blockX1) { blockStepX = 1; partial = new Fixed(Fixed.FracUnit - ((x1.Data >> BlockMap.BlockToFracShift) & (Fixed.FracUnit - 1))); stepY = (y2 - y1) / Fixed.Abs(x2 - x1); } else if (blockX2 < blockX1) { blockStepX = -1; partial = new Fixed((x1.Data >> BlockMap.BlockToFracShift) & (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.BlockToFracShift) + (partial * stepY); if (blockY2 > blockY1) { blockStepY = 1; partial = new Fixed(Fixed.FracUnit - ((y1.Data >> BlockMap.BlockToFracShift) & (Fixed.FracUnit - 1))); stepX = (x2 - x1) / Fixed.Abs(y2 - y1); } else if (blockY2 < blockY1) { blockStepY = -1; partial = new Fixed((y1.Data >> BlockMap.BlockToFracShift) & (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.BlockToFracShift) + (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> /// 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 = 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 = currentRange * intercept.Frac; // The null check of the backsector below is necessary to avoid crash // in certain PWADs, which contain two-sided lines with no backsector. // These are imported from Chocolate Doom. if (line.BackSector == null || line.FrontSector.FloorHeight != line.BackSector.FloorHeight) { var slope = (mc.OpenBottom - currentShooterZ) / dist; if (slope > bottomSlope) { bottomSlope = slope; } } if (line.BackSector == null || line.FrontSector.CeilingHeight != line.BackSector.CeilingHeight) { var slope = (mc.OpenTop - currentShooterZ) / dist; if (slope < topSlope) { topSlope = slope; } } if (topSlope <= bottomSlope) { // Stop. return(false); } // Shot continues. return(true); } // Shoot a thing. var thing = intercept.Thing; if (thing == 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 = currentRange * intercept.Frac; var thingTopSlope = (thing.Z + thing.Height - currentShooterZ) / dist; if (thingTopSlope < bottomSlope) { // Shot over the thing. return(true); } var thingBottomSlope = (thing.Z - currentShooterZ) / dist; if (thingBottomSlope > topSlope) { // Shot under the thing. return(true); } // This thing can be hit! if (thingTopSlope > topSlope) { thingTopSlope = topSlope; } if (thingBottomSlope < bottomSlope) { thingBottomSlope = bottomSlope; } currentAimSlope = (thingTopSlope + thingBottomSlope) / 2; lineTarget = thing; // Don't go any farther. return(false); } }
// // P_TouchSpecialThing // 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, 1)) { return; } //player.Message = GOTARMOR; break; case Sprite.ARM2: if (!GiveArmor(player, 2)) { return; } //player.Message = GOTMEGA; break; // bonus items case Sprite.BON1: player.Health++; // can go over 100% if (player.Health > 200) { player.Health = 200; } player.Mobj.Health = player.Health; //player.Message = GOTHTHBONUS; break; case Sprite.BON2: player.ArmorPoints++; // can go over 100% if (player.ArmorPoints > 200) { player.ArmorPoints = 200; } if (player.ArmorType == 0) { player.ArmorType = 1; } //player.Message = GOTARMBONUS; break; case Sprite.SOUL: player.Health += 100; if (player.Health > 200) { player.Health = 200; } player.Mobj.Health = player.Health; //player.Message = GOTSUPER; sound = Sfx.GETPOW; break; case Sprite.MEGA: if (world.Options.GameMode != GameMode.Commercial) { return; } player.Health = 200; player.Mobj.Health = player.Health; GiveArmor(player, 2); //player.Message = GOTMSPHERE; sound = Sfx.GETPOW; break; // cards // leave cards for everyone case Sprite.BKEY: if (!player.Cards[(int)CardType.BlueCard]) { //player.Message = GOTBLUECARD; } GiveCard(player, CardType.BlueCard); if (!world.Options.NetGame) { break; } return; case Sprite.YKEY: if (!player.Cards[(int)CardType.YellowCard]) { //player.Message = GOTYELWCARD; } GiveCard(player, CardType.YellowCard); if (!world.Options.NetGame) { break; } return; case Sprite.RKEY: if (!player.Cards[(int)CardType.RedCard]) { //player.Message = GOTREDCARD; } GiveCard(player, CardType.RedCard); if (!world.Options.NetGame) { break; } return; case Sprite.BSKU: if (!player.Cards[(int)CardType.BlueSkull]) { //player.Message = GOTBLUESKUL; } GiveCard(player, CardType.BlueSkull); if (!world.Options.NetGame) { break; } return; case Sprite.YSKU: if (!player.Cards[(int)CardType.YellowSkull]) { //player.Message = GOTYELWSKUL; } GiveCard(player, CardType.YellowSkull); if (!world.Options.NetGame) { break; } return; case Sprite.RSKU: if (!player.Cards[(int)CardType.RedSkull]) { //player.Message = GOTREDSKULL; } GiveCard(player, CardType.RedSkull); if (!world.Options.NetGame) { break; } return; // medikits, heals case Sprite.STIM: if (!GiveBody(player, 10)) { return; } //player.Message = GOTSTIM; break; case Sprite.MEDI: if (!GiveBody(player, 25)) { return; } if (player.Health < 25) { //player.Message = GOTMEDINEED; } else { //player.Message = GOTMEDIKIT; } break; // power ups case Sprite.PINV: if (!GivePower(player, PowerType.Invulnerability)) { return; } //player.Message = GOTINVUL; sound = Sfx.GETPOW; break; case Sprite.PSTR: if (!GivePower(player, PowerType.Strength)) { return; } //player.Message = GOTBERSERK; if (player.ReadyWeapon != WeaponType.Fist) { player.PendingWeapon = WeaponType.Fist; } sound = Sfx.GETPOW; break; case Sprite.PINS: if (!GivePower(player, PowerType.Invisibility)) { return; } //player.Message = GOTINVIS; sound = Sfx.GETPOW; break; case Sprite.SUIT: if (!GivePower(player, PowerType.IronFeet)) { return; } //player.Message = GOTSUIT; sound = Sfx.GETPOW; break; case Sprite.PMAP: if (!GivePower(player, PowerType.AllMap)) { return; } //player.Message = GOTMAP; sound = Sfx.GETPOW; break; case Sprite.PVIS: if (!GivePower(player, PowerType.Infrared)) { return; } //player.Message = 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.Message = GOTCLIP; break; case Sprite.AMMO: if (!GiveAmmo(player, AmmoType.Clip, 5)) { return; } //player.Message = GOTCLIPBOX; break; case Sprite.ROCK: if (!GiveAmmo(player, AmmoType.Missile, 1)) { return; } //player.Message = GOTROCKET; break; case Sprite.BROK: if (!GiveAmmo(player, AmmoType.Missile, 5)) { return; } //player.Message = GOTROCKBOX; break; case Sprite.CELL: if (!GiveAmmo(player, AmmoType.Cell, 1)) { return; } //player.Message = GOTCELL; break; case Sprite.CELP: if (!GiveAmmo(player, AmmoType.Cell, 5)) { return; } //player.Message = GOTCELLBOX; break; case Sprite.SHEL: if (!GiveAmmo(player, AmmoType.Shell, 1)) { return; } //player.Message = GOTSHELLS; break; case Sprite.SBOX: if (!GiveAmmo(player, AmmoType.Shell, 5)) { return; } //player.Message = 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.Message = GOTBACKPACK; break; // weapons case Sprite.BFUG: if (!GiveWeapon(player, WeaponType.Bfg, false)) { return; } //player.Message = GOTBFG9000; sound = Sfx.WPNUP; break; case Sprite.MGUN: if (!GiveWeapon(player, WeaponType.Chaingun, (special.Flags & MobjFlags.Dropped) != 0)) { return; } //player.Message = GOTCHAINGUN; sound = Sfx.WPNUP; break; case Sprite.CSAW: if (!GiveWeapon(player, WeaponType.Chainsaw, false)) { return; } //player.Message = GOTCHAINSAW; sound = Sfx.WPNUP; break; case Sprite.LAUN: if (!GiveWeapon(player, WeaponType.Missile, false)) { return; } //player.Message = GOTLAUNCHER; sound = Sfx.WPNUP; break; case Sprite.PLAS: if (!GiveWeapon(player, WeaponType.Plasma, false)) { return; } //player.Message = GOTPLASMA; sound = Sfx.WPNUP; break; case Sprite.SHOT: if (!GiveWeapon(player, WeaponType.Shotgun, (special.Flags & MobjFlags.Dropped) != 0)) { return; } //player.Message = GOTSHOTGUN; sound = Sfx.WPNUP; break; case Sprite.SGN2: if (!GiveWeapon(player, WeaponType.SuperShotgun, (special.Flags & MobjFlags.Dropped) != 0)) { return; } //player.Message = GOTSHOTGUN2; sound = Sfx.WPNUP; break; default: throw new Exception("P_SpecialThing: Unknown gettable thing"); } if ((special.Flags & MobjFlags.CountItem) != 0) { player.ItemCount++; } world.ThingAllocation.RemoveMobj(special); player.BonusCount += BONUSADD; if (player == world.Players[world.consoleplayer]) { world.StartSound(null, sound); } }
public static void BuildTicCmd(TicCmd cmd) { var keyLeft = Keyboard.IsKeyPressed(Keyboard.Key.Left); var keyRight = Keyboard.IsKeyPressed(Keyboard.Key.Right); var keyUp = Keyboard.IsKeyPressed(Keyboard.Key.Up); var keyDown = Keyboard.IsKeyPressed(Keyboard.Key.Down); var keySpeed = Keyboard.IsKeyPressed(Keyboard.Key.LShift); var keyStrafe = Keyboard.IsKeyPressed(Keyboard.Key.LAlt); var keyFire = Keyboard.IsKeyPressed(Keyboard.Key.LControl); var keyUse = Keyboard.IsKeyPressed(Keyboard.Key.Space); weaponKeys[0] = Keyboard.IsKeyPressed(Keyboard.Key.Num1); weaponKeys[1] = Keyboard.IsKeyPressed(Keyboard.Key.Num2); weaponKeys[2] = Keyboard.IsKeyPressed(Keyboard.Key.Num3); weaponKeys[3] = Keyboard.IsKeyPressed(Keyboard.Key.Num4); weaponKeys[4] = Keyboard.IsKeyPressed(Keyboard.Key.Num5); weaponKeys[5] = Keyboard.IsKeyPressed(Keyboard.Key.Num6); weaponKeys[6] = Keyboard.IsKeyPressed(Keyboard.Key.Num7); cmd.Clear(); var strafe = keyStrafe; var speed = keySpeed ? 1 : 0; Fixed forward = Fixed.Zero; Fixed side = Fixed.Zero; if (keyLeft || keyRight) { turnheld++; } else { turnheld = 0; } int tspeed; if (turnheld < slowTurnTics) { tspeed = 2; } else { tspeed = speed; } if (strafe) { if (keyRight) { side += sidemove[speed]; } if (keyLeft) { side -= sidemove[speed]; } } else { if (keyRight) { cmd.AngleTurn -= (short)angleturn[tspeed].Data; } if (keyLeft) { cmd.AngleTurn += (short)angleturn[tspeed].Data; } } if (keyUp) { forward += forwardmove[speed]; } if (keyDown) { forward -= forwardmove[speed]; } if (keyFire) { cmd.Buttons |= TicCmdButtons.Attack; } if (keyUse) { cmd.Buttons |= TicCmdButtons.Use; } // If the previous or next weapon button is pressed, the // next_weapon variable is set to change weapons when // we generate a ticcmd. Choose a new weapon. /* * if (gamestate == GS_LEVEL && next_weapon != 0) * { * i = G_NextWeapon(next_weapon); * cmd->buttons |= BT_CHANGE; * cmd->buttons |= i << BT_WEAPONSHIFT; * } * else */ { // Check weapon keys. for (var i = 0; i < weaponKeys.Length; i++) { if (weaponKeys[i]) { cmd.Buttons |= TicCmdButtons.Change; cmd.Buttons |= (byte)(i << TicCmdButtons.WeaponShift); break; } } } next_weapon = 0; if (forward > maxplmove) { forward = maxplmove; } else if (forward < -maxplmove) { forward = -maxplmove; } if (side > maxplmove) { side = maxplmove; } else if (side < -maxplmove) { side = -maxplmove; } cmd.ForwardMove += (sbyte)forward.Data; cmd.SideMove += (sbyte)side.Data; }
public static Fixed operator /(int a, Fixed b) { return(Fixed.FromInt(a) / b); }
public void Update() { if (zoomIn) { zoom += zoom / 16; } if (zoomOut) { zoom -= zoom / 16; } if (zoom < Fixed.One / 2) { zoom = Fixed.One / 2; } else if (zoom > Fixed.One * 32) { zoom = Fixed.One * 32; } if (left) { viewX -= 64 / zoom; } if (right) { viewX += 64 / zoom; } if (up) { viewY += 64 / zoom; } if (down) { viewY -= 64 / zoom; } if (viewX < minX) { viewX = minX; } else if (viewX > maxX) { viewX = maxX; } if (viewY < minY) { viewY = minY; } else if (viewY > maxY) { viewY = maxY; } if (follow) { var player = world.ConsolePlayer.Mobj; viewX = player.X; viewY = player.Y; } }
public void Thrust(Player player, Angle angle, Fixed move) { player.Mobj.MomX += move * Trig.Cos(angle); player.Mobj.MomY += move * Trig.Sin(angle); }
public void DamageMobj(Mobj target, Mobj inflictor, Mobj source, int damage) { if ((target.Flags & MobjFlags.Shootable) == 0) { // Shouldn't happen... return; } if (target.Health <= 0) { return; } if ((target.Flags & MobjFlags.SkullFly) != 0) { target.MomX = target.MomY = target.MomZ = Fixed.Zero; } var player = target.Player; if (player != null && world.Options.Skill == GameSkill.Baby) { // Take half damage in trainer mode. damage >>= 1; } // Some close combat weapons should not inflict thrust and // push the victim out of reach, thus kick away unless using the chainsaw. var notChainsawAttack = source == null || source.Player == null || source.Player.ReadyWeapon != WeaponType.Chainsaw; if (inflictor != null && (target.Flags & MobjFlags.NoClip) == 0 && notChainsawAttack) { var ang = Geometry.PointToAngle( inflictor.X, inflictor.Y, target.X, target.Y); var thrust = new Fixed(damage * (Fixed.FracUnit >> 3) * 100 / target.Info.Mass); // Make fall forwards sometimes. if (damage < 40 && damage > target.Health && target.Z - inflictor.Z > Fixed.FromInt(64) && (world.Random.Next() & 1) != 0) { ang += Angle.Ang180; thrust *= 4; } target.MomX += thrust * Trig.Cos(ang); target.MomY += thrust * Trig.Sin(ang); } // Player specific. if (player != null) { // End of game hell hack. if (target.Subsector.Sector.Special == (SectorSpecial)11 && damage >= target.Health) { damage = target.Health - 1; } // Below certain threshold, ignore damage in GOD mode, or with INVUL power. if (damage < 1000 && ((player.Cheats & CheatFlags.GodMode) != 0 || player.Powers[(int)PowerType.Invulnerability] > 0)) { return; } int saved; if (player.ArmorType != 0) { if (player.ArmorType == 1) { saved = damage / 3; } else { saved = damage / 2; } if (player.ArmorPoints <= saved) { // Armor is used up. saved = player.ArmorPoints; player.ArmorType = 0; } player.ArmorPoints -= saved; damage -= saved; } // Mirror mobj health here for Dave. player.Health -= damage; if (player.Health < 0) { player.Health = 0; } player.Attacker = source; // Add damage after armor / invuln. player.DamageCount += damage; if (player.DamageCount > 100) { // Teleport stomp does 10k points... player.DamageCount = 100; } } // Do the damage. target.Health -= damage; if (target.Health <= 0) { KillMobj(source, target); return; } if ((world.Random.Next() < target.Info.PainChance) && (target.Flags & MobjFlags.SkullFly) == 0) { // Fight back! target.Flags |= MobjFlags.JustHit; target.SetState(target.Info.PainState); } // We're awake now... target.ReactionTime = 0; if ((target.Threshold == 0 || target.Type == MobjType.Vile) && source != null && source != target && source.Type != MobjType.Vile) { // If not intent on another player, chase after this one. target.Target = source; target.Threshold = baseThreshold; if (target.State == DoomInfo.States[(int)target.Info.SpawnState] && target.Info.SeeState != MobjState.Null) { target.SetState(target.Info.SeeState); } } }
public override void Run() { SectorActionResult result; var sa = world.SectorAction; switch (direction) { case 0: // In statis. break; case 1: // Up. result = sa.MovePlane( sector, speed, topHeight, false, 1, direction); if ((world.LevelTime & 7) == 0) { switch (type) { case CeilingMoveType.SilentCrushAndRaise: break; default: world.StartSound(sector.SoundOrigin, Sfx.STNMOV, SfxType.Misc); break; } } if (result == SectorActionResult.PastDestination) { switch (type) { case CeilingMoveType.RaiseToHighest: sa.RemoveActiveCeiling(this); break; case CeilingMoveType.SilentCrushAndRaise: case CeilingMoveType.FastCrushAndRaise: case CeilingMoveType.CrushAndRaise: if (type == CeilingMoveType.SilentCrushAndRaise) { world.StartSound(sector.SoundOrigin, Sfx.PSTOP, SfxType.Misc); } direction = -1; break; default: break; } } break; case -1: // Down. result = sa.MovePlane( sector, speed, bottomHeight, crush, 1, direction); if ((world.LevelTime & 7) == 0) { switch (type) { case CeilingMoveType.SilentCrushAndRaise: break; default: world.StartSound(sector.SoundOrigin, Sfx.STNMOV, SfxType.Misc); break; } } if (result == SectorActionResult.PastDestination) { switch (type) { case CeilingMoveType.SilentCrushAndRaise: case CeilingMoveType.CrushAndRaise: case CeilingMoveType.FastCrushAndRaise: if (type == CeilingMoveType.SilentCrushAndRaise) { world.StartSound(sector.SoundOrigin, Sfx.PSTOP, SfxType.Misc); speed = SectorAction.CeilingSpeed; } if (type == CeilingMoveType.CrushAndRaise) { speed = SectorAction.CeilingSpeed; } direction = 1; break; case CeilingMoveType.LowerAndCrush: case CeilingMoveType.LowerToFloor: sa.RemoveActiveCeiling(this); break; default: break; } } else { if (result == SectorActionResult.Crushed) { switch (type) { case CeilingMoveType.SilentCrushAndRaise: case CeilingMoveType.CrushAndRaise: case CeilingMoveType.LowerAndCrush: speed = SectorAction.CeilingSpeed / 8; break; default: break; } } } break; } }