perks/PerkHealShoot.cs

A mythic perk class named PerkHealShoot that launches a bullet when the player is healed. It computes damage from the heal amount and perk level, picks a target direction toward the nearest enemy or a random direction, spawns a bullet, and triggers visual/animation effects on the player.

Networking
using Sandbox;
using System;
using System.Numerics;

[Perk( Rarity.Mythic, locked: true, alwaysOfferDebug: false )]
public class PerkHealShoot : Perk
{
	private enum Mod { DamagePercent };

	static PerkHealShoot()
	{
		Register<PerkHealShoot>(
			name: "Karma Bullets",
			imagePath: "textures/icons/vector/heal_shoot.png",
			description: level => $"When healed, launch a bullet-icon with\n[+]{GetValue( level, Mod.DamagePercent, true )}%[/+] of the hp as dmg",
			upgradeDescription: level => $"When healed, launch a bullet-icon with\n{GetValue( level - 1, Mod.DamagePercent, true )}%→{GetValue( level, Mod.DamagePercent, true )}% of the hp as dmg"
		);
	}

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

		HighlightColor = new Color( 0.3f, 1f, 0.8f );
		HighlightDuration = 0.2f;
		HighlightOpacity = 1.5f;
	}

	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
					? 100f + 100f * level
					: 1.0f + 1.0f * level;
		}
	}

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

		Shoot( amount );
	}

	void Shoot( float healAmount )
	{
		var closestEnemy = Manager.Instance.GetClosestEnemy( Player.Position2D, 400f );
		Vector2 dir = closestEnemy != null ? (closestEnemy.Position2D - Player.Position2D).Normal : Utils.GetRandomVector();

		var pos = Player.Position2D + dir * Player.BULLET_SPAWN_OFFSET * Player.Stats[PlayerStat.Scale];
		var damage = healAmount * GetValue( Level, Mod.DamagePercent );
		damage *= Player.Stats[PlayerStat.BulletDamageMultiplier];
		damage = MathF.Max( damage, Player.MIN_BULLET_DAMAGE );

		// todo: should add the value from PerkHealBulletDamage

		Player.SpawnBullet( pos, dir, damage );

		Highlight();

		IconScale = Game.Random.Float( 1.1f, 1.2f );
		IconAngleOffset = Game.Random.Float( 10f, 15f ) * (Game.Random.Int( 0, 1 ) == 0 ? -1f : 1f);

		Player.ScaleHeightRpc( amount: Utils.Map( damage, 1f, 20f, 1.3f, 1.5f ), time: Game.Random.Float( 0.075f, 0.1f ) );

		Player.DodgeDuckRpc( dir, time: Game.Random.Float( 0.01f, 0.02f ), shouldFlinch: false );
	}
}