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