perks/PerkCleanse.cs

A Perk implementation named PerkCleanse. When leveled up it removes the player's last acquired perk and then attempts to give the player a number of random existing perks (excluding itself) over time, showing chat and floater feedback.

NetworkingFile Access
using System;
using Sandbox;

[Perk( Rarity.Rare, includedAtStart: false, locked: true, alwaysOfferDebug: false )]
public class PerkCleanse : Perk
{
	//private enum Mod { MoveSpeed, MaxHp };

	private int _numRewards;
	private TimeSince _timeSinceReward;

	public override float ImportanceMultiplier => 0.1f;

	static PerkCleanse()
	{
		Register<PerkCleanse>(
			name: "Cleanse",
			imagePath: "textures/icons/vector/cleanse.png",
			description: level => $"Remove the last perk you got\n+1 random perk you already have",
			upgradeDescription: level => $"Remove the last perk you got\n+1 random perk you already have"
		);
	}

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

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

		// todo: should this perk not be able to remove itself?

		var lastPerkType = Player.GetLastPerkType();
		if ( lastPerkType == null )
			return;

		//var perkLevel = Player.GetPerkLevel( lastPerkType );

		Player.RemovePerk( lastPerkType );

		//for ( int i = 0; i < perkLevel; i++ )
		//	Player.GivePerkItem( lastPerkType, dir: Utils.GetRandomVector() );

		Manager.Instance.Chat.AddLocalChatMessage( $"{Perk.GetRichTextToken( GetType() )} Removed perk: {Perk.GetRichTextToken( lastPerkType )}", from: "" );

		_numRewards++;
		ShouldUpdate = true;
		_timeSinceReward = 0f;
	}

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

		//Player.Modify( this, PlayerStat.MoveSpeedMultiplier, GetValue( Level, Mod.MoveSpeed ), ModifierType.Mult );
		//Player.Modify( this, PlayerStat.MaxHp, GetValue( Level, Mod.MaxHp ), ModifierType.Add );
	}

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

		if( _numRewards > 0 )
		{
			if( _timeSinceReward > 0.35f )
			{
				if ( !Player.GiveRandomExistingPerk( ignoreType: typeof( PerkCleanse ) ) )
				{
					//Player.PlaySfxUI( "error2", pitch: 0.55f, volume: 0.9f );
					Manager.Instance.SpawnFloaterText( Player.WorldPosition.WithZ( 65f ), "FAILED!", new Color( 1f, 0.5f, 0.5f ), 1.3f, FloaterType.NegativeMessage );
				}

				_numRewards--;

				_timeSinceReward = 0f;
			}
		}
		else
		{
			ShouldUpdate = false;
		}
	}

	//private static float GetValue( int level, Mod mod, bool isPercent = false )
	//{
	//	switch ( mod )
	//	{
	//		case Mod.MoveSpeed:
	//		default:
	//			return isPercent
	//				? 3 * level
	//				: 1f + 0.03f * level;
	//		case Mod.MaxHp:
	//			return 10 * level;
	//	}
	//}
}