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.
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;
// }
//}
}