perks/PerkBulletEarlierShotDamage.cs

A Perk class named PerkBulletEarlierShotDamage that increases damage for earlier shots. It registers itself with name, icon and descriptions, applies a damage-per-earlier-shot modifier on Refresh, updates display text on shooting, and computes values per level.

Networking
using System;
using Sandbox;

[Perk( Rarity.Uncommon, alwaysOfferDebug: false )]
public class PerkBulletEarlierShotDamage : Perk
{
	private enum Mod { EarlierShotDamage };

	static PerkBulletEarlierShotDamage()
	{
		Register<PerkBulletEarlierShotDamage>(
			name: "Build Up",
			imagePath: "textures/icons/vector/bullet_damage_earlier_shots.png",
			description: level => $"+{GetValue( level, Mod.EarlierShotDamage ).ToString( "0.##" )} bullet dmg each time you shoot\n(resets on reload)",
			upgradeDescription: level => $"+{GetValue( level - 1, Mod.EarlierShotDamage ).ToString("0.##")}→{GetValue( level, Mod.EarlierShotDamage ).ToString("0.##")} bullet dmg each time\nyou shoot (resets on reload)"
		);
	}

	// todo: needs a cap, so can't go infinite with PerkBulletCritReload?

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

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

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

	private static float GetValue( int level, Mod mod, bool isPercent = false )
	{
		switch ( mod )
		{
			case Mod.EarlierShotDamage:
			default:
				return 0.05f + 0.06f * level;
		}
	}

	public override void OnShoot()
	{
		RefreshDisplayText();
	}

	void RefreshDisplayText()
	{
		DisplayText = Player.Stats[PlayerStat.ShotNum] > 0f ? string.Format( "{0:0.00}", Player.Stats[PlayerStat.ShotNum] * GetValue( Level, Mod.EarlierShotDamage ) ) : " ";
		DisplayTextOpacity = Utils.Map( Player.Stats[PlayerStat.ShotNum], 1, 10, 0.75f, 3f );
	}
}