things/items/BanishItem.cs

An in-game pickup item class named BanishItem that extends Item. It sets lifetime, physics properties, and animates rotation/scale over time; when a Player collides it grants a banish (player.AddBanish), plays a nearby sfx, triggers a collect effect, and removes itself.

Networking
using System;
using Sandbox;
using Sandbox.Diagnostics;
using Sandbox.Utility;

public class BanishItem : Item
{
	private float _rotateTimeOffset;
	private float _personalRotateSpeed;

	public override Vector3 SpawnScale => new Vector3( 0.8f );

	private Vector3 _baseRotation;
	protected override float AttractRangeFactor => 1f;
	protected override float AttractStrengthFactor => 0.6f;

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

		Lifetime = 70f;
		ShouldCheckBounds = true;
		PushStrength = 500f;

		BaseZPos = 5f;
		WorldPosition = WorldPosition.WithZ( BaseZPos );

		if ( IsProxy )
			return;

		Deceleration = 0.92f;

		_rotateTimeOffset = Game.Random.Float( 0f, 10f );
		_personalRotateSpeed = Game.Random.Float( 4f, 8f );

		_baseRotation = new Vector3( 90f, 0f, 0f );
	}

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

		if ( Manager.Instance.IsGameOver )
			return;

		if ( IsProxy )
			return;

		LocalRotation = Rotation.From( new Angles( _baseRotation.x, _baseRotation.y, _baseRotation.z + Utils.FastSin( _rotateTimeOffset + Time.Now * _personalRotateSpeed ) * 7f ) );

		LocalScale = new Vector3( 0.7f + Utils.FastSin( _rotateTimeOffset + Time.Now * _personalRotateSpeed * 2f ) * 0.05f, 0.8f, 0.8f );

		if ( !IsInTheAir )
			WorldPosition = WorldPosition.WithZ( BaseZPos + 3f + Utils.MapReturn( Utils.FastSin( _rotateTimeOffset + Time.Now * _personalRotateSpeed ), -1f, 1f, -1f, 1f, EasingType.Linear ) * 3f );
	}

	public override void Colliding( Thing other, float percent, float dt )
	{
		base.Colliding( other, percent, dt );

		if ( CantBeCollected )
			return;

		if ( other is Player player )
		{
			if ( !player.IsDead )
			{
				player.AddBanish();

				// todo: different sfx
				Manager.Instance.PlaySfxNearbyRpc( "heal", player.Position2D, pitch: Game.Random.Float( 1.6f, 1.7f ), volume: 1.1f, maxDist: 350f );

				player.CollectItemEffect();

				Remove();
			}
		}
	}
}