status/RerollAttackSpeedStatus.cs
using System;
using System.Collections.Generic;
using System.Linq;
using Sandbox;

[Status(7, 0, 1f, maxDifficulty: 2, isCurse: false )]
public class RerollAttackSpeedStatus : Status
{
	private enum Mod { Speed, Time };

	private Queue<float> _rerollTimes = new();

	private float _currStartTime;

	public RerollAttackSpeedStatus()
    {
		Title = "Stim Injection";
		IconPath = "textures/icons/reroll_attack_speed.png";
	}

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

		ShouldUpdate = true;
	}

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

	public override string GetDescription( int newLevel )
	{
		return $"When you reroll, get +{GetValue( newLevel, Mod.Speed, true )}% attack/reload/move speed and for {string.Format( "{0:0.0}", GetValue( newLevel, Mod.Time ) )}s";
	}

	public override string GetUpgradeDescription( int newLevel )
	{
		return newLevel > 1 ? $"When you reroll, get +{GetValue( newLevel - 1, Mod.Speed, true )}%→{GetValue( newLevel, Mod.Speed, true )}% attack/reload/move speed for {string.Format( "{0:0.0}", GetValue( newLevel - 1, Mod.Time ) )}→{string.Format( "{0:0.0}", GetValue( newLevel, Mod.Time ) )}s" : GetDescription( newLevel );
	}

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

		if ( _rerollTimes.Count > 0 )
		{
			var rerollTime = _rerollTimes.Peek();
			if ( Time.Now > rerollTime + GetValue( Level, Mod.Time ) )
			{
				_rerollTimes.Dequeue();
				RefreshBuffs();
				_currStartTime = Time.Now;
				//DisplayCooldown = 0f;
			}
			else
			{
				//DisplayCooldown = Utils.Map( Time.Now, _currStartTime, rerollTime + GetValue( Level, Mod.Time ), 1f, 0f );
			}
		}

		float buffPercent = _rerollTimes.Count * GetValue( Level, Mod.Speed, true );
		DataString = _rerollTimes.Count > 0 ? $"{buffPercent}%" : " ";
	}

	public override void OnReroll()
    {
		if ( _rerollTimes.Count == 0 )
			_currStartTime = Time.Now;

		_rerollTimes.Enqueue( Time.Now );

		RefreshBuffs();
	}

	void RefreshBuffs()
	{
		float speed = 1f + _rerollTimes.Count * GetValue( Level, Mod.Speed );

		Player.Modify( this, PlayerStat.AttackSpeed, speed, ModifierType.Mult );
		Player.Modify( this, PlayerStat.ReloadSpeed, speed, ModifierType.Mult );
		Player.Modify( this, PlayerStat.MoveSpeed, speed, ModifierType.Mult );
	}

	private float GetValue( int level, Mod mod, bool isPercent = false )
	{
		switch ( mod )
		{
			case Mod.Speed:
			default:
				return isPercent
					? 18f + 2f * level
					: 0.18f + 0.02f * level;
			case Mod.Time:
				return 2.7f + 0.3f * level;
		}
	}
}