status/CurseSamePerkDmgStatus.cs
using System;
using System.Collections.Generic;
using System.Linq;
using Sandbox;
using static Sandbox.VertexLayout;

[Status( 4, 0, 1f, 0, true )]
public class CurseSamePerkDmgStatus : Status
{
	private float _totalMaxHpLost;

	public CurseSamePerkDmgStatus()
	{
		Title = "Obsessive";
		IconPath = "textures/icons/curse_same_perk_dmg.png";
	}

	public override void Init( Player player )
	{
		base.Init( player );
	}

	public override void Refresh()
	{
		Description = GetDescription( Level );

	}

	public override void OnAddStatus( int typeIdentity )
	{
		base.OnAddStatus( typeIdentity );

		if ( Player.Statuses.ContainsKey( typeIdentity ) )
		{
			if ( Player.Stats[PlayerStat.MaxHp] <= 1f )
				return;

			var maxHpToLose = Math.Max( (int)Math.Round( Player.Stats[PlayerStat.MaxHp] * GetAmountForLevel( Level ) * 0.01f ), 1 );

			_totalMaxHpLost += maxHpToLose;

			Player.Modify( this, PlayerStat.MaxHp, -_totalMaxHpLost, ModifierType.Add );

			if ( Player.Health > Player.Stats[PlayerStat.MaxHp] )
				Player.Health = Player.Stats[PlayerStat.MaxHp];

			Manager.Instance.PlaySfxNearby( "zombie.attack.player", Player.Position2D, pitch: Game.Random.Float( 0.7f, 0.75f ), volume: 0.9f, maxDist: 3f );

			Manager.Instance.SpawnFloaterParticle( Player.Position2D + new Vector2( 0f, 0.2f ), $"-{maxHpToLose} MAX HP", new Color( 1f, 0.4f, 0.4f ) );
		}
	}

	public override string GetDescription( int newLevel )
	{
		return string.Format( "When you choose a perk you already have, lose {0}% of your max HP", GetAmountForLevel( Level ) );
	}

	public override string GetUpgradeDescription( int newLevel )
	{
		return newLevel > 1 ? string.Format( "When you choose a perk you already have, lose {0}%→{1}% of your max HP", GetAmountForLevel( newLevel - 1 ), GetAmountForLevel( newLevel ) ) : GetDescription( newLevel );
	}

	public float GetAmountForLevel( int level )
	{
		return 5 * level;
	}
}