perks/PerkCopyNext.cs

A game perk component named PerkCopyNext that duplicates the next non-curse perk the player receives. It tracks a deferred count, increments when level increases, applies the copy in OnAddPerkBefore, updates a player stat each frame, and manages UI highlight and display values.

Networking
using System;
using Sandbox;

[Perk( Rarity.Rare, alwaysOfferDebug: false )]
public class PerkCopyNext : Perk
{
	private float _deferredAmount;

	public override float ImportanceMultiplier => 0f;

	static PerkCopyNext()
	{
		Register<PerkCopyNext>(
			name: "Two For One",
			imagePath: "textures/icons/vector/copy_next.png",
			description: level => $"Duplicate the next perk you get",
			upgradeDescription: level => $"Duplicate the next perk you get"
		);
	}

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

		HighlightColor = new Color( 1f, 1f, 0.5f );
		HighlightDuration = 0.4f;
		HighlightOpacity = 6f;
	}

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

		_deferredAmount += 1f;
		ShouldUpdate = true;
		DisplayText = "➕";
		DisplayCooldown = 1f;
	}

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

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

		Player.Stats[PlayerStat.CopyNextPerk] += _deferredAmount;
		_deferredAmount = 0f;

		DisplayCooldownColor = new Color( 0.3f, 0.3f, 1f, Utils.Map( Utils.FastSin( RealTime.Now * 12f ), -1f, 1f, 0f, 1f ) );
	}

	public override void OnAddPerkBefore( TypeDescription type )
	{
		base.OnAddPerkBefore( type );

		var attrib = type.GetAttribute<PerkAttribute>();
		if ( attrib.Curse )
			return;

		if ( Player.Stats[PlayerStat.CopyNextPerk] > 0f )
		{
			Player.GivePerkItem( type, dir: Utils.GetRandomVectorInCone(-Player.FacingDir ) );
			Player.Stats[PlayerStat.CopyNextPerk] -= 1f;

			if ( !(Player.Stats[PlayerStat.CopyNextPerk] > 0f) && _deferredAmount == 0 )
			{
				DisplayText = " ";
				DisplayCooldown = 0f;
				ShouldUpdate = false;
			}

			Highlight();
		}
	}

	public override void Remove( bool restart = false )
	{
		base.Remove( restart );

		Player.Stats[PlayerStat.CopyNextPerk] = 0f;
	}
}