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); }
/// <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())); }
/// <summary> /// Remove the mobj from the level. /// </summary> public void RemoveMobj(Mobj mobj) { var tm = world.ThingMovement; if ((mobj.Flags & MobjFlags.Special) != 0 && (mobj.Flags & MobjFlags.Dropped) == 0 && (mobj.Type != MobjType.Inv) && (mobj.Type != MobjType.Ins)) { itemRespawnQue[itemQueHead] = mobj.SpawnPoint; itemRespawnTime[itemQueHead] = world.LevelTime; itemQueHead = (itemQueHead + 1) & (itemQueSize - 1); // Lose one off the end? if (itemQueHead == itemQueTail) { itemQueTail = (itemQueTail + 1) & (itemQueSize - 1); } } // Unlink from sector and block lists. tm.UnsetThingPosition(mobj); // Stop any playing sound. world.StopSound(mobj); // Free block. world.Thinkers.Remove(mobj); }
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); }
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); }
public void Clear() { mobj = null; playerState = 0; cmd.Clear(); viewZ = Fixed.Zero; viewHeight = Fixed.Zero; deltaViewHeight = Fixed.Zero; bob = Fixed.Zero; health = 0; 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 = 0; pendingWeapon = 0; Array.Clear(weaponOwned, 0, weaponOwned.Length); Array.Clear(ammo, 0, ammo.Length); Array.Clear(maxAmmo, 0, maxAmmo.Length); useDown = false; attackDown = false; cheats = 0; refire = 0; killCount = 0; itemCount = 0; secretCount = 0; message = null; messageTime = 0; damageCount = 0; bonusCount = 0; attacker = null; extraLight = 0; fixedColorMap = 0; colorMap = 0; foreach (var psp in playerSprites) { psp.Clear(); } didSecret = false; }
/// <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 void SkullAttack(Mobj actor) { if (actor.Target == null) { return; } var dest = actor.Target; actor.Flags |= MobjFlags.SkullFly; world.StartSound(actor, actor.Info.AttackSound); FaceTarget(actor); var angle = actor.Angle; actor.MomX = skullSpeed * Trig.Cos(angle); actor.MomY = skullSpeed * Trig.Sin(angle); var dist = Geometry.AproxDistance(dest.X - actor.X, dest.Y - actor.Y); var num = (dest.Z + (dest.Height >> 1) - actor.Z).Data; var den = dist.Data / skullSpeed.Data; if (den < 1) { den = 1; } actor.MomZ = new Fixed(num / den); }
public static int GetMobjHash(Mobj mobj) { var hash = 0; hash = CombineHash(hash, mobj.X.Data); hash = CombineHash(hash, mobj.Y.Data); hash = CombineHash(hash, mobj.Z.Data); hash = CombineHash(hash, (int)mobj.Angle.Data); hash = CombineHash(hash, (int)mobj.Sprite); hash = CombineHash(hash, mobj.Frame); hash = CombineHash(hash, mobj.FloorZ.Data); hash = CombineHash(hash, mobj.CeilingZ.Data); hash = CombineHash(hash, mobj.Radius.Data); hash = CombineHash(hash, mobj.Height.Data); hash = CombineHash(hash, mobj.MomX.Data); hash = CombineHash(hash, mobj.MomY.Data); hash = CombineHash(hash, mobj.MomZ.Data); hash = CombineHash(hash, mobj.Tics); hash = CombineHash(hash, (int)mobj.Flags); hash = CombineHash(hash, mobj.Health); hash = CombineHash(hash, (int)mobj.MoveDir); hash = CombineHash(hash, mobj.MoveCount); hash = CombineHash(hash, mobj.ReactionTime); hash = CombineHash(hash, mobj.Threshold); return(hash); }
public void Pain(Mobj actor) { if (actor.Info.PainSound != 0) { world.StartSound(actor, actor.Info.PainSound); } }
private void StairStep(Mobj thing) { if (!TryMove(thing, thing.X, thing.Y + thing.MomY)) { TryMove(thing, thing.X + thing.MomX, thing.Y); } }
private static string GetMobjCsv(Mobj mobj) { var sb = new StringBuilder(); sb.Append(mobj.X.Data).Append(","); sb.Append(mobj.Y.Data).Append(","); sb.Append(mobj.Z.Data).Append(","); sb.Append((int)mobj.Angle.Data).Append(","); sb.Append((int)mobj.Sprite).Append(","); sb.Append(mobj.Frame).Append(","); sb.Append(mobj.FloorZ.Data).Append(","); sb.Append(mobj.CeilingZ.Data).Append(","); sb.Append(mobj.Radius.Data).Append(","); sb.Append(mobj.Height.Data).Append(","); sb.Append(mobj.MomX.Data).Append(","); sb.Append(mobj.MomY.Data).Append(","); sb.Append(mobj.MomZ.Data).Append(","); sb.Append((int)mobj.Tics).Append(","); sb.Append((int)mobj.Flags).Append(","); sb.Append(mobj.Health).Append(","); sb.Append((int)mobj.MoveDir).Append(","); sb.Append(mobj.MoveCount).Append(","); sb.Append(mobj.ReactionTime).Append(","); sb.Append(mobj.Threshold); return(sb.ToString()); }
public void RemoveMobj(Mobj mobj) { var tm = world.ThingMovement; if ((mobj.Flags & MobjFlags.Special) != 0 && (mobj.Flags & MobjFlags.Dropped) == 0 && (mobj.Type != MobjType.Inv) && (mobj.Type != MobjType.Ins)) { //itemrespawnque[iquehead] = mobj->spawnpoint; //itemrespawntime[iquehead] = leveltime; //iquehead = (iquehead + 1) & (ITEMQUESIZE - 1); // lose one off the end? //if (iquehead == iquetail) // iquetail = (iquetail + 1) & (ITEMQUESIZE - 1); } // Unlink from sector and block lists. tm.UnsetThingPosition(mobj); // Stop any playing sound. world.StopSound(mobj); // Free block. world.Thinkers.Remove(mobj); }
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 bool LookForPlayers(Mobj actor, bool allAround) { var count = 0; var stop = (actor.LastLook - 1) & 3; for (; ; actor.LastLook = (actor.LastLook + 1) & 3) { if (!world.Players[actor.LastLook].InGame) { continue; } if (count++ == 2 || actor.LastLook == stop) { // Done looking. return(false); } var player = world.Players[actor.LastLook]; if (player.Health <= 0) { // Player is dead. continue; } if (!world.VisibilityCheck.CheckSight(actor, player.Mobj)) { // Out of sight. continue; } if (!allAround) { var angle = Geometry.PointToAngle( actor.X, actor.Y, player.Mobj.X, player.Mobj.Y) - actor.Angle; if (angle > Angle.Ang90 && angle < Angle.Ang270) { var dist = Geometry.AproxDistance( player.Mobj.X - actor.X, player.Mobj.Y - actor.Y); // If real close, react anyway. if (dist > World.MELEERANGE) { // Behind back. continue; } } } actor.Target = player.Mobj; return(true); } }
private void GroupLines() { var sectorLines = new List <LineDef>(); var boundingBox = new Fixed[4]; foreach (var line in lines) { if (line.Special != 0) { var so = new Mobj(world); so.X = (line.Vertex1.X + line.Vertex2.X) / 2; so.Y = (line.Vertex1.Y + line.Vertex2.Y) / 2; line.SoundOrigin = so; } } foreach (var sector in sectors) { sectorLines.Clear(); Box.Clear(boundingBox); foreach (var line in lines) { if (line.FrontSector == sector || line.BackSector == sector) { sectorLines.Add(line); Box.AddPoint(boundingBox, line.Vertex1.X, line.Vertex1.Y); Box.AddPoint(boundingBox, line.Vertex2.X, line.Vertex2.Y); } } sector.Lines = sectorLines.ToArray(); // Set the degenmobj_t to the middle of the bounding box. sector.SoundOrigin = new Mobj(world); sector.SoundOrigin.X = (boundingBox[Box.Right] + boundingBox[Box.Left]) / 2; sector.SoundOrigin.Y = (boundingBox[Box.Top] + boundingBox[Box.Bottom]) / 2; sector.BlockBox = new int[4]; int block; // Adjust bounding box to map blocks. block = (boundingBox[Box.Top] - blockMap.OriginY + GameConst.MaxThingRadius).Data >> BlockMap.FracToBlockShift; block = block >= blockMap.Height ? blockMap.Height - 1 : block; sector.BlockBox[Box.Top] = block; block = (boundingBox[Box.Bottom] - blockMap.OriginY - GameConst.MaxThingRadius).Data >> BlockMap.FracToBlockShift; block = block < 0 ? 0 : block; sector.BlockBox[Box.Bottom] = block; block = (boundingBox[Box.Right] - blockMap.OriginX + GameConst.MaxThingRadius).Data >> BlockMap.FracToBlockShift; block = block >= blockMap.Width ? blockMap.Width - 1 : block; sector.BlockBox[Box.Right] = block; block = (boundingBox[Box.Left] - blockMap.OriginX - GameConst.MaxThingRadius).Data >> BlockMap.FracToBlockShift; block = block < 0 ? 0 : block; sector.BlockBox[Box.Left] = block; } }
private void NoiseAlert(Mobj target, Mobj emmiter) { RecursiveSound( emmiter.Subsector.Sector, 0, target, world.GetNewValidCount()); }
public void Clear() { line = null; position = 0; texture = 0; timer = 0; soundOrigin = null; }
public void Clear() { Line = null; Position = 0; Texture = 0; Timer = 0; SoundOrigin = null; }
public void PainDie(Mobj actor) { Fall(actor); PainShootSkull(actor, actor.Angle + Angle.Ang90); PainShootSkull(actor, actor.Angle + Angle.Ang180); PainShootSkull(actor, actor.Angle + Angle.Ang270); }
public void StartSound(Mobj mobj, Sfx sfx) { if (audio == null) { return; } audio.StartSound(mobj, sfx); }
public void StopSound(Mobj mobj) { if (audio == null) { return; } audio.StopSound(mobj); }
private bool AddThingIntercepts(Mobj thing) { var tracePositive = (trace.Dx.Data ^ trace.Dy.Data) > 0; Fixed x1; Fixed y1; Fixed x2; Fixed y2; // Check a corner to corner crossection for hit. if (tracePositive) { x1 = thing.X - thing.Radius; y1 = thing.Y + thing.Radius; x2 = thing.X + thing.Radius; y2 = thing.Y - thing.Radius; } else { x1 = thing.X - thing.Radius; y1 = thing.Y - thing.Radius; x2 = thing.X + thing.Radius; y2 = thing.Y + thing.Radius; } var s1 = Geometry.PointOnDivLineSide(x1, y1, trace); var s2 = Geometry.PointOnDivLineSide(x2, y2, trace); if (s1 == s2) { // Line isn't crossed. return(true); } target.X = x1; target.Y = y1; target.Dx = x2 - x1; target.Dy = y2 - y1; var frac = InterceptVector(trace, target); if (frac < Fixed.Zero) { // Behind source. return(true); } intercepts[interceptCount].Frac = frac; intercepts[interceptCount].Line = null; intercepts[interceptCount].Thing = thing; interceptCount++; // Keep going. return(true); }
public bool TeleportMove(Mobj thing, Fixed x, Fixed y) { // Kill anything occupying the position. 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 ss = Geometry.PointInSubsector(x, y, world.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 = ss.Sector.FloorHeight; currentCeilingZ = ss.Sector.CeilingHeight; var validcount = world.GetNewValidCount(); crossedSpecialCount = 0; // Stomp on any things contacted. var bm = world.Map.BlockMap; 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 (!bm.IterateThings(bx, by, stompThingFunc)) { return(false); } } } // the move is ok, so link the thing into its new position UnsetThingPosition(thing); thing.FloorZ = currentFloorZ; thing.CeilingZ = currentCeilingZ; thing.X = x; thing.Y = y; SetThingPosition(thing); return(true); }
//////////////////////////////////////////////////////////// // Thing spawn functions for the middle of a game //////////////////////////////////////////////////////////// /// <summary> /// Spawn a mobj at the given position as the given type. /// </summary> public Mobj SpawnMobj(Fixed x, Fixed y, Fixed z, MobjType type) { var mobj = new Mobj(world); var info = DoomInfo.MobjInfos[(int)type]; mobj.Type = type; mobj.Info = info; mobj.X = x; mobj.Y = y; mobj.Radius = info.Radius; mobj.Height = info.Height; mobj.Flags = info.Flags; mobj.Flags2 = info.Flags2; mobj.Health = info.SpawnHealth; if (world.Options.Skill != GameSkill.Nightmare) { mobj.ReactionTime = info.ReactionTime; } mobj.LastLook = world.Random.Next() % Player.MaxPlayerCount; // Do not set the state with P_SetMobjState, // because action routines can not be called yet. var st = DoomInfo.States[(int)info.SpawnState]; mobj.State = st; mobj.Tics = st.Tics; mobj.Sprite = st.Sprite; mobj.Frame = st.Frame; // Set subsector and/or block links. world.ThingMovement.SetThingPosition(mobj); mobj.FloorZ = mobj.Subsector.Sector.FloorHeight; mobj.CeilingZ = mobj.Subsector.Sector.CeilingHeight; if (z == Mobj.OnFloorZ) { mobj.Z = mobj.FloorZ; } else if (z == Mobj.OnCeilingZ) { mobj.Z = mobj.CeilingZ - mobj.Info.Height; } else { mobj.Z = z; } world.Thinkers.Add(mobj); return(mobj); }
private void RecursiveSound(Sector sec, int soundblocks, Mobj soundtarget, int validCount) { // Wake up all monsters in this sector. if (sec.ValidCount == validCount && sec.SoundTraversed <= soundblocks + 1) { // Already flooded. return; } sec.ValidCount = validCount; sec.SoundTraversed = soundblocks + 1; sec.SoundTarget = soundtarget; var mc = world.MapCollision; for (var i = 0; i < sec.Lines.Length; i++) { var check = sec.Lines[i]; if ((check.Flags & LineFlags.TwoSided) == 0) { continue; } mc.LineOpening(check); if (mc.OpenRange <= Fixed.Zero) { // Closed door. continue; } Sector other; if (check.FrontSide.Sector == sec) { other = check.BackSide.Sector; } else { other = check.FrontSide.Sector; } if ((check.Flags & LineFlags.SoundBlock) != 0) { if (soundblocks == 0) { RecursiveSound(other, 1, soundtarget, validCount); } } else { RecursiveSound(other, soundblocks, soundtarget, validCount); } } }
public void SkelWhoosh(Mobj actor) { if (actor.Target == null) { return; } FaceTarget(actor); world.StartSound(actor, Sfx.SKESWG); }
public void PainAttack(Mobj actor) { if (actor.Target == null) { return; } FaceTarget(actor); PainShootSkull(actor, actor.Angle); }
public void CyberAttack(Mobj actor) { if (actor.Target == null) { return; } FaceTarget(actor); world.ThingAllocation.SpawnMissile(actor, actor.Target, MobjType.Rocket); }
private bool TryWalk(Mobj actor) { if (!Move(actor)) { return(false); } actor.MoveCount = world.Random.Next() & 15; return(true); }