A Perk class for a game, named "Recuperate". It tracks time since the player last killed an enemy and heals the player for a configured amount when the timer exceeds a threshold. It also updates UI display values, cooldown visuals, and plays a local heal sound effect via Manager.Instance.PlaySfxNearbyRpc.
using System;
using Sandbox;
[Perk( Rarity.Uncommon, alwaysOfferDebug: false )]
public class PerkPacifistRegenHp : Perk
{
private enum Mod { Time, HealthRegen };
private TimeSince _timeSince;
// todo: show hp regen stats after not killing for long enough
static PerkPacifistRegenHp()
{
Register<PerkPacifistRegenHp>(
name: "Recuperate",
imagePath: "textures/icons/vector/pacifist_regen_hp.png",
description: level => $"Heal {GetValue( level, Mod.HealthRegen ).ToString( "0.#" )} hp when you\ndon't kill for {GetValue( level, Mod.Time ).ToString( "0.#" )}s",
upgradeDescription: level => $"Heal {GetValue( level - 1, Mod.HealthRegen ).ToString( "0.#" )}→{GetValue( level, Mod.HealthRegen ).ToString( "0.#" )} hp when you\ndon't kill for {GetValue( level - 1, Mod.Time ).ToString( "0.#" )}→{GetValue( level, Mod.Time ).ToString( "0.#" )}s"
);
}
public override void Start()
{
base.Start();
ShouldUpdate = true;
_timeSince = 0f;
DisplayCooldownColor = new Color( 0.5f, 1f, 0.5f, 3f );
}
public override void Refresh()
{
base.Refresh();
}
public override void Update( float dt )
{
base.Update( dt );
if ( _timeSince > GetValue( Level, Mod.Time ) )
{
if( Player.Health < Player.Stats[PlayerStat.MaxHp] )
{
Player.Heal( GetValue( Level, Mod.HealthRegen ) );
Manager.Instance.PlaySfxNearbyRpc( "heal_pacifist", Player.Position2D, pitch: Game.Random.Float( 0.95f, 1.05f ), volume: 1.2f, maxDist: 400f );
}
_timeSince = 0f;
DisplayCooldown = 0f;
HighlightColor = new Color( 0.5f, 1f, 0.5f );
HighlightDuration = 0.25f;
HighlightOpacity = 4f;
Highlight();
}
else
{
DisplayCooldown = Utils.Map( _timeSince, 0f, GetValue( Level, Mod.Time ), 0f, 1f );
}
DisplayText = $"{Math.Round( GetValue( Level, Mod.Time ) - _timeSince )}";
}
public override void OnKill( Enemy enemy, DamageType damageType, bool countsAsKill )
{
base.OnKill( enemy, damageType, countsAsKill );
if ( !countsAsKill )
return;
_timeSince = 0f;
HighlightColor = new Color( 1f, 0.3f, 0.3f );
HighlightDuration = 0.25f;
HighlightOpacity = 2f;
Highlight();
}
private static float GetValue( int level, Mod mod, bool isPercent = false )
{
switch ( mod )
{
case Mod.Time:
default:
return 6.3f - 0.3f * level;
case Mod.HealthRegen:
return 3.9f + 1.1f * level;
}
}
}