perks/PerkHealBulletDamage.cs

A rare perk class that increases bullet damage based on recent healing. It records Heal events with timestamps, keeps them for 1 second, sums healed amount and applies an additive BulletDamage modifier proportional to that sum and the perk level.

Networking
using System;
using Sandbox;

public struct HealBulletDamageData
{
	public float amount;
	public float time;
}

[Perk( Rarity.Rare, locked: true, minUnlocksReq: 1, alwaysOfferDebug: false )]
public class PerkHealBulletDamage : Perk
{
	private enum Mod { DamagePercent };

	private Queue<HealBulletDamageData> _dataQueue = new();

	static PerkHealBulletDamage()
	{
		Register<PerkHealBulletDamage>(
			name: "Healthy Strength",
			imagePath: "textures/icons/vector/heal_bullet_damage.png",
			description: level => $"bullet-icon dmg increases by\n{(int)GetValue( level, Mod.DamagePercent, true )}% of hp healed in the last 1s",
			upgradeDescription: level => $"bullet-icon dmg increases by {(int)GetValue( level - 1, Mod.DamagePercent, true )}→{(int)GetValue( level, Mod.DamagePercent, true )}%\nof hp healed in the last 1s"
		);
	}

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

		ShouldUpdate = true;
	}

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

	}

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

	public override void OnHeal( float amount )
	{
		base.OnHeal( amount );

		_dataQueue.Enqueue( new HealBulletDamageData() { amount = amount, time = Time.Now } );
		RefreshBuffs();
	}

	public override void Update( float dt )
	{
		base.Update( dt );

		if ( _dataQueue.Count > 0 )
		{
			if ( Time.Now > _dataQueue.First().time + 1f )
			{
				_dataQueue.Dequeue();
				RefreshBuffs();
			}
		}
	}

	void RefreshBuffs()
	{
		float total = 0f;
		foreach ( var data in _dataQueue )
			total += data.amount;

		float bonus = total * GetValue( Level, Mod.DamagePercent );
		// todo: change a separate value instead, so this perk buffs PerkHealShoot?
		Player.Modify( this, PlayerStat.BulletDamage, bonus, ModifierType.Add );
		DisplayText = bonus > 0f ? string.Format( "{0:0.00}", bonus ) : " ";
	}
}