A scene component representing a level exit trapdoor. It defines interaction text, usage conditions (players nearby and owning a key), plays ambient and open sounds, can be spawned at runtime with model and collider, and advances the game to the next level when used.
using System.Linq;
using Sandbox;
namespace BrickJam;
/// <summary>
/// Level exit that advances to the next level. Scene-System port of legacy <c>Trapdoor</c>.
/// Spawned at runtime by the Level subsystem at a <see cref="ValidTrapdoorPosition"/>.
/// </summary>
[Title( "Trapdoor" )]
[Category( "Map" )]
public sealed partial class Trapdoor : LegacyUsableComponent
{
public override float InteractionDuration { get; set; } = 2f;
public override string UseString
{
get => HasKey
? (CanUse ? "proceed to the next level" : "ALL PLAYERS NEED TO BE NEARBY TO PROCEED")
: "YOU NEED TO BUY THE KEY TO PROCEED";
set { }
}
public override bool CanUse => Scene.GetAllComponents<Player>()
.Where( x => x.IsAlive )
.All( x => x.WorldPosition.Distance( WorldPosition ) <= 400f );
public string KeyName => MansionGame.Instance?.CurrentLevelType == LevelType.Mansion ? "Mansion Key" : "Dungeon Key";
// UseString is the hover prompt shown on the LOCAL client, so check the local player's upgrades. The
// legacy bug here checked User (the host-side interacting player), which is null while merely hovering -
// so it always said "buy the key" even when you owned it. The actual use gate is CheckUpgrades(player).
public bool HasKey => Player.Local?.HasUpgrade( KeyName ) ?? false;
private SoundHandle windSound;
public static Trapdoor Create( Vector3 position, Rotation rotation )
{
var go = new GameObject( true, "Trapdoor" );
go.WorldPosition = position;
go.WorldRotation = rotation;
go.Tags.Add( "solid", "trapdoor", "usable" );
var model = Model.Load( "models/furniture/trap_door.vmdl" );
go.Components.Create<ModelRenderer>().Model = model;
go.Components.Create<ModelCollider>().Model = model;
var trapdoor = go.Components.Create<Trapdoor>();
go.NetworkSpawn();
return trapdoor;
}
protected override void OnStart()
{
windSound = Sound.Play( "sounds/doors/blizzard.sound", WorldPosition );
}
protected override void OnDestroy()
{
windSound?.Stop();
}
public override void Use( Player user )
{
if ( !CanUse )
return;
MansionGame.NextLevel();
SoundExtensions.BroadcastPlay( "sounds/doors/dooropen.sound", WorldPosition );
}
public override bool CheckUpgrades( Player player ) => player.HasUpgrade( KeyName );
}