A Perk class for the game that grants additional perk choice slots for a limited time, then automatically levels down or removes itself when the time expires. It updates UI display values, applies the numeric perk choice modifier on refresh, and triggers a level-down via the player when its timer elapses.
using System;
using Sandbox;
[Perk( Rarity.Epic, locked: true, minUnlocksReq: 2, alwaysOfferDebug: false )]
public class PerkNumChoicesTimed : Perk
{
private enum Mod { NumPerkChoices, TimeLimit };
private TimeSince _timeSinceEffect;
static PerkNumChoicesTimed()
{
Register<PerkNumChoicesTimed>(
name: "Shelf Space",
imagePath: "textures/icons/vector/num_choices_timed.png",
description: level => $"+{(int)GetValue( level, Mod.NumPerkChoices )} perk {(level > 1 ? "choices" : "choice")}\nLevel-down this perk after {(int)GetValue( level, Mod.TimeLimit )}s",
upgradeDescription: level => $"+{(int)GetValue( level - 1, Mod.NumPerkChoices )}→{(int)GetValue( level, Mod.NumPerkChoices )} perk choices\nLevel-down this perk after {(int)GetValue( level, Mod.TimeLimit )}s"
);
}
public override void Start()
{
base.Start();
DisplayCooldownColor = new Color( 0.4f, 0.5f, 0.5f, 3f );
HighlightColor = new Color( 1f, 0.3f, 0.3f );
HighlightDuration = 0.66f;
HighlightOpacity = 3f;
ShouldUpdate = true;
_timeSinceEffect = 0f;
}
public override void Refresh()
{
base.Refresh();
Player.Modify( this, PlayerStat.NumPerkChoices, GetValue( Level, Mod.NumPerkChoices ), ModifierType.Add );
}
public override void Update( float dt )
{
base.Update( dt );
var timeLimit = GetValue( Level, Mod.TimeLimit );
DisplayCooldown = Utils.Map( _timeSinceEffect, 0f, timeLimit, 1f, 0f );
DisplayText = $"{(int)Math.Ceiling( timeLimit - _timeSinceEffect )}";
if ( _timeSinceEffect > timeLimit )
{
var type = TypeLibrary.GetType( this.GetType() );
var newLevel = Level - 1;
Manager.Instance.Chat.AddLocalChatMessage( $"{Perk.GetRichTextToken( GetType() )} {(newLevel > 0 ? $"Leveled down from {Level}→{newLevel}" : "Removed perk")}", from: "" );
Highlight();
_timeSinceEffect = 0f;
Player.LevelDownPerk( type );
}
}
private static float GetValue( int level, Mod mod, bool isPercent = false )
{
switch ( mod )
{
case Mod.NumPerkChoices:
default:
return level;
case Mod.TimeLimit:
return 150f;
}
}
}