perks/PerkChooseTimeLimit.cs

A legendary perk component named "Urgency" that gives extra rerolls on level-up and enforces a time limit for choosing perks. It applies stat modifiers, tracks time since perk offer, and when the player exceeds the choose-time limit it picks a random perk choice, awards it, plays a UI sound, and shows a chat message.

NetworkingFile Access
using System;
using Sandbox;

[Perk( Rarity.Legendary, locked: true, alwaysOfferDebug: false )]
public class PerkChooseTimeLimit : Perk
{
	private enum Mod { NumRerolls, TimeLimit };

	private RealTimeSince _timeSinceTrigger;

	static PerkChooseTimeLimit()
	{
		Register<PerkChooseTimeLimit>(
			name: "Urgency",
			imagePath: "textures/icons/vector/choose_time_limit.png",
			description: level => $"+{(int)GetValue( level, Mod.NumRerolls )} reroll-item on level-up\n[-]{(int)GetValue( level, Mod.TimeLimit )}s[/-] time limit to choose perks",
			upgradeDescription: level => $"+{(int)GetValue( level - 1, Mod.NumRerolls )}→{(int)GetValue( level, Mod.NumRerolls )} reroll-item on level-up\n[-]{(int)GetValue( level, Mod.TimeLimit )}s[/-] time limit to choose perks"
		);
	}

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

		ShouldUpdate = true;
		_timeSinceTrigger = 0f;

		HighlightColor = new Color( 1f, 0f, 0f );
		HighlightDuration = 0.5f;
		HighlightOpacity = 3f;
	}

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

		Player.Modify( this, PlayerStat.NumRerollsPerLevel, GetValue( Level, Mod.NumRerolls ), ModifierType.Add );
		Player.Modify( this, PlayerStat.ChooseTimeLimit, GetValue( Level, Mod.TimeLimit ), ModifierType.Add );
	}

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

		if ( Player.IsChoosingLevelUpReward && _timeSinceTrigger > 0.5f && Player.RealTimeSinceOfferedChoices > GetValue( Level, Mod.TimeLimit ) && Player.CurrentPerkChoices != null )
		{
			var type = Player.CurrentPerkChoices[Game.Random.Int( 0, Player.CurrentPerkChoices.Count - 1 )];

			Player.AddPerkUIChoice( type );

			Manager.Instance.PlaySfxUI( "click", pitch: Utils.Map( Player.NumPerkPointsAvailable, 0, 10, 1f, 0.8f, EasingType.QuadIn ), volume: 0.75f );

			Manager.Instance.Chat.AddLocalChatMessage( $"{Perk.GetRichTextToken( GetType() )} Time's up! Perk chosen randomly: {Perk.GetRichTextToken( type )}", from: "" );

			_timeSinceTrigger = 0f;
			Highlight();
		}
	}

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

		_timeSinceTrigger = 0f;
	}

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