perks/PerkDashPlayerHeal.cs

A perk class that heals nearby players when the owner finishes a dash. It spawns a visual ring and iterates alive players, healing those within a radius (excluding the owner) up to their max HP.

Networking
using System;
using Sandbox;

[Perk( Rarity.Rare, multiplayerMode: MultiplayerMode.OnlyMultiplayer, alwaysOfferDebug: false, IncludedCategories = new[] { PerkCategory.Aoe })]
public class PerkDashPlayerHeal : Perk
{
	private enum Mod { HpAmount };

	public const float HEAL_RADIUS = 100f;


	static PerkDashPlayerHeal()
	{
		Register<PerkDashPlayerHeal>(
			name: "Lifesaver",
			imagePath: "textures/icons/vector/dash_heal_player.png",
			description: level => $"Heal nearby players for\n{(int)GetValue( level, Mod.HpAmount )} hp when you dash",
			upgradeDescription: level => $"Heal nearby players for\n{(int)GetValue( level - 1, Mod.HpAmount )}→{(int)GetValue( level, Mod.HpAmount )} hp when you dash"
		);
	}
	
	public override void Start()
	{
		base.Start();

		HighlightColor = new Color( 0.8f, 1f, 0.8f );
		HighlightDuration = 0.4f;
		HighlightOpacity = 1.5f;
	}

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

	}

	public override void OnDashFinished( Vector2 dir )
	{
		base.OnDashFinished( dir );

		Vector2 pos = Player.Position2D;
		float radius = HEAL_RADIUS * Player.Stats[PlayerStat.RadiusMultiplier];
		Manager.Instance.SpawnRingRpc( Player.Position2D, radius, new Color( 0.1f, 1f, 0.1f, 0.5f ), lifetime: 0.35f, path: "ring2" );

		foreach ( Player player in Manager.Instance.AlivePlayers )
		{
			if ( player == Player )
				continue;

			if ( (player.Position2D - pos).LengthSquared < MathF.Pow( radius, 2f ) && player.Health < player.GetSyncStat(PlayerStat.MaxHp) )
			{
				player.HealRpc( GetValue( Level, Mod.HpAmount ), playSfx: true, Player );
				Highlight();
			}
		}
	}

	private static float GetValue( int level, Mod mod, bool isPercent = false )
	{
		switch ( mod )
		{
			case Mod.HpAmount:
			default:
				return 3f + 2f * level;
		}
	}
}