perks/PerkDrainUntil1Hp.cs

A Mythic perk class named PerkDrainUntil1Hp called "Blood Pact". It applies a damage multiplier and drains the player's health per second while the player is above 1 HP, toggling the drain on/off as health crosses the 1 HP threshold and updating a UI cooldown color while active.

NetworkingFile Access
[Perk( Rarity.Mythic, locked: true, alwaysOfferDebug: false )]
public class PerkDrainUntil1Hp : Perk
{
	private enum Mod { HealthDrain, OverallDamageMultiplier };

	private bool _isDraining;


	static PerkDrainUntil1Hp()
	{
		Register<PerkDrainUntil1Hp>(
			name: "Blood Pact",
			imagePath: "textures/icons/vector/drain_until_1hp.png",
			description: level => $"+{GetValue( level, Mod.OverallDamageMultiplier, true )}% dmg\n-{GetValue( level, Mod.HealthDrain ).ToString( "0.#" )} hp/s while over 1 hp",
			upgradeDescription: level => $"+{GetValue( level - 1, Mod.OverallDamageMultiplier, true )}%→{GetValue( level, Mod.OverallDamageMultiplier, true )}% dmg\n-{GetValue( level - 1, Mod.HealthDrain ).ToString("0.#")}→-{GetValue( level, Mod.HealthDrain ).ToString("0.#")} hp/s while over 1 hp"
		);
	}

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

		ShouldUpdate = true;
	}

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

		if ( Player.Health > 1f )
			EnableDraining();

		Player.Modify( this, PlayerStat.OverallDamageMultiplier, GetValue( Level, Mod.OverallDamageMultiplier ), ModifierType.Mult );
	}

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

		if ( _isDraining )
		{
			DisplayCooldownColor = Color.Lerp( new Color( 1f, 0f, 0f, 0.5f ), new Color( 1f, 1f, 0f, 0.5f ), 0.5f + Utils.FastSin( RealTime.Now * 24f ) * 0.5f );

			if ( !(Player.Health > 1f) )
				DisableDraining();
		}
		else
		{
			if ( Player.Health > 1f )
				EnableDraining();
		}
	}

	void EnableDraining()
	{
		Player.Modify( this, PlayerStat.HealthDrain, -GetValue( Level, Mod.HealthDrain ), ModifierType.Add );
		Player.Modify( this, PlayerStat.DrainUntil1Hp, 1f, ModifierType.Add );
		_isDraining = true;
		DisplayCooldown = 1f;
	}

	void DisableDraining()
	{
		Player.StopModifying( this, PlayerStat.HealthDrain );
		Player.StopModifying( this, PlayerStat.DrainUntil1Hp );
		_isDraining = false;
		DisplayCooldown = 0f;
	}

	private static float GetValue( int level, Mod mod, bool isPercent = false )
	{
		switch ( mod )
		{
			case Mod.HealthDrain:
			default:
				return 0.5f + 0.5f * level;
			case Mod.OverallDamageMultiplier:
				return isPercent
					? 9f + 6f * level
					: 1f + 0.09f + 0.06f * level;
		}
	}
}