perks/PerkFullHealthAoe.cs

Perk class that triggers when the player is at full health. It costs the player 50% of max HP, spawns a visual ring, and deals configurable area damage and repulsion to nearby enemies based on perk level and player stats.

Networking
using System;
using Sandbox;
using Sandbox.UI;

[Perk( Rarity.Mythic, locked: true, minUnlocksReq: 1, alwaysOfferDebug: false, IncludedCategories = new[] { PerkCategory.Aoe, PerkCategory.SelfDmg })]
public class PerkFullHealthAoe : Perk
{
	private const float DAMAGE_RADIUS = 165f;

	private enum Mod { DamageAmount };


	static PerkFullHealthAoe()
	{
		Register<PerkFullHealthAoe>(
			name: "Perfect Fury",
			imagePath: "textures/icons/vector/full_hp_aoe.png",
			description: level => $"When at full hp, get -50% hp and do {(int)GetValue( level, Mod.DamageAmount )} dmg to nearby enemies",
			upgradeDescription: level => $"When at full hp, get -50% hp and do {(int)GetValue( level - 1, Mod.DamageAmount, true )}→{(int)GetValue( level, Mod.DamageAmount )} dmg to nearby enemies"
		);
	}

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

		ShouldUpdate = true;

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

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

	}

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

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

		if ( !(Player.Health < Player.Stats[PlayerStat.MaxHp]) )
		{
			Player.Damage( Player.Stats[PlayerStat.MaxHp] * 0.5f, DamageType.Self, hitPos: Player.Position2D, Utils.GetRandomVector(), upwardAmount: 0f, force: 0f, ragdollForce: 1f, enemySource: null, enemyType: EnemyType.None );

			Vector2 pos = Player.Position2D;
			float dmg = GetValue( Level, Mod.DamageAmount );
			float radius = DAMAGE_RADIUS * Player.Stats[PlayerStat.RadiusMultiplier];
			var force = dmg * 10f;

			// todo: better sfx
			// todo: prevent explosion from playing so many death sfx
			// todo better vfx

			Manager.Instance.SpawnRingRpc( pos, radius, new Color( 1f, 0.7f, 1f, 0.2f ), lifetime: Game.Random.Float( 0.15f, 0.2f ), path: "ring_spiky_2_b" );

			//Manager.Instance.DamageInRadiusHost( pos, radius, dmg, radius * 1.1f, force, Player, DamageType.Aoe, damagePlayers: false );
			Manager.Instance.AffectInRadiusHost( Player.Position2D, radius * 1.1f, dmg, repelRadius: radius * 1.2f, force, Player, enemySource: null, enemyType: EnemyType.None, DamageType.Aoe, options: RepelOptions.DamageEnemies | RepelOptions.RepelEnemies | RepelOptions.RepelItems );

			Highlight();
		}
	}
}