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.
[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;
}
}
}