A Perk class named PerkArmorHurtHp (Bloodsteel). When the player loses HP and the perk is ready, it grants that much armor (integer of the damage amount) and starts a cooldown; it updates UI cooldown, highlight and icon effects.
using System;
using Sandbox;
[Perk( Rarity.Epic, locked: true, alwaysOfferDebug: false, IncludedCategories = new[] { PerkCategory.Armor })]
public class PerkArmorHurtHp : Perk
{
private enum Mod { Cooldown };
private bool _isReady = true;
private TimeSince _timeSinceActivate;
static PerkArmorHurtHp()
{
Register<PerkArmorHurtHp>(
name: "Bloodsteel",
imagePath: "textures/icons/vector/armor_hurt_hp.png",
description: level => $"When you lose hp,\nget that much armor-item\n(cooldown: {GetValue( level, Mod.Cooldown ).ToString( "0.#" )}s)",
upgradeDescription: level => $"When you lose hp,\nget that much armor-item\n(cooldown: {GetValue( level - 1, Mod.Cooldown ).ToString( "0.#" )}→{GetValue( level, Mod.Cooldown ).ToString( "0.#" )}s)"
);
}
public override void Start()
{
base.Start();
}
public override void IncreaseLevel()
{
base.IncreaseLevel();
if ( Level > 1 && !_isReady )
ReadyFx();
_isReady = true;
ShouldUpdate = false;
DisplayText = " ";
DisplayCooldown = 0f;
}
public override void Refresh()
{
base.Refresh();
}
void ReadyFx()
{
Manager.Instance.PlaySfxUI( "armor_hurt_hp_ready", pitch: Game.Random.Float( 0.95f, 1.05f ), volume: 0.75f );
HighlightColor = new Color( 0.7f, 0.5f, 1f, 0.75f );
HighlightDuration = 0.25f;
HighlightOpacity = 3f;
Highlight();
IconScale = Game.Random.Float( 1.2f, 1.3f );
IconAngleOffset = Game.Random.Float( 10f, 20f ) * (Game.Random.Int( 0, 1 ) == 0 ? -1f : 1f);
// todo: show particle vfx or something
}
public override void Update( float dt )
{
base.Update( dt );
float cooldown = GetValue( Level, Mod.Cooldown );
if ( _timeSinceActivate > cooldown )
{
_isReady = true;
ShouldUpdate = false;
DisplayText = " ";
DisplayCooldown = 0f;
ReadyFx();
}
else
{
DisplayCooldown = Utils.Map( _timeSinceActivate, 0f, cooldown, 1f, 0f );
DisplayText = $"{MathX.CeilToInt( cooldown - _timeSinceActivate )}";
}
}
public override void OnHurt( float amount, DamageType damageType, bool isSelfInflicted, Vector2 dir, Enemy enemySource, EnemyType enemyType, float previousHealth )
{
base.OnHurt( amount, damageType, isSelfInflicted, dir, enemySource, enemyType, previousHealth );
if ( !_isReady || amount <= 0f )
return;
Player.GainArmor( (int)amount );
_timeSinceActivate = 0f;
_isReady = false;
ShouldUpdate = true;
HighlightColor = new Color( 0.7f, 0.5f, 1f, 0.75f );
HighlightDuration = 0.3f;
HighlightOpacity = 3f;
Highlight();
IconScale = Game.Random.Float( 1.2f, 1.3f );
IconAngleOffset = Game.Random.Float( 10f, 20f ) * (Game.Random.Int( 0, 1 ) == 0 ? -1f : 1f);
}
private static float GetValue( int level, Mod mod, bool isPercent = false )
{
switch ( mod )
{
case Mod.Cooldown:
default:
return 30f - 5f * level;
}
}
}