A Perk class for the game that grants an effect called "XP Shrapnel". When the player gains XP coins it spawns a visual ring, plays a nearby sound, and deals damage to nearby enemies scaled by the XP amount and perk level. It also updates a display stat and highlight visuals.
using System;
using Sandbox;
[Perk( Rarity.Uncommon, alwaysOfferDebug: false, IncludedCategories = new[] { PerkCategory.Aoe })]
public class PerkXpDamage : Perk
{
private enum Mod { DamageAmount };
private const float RADIUS = 120f;
static PerkXpDamage()
{
Register<PerkXpDamage>(
name: "XP Shrapnel",
imagePath: "textures/icons/vector/xp_damage.png",
description: level => $"xp coins hurt nearby enemies for\n{GetValue( level, Mod.DamageAmount ).ToString( "0.#" )} dmg per point of xp",
upgradeDescription: level => $"xp coins hurt nearby enemies for\n{GetValue( level - 1, Mod.DamageAmount ).ToString( "0.#" )}→{GetValue( level, Mod.DamageAmount ).ToString( "0.#" )} dmg per point of xp"
);
}
public override void Start()
{
base.Start();
HighlightColor = new Color( 0.6f, 0.6f, 1f );
HighlightDuration = 0.2f;
HighlightOpacity = 0.8f;
}
public override void Refresh()
{
base.Refresh();
Player.Modify( this, PlayerStat.XpDamageDisplay, GetValue( Level, Mod.DamageAmount ), ModifierType.Add );
}
public override void OnGainXpCoin( float xp )
{
base.OnGainXpCoin( xp );
float radius = RADIUS * Player.Stats[PlayerStat.RadiusMultiplier];
float damage = xp * GetValue( Level, Mod.DamageAmount );
Manager.Instance.PlaySfxNearbyRpc( "player.shoot", Player.Position2D, pitch: Utils.Map( xp, 1, 16, 1.2f, 1.4f ), volume: Utils.Map( xp, 1, 16, 0.75f, 1f ), maxDist: 300f );
Manager.Instance.SpawnRingRpc( Player.Position2D, radius, new Color( 0.2f, 0.2f, 1f, 0.2f ), lifetime: Game.Random.Float( 0.2f, 0.3f ), path: "ring_jagged" );
Manager.Instance.DamageNearbyEnemies( Player.Position2D, radius, damage, force: damage * 0.25f, DamageType.XpShrapnel, Player );
Highlight();
}
private static float GetValue( int level, Mod mod, bool isPercent = false )
{
switch ( mod )
{
case Mod.DamageAmount:
default:
return 0.4f + 0.4f * level;
}
}
}