Scene component representing the final exit door in the map. Displays a hover prompt based on whether the local player has bought an "Exit Key", checks that all alive players are within range to allow use, awards escape stats/achievements to alive players, credits the level escape and restarts the game when used. Also includes a Create helper that spawns the door GameObject with model, collider and tags.
using System.Linq;
using Sandbox;
namespace BrickJam;
/// <summary>
/// Final level exit (end of a run). Scene-System port of legacy <c>FinalDoor</c>. Spawned at runtime
/// by the Bathrooms level at a <see cref="ValidFinalDoorPosition"/>.
/// </summary>
[Title( "Final Door" )]
[Category( "Map" )]
public sealed partial class FinalDoor : LegacyUsableComponent
{
public override float InteractionDuration { get; set; } = 1.7f;
public override string UseString
{
get => HasKey
? (CanUse ? "exit the mansion" : "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 );
// Hover prompt shown on the LOCAL client - check the local player, not the host-side User (which is null
// while merely hovering, so it always said "buy the key" even when owned). Use gate = CheckUpgrades.
public bool HasKey => Player.Local?.HasUpgrade( "Exit Key" ) ?? false;
public static FinalDoor Create( Vector3 position, Rotation rotation )
{
var go = new GameObject( true, "FinalDoor" );
go.WorldPosition = position;
go.WorldRotation = rotation;
go.Tags.Add( "door", "usable" );
var model = Model.Load( "models/furniture/exit_door.vmdl" );
go.Components.Create<ModelRenderer>().Model = model;
go.Components.Create<ModelCollider>().Model = model;
var door = go.Components.Create<FinalDoor>();
go.NetworkSpawn();
return door;
}
public override void Use( Player user )
{
// Escaped! Credit every survivor (Services stat + achievement), then end the run.
foreach ( var p in Scene.GetAllComponents<Player>().Where( x => x.IsAlive ) )
{
p.TrackStat( GameStats.Escapes, 1 );
p.TrackAchievement( GameStats.AchEscape );
// Hoarder's Paradise: extracted with a completely full inventory.
if ( p.Inventory is { } inv && inv.Count >= inv.Limit )
p.TrackAchievement( GameStats.AchHoardersParadise );
}
// Grand Tour (Bathrooms leg) + Left For Dead, same crediting as a trapdoor escape.
MansionGame.CreditLevelEscape( LevelType.Bathrooms );
MansionGame.RestartGame(); // TODO: Give bonus / show ending
}
public override bool CheckUpgrades( Player player ) => player.HasUpgrade( "Exit Key" );
}