Map entity component definitions for legacy map objects. Defines DoorState enum and several components used by map-placed entities (usable components, player spawn, loot spawners, door behaviour and simple markers). It sets up default properties, sync fields, interaction behaviour, and initializes a LockedComponent when StartLocked is used and a model has a lock attachment.
using Sandbox;
namespace BrickJam;
public enum DoorState : sbyte
{
Opening = 1,
Closing = -1,
Open = 2,
Closed = 3,
}
public abstract partial class LegacyMapComponent : Component
{
public Vector3 Position => GameObject.WorldPosition;
public Rotation Rotation => GameObject.WorldRotation;
}
public abstract partial class LegacyUsableComponent : LegacyMapComponent
{
[Property] public virtual float InteractionDuration { get; set; } = 1f;
[Property] public virtual string UseString { get; set; } = "use";
/// <summary>Can this be interacted with right now?</summary>
public virtual bool CanUse => true;
/// <summary>Whether the interaction hint should sit at the world centre of the object.</summary>
public virtual bool ShouldCenterInteractionHint => true;
/// <summary>Prompt shown while the object is locked.</summary>
public virtual string LockText => "lockpick";
/// <summary>Whether the object starts locked when spawned.</summary>
public virtual bool StartLocked => false;
/// <summary>Replicated locked state (lock object/lockpicking deferred to the interactions system).</summary>
[Sync] public bool Locked { get; set; }
/// <summary>The player currently interacting with this object. Host-side bookkeeping for now.</summary>
public Player User { get; set; }
/// <summary>Upgrade gate hook; defaults to allowing use. The upgrades system refines this later.</summary>
public virtual bool CheckUpgrades( Player user ) => true;
/// <summary>Invoked when an interaction completes. Overridden by concrete usables.</summary>
public virtual void Use( Player user ) { }
protected override void OnAwake()
{
// Every usable must carry the "usable" tag so the player's interaction trace
// (Scene.Trace...WithTag("usable")) can find it - including map-placed doors/shops.
GameObject.Tags.Add( "usable" );
}
protected override void OnStart()
{
if ( !Networking.IsHost || !StartLocked )
return;
// Legacy parity (UsableEntity.OnNewModel): a StartLocked usable spawns locked, and gets a
// physical padlock when its model exposes a "lock" attachment. Without this, ShopDoor.StartLocked
// was dead - the mansion door spawned openable and the lockpick-to-proceed loop never triggered.
Locked = true;
var attachment = Components.Get<ModelRenderer>()?.Model?.Attachments.Get( "lock" );
if ( attachment is not null )
Components.GetOrCreate<LockedComponent>().Initialize( attachment.LocalTransform );
}
}
public sealed partial class PlayerSpawn : LegacyMapComponent
{
[Property] public LevelType LevelType { get; set; } = LevelType.None;
}
public sealed partial class ValidTrapdoorPosition : LegacyMapComponent
{
[Property] public LevelType LevelType { get; set; } = LevelType.None;
}
public sealed partial class ValidFinalDoorPosition : LegacyMapComponent
{
}
public sealed partial class LootSpawner : LegacyMapComponent
{
[Property] public LootPrefab LootToSpawn { get; set; }
[Property] public bool IsContainer { get; set; }
[Property] public float ChanceToSpawn { get; set; } = 0.5f;
[Property] public LevelType LevelType { get; set; } = LevelType.None;
}
public sealed partial class PissingGuySpawner : LegacyMapComponent
{
[Property] public float ChanceToSpawn { get; set; } = 0.35f;
}
public sealed partial class Door : LegacyUsableComponent
{
[Property, Sync] public DoorState State { get; set; } = DoorState.Closed;
[Property] public LevelType LevelType { get; set; } = LevelType.None;
[Property] public bool AlternativeModel { get; set; }
[Property] public override float InteractionDuration { get; set; } = 0.3f;
public override string UseString
{
get => (State == DoorState.Open || State == DoorState.Opening) ? "close the door" : "open the door";
set { }
}
}
public sealed partial class SlipperySign : LegacyMapComponent
{
}