perks/PerkArmorBuffer.cs

A perk component that grants the player periodic armor while their armor is below a level-dependent cap. It registers metadata (name, icon, descriptions), increments an internal timer in Update, gives 1 armor every 3 seconds up to MaxArmor (level*2), and updates UI highlight and icon animation values.

Networking
using System;
using Sandbox;

[Perk( Rarity.Uncommon, alwaysOfferDebug: false, IncludedCategories = new[] { PerkCategory.Armor })]
public class PerkArmorBuffer : Perk
{
	private enum Mod { MaxArmor };

	private float _timer;

	private const float DELAY = 3f;


	static PerkArmorBuffer()
	{
		Register<PerkArmorBuffer>(
			name: "Armor Buffer",
			imagePath: "textures/icons/vector/armor_buffer.png",
			description: level => $"+1 armor-item every {DELAY}s while\nbelow {(int)GetValue( level, Mod.MaxArmor )} armor-item",
			upgradeDescription: level => $"+1 armor-item every {DELAY}s while\nbelow {(int)GetValue( level - 1, Mod.MaxArmor )}→{(int)GetValue( level, Mod.MaxArmor )} armor-item"
		);
	}

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

		ShouldUpdate = true;

		HighlightColor = new Color( 0.9f, 0.9f, 1f );
		HighlightDuration = 0.2f;
		HighlightOpacity = 0.5f;
	}

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

	}

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

		var maxArmor = (int)GetValue( Level, Mod.MaxArmor );

		if ( Player.Armor < maxArmor )
		{
			_timer += dt;
			if ( _timer >= DELAY )
			{
				Player.GainArmor( 1 );
				_timer = 0f;

				Highlight();

				IconScale = Game.Random.Float( 1.1f, 1.15f );
				IconAngleOffset = Game.Random.Float( 5f, 8f ) * (Game.Random.Int( 0, 1 ) == 0 ? -1f : 1f);
			}
		}
		else
		{
			_timer = 0f;
		}

		DisplayCooldown = Player.Armor < maxArmor ? Utils.Map( _timer, 0f, 1f, 0f, 1f ) : 0f;
	}

	private static float GetValue( int level, Mod mod, bool isPercent = false )
	{
		switch ( mod )
		{
			case Mod.MaxArmor:
			default:
				return level * 2;
		}
	}
}