Bluespace locker event prep (#13397)

This commit is contained in:
Chief-Engineer
2023-01-13 16:20:28 -06:00
committed by GitHub
parent ea8ee5d899
commit 60ba6fa51e
7 changed files with 454 additions and 84 deletions

View File

@@ -52,17 +52,17 @@ public sealed class LinkBluespaceLocker : IConsoleCommand
} }
entityManager.EnsureComponent<BluespaceLockerComponent>(originUid, out var originBluespaceComponent); entityManager.EnsureComponent<BluespaceLockerComponent>(originUid, out var originBluespaceComponent);
originBluespaceComponent.BluespaceLinks.Add(targetComponent); originBluespaceComponent.BluespaceLinks.Add(targetUid);
entityManager.EnsureComponent<BluespaceLockerComponent>(targetUid, out var targetBluespaceComponent); entityManager.EnsureComponent<BluespaceLockerComponent>(targetUid, out var targetBluespaceComponent);
if (bidirectional) if (bidirectional)
{ {
targetBluespaceComponent.BluespaceLinks.Add(originComponent); targetBluespaceComponent.BluespaceLinks.Add(originUid);
} }
else if (targetBluespaceComponent.BluespaceLinks.Count == 0) else if (targetBluespaceComponent.BluespaceLinks.Count == 0)
{ {
targetBluespaceComponent.AllowSentient = false; targetBluespaceComponent.BehaviorProperties.TransportSentient = false;
targetBluespaceComponent.TransportEntities = false; targetBluespaceComponent.BehaviorProperties.TransportEntities = false;
targetBluespaceComponent.TransportGas = false; targetBluespaceComponent.BehaviorProperties.TransportGas = false;
} }
} }
} }

View File

@@ -0,0 +1,51 @@
using System.Linq;
using Content.Server.Resist;
using Content.Server.Station.Components;
using Content.Server.Storage.Components;
using Content.Shared.Access.Components;
using Content.Shared.Coordinates;
using Robust.Shared.Random;
namespace Content.Server.StationEvents.Events;
public sealed class BluespaceLockerLink : StationEventSystem
{
[Dependency] private readonly IRobustRandom _robustRandom = default!;
public override string Prototype => "BluespaceLockerLink";
public override void Started()
{
base.Started();
var targets = EntityQuery<EntityStorageComponent, ResistLockerComponent>().ToList();
_robustRandom.Shuffle(targets);
foreach (var target in targets)
{
var potentialLink = target.Item1.Owner;
if (HasComp<AccessReaderComponent>(potentialLink) ||
HasComp<BluespaceLockerComponent>(potentialLink) ||
!HasComp<StationMemberComponent>(potentialLink.ToCoordinates().GetGridUid(EntityManager)))
continue;
using var compInitializeHandle = EntityManager.AddComponentUninitialized<BluespaceLockerComponent>(potentialLink);
var comp = compInitializeHandle.Comp;
comp.PickLinksFromSameMap = true;
comp.MinBluespaceLinks = 1;
comp.BluespaceEffectOnInit = true;
comp.BehaviorProperties.BluespaceEffectOnTeleportSource = true;
comp.AutoLinksBidirectional = true;
comp.AutoLinksUseProperties = true;
comp.AutoLinkProperties.BluespaceEffectOnTeleportSource = true;
compInitializeHandle.Dispose();
Sawmill.Info($"Converted {ToPrettyString(potentialLink)} to bluespace locker");
return;
}
}
}

View File

