A rare AoE perk called Volatile Shield that triggers when the player's shield breaks. It spawns a visual ring and applies scaled area damage and knockback to nearby enemies, with damage value increasing by level.
using System;
using Sandbox;
using Sandbox.UI;
[Perk( Rarity.Rare, includedAtStart: false, locked: true, minUnlocksReq: 2, alwaysOfferDebug: false, IncludedCategories = new[] { PerkCategory.Aoe })]
public class PerkShieldBreakAoe : Perk
{
private const float DAMAGE_RADIUS = 140f;
private enum Mod { Damage };
static PerkShieldBreakAoe()
{
Register<PerkShieldBreakAoe>(
name: "Volatile Shield",
imagePath: "textures/icons/vector/shield_break_damage.png",
description: level => $"Do [+]{GetValue( level, Mod.Damage )}[/+] dmg to nearby enemies\nwhen your shield breaks",
upgradeDescription: level => $"Do {GetValue( level - 1, Mod.Damage )}→{GetValue( level, Mod.Damage )} dmg to nearby enemies\nwhen your shield breaks"
);
}
public override void Start()
{
base.Start();
HighlightColor = new Color( 0.5f, 0.5f, 1f );
HighlightDuration = 0.25f;
HighlightOpacity = 3f;
}
public override void Refresh()
{
base.Refresh();
}
private static float GetValue( int level, Mod mod, bool isPercent = false )
{
switch ( mod )
{
case Mod.Damage:
default:
return 5f + 10f * level;
}
}
public override void OnLoseShield()
{
float damage = GetValue( Level, Mod.Damage );
float radius = DAMAGE_RADIUS * Player.Stats[PlayerStat.RadiusMultiplier];
Vector2 pos = Player.Position2D;
Manager.Instance.SpawnRingRpc( pos, radius, new Color( 1f, 1f, 0f, 0.6f ), lifetime: Game.Random.Float( 0.25f, 0.3f ), path: "ring_spiky_2" );
// todo: replace with Manager.DamageInRadius or something
foreach ( var enemy in Manager.Instance.GetNearbyEnemies( pos, radius ) )
{
if ( enemy.IsDying || enemy.IsInTheAir || (enemy.IsSpawning && !enemy.AlmostFinishedSpawning) )
continue;
Vector2 dir = (enemy.Position2D - pos).LengthSquared > Manager.TOUCH_DIST_REQUIRED_SQR
? (enemy.Position2D - pos).Normal
: Utils.GetRandomVector();
var hitPos = enemy.Position2D - dir * enemy.Radius;
var dist_sqr = (enemy.Position2D - pos).LengthSquared;
var percent = Utils.Map( dist_sqr, 0f, MathF.Pow( radius, 2f ), 1f, 0.2f, EasingType.QuadIn );
var shouldFlinch = percent > 0.7f;
enemy.DamageRpc( damage * percent, Player, DamageType.Aoe, hitPos, dir * damage * 0.4f, isCrit: false, shouldFlinch );
}
Highlight();
}
}