perks/PerkLoseWhenGainXp.cs

A perk class named PerkLoseWhenGainXp (Anarchist) that adds flat bullet damage while active and removes plus banishes itself when the player gains an XP coin. It registers metadata, applies a bullet damage modifier on Refresh, and handles OnGainXpCoin by removing the perk, banishing it, sending a local chat message, and playing a nearby sound.

NetworkingFile Access
using System;
using System.Numerics;
using Sandbox;

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

	static PerkLoseWhenGainXp()
	{
		Register<PerkLoseWhenGainXp>(
			name: "Anarchist",
			imagePath: "textures/icons/vector/lose_when_gain_xp.png",
			description: level => $"+{GetValue( level, Mod.BulletDamageAddition )} bullet dmg\nRemove and banish this perk\nwhen you get xp coin"
		);
	}

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

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

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

	private static float GetValue( int level, Mod mod, bool isPercent = false )
	{
		switch ( mod )
		{
			case Mod.BulletDamageAddition:
			default:
				return 4f;
		}
	}

	public override void OnGainXpCoin( float xp )
	{
		base.OnGainXpCoin( xp );

		Player.RemovePerk( TypeLibrary.GetType( GetType() ) );
		Player.BanishPerk( TypeLibrary.GetType( GetType() ) );

		Manager.Instance.Chat.AddLocalChatMessage( $"{Perk.GetRichTextToken( GetType() )} Removed and banished because you got a coin", from: "" );

		Manager.Instance.PlaySfxNearby( "burn", Player.Position2D, pitch: 0.7f, volume: 0.8f, maxDist: 200f );
	}
}