BreakableDoor.cs

Placeholder

Really Bad Code
using Sandbox;
using System;
using System.Threading.Tasks;

public sealed class BreakableDoor : Component, Component.ITriggerListener
{
	[Property] public float MaxHealth { get; set; } = 2f;
	[Sync] public float CurrentHealth { get; set; } = 2f;
	[Sync] public bool IsBroken { get; set; } = false;

	[Property] public string HitSound { get; set; } = "music/buttonhover.sound";
	[Property] public string BreakSound { get; set; } = "music/buttonhover.sound";

	private Collider _collider;
	private ModelRenderer _modelRenderer;
	[Sync] private TimeSince _timeSinceLastHit { get; set; } = 1f;

	protected override void OnStart()
	{
		CurrentHealth = MaxHealth;
		_collider = Components.Get<Collider>() ?? Components.GetInChildren<Collider>();
		_modelRenderer = Components.Get<ModelRenderer>() ?? Components.GetInChildren<ModelRenderer>();
	}

	public void TakeHit( float amount = 1f )
	{
		if ( IsBroken ) return;

		CurrentHealth -= amount;
		_timeSinceLastHit = 0f;

		if ( !string.IsNullOrEmpty( HitSound ) )
		{
			Sound.Play( HitSound, WorldPosition );
		}

		CameraJuice.Instance?.Shake( 12f, 3f );

		if ( CurrentHealth <= 0f )
		{
			Break();
		}
	}

	public void Break()
	{
		if ( IsBroken ) return;
		IsBroken = true;

		if ( !string.IsNullOrEmpty( BreakSound ) )
		{
			Sound.Play( BreakSound, WorldPosition );
		}

		CameraJuice.Instance?.Shake( 26f, 6f );

		if ( _collider.IsValid() ) _collider.Enabled = false;
		if ( _modelRenderer.IsValid() ) _modelRenderer.Enabled = false;

		// Splinter burst effect
		SpawnDebris();

		Log.Info( $"[BreakableDoor] Door {GameObject.Name} was smashed open!" );
	}

	private void SpawnDebris()
	{
		for ( int i = 0; i < 3; i++ )
		{
			var debris = Scene.CreateObject();
			debris.Name = "Door_Splinter";
			debris.WorldPosition = WorldPosition + Vector3.Up * ( 20f * i );
			debris.WorldScale = new Vector3( 0.4f, 0.4f, 0.4f );

			var mr = debris.Components.Create<ModelRenderer>();
			mr.Model = Model.Load( "models/sbox_props/wooden_crate/wooden_crate.vmdl" ) ?? Model.Load( "models/dev/box.vmdl" );

			var col = debris.Components.Create<BoxCollider>();
			col.Scale = new Vector3( 20f, 20f, 20f );

			var rb = debris.Components.Create<Rigidbody>();
			rb.Velocity = Vector3.Random * 250f + Vector3.Up * 150f;

			_ = DestroyAfter( debris, 6f );
		}
	}

	private async Task DestroyAfter( GameObject go, float delay )
	{
		await Task.DelaySeconds( delay );
		if ( go.IsValid() ) go.Destroy();
	}

	public void OnTriggerEnter( Collider other )
	{
		if ( IsBroken || !other.GameObject.IsValid() ) return;

		// If a Nextbot hits the door, smash it
		var nextbot = other.GameObject.Root.Components.Get<NextbotAI>();
		if ( nextbot.IsValid() && _timeSinceLastHit > 0.8f )
		{
			TakeHit( 1f );
		}
	}
}