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.
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 );
}
}