perks/PerkSelfDmgAoe.cs

A rare perk called "Voodoo Doll" that triggers when the player takes self-inflicted damage. It calculates an AOE damage based on a percent of the self-damage, applies that damage to nearby enemies, spawns a visual ring effect, and sets some highlight visuals on start.

Networking
using System;
using Sandbox;

[Perk( Rarity.Rare, includedAtStart: false, locked: true, alwaysOfferDebug: false, IncludedCategories = new[] { PerkCategory.Aoe })]
public class PerkSelfDmgAoe : Perk
{
	private enum Mod { DamagePercent };

	private const float RADIUS = 180f;


	static PerkSelfDmgAoe()
	{
		Register<PerkSelfDmgAoe>(
			name: "Voodoo Doll",
			imagePath: "textures/icons/vector/self_dmg_aoe.png",
			description: level => $"Hurt nearby enemies for\n{(int)GetValue( level, Mod.DamagePercent, true )}% of self dmg taken",
			upgradeDescription: level => $"Hurt nearby enemies for\n{(int)GetValue( level - 1, Mod.DamagePercent, true )}%→{(int)GetValue( level, Mod.DamagePercent, true )}% of self dmg taken"
		);
	}

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

		HighlightColor = new Color( 0.75f, 0f, 1f );
		HighlightDuration = 0.25f;
		HighlightOpacity = 2f;
	}

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

	}

	private static float GetValue( int level, Mod mod, bool isPercent = false )
	{
		switch ( mod )
		{
			case Mod.DamagePercent:
			default:
				return isPercent
					? 70f + 40f * level
					: 0.70f + 0.40f * level;
		}
	}

	public override void OnHit( float amount, DamageType damageType, bool isSelfInflicted, Vector2 dir, float force, Enemy enemySource, EnemyType enemyType, float previousHealth )
	{
		base.OnHit( amount, damageType, isSelfInflicted, dir, force, enemySource, enemyType, previousHealth );

		if ( damageType != DamageType.Self )
			return;

		float damage = amount * GetValue( Level, Mod.DamagePercent );
		float radius = RADIUS * Player.Stats[PlayerStat.RadiusMultiplier];

		Manager.Instance.DamageNearbyEnemies( Player.Position2D, radius, damage, force: damage * 10f, DamageType.Aoe, Player );
		Manager.Instance.SpawnRingRpc( Player.Position2D, radius, new Color( 1f, 0.3f, 0.7f, 0.1f ), 0.25f, path: "ring_spiky_2_b", useRealtime: Manager.Instance.IsPausedForChoosing );

		Highlight();
	}
}