@@ -1,32 +1,16 @@
namespace Content.Server.Storage.Components; using System.Threading;
namespace Content.Server.Storage.Components;
[RegisterComponent] [RegisterComponent]
public sealed class BluespaceLockerComponent : Component public sealed class BluespaceLockerComponent : Component
{ {
/// <summary>
/// Determines if gas will be transported.
/// </summary>
[DataField("transportGas"), ViewVariables(VVAccess.ReadWrite)]
public bool TransportGas = true;
/// <summary>
/// Determines if entities will be transported.
/// </summary>
[DataField("transportEntities"), ViewVariables(VVAccess.ReadWrite)]
public bool TransportEntities = true;
/// <summary>
/// Determines if entities with a Mind component will be transported.
/// </summary>
[DataField("allowSentient"), ViewVariables(VVAccess.ReadWrite)]
public bool AllowSentient = true;
/// <summary> /// <summary>
/// If length > 0, when something is added to the storage, it will instead be teleported to a random storage /// If length > 0, when something is added to the storage, it will instead be teleported to a random storage
/// from the list and the other storage will be opened. /// from the list and the other storage will be opened.
/// </summary> /// </summary>
[DataField("bluespaceLinks"), ViewVariables(VVAccess.ReadOnly)] [DataField("bluespaceLinks"), ViewVariables(VVAccess.ReadOnly)]
public HashSet<EntityStorageComponent> BluespaceLinks = new(); public HashSet<EntityUid> BluespaceLinks = new();
/// <summary> /// <summary>
/// Each time the system attempts to get a link, it will link additional lockers to ensure the minimum amount /// Each time the system attempts to get a link, it will link additional lockers to ensure the minimum amount
@@ -54,8 +38,126 @@ public sealed class BluespaceLockerComponent : Component
public bool PickLinksFromStationGrids = true; public bool PickLinksFromStationGrids = true;
/// <summary> /// <summary>
/// Determines if links automatically added are bidirectional /// Determines if links automatically added are restricted to having the same access
/// </summary>
[DataField("pickLinksFromSameAccess"), ViewVariables(VVAccess.ReadWrite)]
public bool PickLinksFromSameAccess = true;
/// <summary>
/// Determines if links automatically added are restricted to existing bluespace lockers
/// </summary>
[DataField("pickLinksFromBluespaceLockers"), ViewVariables(VVAccess.ReadWrite)]
public bool PickLinksFromBluespaceLockers;
/// <summary>
/// Determines if links automatically added are restricted to non-bluespace lockers
/// </summary>
[DataField("pickLinksFromNonBluespaceLockers"), ViewVariables(VVAccess.ReadWrite)]
public bool PickLinksFromNonBluespaceLockers = true;
public CancellationTokenSource? CancelToken;
/// <summary>
/// Determines if bluespace effect is show on component init
/// </summary>
[DataField("bluespaceEffectOnInit")]
public bool BluespaceEffectOnInit;
/// <summary>
/// Determines if links automatically added get the source locker set as a target
/// </summary> /// </summary>
[DataField("autoLinksBidirectional"), ViewVariables(VVAccess.ReadWrite)] [DataField("autoLinksBidirectional"), ViewVariables(VVAccess.ReadWrite)]
public bool AutoLinksBidirectional; public bool AutoLinksBidirectional;
/// <summary>
/// Determines if links automatically use <see cref="AutoLinkProperties"/>
/// </summary>
[DataField("autoLinksUseProperties"), ViewVariables(VVAccess.ReadWrite)]
public bool AutoLinksUseProperties;
public int UsesSinceLinkClear;
/// <summary>
/// Determines properties of automatically created links
/// </summary>
[DataField("autoLinkProperties"), ViewVariables(VVAccess.ReadOnly)]
public BluespaceLockerBehaviorProperties AutoLinkProperties = new();
/// <summary>
/// Determines properties of this locker
/// </summary>
[DataField("behaviorProperties"), ViewVariables(VVAccess.ReadOnly)]
public BluespaceLockerBehaviorProperties BehaviorProperties = new();
}
[DataDefinition]
public record BluespaceLockerBehaviorProperties
{
/// <summary>
/// Determines if gas will be transported.
/// </summary>
[DataField("transportGas"), ViewVariables(VVAccess.ReadWrite)]
public bool TransportGas { get; set; } = true;
/// <summary>
/// Determines if entities will be transported.
/// </summary>
[DataField("transportEntities"), ViewVariables(VVAccess.ReadWrite)]
public bool TransportEntities { get; set; } = true;
/// <summary>
/// Determines if entities with a Mind component will be transported.
/// </summary>
[DataField("transportSentient"), ViewVariables(VVAccess.ReadWrite)]
public bool TransportSentient { get; set; } = true;
/// <summary>
/// Delay to wait after closing before transporting
/// </summary>
[DataField("delay"), ViewVariables(VVAccess.ReadWrite)]
public float Delay { get; set; }
/// <summary>
/// Defines prototype to spawn for bluespace effect
/// </summary>
[DataField("bluespaceEffectPrototype"), ViewVariables(VVAccess.ReadWrite)]
public string BluespaceEffectPrototype { get; set; } = "EffectFlashBluespace";
/// <summary>
/// Determines if bluespace effect is show on teleport at the source
/// </summary>
[DataField("bluespaceEffectOnTeleportSource"), ViewVariables(VVAccess.ReadWrite)]
public bool BluespaceEffectOnTeleportSource { get; set; }
/// <summary>
/// Determines if bluespace effect is show on teleport at the target
/// </summary>
[DataField("bluespaceEffectOnTeleportTarget"), ViewVariables(VVAccess.ReadWrite)]
public bool BluespaceEffectOnTeleportTarget { get; set; }
/// <summary>
/// Uses left before the locker is destroyed. -1 indicates infinite
/// </summary>
[DataField("destroyAfterUses"), ViewVariables(VVAccess.ReadWrite)]
public int DestroyAfterUses { get; set; } = -1;
/// <summary>
/// How to destroy the locker after it runs out of uses
/// </summary>
[DataField("destroyType"), ViewVariables(VVAccess.ReadWrite)]
public BluespaceLockerDestroyType DestroyType { get; set; } = BluespaceLockerDestroyType.Delete;
/// <summary>
/// Uses left before the lockers links are cleared. -1 indicates infinite
/// </summary>
[DataField("clearLinksEvery"), ViewVariables(VVAccess.ReadWrite)]
public int ClearLinksEvery { get; set; } = -1;
}
[Flags]
public enum BluespaceLockerDestroyType
{
Delete,
DeleteComponent,
Explode,
} }

