perks/PerkBoomerangKillEnemy.cs

A perk component for a game that can spawn boomerang projectiles when the player kills an enemy with a bullet. It defines spawn chance, damage percent, limits active boomerangs, visual highlight settings, and tracks active boomerangs.

NetworkingFile Access
using System;
using Sandbox;

[Perk( Rarity.Epic, locked: true, alwaysOfferDebug: false, IncludedCategories = new[] { PerkCategory.Boomerang })]
public class PerkBoomerangKillEnemy : Perk
{
	private enum Mod { Chance, DamagePercent, MaxBoomerangs };

	public int CurrNumBoomerangs { get; set; }


	static PerkBoomerangKillEnemy()
	{
		Register<PerkBoomerangKillEnemy>(
			name: "Bone Boomerangs",
			imagePath: "textures/icons/vector/boomerang_kill_enemy.png",
			description: level => $"{GetValue( level, Mod.Chance, true )}% chance to spawn boomerang-item\nthat does {GetValue( level, Mod.DamagePercent, true )}% bullet dmg\nwhen you kill with bullet-icon",
			upgradeDescription: level => $"{GetValue( level - 1, Mod.Chance, true )}%→{GetValue( level, Mod.Chance, true )}% chance to spawn boomerang-item\nthat does {GetValue( level - 1, Mod.DamagePercent, true )}%→{GetValue( level, Mod.DamagePercent, true )}% bullet dmg\nwhen you kill with bullet-icon"
		);
	}

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

		HighlightColor = new Color( 0.3f, 0.6f, 1f );
		HighlightOpacity = 1.75f;
		HighlightDuration = 0.3f;
	}

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

	}

	private static float GetValue( int level, Mod mod, bool isPercent = false )
	{
		switch ( mod )
		{
			case Mod.Chance:
			default:
				return isPercent
					? 6f + 4f * level
					: 0.06f + 0.04f * level;
			case Mod.DamagePercent:
				return isPercent
					? 65f + 15f * level
					: 0.65f + 0.15f * level;
			case Mod.MaxBoomerangs:
				return 20;
		}
	}

	public override void OnKill( Enemy enemy, DamageType damageType, bool countsAsKill )
	{
		base.OnKill( enemy, damageType, countsAsKill );
		if ( !countsAsKill ) return;

		// todo: also should be able to trigger this when you execute an enemy with a bullet (require some refactoring to know the damage type on execute?)

		if ( damageType != DamageType.Bullet )
			return;

		if ( Game.Random.Float( 0f, 1f ) < GetValue( Level, Mod.Chance ) && CurrNumBoomerangs < (int)GetValue( Level, Mod.MaxBoomerangs ) )
		{
			SpawnBoomerang( enemy.Position2D, (enemy.Position2D - Player.Position2D).Normal );
			
			Highlight();

			Manager.Instance.PlaySfxNearbyRpc( "boomerang_enemy_spawn", enemy.Position2D, pitch: Game.Random.Float( 0.85f, 0.95f ), volume: 2.5f, maxDist: 450f );
		}
	}

	void SpawnBoomerang(Vector2 pos, Vector2 dir)
	{
		var damage = Player.GetBulletDamage( isFromClip: false, isLastAmmo: false ) * GetValue( Level, Mod.DamagePercent ) + (Player.Stats[PlayerStat.BoomerangeExtraDmg]); // todo: should apply extra dmg before multipliers?
		var boomerang = Manager.Instance.SpawnBoomerang( pos, dir * Game.Random.Float( 200f, 700f ), damage, Player );
		boomerang.FromBoomerangKillEnemyPerk = true;

		CurrNumBoomerangs++;

		Highlight();
	}

	public void BoomerangDestroyed()
	{
		CurrNumBoomerangs = Math.Max( CurrNumBoomerangs - 1, 0 );
	}
}