perks/PerkHealthPackMaxHp.cs

A unique perk called Overmedicated that modifies player stats when picked. It reduces move speed multiplicatively, and when the player picks up a healthpack while at full health it permanently adds max HP (tracked per-perk) and spawns a floater text and highlight.

Networking
using System;
using System.Net.WebSockets;
using Sandbox;

[Perk( Rarity.Unique, locked: true, alwaysOfferDebug: false )]
public class PerkHealthPackMaxHp : Perk
{
	private enum Mod { MoveSpeed, HpAmount };

	private int _hpAdded;

	static PerkHealthPackMaxHp()
	{
		Register<PerkHealthPackMaxHp>(
			name: "Overmedicated",
			imagePath: "textures/icons/vector/healthpack_max_hp.png",
			description: level => $"Healthpacks give +{(int)GetValue( level, Mod.HpAmount )} max hp while at full hp\n-{GetValue( level, Mod.MoveSpeed, true )}% move speed"
		);
	}

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

		HighlightColor = new Color( 0.8f, 1f, 0.8f );
		HighlightDuration = 0.4f;
		HighlightOpacity = 4f;
	}

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

		Player.Modify( this, PlayerStat.MoveSpeedMultiplier, GetValue( Level, Mod.MoveSpeed ), ModifierType.Mult );
	}

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

		if ( !(Player.Health < Player.Stats[PlayerStat.MaxHp]) )
		{
			var hpToAdd = (int)GetValue( Level, Mod.HpAmount );
			_hpAdded += hpToAdd;
			Player.Modify( this, PlayerStat.MaxHp, _hpAdded, ModifierType.Add );

			Manager.Instance.SpawnFloaterTextRpc( Player.WorldPosition.WithZ( 65f ), $"+{hpToAdd} MAX HP", new Color( 0f, 0.8f, 0f ), size: 1.2f, floaterType: FloaterType.PositiveMessage );

			//Manager.Instance.PlaySfxNearbyRpc( "heal", Player.Position2D, pitch: Game.Random.Float( 3.2f, 3.4f ), volume: 1.2f, maxDist: 450f );

			Highlight();
		}
	}

	private static float GetValue( int level, Mod mod, bool isPercent = false )
	{
		switch ( mod )
		{
			case Mod.MoveSpeed:
			default:
				return isPercent
					? 8f
					: 1f - (0.08f);
				case Mod.HpAmount:
					return 3;
		}
	}
}