perks/CurseRerollAuto.cs

A unique curse perk named Indecision that automatically rerolls the player's level-up reward after a fixed time. It tracks a countdown while the player is choosing a reward, updates visual cooldown/highlight values, and triggers Player.UseReroll() when the timer exceeds the time limit.

Networking
using System;
using Sandbox;

[Perk( Rarity.Unique, curse: true, alwaysOfferDebug: false )]
public class CurseRerollAuto : Perk
{
	private enum Mod { TimeLimit };

	private RealTimeSince _timeSinceTrigger;
	public float TimerProgress { get; private set; }

	static CurseRerollAuto()
	{
		Register<CurseRerollAuto>(
			name: "Indecision",
			imagePath: "textures/icons/vector/curse_reroll_auto.png",
			description: level => $"You automatically reroll after {(int)GetValue( level, Mod.TimeLimit )}s"
		);
	}

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

		ShouldUpdate = true;
		_timeSinceTrigger = 0f;
		TimerProgress = 0f;

		HighlightColor = new Color( 0.7f, 0.3f, 1f );
		HighlightDuration = 0.3f;
		HighlightOpacity = 4f;

		DisplayCooldownColor = new Color( 0.6f, 0.25f, 0.9f, 0.65f );
	}

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

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

		if ( Player.IsChoosingLevelUpReward && Player.CanReroll() )
		{
			TimerProgress = Utils.Map( _timeSinceTrigger, 0f, GetValue( Level, Mod.TimeLimit ), 0f, 1f );
			DisplayCooldown = TimerProgress;
			DisplayCooldownColor = Color.Lerp(
				new Color( 0.5f, 0.2f, 0.85f, 0.6f ),
				new Color( 1f, 0.2f, 0.9f, 0.85f ),
				TimerProgress
			);

			if ( _timeSinceTrigger > GetValue( Level, Mod.TimeLimit ) )
			{
				Player.UseReroll();
				_timeSinceTrigger = 0f;
				TimerProgress = 0f;
				DisplayCooldown = 0f;

				Highlight();
				IconScale = Game.Random.Float( 1.1f, 1.2f );
				IconAngleOffset = Game.Random.Float( 5f, 15f ) * (Game.Random.Int( 0, 1 ) == 0 ? -1f : 1f);
			}
		}
		else
		{
			TimerProgress = 0f;
			DisplayCooldown = 0f;

			if ( Player.IsChoosingLevelUpReward )
				_timeSinceTrigger = 0f;
		}
	}

	public override void OnChoosePerk( TypeDescription type )
	{
		base.OnChoosePerk( type );
		_timeSinceTrigger = 0f;
	}

	public override void OnRerollAfter()
	{
		base.OnRerollAfter();
		_timeSinceTrigger = 0f;
	}

	public override void OnPlayerLevelUp()
	{
		base.OnPlayerLevelUp();
		if ( Player.NumPerkPointsAvailable <= 1 )
			_timeSinceTrigger = 0f;
	}

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

		_timeSinceTrigger = 0f;
	}

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