Containment Field Rework (#9312)
This commit is contained in:
@@ -1,31 +1,7 @@
|
|||||||
using Content.Shared.Singularity.Components;
|
using Content.Shared.Singularity.Components;
|
||||||
using Robust.Client.GameObjects;
|
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.IoC;
|
|
||||||
using Robust.Shared.Log;
|
|
||||||
|
|
||||||
namespace Content.Client.Singularity.Components
|
namespace Content.Client.Singularity.Components;
|
||||||
{
|
|
||||||
[RegisterComponent]
|
|
||||||
[ComponentReference(typeof(SharedContainmentFieldComponent))]
|
|
||||||
public sealed class ContainmentFieldComponent : SharedContainmentFieldComponent
|
|
||||||
{
|
|
||||||
// Jesus what is this code.
|
|
||||||
// Singulo cleanup WHEEENNN
|
|
||||||
private SpriteComponent? _spriteComponent;
|
|
||||||
|
|
||||||
protected override void Initialize()
|
[RegisterComponent]
|
||||||
{
|
[ComponentReference(typeof(SharedContainmentFieldComponent))]
|
||||||
base.Initialize();
|
public sealed class ContainmentFieldComponent : SharedContainmentFieldComponent { }
|
||||||
|
|
||||||
if (!IoCManager.Resolve<IEntityManager>().TryGetComponent(Owner, out _spriteComponent))
|
|
||||||
{
|
|
||||||
Logger.Error($"{nameof(ContainmentFieldComponent)} created without {nameof(SpriteComponent)}");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_spriteComponent.NoRotation = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,12 +1,6 @@
|
|||||||
using Content.Shared.Singularity.Components;
|
using Content.Shared.Singularity.Components;
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
|
|
||||||
namespace Content.Client.Singularity.Components
|
namespace Content.Client.Singularity.Components;
|
||||||
{
|
[RegisterComponent]
|
||||||
[RegisterComponent]
|
[ComponentReference(typeof(SharedContainmentFieldGeneratorComponent))]
|
||||||
[ComponentReference(typeof(SharedContainmentFieldGeneratorComponent))]
|
public sealed class ContainmentFieldGeneratorComponent : SharedContainmentFieldGeneratorComponent { }
|
||||||
public sealed class ContainmentFieldGeneratorComponent : SharedContainmentFieldGeneratorComponent
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,11 +1,24 @@
|
|||||||
using Content.Shared.Singularity.Components;
|
using Content.Shared.Singularity.Components;
|
||||||
|
|
||||||
namespace Content.Server.Singularity.Components
|
namespace Content.Server.Singularity.Components;
|
||||||
|
|
||||||
|
[RegisterComponent]
|
||||||
|
[ComponentReference(typeof(SharedContainmentFieldComponent))]
|
||||||
|
public sealed class ContainmentFieldComponent : SharedContainmentFieldComponent
|
||||||
{
|
{
|
||||||
[RegisterComponent]
|
/// <summary>
|
||||||
[ComponentReference(typeof(SharedContainmentFieldComponent))]
|
/// The throw force for the field if an entity collides with it
|
||||||
public sealed class ContainmentFieldComponent : SharedContainmentFieldComponent
|
/// The lighter the mass the further it will throw. 5 mass will go about 4 tiles out, 70 mass goes only a couple tiles.
|
||||||
{
|
/// </summary>
|
||||||
public ContainmentFieldConnection? Parent;
|
[ViewVariables]
|
||||||
}
|
[DataField("throwForce")]
|
||||||
|
public float ThrowForce = 100f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This shouldn't be at 99999 or higher to prevent the singulo glitching out
|
||||||
|
/// Will throw anything at the supplied mass or less that collides with the field.
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables]
|
||||||
|
[DataField("maxMass")]
|
||||||
|
public float MaxMass = 10000f;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,112 +0,0 @@
|
|||||||
using System.Threading;
|
|
||||||
using Content.Server.Singularity.EntitySystems;
|
|
||||||
using Content.Shared.Singularity.Components;
|
|
||||||
using Robust.Server.GameObjects;
|
|
||||||
using Timer = Robust.Shared.Timing.Timer;
|
|
||||||
|
|
||||||
namespace Content.Server.Singularity.Components
|
|
||||||
{
|
|
||||||
public sealed class ContainmentFieldConnection : IDisposable
|
|
||||||
{
|
|
||||||
public ContainmentFieldGeneratorComponent Generator1;
|
|
||||||
public ContainmentFieldGeneratorComponent Generator2;
|
|
||||||
private readonly List<EntityUid> _fields = new();
|
|
||||||
private int _sharedEnergyPool;
|
|
||||||
private readonly CancellationTokenSource _powerDecreaseCancellationTokenSource = new();
|
|
||||||
public int SharedEnergyPool
|
|
||||||
{
|
|
||||||
get => _sharedEnergyPool;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_sharedEnergyPool = Math.Clamp(value, 0, 25);
|
|
||||||
if (_sharedEnergyPool == 0)
|
|
||||||
{
|
|
||||||
Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public ContainmentFieldConnection(ContainmentFieldGeneratorComponent generator1, ContainmentFieldGeneratorComponent generator2)
|
|
||||||
{
|
|
||||||
Generator1 = generator1;
|
|
||||||
Generator2 = generator2;
|
|
||||||
|
|
||||||
//generateFields
|
|
||||||
var pos1 = IoCManager.Resolve<IEntityManager>().GetComponent<TransformComponent>(generator1.Owner).Coordinates;
|
|
||||||
var pos2 = IoCManager.Resolve<IEntityManager>().GetComponent<TransformComponent>(generator2.Owner).Coordinates;
|
|
||||||
if (pos1 == pos2)
|
|
||||||
{
|
|
||||||
Dispose();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var entityManager = IoCManager.Resolve<IEntityManager>();
|
|
||||||
|
|
||||||
var delta = (pos2 - pos1).Position;
|
|
||||||
var dirVec = delta.Normalized;
|
|
||||||
var stopDist = delta.Length;
|
|
||||||
var currentOffset = dirVec;
|
|
||||||
while (currentOffset.Length < stopDist)
|
|
||||||
{
|
|
||||||
var currentCoords = pos1.Offset(currentOffset);
|
|
||||||
var newEnt = entityManager.SpawnEntity("ContainmentField", currentCoords);
|
|
||||||
if (!IoCManager.Resolve<IEntityManager>().TryGetComponent<ContainmentFieldComponent?>(newEnt, out var containmentFieldComponent))
|
|
||||||
{
|
|
||||||
Logger.Error("While creating Fields in ContainmentFieldConnection, a ContainmentField without a ContainmentFieldComponent was created. Deleting newly spawned ContainmentField...");
|
|
||||||
IoCManager.Resolve<IEntityManager>().DeleteEntity(newEnt);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
containmentFieldComponent.Parent = this;
|
|
||||||
IoCManager.Resolve<IEntityManager>().GetComponent<TransformComponent>(newEnt).WorldRotation = IoCManager.Resolve<IEntityManager>().GetComponent<TransformComponent>(generator1.Owner).WorldRotation + dirVec.ToWorldAngle();
|
|
||||||
|
|
||||||
_fields.Add(newEnt);
|
|
||||||
currentOffset += dirVec;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Timer.SpawnRepeating(1000, () => { SharedEnergyPool--; }, _powerDecreaseCancellationTokenSource.Token);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool CanRepel(SharedSingularityComponent toRepel)
|
|
||||||
{
|
|
||||||
var powerNeeded = 2 * toRepel.Level + 1;
|
|
||||||
|
|
||||||
return _sharedEnergyPool > powerNeeded;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
_powerDecreaseCancellationTokenSource.Cancel();
|
|
||||||
foreach (var field in _fields)
|
|
||||||
{
|
|
||||||
IoCManager.Resolve<IEntityManager>().DeleteEntity(field);
|
|
||||||
}
|
|
||||||
_fields.Clear();
|
|
||||||
|
|
||||||
RemoveConnection(this, Generator1);
|
|
||||||
RemoveConnection(this, Generator2);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RemoveConnection(ContainmentFieldConnection? connection, ContainmentFieldGeneratorComponent component)
|
|
||||||
{
|
|
||||||
if (component.Connection1?.Item2 == connection)
|
|
||||||
{
|
|
||||||
component.Connection1 = null;
|
|
||||||
}
|
|
||||||
else if (component.Connection2?.Item2 == connection)
|
|
||||||
{
|
|
||||||
component.Connection2 = null;
|
|
||||||
}
|
|
||||||
else if (connection != null)
|
|
||||||
{
|
|
||||||
Logger.Error("RemoveConnection called on Containmentfieldgenerator with a connection that can't be found in its connections.");
|
|
||||||
}
|
|
||||||
if (IoCManager.Resolve<IEntityManager>().TryGetComponent<PointLightComponent>(component.Owner, out var pointLightComponent))
|
|
||||||
{
|
|
||||||
bool hasAnyConnection = (component.Connection1 != null) || (component.Connection2 != null);
|
|
||||||
pointLightComponent.Enabled = hasAnyConnection;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,33 +1,107 @@
|
|||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
using System.Linq;
|
|
||||||
using Content.Shared.Physics;
|
using Content.Shared.Physics;
|
||||||
using Content.Shared.Singularity.Components;
|
using Content.Shared.Singularity.Components;
|
||||||
using Robust.Server.GameObjects;
|
using Content.Shared.Tag;
|
||||||
using Robust.Shared.Physics;
|
using Robust.Shared.Prototypes;
|
||||||
|
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||||
|
|
||||||
namespace Content.Server.Singularity.Components
|
namespace Content.Server.Singularity.Components;
|
||||||
|
[RegisterComponent]
|
||||||
|
[ComponentReference(typeof(SharedContainmentFieldGeneratorComponent))]
|
||||||
|
public sealed class ContainmentFieldGeneratorComponent : SharedContainmentFieldGeneratorComponent
|
||||||
{
|
{
|
||||||
[RegisterComponent]
|
|
||||||
[ComponentReference(typeof(SharedContainmentFieldGeneratorComponent))]
|
|
||||||
public sealed class ContainmentFieldGeneratorComponent : SharedContainmentFieldGeneratorComponent
|
|
||||||
{
|
|
||||||
private int _powerBuffer;
|
private int _powerBuffer;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Store power with a cap. Decrease over time if not being powered from source.
|
||||||
|
/// </summary>
|
||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
|
[DataField("powerBuffer")]
|
||||||
public int PowerBuffer
|
public int PowerBuffer
|
||||||
{
|
{
|
||||||
get => _powerBuffer;
|
get => _powerBuffer;
|
||||||
set => _powerBuffer = Math.Clamp(value, 0, 6);
|
set => _powerBuffer = Math.Clamp(value, 0, 25); //have this decrease over time if not hit by a bolt
|
||||||
}
|
}
|
||||||
|
|
||||||
public Tuple<Direction, ContainmentFieldConnection>? Connection1;
|
/// <summary>
|
||||||
public Tuple<Direction, ContainmentFieldConnection>? Connection2;
|
/// The minimum the field generator needs to start generating a connection
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
[DataField("powerMinimum")]
|
||||||
|
public int PowerMinimum = 6;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// How much power should this field generator receive from a collision
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
[DataField("power")]
|
||||||
|
public int PowerReceived = 3;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// How much power should this field generator lose if not powered?
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
[DataField("powerLoss")]
|
||||||
|
public int PowerLoss = 2;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Used to check if it's received power recently.
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables]
|
||||||
|
[DataField("accumulator")]
|
||||||
|
public float Accumulator;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// How many seconds should the generators wait before losing power?
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables]
|
||||||
|
[DataField("threshold")]
|
||||||
|
public float Threshold = 10f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// How many tiles should this field check before giving up?
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables]
|
||||||
|
[DataField("maxLength")]
|
||||||
|
public float MaxLength = 8F;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// What collision should power this generator?
|
||||||
|
/// It really shouldn't be anything but an emitter bolt but it's here for fun.
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
[DataField("idTag", customTypeSerializer: typeof(PrototypeIdSerializer<TagPrototype>))]
|
||||||
|
public string IDTag = "EmitterBolt";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Is the generator toggled on?
|
||||||
|
/// </summary>
|
||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
public bool Enabled;
|
public bool Enabled;
|
||||||
|
|
||||||
[ViewVariables]
|
/// <summary>
|
||||||
|
/// Is this generator connected to fields?
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
public bool IsConnected;
|
public bool IsConnected;
|
||||||
|
|
||||||
}
|
/// <summary>
|
||||||
|
/// The masks the raycast should not go through
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables]
|
||||||
|
[DataField("collisionMask")]
|
||||||
|
public int CollisionMask = (int) (CollisionGroup.MobMask | CollisionGroup.Impassable | CollisionGroup.MachineMask);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A collection of connections that the generator has based on direction.
|
||||||
|
/// Stores a list of fields connected between generators in this direction.
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables]
|
||||||
|
public Dictionary<Direction, (ContainmentFieldGeneratorComponent, List<EntityUid>)> Connections = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// What fields should this spawn?
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
[DataField("createdField", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
|
||||||
|
public string CreatedField = "ContainmentField";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,36 +1,79 @@
|
|||||||
using Content.Server.ParticleAccelerator.Components;
|
using Content.Server.Singularity.Components;
|
||||||
using Content.Server.Singularity.Components;
|
|
||||||
using Content.Shared.Physics;
|
|
||||||
using Content.Shared.Singularity.Components;
|
using Content.Shared.Singularity.Components;
|
||||||
using Content.Shared.Tag;
|
using Content.Shared.Tag;
|
||||||
using Robust.Server.GameObjects;
|
using Robust.Server.GameObjects;
|
||||||
using Robust.Shared.Physics;
|
using Robust.Shared.Physics;
|
||||||
using Robust.Shared.Physics.Dynamics;
|
using Robust.Shared.Physics.Dynamics;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Content.Server.Popups;
|
using Content.Server.Popups;
|
||||||
using Content.Shared.Construction.Components;
|
using Content.Shared.Construction.Components;
|
||||||
|
using Content.Shared.Examine;
|
||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
|
using Content.Shared.Popups;
|
||||||
|
using Content.Shared.Throwing;
|
||||||
using Robust.Shared.Player;
|
using Robust.Shared.Player;
|
||||||
|
|
||||||
namespace Content.Server.Singularity.EntitySystems
|
namespace Content.Server.Singularity.EntitySystems;
|
||||||
|
|
||||||
|
public sealed class ContainmentFieldGeneratorSystem : EntitySystem
|
||||||
{
|
{
|
||||||
public sealed class ContainmentFieldGeneratorSystem : EntitySystem
|
|
||||||
{
|
|
||||||
[Dependency] private readonly TagSystem _tags = default!;
|
[Dependency] private readonly TagSystem _tags = default!;
|
||||||
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
||||||
|
[Dependency] private readonly PhysicsSystem _physics = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
SubscribeLocalEvent<ContainmentFieldGeneratorComponent, ComponentRemove>(OnComponentRemoved);
|
|
||||||
SubscribeLocalEvent<ContainmentFieldComponent, StartCollideEvent>(HandleFieldCollide);
|
|
||||||
SubscribeLocalEvent<ContainmentFieldGeneratorComponent, StartCollideEvent>(HandleGeneratorCollide);
|
SubscribeLocalEvent<ContainmentFieldGeneratorComponent, StartCollideEvent>(HandleGeneratorCollide);
|
||||||
SubscribeLocalEvent<ParticleProjectileComponent, StartCollideEvent>(HandleParticleCollide);
|
SubscribeLocalEvent<ContainmentFieldGeneratorComponent, ExaminedEvent>(OnExamine);
|
||||||
SubscribeLocalEvent<ContainmentFieldGeneratorComponent, AnchorStateChangedEvent>(OnAnchorChanged);
|
|
||||||
SubscribeLocalEvent<ContainmentFieldGeneratorComponent, UnanchorAttemptEvent>(OnUnanchorAttempt);
|
|
||||||
SubscribeLocalEvent<ContainmentFieldGeneratorComponent, InteractHandEvent>(OnInteract);
|
SubscribeLocalEvent<ContainmentFieldGeneratorComponent, InteractHandEvent>(OnInteract);
|
||||||
|
SubscribeLocalEvent<ContainmentFieldGeneratorComponent, AnchorStateChangedEvent>(OnAnchorChanged);
|
||||||
|
SubscribeLocalEvent<ContainmentFieldGeneratorComponent, ReAnchorEvent>(OnReanchorEvent);
|
||||||
|
SubscribeLocalEvent<ContainmentFieldGeneratorComponent, UnanchorAttemptEvent>(OnUnanchorAttempt);
|
||||||
|
SubscribeLocalEvent<ContainmentFieldGeneratorComponent, ComponentRemove>(OnComponentRemoved);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Update(float frameTime)
|
||||||
|
{
|
||||||
|
base.Update(frameTime);
|
||||||
|
|
||||||
|
foreach (var generator in EntityQuery<ContainmentFieldGeneratorComponent>())
|
||||||
|
{
|
||||||
|
if (generator.PowerBuffer <= 0) //don't drain power if there's no power, or if it's somehow less than 0.
|
||||||
|
return;
|
||||||
|
|
||||||
|
generator.Accumulator += frameTime;
|
||||||
|
|
||||||
|
if (generator.Accumulator >= generator.Threshold)
|
||||||
|
{
|
||||||
|
LosePower(generator.PowerLoss, generator);
|
||||||
|
generator.Accumulator -= generator.Threshold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Events
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A generator receives power from a source colliding with it.
|
||||||
|
/// </summary>
|
||||||
|
private void HandleGeneratorCollide(EntityUid uid, ContainmentFieldGeneratorComponent component, StartCollideEvent args)
|
||||||
|
{
|
||||||
|
if (_tags.HasTag(args.OtherFixture.Body.Owner, component.IDTag))
|
||||||
|
{
|
||||||
|
ReceivePower(component.PowerReceived, component);
|
||||||
|
component.Accumulator = 0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnExamine(EntityUid uid, ContainmentFieldGeneratorComponent component, ExaminedEvent args)
|
||||||
|
{
|
||||||
|
if (component.Enabled)
|
||||||
|
args.PushMarkup(Loc.GetString("comp-containment-on"));
|
||||||
|
|
||||||
|
else
|
||||||
|
args.PushMarkup(Loc.GetString("comp-containment-off"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnInteract(EntityUid uid, ContainmentFieldGeneratorComponent component, InteractHandEvent args)
|
private void OnInteract(EntityUid uid, ContainmentFieldGeneratorComponent component, InteractHandEvent args)
|
||||||
@@ -44,21 +87,32 @@ namespace Content.Server.Singularity.EntitySystems
|
|||||||
TurnOn(component);
|
TurnOn(component);
|
||||||
else if (component.Enabled && component.IsConnected)
|
else if (component.Enabled && component.IsConnected)
|
||||||
{
|
{
|
||||||
_popupSystem.PopupEntity(Loc.GetString("comp-containment-anchor-warning"), args.User, Filter.Entities(args.User));
|
_popupSystem.PopupEntity(Loc.GetString("comp-containment-toggle-warning"), args.User, Filter.Entities(args.User), PopupType.LargeCaution);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
TurnOff(component);
|
TurnOff(component);
|
||||||
}
|
}
|
||||||
|
|
||||||
args.Handled = true;
|
args.Handled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnUnanchorAttempt(EntityUid uid, ContainmentFieldGeneratorComponent component, UnanchorAttemptEvent args)
|
private void OnAnchorChanged(EntityUid uid, ContainmentFieldGeneratorComponent component, ref AnchorStateChangedEvent args)
|
||||||
|
{
|
||||||
|
if (!args.Anchored)
|
||||||
|
RemoveConnections(component);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnReanchorEvent(EntityUid uid, ContainmentFieldGeneratorComponent component, ref ReAnchorEvent args)
|
||||||
|
{
|
||||||
|
GridCheck(component);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnUnanchorAttempt(EntityUid uid, ContainmentFieldGeneratorComponent component,
|
||||||
|
UnanchorAttemptEvent args)
|
||||||
{
|
{
|
||||||
if (component.Enabled)
|
if (component.Enabled)
|
||||||
{
|
{
|
||||||
_popupSystem.PopupEntity(Loc.GetString("comp-containment-anchor-warning"), args.User, Filter.Entities(args.User));
|
_popupSystem.PopupEntity(Loc.GetString("comp-containment-anchor-warning"), args.User, Filter.Entities(args.User), PopupType.LargeCaution);
|
||||||
args.Cancel();
|
args.Cancel();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -66,199 +120,296 @@ namespace Content.Server.Singularity.EntitySystems
|
|||||||
private void TurnOn(ContainmentFieldGeneratorComponent component)
|
private void TurnOn(ContainmentFieldGeneratorComponent component)
|
||||||
{
|
{
|
||||||
component.Enabled = true;
|
component.Enabled = true;
|
||||||
|
ChangeFieldVisualizer(component);
|
||||||
_popupSystem.PopupEntity(Loc.GetString("comp-containment-turned-on"), component.Owner, Filter.Pvs(component.Owner));
|
_popupSystem.PopupEntity(Loc.GetString("comp-containment-turned-on"), component.Owner, Filter.Pvs(component.Owner));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void TurnOff(ContainmentFieldGeneratorComponent component)
|
private void TurnOff(ContainmentFieldGeneratorComponent component)
|
||||||
{
|
{
|
||||||
component.Enabled = false;
|
component.Enabled = false;
|
||||||
|
ChangeFieldVisualizer(component);
|
||||||
_popupSystem.PopupEntity(Loc.GetString("comp-containment-turned-off"), component.Owner, Filter.Pvs(component.Owner));
|
_popupSystem.PopupEntity(Loc.GetString("comp-containment-turned-off"), component.Owner, Filter.Pvs(component.Owner));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnComponentRemoved(EntityUid uid, ContainmentFieldGeneratorComponent component, ComponentRemove args)
|
private void OnComponentRemoved(EntityUid uid, ContainmentFieldGeneratorComponent component, ComponentRemove args)
|
||||||
{
|
{
|
||||||
component.Connection1?.Item2.Dispose();
|
RemoveConnections(component);
|
||||||
component.Connection2?.Item2.Dispose();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnAnchorChanged(EntityUid uid, ContainmentFieldGeneratorComponent component, ref AnchorStateChangedEvent args)
|
/// <summary>
|
||||||
|
/// Deletes the fields and removes the respective connections for the generators.
|
||||||
|
/// </summary>
|
||||||
|
private void RemoveConnections(ContainmentFieldGeneratorComponent component)
|
||||||
{
|
{
|
||||||
if (!args.Anchored)
|
foreach (var (direction, value) in component.Connections)
|
||||||
{
|
{
|
||||||
component.Connection1?.Item2.Dispose();
|
foreach (var field in value.Item2)
|
||||||
component.Connection2?.Item2.Dispose();
|
{
|
||||||
|
QueueDel(field);
|
||||||
}
|
}
|
||||||
|
value.Item1.Connections.Remove(direction.GetOpposite());
|
||||||
|
|
||||||
|
if (value.Item1.Connections.Count == 0) //Change isconnected only if there's no more connections
|
||||||
|
{
|
||||||
|
value.Item1.IsConnected = false;
|
||||||
|
ChangeOnLightVisualizer(value.Item1);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleParticleCollide(EntityUid uid, ParticleProjectileComponent component, StartCollideEvent args)
|
ChangeFieldVisualizer(value.Item1);
|
||||||
{
|
|
||||||
if (EntityManager.TryGetComponent<SingularityGeneratorComponent?>(args.OtherFixture.Body.Owner, out var singularityGeneratorComponent))
|
|
||||||
{
|
|
||||||
singularityGeneratorComponent.Power += component.State switch
|
|
||||||
{
|
|
||||||
ParticleAcceleratorPowerState.Standby => 0,
|
|
||||||
ParticleAcceleratorPowerState.Level0 => 1,
|
|
||||||
ParticleAcceleratorPowerState.Level1 => 2,
|
|
||||||
ParticleAcceleratorPowerState.Level2 => 4,
|
|
||||||
ParticleAcceleratorPowerState.Level3 => 8,
|
|
||||||
_ => 0
|
|
||||||
};
|
|
||||||
|
|
||||||
EntityManager.QueueDeleteEntity(uid);
|
|
||||||
}
|
}
|
||||||
|
component.Connections.Clear();
|
||||||
|
component.IsConnected = false;
|
||||||
|
ChangeOnLightVisualizer(component);
|
||||||
|
ChangeFieldVisualizer(component);
|
||||||
|
_popupSystem.PopupEntity(Loc.GetString("comp-containment-disconnected"), component.Owner, Filter.Pvs(component.Owner), PopupType.LargeCaution);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleGeneratorCollide(EntityUid uid, ContainmentFieldGeneratorComponent component, StartCollideEvent args)
|
#endregion
|
||||||
{
|
|
||||||
if (_tags.HasTag(args.OtherFixture.Body.Owner, "EmitterBolt"))
|
|
||||||
{
|
|
||||||
ReceivePower(6, component);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void HandleFieldCollide(EntityUid uid, ContainmentFieldComponent component, StartCollideEvent args)
|
#region Connections
|
||||||
{
|
|
||||||
if (component.Parent == null)
|
|
||||||
{
|
|
||||||
EntityManager.QueueDeleteEntity(uid);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Stores power in the generator. If it hits the threshold, it tries to establish a connection.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="power">The power that this generator received from the collision in <see cref="HandleGeneratorCollide"/></param>
|
||||||
public void ReceivePower(int power, ContainmentFieldGeneratorComponent component)
|
public void ReceivePower(int power, ContainmentFieldGeneratorComponent component)
|
||||||
{
|
{
|
||||||
var totalPower = power + component.PowerBuffer;
|
component.PowerBuffer += power;
|
||||||
var powerPerConnection = totalPower / 2;
|
|
||||||
var newBuffer = totalPower % 2;
|
|
||||||
TryPowerConnection(ref component.Connection1, ref newBuffer, powerPerConnection, component);
|
|
||||||
TryPowerConnection(ref component.Connection2, ref newBuffer, powerPerConnection, component);
|
|
||||||
|
|
||||||
component.PowerBuffer = newBuffer;
|
var genXForm = Transform(component.Owner);
|
||||||
|
|
||||||
|
if (component.PowerBuffer >= component.PowerMinimum)
|
||||||
|
{
|
||||||
|
var directions = Enum.GetValues<Direction>().Length;
|
||||||
|
for (int i = 0; i < directions-1; i+=2)
|
||||||
|
{
|
||||||
|
var dir = (Direction)i;
|
||||||
|
|
||||||
|
if (component.Connections.ContainsKey(dir))
|
||||||
|
continue; // This direction already has an active connection
|
||||||
|
|
||||||
|
TryGenerateFieldConnection(dir, component, genXForm);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ChangePowerVisualizer(power, component);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LosePower(int power, ContainmentFieldGeneratorComponent component)
|
||||||
|
{
|
||||||
|
component.PowerBuffer -= power;
|
||||||
|
|
||||||
|
if (component.PowerBuffer < component.PowerMinimum && component.Connections.Count != 0)
|
||||||
|
{
|
||||||
|
RemoveConnections(component);
|
||||||
|
}
|
||||||
|
|
||||||
|
ChangePowerVisualizer(power, component);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This will attempt to establish a connection of fields between two generators.
|
||||||
|
/// If all the checks pass and fields spawn, it will store this connection on each respective generator.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dir">The field generator establishes a connection in this direction.</param>
|
||||||
|
/// <param name="component">The field generator component</param>
|
||||||
|
/// <param name="gen1XForm">The transform component for the first generator</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private bool TryGenerateFieldConnection(Direction dir, ContainmentFieldGeneratorComponent component, TransformComponent gen1XForm)
|
||||||
|
{
|
||||||
|
if (!component.Enabled)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!gen1XForm.Anchored)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var genWorldPosRot = gen1XForm.GetWorldPositionRotation();
|
||||||
|
var dirRad = dir.ToAngle() + genWorldPosRot.WorldRotation; //needs to be like this for the raycast to work properly
|
||||||
|
|
||||||
|
var ray = new CollisionRay(genWorldPosRot.WorldPosition, dirRad.ToVec(), component.CollisionMask);
|
||||||
|
var rayCastResults = _physics.IntersectRay(gen1XForm.MapID, ray, component.MaxLength, component.Owner, false);
|
||||||
|
var genQuery = GetEntityQuery<ContainmentFieldGeneratorComponent>();
|
||||||
|
|
||||||
|
RayCastResults? closestResult = null;
|
||||||
|
|
||||||
|
foreach (var result in rayCastResults)
|
||||||
|
{
|
||||||
|
if (genQuery.HasComponent(result.HitEntity))
|
||||||
|
closestResult = result;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (closestResult == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var ent = closestResult.Value.HitEntity;
|
||||||
|
|
||||||
|
if (!TryComp<ContainmentFieldGeneratorComponent?>(ent, out var otherFieldGeneratorComponent) ||
|
||||||
|
otherFieldGeneratorComponent == component ||
|
||||||
|
!TryComp<PhysicsComponent>(ent, out var collidableComponent) ||
|
||||||
|
collidableComponent.BodyType != BodyType.Static ||
|
||||||
|
gen1XForm.ParentUid != Transform(otherFieldGeneratorComponent.Owner).ParentUid)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var fields = GenerateFieldConnection(component, otherFieldGeneratorComponent);
|
||||||
|
|
||||||
|
component.Connections[dir] = (otherFieldGeneratorComponent, fields);
|
||||||
|
otherFieldGeneratorComponent.Connections[dir.GetOpposite()] = (component, fields);
|
||||||
|
ChangeFieldVisualizer(otherFieldGeneratorComponent);
|
||||||
|
|
||||||
|
if (!component.IsConnected)
|
||||||
|
{
|
||||||
|
component.IsConnected = true;
|
||||||
|
ChangeOnLightVisualizer(component);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!otherFieldGeneratorComponent.IsConnected)
|
||||||
|
{
|
||||||
|
otherFieldGeneratorComponent.IsConnected = true;
|
||||||
|
ChangeOnLightVisualizer(otherFieldGeneratorComponent);
|
||||||
|
}
|
||||||
|
|
||||||
|
ChangeFieldVisualizer(component);
|
||||||
|
UpdateConnectionLights(component);
|
||||||
|
_popupSystem.PopupEntity(Loc.GetString("comp-containment-connected"), component.Owner, Filter.Pvs(component.Owner));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Spawns fields between two generators if the <see cref="TryGenerateFieldConnection"/> finds two generators to connect.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="firstGenComp">The source field generator</param>
|
||||||
|
/// <param name="secondGenComp">The second generator that the source is connected to</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private List<EntityUid> GenerateFieldConnection(ContainmentFieldGeneratorComponent firstGenComp, ContainmentFieldGeneratorComponent secondGenComp)
|
||||||
|
{
|
||||||
|
var fieldList = new List<EntityUid>();
|
||||||
|
var gen1Coords = Transform(firstGenComp.Owner).Coordinates;
|
||||||
|
var gen2Coords = Transform(secondGenComp.Owner).Coordinates;
|
||||||
|
|
||||||
|
var delta = (gen2Coords - gen1Coords).Position;
|
||||||
|
var dirVec = delta.Normalized;
|
||||||
|
var stopDist = delta.Length;
|
||||||
|
var currentOffset = dirVec;
|
||||||
|
while (currentOffset.Length < stopDist)
|
||||||
|
{
|
||||||
|
var currentCoords = gen1Coords.Offset(currentOffset);
|
||||||
|
var newField = Spawn(firstGenComp.CreatedField, currentCoords);
|
||||||
|
|
||||||
|
var fieldXForm = Transform(newField);
|
||||||
|
fieldXForm.AttachParent(firstGenComp.Owner);
|
||||||
|
if (dirVec.GetDir() == Direction.East || dirVec.GetDir() == Direction.West)
|
||||||
|
{
|
||||||
|
var angle = fieldXForm.LocalPosition.ToAngle();
|
||||||
|
var rotateBy90 = angle.Degrees + 90;
|
||||||
|
var rotatedAngle = Angle.FromDegrees(rotateBy90);
|
||||||
|
|
||||||
|
fieldXForm.LocalRotation = rotatedAngle;
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldList.Add(newField);
|
||||||
|
currentOffset += dirVec;
|
||||||
|
}
|
||||||
|
return fieldList;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a light component for the spawned fields.
|
||||||
|
/// </summary>
|
||||||
public void UpdateConnectionLights(ContainmentFieldGeneratorComponent component)
|
public void UpdateConnectionLights(ContainmentFieldGeneratorComponent component)
|
||||||
{
|
{
|
||||||
if (EntityManager.TryGetComponent<PointLightComponent>(component.Owner, out var pointLightComponent))
|
if (EntityManager.TryGetComponent<PointLightComponent>(component.Owner, out var pointLightComponent))
|
||||||
{
|
{
|
||||||
bool hasAnyConnection = (component.Connection1 != null) || (component.Connection2 != null);
|
bool hasAnyConnection = component.Connections != null;
|
||||||
pointLightComponent.Enabled = hasAnyConnection;
|
pointLightComponent.Enabled = hasAnyConnection;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveConnection(ContainmentFieldConnection? connection, ContainmentFieldGeneratorComponent component)
|
/// <summary>
|
||||||
|
/// Checks to see if this or the other gens connected to a new grid. If they did, remove connection.
|
||||||
|
/// </summary>
|
||||||
|
public void GridCheck(ContainmentFieldGeneratorComponent component)
|
||||||
{
|
{
|
||||||
if (component.Connection1?.Item2 == connection)
|
var xFormQuery = GetEntityQuery<TransformComponent>();
|
||||||
|
|
||||||
|
foreach (var (_, generators) in component.Connections)
|
||||||
{
|
{
|
||||||
component.Connection1 = null;
|
var gen1ParentGrid = xFormQuery.GetComponent(component.Owner).ParentUid;
|
||||||
component.IsConnected = false;
|
var gent2ParentGrid = xFormQuery.GetComponent(generators.Item1.Owner).ParentUid;
|
||||||
UpdateConnectionLights(component);
|
|
||||||
}
|
if (gen1ParentGrid != gent2ParentGrid)
|
||||||
else if (component.Connection2?.Item2 == connection)
|
RemoveConnections(component);
|
||||||
{
|
|
||||||
component.Connection2 = null;
|
|
||||||
component.IsConnected = false;
|
|
||||||
UpdateConnectionLights(component);
|
|
||||||
}
|
|
||||||
else if (connection != null)
|
|
||||||
{
|
|
||||||
Logger.Error("RemoveConnection called on Containmentfieldgenerator with a connection that can't be found in its connections.");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool TryGenerateFieldConnection([NotNullWhen(true)] ref Tuple<Direction, ContainmentFieldConnection>? propertyFieldTuple, ContainmentFieldGeneratorComponent component)
|
#endregion
|
||||||
|
|
||||||
|
#region VisualizerHelpers
|
||||||
|
/// <summary>
|
||||||
|
/// Check if a fields power falls between certain ranges to update the field gen visual for power.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="power"></param>
|
||||||
|
/// <param name="component"></param>
|
||||||
|
private void ChangePowerVisualizer(int power, ContainmentFieldGeneratorComponent component)
|
||||||
{
|
{
|
||||||
if (propertyFieldTuple != null) return false;
|
if (!TryComp<AppearanceComponent>(component.Owner, out var appearance))
|
||||||
if (!component.Enabled) return false; //don't gen a field unless it's on
|
return;
|
||||||
if (EntityManager.TryGetComponent<TransformComponent>(component.Owner, out var xform) && !xform.Anchored) return false;
|
|
||||||
|
|
||||||
foreach (var direction in new[] { Direction.North, Direction.East, Direction.South, Direction.West })
|
if(component.PowerBuffer == 0)
|
||||||
|
appearance.SetData(ContainmentFieldGeneratorVisuals.PowerLight, PowerLevelVisuals.NoPower);
|
||||||
|
|
||||||
|
if (component.PowerBuffer > 0 && component.PowerBuffer < component.PowerMinimum)
|
||||||
|
appearance.SetData(ContainmentFieldGeneratorVisuals.PowerLight, PowerLevelVisuals.LowPower);
|
||||||
|
|
||||||
|
if (component.PowerBuffer >= component.PowerMinimum && component.PowerBuffer < 25)
|
||||||
{
|
{
|
||||||
if (component.Connection1?.Item1 == direction || component.Connection2?.Item1 == direction) continue;
|
appearance.SetData(ContainmentFieldGeneratorVisuals.PowerLight, PowerLevelVisuals.MediumPower);
|
||||||
|
|
||||||
var dirVec = EntityManager.GetComponent<TransformComponent>(component.Owner).WorldRotation.RotateVec(direction.ToVec());
|
|
||||||
var ray = new CollisionRay(EntityManager.GetComponent<TransformComponent>(component.Owner).WorldPosition, dirVec, (int) CollisionGroup.MobMask);
|
|
||||||
var rawRayCastResults = EntitySystem.Get<SharedPhysicsSystem>().IntersectRay(EntityManager.GetComponent<TransformComponent>(component.Owner).MapID, ray, 4.5f, component.Owner, false);
|
|
||||||
|
|
||||||
var rayCastResults = rawRayCastResults as RayCastResults[] ?? rawRayCastResults.ToArray();
|
|
||||||
if (!rayCastResults.Any()) continue;
|
|
||||||
|
|
||||||
RayCastResults? closestResult = null;
|
|
||||||
var smallestDist = 4.5f;
|
|
||||||
foreach (var res in rayCastResults)
|
|
||||||
{
|
|
||||||
if (res.Distance > smallestDist) continue;
|
|
||||||
|
|
||||||
smallestDist = res.Distance;
|
|
||||||
closestResult = res;
|
|
||||||
}
|
|
||||||
if (closestResult == null) continue;
|
|
||||||
var ent = closestResult.Value.HitEntity;
|
|
||||||
if (!EntityManager.TryGetComponent<ContainmentFieldGeneratorComponent?>(ent, out var fieldGeneratorComponent) ||
|
|
||||||
fieldGeneratorComponent.Owner == component.Owner ||
|
|
||||||
!HasFreeConnections(fieldGeneratorComponent) ||
|
|
||||||
IsConnectedWith(component, fieldGeneratorComponent) ||
|
|
||||||
!EntityManager.TryGetComponent<PhysicsComponent?>(ent, out var collidableComponent) ||
|
|
||||||
collidableComponent.BodyType != BodyType.Static)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var connection = new ContainmentFieldConnection(component, fieldGeneratorComponent);
|
if (component.PowerBuffer == 25)
|
||||||
propertyFieldTuple = new Tuple<Direction, ContainmentFieldConnection>(direction, connection);
|
|
||||||
if (fieldGeneratorComponent.Connection1 == null)
|
|
||||||
{
|
{
|
||||||
fieldGeneratorComponent.Connection1 = new Tuple<Direction, ContainmentFieldConnection>(direction.GetOpposite(), connection);
|
appearance.SetData(ContainmentFieldGeneratorVisuals.PowerLight, PowerLevelVisuals.HighPower);
|
||||||
}
|
|
||||||
else if (fieldGeneratorComponent.Connection2 == null)
|
|
||||||
{
|
|
||||||
fieldGeneratorComponent.Connection2 = new Tuple<Direction, ContainmentFieldConnection>(direction.GetOpposite(), connection);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Logger.Error("When trying to connect two Containmentfieldgenerators, the second one already had two connection but the check didn't catch it");
|
|
||||||
}
|
|
||||||
|
|
||||||
component.IsConnected = true;
|
|
||||||
UpdateConnectionLights(component);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool IsConnectedWith(ContainmentFieldGeneratorComponent comp, ContainmentFieldGeneratorComponent otherComp)
|
|
||||||
{
|
|
||||||
return otherComp == comp || comp.Connection1?.Item2.Generator1 == otherComp || comp.Connection1?.Item2.Generator2 == otherComp ||
|
|
||||||
comp.Connection2?.Item2.Generator1 == otherComp || comp.Connection2?.Item2.Generator2 == otherComp;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void TryPowerConnection(ref Tuple<Direction, ContainmentFieldConnection>? connectionProperty, ref int powerBuffer, int powerPerConnection, ContainmentFieldGeneratorComponent component)
|
|
||||||
{
|
|
||||||
if (connectionProperty != null)
|
|
||||||
{
|
|
||||||
connectionProperty.Item2.SharedEnergyPool += powerPerConnection;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (TryGenerateFieldConnection(ref connectionProperty, component))
|
|
||||||
{
|
|
||||||
connectionProperty.Item2.SharedEnergyPool += powerPerConnection;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
powerBuffer += powerPerConnection;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool CanRepel(SharedSingularityComponent toRepel, ContainmentFieldGeneratorComponent component) => component.Connection1?.Item2?.CanRepel(toRepel) == true ||
|
/// <summary>
|
||||||
component.Connection2?.Item2?.CanRepel(toRepel) == true;
|
/// Check if a field has any or no connections and if it's enabled to toggle the field level light
|
||||||
|
/// </summary>
|
||||||
public bool HasFreeConnections(ContainmentFieldGeneratorComponent component)
|
/// <param name="component"></param>
|
||||||
|
private void ChangeFieldVisualizer(ContainmentFieldGeneratorComponent component)
|
||||||
{
|
{
|
||||||
return component.Connection1 == null || component.Connection2 == null;
|
if (!TryComp<AppearanceComponent>(component.Owner, out var appearance))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (component.Connections.Count == 0 && !component.Enabled)
|
||||||
|
{
|
||||||
|
appearance.SetData(ContainmentFieldGeneratorVisuals.FieldLight, FieldLevelVisuals.NoLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (component.Connections.Count == 0 && component.Enabled)
|
||||||
|
{
|
||||||
|
appearance.SetData(ContainmentFieldGeneratorVisuals.FieldLight, FieldLevelVisuals.On);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (component.Connections.Count == 1)
|
||||||
|
{
|
||||||
|
appearance.SetData(ContainmentFieldGeneratorVisuals.FieldLight, FieldLevelVisuals.OneField);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (component.Connections.Count > 1)
|
||||||
|
{
|
||||||
|
appearance.SetData(ContainmentFieldGeneratorVisuals.FieldLight, FieldLevelVisuals.MultipleFields);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ChangeOnLightVisualizer(ContainmentFieldGeneratorComponent component)
|
||||||
|
{
|
||||||
|
if (!TryComp<AppearanceComponent>(component.Owner, out var appearance))
|
||||||
|
return;
|
||||||
|
|
||||||
|
appearance.SetData(ContainmentFieldGeneratorVisuals.OnLight, component.IsConnected);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
using Content.Server.Popups;
|
||||||
|
using Content.Server.Shuttles.Components;
|
||||||
|
using Content.Server.Singularity.Components;
|
||||||
|
using Content.Shared.Popups;
|
||||||
|
using Content.Shared.Tag;
|
||||||
|
using Content.Shared.Throwing;
|
||||||
|
using Robust.Shared.Physics;
|
||||||
|
using Robust.Shared.Physics.Dynamics;
|
||||||
|
using Robust.Shared.Player;
|
||||||
|
|
||||||
|
namespace Content.Server.Singularity.EntitySystems;
|
||||||
|
|
||||||
|
public sealed class ContainmentFieldSystem : EntitySystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly ThrowingSystem _throwing = default!;
|
||||||
|
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeLocalEvent<ContainmentFieldComponent, StartCollideEvent>(HandleFieldCollide);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleFieldCollide(EntityUid uid, ContainmentFieldComponent component, StartCollideEvent args)
|
||||||
|
{
|
||||||
|
var otherBody = args.OtherFixture.Body.Owner;
|
||||||
|
|
||||||
|
if (TryComp<SpaceGarbageComponent>(otherBody, out var garbage))
|
||||||
|
{
|
||||||
|
_popupSystem.PopupEntity(Loc.GetString("comp-field-vaporized", ("entity", otherBody)), component.Owner, Filter.Pvs(component.Owner), PopupType.LargeCaution);
|
||||||
|
QueueDel(garbage.Owner);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TryComp<PhysicsComponent>(otherBody, out var physics) && physics.Mass <= component.MaxMass && physics.Hard)
|
||||||
|
{
|
||||||
|
var fieldDir = Transform(component.Owner).WorldPosition;
|
||||||
|
var playerDir = Transform(otherBody).WorldPosition;
|
||||||
|
|
||||||
|
_throwing.TryThrow(otherBody, playerDir-fieldDir, strength: component.ThrowForce);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
using Content.Server.ParticleAccelerator.Components;
|
||||||
|
using Content.Server.Singularity.Components;
|
||||||
|
using Content.Shared.Singularity.Components;
|
||||||
|
using Robust.Shared.Physics.Dynamics;
|
||||||
|
|
||||||
|
namespace Content.Server.Singularity.EntitySystems;
|
||||||
|
|
||||||
|
public sealed class SingularityGeneratorSystem : EntitySystem
|
||||||
|
{
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeLocalEvent<ParticleProjectileComponent, StartCollideEvent>(HandleParticleCollide);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleParticleCollide(EntityUid uid, ParticleProjectileComponent component, StartCollideEvent args)
|
||||||
|
{
|
||||||
|
if (EntityManager.TryGetComponent<SingularityGeneratorComponent?>(args.OtherFixture.Body.Owner, out var singularityGeneratorComponent))
|
||||||
|
{
|
||||||
|
singularityGeneratorComponent.Power += component.State switch
|
||||||
|
{
|
||||||
|
ParticleAcceleratorPowerState.Standby => 0,
|
||||||
|
ParticleAcceleratorPowerState.Level0 => 1,
|
||||||
|
ParticleAcceleratorPowerState.Level1 => 2,
|
||||||
|
ParticleAcceleratorPowerState.Level2 => 4,
|
||||||
|
ParticleAcceleratorPowerState.Level3 => 8,
|
||||||
|
_ => 0
|
||||||
|
};
|
||||||
|
EntityManager.QueueDeleteEntity(uid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -132,7 +132,7 @@ namespace Content.Server.Singularity.EntitySystems
|
|||||||
!EntityManager.HasComponent<GhostComponent>(entity) &&
|
!EntityManager.HasComponent<GhostComponent>(entity) &&
|
||||||
(component.Level > 4 ||
|
(component.Level > 4 ||
|
||||||
!EntityManager.HasComponent<ContainmentFieldComponent>(entity) &&
|
!EntityManager.HasComponent<ContainmentFieldComponent>(entity) &&
|
||||||
!(EntityManager.TryGetComponent<ContainmentFieldGeneratorComponent>(entity, out var containFieldGen) && _fieldGeneratorSystem.CanRepel(component, containFieldGen)));
|
!EntityManager.HasComponent<ContainmentFieldGeneratorComponent>(entity));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleDestroy(ServerSingularityComponent component, EntityUid entity)
|
private void HandleDestroy(ServerSingularityComponent component, EntityUid entity)
|
||||||
|
|||||||
@@ -1,6 +1,2 @@
|
|||||||
namespace Content.Shared.Singularity.Components
|
namespace Content.Shared.Singularity.Components;
|
||||||
{
|
public abstract class SharedContainmentFieldComponent : Component { }
|
||||||
public abstract class SharedContainmentFieldComponent : Component
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,6 +1,30 @@
|
|||||||
namespace Content.Shared.Singularity.Components
|
using Robust.Shared.Serialization;
|
||||||
|
|
||||||
|
namespace Content.Shared.Singularity.Components;
|
||||||
|
public abstract class SharedContainmentFieldGeneratorComponent : Component { }
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public enum ContainmentFieldGeneratorVisuals : byte
|
||||||
{
|
{
|
||||||
public abstract class SharedContainmentFieldGeneratorComponent : Component
|
PowerLight,
|
||||||
{
|
FieldLight,
|
||||||
}
|
OnLight,
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public enum PowerLevelVisuals : byte
|
||||||
|
{
|
||||||
|
NoPower,
|
||||||
|
LowPower,
|
||||||
|
MediumPower,
|
||||||
|
HighPower,
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public enum FieldLevelVisuals : byte
|
||||||
|
{
|
||||||
|
NoLevel,
|
||||||
|
On,
|
||||||
|
OneField,
|
||||||
|
MultipleFields,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,13 @@
|
|||||||
comp-containment-turned-on = The containment field generator boots up.
|
comp-containment-turned-on = The containment field generator boots up.
|
||||||
comp-containment-turned-off = The containment field generator shuts down.
|
comp-containment-turned-off = The containment field generator shuts down.
|
||||||
|
|
||||||
|
comp-containment-on = It's switched [color=green]on[/color], ready to generate a connection.
|
||||||
|
comp-containment-off = It's switched [color=red]off[/color].
|
||||||
|
|
||||||
comp-containment-connected = The containment field generator shoots out a light as it establishes a connection!
|
comp-containment-connected = The containment field generator shoots out a light as it establishes a connection!
|
||||||
comp-containment-disconnected = The containment field generator light fades away, severing the connection.
|
comp-containment-disconnected = The containment field generator light fades away, severing the connection.
|
||||||
|
|
||||||
comp-containment-anchor-warning = You cannot unanchor the containment field generator while it's on or connected!
|
comp-containment-anchor-warning = You cannot unanchor the containment field generator while it's on or connected!
|
||||||
|
comp-containment-toggle-warning = You cannot turn the generator off while it's connected.
|
||||||
|
|
||||||
|
comp-field-vaporized = The {$entity} hits the field and vaporizes into nothing!
|
||||||
|
|||||||
@@ -41718,22 +41718,6 @@ entities:
|
|||||||
- pos: 14.5,-27.5
|
- pos: 14.5,-27.5
|
||||||
parent: 852
|
parent: 852
|
||||||
type: Transform
|
type: Transform
|
||||||
- uid: 4334
|
|
||||||
type: Emitter
|
|
||||||
components:
|
|
||||||
- pos: 71.5,9.5
|
|
||||||
parent: 852
|
|
||||||
type: Transform
|
|
||||||
- containers:
|
|
||||||
- machine_parts
|
|
||||||
- machine_board
|
|
||||||
type: Construction
|
|
||||||
- containers:
|
|
||||||
machine_board: !type:Container
|
|
||||||
ents: []
|
|
||||||
machine_parts: !type:Container
|
|
||||||
ents: []
|
|
||||||
type: ContainerContainer
|
|
||||||
- uid: 4335
|
- uid: 4335
|
||||||
type: CableMV
|
type: CableMV
|
||||||
components:
|
components:
|
||||||
@@ -41801,24 +41785,6 @@ entities:
|
|||||||
pos: 63.5,2.5
|
pos: 63.5,2.5
|
||||||
parent: 852
|
parent: 852
|
||||||
type: Transform
|
type: Transform
|
||||||
- uid: 4345
|
|
||||||
type: RadiationCollector
|
|
||||||
components:
|
|
||||||
- pos: 78.5,3.5
|
|
||||||
parent: 852
|
|
||||||
type: Transform
|
|
||||||
- uid: 4346
|
|
||||||
type: RadiationCollector
|
|
||||||
components:
|
|
||||||
- pos: 78.5,5.5
|
|
||||||
parent: 852
|
|
||||||
type: Transform
|
|
||||||
- uid: 4347
|
|
||||||
type: RadiationCollector
|
|
||||||
components:
|
|
||||||
- pos: 74.5,9.5
|
|
||||||
parent: 852
|
|
||||||
type: Transform
|
|
||||||
- uid: 4348
|
- uid: 4348
|
||||||
type: CableMV
|
type: CableMV
|
||||||
components:
|
components:
|
||||||
@@ -41897,22 +41863,6 @@ entities:
|
|||||||
- pos: 77.5,9.5
|
- pos: 77.5,9.5
|
||||||
parent: 852
|
parent: 852
|
||||||
type: Transform
|
type: Transform
|
||||||
- uid: 4361
|
|
||||||
type: Emitter
|
|
||||||
components:
|
|
||||||
- pos: 75.5,9.5
|
|
||||||
parent: 852
|
|
||||||
type: Transform
|
|
||||||
- containers:
|
|
||||||
- machine_parts
|
|
||||||
- machine_board
|
|
||||||
type: Construction
|
|
||||||
- containers:
|
|
||||||
machine_board: !type:Container
|
|
||||||
ents: []
|
|
||||||
machine_parts: !type:Container
|
|
||||||
ents: []
|
|
||||||
type: ContainerContainer
|
|
||||||
- uid: 4362
|
- uid: 4362
|
||||||
type: CableMV
|
type: CableMV
|
||||||
components:
|
components:
|
||||||
@@ -41960,23 +41910,6 @@ entities:
|
|||||||
- pos: 78.5,9.5
|
- pos: 78.5,9.5
|
||||||
parent: 852
|
parent: 852
|
||||||
type: Transform
|
type: Transform
|
||||||
- uid: 4368
|
|
||||||
type: Emitter
|
|
||||||
components:
|
|
||||||
- rot: -1.5707963267948966 rad
|
|
||||||
pos: 78.5,2.5
|
|
||||||
parent: 852
|
|
||||||
type: Transform
|
|
||||||
- containers:
|
|
||||||
- machine_parts
|
|
||||||
- machine_board
|
|
||||||
type: Construction
|
|
||||||
- containers:
|
|
||||||
machine_board: !type:Container
|
|
||||||
ents: []
|
|
||||||
machine_parts: !type:Container
|
|
||||||
ents: []
|
|
||||||
type: ContainerContainer
|
|
||||||
- uid: 4369
|
- uid: 4369
|
||||||
type: CableMV
|
type: CableMV
|
||||||
components:
|
components:
|
||||||
@@ -42386,23 +42319,6 @@ entities:
|
|||||||
- pos: 80.5,-6.5
|
- pos: 80.5,-6.5
|
||||||
parent: 852
|
parent: 852
|
||||||
type: Transform
|
type: Transform
|
||||||
- uid: 4433
|
|
||||||
type: Emitter
|
|
||||||
components:
|
|
||||||
- rot: 1.5707963267948966 rad
|
|
||||||
pos: 64.5,2.5
|
|
||||||
parent: 852
|
|
||||||
type: Transform
|
|
||||||
- containers:
|
|
||||||
- machine_parts
|
|
||||||
- machine_board
|
|
||||||
type: Construction
|
|
||||||
- containers:
|
|
||||||
machine_board: !type:Container
|
|
||||||
ents: []
|
|
||||||
machine_parts: !type:Container
|
|
||||||
ents: []
|
|
||||||
type: ContainerContainer
|
|
||||||
- uid: 4434
|
- uid: 4434
|
||||||
type: Grille
|
type: Grille
|
||||||
components:
|
components:
|
||||||
@@ -43245,18 +43161,6 @@ entities:
|
|||||||
machine_parts: !type:Container
|
machine_parts: !type:Container
|
||||||
ents: []
|
ents: []
|
||||||
type: ContainerContainer
|
type: ContainerContainer
|
||||||
- uid: 4549
|
|
||||||
type: RadiationCollector
|
|
||||||
components:
|
|
||||||
- pos: 68.5,9.5
|
|
||||||
parent: 852
|
|
||||||
type: Transform
|
|
||||||
- uid: 4550
|
|
||||||
type: RadiationCollector
|
|
||||||
components:
|
|
||||||
- pos: 69.5,9.5
|
|
||||||
parent: 852
|
|
||||||
type: Transform
|
|
||||||
- uid: 4551
|
- uid: 4551
|
||||||
type: Grille
|
type: Grille
|
||||||
components:
|
components:
|
||||||
@@ -43275,29 +43179,6 @@ entities:
|
|||||||
- pos: 78.5,-4.5
|
- pos: 78.5,-4.5
|
||||||
parent: 852
|
parent: 852
|
||||||
type: Transform
|
type: Transform
|
||||||
- uid: 4554
|
|
||||||
type: Emitter
|
|
||||||
components:
|
|
||||||
- rot: 3.141592653589793 rad
|
|
||||||
pos: 67.5,-4.5
|
|
||||||
parent: 852
|
|
||||||
type: Transform
|
|
||||||
- containers:
|
|
||||||
- machine_parts
|
|
||||||
- machine_board
|
|
||||||
type: Construction
|
|
||||||
- containers:
|
|
||||||
machine_board: !type:Container
|
|
||||||
ents: []
|
|
||||||
machine_parts: !type:Container
|
|
||||||
ents: []
|
|
||||||
type: ContainerContainer
|
|
||||||
- uid: 4555
|
|
||||||
type: RadiationCollector
|
|
||||||
components:
|
|
||||||
- pos: 70.5,9.5
|
|
||||||
parent: 852
|
|
||||||
type: Transform
|
|
||||||
- uid: 4556
|
- uid: 4556
|
||||||
type: Emitter
|
type: Emitter
|
||||||
components:
|
components:
|
||||||
@@ -43315,18 +43196,6 @@ entities:
|
|||||||
machine_parts: !type:Container
|
machine_parts: !type:Container
|
||||||
ents: []
|
ents: []
|
||||||
type: ContainerContainer
|
type: ContainerContainer
|
||||||
- uid: 4557
|
|
||||||
type: RadiationCollector
|
|
||||||
components:
|
|
||||||
- pos: 72.5,9.5
|
|
||||||
parent: 852
|
|
||||||
type: Transform
|
|
||||||
- uid: 4558
|
|
||||||
type: RadiationCollector
|
|
||||||
components:
|
|
||||||
- pos: 73.5,9.5
|
|
||||||
parent: 852
|
|
||||||
type: Transform
|
|
||||||
- uid: 4559
|
- uid: 4559
|
||||||
type: ContainmentFieldGenerator
|
type: ContainmentFieldGenerator
|
||||||
components:
|
components:
|
||||||
@@ -43409,46 +43278,6 @@ entities:
|
|||||||
pos: 56.5,2.5
|
pos: 56.5,2.5
|
||||||
parent: 852
|
parent: 852
|
||||||
type: Transform
|
type: Transform
|
||||||
- uid: 4572
|
|
||||||
type: RadiationCollector
|
|
||||||
components:
|
|
||||||
- pos: 74.5,-4.5
|
|
||||||
parent: 852
|
|
||||||
type: Transform
|
|
||||||
- uid: 4573
|
|
||||||
type: RadiationCollector
|
|
||||||
components:
|
|
||||||
- pos: 72.5,-4.5
|
|
||||||
parent: 852
|
|
||||||
type: Transform
|
|
||||||
- uid: 4574
|
|
||||||
type: RadiationCollector
|
|
||||||
components:
|
|
||||||
- pos: 69.5,-4.5
|
|
||||||
parent: 852
|
|
||||||
type: Transform
|
|
||||||
- uid: 4575
|
|
||||||
type: Emitter
|
|
||||||
components:
|
|
||||||
- pos: 67.5,9.5
|
|
||||||
parent: 852
|
|
||||||
type: Transform
|
|
||||||
- containers:
|
|
||||||
- machine_parts
|
|
||||||
- machine_board
|
|
||||||
type: Construction
|
|
||||||
- containers:
|
|
||||||
machine_board: !type:Container
|
|
||||||
ents: []
|
|
||||||
machine_parts: !type:Container
|
|
||||||
ents: []
|
|
||||||
type: ContainerContainer
|
|
||||||
- uid: 4576
|
|
||||||
type: ContainmentFieldGenerator
|
|
||||||
components:
|
|
||||||
- pos: 67.5,2.5
|
|
||||||
parent: 852
|
|
||||||
type: Transform
|
|
||||||
- uid: 4577
|
- uid: 4577
|
||||||
type: ReinforcedWindow
|
type: ReinforcedWindow
|
||||||
components:
|
components:
|
||||||
@@ -45870,12 +45699,6 @@ entities:
|
|||||||
- containers:
|
- containers:
|
||||||
ItemCabinet: !type:ContainerSlot {}
|
ItemCabinet: !type:ContainerSlot {}
|
||||||
type: ContainerContainer
|
type: ContainerContainer
|
||||||
- uid: 4910
|
|
||||||
type: RadiationCollector
|
|
||||||
components:
|
|
||||||
- pos: 78.5,4.5
|
|
||||||
parent: 852
|
|
||||||
type: Transform
|
|
||||||
- uid: 4911
|
- uid: 4911
|
||||||
type: CableMV
|
type: CableMV
|
||||||
components:
|
components:
|
||||||
@@ -57150,12 +56973,6 @@ entities:
|
|||||||
- pos: 56.5,2.5
|
- pos: 56.5,2.5
|
||||||
parent: 852
|
parent: 852
|
||||||
type: Transform
|
type: Transform
|
||||||
- uid: 6298
|
|
||||||
type: ContainmentFieldGenerator
|
|
||||||
components:
|
|
||||||
- pos: 71.5,-1.5
|
|
||||||
parent: 852
|
|
||||||
type: Transform
|
|
||||||
- uid: 6299
|
- uid: 6299
|
||||||
type: ContainmentFieldGenerator
|
type: ContainmentFieldGenerator
|
||||||
components:
|
components:
|
||||||
@@ -57181,12 +56998,6 @@ entities:
|
|||||||
- pos: 44.5,1.5
|
- pos: 44.5,1.5
|
||||||
parent: 852
|
parent: 852
|
||||||
type: Transform
|
type: Transform
|
||||||
- uid: 6303
|
|
||||||
type: RadiationCollector
|
|
||||||
components:
|
|
||||||
- pos: 73.5,-4.5
|
|
||||||
parent: 852
|
|
||||||
type: Transform
|
|
||||||
- uid: 6304
|
- uid: 6304
|
||||||
type: CableHV
|
type: CableHV
|
||||||
components:
|
components:
|
||||||
@@ -57199,24 +57010,6 @@ entities:
|
|||||||
- pos: 47.5,1.5
|
- pos: 47.5,1.5
|
||||||
parent: 852
|
parent: 852
|
||||||
type: Transform
|
type: Transform
|
||||||
- uid: 6306
|
|
||||||
type: ContainmentFieldGenerator
|
|
||||||
components:
|
|
||||||
- pos: 71.5,6.5
|
|
||||||
parent: 852
|
|
||||||
type: Transform
|
|
||||||
- uid: 6307
|
|
||||||
type: RadiationCollector
|
|
||||||
components:
|
|
||||||
- pos: 68.5,-4.5
|
|
||||||
parent: 852
|
|
||||||
type: Transform
|
|
||||||
- uid: 6308
|
|
||||||
type: RadiationCollector
|
|
||||||
components:
|
|
||||||
- pos: 70.5,-4.5
|
|
||||||
parent: 852
|
|
||||||
type: Transform
|
|
||||||
- uid: 6309
|
- uid: 6309
|
||||||
type: AirlockEngineeringGlassLocked
|
type: AirlockEngineeringGlassLocked
|
||||||
components:
|
components:
|
||||||
@@ -57255,29 +57048,6 @@ entities:
|
|||||||
- pos: 50.5,1.5
|
- pos: 50.5,1.5
|
||||||
parent: 852
|
parent: 852
|
||||||
type: Transform
|
type: Transform
|
||||||
- uid: 6315
|
|
||||||
type: ContainmentFieldGenerator
|
|
||||||
components:
|
|
||||||
- pos: 75.5,2.5
|
|
||||||
parent: 852
|
|
||||||
type: Transform
|
|
||||||
- uid: 6316
|
|
||||||
type: Emitter
|
|
||||||
components:
|
|
||||||
- rot: 3.141592653589793 rad
|
|
||||||
pos: 75.5,-4.5
|
|
||||||
parent: 852
|
|
||||||
type: Transform
|
|
||||||
- containers:
|
|
||||||
- machine_parts
|
|
||||||
- machine_board
|
|
||||||
type: Construction
|
|
||||||
- containers:
|
|
||||||
machine_board: !type:Container
|
|
||||||
ents: []
|
|
||||||
machine_parts: !type:Container
|
|
||||||
ents: []
|
|
||||||
type: ContainerContainer
|
|
||||||
- uid: 6317
|
- uid: 6317
|
||||||
type: CableMV
|
type: CableMV
|
||||||
components:
|
components:
|
||||||
@@ -57308,35 +57078,6 @@ entities:
|
|||||||
- pos: 75.5,6.5
|
- pos: 75.5,6.5
|
||||||
parent: 852
|
parent: 852
|
||||||
type: Transform
|
type: Transform
|
||||||
- uid: 6322
|
|
||||||
type: RadiationCollector
|
|
||||||
components:
|
|
||||||
- pos: 78.5,0.5
|
|
||||||
parent: 852
|
|
||||||
type: Transform
|
|
||||||
- uid: 6323
|
|
||||||
type: RadiationCollector
|
|
||||||
components:
|
|
||||||
- pos: 78.5,1.5
|
|
||||||
parent: 852
|
|
||||||
type: Transform
|
|
||||||
- uid: 6324
|
|
||||||
type: Emitter
|
|
||||||
components:
|
|
||||||
- rot: 3.141592653589793 rad
|
|
||||||
pos: 71.5,-4.5
|
|
||||||
parent: 852
|
|
||||||
type: Transform
|
|
||||||
- containers:
|
|
||||||
- machine_parts
|
|
||||||
- machine_board
|
|
||||||
type: Construction
|
|
||||||
- containers:
|
|
||||||
machine_board: !type:Container
|
|
||||||
ents: []
|
|
||||||
machine_parts: !type:Container
|
|
||||||
ents: []
|
|
||||||
type: ContainerContainer
|
|
||||||
- uid: 6325
|
- uid: 6325
|
||||||
type: CableMV
|
type: CableMV
|
||||||
components:
|
components:
|
||||||
@@ -63171,12 +62912,6 @@ entities:
|
|||||||
- pos: 43.5,6.5
|
- pos: 43.5,6.5
|
||||||
parent: 852
|
parent: 852
|
||||||
type: Transform
|
type: Transform
|
||||||
- uid: 7175
|
|
||||||
type: RadiationCollector
|
|
||||||
components:
|
|
||||||
- pos: 78.5,-0.5
|
|
||||||
parent: 852
|
|
||||||
type: Transform
|
|
||||||
- uid: 7176
|
- uid: 7176
|
||||||
type: GrilleBroken
|
type: GrilleBroken
|
||||||
components:
|
components:
|
||||||
|
|||||||
@@ -21,6 +21,20 @@
|
|||||||
state: icon
|
state: icon
|
||||||
netsync: false
|
netsync: false
|
||||||
noRot: true
|
noRot: true
|
||||||
|
layers:
|
||||||
|
- state: icon
|
||||||
|
- state: p1
|
||||||
|
map: ["powerLight"]
|
||||||
|
visible: false
|
||||||
|
shader: unshaded
|
||||||
|
- state: a1
|
||||||
|
map: ["fieldLight"]
|
||||||
|
visible: false
|
||||||
|
shader: unshaded
|
||||||
|
- state: on
|
||||||
|
map: ["connectedLight"]
|
||||||
|
visible: false
|
||||||
|
shader: unshaded
|
||||||
- type: Icon
|
- type: Icon
|
||||||
sprite: Structures/Power/Generation/Singularity/containment.rsi
|
sprite: Structures/Power/Generation/Singularity/containment.rsi
|
||||||
state: icon
|
state: icon
|
||||||
@@ -31,6 +45,25 @@
|
|||||||
radius: 32
|
radius: 32
|
||||||
energy: 2.0
|
energy: 2.0
|
||||||
softness: 32.0
|
softness: 32.0
|
||||||
|
- type: Appearance
|
||||||
|
- type: GenericVisualizer
|
||||||
|
visuals:
|
||||||
|
enum.ContainmentFieldGeneratorVisuals.PowerLight:
|
||||||
|
powerLight:
|
||||||
|
NoPower: {visible: false}
|
||||||
|
LowPower: {visible: true, state: p1}
|
||||||
|
MediumPower: {visible: true, state: p3}
|
||||||
|
HighPower: {visible: true, state: p6}
|
||||||
|
enum.ContainmentFieldGeneratorVisuals.FieldLight:
|
||||||
|
fieldLight:
|
||||||
|
NoLevel: {visible: false}
|
||||||
|
On: {visible: true, state: a1}
|
||||||
|
OneField: {visible: true, state: a2}
|
||||||
|
MultipleFields: {visible: true, state: a3}
|
||||||
|
enum.ContainmentFieldGeneratorVisuals.OnLight:
|
||||||
|
connectedLight:
|
||||||
|
True: { visible: true }
|
||||||
|
False: { visible: false }
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
id: ContainmentField
|
id: ContainmentField
|
||||||
@@ -52,12 +85,11 @@
|
|||||||
- FullTileMask
|
- FullTileMask
|
||||||
layer:
|
layer:
|
||||||
- GlassLayer
|
- GlassLayer
|
||||||
- type: Transform
|
|
||||||
anchored: true
|
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
sprite: Structures/Power/Generation/Singularity/containment_field.rsi
|
sprite: Structures/Power/Generation/Singularity/containment_field.rsi
|
||||||
state: field
|
state: field
|
||||||
netsync: false
|
netsync: false
|
||||||
|
noRot: true
|
||||||
- type: Icon
|
- type: Icon
|
||||||
sprite: Structures/Power/Generation/Singularity/containment_field.rsi
|
sprite: Structures/Power/Generation/Singularity/containment_field.rsi
|
||||||
state: field
|
state: field
|
||||||
|
|||||||
Reference in New Issue
Block a user