Remove IClientSingularityInstance, move visual effects to SingularityDistortionComponent (#4194)

* Remove IClientSingularityInstance

* In and out 5 minute refactor

* Component states for singularity distortion

* Fix distortion states

* Address reviews
This commit is contained in:
DrSmugleaf
2021-06-24 04:48:11 +02:00
committed by GitHub
parent 34e457b854
commit 716bee0746
16 changed files with 244 additions and 190 deletions

View File

@@ -1,75 +1,11 @@
using Content.Shared.Singularity.Components; using Content.Shared.Singularity.Components;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
using Robust.Shared.ViewVariables;
namespace Content.Client.Singularity.Components namespace Content.Client.Singularity.Components
{ {
[RegisterComponent] [RegisterComponent]
[ComponentReference(typeof(IClientSingularityInstance))] [ComponentReference(typeof(SharedSingularityComponent))]
class ClientSingularityComponent : SharedSingularityComponent, IClientSingularityInstance public class ClientSingularityComponent : SharedSingularityComponent
{ {
[ViewVariables]
public int Level { get; set; }
//I am lazy
[ViewVariables]
public float Intensity
{
get
{
switch (Level)
{
case 0:
return 0.0f;
case 1:
return 2.7f;
case 2:
return 14.4f;
case 3:
return 47.2f;
case 4:
return 180.0f;
case 5:
return 600.0f;
case 6:
return 800.0f;
}
return -1.0f;
}
}
[ViewVariables]
public float Falloff
{
get
{
switch (Level)
{
case 0:
return 9999f;
case 1:
return 6.4f;
case 2:
return 7.0f;
case 3:
return 8.0f;
case 4:
return 10.0f;
case 5:
return 12.0f;
case 6:
return 12.0f;
}
return -1.0f;
}
}
public override void HandleComponentState(ComponentState? curState, ComponentState? nextState)
{
if (curState is not SingularityComponentState state)
{
return;
}
Level = state.Level;
}
} }
} }

View File

@@ -6,7 +6,7 @@ namespace Content.Client.Singularity.Components
{ {
public class ContainmentFieldComponent : Component public class ContainmentFieldComponent : Component
{ {
public override string Name => "Containment Field"; public override string Name => "ContainmentField";
private SpriteComponent? _spriteComponent; private SpriteComponent? _spriteComponent;
@@ -16,7 +16,7 @@ namespace Content.Client.Singularity.Components
if (!Owner.TryGetComponent(out _spriteComponent)) if (!Owner.TryGetComponent(out _spriteComponent))
{ {
Logger.Error("Containmentfieldcomponent created without spritecomponent"); Logger.Error($"{nameof(ContainmentFieldComponent)} created without {nameof(SpriteComponent)}");
} }
else else
{ {

View File

@@ -1,12 +0,0 @@
namespace Content.Client.Singularity.Components
{
interface IClientSingularityInstance
{
public float Intensity { get; }
public float Falloff { get; }
}
}

View File

@@ -1,17 +0,0 @@
using Robust.Shared.GameObjects;
using Robust.Shared.ViewVariables;
namespace Content.Client.Singularity.Components
{
[RegisterComponent]
[ComponentReference(typeof(IClientSingularityInstance))]
public class ToySingularityComponent : Component, IClientSingularityInstance
{
public override string Name => "ToySingularity";
[ViewVariables(VVAccess.ReadWrite)]
public float Falloff { get; set; } = 2.0f;
[ViewVariables(VVAccess.ReadWrite)]
public float Intensity { get; set; } = 0.25f;
}
}

View File

@@ -1,7 +1,7 @@
#nullable enable #nullable enable
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Content.Client.Singularity.Components; using Content.Shared.Singularity.Components;
using Robust.Client.Graphics; using Robust.Client.Graphics;
using Robust.Shared.Enums; using Robust.Shared.Enums;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
@@ -17,14 +17,14 @@ namespace Content.Client.Singularity
[Dependency] private readonly IComponentManager _componentManager = default!; [Dependency] private readonly IComponentManager _componentManager = default!;
[Dependency] private readonly IEntityManager _entityManager = default!; [Dependency] private readonly IEntityManager _entityManager = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IClyde _displayManager = default!;
private const float MaxDist = 15.0f;
public override OverlaySpace Space => OverlaySpace.WorldSpace; public override OverlaySpace Space => OverlaySpace.WorldSpace;
public override bool RequestScreenTexture => true; public override bool RequestScreenTexture => true;
private readonly ShaderInstance _shader; private readonly ShaderInstance _shader;
private readonly Dictionary<EntityUid, SingularityShaderInstance> _singularities = new();
Dictionary<EntityUid, SingularityShaderInstance> _singularities = new Dictionary<EntityUid, SingularityShaderInstance>();
public SingularityOverlay() public SingularityOverlay()
{ {
@@ -34,7 +34,7 @@ namespace Content.Client.Singularity
public override bool OverwriteTargetFrameBuffer() public override bool OverwriteTargetFrameBuffer()
{ {
return _singularities.Count() > 0; return _singularities.Count > 0;
} }
protected override void Draw(in OverlayDrawArgs args) protected override void Draw(in OverlayDrawArgs args)
@@ -63,10 +63,7 @@ namespace Content.Client.Singularity
} }
//Queries all singulos on the map and either adds or removes them from the list of rendered singulos based on whether they should be drawn (in range? on the same z-level/map? singulo entity still exists?) //Queries all singulos on the map and either adds or removes them from the list of rendered singulos based on whether they should be drawn (in range? on the same z-level/map? singulo entity still exists?)
private float _maxDist = 15.0f;
private void SingularityQuery(IEye? currentEye) private void SingularityQuery(IEye? currentEye)
{ {
if (currentEye == null) if (currentEye == null)
@@ -74,24 +71,24 @@ namespace Content.Client.Singularity
_singularities.Clear(); _singularities.Clear();
return; return;
} }
var currentEyeLoc = currentEye.Position;
var currentMap = currentEye.Position.MapId;
var singuloComponents = _componentManager.EntityQuery<IClientSingularityInstance>(); var currentEyeLoc = currentEye.Position;
foreach (var singuloInterface in singuloComponents) //Add all singulos that are not added yet but qualify
var distortions = _componentManager.EntityQuery<SingularityDistortionComponent>();
foreach (var distortion in distortions) //Add all singulos that are not added yet but qualify
{ {
var singuloComponent = (Component)singuloInterface; var singuloEntity = distortion.Owner;
var singuloEntity = singuloComponent.Owner;
if (!_singularities.Keys.Contains(singuloEntity.Uid) && SinguloQualifies(singuloEntity, currentEyeLoc)) if (!_singularities.Keys.Contains(singuloEntity.Uid) && SinguloQualifies(singuloEntity, currentEyeLoc))
{ {
_singularities.Add(singuloEntity.Uid, new SingularityShaderInstance(singuloEntity.Transform.MapPosition.Position, singuloInterface.Intensity, singuloInterface.Falloff)); _singularities.Add(singuloEntity.Uid, new SingularityShaderInstance(singuloEntity.Transform.MapPosition.Position, distortion.Intensity, distortion.Falloff));
} }
} }
var activeShaderUids = _singularities.Keys; var activeShaderIds = _singularities.Keys;
foreach (var activeSinguloUid in activeShaderUids) //Remove all singulos that are added and no longer qualify foreach (var activeSinguloUid in activeShaderIds) //Remove all singulos that are added and no longer qualify
{ {
if (_entityManager.TryGetEntity(activeSinguloUid, out IEntity? singuloEntity)) if (_entityManager.TryGetEntity(activeSinguloUid, out var singuloEntity))
{ {
if (!SinguloQualifies(singuloEntity, currentEyeLoc)) if (!SinguloQualifies(singuloEntity, currentEyeLoc))
{ {
@@ -99,7 +96,7 @@ namespace Content.Client.Singularity
} }
else else
{ {
if (!singuloEntity.TryGetComponent<IClientSingularityInstance>(out var singuloInterface)) if (!singuloEntity.TryGetComponent<SingularityDistortionComponent>(out var distortion))
{ {
_singularities.Remove(activeSinguloUid); _singularities.Remove(activeSinguloUid);
} }
@@ -107,8 +104,8 @@ namespace Content.Client.Singularity
{ {
var shaderInstance = _singularities[activeSinguloUid]; var shaderInstance = _singularities[activeSinguloUid];
shaderInstance.CurrentMapCoords = singuloEntity.Transform.MapPosition.Position; shaderInstance.CurrentMapCoords = singuloEntity.Transform.MapPosition.Position;
shaderInstance.Intensity = singuloInterface.Intensity; shaderInstance.Intensity = distortion.Intensity;
shaderInstance.Falloff = singuloInterface.Falloff; shaderInstance.Falloff = distortion.Falloff;
} }
} }
@@ -123,7 +120,7 @@ namespace Content.Client.Singularity
private bool SinguloQualifies(IEntity singuloEntity, MapCoordinates currentEyeLoc) private bool SinguloQualifies(IEntity singuloEntity, MapCoordinates currentEyeLoc)
{ {
return singuloEntity.Transform.MapID == currentEyeLoc.MapId && singuloEntity.Transform.Coordinates.InRange(_entityManager, EntityCoordinates.FromMap(_entityManager, singuloEntity.Transform.ParentUid, currentEyeLoc), _maxDist); return singuloEntity.Transform.MapID == currentEyeLoc.MapId && singuloEntity.Transform.Coordinates.InRange(_entityManager, EntityCoordinates.FromMap(_entityManager, singuloEntity.Transform.ParentUid, currentEyeLoc), MaxDist);
} }
private sealed class SingularityShaderInstance private sealed class SingularityShaderInstance
@@ -131,6 +128,7 @@ namespace Content.Client.Singularity
public Vector2 CurrentMapCoords; public Vector2 CurrentMapCoords;
public float Intensity; public float Intensity;
public float Falloff; public float Falloff;
public SingularityShaderInstance(Vector2 mapCoords, float intensity, float falloff) public SingularityShaderInstance(Vector2 mapCoords, float intensity, float falloff)
{ {
CurrentMapCoords = mapCoords; CurrentMapCoords = mapCoords;

View File

@@ -0,0 +1,8 @@
using Content.Shared.Singularity;
namespace Content.Client.Singularity
{
public class SingularitySystem : SharedSingularitySystem
{
}
}

View File

@@ -109,7 +109,7 @@ namespace Content.Server.Radiation
return; return;
if(_duration <= 0f) if(_duration <= 0f)
Owner.Delete(); Owner.QueueDelete();
_duration -= frameTime; _duration -= frameTime;
} }

View File

@@ -1,3 +1,4 @@
using System.Linq;
using Content.Shared.Radiation; using Content.Shared.Radiation;
using JetBrains.Annotations; using JetBrains.Annotations;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
@@ -53,7 +54,7 @@ namespace Content.Server.Radiation
{ {
if (entity.Deleted) continue; if (entity.Deleted) continue;
foreach (var radiation in entity.GetAllComponents<IRadiationAct>()) foreach (var radiation in entity.GetAllComponents<IRadiationAct>().ToArray())
{ {
radiation.RadiationAct(frameTime, comp); radiation.RadiationAct(frameTime, comp);
} }

View File

@@ -1,15 +1,10 @@
#nullable enable #nullable enable
using System.Linq;
using Content.Server.Radiation;
using Content.Shared.Singularity; using Content.Shared.Singularity;
using Content.Shared.Singularity.Components; using Content.Shared.Singularity.Components;
using Robust.Server.GameObjects;
using Robust.Shared.Audio; using Robust.Shared.Audio;
using Robust.Shared.Containers; using Robust.Shared.Containers;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
using Robust.Shared.Maths;
using Robust.Shared.Physics.Collision; using Robust.Shared.Physics.Collision;
using Robust.Shared.Physics.Collision.Shapes;
using Robust.Shared.Physics.Dynamics; using Robust.Shared.Physics.Dynamics;
using Robust.Shared.Player; using Robust.Shared.Player;
using Robust.Shared.Players; using Robust.Shared.Players;
@@ -19,8 +14,11 @@ using Robust.Shared.ViewVariables;
namespace Content.Server.Singularity.Components namespace Content.Server.Singularity.Components
{ {
[RegisterComponent] [RegisterComponent]
[ComponentReference(typeof(SharedSingularityComponent))]
public class ServerSingularityComponent : SharedSingularityComponent, IStartCollide public class ServerSingularityComponent : SharedSingularityComponent, IStartCollide
{ {
private SharedSingularitySystem _singularitySystem = default!;
[ViewVariables(VVAccess.ReadWrite)] [ViewVariables(VVAccess.ReadWrite)]
public int Energy public int Energy
{ {
@@ -36,54 +34,20 @@ namespace Content.Server.Singularity.Components
return; return;
} }
Level = _energy switch var level = _energy switch
{ {
var n when n >= 1500 => 6, >= 1500 => 6,
var n when n >= 1000 => 5, >= 1000 => 5,
var n when n >= 600 => 4, >= 600 => 4,
var n when n >= 300 => 3, >= 300 => 3,
var n when n >= 200 => 2, >= 200 => 2,
var n when n < 200 => 1, < 200 => 1
_ => 1
}; };
_singularitySystem.ChangeSingularityLevel(this, level);
} }
} }
private int _energy = 180; private int _energy = 180;
[ViewVariables]
public int Level
{
get => _level;
set
{
if (value == _level) return;
if (value < 0) value = 0;
if (value > 6) value = 6;
if ((_level > 1) && (value <= 1))
{
// Prevents it getting stuck (see SingularityController.MoveSingulo)
if (_collidableComponent != null) _collidableComponent.LinearVelocity = Vector2.Zero;
}
_level = value;
if(_radiationPulseComponent != null) _radiationPulseComponent.RadsPerSecond = 10 * value;
if (Owner.TryGetComponent(out AppearanceComponent? appearance))
{
appearance.SetData(SingularityVisuals.Level, _level);
}
if (_collidableComponent != null && _collidableComponent.Fixtures.Any() && _collidableComponent.Fixtures[0].Shape is PhysShapeCircle circle)
{
circle.Radius = _level - 0.5f;
}
Dirty();
}
}
private int _level;
[ViewVariables] [ViewVariables]
public int EnergyDrain => public int EnergyDrain =>
Level switch Level switch
@@ -101,11 +65,8 @@ namespace Content.Server.Singularity.Components
// See, two singularities queuing deletion of each other at the same time will annihilate. // See, two singularities queuing deletion of each other at the same time will annihilate.
// This is undesirable behaviour, so this flag allows the imperatively first one processed to take priority. // This is undesirable behaviour, so this flag allows the imperatively first one processed to take priority.
[ViewVariables(VVAccess.ReadWrite)] [ViewVariables(VVAccess.ReadWrite)]
public bool BeingDeletedByAnotherSingularity { get; set; } = false; public bool BeingDeletedByAnotherSingularity { get; set; }
private PhysicsComponent _collidableComponent = default!;
private RadiationPulseComponent _radiationPulseComponent = default!;
private SpriteComponent _spriteComponent = default!;
private IPlayingAudioStream? _playingSound; private IPlayingAudioStream? _playingSound;
public override ComponentState GetComponentState(ICommonSession player) public override ComponentState GetComponentState(ICommonSession player)
@@ -117,9 +78,7 @@ namespace Content.Server.Singularity.Components
{ {
base.Initialize(); base.Initialize();
Owner.EnsureComponent(out _radiationPulseComponent); _singularitySystem = EntitySystem.Get<SharedSingularitySystem>();
Owner.EnsureComponent(out _collidableComponent);
Owner.EnsureComponent(out _spriteComponent);
var audioParams = AudioParams.Default; var audioParams = AudioParams.Default;
audioParams.Loop = true; audioParams.Loop = true;
@@ -128,7 +87,7 @@ namespace Content.Server.Singularity.Components
SoundSystem.Play(Filter.Pvs(Owner), "/Audio/Effects/singularity_form.ogg", Owner); SoundSystem.Play(Filter.Pvs(Owner), "/Audio/Effects/singularity_form.ogg", Owner);
Timer.Spawn(5200,() => _playingSound = SoundSystem.Play(Filter.Pvs(Owner), "/Audio/Effects/singularity.ogg", Owner, audioParams)); Timer.Spawn(5200,() => _playingSound = SoundSystem.Play(Filter.Pvs(Owner), "/Audio/Effects/singularity.ogg", Owner, audioParams));
Level = 1; _singularitySystem.ChangeSingularityLevel(this, 1);
} }
public void Update(int seconds) public void Update(int seconds)
@@ -155,7 +114,8 @@ namespace Content.Server.Singularity.Components
return; return;
} }
if (otherEntity.HasComponent<ContainmentFieldComponent>() || (otherEntity.TryGetComponent<ContainmentFieldGeneratorComponent>(out var component) && component.CanRepell(Owner))) if (otherEntity.HasComponent<ContainmentFieldComponent>() ||
(otherEntity.TryGetComponent<ContainmentFieldGeneratorComponent>(out var component) && component.CanRepell(Owner)))
{ {
return; return;
} }

View File

@@ -1,11 +1,11 @@
using Content.Server.Singularity.Components; using Content.Server.Singularity.Components;
using Content.Shared.Singularity;
using JetBrains.Annotations; using JetBrains.Annotations;
using Robust.Shared.GameObjects;
namespace Content.Server.Singularity.EntitySystems namespace Content.Server.Singularity.EntitySystems
{ {
[UsedImplicitly] [UsedImplicitly]
public class SingularitySystem : EntitySystem public class SingularitySystem : SharedSingularitySystem
{ {
private float _updateInterval = 1.0f; private float _updateInterval = 1.0f;
private float _accumulator; private float _accumulator;
@@ -24,7 +24,6 @@ namespace Content.Server.Singularity.EntitySystems
singularity.Update(1); singularity.Update(1);
} }
} }
} }
} }
} }

View File

@@ -98,6 +98,7 @@ namespace Content.Shared.NetIDs
public const uint SPAWN_AFTER_INTERACT = 1088; public const uint SPAWN_AFTER_INTERACT = 1088;
public const uint DISASSEMBLE_ON_ACTIVATE = 1089; public const uint DISASSEMBLE_ON_ACTIVATE = 1089;
public const uint LIGHT_REPLACER = 1090; public const uint LIGHT_REPLACER = 1090;
public const uint SINGULARITY_DISTORTION = 1091;
// Net IDs for integration tests. // Net IDs for integration tests.
public const uint PREDICTION_TEST = 10001; public const uint PREDICTION_TEST = 10001;

View File

@@ -2,25 +2,43 @@ using System;
using Content.Shared.NetIDs; using Content.Shared.NetIDs;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
using Robust.Shared.Serialization; using Robust.Shared.Serialization;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.ViewVariables;
namespace Content.Shared.Singularity.Components namespace Content.Shared.Singularity.Components
{ {
public abstract class SharedSingularityComponent : Component public abstract class SharedSingularityComponent : Component
{ {
public override string Name => "Singularity"; public override string Name => "Singularity";
public override uint? NetID => ContentNetIDs.SINGULARITY; public override uint? NetID => ContentNetIDs.SINGULARITY;
[DataField("deleteFixture")] public string? DeleteFixtureId { get; } = default;
[Serializable, NetSerializable] /// <summary>
protected sealed class SingularityComponentState : ComponentState /// Changed by <see cref="SharedSingularitySystem.ChangeSingularityLevel"/>
/// </summary>
[ViewVariables]
public int Level { get; set; }
public override void HandleComponentState(ComponentState? curState, ComponentState? nextState)
{ {
public int Level { get; } if (curState is not SingularityComponentState state)
public SingularityComponentState(int level) : base(ContentNetIDs.SINGULARITY)
{ {
Level = level; return;
} }
EntitySystem.Get<SharedSingularitySystem>().ChangeSingularityLevel(this, state.Level);
}
}
[Serializable, NetSerializable]
public sealed class SingularityComponentState : ComponentState
{
public int Level { get; }
public SingularityComponentState(int level) : base(ContentNetIDs.SINGULARITY)
{
Level = level;
} }
} }
} }

View File

@@ -0,0 +1,68 @@
using System;
using Content.Shared.NetIDs;
using Robust.Shared.GameObjects;
using Robust.Shared.Players;
using Robust.Shared.Serialization;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.ViewVariables;
namespace Content.Shared.Singularity.Components
{
[RegisterComponent]
public class SingularityDistortionComponent : Component
{
public override string Name => "SingularityDistortion";
public override uint? NetID => ContentNetIDs.SINGULARITY_DISTORTION;
[DataField("intensity")]
private float _intensity = 0.25f;
[DataField("falloff")]
private float _falloff = 2;
[ViewVariables(VVAccess.ReadWrite)]
public float Intensity
{
get => _intensity;
set => this.SetAndDirtyIfChanged(ref _intensity, value);
}
[ViewVariables(VVAccess.ReadWrite)]
public float Falloff
{
get => _falloff;
set => this.SetAndDirtyIfChanged(ref _falloff, value);
}
public override ComponentState GetComponentState(ICommonSession player)
{
return new SingularityDistortionComponentState(Intensity, Falloff);
}
public override void HandleComponentState(ComponentState? curState, ComponentState? nextState)
{
base.HandleComponentState(curState, nextState);
if (curState is not SingularityDistortionComponentState state)
{
return;
}
Intensity = state.Intensity;
Falloff = state.Falloff;
}
}
[Serializable, NetSerializable]
public class SingularityDistortionComponentState : ComponentState
{
public SingularityDistortionComponentState(float intensity, float falloff) : base(ContentNetIDs.SINGULARITY_DISTORTION)
{
Intensity = intensity;
Falloff = falloff;
}
public float Intensity { get; }
public float Falloff { get; }
}
}

View File

@@ -0,0 +1,90 @@
using System;
using Content.Shared.Radiation;
using Content.Shared.Singularity.Components;
using Robust.Shared.GameObjects;
using Robust.Shared.Maths;
using Robust.Shared.Physics.Collision.Shapes;
namespace Content.Shared.Singularity
{
public abstract class SharedSingularitySystem : EntitySystem
{
private float GetFalloff(int level)
{
return level switch
{
0 => 9999f,
1 => 6.4f,
2 => 7.0f,
3 => 8.0f,
4 => 10.0f,
5 => 12.0f,
6 => 12.0f,
_ => -1.0f
};
}
private float GetIntensity(int level)
{
return level switch
{
0 => 0.0f,
1 => 2.7f,
2 => 14.4f,
3 => 47.2f,
4 => 180.0f,
5 => 600.0f,
6 => 800.0f,
_ => -1.0f
};
}
public void ChangeSingularityLevel(SharedSingularityComponent singularity, int value)
{
if (value == singularity.Level)
{
return;
}
value = Math.Clamp(value, 0, 6);
var physics = singularity.Owner.GetComponentOrNull<PhysicsComponent>();
if (singularity.Level > 1 && value <= 1)
{
// Prevents it getting stuck (see SingularityController.MoveSingulo)
if (physics != null)
{
physics.LinearVelocity = Vector2.Zero;
}
}
singularity.Level = value;
if (singularity.Owner.TryGetComponent(out SharedRadiationPulseComponent? pulse))
{
pulse.RadsPerSecond = 10 * value;
}
if (singularity.Owner.TryGetComponent(out SharedAppearanceComponent? appearance))
{
appearance.SetData(SingularityVisuals.Level, value);
}
if (physics != null &&
singularity.DeleteFixtureId != null &&
physics.GetFixture(singularity.DeleteFixtureId) is {Shape: PhysShapeCircle circle})
{
circle.Radius = value - 0.5f;
}
if (singularity.Owner.TryGetComponent(out SingularityDistortionComponent? distortion))
{
distortion.Falloff = GetFalloff(value);
distortion.Intensity = GetIntensity(value);
}
singularity.Dirty();
}
}
}

View File

@@ -7,7 +7,8 @@
- type: Physics - type: Physics
bodyType: Dynamic bodyType: Dynamic
fixtures: fixtures:
- shape: - id: DeleteCircle
shape:
!type:PhysShapeCircle !type:PhysShapeCircle
radius: 0.5 radius: 0.5
mass: 5 mass: 5
@@ -17,6 +18,7 @@
mask: mask:
- AllMask - AllMask
- type: Singularity - type: Singularity
- type: SingularityDistortion
- type: RadiationPulse - type: RadiationPulse
range: 15 range: 15
decay: false decay: false

View File

@@ -606,7 +606,9 @@
- type: Icon - type: Icon
sprite: Objects/Fun/toys.rsi sprite: Objects/Fun/toys.rsi
state: singularitytoy state: singularitytoy
- type: ToySingularity - type: SingularityDistortion
intensity: 2
falloff: 7
- type: Item - type: Item
size: 12 size: 12
sprite: Objects/Fun/toys.rsi sprite: Objects/Fun/toys.rsi