things/enemies/Mushroom.cs

Enemy subclass for a Mushroom enemy. It configures stats, movement-disabled behavior, proximity-triggered explosion logic, visuals and death effects.

Networking
using System;
using System.Numerics;
using Sandbox;

public class Mushroom : Enemy
{
	public override EnemyType EnemyType => EnemyType.Mushroom;
	public override float GetMaxHealth()
	{
		return 250f;
	}

	[Property] public Material MushroomExplodeFlashMaterial { get; set; }

	public override Vector3 SpawnScale => new Vector3( 4f, 4f, 5f );
	public override bool CanHaveTarget => false;
	public override bool CanAttack => false;
	public override bool CanTurn => false;
	public override bool CanBeBackstabbed => false;
	public override bool CountsAsKill => false;
	public override bool CanMove => false;
	public override bool CanBeTargeted => false;

	private float _explodeRange;

	protected override void OnStart()
	{
		base.OnStart();

		CoinValueMin = 1;
		CoinValueMax = 2;
		CoinChance = 0.75f;

		PushStrength = 16000f;
		Weight = 6f;

		ExplodeFlashMaterial = MushroomExplodeFlashMaterial;

		if ( IsProxy )
			return;

		Deceleration = 4.5f;

		_explodeRange = Game.Random.Float( 60f, 150f );
	}

	protected override void OnUpdate()
	{
		base.OnUpdate();

		//Gizmo.Draw.Color = Color.White;
		//Gizmo.Draw.Text( $"IsExploding: {IsExploding}", new global::Transform( WorldPosition ) );

		if ( IsProxy || IsDying || IsSpawning )
			return;

		Velocity *= Math.Max( 1f - Time.Delta * Deceleration * Manager.Instance.GlobalFrictionModifier, 0f );

		WorldPosition += (Vector3)Velocity * Time.Delta;

		if( !IsExploding )
		{
			foreach ( var player in Manager.Instance.AlivePlayers )
			{
				var dist_sqr = (Position2D - player.Position2D).LengthSquared;
				var req_dist_sqr = MathF.Pow( _explodeRange, 2f );

				if ( dist_sqr < req_dist_sqr )
				{
					if( player.IsValid() )
						player.OnDisturbMushroom();

					// todo: sfx

					StartExplodingRpc( 
						time: Game.Random.Float( 0.5f, 2f), 
						radius: Game.Random.Float(130f, 200f), 
						damage: 0f, 
						player: null 
					);

					break;
				}
			}
		}
	}

	public override void Explode()
	{
		Manager.Instance.SpawnRingRpc( Position2D, _explosionRadius, new Color( 0.6f, 0.1f, 1f, 0.8f ), lifetime: Game.Random.Float( 0.2f, 0.3f ), path: "ring_mushroom" );

		Manager.Instance.PlaySfxNearbyRpc( "enemy.explode", Position2D, pitch: Game.Random.Float( 2.2f, 2.5f ), volume: 0.8f, maxDist: 750f );

		Manager.Instance.AffectInRadius( Position2D, _explosionRadius, damage: 0f, repelRadius: _explosionRadius, repelForce: Game.Random.Float( 750f, 1100f ), options: RepelOptions.RepelPlayers | RepelOptions.RepelEnemies | RepelOptions.RepelItems );

		DieRpc( dir: Vector2.Zero, force: 4f, player: _playerWhoKilledUs, damageType: DamageType.Explosion );
	}

	public override void Flinch( float time, Vector2 dir )
	{
		base.Flinch( time, dir );

		ModelRenderer.LocalRotation = new Angles(Game.Random.Float(-6f, 6f), 0f, Game.Random.Float(-6f, 6f));
	}

	public override void StopFlinching()
	{
		base.StopFlinching();

		ModelRenderer.LocalRotation = new Angles(0f, 0f, 0f);
	}

	public override void SetAnim( string name, bool forceRestart = false )
	{
		return;
	}

	//protected override void ResetMaterial()
	//{
	//	ModelRenderer.ClearMaterialOverrides();
	//	ModelRenderer.RenderType = Sandbox.ModelRenderer.ShadowRenderType.On;
	//}

	protected override void SpawnGibs( Vector2 dir, float force, DamageType damageType )
	{
		
	}

}