Player/Tools/PulseTool.cs
namespace PlanetMeat;
[Title( "Pulse Ring" ), Icon( "offline_bolt" )]
public sealed class PulseTool : PlayerTool, IUpgradeableAttack, IUpradeableSize
{
private static GameObject BurstPrefab => GameObject.GetPrefab( "effects/pulse_burst.prefab" );
public const float MINIMUM_RADIUS = 75.0f;
public const float PULSE_TOOL_COOLDOWN = 20.0f;
public override float BaseCooldown => PULSE_TOOL_COOLDOWN;
public ValueAggregator<int> AggregateDamage => field ??= ValueAggregator<int>.FromImprovement( "pulse_dmg", 10 );
public ValueAggregator<int> AggregateSize => field ??= ValueAggregator<int>.FromImprovement( "pulse_size", 50 );
[Property] private float RadiusSpeed { get; set; } = 500.0f;
[Property] private Color RingColor { get; set; } = Color.Blue;
public float Radius => MINIMUM_RADIUS + chargeTime * RadiusSpeed;
public int Thickness => this.GetStrikeSize();
private float chargeTime = 0.0f;
public bool Charging { get; private set; } = false;
private (float, float) Radii
{
get
{
var radius = Radius;
var halfThick = 0.5f * Thickness;
return (radius - halfThick, radius + halfThick);
}
}
private AoeRing InnerRing
{
get;
set
{
if ( field?.GameObject is GameObject ringGo && ringGo.IsValid )
ringGo.Destroy();
field = value;
}
}
private AoeRing OuterRing
{
get;
set
{
if ( field?.GameObject is GameObject ringGo && ringGo.IsValid )
ringGo.Destroy();
field = value;
}
}
private void DestroyRings()
{
InnerRing = null;
OuterRing = null;
}
public override void OnPlaceStarted( Vector3 position )
{
base.OnPlaceStarted( position );
if ( IsUsable )
{
StartCooldown();
chargeTime = 0.0f;
Charging = true;
DestroyRings();
var (inner, outer) = Radii;
InnerRing = AoeRing.Create( WorldPosition, inner );
OuterRing = AoeRing.Create( WorldPosition, outer );
InnerRing.RingColor = OuterRing.RingColor = RingColor;
}
}
public override void OnPlaceUpdated( Vector3 fromPosition, Vector3 toPosition )
{
base.OnPlaceUpdated( fromPosition, toPosition );
if ( Charging )
{
chargeTime += Time.Delta;
(InnerRing.Radius, OuterRing.Radius) = Radii;
}
}
private void FireChargedPulse()
{
Charging = false;
var (inner, outer) = Radii;
var innerSq = inner * inner;
var outerSq = outer * outer;
var myPos = WorldPosition;
var damage = new DamageInfo( this.GetAttackDamage(), GameObject, GameObject );
damage.SetExplosive( true );
foreach ( var t in Scene.GetAllComponents<Targetable>() )
{
var distSq = myPos.DistanceSquared( t.WorldPosition );
if ( distSq >= innerSq && distSq <= outerSq )
t.OnDamage( in damage );
}
DestroyRings();
Components.Get<PreparedEffects>()?.PerformEffects();
if ( BurstPrefab?.Clone( WorldPosition ).Components.Get<ParticleRingEmitter>() is ParticleRingEmitter ringEmitter )
{
ringEmitter.Radius = Radius;
ringEmitter.Thickness = Thickness;
}
chargeTime = 0.0f;
}
public override void OnPlaceEnded( Vector3 position )
{
base.OnPlaceEnded( position );
if ( Charging )
FireChargedPulse();
}
protected override void OnUseEnds()
{
base.OnUseEnds();
if ( Charging )
FireChargedPulse();
}
}