status/XpDamageStatus.cs
using System;
using System.Collections.Generic;
using System.Linq;
using Sandbox;

[Status(7, 0, 1f, 0, false )]
public class XpDamageStatus : Status
{
	public XpDamageStatus()
    {
		Title = "XP Shrapnel";
		IconPath = "textures/icons/xp_damage.png";
	}

	public override void Init(Player player)
	{
		base.Init(player);
	}

	public override void Refresh()
    {
		Description = GetDescription(Level);
    }

	public override string GetDescription(int newLevel)
	{
		return string.Format("When you gain XP, hurt nearby enemies for {0} per point", GetPrintAmountForLevel( Level));
	}

	public override string GetUpgradeDescription(int newLevel)
	{
		return newLevel > 1 ? string.Format("When you gain XP, hurt nearby enemies for {0}→{1} per point", GetPrintAmountForLevel( newLevel - 1), GetPrintAmountForLevel( newLevel)) : GetDescription(newLevel);
	}

    public override void OnGainExperience(int xp)
    {
		List<Thing> nearbyThings = new List<Thing>();

		for ( int dx = -2; dx <= 2; dx++ )
			for ( int dy = -2; dy <= 2; dy++ )
				Manager.Instance.AddThingsInGridSquare( new Manager.GridSquare( Player.GridPos.x + dx, Player.GridPos.y + dy ), nearbyThings );

		float radius = 2.15f * Player.Stats[PlayerStat.RadiusMultiplier];
		float damage = xp * GetAmountForLevel( Level ) * Player.GetDamageMultiplier();

		//Manager.Instance.PlaySfxNearby( "shoot", Player.Position2D, pitch: Utils.Map( xp, 1, 16, 0.85f, 1.4f ), volume: Utils.Map( xp, 1, 16, 0.6f, 1f ), maxDist: 3f );

		foreach ( Thing thing in nearbyThings )
		{
			if ( thing is Enemy enemy && !enemy.IsDying && (!enemy.IsSpawning || enemy.TimeSinceSpawn > 0.75f) && !enemy.IgnoreCollision && !enemy.IsCharmed )
			{
				var dist_sqr = (thing.Position2D - Player.Position2D).LengthSquared;
				if ( dist_sqr < MathF.Pow( radius, 2f ) )
				{
					var addVel = (thing.Position2D - Player.Position2D).Normal * Utils.Map( xp, 1, 16, 0.3f, 1.5f, EasingType.QuadIn ) * Utils.Map(Level, 1, 7, 1f, 1.2f, EasingType.QuadOut);
					var addTempWeight = 0f;

					enemy.Damage( damage, Player, addVel, addTempWeight, false, DamageType.Ranged );
					//enemy.Damage( Utils.Map(dist_sqr, MathF.Pow(0.2f, 2f), MathF.Pow( radius, 2f ), damage, 1f), Player, addVel, addTempWeight, false, DamageType.Ranged );
				}
			}
		}

		var explosion = Manager.Instance.SpawnExplosionEffect( Player.Position2D, new Color(0f, 0f, 1f), new Color( 0.2f, 0.2f, 1f ), opacity: 0.05f, scaleModifier: 0.75f * radius );
		explosion.Sprite.PlaybackSpeed = 5f;
		explosion.Lifetime = 0.2f;

		Manager.Instance.PlaySfxNearby( "burn", Player.Position2D, pitch: Game.Random.Float(2.4f, 2.6f), volume: Utils.Map( xp, 1, 16, 0.4f, 0.6f ), maxDist: 4f );
	}

    public float GetAmountForLevel(int level)
	{
		return 0.4f + level * 0.3f + (level == 7 ? 0.15f : 0f);
	}

    public string GetPrintAmountForLevel(int level)
    {
        return string.Format("{0:0.00}", GetAmountForLevel(level));
    }
}