charms/CharmLightning.cs

Charm component that spawns periodic lightning effects around the player. It manages particle prefabs, updates a timer to trigger a lightning bolt prefab every INTERVAL seconds, applies damage/chain settings to the bolt, and hides/shows particle visuals on death/revive.

NetworkingFile Access
using Sandbox;

public class CharmLightning : Charm
{
	public const string ItemId = "charm_lightning";

	private const float INTERVAL = 5f;
	private const float DAMAGE = 5f;
	private const int CHAINS = 20;

	private float _timer;

	private GameObject _particles;
	private ParticleEffect _particleRing;
	private ParticleRingEmitter _particleRingEmitter;
	private LightningParticleEffect _lightningParticleEffect;

	public static string Description() => $"Every {INTERVAL}s, lightning strikes for {(int)DAMAGE} damage and chains {CHAINS} times";

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

		_particles = GameObject.Clone( "prefabs/effects/lightning_target_particles.prefab", new global::Transform( Player.WorldPosition.WithZ( -100f ) ) );
		_particleRing = _particles.GetComponent<ParticleEffect>();
		_particleRing.Alpha = 0f;
		_particleRingEmitter = _particles.GetComponent<ParticleRingEmitter>();
		_particleRingEmitter.Rate = 0;
		_lightningParticleEffect = _particles.GetComponent<LightningParticleEffect>();

		_particles.NetworkSpawn();
	}

	public override void Update( float dt )
	{
		base.Update( dt );

		if ( Player.IsDead )
			return;

		_timer += dt;

		float progress = _timer / INTERVAL;

		var pos = Player.Position2D;
		_particles.WorldPosition = new Vector3( pos.x, pos.y, 2f );
		_particleRing.Alpha = Utils.Map( progress, 0f, 1f, 0f, 1f, EasingType.ExpoIn );
		_particleRingEmitter.Radius = Utils.Map( progress, 0f, 1f, 30f, 0f, EasingType.SineIn );
		_particleRingEmitter.Rate = 500;

		if ( _timer >= INTERVAL )
		{
			Strike( pos );

			_timer = 0f;
			_particles.WorldPosition = _particles.WorldPosition.WithZ( -100f );
			_particleRing.Alpha = 0f;
			_particleRingEmitter.Rate = 0;
			_lightningParticleEffect.ResetEffect();
		}
	}

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

		_particles.WorldPosition = _particles.WorldPosition.WithZ( -100f );
		_particleRing.Alpha = 0f;
		_particleRingEmitter.Rate = 0;
		_lightningParticleEffect.SetVisible( false );
	}

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

		_timer = 0f;
		_lightningParticleEffect.SetVisible( true );
	}

	void Strike( Vector2 pos )
	{
		var lightningBoltGo = GameObject.Clone( $"prefabs/lightning_bolt.prefab", new CloneConfig { StartEnabled = true, Transform = new Transform( new Vector3( pos.x, pos.y, -100f ) ) } );
		var lightningBolt = lightningBoltGo.GetComponent<LightningBolt>();
		lightningBolt.Shooter = Player;
		lightningBolt.Damage = DAMAGE;
		lightningBolt.SpreadLimit = CHAINS;

		lightningBoltGo.NetworkSpawn( Player.Network.Owner );
	}

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

		if ( _particles != null )
			_particles.Destroy();
	}
}