perks/PerkDashRandomlyWhenHit.cs

A mythic perk class named PerkDashRandomlyWhenHit (Featherweight). It increases player's dash count and gives a chance to automatically dash when hit, highlights the player when triggered, and provides UI strings for description and upgrades.

Networking
using System;
using Sandbox;

[Perk( Rarity.Mythic, locked: true, minUnlocksReq: 2, alwaysOfferDebug: false )]
public class PerkDashRandomlyWhenHit : Perk
{
	private enum Mod { NumDashes, Chance };

	static PerkDashRandomlyWhenHit()
	{
		Register<PerkDashRandomlyWhenHit>(
			name: "Featherweight",
			imagePath: "textures/icons/vector/dash_randomly_when_hit.png",
			description: level => $"+{(int)GetValue( level, Mod.NumDashes )} {((int)GetValue( level, Mod.NumDashes ) > 1 ? "dashes" : "dash")}\n[-]{GetValue( level, Mod.Chance, true )}%[/-] chance to attempt\ndashing when hit",
			upgradeDescription: level => GetUpgradeDescription( level )
		);
	}

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

		HighlightColor = new Color( 1f, 0.25f, 0.25f );
		HighlightDuration = 0.6f;
		HighlightOpacity = 4f;
	}

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

		Player.Modify( this, PlayerStat.NumDashes, GetValue( Level, Mod.NumDashes ), ModifierType.Add );
	}

	private static float GetValue( int level, Mod mod, bool isPercent = false )
	{
		switch ( mod )
		{
			case Mod.NumDashes:
			default:
				return level;
			case Mod.Chance:
				return isPercent
					? 25f + 25f * level
					: 0.25f + 0.25f * level;
		}
	}

	public override void OnHit( float amount, DamageType damageType, bool isSelfInflicted, Vector2 dir, float force, Enemy enemySource, EnemyType enemyType, float previousHealth )
	{
		base.OnHit( amount, damageType, isSelfInflicted, dir, force, enemySource, enemyType, previousHealth );

		if ( damageType == DamageType.Self )
			return;

		if ( !Player.IsInTheAir && Player.TimeSinceDash > 0.3f && Game.Random.Float( 0f, 1f ) < GetValue( Level, Mod.Chance ) )
		{
			Player.Dash( dir );

			Highlight();
		}
	}

	public static string GetUpgradeDescription( int level )
	{
		int numPrev = (int)GetValue( level - 1, Mod.NumDashes );
		int currPrev = (int)GetValue( level, Mod.NumDashes );

		string str = numPrev != currPrev
			? $"+{(int)GetValue( level - 1, Mod.NumDashes )}→{(int)GetValue( level, Mod.NumDashes )} dashes"
			: $"+{(int)GetValue( level, Mod.NumDashes )} {((int)GetValue( level, Mod.NumDashes ) > 1 ? "dashes" : "dash")}";

		return $"{str}\n[-]{GetValue( level - 1, Mod.Chance, true )}%→{GetValue( level, Mod.Chance, true )}%[/-] chance to attempt\ndashing when hit";
	}
}