/// <summary> /// Spawn a mobj at the mapthing. /// </summary> public void SpawnMapThing(MapThing mt) { // Count deathmatch start positions. if (mt.Type == 11) { if (this.deathmatchStarts.Count < 10) { this.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. this.playerStarts[playerNumber] = mt; if (this.world.Options.Deathmatch == 0) { this.SpawnPlayer(mt); } return; } if (mt.Type == 11 || mt.Type <= 4) { return; } // Check for apropriate skill level. if (!this.world.Options.NetGame && ((int)mt.Flags & 16) != 0) { return; } int bit; if (this.world.Options.Skill == GameSkill.Baby) { bit = 1; } else if (this.world.Options.Skill == GameSkill.Nightmare) { bit = 4; } else { bit = 1 << ((int)this.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 (this.world.Options.Deathmatch != 0 && (DoomInfo.MobjInfos[i].Flags & MobjFlags.NotDeathmatch) != 0) { return; } // Don't spawn any monsters if -nomonsters. if (this.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 = this.SpawnMobj(x, y, z, (MobjType)i); mobj.SpawnPoint = mt; if (mobj.Tics > 0) { mobj.Tics = 1 + (this.world.Random.Next() % mobj.Tics); } if ((mobj.Flags & MobjFlags.CountKill) != 0) { this.world.TotalKills++; } if ((mobj.Flags & MobjFlags.CountItem) != 0) { this.world.TotalItems++; } mobj.Angle = mt.Angle; if ((mt.Flags & ThingFlags.Ambush) != 0) { mobj.Flags |= MobjFlags.Ambush; } }
/// <summary> /// Called when a player is spawned on the level. /// Most of the player structure stays unchanged between levels. /// </summary> public void SpawnPlayer(MapThing mt) { var players = this.world.Options.Players; var playerNumber = mt.Type - 1; // Not playing? if (!players[playerNumber].InGame) { return; } var player = players[playerNumber]; if (player.PlayerState == PlayerState.Reborn) { players[playerNumber].Reborn(); } var x = mt.X; var y = mt.Y; var z = Mobj.OnFloorZ; var mobj = this.SpawnMobj(x, y, z, MobjType.Player); if (mt.Type - 1 == this.world.Options.ConsolePlayer) { this.world.StatusBar?.Reset(); this.world.Options.Sound.SetListener(mobj); } // Set color translations for player sprites. if (playerNumber >= 1) { mobj.Flags |= (MobjFlags)((mt.Type - 1) << (int)MobjFlags.TransShift); } mobj.Angle = mt.Angle; mobj.Player = player; mobj.Health = player.Health; player.Mobj = mobj; player.PlayerState = PlayerState.Live; player.Refire = 0; player.Message = null; player.MessageTime = 0; player.DamageCount = 0; player.BonusCount = 0; player.ExtraLight = 0; player.FixedColorMap = 0; player.ViewHeight = Player.NormalViewHeight; // Setup gun psprite. this.world.PlayerBehavior.SetupPlayerSprites(player); // Give all cards in death match mode. if (this.world.Options.Deathmatch != 0) { for (var i = 0; i < (int)CardType.Count; i++) { player.Cards[i] = true; } } }
/// <summary> /// Returns false if the player cannot be respawned at the given /// mapthing spot because something is occupying it. /// </summary> public bool CheckSpot(int playernum, MapThing mthing) { var players = this.world.Options.Players; if (players[playernum].Mobj == null) { // First spawn of level, before corpses. for (var i = 0; i < playernum; i++) { if (players[i].Mobj.X == mthing.X && players[i].Mobj.Y == mthing.Y) { return(false); } } return(true); } var x = mthing.X; var y = mthing.Y; if (!this.world.ThingMovement.CheckPosition(players[playernum].Mobj, x, y)) { return(false); } // Flush an old corpse if needed. if (this.bodyQueSlot >= ThingAllocation.bodyQueSize) { this.RemoveMobj(this.bodyQue[this.bodyQueSlot % ThingAllocation.bodyQueSize]); } this.bodyQue[this.bodyQueSlot % ThingAllocation.bodyQueSize] = players[playernum].Mobj; this.bodyQueSlot++; // Spawn a teleport fog. var subsector = Geometry.PointInSubsector(x, y, this.world.Map); var angle = (Angle.Ang45.Data >> Trig.AngleToFineShift) * ((int)Math.Round(mthing.Angle.ToDegree()) / 45); // // The code below to reproduce respawn fog bug in deathmath // is based on Chocolate Doom's implementation. // Fixed xa; Fixed ya; switch (angle) { case 4096: // -4096: xa = Trig.Tan(2048); // finecosine[-4096] ya = Trig.Tan(0); // finesine[-4096] break; case 5120: // -3072: xa = Trig.Tan(3072); // finecosine[-3072] ya = Trig.Tan(1024); // finesine[-3072] break; case 6144: // -2048: xa = Trig.Sin(0); // finecosine[-2048] ya = Trig.Tan(2048); // finesine[-2048] break; case 7168: // -1024: xa = Trig.Sin(1024); // finecosine[-1024] ya = Trig.Tan(3072); // finesine[-1024] break; case 0: case 1024: case 2048: case 3072: xa = Trig.Cos((int)angle); ya = Trig.Sin((int)angle); break; default: throw new Exception("Unexpected angle: " + angle); } var mo = this.SpawnMobj(x + 20 * xa, y + 20 * ya, subsector.Sector.FloorHeight, MobjType.Tfog); if (!this.world.FirstTicIsNotYetDone) { // Don't start sound on first frame. this.world.StartSound(mo, Sfx.TELEPT, SfxType.Misc); } return(true); }
public StackOverflowExample() { _map = new MapThing(); _mapActions = new Dictionary <string, Action> { { "orange", _map.functionOrange },