View File

@@ -1,10 +1,14 @@
using System.Linq; using System.Linq;
using System.Threading;
using Content.Server.DoAfter;
using Content.Server.Explosion.EntitySystems;
using Content.Server.Lock; using Content.Server.Lock;
using Content.Server.Mind.Components; using Content.Server.Mind.Components;
using Content.Server.Resist; using Content.Server.Resist;
using Content.Server.Station.Components; using Content.Server.Station.Components;
using Content.Server.Storage.Components; using Content.Server.Storage.Components;
using Content.Server.Tools.Systems; using Content.Server.Tools.Systems;
using Content.Shared.Access.Components;
using Content.Shared.Coordinates; using Content.Shared.Coordinates;
using Robust.Shared.Random; using Robust.Shared.Random;
@@ -17,6 +21,8 @@ public sealed class BluespaceLockerSystem : EntitySystem
[Dependency] private readonly EntityStorageSystem _entityStorage = default!; [Dependency] private readonly EntityStorageSystem _entityStorage = default!;
[Dependency] private readonly WeldableSystem _weldableSystem = default!; [Dependency] private readonly WeldableSystem _weldableSystem = default!;
[Dependency] private readonly LockSystem _lockSystem = default!; [Dependency] private readonly LockSystem _lockSystem = default!;
[Dependency] private readonly DoAfterSystem _doAfterSystem = default!;
[Dependency] private readonly ExplosionSystem _explosionSystem = default!;
public override void Initialize() public override void Initialize()
{ {
@@ -25,11 +31,20 @@ public sealed class BluespaceLockerSystem : EntitySystem
SubscribeLocalEvent<BluespaceLockerComponent, ComponentStartup>(OnStartup); SubscribeLocalEvent<BluespaceLockerComponent, ComponentStartup>(OnStartup);
SubscribeLocalEvent<BluespaceLockerComponent, StorageBeforeOpenEvent>(PreOpen); SubscribeLocalEvent<BluespaceLockerComponent, StorageBeforeOpenEvent>(PreOpen);
SubscribeLocalEvent<BluespaceLockerComponent, StorageAfterCloseEvent>(PostClose); SubscribeLocalEvent<BluespaceLockerComponent, StorageAfterCloseEvent>(PostClose);
SubscribeLocalEvent<BluespaceLockerComponent, BluespaceLockerTeleportDelayComplete>(OnBluespaceLockerTeleportDelayComplete);
} }
private void OnStartup(EntityUid uid, BluespaceLockerComponent component, ComponentStartup args) private void OnStartup(EntityUid uid, BluespaceLockerComponent component, ComponentStartup args)
{ {
GetTargetStorage(component); GetTarget(uid, component);
if (component.BluespaceEffectOnInit)
BluespaceEffect(uid, component);
}
private void BluespaceEffect(EntityUid uid, BluespaceLockerComponent component)
{
Spawn(component.BehaviorProperties.BluespaceEffectPrototype, uid.ToCoordinates());
} }
private void PreOpen(EntityUid uid, BluespaceLockerComponent component, StorageBeforeOpenEvent args) private void PreOpen(EntityUid uid, BluespaceLockerComponent component, StorageBeforeOpenEvent args)
@@ -39,63 +54,110 @@ public sealed class BluespaceLockerSystem : EntitySystem
if (!Resolve(uid, ref entityStorageComponent)) if (!Resolve(uid, ref entityStorageComponent))
return; return;
component.CancelToken?.Cancel();
// Select target // Select target
var targetContainerStorageComponent = GetTargetStorage(component); var target = GetTarget(uid, component);
if (targetContainerStorageComponent == null) if (target == null)
return; return;
BluespaceLockerComponent? targetContainerBluespaceComponent = null;
// Close target if it is open // Close target if it is open
if (targetContainerStorageComponent.Open) if (target.Value.storageComponent.Open)
_entityStorage.CloseStorage(targetContainerStorageComponent.Owner, targetContainerStorageComponent); _entityStorage.CloseStorage(target.Value.uid, target.Value.storageComponent);
// Apply bluespace effects if target is not a bluespace locker, otherwise let it handle it // Apply bluespace effects if target is not a bluespace locker, otherwise let it handle it
if (!Resolve(targetContainerStorageComponent.Owner, ref targetContainerBluespaceComponent, false)) if (target.Value.bluespaceLockerComponent == null)
{ {
// Move contained items // Move contained items
if (component.TransportEntities) if (component.BehaviorProperties.TransportEntities || component.BehaviorProperties.TransportSentient)
foreach (var entity in targetContainerStorageComponent.Contents.ContainedEntities.ToArray()) foreach (var entity in target.Value.storageComponent.Contents.ContainedEntities.ToArray())
{ {
if (!component.AllowSentient && EntityManager.HasComponent<MindComponent>(entity)) if (EntityManager.HasComponent<MindComponent>(entity))
continue; {
entityStorageComponent.Contents.Insert(entity, EntityManager); if (component.BehaviorProperties.TransportSentient)
entityStorageComponent.Contents.Insert(entity, EntityManager);
}
else if (component.BehaviorProperties.TransportEntities)
entityStorageComponent.Contents.Insert(entity, EntityManager);
} }
// Move contained air // Move contained air
if (component.TransportGas) if (component.BehaviorProperties.TransportGas)
{ {
entityStorageComponent.Air.CopyFromMutable(targetContainerStorageComponent.Air); entityStorageComponent.Air.CopyFromMutable(target.Value.storageComponent.Air);
targetContainerStorageComponent.Air.Clear(); target.Value.storageComponent.Air.Clear();
} }
// Bluespace effects
if (component.BehaviorProperties.BluespaceEffectOnTeleportSource)
BluespaceEffect(target.Value.uid, component);
if (component.BehaviorProperties.BluespaceEffectOnTeleportTarget)
BluespaceEffect(uid, component);
} }
DestroyAfterLimit(uid, component);
} }
private bool ValidLink(BluespaceLockerComponent component, EntityStorageComponent link) private bool ValidLink(EntityUid locker, EntityUid link, BluespaceLockerComponent lockerComponent)
{ {
return link.Owner.Valid && link.LifeStage != ComponentLifeStage.Deleted; return link.Valid && TryComp<EntityStorageComponent>(link, out var linkStorage) && linkStorage.LifeStage != ComponentLifeStage.Deleted && link != locker;
} }
private bool ValidAutolink(BluespaceLockerComponent component, EntityStorageComponent link) /// <returns>True if any HashSet in <paramref name="a"/> would grant access to <paramref name="b"/></returns>
private bool AccessMatch(IReadOnlyCollection<HashSet<string>>? a, IReadOnlyCollection<HashSet<string>>? b)
{ {
if (!ValidLink(component, link)) if ((a == null || a.Count == 0) && (b == null || b.Count == 0))
return true;
if (a != null && a.Any(aSet => aSet.Count == 0))
return true;
if (b != null && b.Any(bSet => bSet.Count == 0))
return true;
if (a != null && b != null)
return a.Any(aSet => b.Any(aSet.SetEquals));
return false;
}
private bool ValidAutolink(EntityUid locker, EntityUid link, BluespaceLockerComponent lockerComponent)
{
if (!ValidLink(locker, link, lockerComponent))
return false; return false;
if (component.PickLinksFromSameMap && if (lockerComponent.PickLinksFromSameMap &&
link.Owner.ToCoordinates().GetMapId(_entityManager) == component.Owner.ToCoordinates().GetMapId(_entityManager)) link.ToCoordinates().GetMapId(_entityManager) != locker.ToCoordinates().GetMapId(_entityManager))
return false; return false;
if (component.PickLinksFromStationGrids && if (lockerComponent.PickLinksFromStationGrids &&
!_entityManager.HasComponent<StationMemberComponent>(link.Owner.ToCoordinates().GetGridUid(_entityManager))) !HasComp<StationMemberComponent>(link.ToCoordinates().GetGridUid(_entityManager)))
return false; return false;
if (component.PickLinksFromResistLockers && if (lockerComponent.PickLinksFromResistLockers &&
!_entityManager.HasComponent<ResistLockerComponent>(link.Owner)) !HasComp<ResistLockerComponent>(link))
return false; return false;
if (lockerComponent.PickLinksFromSameAccess)
{
TryComp<AccessReaderComponent>(locker, out var sourceAccess);
TryComp<AccessReaderComponent>(link, out var targetAccess);
if (!AccessMatch(sourceAccess?.AccessLists, targetAccess?.AccessLists))
return false;
}
if (HasComp<BluespaceLockerComponent>(link))
{
if (lockerComponent.PickLinksFromNonBluespaceLockers)
return false;
}
else
{
if (lockerComponent.PickLinksFromBluespaceLockers)
return false;
}
return true; return true;
} }
private EntityStorageComponent? GetTargetStorage(BluespaceLockerComponent component) private (EntityUid uid, EntityStorageComponent storageComponent, BluespaceLockerComponent? bluespaceLockerComponent)? GetTarget(EntityUid lockerUid, BluespaceLockerComponent component)
{ {
while (true) while (true)
{ {
@@ -103,20 +165,27 @@ public sealed class BluespaceLockerSystem : EntitySystem
if (component.BluespaceLinks.Count < component.MinBluespaceLinks) if (component.BluespaceLinks.Count < component.MinBluespaceLinks)
{ {
// Get an shuffle the list of all EntityStorages // Get an shuffle the list of all EntityStorages
var storages = _entityManager.EntityQuery<EntityStorageComponent>().ToArray(); var storages = EntityQuery<EntityStorageComponent>().ToArray();
_robustRandom.Shuffle(storages); _robustRandom.Shuffle(storages);
// Add valid candidates till MinBluespaceLinks is met // Add valid candidates till MinBluespaceLinks is met
foreach (var storage in storages) foreach (var storage in storages)
{ {
if (!ValidAutolink(component, storage)) var potentialLink = storage.Owner;
if (!ValidAutolink(lockerUid, potentialLink, component))
continue; continue;
component.BluespaceLinks.Add(storage); component.BluespaceLinks.Add(potentialLink);
if (component.AutoLinksBidirectional) if (component.AutoLinksBidirectional || component.AutoLinksUseProperties)
{ {
_entityManager.EnsureComponent<BluespaceLockerComponent>(storage.Owner, out var targetBluespaceComponent); var targetBluespaceComponent = EnsureComp<BluespaceLockerComponent>(potentialLink);
targetBluespaceComponent.BluespaceLinks.Add(_entityManager.GetComponent<EntityStorageComponent>(component.Owner));
if (component.AutoLinksBidirectional)
targetBluespaceComponent.BluespaceLinks.Add(lockerUid);
if (component.AutoLinksUseProperties)
targetBluespaceComponent.BehaviorProperties = component.AutoLinkProperties with {};
} }
if (component.BluespaceLinks.Count >= component.MinBluespaceLinks) if (component.BluespaceLinks.Count >= component.MinBluespaceLinks)
break; break;
@@ -130,61 +199,136 @@ public sealed class BluespaceLockerSystem : EntitySystem
// Attempt to select, validate, and return a link // Attempt to select, validate, and return a link
var links = component.BluespaceLinks.ToArray(); var links = component.BluespaceLinks.ToArray();
var link = links[_robustRandom.Next(0, component.BluespaceLinks.Count)]; var link = links[_robustRandom.Next(0, component.BluespaceLinks.Count)];
if (ValidLink(component, link)) if (ValidLink(lockerUid, link, component))
return link; return (link, Comp<EntityStorageComponent>(link), CompOrNull<BluespaceLockerComponent>(link));
component.BluespaceLinks.Remove(link); component.BluespaceLinks.Remove(link);
} }
} }
private void PostClose(EntityUid uid, BluespaceLockerComponent component, StorageAfterCloseEvent args) private void PostClose(EntityUid uid, BluespaceLockerComponent component, StorageAfterCloseEvent args)
{
PostClose(uid, component);
}
private void OnBluespaceLockerTeleportDelayComplete(EntityUid uid, BluespaceLockerComponent component, BluespaceLockerTeleportDelayComplete args)
{
PostClose(uid, component, false);
}
private void PostClose(EntityUid uid, BluespaceLockerComponent component, bool doDelay = true)
{ {
EntityStorageComponent? entityStorageComponent = null; EntityStorageComponent? entityStorageComponent = null;
if (!Resolve(uid, ref entityStorageComponent)) if (!Resolve(uid, ref entityStorageComponent))
return; return;
component.CancelToken?.Cancel();
// Do delay
if (doDelay && component.BehaviorProperties.Delay > 0)
{
EnsureComp<DoAfterComponent>(uid);
component.CancelToken = new CancellationTokenSource();
_doAfterSystem.DoAfter(
new DoAfterEventArgs(uid, component.BehaviorProperties.Delay, component.CancelToken.Token)
{
UserFinishedEvent = new BluespaceLockerTeleportDelayComplete()
});
return;
}
// Select target // Select target
var targetContainerStorageComponent = GetTargetStorage(component); var target = GetTarget(uid, component);
if (targetContainerStorageComponent == null) if (target == null)
return; return;
// Move contained items // Move contained items
if (component.TransportEntities) if (component.BehaviorProperties.TransportEntities || component.BehaviorProperties.TransportSentient)
foreach (var entity in entityStorageComponent.Contents.ContainedEntities.ToArray()) foreach (var entity in entityStorageComponent.Contents.ContainedEntities.ToArray())
{ {
if (!component.AllowSentient && EntityManager.HasComponent<MindComponent>(entity)) if (EntityManager.HasComponent<MindComponent>(entity))
continue; {
targetContainerStorageComponent.Contents.Insert(entity, EntityManager); if (component.BehaviorProperties.TransportSentient)
target.Value.storageComponent.Contents.Insert(entity, EntityManager);
}
else if (component.BehaviorProperties.TransportEntities)
target.Value.storageComponent.Contents.Insert(entity, EntityManager);
} }
// Move contained air // Move contained air
if (component.TransportGas) if (component.BehaviorProperties.TransportGas)
{ {
targetContainerStorageComponent.Air.CopyFromMutable(entityStorageComponent.Air); target.Value.storageComponent.Air.CopyFromMutable(entityStorageComponent.Air);
entityStorageComponent.Air.Clear(); entityStorageComponent.Air.Clear();
} }
// Open and empty target // Open and empty target
if (targetContainerStorageComponent.Open) if (target.Value.storageComponent.Open)
{ {
_entityStorage.EmptyContents(targetContainerStorageComponent.Owner, targetContainerStorageComponent); _entityStorage.EmptyContents(target.Value.uid, target.Value.storageComponent);
_entityStorage.ReleaseGas(targetContainerStorageComponent.Owner, targetContainerStorageComponent); _entityStorage.ReleaseGas(target.Value.uid, target.Value.storageComponent);
} }
else else
{ {
if (targetContainerStorageComponent.IsWeldedShut) if (target.Value.storageComponent.IsWeldedShut)
{ {
// It gets bluespaced open... // It gets bluespaced open...
_weldableSystem.ForceWeldedState(targetContainerStorageComponent.Owner, false); _weldableSystem.ForceWeldedState(target.Value.uid, false);
if (targetContainerStorageComponent.IsWeldedShut) if (target.Value.storageComponent.IsWeldedShut)
targetContainerStorageComponent.IsWeldedShut = false; target.Value.storageComponent.IsWeldedShut = false;
} }
LockComponent? lockComponent = null; LockComponent? lockComponent = null;
if (Resolve(targetContainerStorageComponent.Owner, ref lockComponent, false) && lockComponent.Locked) if (Resolve(target.Value.uid, ref lockComponent, false) && lockComponent.Locked)
_lockSystem.Unlock(lockComponent.Owner, lockComponent.Owner, lockComponent); _lockSystem.Unlock(target.Value.uid, target.Value.uid, lockComponent);
_entityStorage.OpenStorage(targetContainerStorageComponent.Owner, targetContainerStorageComponent); _entityStorage.OpenStorage(target.Value.uid, target.Value.storageComponent);
}
// Bluespace effects
if (component.BehaviorProperties.BluespaceEffectOnTeleportSource)
BluespaceEffect(uid, component);
if (component.BehaviorProperties.BluespaceEffectOnTeleportTarget)
BluespaceEffect(target.Value.uid, component);
DestroyAfterLimit(uid, component);
}
private void DestroyAfterLimit(EntityUid uid, BluespaceLockerComponent component)
{
if (component.BehaviorProperties.ClearLinksEvery != -1)
{
component.UsesSinceLinkClear++;
if (component.BehaviorProperties.ClearLinksEvery >= component.UsesSinceLinkClear)
{
component.BluespaceLinks.Clear();
component.UsesSinceLinkClear = 0;
}
}
if (component.BehaviorProperties.DestroyAfterUses == -1)
return;
component.BehaviorProperties.DestroyAfterUses--;
if (component.BehaviorProperties.DestroyAfterUses > 0)
return;
switch (component.BehaviorProperties.DestroyType)
{
case BluespaceLockerDestroyType.Explode:
_explosionSystem.QueueExplosion(uid.ToCoordinates().ToMap(_entityManager),
ExplosionSystem.DefaultExplosionPrototypeId, 4, 1, 2, maxTileBreak: 0);
goto case BluespaceLockerDestroyType.Delete;
case BluespaceLockerDestroyType.Delete:
QueueDel(uid);
break;
case BluespaceLockerDestroyType.DeleteComponent:
RemComp<BluespaceLockerComponent>(uid);
break;
} }
} }
private sealed class BluespaceLockerTeleportDelayComplete : EntityEventArgs
{
}
} }

View File

@@ -353,3 +353,25 @@
state: syndicate state: syndicate
state_open: syndicate_open state_open: syndicate_open
state_closed: syndicate_door state_closed: syndicate_door
# Bluespace
- type: entity
id: LockerBluespaceStation
name: bluespace locker
suffix: once to station
parent: LockerSyndicatePersonal
description: Advanced locker technology.
components:
- type: BluespaceLocker
minBluespaceLinks: 1
bluespaceEffectOnInit: true
behaviorProperties:
delay: 0.5
bluespaceEffectOnTeleportSource: true
bluespaceEffectOnTeleportTarget: true
destroyAfterUses: 2
destroyType: Delete
autoLinksUseProperties: true
autoLinkProperties:
destroyAfterUses: 2
destroyType: DeleteComponent

View File

@@ -127,8 +127,49 @@
parent: ClosetBase parent: ClosetBase
description: It's a storage unit. description: It's a storage unit.
components: components:
- type: Appearance - type: Appearance
visuals: visuals:
- type: StorageVisualizer - type: StorageVisualizer
state_open: generic_open state_open: generic_open
state_closed: generic_door state_closed: generic_door
# Bluespace closet
- type: entity
id: ClosetBluespace
name: suspicious closet
suffix: Bluespace
parent: ClosetMaintenance
description: It's a storage unit... right?
components:
- type: BluespaceLocker
pickLinksFromSameMap: true
minBluespaceLinks: 1
behaviorProperties:
bluespaceEffectOnTeleportSource: true
autoLinksBidirectional: true
autoLinksUseProperties: true
autoLinkProperties:
bluespaceEffectOnTeleportSource: true
# Unstable bluespace closet
- type: entity
id: ClosetBluespaceUnstable
name: suspicious closet
suffix: Bluespace unstable
parent: ClosetMaintenance
description: It's a storage unit... right?
components:
- type: BluespaceLocker
pickLinksFromSameMap: true
minBluespaceLinks: 1
behaviorProperties:
transportEntities: false
bluespaceEffectOnTeleportSource: true
clearLinksEvery: 2
autoLinksBidirectional: true
autoLinksUseProperties: true
autoLinkProperties:
transportEntities: false
bluespaceEffectOnTeleportSource: true
destroyAfterUses: 2
destroyType: DeleteComponent

View File

@@ -7,6 +7,16 @@
startAfter: 30 startAfter: 30
endAfter: 35 endAfter: 35
- type: gameRule
id: BluespaceLockerLink
config:
!type:StationEventRuleConfiguration
id: BluespaceLockerLink
weight: 0
reoccurrenceDelay: 5
earliestStart: 1
endAfter: 1
- type: gameRule - type: gameRule
id: BreakerFlip id: BreakerFlip
config: config: