mirror of
https://github.com/space-syndicate/space-station-14.git
synced 2026-02-15 03:32:07 +01:00
Merge remote-tracking branch 'wizards/master' into upstream-sync
This commit is contained in:
@@ -11,14 +11,16 @@ public sealed class AccessOverlay : Overlay
|
||||
{
|
||||
private readonly IEntityManager _entityManager;
|
||||
private readonly EntityLookupSystem _lookup;
|
||||
private readonly SharedTransformSystem _xform;
|
||||
private readonly Font _font;
|
||||
|
||||
public override OverlaySpace Space => OverlaySpace.ScreenSpace;
|
||||
|
||||
public AccessOverlay(IEntityManager entManager, IResourceCache cache, EntityLookupSystem lookup)
|
||||
public AccessOverlay(IEntityManager entManager, IResourceCache cache, EntityLookupSystem lookup, SharedTransformSystem xform)
|
||||
{
|
||||
_entityManager = entManager;
|
||||
_lookup = lookup;
|
||||
_xform = xform;
|
||||
|
||||
_font = cache.GetFont("/Fonts/NotoSans/NotoSans-Regular.ttf", 12);
|
||||
}
|
||||
@@ -71,7 +73,7 @@ public sealed class AccessOverlay : Overlay
|
||||
textStr = "";
|
||||
}
|
||||
|
||||
var screenPos = args.ViewportControl.WorldToScreen(xform.WorldPosition);
|
||||
var screenPos = args.ViewportControl.WorldToScreen(_xform.GetWorldPosition(xform));
|
||||
|
||||
args.ScreenHandle.DrawString(_font, screenPos, textStr, Color.Gold);
|
||||
}
|
||||
|
||||
@@ -2,4 +2,6 @@ using Content.Shared.Access.Systems;
|
||||
|
||||
namespace Content.Client.Access;
|
||||
|
||||
public sealed class AccessSystem : SharedAccessSystem {}
|
||||
public sealed class AccessSystem : SharedAccessSystem
|
||||
{
|
||||
}
|
||||
|
||||
@@ -13,7 +13,8 @@ public sealed class ShowAccessReadersCommand : IConsoleCommand
|
||||
{
|
||||
var collection = IoCManager.Instance;
|
||||
|
||||
if (collection == null) return;
|
||||
if (collection == null)
|
||||
return;
|
||||
|
||||
var overlay = collection.Resolve<IOverlayManager>();
|
||||
|
||||
@@ -25,9 +26,10 @@ public sealed class ShowAccessReadersCommand : IConsoleCommand
|
||||
|
||||
var entManager = collection.Resolve<IEntityManager>();
|
||||
var cache = collection.Resolve<IResourceCache>();
|
||||
var system = entManager.EntitySysManager.GetEntitySystem<EntityLookupSystem>();
|
||||
var lookup = entManager.System<EntityLookupSystem>();
|
||||
var xform = entManager.System<SharedTransformSystem>();
|
||||
|
||||
overlay.AddOverlay(new AccessOverlay(entManager, cache, system));
|
||||
overlay.AddOverlay(new AccessOverlay(entManager, cache, lookup, xform));
|
||||
shell.WriteLine($"Set access reader debug overlay to true");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,9 +56,10 @@ namespace Content.Client.Access.UI
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
if (!disposing) return;
|
||||
if (!disposing)
|
||||
return;
|
||||
|
||||
_window?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -51,7 +51,9 @@ namespace Content.Client.Access.UI
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
if (!disposing) return;
|
||||
if (!disposing)
|
||||
return;
|
||||
|
||||
_window?.Dispose();
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,8 @@ namespace Content.Client.Access.UI
|
||||
public sealed partial class IdCardConsoleWindow : DefaultWindow
|
||||
{
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
[Dependency] private readonly ILogManager _logManager = default!;
|
||||
private readonly ISawmill _logMill = default!;
|
||||
|
||||
private readonly IdCardConsoleBoundUserInterface _owner;
|
||||
|
||||
@@ -30,6 +32,7 @@ namespace Content.Client.Access.UI
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
IoCManager.InjectDependencies(this);
|
||||
_logMill = _logManager.GetSawmill(SharedIdCardConsoleSystem.Sawmill);
|
||||
|
||||
_owner = owner;
|
||||
|
||||
@@ -67,7 +70,7 @@ namespace Content.Client.Access.UI
|
||||
{
|
||||
if (!prototypeManager.TryIndex<AccessLevelPrototype>(access, out var accessLevel))
|
||||
{
|
||||
Logger.ErrorS(SharedIdCardConsoleSystem.Sawmill, $"Unable to find accesslevel for {access}");
|
||||
_logMill.Error($"Unable to find accesslevel for {access}");
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using Content.Shared.Administration.Notes;
|
||||
using Content.Shared.Administration.Notes;
|
||||
using Content.Shared.Database;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
@@ -18,6 +18,7 @@ public sealed partial class AdminNotesLinePopup : Popup
|
||||
|
||||
public AdminNotesLinePopup(SharedAdminNote note, string playerName, bool showDelete, bool showEdit)
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
RobustXamlLoader.Load(this);
|
||||
|
||||
NoteId = note.Id;
|
||||
|
||||
@@ -163,7 +163,7 @@ public sealed partial class NoteEdit : FancyWindow
|
||||
return;
|
||||
if (DeleteResetOn is null)
|
||||
{
|
||||
DeleteResetOn = _gameTiming.CurTime.Add(TimeSpan.FromSeconds(3));
|
||||
DeleteResetOn = _gameTiming.RealTime + TimeSpan.FromSeconds(3);
|
||||
SubmitButton.Text = Loc.GetString("admin-note-editor-submit-confirm");
|
||||
SubmitButton.ModulateSelfOverride = Color.Red;
|
||||
// Task.Delay(3000).ContinueWith(_ => ResetSubmitButton()); // TODO: fix
|
||||
@@ -185,7 +185,7 @@ public sealed partial class NoteEdit : FancyWindow
|
||||
{
|
||||
base.FrameUpdate(args);
|
||||
// This checks for null for free, do not invert it as null always produces a false value
|
||||
if (DeleteResetOn > _gameTiming.CurTime)
|
||||
if (DeleteResetOn < _gameTiming.RealTime)
|
||||
{
|
||||
ResetSubmitButton();
|
||||
DeleteResetOn = null;
|
||||
|
||||
@@ -40,6 +40,7 @@ namespace Content.Client.Administration.UI.Tabs.AdminbusTab
|
||||
private void Reset()
|
||||
{
|
||||
var entManager = IoCManager.Resolve<IEntityManager>();
|
||||
var xformSystem = entManager.System<SharedTransformSystem>();
|
||||
var playerManager = IoCManager.Resolve<IPlayerManager>();
|
||||
var player = playerManager.LocalPlayer?.ControlledEntity;
|
||||
|
||||
@@ -50,16 +51,16 @@ namespace Content.Client.Administration.UI.Tabs.AdminbusTab
|
||||
if (entManager.TryGetComponent<TransformComponent>(player, out var xform))
|
||||
{
|
||||
currentMap = xform.MapID;
|
||||
position = xform.WorldPosition;
|
||||
position = xformSystem.GetWorldPosition(xform);
|
||||
|
||||
if (entManager.TryGetComponent<TransformComponent>(xform.GridUid, out var gridXform))
|
||||
{
|
||||
rotation = gridXform.WorldRotation;
|
||||
rotation = xformSystem.GetWorldRotation(gridXform);
|
||||
}
|
||||
else
|
||||
{
|
||||
// MapId moment
|
||||
rotation = xform.WorldRotation - xform.LocalRotation;
|
||||
rotation = xformSystem.GetWorldRotation(xform) - xform.LocalRotation;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Client.Atmos.EntitySystems;
|
||||
using Content.Shared.Atmos.Prototypes;
|
||||
@@ -8,9 +7,6 @@ using Robust.Client.Console;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Map.Components;
|
||||
|
||||
namespace Content.Client.Administration.UI.Tabs.AtmosTab
|
||||
@@ -19,24 +15,31 @@ namespace Content.Client.Administration.UI.Tabs.AtmosTab
|
||||
[UsedImplicitly]
|
||||
public sealed partial class AddGasWindow : DefaultWindow
|
||||
{
|
||||
private IEnumerable<MapGridComponent>? _gridData;
|
||||
private List<EntityUid>? _gridData;
|
||||
private IEnumerable<GasPrototype>? _gasData;
|
||||
|
||||
protected override void EnteredTree()
|
||||
{
|
||||
// Fill out grids
|
||||
_gridData = IoCManager.Resolve<IMapManager>().GetAllGrids().Where(g => (int) g.Owner != 0);
|
||||
foreach (var grid in _gridData)
|
||||
var entManager = IoCManager.Resolve<IEntityManager>();
|
||||
var playerManager = IoCManager.Resolve<IPlayerManager>();
|
||||
|
||||
var gridQuery = entManager.AllEntityQueryEnumerator<MapGridComponent>();
|
||||
_gridData ??= new List<EntityUid>();
|
||||
_gridData.Clear();
|
||||
|
||||
while (gridQuery.MoveNext(out var uid, out _))
|
||||
{
|
||||
var player = IoCManager.Resolve<IPlayerManager>().LocalPlayer?.ControlledEntity;
|
||||
var playerGrid = IoCManager.Resolve<IEntityManager>().GetComponentOrNull<TransformComponent>(player)?.GridUid;
|
||||
GridOptions.AddItem($"{grid.Owner} {(playerGrid == grid.Owner ? " (Current)" : "")}");
|
||||
var player = playerManager.LocalPlayer?.ControlledEntity;
|
||||
var playerGrid = entManager.GetComponentOrNull<TransformComponent>(player)?.GridUid;
|
||||
GridOptions.AddItem($"{uid} {(playerGrid == uid ? " (Current)" : "")}");
|
||||
}
|
||||
|
||||
GridOptions.OnItemSelected += eventArgs => GridOptions.SelectId(eventArgs.Id);
|
||||
|
||||
// Fill out gases
|
||||
_gasData = EntitySystem.Get<AtmosphereSystem>().Gases;
|
||||
_gasData = entManager.System<AtmosphereSystem>().Gases;
|
||||
|
||||
foreach (var gas in _gasData)
|
||||
{
|
||||
var gasName = Loc.GetString(gas.Name);
|
||||
@@ -53,8 +56,7 @@ namespace Content.Client.Administration.UI.Tabs.AtmosTab
|
||||
if (_gridData == null || _gasData == null)
|
||||
return;
|
||||
|
||||
var gridList = _gridData.ToList();
|
||||
var gridIndex = gridList[GridOptions.SelectedId].Owner;
|
||||
var gridIndex = _gridData[GridOptions.SelectedId];
|
||||
|
||||
var gasList = _gasData.ToList();
|
||||
var gasId = gasList[GasOptions.SelectedId].ID;
|
||||
|
||||
@@ -19,24 +19,32 @@ namespace Content.Client.Administration.UI.Tabs.AtmosTab
|
||||
[UsedImplicitly]
|
||||
public sealed partial class FillGasWindow : DefaultWindow
|
||||
{
|
||||
private IEnumerable<MapGridComponent>? _gridData;
|
||||
private List<EntityUid>? _gridData;
|
||||
private IEnumerable<GasPrototype>? _gasData;
|
||||
|
||||
protected override void EnteredTree()
|
||||
{
|
||||
// Fill out grids
|
||||
_gridData = IoCManager.Resolve<IMapManager>().GetAllGrids().Where(g => (int) g.Owner != 0);
|
||||
foreach (var grid in _gridData)
|
||||
var entManager = IoCManager.Resolve<IEntityManager>();
|
||||
var playerManager = IoCManager.Resolve<IPlayerManager>();
|
||||
|
||||
var gridQuery = entManager.AllEntityQueryEnumerator<MapGridComponent>();
|
||||
_gridData ??= new List<EntityUid>();
|
||||
_gridData.Clear();
|
||||
|
||||
while (gridQuery.MoveNext(out var uid, out _))
|
||||
{
|
||||
var player = IoCManager.Resolve<IPlayerManager>().LocalPlayer?.ControlledEntity;
|
||||
var playerGrid = IoCManager.Resolve<IEntityManager>().GetComponentOrNull<TransformComponent>(player)?.GridUid;
|
||||
GridOptions.AddItem($"{grid.Owner} {(playerGrid == grid.Owner ? " (Current)" : "")}");
|
||||
var player = playerManager.LocalPlayer?.ControlledEntity;
|
||||
var playerGrid = entManager.GetComponentOrNull<TransformComponent>(player)?.GridUid;
|
||||
GridOptions.AddItem($"{uid} {(playerGrid == uid ? " (Current)" : "")}");
|
||||
_gridData.Add(uid);
|
||||
}
|
||||
|
||||
GridOptions.OnItemSelected += eventArgs => GridOptions.SelectId(eventArgs.Id);
|
||||
|
||||
// Fill out gases
|
||||
_gasData = EntitySystem.Get<AtmosphereSystem>().Gases;
|
||||
_gasData = entManager.System<AtmosphereSystem>().Gases;
|
||||
|
||||
foreach (var gas in _gasData)
|
||||
{
|
||||
var gasName = Loc.GetString(gas.Name);
|
||||
@@ -53,8 +61,7 @@ namespace Content.Client.Administration.UI.Tabs.AtmosTab
|
||||
if (_gridData == null || _gasData == null)
|
||||
return;
|
||||
|
||||
var gridList = _gridData.ToList();
|
||||
var gridIndex = gridList[GridOptions.SelectedId].Owner;
|
||||
var gridIndex = _gridData[GridOptions.SelectedId];
|
||||
|
||||
var gasList = _gasData.ToList();
|
||||
var gasId = gasList[GasOptions.SelectedId].ID;
|
||||
|
||||
@@ -17,16 +17,23 @@ namespace Content.Client.Administration.UI.Tabs.AtmosTab
|
||||
[UsedImplicitly]
|
||||
public sealed partial class SetTemperatureWindow : DefaultWindow
|
||||
{
|
||||
private IEnumerable<MapGridComponent>? _data;
|
||||
private List<EntityUid>? _data;
|
||||
|
||||
protected override void EnteredTree()
|
||||
{
|
||||
_data = IoCManager.Resolve<IMapManager>().GetAllGrids().Where(g => (int) g.Owner != 0);
|
||||
foreach (var grid in _data)
|
||||
var entManager = IoCManager.Resolve<IEntityManager>();
|
||||
var playerManager = IoCManager.Resolve<IPlayerManager>();
|
||||
|
||||
var gridQuery = entManager.AllEntityQueryEnumerator<MapGridComponent>();
|
||||
_data ??= new List<EntityUid>();
|
||||
_data.Clear();
|
||||
|
||||
while (gridQuery.MoveNext(out var uid, out _))
|
||||
{
|
||||
var player = IoCManager.Resolve<IPlayerManager>().LocalPlayer?.ControlledEntity;
|
||||
var playerGrid = IoCManager.Resolve<IEntityManager>().GetComponentOrNull<TransformComponent>(player)?.GridUid;
|
||||
GridOptions.AddItem($"{grid.Owner} {(playerGrid == grid.Owner ? " (Current)" : "")}");
|
||||
var player = playerManager.LocalPlayer?.ControlledEntity;
|
||||
var playerGrid = entManager.GetComponentOrNull<TransformComponent>(player)?.GridUid;
|
||||
GridOptions.AddItem($"{uid} {(playerGrid == uid ? " (Current)" : "")}");
|
||||
_data.Add(uid);
|
||||
}
|
||||
|
||||
GridOptions.OnItemSelected += eventArgs => GridOptions.SelectId(eventArgs.Id);
|
||||
@@ -37,8 +44,8 @@ namespace Content.Client.Administration.UI.Tabs.AtmosTab
|
||||
{
|
||||
if (_data == null)
|
||||
return;
|
||||
var dataList = _data.ToList();
|
||||
var selectedGrid = dataList[GridOptions.SelectedId].Owner;
|
||||
|
||||
var selectedGrid = _data[GridOptions.SelectedId];
|
||||
IoCManager.Resolve<IClientConsoleHost>()
|
||||
.ExecuteCommand($"settemp {TileXSpin.Value} {TileYSpin.Value} {selectedGrid} {TemperatureSpin.Value}");
|
||||
}
|
||||
|
||||
@@ -9,9 +9,9 @@ namespace Content.Client.Audio;
|
||||
/// </summary>
|
||||
public sealed class AmbientSoundOverlay : Overlay
|
||||
{
|
||||
private IEntityManager _entManager;
|
||||
private AmbientSoundSystem _ambient;
|
||||
private EntityLookupSystem _lookup;
|
||||
private readonly IEntityManager _entManager;
|
||||
private readonly AmbientSoundSystem _ambient;
|
||||
private readonly EntityLookupSystem _lookup;
|
||||
|
||||
public override OverlaySpace Space => OverlaySpace.WorldSpace;
|
||||
|
||||
@@ -27,6 +27,7 @@ public sealed class AmbientSoundOverlay : Overlay
|
||||
var worldHandle = args.WorldHandle;
|
||||
var ambientQuery = _entManager.GetEntityQuery<AmbientSoundComponent>();
|
||||
var xformQuery = _entManager.GetEntityQuery<TransformComponent>();
|
||||
var xformSystem = _entManager.System<SharedTransformSystem>();
|
||||
|
||||
const float Size = 0.25f;
|
||||
const float Alpha = 0.25f;
|
||||
@@ -40,16 +41,16 @@ public sealed class AmbientSoundOverlay : Overlay
|
||||
{
|
||||
if (_ambient.IsActive(ambientSound))
|
||||
{
|
||||
worldHandle.DrawCircle(xform.WorldPosition, Size, Color.LightGreen.WithAlpha(Alpha * 2f));
|
||||
worldHandle.DrawCircle(xformSystem.GetWorldPosition(xform), Size, Color.LightGreen.WithAlpha(Alpha * 2f));
|
||||
}
|
||||
else
|
||||
{
|
||||
worldHandle.DrawCircle(xform.WorldPosition, Size, Color.Orange.WithAlpha(Alpha));
|
||||
worldHandle.DrawCircle(xformSystem.GetWorldPosition(xform), Size, Color.Orange.WithAlpha(Alpha));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
worldHandle.DrawCircle(xform.WorldPosition, Size, Color.Red.WithAlpha(Alpha));
|
||||
worldHandle.DrawCircle(xformSystem.GetWorldPosition(xform), Size, Color.Red.WithAlpha(Alpha));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace Content.Client.Inventory
|
||||
public Action<SlotData>? EntitySlotUpdate = null;
|
||||
public Action<SlotData>? OnSlotAdded = null;
|
||||
public Action<SlotData>? OnSlotRemoved = null;
|
||||
public Action<InventorySlotsComponent>? OnLinkInventorySlots = null;
|
||||
public Action<EntityUid, InventorySlotsComponent>? OnLinkInventorySlots = null;
|
||||
public Action? OnUnlinkInventory = null;
|
||||
public Action<SlotSpriteUpdate>? OnSpriteUpdate = null;
|
||||
|
||||
@@ -138,7 +138,7 @@ namespace Content.Client.Inventory
|
||||
}
|
||||
}
|
||||
|
||||
OnLinkInventorySlots?.Invoke(component);
|
||||
OnLinkInventorySlots?.Invoke(uid, component);
|
||||
}
|
||||
|
||||
public override void Shutdown()
|
||||
@@ -173,7 +173,7 @@ namespace Content.Client.Inventory
|
||||
}
|
||||
|
||||
OnUnlinkInventory?.Invoke();
|
||||
OnLinkInventorySlots?.Invoke(component);
|
||||
OnLinkInventorySlots?.Invoke(player.Value, component);
|
||||
}
|
||||
|
||||
public void SetSlotHighlight(EntityUid owner, InventorySlotsComponent component, string slotName, bool state)
|
||||
|
||||
@@ -384,7 +384,7 @@ namespace Content.Client.Light.Components
|
||||
public readonly List<LightBehaviourAnimationTrack> Behaviours = new();
|
||||
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
private readonly List<AnimationContainer> _animations = new();
|
||||
public readonly List<AnimationContainer> Animations = new();
|
||||
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
private Dictionary<string, object> _originalPropertyValues = new();
|
||||
@@ -400,60 +400,11 @@ namespace Content.Client.Light.Components
|
||||
AnimationTracks = {behaviour}
|
||||
};
|
||||
|
||||
_animations.Add(new AnimationContainer(key, animation, behaviour));
|
||||
Animations.Add(new AnimationContainer(key, animation, behaviour));
|
||||
key++;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Startup()
|
||||
{
|
||||
base.Startup();
|
||||
|
||||
// TODO: Do NOT ensure component here. And use eventbus events instead...
|
||||
Owner.EnsureComponent<AnimationPlayerComponent>();
|
||||
|
||||
if (_entMan.TryGetComponent(Owner, out AnimationPlayerComponent? animation))
|
||||
{
|
||||
#pragma warning disable 618
|
||||
animation.AnimationCompleted += OnAnimationCompleted;
|
||||
#pragma warning restore 618
|
||||
}
|
||||
|
||||
foreach (var container in _animations)
|
||||
{
|
||||
container.LightBehaviour.Initialize(Owner, _random, _entMan);
|
||||
}
|
||||
|
||||
// we need to initialize all behaviours before starting any
|
||||
foreach (var container in _animations)
|
||||
{
|
||||
if (container.LightBehaviour.Enabled)
|
||||
{
|
||||
StartLightBehaviour(container.LightBehaviour.ID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnAnimationCompleted(string key)
|
||||
{
|
||||
var container = _animations.FirstOrDefault(x => x.FullKey == key);
|
||||
|
||||
if (container == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (container.LightBehaviour.IsLooped)
|
||||
{
|
||||
container.LightBehaviour.UpdatePlaybackValues(container.Animation);
|
||||
|
||||
if (_entMan.TryGetComponent(Owner, out AnimationPlayerComponent? animation))
|
||||
{
|
||||
animation.Play(container.Animation, container.FullKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If we disable all the light behaviours we want to be able to revert the light to its original state.
|
||||
/// </summary>
|
||||
@@ -485,7 +436,7 @@ namespace Content.Client.Light.Components
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var container in _animations)
|
||||
foreach (var container in Animations)
|
||||
{
|
||||
if (container.LightBehaviour.ID == id || id == string.Empty)
|
||||
{
|
||||
@@ -516,7 +467,7 @@ namespace Content.Client.Light.Components
|
||||
|
||||
var toRemove = new List<AnimationContainer>();
|
||||
|
||||
foreach (var container in _animations)
|
||||
foreach (var container in Animations)
|
||||
{
|
||||
if (container.LightBehaviour.ID == id || id == string.Empty)
|
||||
{
|
||||
@@ -534,7 +485,7 @@ namespace Content.Client.Light.Components
|
||||
|
||||
foreach (var container in toRemove)
|
||||
{
|
||||
_animations.Remove(container);
|
||||
Animations.Remove(container);
|
||||
}
|
||||
|
||||
if (resetToOriginalSettings && _entMan.TryGetComponent(Owner, out PointLightComponent? light))
|
||||
@@ -559,7 +510,7 @@ namespace Content.Client.Light.Components
|
||||
return false;
|
||||
}
|
||||
|
||||
return _animations.Any(container => animation.HasRunningAnimation(KeyPrefix + container.Key));
|
||||
return Animations.Any(container => animation.HasRunningAnimation(KeyPrefix + container.Key));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -569,7 +520,7 @@ namespace Content.Client.Light.Components
|
||||
{
|
||||
var key = 0;
|
||||
|
||||
while (_animations.Any(x => x.Key == key))
|
||||
while (Animations.Any(x => x.Key == key))
|
||||
{
|
||||
key++;
|
||||
}
|
||||
@@ -582,7 +533,7 @@ namespace Content.Client.Light.Components
|
||||
behaviour.Initialize(Owner, _random, _entMan);
|
||||
|
||||
var container = new AnimationContainer(key, animation, behaviour);
|
||||
_animations.Add(container);
|
||||
Animations.Add(container);
|
||||
|
||||
if (playImmediately)
|
||||
{
|
||||
|
||||
55
Content.Client/Light/EntitySystems/LightBehaviorSystem.cs
Normal file
55
Content.Client/Light/EntitySystems/LightBehaviorSystem.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
using System.Linq;
|
||||
using Content.Client.Light.Components;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Shared.Random;
|
||||
|
||||
namespace Content.Client.Light.EntitySystems;
|
||||
|
||||
public sealed class LightBehaviorSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
[Dependency] private readonly AnimationPlayerSystem _player = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeLocalEvent<LightBehaviourComponent, ComponentStartup>(OnLightStartup);
|
||||
SubscribeLocalEvent<LightBehaviourComponent, AnimationCompletedEvent>(OnBehaviorAnimationCompleted);
|
||||
}
|
||||
|
||||
private void OnBehaviorAnimationCompleted(EntityUid uid, LightBehaviourComponent component, AnimationCompletedEvent args)
|
||||
{
|
||||
var container = component.Animations.FirstOrDefault(x => x.FullKey == args.Key);
|
||||
|
||||
if (container == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (container.LightBehaviour.IsLooped)
|
||||
{
|
||||
container.LightBehaviour.UpdatePlaybackValues(container.Animation);
|
||||
_player.Play(uid, container.Animation, container.FullKey);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnLightStartup(EntityUid uid, LightBehaviourComponent component, ComponentStartup args)
|
||||
{
|
||||
// TODO: Do NOT ensure component here. And use eventbus events instead...
|
||||
EnsureComp<AnimationPlayerComponent>(uid);
|
||||
|
||||
foreach (var container in component.Animations)
|
||||
{
|
||||
container.LightBehaviour.Initialize(uid, _random, EntityManager);
|
||||
}
|
||||
|
||||
// we need to initialize all behaviours before starting any
|
||||
foreach (var container in component.Animations)
|
||||
{
|
||||
if (container.LightBehaviour.Enabled)
|
||||
{
|
||||
component.StartLightBehaviour(container.LightBehaviour.ID);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@ public sealed class JetpackSystem : SharedJetpackSystem
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||
[Dependency] private readonly ClothingSystem _clothing = default!;
|
||||
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -22,7 +22,7 @@ public sealed class JetpackSystem : SharedJetpackSystem
|
||||
SubscribeLocalEvent<JetpackComponent, AppearanceChangeEvent>(OnJetpackAppearance);
|
||||
}
|
||||
|
||||
protected override bool CanEnable(JetpackComponent component)
|
||||
protected override bool CanEnable(EntityUid uid, JetpackComponent component)
|
||||
{
|
||||
// No predicted atmos so you'd have to do a lot of funny to get this working.
|
||||
return false;
|
||||
@@ -30,7 +30,7 @@ public sealed class JetpackSystem : SharedJetpackSystem
|
||||
|
||||
private void OnJetpackAppearance(EntityUid uid, JetpackComponent component, ref AppearanceChangeEvent args)
|
||||
{
|
||||
_appearance.TryGetData<bool>(uid, JetpackVisuals.Enabled, out var enabled, args.Component);
|
||||
Appearance.TryGetData<bool>(uid, JetpackVisuals.Enabled, out var enabled, args.Component);
|
||||
|
||||
var state = "icon" + (enabled ? "-on" : "");
|
||||
args.Sprite?.LayerSetState(0, state);
|
||||
@@ -43,16 +43,21 @@ public sealed class JetpackSystem : SharedJetpackSystem
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
if (!_timing.IsFirstTimePredicted) return;
|
||||
if (!_timing.IsFirstTimePredicted)
|
||||
return;
|
||||
|
||||
foreach (var comp in EntityQuery<ActiveJetpackComponent>())
|
||||
// TODO: Please don't copy-paste this I beg
|
||||
// make a generic particle emitter system / actual particles instead.
|
||||
var query = EntityQueryEnumerator<ActiveJetpackComponent>();
|
||||
|
||||
while (query.MoveNext(out var uid, out var comp))
|
||||
{
|
||||
if (_timing.CurTime < comp.TargetTime)
|
||||
continue;
|
||||
|
||||
comp.TargetTime = _timing.CurTime + TimeSpan.FromSeconds(comp.EffectCooldown);
|
||||
|
||||
CreateParticles(comp.Owner);
|
||||
CreateParticles(uid);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,7 +67,9 @@ public sealed class JetpackSystem : SharedJetpackSystem
|
||||
if (Container.TryGetContainingContainer(uid, out var container) &&
|
||||
TryComp<PhysicsComponent>(container.Owner, out var body) &&
|
||||
body.LinearVelocity.LengthSquared() < 1f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var uidXform = Transform(uid);
|
||||
var coordinates = uidXform.Coordinates;
|
||||
@@ -70,19 +77,17 @@ public sealed class JetpackSystem : SharedJetpackSystem
|
||||
|
||||
if (_mapManager.TryGetGrid(gridUid, out var grid))
|
||||
{
|
||||
coordinates = new EntityCoordinates(grid.Owner, grid.WorldToLocal(coordinates.ToMapPos(EntityManager)));
|
||||
coordinates = new EntityCoordinates(gridUid.Value, grid.WorldToLocal(coordinates.ToMapPos(EntityManager, _transform)));
|
||||
}
|
||||
else if (uidXform.MapUid != null)
|
||||
{
|
||||
coordinates = new EntityCoordinates(uidXform.MapUid.Value, uidXform.WorldPosition);
|
||||
coordinates = new EntityCoordinates(uidXform.MapUid.Value, _transform.GetWorldPosition(uidXform));
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var ent = Spawn("JetpackEffect", coordinates);
|
||||
var xform = Transform(ent);
|
||||
xform.Coordinates = coordinates;
|
||||
Spawn("JetpackEffect", coordinates);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ public sealed class InventoryUIController : UIController, IOnStateEntered<Gamepl
|
||||
[UISystemDependency] private readonly ClientInventorySystem _inventorySystem = default!;
|
||||
[UISystemDependency] private readonly HandsSystem _handsSystem = default!;
|
||||
|
||||
private EntityUid? _playerUid;
|
||||
private InventorySlotsComponent? _playerInventory;
|
||||
private readonly Dictionary<string, ItemSlotButtonContainer> _slotGroups = new();
|
||||
|
||||
@@ -222,26 +223,26 @@ public sealed class InventoryUIController : UIController, IOnStateEntered<Gamepl
|
||||
return;
|
||||
}
|
||||
|
||||
if (_playerInventory == null)
|
||||
if (_playerInventory == null || _playerUid == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.Function == ContentKeyFunctions.ExamineEntity)
|
||||
{
|
||||
_inventorySystem.UIInventoryExamine(slot, _playerInventory.Owner);
|
||||
_inventorySystem.UIInventoryExamine(slot, _playerUid.Value);
|
||||
}
|
||||
else if (args.Function == EngineKeyFunctions.UseSecondary)
|
||||
{
|
||||
_inventorySystem.UIInventoryOpenContextMenu(slot, _playerInventory.Owner);
|
||||
_inventorySystem.UIInventoryOpenContextMenu(slot, _playerUid.Value);
|
||||
}
|
||||
else if (args.Function == ContentKeyFunctions.ActivateItemInWorld)
|
||||
{
|
||||
_inventorySystem.UIInventoryActivateItem(slot, _playerInventory.Owner);
|
||||
_inventorySystem.UIInventoryActivateItem(slot, _playerUid.Value);
|
||||
}
|
||||
else if (args.Function == ContentKeyFunctions.AltActivateItemInWorld)
|
||||
{
|
||||
_inventorySystem.UIInventoryAltActivateItem(slot, _playerInventory.Owner);
|
||||
_inventorySystem.UIInventoryAltActivateItem(slot, _playerUid.Value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -258,7 +259,7 @@ public sealed class InventoryUIController : UIController, IOnStateEntered<Gamepl
|
||||
|
||||
public void UpdateHover(SlotControl control)
|
||||
{
|
||||
var player = _playerInventory?.Owner;
|
||||
var player = _playerUid;
|
||||
|
||||
if (!control.MouseIsHovering ||
|
||||
_playerInventory == null ||
|
||||
@@ -305,9 +306,10 @@ public sealed class InventoryUIController : UIController, IOnStateEntered<Gamepl
|
||||
_inventorySystem.ReloadInventory();
|
||||
}
|
||||
|
||||
private void LoadSlots(InventorySlotsComponent clientInv)
|
||||
private void LoadSlots(EntityUid clientUid, InventorySlotsComponent clientInv)
|
||||
{
|
||||
UnloadSlots();
|
||||
_playerUid = clientUid;
|
||||
_playerInventory = clientInv;
|
||||
foreach (var slotData in clientInv.SlotData.Values)
|
||||
{
|
||||
@@ -319,6 +321,7 @@ public sealed class InventoryUIController : UIController, IOnStateEntered<Gamepl
|
||||
|
||||
private void UnloadSlots()
|
||||
{
|
||||
_playerUid = null;
|
||||
_playerInventory = null;
|
||||
foreach (var slotGroup in _slotGroups.Values)
|
||||
{
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Shared.Access;
|
||||
using Content.Shared.Access.Components;
|
||||
using Content.Shared.Access.Systems;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.IntegrationTests.Tests.Access
|
||||
{
|
||||
@@ -9,6 +12,35 @@ namespace Content.IntegrationTests.Tests.Access
|
||||
[TestOf(typeof(AccessReaderComponent))]
|
||||
public sealed class AccessReaderTest
|
||||
{
|
||||
[Test]
|
||||
public async Task TestProtoTags()
|
||||
{
|
||||
await using var pair = await PoolManager.GetServerClient(new PoolSettings() { NoClient = true });
|
||||
var server = pair.Pair.Server;
|
||||
|
||||
var protoManager = server.ResolveDependency<IPrototypeManager>();
|
||||
var accessName = server.ResolveDependency<IComponentFactory>().GetComponentName(typeof(AccessReaderComponent));
|
||||
|
||||
await server.WaitAssertion(() =>
|
||||
{
|
||||
foreach (var ent in protoManager.EnumeratePrototypes<EntityPrototype>())
|
||||
{
|
||||
if (!ent.Components.TryGetComponent(accessName, out var access))
|
||||
continue;
|
||||
|
||||
var reader = (AccessReaderComponent) access;
|
||||
var allTags = reader.AccessLists.SelectMany(c => c).Union(reader.DenyTags);
|
||||
|
||||
foreach (var level in allTags)
|
||||
{
|
||||
Assert.That(protoManager.HasIndex<AccessLevelPrototype>(level), $"Invalid access level: {level} found on {ent}");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
await pair.CleanReturnAsync();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task TestTags()
|
||||
{
|
||||
|
||||
@@ -28,10 +28,6 @@ namespace Content.Server.Database.Migrations.Postgres
|
||||
name: "FK_admin_notes_player_player_user_id",
|
||||
table: "admin_notes");
|
||||
|
||||
migrationBuilder.DropCheckConstraint(
|
||||
name: "HaveEitherAddressOrUserIdOrHWId",
|
||||
table: "server_role_ban");
|
||||
|
||||
migrationBuilder.DropCheckConstraint(
|
||||
name: "HaveEitherAddressOrUserIdOrHWId",
|
||||
table: "server_ban");
|
||||
|
||||
@@ -2,5 +2,6 @@ namespace Content.Server.Access.Components
|
||||
{
|
||||
[RegisterComponent]
|
||||
public sealed class AgentIDCardComponent : Component
|
||||
{}
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,5 +4,4 @@ namespace Content.Server.Access.Systems;
|
||||
|
||||
public sealed class AccessSystem : SharedAccessSystem
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ namespace Content.Server.Access.Systems
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
|
||||
[Dependency] private readonly MetaDataSystem _metaSystem = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -112,7 +113,7 @@ namespace Content.Server.Access.Systems
|
||||
if (player != null)
|
||||
{
|
||||
_adminLogger.Add(LogType.Identity, LogImpact.Low,
|
||||
$"{ToPrettyString(player.Value):player} has changed the job title of {ToPrettyString(id.Owner):entity} to {jobTitle} ");
|
||||
$"{ToPrettyString(player.Value):player} has changed the job title of {ToPrettyString(uid):entity} to {jobTitle} ");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -149,7 +150,7 @@ namespace Content.Server.Access.Systems
|
||||
if (player != null)
|
||||
{
|
||||
_adminLogger.Add(LogType.Identity, LogImpact.Low,
|
||||
$"{ToPrettyString(player.Value):player} has changed the name of {ToPrettyString(id.Owner):entity} to {fullName} ");
|
||||
$"{ToPrettyString(player.Value):player} has changed the name of {ToPrettyString(uid):entity} to {fullName} ");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -174,7 +175,7 @@ namespace Content.Server.Access.Systems
|
||||
: Loc.GetString("access-id-card-component-owner-full-name-job-title-text",
|
||||
("fullName", id.FullName),
|
||||
("jobSuffix", jobSuffix));
|
||||
EntityManager.GetComponent<MetaDataComponent>(id.Owner).EntityName = val;
|
||||
_metaSystem.SetEntityName(uid, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,9 +21,8 @@ public sealed class IdExaminableSystem : EntitySystem
|
||||
|
||||
private void OnGetExamineVerbs(EntityUid uid, IdExaminableComponent component, GetVerbsEvent<ExamineVerb> args)
|
||||
{
|
||||
|
||||
var detailsRange = _examineSystem.IsInDetailsRange(args.User, uid);
|
||||
var info = GetInfo(component.Owner) ?? Loc.GetString("id-examinable-component-verb-no-id");
|
||||
var info = GetInfo(uid) ?? Loc.GetString("id-examinable-component-verb-no-id");
|
||||
|
||||
var verb = new ExamineVerb()
|
||||
{
|
||||
@@ -36,7 +35,7 @@ public sealed class IdExaminableSystem : EntitySystem
|
||||
Category = VerbCategory.Examine,
|
||||
Disabled = !detailsRange,
|
||||
Message = Loc.GetString("id-examinable-component-verb-disabled"),
|
||||
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/character.svg.192dpi.png"))
|
||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/character.svg.192dpi.png"))
|
||||
};
|
||||
|
||||
args.Verbs.Add(verb);
|
||||
@@ -47,12 +46,13 @@ public sealed class IdExaminableSystem : EntitySystem
|
||||
if (_inventorySystem.TryGetSlotEntity(uid, "id", out var idUid))
|
||||
{
|
||||
// PDA
|
||||
if (EntityManager.TryGetComponent(idUid, out PdaComponent? pda) && pda.ContainedId is not null)
|
||||
if (EntityManager.TryGetComponent(idUid, out PdaComponent? pda) &&
|
||||
TryComp<IdCardComponent>(pda.ContainedId, out var id))
|
||||
{
|
||||
return GetNameAndJob(pda.ContainedId);
|
||||
return GetNameAndJob(id);
|
||||
}
|
||||
// ID Card
|
||||
if (EntityManager.TryGetComponent(idUid, out IdCardComponent? id))
|
||||
if (EntityManager.TryGetComponent(idUid, out id))
|
||||
{
|
||||
return GetNameAndJob(id);
|
||||
}
|
||||
|
||||
@@ -26,15 +26,16 @@ namespace Content.Server.Access.Systems
|
||||
{
|
||||
// Go over all ID cards and make sure they're correctly configured for extended access.
|
||||
|
||||
foreach (var card in EntityQuery<PresetIdCardComponent>())
|
||||
var query = EntityQueryEnumerator<PresetIdCardComponent>();
|
||||
while (query.MoveNext(out var uid, out var card))
|
||||
{
|
||||
var station = _stationSystem.GetOwningStation(card.Owner);
|
||||
var station = _stationSystem.GetOwningStation(uid);
|
||||
|
||||
// If we're not on an extended access station, the ID is already configured correctly from MapInit.
|
||||
if (station == null || !Comp<StationJobsComponent>(station.Value).ExtendedAccess)
|
||||
return;
|
||||
|
||||
SetupIdAccess(card.Owner, card, true);
|
||||
SetupIdAccess(uid, card, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,7 +46,7 @@ namespace Content.Server.Access.Systems
|
||||
// or may not yet know whether it is on extended access (players not spawned yet).
|
||||
// PlayerJobsAssigned makes sure extended access is configured correctly in that case.
|
||||
|
||||
var station = _stationSystem.GetOwningStation(id.Owner);
|
||||
var station = _stationSystem.GetOwningStation(uid);
|
||||
var extended = false;
|
||||
if (station != null)
|
||||
extended = Comp<StationJobsComponent>(station.Value).ExtendedAccess;
|
||||
|
||||
@@ -31,6 +31,13 @@ public sealed class BanListEui : BaseEui
|
||||
_admins.OnPermsChanged += OnPermsChanged;
|
||||
}
|
||||
|
||||
public override void Closed()
|
||||
{
|
||||
base.Closed();
|
||||
|
||||
_admins.OnPermsChanged -= OnPermsChanged;
|
||||
}
|
||||
|
||||
public override EuiStateBase GetNewState()
|
||||
{
|
||||
return new BanListEuiState(BanListPlayerName, Bans);
|
||||
@@ -42,10 +49,6 @@ public sealed class BanListEui : BaseEui
|
||||
{
|
||||
Close();
|
||||
}
|
||||
else
|
||||
{
|
||||
StateDirty();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task LoadFromDb()
|
||||
|
||||
@@ -99,8 +99,6 @@ public sealed class DepartmentBanCommand : IConsoleCommand
|
||||
{
|
||||
_banManager.CreateRoleBan(targetUid, located.Username, shell.Player?.UserId, null, targetHWid, job, minutes, severity, reason, now);
|
||||
}
|
||||
|
||||
_banManager.SendRoleBans(located.UserId);
|
||||
}
|
||||
|
||||
public CompletionResult GetCompletion(IConsoleShell shell, string[] args)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.Linq;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Content.Server.Administration.Managers;
|
||||
using Content.Shared.Administration;
|
||||
@@ -87,7 +87,6 @@ public sealed class RoleBanCommand : IConsoleCommand
|
||||
var targetHWid = located.LastHWId;
|
||||
|
||||
_bans.CreateRoleBan(targetUid, located.Username, shell.Player?.UserId, null, targetHWid, job, minutes, severity, reason, DateTimeOffset.UtcNow);
|
||||
_bans.SendRoleBans(located.UserId);
|
||||
}
|
||||
|
||||
public CompletionResult GetCompletion(IConsoleShell shell, string[] args)
|
||||
|
||||
@@ -2,6 +2,7 @@ using Content.Server.Administration.UI;
|
||||
using Content.Server.EUI;
|
||||
using Content.Server.Hands.Systems;
|
||||
using Content.Server.Preferences.Managers;
|
||||
using Content.Shared.Access.Components;
|
||||
using Content.Shared.Administration;
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.Inventory;
|
||||
@@ -16,7 +17,7 @@ using Robust.Shared.Prototypes;
|
||||
namespace Content.Server.Administration.Commands
|
||||
{
|
||||
[AdminCommand(AdminFlags.Admin)]
|
||||
sealed class SetOutfitCommand : IConsoleCommand
|
||||
public sealed class SetOutfitCommand : IConsoleCommand
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entities = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototypes = default!;
|
||||
@@ -25,7 +26,7 @@ namespace Content.Server.Administration.Commands
|
||||
|
||||
public string Description => Loc.GetString("set-outfit-command-description", ("requiredComponent", nameof(InventoryComponent)));
|
||||
|
||||
public string Help => Loc.GetString("set-outfit-command-help-text", ("command",Command));
|
||||
public string Help => Loc.GetString("set-outfit-command-help-text", ("command", Command));
|
||||
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
@@ -51,7 +52,7 @@ namespace Content.Server.Administration.Commands
|
||||
|
||||
if (!_entities.HasComponent<InventoryComponent?>(target))
|
||||
{
|
||||
shell.WriteLine(Loc.GetString("shell-target-entity-does-not-have-message",("missing", "inventory")));
|
||||
shell.WriteLine(Loc.GetString("shell-target-entity-does-not-have-message", ("missing", "inventory")));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -106,9 +107,9 @@ namespace Content.Server.Administration.Commands
|
||||
var equipmentEntity = entityManager.SpawnEntity(gearStr, entityManager.GetComponent<TransformComponent>(target).Coordinates);
|
||||
if (slot.Name == "id" &&
|
||||
entityManager.TryGetComponent<PdaComponent?>(equipmentEntity, out var pdaComponent) &&
|
||||
pdaComponent.ContainedId != null)
|
||||
entityManager.TryGetComponent<IdCardComponent>(pdaComponent.ContainedId, out var id))
|
||||
{
|
||||
pdaComponent.ContainedId.FullName = entityManager.GetComponent<MetaDataComponent>(target).EntityName;
|
||||
id.FullName = entityManager.GetComponent<MetaDataComponent>(target).EntityName;
|
||||
}
|
||||
|
||||
invSystem.TryEquip(target, equipmentEntity, slot.Name, silent: true, force: true, inventory: inventoryComponent);
|
||||
|
||||
@@ -40,6 +40,8 @@ public sealed class BanManager : IBanManager, IPostInjectInit
|
||||
public void Initialize()
|
||||
{
|
||||
_playerManager.PlayerStatusChanged += OnPlayerStatusChanged;
|
||||
|
||||
_netManager.RegisterNetMessage<MsgRoleBans>();
|
||||
}
|
||||
|
||||
private async void OnPlayerStatusChanged(object? sender, SessionStatusEventArgs e)
|
||||
@@ -212,6 +214,11 @@ public sealed class BanManager : IBanManager, IPostInjectInit
|
||||
|
||||
var length = expires == null ? Loc.GetString("cmd-roleban-inf") : Loc.GetString("cmd-roleban-until", ("expires", expires));
|
||||
_chat.SendAdminAlert(Loc.GetString("cmd-roleban-success", ("target", targetUsername ?? "null"), ("role", role), ("reason", reason), ("length", length)));
|
||||
|
||||
if (target != null)
|
||||
{
|
||||
SendRoleBans(target.Value);
|
||||
}
|
||||
}
|
||||
|
||||
public HashSet<string>? GetJobBans(NetUserId playerUserId)
|
||||
|
||||
@@ -10,6 +10,7 @@ using Content.Server.Damage.Components;
|
||||
using Content.Server.Doors.Systems;
|
||||
using Content.Server.Hands.Systems;
|
||||
using Content.Server.Power.Components;
|
||||
using Content.Server.Power.EntitySystems;
|
||||
using Content.Server.Stack;
|
||||
using Content.Server.Station.Components;
|
||||
using Content.Server.Station.Systems;
|
||||
@@ -49,6 +50,9 @@ public sealed partial class AdminVerbSystem
|
||||
[Dependency] private readonly AdminTestArenaSystem _adminTestArenaSystem = default!;
|
||||
[Dependency] private readonly StationJobsSystem _stationJobsSystem = default!;
|
||||
[Dependency] private readonly JointSystem _jointSystem = default!;
|
||||
[Dependency] private readonly BatterySystem _batterySystem = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _xformSystem = default!;
|
||||
[Dependency] private readonly MetaDataSystem _metaSystem = default!;
|
||||
|
||||
private void AddTricksVerbs(GetVerbsEvent<Verb> args)
|
||||
{
|
||||
@@ -80,7 +84,6 @@ public sealed partial class AdminVerbSystem
|
||||
? "admin-trick-unbolt-description"
|
||||
: "admin-trick-bolt-description"),
|
||||
Priority = (int) (bolts.BoltsDown ? TricksVerbPriorities.Unbolt : TricksVerbPriorities.Bolt),
|
||||
|
||||
};
|
||||
args.Verbs.Add(bolt);
|
||||
}
|
||||
@@ -91,7 +94,7 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = airlock.EmergencyAccess ? "Emergency Access Off" : "Emergency Access On",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/AdminActions/emergency_access.png")),
|
||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/emergency_access.png")),
|
||||
Act = () =>
|
||||
{
|
||||
_airlockSystem.ToggleEmergencyAccess(args.Target, airlock);
|
||||
@@ -100,9 +103,7 @@ public sealed partial class AdminVerbSystem
|
||||
Message = Loc.GetString(airlock.EmergencyAccess
|
||||
? "admin-trick-emergency-access-off-description"
|
||||
: "admin-trick-emergency-access-on-description"),
|
||||
Priority = (int) (airlock.EmergencyAccess
|
||||
? TricksVerbPriorities.EmergencyAccessOff
|
||||
: TricksVerbPriorities.EmergencyAccessOn),
|
||||
Priority = (int) (airlock.EmergencyAccess ? TricksVerbPriorities.EmergencyAccessOff : TricksVerbPriorities.EmergencyAccessOn),
|
||||
};
|
||||
args.Verbs.Add(emergencyAccess);
|
||||
}
|
||||
@@ -113,7 +114,7 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Rejuvenate",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/AdminActions/rejuvenate.png")),
|
||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/rejuvenate.png")),
|
||||
Act = () =>
|
||||
{
|
||||
RejuvenateCommand.PerformRejuvenate(args.Target);
|
||||
@@ -131,7 +132,7 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Make Indestructible",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/VerbIcons/plus.svg.192dpi.png")),
|
||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/plus.svg.192dpi.png")),
|
||||
Act = () =>
|
||||
{
|
||||
_godmodeSystem.EnableGodmode(args.Target);
|
||||
@@ -148,7 +149,7 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Make Vulnerable",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/VerbIcons/plus.svg.192dpi.png")),
|
||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/plus.svg.192dpi.png")),
|
||||
Act = () =>
|
||||
{
|
||||
_godmodeSystem.DisableGodmode(args.Target);
|
||||
@@ -166,11 +167,11 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Refill Battery",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/AdminActions/fill_battery.png")),
|
||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/fill_battery.png")),
|
||||
Act = () =>
|
||||
{
|
||||
battery.CurrentCharge = battery.MaxCharge;
|
||||
Dirty(battery);
|
||||
_batterySystem.SetCharge(args.Target, battery.MaxCharge, battery);
|
||||
Dirty(args.Target, battery);
|
||||
},
|
||||
Impact = LogImpact.Medium,
|
||||
Message = Loc.GetString("admin-trick-refill-battery-description"),
|
||||
@@ -182,11 +183,11 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Drain Battery",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/AdminActions/drain_battery.png")),
|
||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/drain_battery.png")),
|
||||
Act = () =>
|
||||
{
|
||||
battery.CurrentCharge = 0;
|
||||
Dirty(battery);
|
||||
_batterySystem.SetCharge(args.Target, 0, battery);
|
||||
Dirty(args.Target, battery);
|
||||
},
|
||||
Impact = LogImpact.Medium,
|
||||
Message = Loc.GetString("admin-trick-drain-battery-description"),
|
||||
@@ -198,7 +199,7 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Infinite Battery",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/AdminActions/infinite_battery.png")),
|
||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/infinite_battery.png")),
|
||||
Act = () =>
|
||||
{
|
||||
var recharger = EnsureComp<BatterySelfRechargerComponent>(args.Target);
|
||||
@@ -218,7 +219,7 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Block Unanchoring",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/VerbIcons/anchor.svg.192dpi.png")),
|
||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/anchor.svg.192dpi.png")),
|
||||
Act = () =>
|
||||
{
|
||||
RemComp(args.Target, anchor);
|
||||
@@ -236,7 +237,7 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Refill Internals Oxygen",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Objects/Tanks/oxygen.rsi"), "icon"),
|
||||
Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Tanks/oxygen.rsi"), "icon"),
|
||||
Act = () =>
|
||||
{
|
||||
RefillGasTank(args.Target, Gas.Oxygen, tank);
|
||||
@@ -251,7 +252,7 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Refill Internals Nitrogen",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Objects/Tanks/red.rsi"), "icon"),
|
||||
Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Tanks/red.rsi"), "icon"),
|
||||
Act = () =>
|
||||
{
|
||||
RefillGasTank(args.Target, Gas.Nitrogen, tank);
|
||||
@@ -266,7 +267,7 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Refill Internals Plasma",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Objects/Tanks/plasma.rsi"), "icon"),
|
||||
Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Tanks/plasma.rsi"), "icon"),
|
||||
Act = () =>
|
||||
{
|
||||
RefillGasTank(args.Target, Gas.Plasma, tank);
|
||||
@@ -284,7 +285,7 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Refill Internals Oxygen",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Objects/Tanks/oxygen.rsi"), "icon"),
|
||||
Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Tanks/oxygen.rsi"), "icon"),
|
||||
Act = () =>
|
||||
{
|
||||
foreach (var slot in _inventorySystem.GetSlots(args.Target))
|
||||
@@ -316,7 +317,7 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Refill Internals Nitrogen",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Objects/Tanks/red.rsi"), "icon"),
|
||||
Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Tanks/red.rsi"), "icon"),
|
||||
Act = () =>
|
||||
{
|
||||
foreach (var slot in _inventorySystem.GetSlots(args.Target))
|
||||
@@ -348,7 +349,7 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Refill Internals Plasma",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Objects/Tanks/plasma.rsi"), "icon"),
|
||||
Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Tanks/plasma.rsi"), "icon"),
|
||||
Act = () =>
|
||||
{
|
||||
foreach (var slot in _inventorySystem.GetSlots(args.Target))
|
||||
@@ -381,12 +382,12 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Send to test arena",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/VerbIcons/eject.svg.192dpi.png")),
|
||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/eject.svg.192dpi.png")),
|
||||
|
||||
Act = () =>
|
||||
{
|
||||
var (mapUid, gridUid) = _adminTestArenaSystem.AssertArenaLoaded(player);
|
||||
Transform(args.Target).Coordinates = new EntityCoordinates(gridUid ?? mapUid, Vector2.One);
|
||||
_xformSystem.SetCoordinates(args.Target, new EntityCoordinates(gridUid ?? mapUid, Vector2.One));
|
||||
},
|
||||
Impact = LogImpact.Medium,
|
||||
Message = Loc.GetString("admin-trick-send-to-test-arena-description"),
|
||||
@@ -402,7 +403,7 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Grant All Access",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Objects/Misc/id_cards.rsi"), "centcom"),
|
||||
Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Misc/id_cards.rsi"), "centcom"),
|
||||
Act = () =>
|
||||
{
|
||||
GiveAllAccess(activeId.Value);
|
||||
@@ -417,7 +418,7 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Revoke All Access",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Objects/Misc/id_cards.rsi"), "default"),
|
||||
Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Misc/id_cards.rsi"), "default"),
|
||||
Act = () =>
|
||||
{
|
||||
RevokeAllAccess(activeId.Value);
|
||||
@@ -435,7 +436,7 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Grant All Access",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Objects/Misc/id_cards.rsi"), "centcom"),
|
||||
Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Misc/id_cards.rsi"), "centcom"),
|
||||
Act = () =>
|
||||
{
|
||||
GiveAllAccess(args.Target);
|
||||
@@ -450,7 +451,7 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Revoke All Access",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Objects/Misc/id_cards.rsi"), "default"),
|
||||
Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Misc/id_cards.rsi"), "default"),
|
||||
Act = () =>
|
||||
{
|
||||
RevokeAllAccess(args.Target);
|
||||
@@ -469,7 +470,7 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Adjust Stack",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/AdminActions/adjust-stack.png")),
|
||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/adjust-stack.png")),
|
||||
Act = () =>
|
||||
{
|
||||
// Unbounded intentionally.
|
||||
@@ -488,7 +489,7 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Fill Stack",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/AdminActions/fill-stack.png")),
|
||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/fill-stack.png")),
|
||||
Act = () =>
|
||||
{
|
||||
_stackSystem.SetCount(args.Target, _stackSystem.GetMaxCount(stack), stack);
|
||||
@@ -504,12 +505,12 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Rename",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/AdminActions/rename.png")),
|
||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/rename.png")),
|
||||
Act = () =>
|
||||
{
|
||||
_quickDialog.OpenDialog(player, "Rename", "Name", (string newName) =>
|
||||
{
|
||||
MetaData(args.Target).EntityName = newName;
|
||||
_metaSystem.SetEntityName(args.Target, newName);
|
||||
});
|
||||
},
|
||||
Impact = LogImpact.Medium,
|
||||
@@ -522,12 +523,12 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Redescribe",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/AdminActions/redescribe.png")),
|
||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/redescribe.png")),
|
||||
Act = () =>
|
||||
{
|
||||
_quickDialog.OpenDialog(player, "Redescribe", "Description", (LongString newDescription) =>
|
||||
{
|
||||
MetaData(args.Target).EntityDescription = newDescription.String;
|
||||
_metaSystem.SetEntityDescription(args.Target, newDescription.String);
|
||||
});
|
||||
},
|
||||
Impact = LogImpact.Medium,
|
||||
@@ -540,15 +541,15 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Redescribe",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/AdminActions/rename_and_redescribe.png")),
|
||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/rename_and_redescribe.png")),
|
||||
Act = () =>
|
||||
{
|
||||
_quickDialog.OpenDialog(player, "Rename & Redescribe", "Name", "Description",
|
||||
(string newName, LongString newDescription) =>
|
||||
{
|
||||
var meta = MetaData(args.Target);
|
||||
meta.EntityName = newName;
|
||||
meta.EntityDescription = newDescription.String;
|
||||
_metaSystem.SetEntityName(args.Target, newName, meta);
|
||||
_metaSystem.SetEntityDescription(args.Target, newDescription.String, meta);
|
||||
});
|
||||
},
|
||||
Impact = LogImpact.Medium,
|
||||
@@ -565,7 +566,7 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Bar job slots",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/AdminActions/bar_jobslots.png")),
|
||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/bar_jobslots.png")),
|
||||
Act = () =>
|
||||
{
|
||||
foreach (var (job, _) in _stationJobsSystem.GetJobs(args.Target))
|
||||
@@ -584,7 +585,7 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Locate Cargo Shuttle",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Clothing/Head/Soft/cargosoft.rsi"), "icon"),
|
||||
Icon = new SpriteSpecifier.Rsi(new("/Textures/Clothing/Head/Soft/cargosoft.rsi"), "icon"),
|
||||
Act = () =>
|
||||
{
|
||||
var shuttle = Comp<StationCargoOrderDatabaseComponent>(args.Target).Shuttle;
|
||||
@@ -592,7 +593,7 @@ public sealed partial class AdminVerbSystem
|
||||
if (shuttle is null)
|
||||
return;
|
||||
|
||||
Transform(args.User).Coordinates = new EntityCoordinates(shuttle.Value, Vector2.Zero);
|
||||
_xformSystem.SetCoordinates(args.User, new EntityCoordinates(shuttle.Value, Vector2.Zero));
|
||||
},
|
||||
Impact = LogImpact.Low,
|
||||
Message = Loc.GetString("admin-trick-locate-cargo-shuttle-description"),
|
||||
@@ -607,7 +608,7 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Refill Battery",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/AdminActions/fill_battery.png")),
|
||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/fill_battery.png")),
|
||||
Act = () =>
|
||||
{
|
||||
foreach (var ent in childEnum)
|
||||
@@ -615,8 +616,8 @@ public sealed partial class AdminVerbSystem
|
||||
if (!HasComp<StationInfiniteBatteryTargetComponent>(ent))
|
||||
continue;
|
||||
var battery = EnsureComp<BatteryComponent>(ent);
|
||||
battery.CurrentCharge = battery.MaxCharge;
|
||||
Dirty(battery);
|
||||
_batterySystem.SetCharge(ent, battery.MaxCharge, battery);
|
||||
Dirty(ent, battery);
|
||||
}
|
||||
},
|
||||
Impact = LogImpact.Extreme,
|
||||
@@ -629,7 +630,7 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Drain Battery",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/AdminActions/drain_battery.png")),
|
||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/drain_battery.png")),
|
||||
Act = () =>
|
||||
{
|
||||
foreach (var ent in childEnum)
|
||||
@@ -637,8 +638,8 @@ public sealed partial class AdminVerbSystem
|
||||
if (!HasComp<StationInfiniteBatteryTargetComponent>(ent))
|
||||
continue;
|
||||
var battery = EnsureComp<BatteryComponent>(ent);
|
||||
battery.CurrentCharge = 0;
|
||||
Dirty(battery);
|
||||
_batterySystem.SetCharge(ent, 0, battery);
|
||||
Dirty(ent, battery);
|
||||
}
|
||||
},
|
||||
Impact = LogImpact.Extreme,
|
||||
@@ -651,7 +652,7 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Infinite Battery",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/AdminActions/infinite_battery.png")),
|
||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/infinite_battery.png")),
|
||||
Act = () =>
|
||||
{
|
||||
// this kills the sloth
|
||||
@@ -680,7 +681,7 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Halt Movement",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/AdminActions/halt.png")),
|
||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/halt.png")),
|
||||
Act = () =>
|
||||
{
|
||||
_physics.SetLinearVelocity(args.Target, Vector2.Zero, body: physics);
|
||||
@@ -703,7 +704,7 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Unpause Map",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/AdminActions/play.png")),
|
||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/play.png")),
|
||||
Act = () =>
|
||||
{
|
||||
_mapManager.SetMapPaused(map.MapId, false);
|
||||
@@ -720,7 +721,7 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Pause Map",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/AdminActions/pause.png")),
|
||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/pause.png")),
|
||||
Act = () =>
|
||||
{
|
||||
_mapManager.SetMapPaused(map.MapId, true);
|
||||
@@ -740,10 +741,10 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Snap Joints",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/AdminActions/snap_joints.png")),
|
||||
Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/snap_joints.png")),
|
||||
Act = () =>
|
||||
{
|
||||
_jointSystem.ClearJoints(joints);
|
||||
_jointSystem.ClearJoints(args.Target, joints);
|
||||
},
|
||||
Impact = LogImpact.Medium,
|
||||
Message = Loc.GetString("admin-trick-snap-joints-description"),
|
||||
@@ -758,7 +759,7 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Make Minigun",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Objects/Weapons/Guns/HMGs/minigun.rsi"), "icon"),
|
||||
Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Weapons/Guns/HMGs/minigun.rsi"), "icon"),
|
||||
Act = () =>
|
||||
{
|
||||
gun.FireRate = 15;
|
||||
@@ -776,7 +777,7 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "Set Bullet Amount",
|
||||
Category = VerbCategory.Tricks,
|
||||
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Objects/Fun/caps.rsi"), "mag-6"),
|
||||
Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Fun/caps.rsi"), "mag-6"),
|
||||
Act = () =>
|
||||
{
|
||||
_quickDialog.OpenDialog(player, "Set Bullet Amount", $"Amount (max {ballisticAmmo.Capacity}):", (int amount) =>
|
||||
@@ -858,12 +859,10 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
return slotEntity.Value;
|
||||
}
|
||||
else if (TryComp<PdaComponent>(slotEntity, out var pda))
|
||||
else if (TryComp<PdaComponent>(slotEntity, out var pda)
|
||||
&& HasComp<IdCardComponent>(pda.ContainedId))
|
||||
{
|
||||
if (pda.ContainedId != null)
|
||||
{
|
||||
return pda.ContainedId.Owner;
|
||||
}
|
||||
return pda.ContainedId;
|
||||
}
|
||||
}
|
||||
else if (TryComp<HandsComponent>(target, out var hands))
|
||||
@@ -891,40 +890,40 @@ public sealed partial class AdminVerbSystem
|
||||
|
||||
private void RevokeAllAccess(EntityUid entity)
|
||||
{
|
||||
_accessSystem.TrySetTags(entity, new string[]{});
|
||||
_accessSystem.TrySetTags(entity, Array.Empty<string>());
|
||||
}
|
||||
|
||||
public enum TricksVerbPriorities
|
||||
{
|
||||
Bolt = 0,
|
||||
Unbolt = 0,
|
||||
EmergencyAccessOn = -1, // These are separate intentionally for `invokeverb` shenanigans.
|
||||
EmergencyAccessOff = -1,
|
||||
MakeIndestructible = -2,
|
||||
MakeVulnerable = -2,
|
||||
BlockUnanchoring = -3,
|
||||
RefillBattery = -4,
|
||||
DrainBattery = -5,
|
||||
RefillOxygen = -6,
|
||||
RefillNitrogen = -7,
|
||||
RefillPlasma = -8,
|
||||
SendToTestArena = -9,
|
||||
GrantAllAccess = -10,
|
||||
RevokeAllAccess = -11,
|
||||
Rejuvenate = -12,
|
||||
AdjustStack = -13,
|
||||
FillStack = -14,
|
||||
Rename = -15,
|
||||
Redescribe = -16,
|
||||
RenameAndRedescribe = -17,
|
||||
BarJobSlots = -18,
|
||||
LocateCargoShuttle = -19,
|
||||
InfiniteBattery = -20,
|
||||
HaltMovement = -21,
|
||||
Unpause = -22,
|
||||
Pause = -23,
|
||||
SnapJoints = -24,
|
||||
MakeMinigun = -25,
|
||||
SetBulletAmount = -26,
|
||||
Unbolt = -1,
|
||||
EmergencyAccessOn = -2,
|
||||
EmergencyAccessOff = -3,
|
||||
MakeIndestructible = -4,
|
||||
MakeVulnerable = -5,
|
||||
BlockUnanchoring = -6,
|
||||
RefillBattery = -7,
|
||||
DrainBattery = -8,
|
||||
RefillOxygen = -9,
|
||||
RefillNitrogen = -10,
|
||||
RefillPlasma = -11,
|
||||
SendToTestArena = -12,
|
||||
GrantAllAccess = -13,
|
||||
RevokeAllAccess = -14,
|
||||
Rejuvenate = -15,
|
||||
AdjustStack = -16,
|
||||
FillStack = -17,
|
||||
Rename = -18,
|
||||
Redescribe = -19,
|
||||
RenameAndRedescribe = -20,
|
||||
BarJobSlots = -21,
|
||||
LocateCargoShuttle = -22,
|
||||
InfiniteBattery = -23,
|
||||
HaltMovement = -24,
|
||||
Unpause = -25,
|
||||
Pause = -26,
|
||||
SnapJoints = -27,
|
||||
MakeMinigun = -28,
|
||||
SetBulletAmount = -29,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="JetBrains.Annotations" Version="2022.1.0" PrivateAssets="All" />
|
||||
<PackageReference Include="System.Linq.Async" Version="6.0.1" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Content.Packaging\Content.Packaging.csproj" />
|
||||
|
||||
@@ -1312,70 +1312,67 @@ INSERT INTO player_round (players_id, rounds_id) VALUES ({players[player]}, {id}
|
||||
// You can't group queries, as player will not always exist. When it doesn't, the
|
||||
// whole query returns nothing
|
||||
var player = await db.DbContext.Player.SingleOrDefaultAsync(p => p.UserId == user);
|
||||
return await (from ban in db.DbContext.Ban
|
||||
where ban.PlayerUserId == user &&
|
||||
!ban.Hidden
|
||||
select ban)
|
||||
var bans = await db.DbContext.Ban
|
||||
.Where(ban => ban.PlayerUserId == user && !ban.Hidden)
|
||||
.Include(ban => ban.Unban)
|
||||
.Include(ban => ban.Round)
|
||||
.ThenInclude(r => r!.Server)
|
||||
.Include(ban => ban.CreatedBy)
|
||||
.Include(ban => ban.LastEditedBy)
|
||||
.Include(ban => ban.Unban)
|
||||
.ToAsyncEnumerable()
|
||||
.SelectAwait(async ban =>
|
||||
new ServerBanNote(ban.Id, ban.RoundId, ban.Round, ban.PlayerUserId, player,
|
||||
ban.PlaytimeAtNote, ban.Reason, ban.Severity, ban.CreatedBy, ban.BanTime,
|
||||
ban.LastEditedBy, ban.LastEditedAt, ban.ExpirationTime, ban.Hidden,
|
||||
ban.Unban?.UnbanningAdmin == null
|
||||
? null
|
||||
: await db.DbContext.Player.SingleOrDefaultAsync(p => p.UserId == ban.Unban.UnbanningAdmin.Value),
|
||||
ban.Unban?.UnbanTime)
|
||||
).ToListAsync();
|
||||
.ToArrayAsync();
|
||||
|
||||
var banNotes = new List<ServerBanNote>();
|
||||
foreach (var ban in bans)
|
||||
{
|
||||
var banNote = new ServerBanNote(ban.Id, ban.RoundId, ban.Round, ban.PlayerUserId, player,
|
||||
ban.PlaytimeAtNote, ban.Reason, ban.Severity, ban.CreatedBy, ban.BanTime,
|
||||
ban.LastEditedBy, ban.LastEditedAt, ban.ExpirationTime, ban.Hidden,
|
||||
ban.Unban?.UnbanningAdmin == null
|
||||
? null
|
||||
: await db.DbContext.Player.SingleOrDefaultAsync(
|
||||
p => p.UserId == ban.Unban.UnbanningAdmin.Value),
|
||||
ban.Unban?.UnbanTime);
|
||||
|
||||
banNotes.Add(banNote);
|
||||
}
|
||||
|
||||
return banNotes;
|
||||
}
|
||||
|
||||
protected async Task<List<ServerRoleBanNote>> GetGroupedServerRoleBansAsNotesForUser(DbGuard db, Guid user)
|
||||
{
|
||||
// Server side query
|
||||
var bansQuery =
|
||||
(from ban in db.DbContext.RoleBan
|
||||
where ban.PlayerUserId == user &&
|
||||
!ban.Hidden
|
||||
select ban)
|
||||
var bansQuery = await db.DbContext.RoleBan
|
||||
.Where(ban => ban.PlayerUserId == user && !ban.Hidden)
|
||||
.Include(ban => ban.Unban)
|
||||
.Include(ban => ban.Round)
|
||||
.ThenInclude(r => r!.Server)
|
||||
.Include(ban => ban.CreatedBy)
|
||||
.Include(ban => ban.LastEditedBy)
|
||||
.Include(ban => ban.Unban)
|
||||
.ToAsyncEnumerable();
|
||||
.ToArrayAsync();
|
||||
|
||||
// Client side query, as EF can't do groups yet
|
||||
var bansEnumerable =
|
||||
(from ban in bansQuery
|
||||
group ban by new
|
||||
{
|
||||
ban.BanTime,
|
||||
ban.CreatedBy,
|
||||
ban.Reason,
|
||||
Unbanned = ban.Unban == null
|
||||
}
|
||||
into banGroup
|
||||
select banGroup)
|
||||
.AsAsyncEnumerable();
|
||||
var bansEnumerable = bansQuery
|
||||
.GroupBy(ban => new { ban.BanTime, CreatedBy = (Player?)ban.CreatedBy, ban.Reason, Unbanned = ban.Unban == null })
|
||||
.Select(banGroup => banGroup)
|
||||
.ToArray();
|
||||
|
||||
List<ServerRoleBanNote> bans = new();
|
||||
var player = await db.DbContext.Player.SingleOrDefaultAsync(p => p.UserId == user);
|
||||
await foreach (var banGroup in bansEnumerable)
|
||||
foreach (var banGroup in bansEnumerable)
|
||||
{
|
||||
var firstBan = await banGroup.FirstAsync();
|
||||
var firstBan = banGroup.First();
|
||||
Player? unbanningAdmin = null;
|
||||
|
||||
if (firstBan.Unban?.UnbanningAdmin is not null)
|
||||
unbanningAdmin = await db.DbContext.Player.SingleOrDefaultAsync(p => p.UserId == firstBan.Unban.UnbanningAdmin.Value);
|
||||
|
||||
bans.Add(new ServerRoleBanNote(firstBan.Id, firstBan.RoundId, firstBan.Round, firstBan.PlayerUserId,
|
||||
player, firstBan.PlaytimeAtNote, firstBan.Reason, firstBan.Severity, firstBan.CreatedBy,
|
||||
firstBan.BanTime, firstBan.LastEditedBy, firstBan.LastEditedAt, firstBan.ExpirationTime,
|
||||
firstBan.Hidden, await banGroup.Select(ban => ban.RoleId.Replace(BanManager.JobPrefix, null)).ToArrayAsync(),
|
||||
firstBan.Hidden, banGroup.Select(ban => ban.RoleId.Replace(BanManager.JobPrefix, null)).ToArray(),
|
||||
unbanningAdmin, firstBan.Unban?.UnbanTime));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,18 +1,10 @@
|
||||
using System.Numerics;
|
||||
|
||||
namespace Content.Server.Movement.Components
|
||||
namespace Content.Server.Movement.Components;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed class StressTestMovementComponent : Component
|
||||
{
|
||||
[RegisterComponent]
|
||||
public sealed class StressTestMovementComponent : Component
|
||||
{
|
||||
public float Progress { get; set; }
|
||||
public Vector2 Origin { get; set; }
|
||||
|
||||
protected override void Startup()
|
||||
{
|
||||
base.Startup();
|
||||
|
||||
Origin = IoCManager.Resolve<IEntityManager>().GetComponent<TransformComponent>(Owner).WorldPosition;
|
||||
}
|
||||
}
|
||||
public float Progress { get; set; }
|
||||
public Vector2 Origin { get; set; }
|
||||
}
|
||||
|
||||
@@ -1,32 +1,42 @@
|
||||
using System.Numerics;
|
||||
using Content.Server.Movement.Components;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Content.Server.Movement
|
||||
namespace Content.Server.Movement;
|
||||
|
||||
public sealed class StressTestMovementSystem : EntitySystem
|
||||
{
|
||||
[UsedImplicitly]
|
||||
internal sealed class StressTestMovementSystem : EntitySystem
|
||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
public override void Update(float frameTime)
|
||||
base.Initialize();
|
||||
SubscribeLocalEvent<StressTestMovementComponent, ComponentStartup>(OnStressStartup);
|
||||
}
|
||||
|
||||
private void OnStressStartup(EntityUid uid, StressTestMovementComponent component, ComponentStartup args)
|
||||
{
|
||||
component.Origin = _transform.GetWorldPosition(uid);
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
var query = EntityQueryEnumerator<StressTestMovementComponent, TransformComponent>();
|
||||
|
||||
while (query.MoveNext(out var uid, out var stressTest, out var transform))
|
||||
{
|
||||
base.Update(frameTime);
|
||||
stressTest.Progress += frameTime;
|
||||
|
||||
foreach (var stressTest in EntityManager.EntityQuery<StressTestMovementComponent>(true))
|
||||
if (stressTest.Progress > 1)
|
||||
{
|
||||
var transform = EntityManager.GetComponent<TransformComponent>(stressTest.Owner);
|
||||
|
||||
stressTest.Progress += frameTime;
|
||||
|
||||
if (stressTest.Progress > 1)
|
||||
{
|
||||
stressTest.Progress -= 1;
|
||||
}
|
||||
|
||||
var x = MathF.Sin(stressTest.Progress * MathHelper.TwoPi);
|
||||
var y = MathF.Cos(stressTest.Progress * MathHelper.TwoPi);
|
||||
|
||||
transform.WorldPosition = stressTest.Origin + (new Vector2(x, y) * 5);
|
||||
stressTest.Progress -= 1;
|
||||
}
|
||||
|
||||
var x = MathF.Sin(stressTest.Progress * MathHelper.TwoPi);
|
||||
var y = MathF.Cos(stressTest.Progress * MathHelper.TwoPi);
|
||||
|
||||
_transform.SetWorldPosition(transform, stressTest.Origin + new Vector2(x, y) * 5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,38 +12,40 @@ public sealed class JetpackSystem : SharedJetpackSystem
|
||||
[Dependency] private readonly GasTankSystem _gasTank = default!;
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
|
||||
private const float UpdateCooldown = 0.5f;
|
||||
|
||||
protected override bool CanEnable(JetpackComponent component)
|
||||
protected override bool CanEnable(EntityUid uid, JetpackComponent component)
|
||||
{
|
||||
return base.CanEnable(component) && TryComp<GasTankComponent>(component.Owner, out var gasTank) && !(gasTank.Air.TotalMoles < component.MoleUsage);
|
||||
return base.CanEnable(uid, component) &&
|
||||
TryComp<GasTankComponent>(uid, out var gasTank) &&
|
||||
!(gasTank.Air.TotalMoles < component.MoleUsage);
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
var toDisable = new ValueList<JetpackComponent>();
|
||||
var toDisable = new ValueList<(EntityUid Uid, JetpackComponent Component)>();
|
||||
var query = EntityQueryEnumerator<ActiveJetpackComponent, JetpackComponent, GasTankComponent>();
|
||||
|
||||
foreach (var (active, comp, gasTank) in EntityQuery<ActiveJetpackComponent, JetpackComponent, GasTankComponent>())
|
||||
while (query.MoveNext(out var uid, out var active, out var comp, out var gasTank))
|
||||
{
|
||||
if (_timing.CurTime < active.TargetTime) continue;
|
||||
if (_timing.CurTime < active.TargetTime)
|
||||
continue;
|
||||
|
||||
active.TargetTime = _timing.CurTime + TimeSpan.FromSeconds(active.EffectCooldown);
|
||||
var air = _gasTank.RemoveAir(gasTank, comp.MoleUsage);
|
||||
|
||||
if (air == null || !MathHelper.CloseTo(air.TotalMoles, comp.MoleUsage, 0.001f))
|
||||
{
|
||||
toDisable.Add(comp);
|
||||
toDisable.Add((uid, comp));
|
||||
continue;
|
||||
}
|
||||
|
||||
_gasTank.UpdateUserInterface(gasTank);
|
||||
}
|
||||
|
||||
foreach (var comp in toDisable)
|
||||
foreach (var (uid, comp) in toDisable)
|
||||
{
|
||||
SetEnabled(comp, false);
|
||||
SetEnabled(uid, comp, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ using Content.Server.PDA.Ringer;
|
||||
using Content.Server.Station.Systems;
|
||||
using Content.Server.Store.Components;
|
||||
using Content.Server.Store.Systems;
|
||||
using Content.Shared.Access.Components;
|
||||
using Content.Shared.PDA;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Server.Player;
|
||||
@@ -117,14 +118,15 @@ namespace Content.Server.PDA
|
||||
// TODO: Update the level and name of the station with each call to UpdatePdaUi is only needed for latejoin players.
|
||||
// TODO: If someone can implement changing the level and name of the station when changing the PDA grid, this can be removed.
|
||||
|
||||
var id = CompOrNull<IdCardComponent>(pda.ContainedId);
|
||||
var state = new PdaUpdateState(
|
||||
pda.FlashlightOn,
|
||||
pda.PenSlot.HasItem,
|
||||
new PdaIdInfoText
|
||||
{
|
||||
ActualOwnerName = pda.OwnerName,
|
||||
IdOwner = pda.ContainedId?.FullName,
|
||||
JobTitle = pda.ContainedId?.JobTitle,
|
||||
IdOwner = id?.FullName,
|
||||
JobTitle = id?.JobTitle,
|
||||
StationAlertLevel = pda.StationAlertLevel,
|
||||
StationAlertColor = pda.StationAlertColor
|
||||
},
|
||||
|
||||
@@ -93,7 +93,7 @@ namespace Content.Server.Sandbox
|
||||
if (e.NewStatus != SessionStatus.Connected || e.OldStatus != SessionStatus.Connecting)
|
||||
return;
|
||||
|
||||
RaiseNetworkEvent(new MsgSandboxStatus {SandboxAllowed = IsSandboxEnabled}, e.Session.ConnectedClient);
|
||||
RaiseNetworkEvent(new MsgSandboxStatus { SandboxAllowed = IsSandboxEnabled }, e.Session.ConnectedClient);
|
||||
}
|
||||
|
||||
private void SandboxRespawnReceived(MsgSandboxRespawn message, EntitySessionEventArgs args)
|
||||
@@ -113,7 +113,7 @@ namespace Content.Server.Sandbox
|
||||
return;
|
||||
|
||||
var player = _playerManager.GetSessionByChannel(args.SenderSession.ConnectedClient);
|
||||
if (player.AttachedEntity is not {} attached)
|
||||
if (player.AttachedEntity is not { } attached)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -130,17 +130,17 @@ namespace Content.Server.Sandbox
|
||||
}
|
||||
else if (TryComp<PdaComponent>(slotEntity, out var pda))
|
||||
{
|
||||
if (pda.ContainedId == null)
|
||||
if (pda.ContainedId is null)
|
||||
{
|
||||
var newID = CreateFreshId();
|
||||
if (TryComp<ItemSlotsComponent>(pda.Owner, out var itemSlots))
|
||||
if (TryComp<ItemSlotsComponent>(slotEntity, out var itemSlots))
|
||||
{
|
||||
_slots.TryInsert(slotEntity.Value, pda.IdSlot, newID, null);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UpgradeId(pda.ContainedId.Owner);
|
||||
UpgradeId(pda.ContainedId!.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -189,7 +189,7 @@ namespace Content.Server.Sandbox
|
||||
|
||||
private void UpdateSandboxStatusForAll()
|
||||
{
|
||||
RaiseNetworkEvent(new MsgSandboxStatus {SandboxAllowed = IsSandboxEnabled});
|
||||
RaiseNetworkEvent(new MsgSandboxStatus { SandboxAllowed = IsSandboxEnabled });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ using Content.Server.Mind.Commands;
|
||||
using Content.Server.PDA;
|
||||
using Content.Server.Roles;
|
||||
using Content.Server.Station.Components;
|
||||
using Content.Shared.Access.Components;
|
||||
using Content.Shared.Access.Systems;
|
||||
using Content.Shared.CCVar;
|
||||
using Content.Shared.Hands.Components;
|
||||
@@ -44,6 +45,7 @@ public sealed class StationSpawningSystem : EntitySystem
|
||||
[Dependency] private readonly PdaSystem _pdaSystem = default!;
|
||||
[Dependency] private readonly SharedAccessSystem _accessSystem = default!;
|
||||
[Dependency] private readonly IdentitySystem _identity = default!;
|
||||
[Dependency] private readonly MetaDataSystem _metaSystem = default!;
|
||||
|
||||
private bool _randomizeCharacters;
|
||||
|
||||
@@ -73,7 +75,7 @@ public sealed class StationSpawningSystem : EntitySystem
|
||||
var ev = new PlayerSpawningEvent(job, profile, station);
|
||||
RaiseLocalEvent(ev);
|
||||
|
||||
DebugTools.Assert(ev.SpawnResult is {Valid: true} or null);
|
||||
DebugTools.Assert(ev.SpawnResult is { Valid: true } or null);
|
||||
|
||||
return ev.SpawnResult;
|
||||
}
|
||||
@@ -146,7 +148,7 @@ public sealed class StationSpawningSystem : EntitySystem
|
||||
if (profile != null)
|
||||
{
|
||||
_humanoidSystem.LoadProfile(entity.Value, profile);
|
||||
MetaData(entity.Value).EntityName = profile.Name;
|
||||
_metaSystem.SetEntityName(entity.Value, profile.Name);
|
||||
if (profile.FlavorText != "" && _configurationManager.GetCVar(CCVars.FlavorText))
|
||||
{
|
||||
AddComp<DetailExaminableComponent>(entity.Value).Content = profile.FlavorText;
|
||||
@@ -158,7 +160,7 @@ public sealed class StationSpawningSystem : EntitySystem
|
||||
return entity.Value;
|
||||
}
|
||||
|
||||
private void DoJobSpecials(Job? job, EntityUid entity)
|
||||
private static void DoJobSpecials(Job? job, EntityUid entity)
|
||||
{
|
||||
foreach (var jobSpecial in job?.Prototype.Special ?? Array.Empty<JobSpecial>())
|
||||
{
|
||||
@@ -211,11 +213,10 @@ public sealed class StationSpawningSystem : EntitySystem
|
||||
if (!_inventorySystem.TryGetSlotEntity(entity, "id", out var idUid))
|
||||
return;
|
||||
|
||||
if (!EntityManager.TryGetComponent(idUid, out PdaComponent? pdaComponent) || pdaComponent.ContainedId == null)
|
||||
if (!EntityManager.TryGetComponent(idUid, out PdaComponent? pdaComponent) || !TryComp<IdCardComponent>(pdaComponent.ContainedId, out var card))
|
||||
return;
|
||||
|
||||
var card = pdaComponent.ContainedId;
|
||||
var cardId = card.Owner;
|
||||
var cardId = pdaComponent.ContainedId.Value;
|
||||
_cardSystem.TryChangeFullName(cardId, characterName, card);
|
||||
_cardSystem.TryChangeJobTitle(cardId, jobPrototype.LocalizedName, card);
|
||||
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
using System.Linq;
|
||||
using Content.Server.Anomaly;
|
||||
using Content.Server.Anomaly;
|
||||
using Content.Server.GameTicking.Rules.Components;
|
||||
using Content.Server.Station.Components;
|
||||
using Content.Server.StationEvents.Components;
|
||||
using Robust.Shared.Random;
|
||||
|
||||
namespace Content.Server.StationEvents.Events;
|
||||
|
||||
@@ -30,13 +28,9 @@ public sealed class AnomalySpawnRule : StationEventSystem<AnomalySpawnRuleCompon
|
||||
if (!TryComp<StationDataComponent>(chosenStation, out var stationData))
|
||||
return;
|
||||
|
||||
EntityUid? grid = null;
|
||||
foreach (var g in stationData.Grids.Where(HasComp<BecomesStationComponent>))
|
||||
{
|
||||
grid = g;
|
||||
}
|
||||
var grid = StationSystem.GetLargestGrid(stationData);
|
||||
|
||||
if (grid is not { })
|
||||
if (grid is null)
|
||||
return;
|
||||
|
||||
var amountToSpawn = Math.Max(1, (int) MathF.Round(GetSeverityModifier() / 2));
|
||||
|
||||
@@ -59,7 +59,7 @@ public sealed class StationRecordsSystem : EntitySystem
|
||||
string? jobId, StationRecordsComponent? records = null)
|
||||
{
|
||||
if (!Resolve(station, ref records)
|
||||
|| String.IsNullOrEmpty(jobId)
|
||||
|| string.IsNullOrEmpty(jobId)
|
||||
|| !_prototypeManager.HasIndex<JobPrototype>(jobId))
|
||||
{
|
||||
return;
|
||||
@@ -204,7 +204,7 @@ public sealed class StationRecordsSystem : EntitySystem
|
||||
{
|
||||
if (!Resolve(station, ref records))
|
||||
{
|
||||
return new (StationRecordKey, T)[]{};
|
||||
return Array.Empty<(StationRecordKey, T)>();
|
||||
}
|
||||
|
||||
return records.Records.GetRecordsOfType<T>();
|
||||
|
||||
@@ -50,12 +50,13 @@ namespace Content.Server.Tabletop
|
||||
|
||||
TabletopMap = _mapManager.CreateMap();
|
||||
_tabletops = 0;
|
||||
var mapUid = _mapManager.GetMapEntityId(TabletopMap);
|
||||
|
||||
var mapComp = EntityManager.GetComponent<MapComponent>(_mapManager.GetMapEntityId(TabletopMap));
|
||||
var mapComp = EntityManager.GetComponent<MapComponent>(mapUid);
|
||||
|
||||
// Lighting is always disabled in tabletop world.
|
||||
mapComp.LightingEnabled = false;
|
||||
mapComp.Dirty();
|
||||
Dirty(mapUid, mapComp);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace Content.Server.Verbs.Commands
|
||||
}
|
||||
|
||||
var entityManager = IoCManager.Resolve<IEntityManager>();
|
||||
var verbSystem = EntitySystem.Get<SharedVerbSystem>();
|
||||
var verbSystem = entityManager.System<SharedVerbSystem>();
|
||||
|
||||
// get the 'player' entity (defaulting to command user, otherwise uses a uid)
|
||||
EntityUid? playerEntity = null;
|
||||
|
||||
@@ -14,6 +14,6 @@ public sealed class AccessGroupPrototype : IPrototype
|
||||
[IdDataField]
|
||||
public string ID { get; } = default!;
|
||||
|
||||
[DataField("tags", required: true, customTypeSerializer:typeof(PrototypeIdHashSetSerializer<AccessLevelPrototype>))]
|
||||
[DataField("tags", required: true, customTypeSerializer: typeof(PrototypeIdHashSetSerializer<AccessLevelPrototype>))]
|
||||
public HashSet<string> Tags = default!;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using Content.Shared.Access.Systems;
|
||||
using Content.Shared.StationRecords;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Serialization;
|
||||
@@ -59,4 +58,3 @@ public sealed class AccessReaderComponentState : ComponentState
|
||||
AccessKeys = accessKeys;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using Content.Shared.Access.Systems;
|
||||
using Content.Shared.PDA;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.Access.Components
|
||||
{
|
||||
@@ -17,8 +16,7 @@ namespace Content.Shared.Access.Components
|
||||
|
||||
[DataField("jobTitle")]
|
||||
[AutoNetworkedField]
|
||||
[Access(typeof(SharedIdCardSystem), typeof(SharedPdaSystem), typeof(SharedAgentIdCardSystem),
|
||||
Other = AccessPermissions.ReadWrite)]
|
||||
[Access(typeof(SharedIdCardSystem), typeof(SharedPdaSystem), typeof(SharedAgentIdCardSystem), Other = AccessPermissions.ReadWrite)]
|
||||
public string? JobTitle;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,6 +48,7 @@ namespace Content.Shared.Access.Systems
|
||||
public sealed class AgentIDCardJobChangedMessage : BoundUserInterfaceMessage
|
||||
{
|
||||
public string Job { get; }
|
||||
|
||||
public AgentIDCardJobChangedMessage(string job)
|
||||
{
|
||||
Job = job;
|
||||
|
||||
@@ -11,286 +11,272 @@ using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.StationRecords;
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared.Access.Systems
|
||||
namespace Content.Shared.Access.Systems;
|
||||
|
||||
public sealed class AccessReaderSystem : EntitySystem
|
||||
{
|
||||
public sealed class AccessReaderSystem : EntitySystem
|
||||
[Dependency] private readonly InventorySystem _inventorySystem = default!;
|
||||
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
[Dependency] private readonly InventorySystem _inventorySystem = default!;
|
||||
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||
base.Initialize();
|
||||
|
||||
public override void Initialize()
|
||||
SubscribeLocalEvent<AccessReaderComponent, GotEmaggedEvent>(OnEmagged);
|
||||
SubscribeLocalEvent<AccessReaderComponent, LinkAttemptEvent>(OnLinkAttempt);
|
||||
|
||||
SubscribeLocalEvent<AccessReaderComponent, ComponentGetState>(OnGetState);
|
||||
SubscribeLocalEvent<AccessReaderComponent, ComponentHandleState>(OnHandleState);
|
||||
}
|
||||
|
||||
private void OnGetState(EntityUid uid, AccessReaderComponent component, ref ComponentGetState args)
|
||||
{
|
||||
args.State = new AccessReaderComponentState(component.Enabled, component.DenyTags, component.AccessLists,
|
||||
component.AccessKeys);
|
||||
}
|
||||
|
||||
private void OnHandleState(EntityUid uid, AccessReaderComponent component, ref ComponentHandleState args)
|
||||
{
|
||||
if (args.Current is not AccessReaderComponentState state)
|
||||
return;
|
||||
component.Enabled = state.Enabled;
|
||||
component.AccessKeys = new (state.AccessKeys);
|
||||
component.AccessLists = new (state.AccessLists);
|
||||
component.DenyTags = new (state.DenyTags);
|
||||
}
|
||||
|
||||
private void OnLinkAttempt(EntityUid uid, AccessReaderComponent component, LinkAttemptEvent args)
|
||||
{
|
||||
if (args.User == null) // AutoLink (and presumably future external linkers) have no user.
|
||||
return;
|
||||
if (!HasComp<EmaggedComponent>(uid) && !IsAllowed(args.User.Value, component))
|
||||
args.Cancel();
|
||||
}
|
||||
|
||||
private void OnEmagged(EntityUid uid, AccessReaderComponent reader, ref GotEmaggedEvent args)
|
||||
{
|
||||
args.Handled = true;
|
||||
reader.Enabled = false;
|
||||
Dirty(reader);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Searches the source for access tags
|
||||
/// then compares it with the targets readers access list to see if it is allowed.
|
||||
/// </summary>
|
||||
/// <param name="source">The entity that wants access.</param>
|
||||
/// <param name="target">The entity to search for an access reader</param>
|
||||
/// <param name="reader">Optional reader from the target entity</param>
|
||||
public bool IsAllowed(EntityUid source, EntityUid target, AccessReaderComponent? reader = null)
|
||||
{
|
||||
if (!Resolve(target, ref reader, false))
|
||||
return true;
|
||||
return IsAllowed(source, reader);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Searches the given entity for access tags
|
||||
/// then compares it with the readers access list to see if it is allowed.
|
||||
/// </summary>
|
||||
/// <param name="entity">The entity that wants access.</param>
|
||||
/// <param name="reader">A reader from a different entity</param>
|
||||
public bool IsAllowed(EntityUid entity, AccessReaderComponent reader)
|
||||
{
|
||||
var allEnts = FindPotentialAccessItems(entity);
|
||||
|
||||
// Access reader is totally disabled, so access is always allowed.
|
||||
if (!reader.Enabled)
|
||||
return true;
|
||||
|
||||
if (AreAccessTagsAllowed(FindAccessTags(entity, allEnts), reader))
|
||||
return true;
|
||||
|
||||
if (AreStationRecordKeysAllowed(FindStationRecordKeys(entity, allEnts), reader))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compares the given tags with the readers access list to see if it is allowed.
|
||||
/// </summary>
|
||||
/// <param name="accessTags">A list of access tags</param>
|
||||
/// <param name="reader">An access reader to check against</param>
|
||||
public bool AreAccessTagsAllowed(ICollection<string> accessTags, AccessReaderComponent reader)
|
||||
{
|
||||
if (reader.DenyTags.Overlaps(accessTags))
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeLocalEvent<AccessReaderComponent, ComponentInit>(OnInit);
|
||||
SubscribeLocalEvent<AccessReaderComponent, GotEmaggedEvent>(OnEmagged);
|
||||
SubscribeLocalEvent<AccessReaderComponent, LinkAttemptEvent>(OnLinkAttempt);
|
||||
|
||||
SubscribeLocalEvent<AccessReaderComponent, ComponentGetState>(OnGetState);
|
||||
SubscribeLocalEvent<AccessReaderComponent, ComponentHandleState>(OnHandleState);
|
||||
}
|
||||
|
||||
private void OnGetState(EntityUid uid, AccessReaderComponent component, ref ComponentGetState args)
|
||||
{
|
||||
args.State = new AccessReaderComponentState(component.Enabled, component.DenyTags, component.AccessLists,
|
||||
component.AccessKeys);
|
||||
}
|
||||
|
||||
private void OnHandleState(EntityUid uid, AccessReaderComponent component, ref ComponentHandleState args)
|
||||
{
|
||||
if (args.Current is not AccessReaderComponentState state)
|
||||
return;
|
||||
component.Enabled = state.Enabled;
|
||||
component.AccessKeys = new (state.AccessKeys);
|
||||
component.AccessLists = new (state.AccessLists);
|
||||
component.DenyTags = new (state.DenyTags);
|
||||
}
|
||||
|
||||
private void OnLinkAttempt(EntityUid uid, AccessReaderComponent component, LinkAttemptEvent args)
|
||||
{
|
||||
if (args.User == null) // AutoLink (and presumably future external linkers) have no user.
|
||||
return;
|
||||
if (!HasComp<EmaggedComponent>(uid) && !IsAllowed(args.User.Value, component))
|
||||
args.Cancel();
|
||||
}
|
||||
|
||||
private void OnInit(EntityUid uid, AccessReaderComponent reader, ComponentInit args)
|
||||
{
|
||||
var allTags = reader.AccessLists.SelectMany(c => c).Union(reader.DenyTags);
|
||||
foreach (var level in allTags)
|
||||
{
|
||||
if (!_prototypeManager.HasIndex<AccessLevelPrototype>(level))
|
||||
{
|
||||
Logger.ErrorS("access", $"Invalid access level: {level}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnEmagged(EntityUid uid, AccessReaderComponent reader, ref GotEmaggedEvent args)
|
||||
{
|
||||
args.Handled = true;
|
||||
reader.Enabled = false;
|
||||
Dirty(reader);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Searches the source for access tags
|
||||
/// then compares it with the targets readers access list to see if it is allowed.
|
||||
/// </summary>
|
||||
/// <param name="source">The entity that wants access.</param>
|
||||
/// <param name="target">The entity to search for an access reader</param>
|
||||
/// <param name="reader">Optional reader from the target entity</param>
|
||||
public bool IsAllowed(EntityUid source, EntityUid target, AccessReaderComponent? reader = null)
|
||||
{
|
||||
if (!Resolve(target, ref reader, false))
|
||||
return true;
|
||||
return IsAllowed(source, reader);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Searches the given entity for access tags
|
||||
/// then compares it with the readers access list to see if it is allowed.
|
||||
/// </summary>
|
||||
/// <param name="entity">The entity that wants access.</param>
|
||||
/// <param name="reader">A reader from a different entity</param>
|
||||
public bool IsAllowed(EntityUid entity, AccessReaderComponent reader)
|
||||
{
|
||||
var allEnts = FindPotentialAccessItems(entity);
|
||||
|
||||
// Access reader is totally disabled, so access is always allowed.
|
||||
if (!reader.Enabled)
|
||||
return true;
|
||||
|
||||
if (AreAccessTagsAllowed(FindAccessTags(entity, allEnts), reader))
|
||||
return true;
|
||||
|
||||
if (AreStationRecordKeysAllowed(FindStationRecordKeys(entity, allEnts), reader))
|
||||
return true;
|
||||
// Sec owned by cargo.
|
||||
|
||||
// Note that in resolving the issue with only one specific item "counting" for access, this became a bit more strict.
|
||||
// As having an ID card in any slot that "counts" with a denied access group will cause denial of access.
|
||||
// DenyTags doesn't seem to be used right now anyway, though, so it'll be dependent on whoever uses it to figure out if this matters.
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compares the given tags with the readers access list to see if it is allowed.
|
||||
/// </summary>
|
||||
/// <param name="accessTags">A list of access tags</param>
|
||||
/// <param name="reader">An access reader to check against</param>
|
||||
public bool AreAccessTagsAllowed(ICollection<string> accessTags, AccessReaderComponent reader)
|
||||
return reader.AccessLists.Count == 0 || reader.AccessLists.Any(a => a.IsSubsetOf(accessTags));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compares the given stationrecordkeys with the accessreader to see if it is allowed.
|
||||
/// </summary>
|
||||
public bool AreStationRecordKeysAllowed(ICollection<StationRecordKey> keys, AccessReaderComponent reader)
|
||||
{
|
||||
return keys.Any() && reader.AccessKeys.Any(keys.Contains);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds all the items that could potentially give access to a given entity
|
||||
/// </summary>
|
||||
public HashSet<EntityUid> FindPotentialAccessItems(EntityUid uid)
|
||||
{
|
||||
FindAccessItemsInventory(uid, out var items);
|
||||
|
||||
var ev = new GetAdditionalAccessEvent
|
||||
{
|
||||
if (reader.DenyTags.Overlaps(accessTags))
|
||||
{
|
||||
// Sec owned by cargo.
|
||||
Entities = items
|
||||
};
|
||||
RaiseLocalEvent(uid, ref ev);
|
||||
items.Add(uid);
|
||||
return items;
|
||||
}
|
||||
|
||||
// Note that in resolving the issue with only one specific item "counting" for access, this became a bit more strict.
|
||||
// As having an ID card in any slot that "counts" with a denied access group will cause denial of access.
|
||||
// DenyTags doesn't seem to be used right now anyway, though, so it'll be dependent on whoever uses it to figure out if this matters.
|
||||
return false;
|
||||
}
|
||||
/// <summary>
|
||||
/// Finds the access tags on the given entity
|
||||
/// </summary>
|
||||
/// <param name="uid">The entity that is being searched.</param>
|
||||
/// <param name="items">All of the items to search for access. If none are passed in, <see cref="FindPotentialAccessItems"/> will be used.</param>
|
||||
public ICollection<string> FindAccessTags(EntityUid uid, HashSet<EntityUid>? items = null)
|
||||
{
|
||||
HashSet<string>? tags = null;
|
||||
var owned = false;
|
||||
|
||||
return reader.AccessLists.Count == 0 || reader.AccessLists.Any(a => a.IsSubsetOf(accessTags));
|
||||
items ??= FindPotentialAccessItems(uid);
|
||||
|
||||
foreach (var ent in items)
|
||||
{
|
||||
FindAccessTagsItem(ent, ref tags, ref owned);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compares the given stationrecordkeys with the accessreader to see if it is allowed.
|
||||
/// </summary>
|
||||
public bool AreStationRecordKeysAllowed(ICollection<StationRecordKey> keys, AccessReaderComponent reader)
|
||||
return (ICollection<string>?) tags ?? Array.Empty<string>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds the access tags on the given entity
|
||||
/// </summary>
|
||||
/// <param name="uid">The entity that is being searched.</param>
|
||||
/// <param name="items">All of the items to search for access. If none are passed in, <see cref="FindPotentialAccessItems"/> will be used.</param>
|
||||
public ICollection<StationRecordKey> FindStationRecordKeys(EntityUid uid, HashSet<EntityUid>? items = null)
|
||||
{
|
||||
HashSet<StationRecordKey> keys = new();
|
||||
|
||||
items ??= FindPotentialAccessItems(uid);
|
||||
|
||||
foreach (var ent in items)
|
||||
{
|
||||
return keys.Any() && reader.AccessKeys.Any(keys.Contains);
|
||||
if (FindStationRecordKeyItem(ent, out var key))
|
||||
keys.Add(key.Value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds all the items that could potentially give access to a given entity
|
||||
/// </summary>
|
||||
public HashSet<EntityUid> FindPotentialAccessItems(EntityUid uid)
|
||||
{
|
||||
FindAccessItemsInventory(uid, out var items);
|
||||
return keys;
|
||||
}
|
||||
|
||||
var ev = new GetAdditionalAccessEvent
|
||||
{
|
||||
Entities = items
|
||||
};
|
||||
RaiseLocalEvent(uid, ref ev);
|
||||
items.Add(uid);
|
||||
return items;
|
||||
/// <summary>
|
||||
/// Try to find <see cref="AccessComponent"/> on this item
|
||||
/// or inside this item (if it's pda)
|
||||
/// This version merges into a set or replaces the set.
|
||||
/// If owned is false, the existing tag-set "isn't ours" and can't be merged with (is read-only).
|
||||
/// </summary>
|
||||
private void FindAccessTagsItem(EntityUid uid, ref HashSet<string>? tags, ref bool owned)
|
||||
{
|
||||
if (!FindAccessTagsItem(uid, out var targetTags))
|
||||
{
|
||||
// no tags, no problem
|
||||
return;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds the access tags on the given entity
|
||||
/// </summary>
|
||||
/// <param name="uid">The entity that is being searched.</param>
|
||||
/// <param name="items">All of the items to search for access. If none are passed in, <see cref="FindPotentialAccessItems"/> will be used.</param>
|
||||
public ICollection<string> FindAccessTags(EntityUid uid, HashSet<EntityUid>? items = null)
|
||||
if (tags != null)
|
||||
{
|
||||
HashSet<string>? tags = null;
|
||||
var owned = false;
|
||||
|
||||
items ??= FindPotentialAccessItems(uid);
|
||||
|
||||
foreach (var ent in items)
|
||||
// existing tags, so copy to make sure we own them
|
||||
if (!owned)
|
||||
{
|
||||
FindAccessTagsItem(ent, ref tags, ref owned);
|
||||
tags = new(tags);
|
||||
owned = true;
|
||||
}
|
||||
|
||||
return (ICollection<string>?) tags ?? Array.Empty<string>();
|
||||
// then merge
|
||||
tags.UnionWith(targetTags);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds the access tags on the given entity
|
||||
/// </summary>
|
||||
/// <param name="uid">The entity that is being searched.</param>
|
||||
/// <param name="items">All of the items to search for access. If none are passed in, <see cref="FindPotentialAccessItems"/> will be used.</param>
|
||||
public ICollection<StationRecordKey> FindStationRecordKeys(EntityUid uid, HashSet<EntityUid>? items = null)
|
||||
else
|
||||
{
|
||||
HashSet<StationRecordKey> keys = new();
|
||||
|
||||
items ??= FindPotentialAccessItems(uid);
|
||||
|
||||
foreach (var ent in items)
|
||||
{
|
||||
if (FindStationRecordKeyItem(ent, out var key))
|
||||
keys.Add(key.Value);
|
||||
}
|
||||
|
||||
return keys;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Try to find <see cref="AccessComponent"/> on this item
|
||||
/// or inside this item (if it's pda)
|
||||
/// This version merges into a set or replaces the set.
|
||||
/// If owned is false, the existing tag-set "isn't ours" and can't be merged with (is read-only).
|
||||
/// </summary>
|
||||
private void FindAccessTagsItem(EntityUid uid, ref HashSet<string>? tags, ref bool owned)
|
||||
{
|
||||
if (!FindAccessTagsItem(uid, out var targetTags))
|
||||
{
|
||||
// no tags, no problem
|
||||
return;
|
||||
}
|
||||
if (tags != null)
|
||||
{
|
||||
// existing tags, so copy to make sure we own them
|
||||
if (!owned)
|
||||
{
|
||||
tags = new(tags);
|
||||
owned = true;
|
||||
}
|
||||
// then merge
|
||||
tags.UnionWith(targetTags);
|
||||
}
|
||||
else
|
||||
{
|
||||
// no existing tags, so now they're ours
|
||||
tags = targetTags;
|
||||
owned = false;
|
||||
}
|
||||
}
|
||||
|
||||
public bool FindAccessItemsInventory(EntityUid uid, out HashSet<EntityUid> items)
|
||||
{
|
||||
items = new();
|
||||
|
||||
foreach (var item in _handsSystem.EnumerateHeld(uid))
|
||||
{
|
||||
items.Add(item);
|
||||
}
|
||||
|
||||
// maybe its inside an inventory slot?
|
||||
if (_inventorySystem.TryGetSlotEntity(uid, "id", out var idUid))
|
||||
{
|
||||
items.Add(idUid.Value);
|
||||
}
|
||||
|
||||
return items.Any();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Try to find <see cref="AccessComponent"/> on this item
|
||||
/// or inside this item (if it's pda)
|
||||
/// </summary>
|
||||
private bool FindAccessTagsItem(EntityUid uid, [NotNullWhen(true)] out HashSet<string>? tags)
|
||||
{
|
||||
if (TryComp(uid, out AccessComponent? access))
|
||||
{
|
||||
tags = access.Tags;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (TryComp(uid, out PdaComponent? pda) &&
|
||||
pda.ContainedId?.Owner is {Valid: true} id)
|
||||
{
|
||||
tags = EntityManager.GetComponent<AccessComponent>(id).Tags;
|
||||
return true;
|
||||
}
|
||||
|
||||
tags = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Try to find <see cref="StationRecordKeyStorageComponent"/> on this item
|
||||
/// or inside this item (if it's pda)
|
||||
/// </summary>
|
||||
private bool FindStationRecordKeyItem(EntityUid uid, [NotNullWhen(true)] out StationRecordKey? key)
|
||||
{
|
||||
if (TryComp(uid, out StationRecordKeyStorageComponent? storage) && storage.Key != null)
|
||||
{
|
||||
key = storage.Key;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (TryComp<PdaComponent>(uid, out var pda) &&
|
||||
pda.ContainedId?.Owner is {Valid: true} id)
|
||||
{
|
||||
if (TryComp<StationRecordKeyStorageComponent>(id, out var pdastorage) && pdastorage.Key != null)
|
||||
{
|
||||
key = pdastorage.Key;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
key = null;
|
||||
return false;
|
||||
// no existing tags, so now they're ours
|
||||
tags = targetTags;
|
||||
owned = false;
|
||||
}
|
||||
}
|
||||
|
||||
public bool FindAccessItemsInventory(EntityUid uid, out HashSet<EntityUid> items)
|
||||
{
|
||||
items = new();
|
||||
|
||||
foreach (var item in _handsSystem.EnumerateHeld(uid))
|
||||
{
|
||||
items.Add(item);
|
||||
}
|
||||
|
||||
// maybe its inside an inventory slot?
|
||||
if (_inventorySystem.TryGetSlotEntity(uid, "id", out var idUid))
|
||||
{
|
||||
items.Add(idUid.Value);
|
||||
}
|
||||
|
||||
return items.Any();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Try to find <see cref="AccessComponent"/> on this item
|
||||
/// or inside this item (if it's pda)
|
||||
/// </summary>
|
||||
private bool FindAccessTagsItem(EntityUid uid, [NotNullWhen(true)] out HashSet<string>? tags)
|
||||
{
|
||||
if (TryComp(uid, out AccessComponent? access))
|
||||
{
|
||||
tags = access.Tags;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (TryComp(uid, out PdaComponent? pda) &&
|
||||
pda.ContainedId is { Valid: true } id)
|
||||
{
|
||||
tags = EntityManager.GetComponent<AccessComponent>(id).Tags;
|
||||
return true;
|
||||
}
|
||||
|
||||
tags = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Try to find <see cref="StationRecordKeyStorageComponent"/> on this item
|
||||
/// or inside this item (if it's pda)
|
||||
/// </summary>
|
||||
private bool FindStationRecordKeyItem(EntityUid uid, [NotNullWhen(true)] out StationRecordKey? key)
|
||||
{
|
||||
if (TryComp(uid, out StationRecordKeyStorageComponent? storage) && storage.Key != null)
|
||||
{
|
||||
key = storage.Key;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (TryComp<PdaComponent>(uid, out var pda) &&
|
||||
pda.ContainedId is { Valid: true } id)
|
||||
{
|
||||
if (TryComp<StationRecordKeyStorageComponent>(id, out var pdastorage) && pdastorage.Key != null)
|
||||
{
|
||||
key = pdastorage.Key;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
key = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ public abstract class SharedIdCardSystem : EntitySystem
|
||||
public bool TryFindIdCard(EntityUid uid, [NotNullWhen(true)] out IdCardComponent? idCard)
|
||||
{
|
||||
// check held item?
|
||||
if (EntityManager.TryGetComponent(uid, out HandsComponent? hands) &&
|
||||
if (TryComp(uid, out HandsComponent? hands) &&
|
||||
hands.ActiveHandEntity is EntityUid heldItem &&
|
||||
TryGetIdCard(heldItem, out idCard))
|
||||
{
|
||||
@@ -30,9 +30,7 @@ public abstract class SharedIdCardSystem : EntitySystem
|
||||
|
||||
// check inventory slot?
|
||||
if (_inventorySystem.TryGetSlotEntity(uid, "id", out var idUid) && TryGetIdCard(idUid.Value, out idCard))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -43,12 +41,12 @@ public abstract class SharedIdCardSystem : EntitySystem
|
||||
/// </summary>
|
||||
public bool TryGetIdCard(EntityUid uid, [NotNullWhen(true)] out IdCardComponent? idCard)
|
||||
{
|
||||
if (EntityManager.TryGetComponent(uid, out idCard))
|
||||
if (TryComp(uid, out idCard))
|
||||
return true;
|
||||
|
||||
if (EntityManager.TryGetComponent(uid, out PdaComponent? pda) && pda.ContainedId != null)
|
||||
if (TryComp(uid, out PdaComponent? pda)
|
||||
&& TryComp(pda.ContainedId, out idCard))
|
||||
{
|
||||
idCard = pda.ContainedId;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -77,13 +77,6 @@ namespace Content.Shared.Containers.ItemSlots
|
||||
[DataField("ejectSound")]
|
||||
public SoundSpecifier EjectSound = new SoundPathSpecifier("/Audio/Weapons/Guns/MagOut/revolver_magout.ogg");
|
||||
|
||||
/// <summary>
|
||||
/// Options used for playing the insert/eject sounds.
|
||||
/// </summary>
|
||||
[DataField("soundOptions")]
|
||||
[Obsolete("Use the sound specifer parameters instead")]
|
||||
public AudioParams SoundOptions = AudioParams.Default;
|
||||
|
||||
/// <summary>
|
||||
/// The name of this item slot. This will be shown to the user in the verb menu.
|
||||
/// </summary>
|
||||
@@ -228,7 +221,6 @@ namespace Content.Shared.Containers.ItemSlots
|
||||
InsertSound = other.InsertSound;
|
||||
EjectSound = other.EjectSound;
|
||||
|
||||
SoundOptions = other.SoundOptions;
|
||||
Name = other.Name;
|
||||
Locked = other.Locked;
|
||||
InsertOnInteract = other.InsertOnInteract;
|
||||
|
||||
@@ -65,7 +65,7 @@ namespace Content.Shared.Containers.ItemSlots
|
||||
if (slot.HasItem || string.IsNullOrEmpty(slot.StartingItem))
|
||||
continue;
|
||||
|
||||
var item = EntityManager.SpawnEntity(slot.StartingItem, EntityManager.GetComponent<TransformComponent>(itemSlots.Owner).Coordinates);
|
||||
var item = EntityManager.SpawnEntity(slot.StartingItem, EntityManager.GetComponent<TransformComponent>(uid).Coordinates);
|
||||
slot.ContainerSlot?.Insert(item);
|
||||
}
|
||||
}
|
||||
@@ -77,7 +77,7 @@ namespace Content.Shared.Containers.ItemSlots
|
||||
{
|
||||
foreach (var (id, slot) in itemSlots.Slots)
|
||||
{
|
||||
slot.ContainerSlot = _containers.EnsureContainer<ContainerSlot>(itemSlots.Owner, id);
|
||||
slot.ContainerSlot = _containers.EnsureContainer<ContainerSlot>(uid, id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,13 +93,13 @@ namespace Content.Shared.Containers.ItemSlots
|
||||
if (itemSlots.Slots.TryGetValue(id, out var existing))
|
||||
{
|
||||
if (existing.Local)
|
||||
Logger.Error($"Duplicate item slot key. Entity: {EntityManager.GetComponent<MetaDataComponent>(itemSlots.Owner).EntityName} ({uid}), key: {id}");
|
||||
Log.Error($"Duplicate item slot key. Entity: {EntityManager.GetComponent<MetaDataComponent>(uid).EntityName} ({uid}), key: {id}");
|
||||
else
|
||||
// server state takes priority
|
||||
slot.CopyFrom(existing);
|
||||
}
|
||||
|
||||
slot.ContainerSlot = _containers.EnsureContainer<ContainerSlot>(itemSlots.Owner, id);
|
||||
slot.ContainerSlot = _containers.EnsureContainer<ContainerSlot>(uid, id);
|
||||
itemSlots.Slots[id] = slot;
|
||||
Dirty(itemSlots);
|
||||
}
|
||||
@@ -340,7 +340,7 @@ namespace Content.Shared.Containers.ItemSlots
|
||||
if (ejected != null && ejected.Value && user != null)
|
||||
_adminLogger.Add(LogType.Action, LogImpact.Low, $"{ToPrettyString(user.Value)} ejected {ToPrettyString(item)} from {slot.ContainerSlot?.ID + " slot of "}{ToPrettyString(uid)}");
|
||||
|
||||
_audioSystem.PlayPredicted(slot.EjectSound, uid, excludeUserAudio ? user : null, slot.SoundOptions);
|
||||
_audioSystem.PlayPredicted(slot.EjectSound, uid, excludeUserAudio ? user : null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -477,9 +477,11 @@ namespace Content.Shared.Containers.ItemSlots
|
||||
? Loc.GetString(slot.Name)
|
||||
: EntityManager.GetComponent<MetaDataComponent>(slot.Item.Value).EntityName ?? string.Empty;
|
||||
|
||||
AlternativeVerb verb = new();
|
||||
verb.IconEntity = slot.Item;
|
||||
verb.Act = () => TryEjectToHands(uid, slot, args.User, excludeUserAudio: true);
|
||||
AlternativeVerb verb = new()
|
||||
{
|
||||
IconEntity = slot.Item,
|
||||
Act = () => TryEjectToHands(uid, slot, args.User, excludeUserAudio: true)
|
||||
};
|
||||
|
||||
if (slot.EjectVerbText == null)
|
||||
{
|
||||
@@ -538,18 +540,20 @@ namespace Content.Shared.Containers.ItemSlots
|
||||
|
||||
var verbSubject = slot.Name != string.Empty
|
||||
? Loc.GetString(slot.Name)
|
||||
: Name(args.Using.Value) ?? string.Empty;
|
||||
: Name(args.Using.Value);
|
||||
|
||||
InteractionVerb insertVerb = new();
|
||||
insertVerb.IconEntity = args.Using;
|
||||
insertVerb.Act = () => Insert(uid, slot, args.Using.Value, args.User, excludeUserAudio: true);
|
||||
InteractionVerb insertVerb = new()
|
||||
{
|
||||
IconEntity = args.Using,
|
||||
Act = () => Insert(uid, slot, args.Using.Value, args.User, excludeUserAudio: true)
|
||||
};
|
||||
|
||||
if (slot.InsertVerbText != null)
|
||||
{
|
||||
insertVerb.Text = Loc.GetString(slot.InsertVerbText);
|
||||
insertVerb.Icon =
|
||||
new SpriteSpecifier.Texture(
|
||||
new("/Textures/Interface/VerbIcons/insert.svg.192dpi.png"));
|
||||
new ResPath("/Textures/Interface/VerbIcons/insert.svg.192dpi.png"));
|
||||
}
|
||||
else if(slot.EjectOnInteract)
|
||||
{
|
||||
@@ -558,7 +562,7 @@ namespace Content.Shared.Containers.ItemSlots
|
||||
insertVerb.Text = Loc.GetString("place-item-verb-text", ("subject", verbSubject));
|
||||
insertVerb.Icon =
|
||||
new SpriteSpecifier.Texture(
|
||||
new("/Textures/Interface/VerbIcons/drop.svg.192dpi.png"));
|
||||
new ResPath("/Textures/Interface/VerbIcons/drop.svg.192dpi.png"));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -635,7 +639,7 @@ namespace Content.Shared.Containers.ItemSlots
|
||||
return;
|
||||
|
||||
slot.Locked = locked;
|
||||
itemSlots.Dirty();
|
||||
Dirty(uid, itemSlots);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -39,18 +39,6 @@ public sealed class CuffableComponent : Component
|
||||
/// </summary>
|
||||
[DataField("canStillInteract"), ViewVariables(VVAccess.ReadWrite)]
|
||||
public bool CanStillInteract = true;
|
||||
|
||||
/// <summary>
|
||||
/// Damage is applied to someone when they try to uncuff themselves.
|
||||
/// </summary>
|
||||
[DataField("damageOnResist"), ViewVariables(VVAccess.ReadWrite)]
|
||||
public DamageSpecifier DamageOnResist = new()
|
||||
{
|
||||
DamageDict = new()
|
||||
{
|
||||
{ "Blunt", 3.0 },
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Content.Shared.Damage;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Prototypes;
|
||||
@@ -47,6 +48,15 @@ public sealed class HandcuffComponent : Component
|
||||
[DataField("brokenPrototype", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>)), ViewVariables(VVAccess.ReadWrite)]
|
||||
public string? BrokenPrototype;
|
||||
|
||||
[DataField("damageOnResist"), ViewVariables(VVAccess.ReadWrite)]
|
||||
public DamageSpecifier DamageOnResist = new()
|
||||
{
|
||||
DamageDict = new()
|
||||
{
|
||||
{ "Blunt", 3.0 },
|
||||
}
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// The path of the RSI file used for the player cuffed overlay.
|
||||
/// </summary>
|
||||
|
||||
@@ -266,7 +266,7 @@ namespace Content.Shared.Cuffs
|
||||
|
||||
private void OnCuffAfterInteract(EntityUid uid, HandcuffComponent component, AfterInteractEvent args)
|
||||
{
|
||||
if (args.Target is not {Valid: true} target)
|
||||
if (args.Target is not { Valid: true } target)
|
||||
return;
|
||||
|
||||
if (!args.CanReach)
|
||||
@@ -580,7 +580,7 @@ namespace Content.Shared.Cuffs
|
||||
|
||||
if (isOwner)
|
||||
{
|
||||
_damageSystem.TryChangeDamage(target, cuffable.DamageOnResist, true, false);
|
||||
_damageSystem.TryChangeDamage(target, cuff.DamageOnResist, true, false);
|
||||
}
|
||||
|
||||
if (_net.IsServer)
|
||||
|
||||
@@ -23,14 +23,14 @@ public abstract class SharedDoorSystem : EntitySystem
|
||||
{
|
||||
[Dependency] protected readonly IGameTiming GameTiming = default!;
|
||||
[Dependency] protected readonly SharedPhysicsSystem PhysicsSystem = default!;
|
||||
[Dependency] private readonly DamageableSystem _damageableSystem = default!;
|
||||
[Dependency] private readonly SharedStunSystem _stunSystem = default!;
|
||||
[Dependency] private readonly DamageableSystem _damageableSystem = default!;
|
||||
[Dependency] private readonly SharedStunSystem _stunSystem = default!;
|
||||
[Dependency] protected readonly TagSystem Tags = default!;
|
||||
[Dependency] protected readonly SharedAudioSystem Audio = default!;
|
||||
[Dependency] private readonly EntityLookupSystem _entityLookup = default!;
|
||||
[Dependency] private readonly EntityLookupSystem _entityLookup = default!;
|
||||
[Dependency] protected readonly SharedAppearanceSystem AppearanceSystem = default!;
|
||||
[Dependency] private readonly OccluderSystem _occluder = default!;
|
||||
[Dependency] private readonly AccessReaderSystem _accessReaderSystem = default!;
|
||||
[Dependency] private readonly OccluderSystem _occluder = default!;
|
||||
[Dependency] private readonly AccessReaderSystem _accessReaderSystem = default!;
|
||||
|
||||
/// <summary>
|
||||
/// A body must have an intersection percentage larger than this in order to be considered as colliding with a
|
||||
|
||||
@@ -8,7 +8,7 @@ using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototy
|
||||
|
||||
namespace Content.Shared.Implants.Components;
|
||||
/// <summary>
|
||||
/// Implanters are used to implant or extract implants from an entity
|
||||
/// Implanters are used to implant or extract implants from an entity.
|
||||
/// Some can be single use (implant only) or some can draw out an implant
|
||||
/// </summary>
|
||||
//TODO: Rework drawing to work with implant cases when surgery is in
|
||||
|
||||
@@ -59,9 +59,9 @@ public abstract class SharedImplanterSystem : EntitySystem
|
||||
implantContainer.Insert(implant.Value);
|
||||
|
||||
if (component.CurrentMode == ImplanterToggleMode.Inject && !component.ImplantOnly)
|
||||
DrawMode(component);
|
||||
DrawMode(implanter, component);
|
||||
else
|
||||
ImplantMode(component);
|
||||
ImplantMode(implanter, component);
|
||||
|
||||
Dirty(component);
|
||||
}
|
||||
@@ -74,8 +74,8 @@ public abstract class SharedImplanterSystem : EntitySystem
|
||||
[NotNullWhen(true)] out EntityUid? implant,
|
||||
[NotNullWhen(true)] out SubdermalImplantComponent? implantComp)
|
||||
{
|
||||
implant = component.ImplanterSlot.ContainerSlot?.ContainedEntities?.FirstOrDefault();
|
||||
if (!TryComp<SubdermalImplantComponent>(implant, out implantComp))
|
||||
implant = component.ImplanterSlot.ContainerSlot?.ContainedEntities.FirstOrDefault();
|
||||
if (!TryComp(implant, out implantComp))
|
||||
return false;
|
||||
|
||||
var ev = new AddImplantAttemptEvent(user, target, implant.Value, implanter);
|
||||
@@ -101,7 +101,7 @@ public abstract class SharedImplanterSystem : EntitySystem
|
||||
foreach (var implant in implantContainer.ContainedEntities)
|
||||
{
|
||||
if (!implantCompQuery.TryGetComponent(implant, out var implantComp))
|
||||
return;
|
||||
continue;
|
||||
|
||||
//Don't remove a permanent implant and look for the next that can be drawn
|
||||
if (!implantContainer.CanRemove(implant))
|
||||
@@ -124,27 +124,27 @@ public abstract class SharedImplanterSystem : EntitySystem
|
||||
}
|
||||
|
||||
if (component.CurrentMode == ImplanterToggleMode.Draw && !component.ImplantOnly && !permanentFound)
|
||||
ImplantMode(component);
|
||||
ImplantMode(implanter, component);
|
||||
|
||||
Dirty(component);
|
||||
}
|
||||
}
|
||||
|
||||
private void ImplantMode(ImplanterComponent component)
|
||||
private void ImplantMode(EntityUid uid, ImplanterComponent component)
|
||||
{
|
||||
component.CurrentMode = ImplanterToggleMode.Inject;
|
||||
ChangeOnImplantVisualizer(component);
|
||||
ChangeOnImplantVisualizer(uid, component);
|
||||
}
|
||||
|
||||
private void DrawMode(ImplanterComponent component)
|
||||
private void DrawMode(EntityUid uid, ImplanterComponent component)
|
||||
{
|
||||
component.CurrentMode = ImplanterToggleMode.Draw;
|
||||
ChangeOnImplantVisualizer(component);
|
||||
ChangeOnImplantVisualizer(uid, component);
|
||||
}
|
||||
|
||||
private void ChangeOnImplantVisualizer(ImplanterComponent component)
|
||||
private void ChangeOnImplantVisualizer(EntityUid uid, ImplanterComponent component)
|
||||
{
|
||||
if (!TryComp<AppearanceComponent>(component.Owner, out var appearance))
|
||||
if (!TryComp<AppearanceComponent>(uid, out var appearance))
|
||||
return;
|
||||
|
||||
bool implantFound;
|
||||
@@ -156,17 +156,17 @@ public abstract class SharedImplanterSystem : EntitySystem
|
||||
implantFound = false;
|
||||
|
||||
if (component.CurrentMode == ImplanterToggleMode.Inject && !component.ImplantOnly)
|
||||
_appearance.SetData(component.Owner, ImplanterVisuals.Full, implantFound, appearance);
|
||||
_appearance.SetData(uid, ImplanterVisuals.Full, implantFound, appearance);
|
||||
|
||||
else if (component.CurrentMode == ImplanterToggleMode.Inject && component.ImplantOnly)
|
||||
{
|
||||
_appearance.SetData(component.Owner, ImplanterVisuals.Full, implantFound, appearance);
|
||||
_appearance.SetData(component.Owner, ImplanterImplantOnlyVisuals.ImplantOnly, component.ImplantOnly,
|
||||
_appearance.SetData(uid, ImplanterVisuals.Full, implantFound, appearance);
|
||||
_appearance.SetData(uid, ImplanterImplantOnlyVisuals.ImplantOnly, component.ImplantOnly,
|
||||
appearance);
|
||||
}
|
||||
|
||||
else
|
||||
_appearance.SetData(component.Owner, ImplanterVisuals.Full, implantFound, appearance);
|
||||
_appearance.SetData(uid, ImplanterVisuals.Full, implantFound, appearance);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,20 +6,17 @@ using Content.Shared.Movement.Events;
|
||||
using Content.Shared.Popups;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Shared.Movement.Systems;
|
||||
|
||||
public abstract class SharedJetpackSystem : EntitySystem
|
||||
{
|
||||
[Dependency] protected readonly MovementSpeedModifierSystem MovementSpeedModifier = default!;
|
||||
[Dependency] protected readonly SharedAppearanceSystem Appearance = default!;
|
||||
[Dependency] private readonly MovementSpeedModifierSystem _movementSpeedModifier = default!;
|
||||
[Dependency] protected readonly SharedAppearanceSystem Appearance = default!;
|
||||
[Dependency] protected readonly SharedContainerSystem Container = default!;
|
||||
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||
[Dependency] private readonly SharedMoverController _mover = default!;
|
||||
[Dependency] private readonly SharedMoverController _mover = default!;
|
||||
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -55,14 +52,16 @@ public abstract class SharedJetpackSystem : EntitySystem
|
||||
{
|
||||
_popup.PopupClient(Loc.GetString("jetpack-to-grid"), uid, uid);
|
||||
|
||||
SetEnabled(jetpack, false, uid);
|
||||
SetEnabled(user.Jetpack, jetpack, false, uid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnJetpackUserHandleState(EntityUid uid, JetpackUserComponent component, ref ComponentHandleState args)
|
||||
{
|
||||
if (args.Current is not JetpackUserComponentState state) return;
|
||||
if (args.Current is not JetpackUserComponentState state)
|
||||
return;
|
||||
|
||||
component.Jetpack = state.Jetpack;
|
||||
}
|
||||
|
||||
@@ -76,7 +75,7 @@ public abstract class SharedJetpackSystem : EntitySystem
|
||||
|
||||
private void OnJetpackDropped(EntityUid uid, JetpackComponent component, DroppedEvent args)
|
||||
{
|
||||
SetEnabled(component, false, args.User);
|
||||
SetEnabled(uid, component, false, args.User);
|
||||
}
|
||||
|
||||
private void OnJetpackUserCanWeightless(EntityUid uid, JetpackUserComponent component, ref CanWeightlessMoveEvent args)
|
||||
@@ -89,22 +88,24 @@ public abstract class SharedJetpackSystem : EntitySystem
|
||||
if (TryComp<JetpackComponent>(component.Jetpack, out var jetpack) &&
|
||||
!CanEnableOnGrid(args.Transform.GridUid))
|
||||
{
|
||||
SetEnabled(jetpack, false, uid);
|
||||
SetEnabled(component.Jetpack, jetpack, false, uid);
|
||||
|
||||
_popup.PopupClient(Loc.GetString("jetpack-to-grid"), uid, uid);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetupUser(EntityUid uid, JetpackComponent component)
|
||||
private void SetupUser(EntityUid user, EntityUid jetpackUid)
|
||||
{
|
||||
var user = EnsureComp<JetpackUserComponent>(uid);
|
||||
_mover.SetRelay(uid, component.Owner);
|
||||
user.Jetpack = component.Owner;
|
||||
var userComp = EnsureComp<JetpackUserComponent>(user);
|
||||
_mover.SetRelay(user, jetpackUid);
|
||||
userComp.Jetpack = jetpackUid;
|
||||
}
|
||||
|
||||
private void RemoveUser(EntityUid uid)
|
||||
{
|
||||
if (!RemComp<JetpackUserComponent>(uid)) return;
|
||||
if (!RemComp<JetpackUserComponent>(uid))
|
||||
return;
|
||||
|
||||
RemComp<RelayInputMoverComponent>(uid);
|
||||
}
|
||||
|
||||
@@ -120,7 +121,7 @@ public abstract class SharedJetpackSystem : EntitySystem
|
||||
return;
|
||||
}
|
||||
|
||||
SetEnabled(component, !IsEnabled(uid));
|
||||
SetEnabled(uid, component, !IsEnabled(uid));
|
||||
}
|
||||
|
||||
private bool CanEnableOnGrid(EntityUid? gridUid)
|
||||
@@ -139,44 +140,48 @@ public abstract class SharedJetpackSystem : EntitySystem
|
||||
return HasComp<ActiveJetpackComponent>(uid);
|
||||
}
|
||||
|
||||
public void SetEnabled(JetpackComponent component, bool enabled, EntityUid? user = null)
|
||||
public void SetEnabled(EntityUid uid, JetpackComponent component, bool enabled, EntityUid? user = null)
|
||||
{
|
||||
if (IsEnabled(component.Owner) == enabled ||
|
||||
enabled && !CanEnable(component)) return;
|
||||
if (IsEnabled(uid) == enabled ||
|
||||
enabled && !CanEnable(uid, component))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (enabled)
|
||||
{
|
||||
EnsureComp<ActiveJetpackComponent>(component.Owner);
|
||||
EnsureComp<ActiveJetpackComponent>(uid);
|
||||
}
|
||||
else
|
||||
{
|
||||
RemComp<ActiveJetpackComponent>(component.Owner);
|
||||
RemComp<ActiveJetpackComponent>(uid);
|
||||
}
|
||||
|
||||
if (user == null)
|
||||
{
|
||||
Container.TryGetContainingContainer(component.Owner, out var container);
|
||||
Container.TryGetContainingContainer(uid, out var container);
|
||||
user = container?.Owner;
|
||||
}
|
||||
|
||||
// Can't activate if no one's using.
|
||||
if (user == null && enabled) return;
|
||||
if (user == null && enabled)
|
||||
return;
|
||||
|
||||
if (user != null)
|
||||
{
|
||||
if (enabled)
|
||||
{
|
||||
SetupUser(user.Value, component);
|
||||
SetupUser(user.Value, uid);
|
||||
}
|
||||
else
|
||||
{
|
||||
RemoveUser(user.Value);
|
||||
}
|
||||
|
||||
MovementSpeedModifier.RefreshMovementSpeedModifiers(user.Value);
|
||||
_movementSpeedModifier.RefreshMovementSpeedModifiers(user.Value);
|
||||
}
|
||||
|
||||
Appearance.SetData(component.Owner, JetpackVisuals.Enabled, enabled);
|
||||
Appearance.SetData(uid, JetpackVisuals.Enabled, enabled);
|
||||
Dirty(component);
|
||||
}
|
||||
|
||||
@@ -185,7 +190,7 @@ public abstract class SharedJetpackSystem : EntitySystem
|
||||
return HasComp<JetpackUserComponent>(uid);
|
||||
}
|
||||
|
||||
protected virtual bool CanEnable(JetpackComponent component)
|
||||
protected virtual bool CanEnable(EntityUid uid, JetpackComponent component)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace Content.Shared.PDA
|
||||
[DataField("id", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
|
||||
public string? IdCard;
|
||||
|
||||
[ViewVariables] public IdCardComponent? ContainedId;
|
||||
[ViewVariables] public EntityUid? ContainedId;
|
||||
[ViewVariables] public bool FlashlightOn;
|
||||
|
||||
[ViewVariables] public string? OwnerName;
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace Content.Shared.PDA
|
||||
protected virtual void OnItemInserted(EntityUid uid, PdaComponent pda, EntInsertedIntoContainerMessage args)
|
||||
{
|
||||
if (args.Container.ID == PdaComponent.PdaIdSlotId)
|
||||
pda.ContainedId = CompOrNull<IdCardComponent>(args.Entity);
|
||||
pda.ContainedId = args.Entity;
|
||||
|
||||
UpdatePdaAppearance(uid, pda);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using Content.Shared.StepTrigger.Components;
|
||||
using Content.Shared.Tag;
|
||||
using Robust.Shared.Collections;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Map.Components;
|
||||
using Robust.Shared.Physics;
|
||||
@@ -74,26 +72,26 @@ public sealed class StepTriggerSystem : EntitySystem
|
||||
|
||||
foreach (var otherUid in component.Colliding)
|
||||
{
|
||||
UpdateColliding(component, transform, otherUid, query);
|
||||
UpdateColliding(uid, component, transform, otherUid, query);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void UpdateColliding(StepTriggerComponent component, TransformComponent ownerTransform, EntityUid otherUid, EntityQuery<PhysicsComponent> query)
|
||||
private void UpdateColliding(EntityUid uid, StepTriggerComponent component, TransformComponent ownerTransform, EntityUid otherUid, EntityQuery<PhysicsComponent> query)
|
||||
{
|
||||
if (!query.TryGetComponent(otherUid, out var otherPhysics))
|
||||
return;
|
||||
|
||||
// TODO: This shouldn't be calculating based on world AABBs.
|
||||
var ourAabb = _entityLookup.GetWorldAABB(component.Owner, ownerTransform);
|
||||
var ourAabb = _entityLookup.GetWorldAABB(uid, ownerTransform);
|
||||
var otherAabb = _entityLookup.GetWorldAABB(otherUid);
|
||||
|
||||
if (!ourAabb.Intersects(otherAabb))
|
||||
{
|
||||
if (component.CurrentlySteppedOn.Remove(otherUid))
|
||||
{
|
||||
Dirty(component);
|
||||
Dirty(uid, component);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -101,17 +99,16 @@ public sealed class StepTriggerSystem : EntitySystem
|
||||
if (otherPhysics.LinearVelocity.Length() < component.RequiredTriggerSpeed
|
||||
|| component.CurrentlySteppedOn.Contains(otherUid)
|
||||
|| otherAabb.IntersectPercentage(ourAabb) < component.IntersectRatio
|
||||
|| !CanTrigger(component.Owner, otherUid, component))
|
||||
|| !CanTrigger(uid, otherUid, component))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var ev = new StepTriggeredEvent { Source = component.Owner, Tripper = otherUid };
|
||||
RaiseLocalEvent(component.Owner, ref ev, true);
|
||||
var ev = new StepTriggeredEvent { Source = uid, Tripper = otherUid };
|
||||
RaiseLocalEvent(uid, ref ev, true);
|
||||
|
||||
component.CurrentlySteppedOn.Add(otherUid);
|
||||
Dirty(component);
|
||||
return;
|
||||
Dirty(uid, component);
|
||||
}
|
||||
|
||||
private bool CanTrigger(EntityUid uid, EntityUid otherUid, StepTriggerComponent component)
|
||||
@@ -140,7 +137,7 @@ public sealed class StepTriggerSystem : EntitySystem
|
||||
|
||||
if (component.Colliding.Add(otherUid))
|
||||
{
|
||||
Dirty(component);
|
||||
Dirty(uid, component);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,7 +149,7 @@ public sealed class StepTriggerSystem : EntitySystem
|
||||
return;
|
||||
|
||||
component.CurrentlySteppedOn.Remove(otherUid);
|
||||
Dirty(component);
|
||||
Dirty(uid, component);
|
||||
|
||||
if (component.Colliding.Count == 0)
|
||||
{
|
||||
@@ -211,7 +208,7 @@ public sealed class StepTriggerSystem : EntitySystem
|
||||
return;
|
||||
|
||||
component.IntersectRatio = ratio;
|
||||
Dirty(component);
|
||||
Dirty(uid, component);
|
||||
}
|
||||
|
||||
public void SetRequiredTriggerSpeed(EntityUid uid, float speed, StepTriggerComponent? component = null)
|
||||
@@ -223,7 +220,7 @@ public sealed class StepTriggerSystem : EntitySystem
|
||||
return;
|
||||
|
||||
component.RequiredTriggerSpeed = speed;
|
||||
Dirty(component);
|
||||
Dirty(uid, component);
|
||||
}
|
||||
|
||||
public void SetActive(EntityUid uid, bool active, StepTriggerComponent? component = null)
|
||||
@@ -235,7 +232,7 @@ public sealed class StepTriggerSystem : EntitySystem
|
||||
return;
|
||||
|
||||
component.Active = active;
|
||||
Dirty(component);
|
||||
Dirty(uid, component);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,32 +21,32 @@ namespace Content.Shared.Storage.EntitySystems
|
||||
private void CounterEntityInserted(EntityUid uid, ItemCounterComponent itemCounter,
|
||||
EntInsertedIntoContainerMessage args)
|
||||
{
|
||||
if (!EntityManager.TryGetComponent(itemCounter.Owner, out AppearanceComponent? appearanceComponent))
|
||||
if (!EntityManager.TryGetComponent(uid, out AppearanceComponent? appearanceComponent))
|
||||
return;
|
||||
|
||||
var count = GetCount(args, itemCounter);
|
||||
if (count == null)
|
||||
return;
|
||||
|
||||
_appearance.SetData(itemCounter.Owner, StackVisuals.Actual, count, appearanceComponent);
|
||||
_appearance.SetData(uid, StackVisuals.Actual, count, appearanceComponent);
|
||||
|
||||
if (itemCounter.MaxAmount != null)
|
||||
_appearance.SetData(itemCounter.Owner, StackVisuals.MaxCount, itemCounter.MaxAmount, appearanceComponent);
|
||||
_appearance.SetData(uid, StackVisuals.MaxCount, itemCounter.MaxAmount, appearanceComponent);
|
||||
}
|
||||
|
||||
private void CounterEntityRemoved(EntityUid uid, ItemCounterComponent itemCounter,
|
||||
EntRemovedFromContainerMessage args)
|
||||
{
|
||||
if (!EntityManager.TryGetComponent(itemCounter.Owner, out AppearanceComponent? appearanceComponent))
|
||||
if (!EntityManager.TryGetComponent(uid, out AppearanceComponent? appearanceComponent))
|
||||
return;
|
||||
|
||||
var count = GetCount(args, itemCounter);
|
||||
if (count == null)
|
||||
return;
|
||||
|
||||
_appearance.SetData(itemCounter.Owner, StackVisuals.Actual, count, appearanceComponent);
|
||||
_appearance.SetData(uid, StackVisuals.Actual, count, appearanceComponent);
|
||||
if (itemCounter.MaxAmount != null)
|
||||
_appearance.SetData(itemCounter.Owner, StackVisuals.MaxCount, itemCounter.MaxAmount, appearanceComponent);
|
||||
_appearance.SetData(uid, StackVisuals.MaxCount, itemCounter.MaxAmount, appearanceComponent);
|
||||
}
|
||||
|
||||
protected abstract int? GetCount(ContainerModifiedMessage msg, ItemCounterComponent itemCounter);
|
||||
|
||||
@@ -78,7 +78,7 @@ public abstract partial class SharedGunSystem
|
||||
|
||||
Audio.PlayPredicted(component.SoundModeToggle, uid, user);
|
||||
Popup(Loc.GetString("gun-selected-mode", ("mode", GetLocSelector(fire))), uid, user);
|
||||
Dirty(component);
|
||||
Dirty(uid, component);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -8,6 +8,7 @@ using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Utility;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Content.Shared.Weapons.Ranged.Systems;
|
||||
|
||||
@@ -164,7 +165,7 @@ public partial class SharedGunSystem
|
||||
Popup(Loc.GetString("gun-revolver-insert"), revolverUid, user);
|
||||
UpdateRevolverAppearance(revolverUid, component);
|
||||
UpdateAmmoCount(uid);
|
||||
Dirty(component);
|
||||
Dirty(uid, component);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -223,6 +224,7 @@ public partial class SharedGunSystem
|
||||
return count;
|
||||
}
|
||||
|
||||
[PublicAPI]
|
||||
private int GetRevolverUnspentCount(RevolverAmmoProviderComponent component)
|
||||
{
|
||||
var count = 0;
|
||||
@@ -261,7 +263,8 @@ public partial class SharedGunSystem
|
||||
|
||||
if (slot == null)
|
||||
{
|
||||
if (chamber == null) continue;
|
||||
if (chamber == null)
|
||||
continue;
|
||||
|
||||
// Too lazy to make a new method don't sue me.
|
||||
if (!_netManager.IsClient)
|
||||
@@ -294,7 +297,7 @@ public partial class SharedGunSystem
|
||||
Audio.PlayPredicted(component.SoundEject, revolverUid, user);
|
||||
UpdateAmmoCount(revolverUid);
|
||||
UpdateRevolverAppearance(revolverUid, component);
|
||||
Dirty(component);
|
||||
Dirty(revolverUid, component);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -366,12 +369,12 @@ public partial class SharedGunSystem
|
||||
component.AmmoContainer.Remove(ent.Value);
|
||||
component.AmmoSlots[index] = null;
|
||||
args.Ammo.Add((ent.Value, EnsureComp<AmmoComponent>(ent.Value)));
|
||||
Transform(ent.Value).Coordinates = args.Coordinates;
|
||||
TransformSystem.SetCoordinates(ent.Value, args.Coordinates);
|
||||
}
|
||||
}
|
||||
|
||||
UpdateRevolverAppearance(uid, component);
|
||||
Dirty(component);
|
||||
Dirty(uid, component);
|
||||
}
|
||||
|
||||
private void Cycle(RevolverAmmoProviderComponent component, int count = 1)
|
||||
|
||||
@@ -329,7 +329,7 @@ public abstract partial class SharedGunSystem : EntitySystem
|
||||
CauseImpulse(fromCoordinates, toCoordinates.Value, user, userPhysics);
|
||||
}
|
||||
|
||||
Dirty(gun);
|
||||
Dirty(gunUid, gun);
|
||||
}
|
||||
|
||||
public void Shoot(
|
||||
@@ -366,7 +366,7 @@ public abstract partial class SharedGunSystem : EntitySystem
|
||||
protected void SetCartridgeSpent(EntityUid uid, CartridgeAmmoComponent cartridge, bool spent)
|
||||
{
|
||||
if (cartridge.Spent != spent)
|
||||
Dirty(cartridge);
|
||||
Dirty(uid, cartridge);
|
||||
|
||||
cartridge.Spent = spent;
|
||||
Appearance.SetData(uid, AmmoVisuals.Spent, spent);
|
||||
@@ -380,14 +380,14 @@ public abstract partial class SharedGunSystem : EntitySystem
|
||||
bool playSound = true)
|
||||
{
|
||||
// TODO: Sound limit version.
|
||||
var offsetPos = (Random.NextVector2(EjectOffset));
|
||||
var offsetPos = Random.NextVector2(EjectOffset);
|
||||
var xform = Transform(entity);
|
||||
|
||||
var coordinates = xform.Coordinates;
|
||||
coordinates = coordinates.Offset(offsetPos);
|
||||
|
||||
xform.LocalRotation = Random.NextAngle();
|
||||
xform.Coordinates = coordinates;
|
||||
TransformSystem.SetLocalRotation(xform, Random.NextAngle());
|
||||
TransformSystem.SetCoordinates(entity, xform, coordinates);
|
||||
|
||||
if (playSound && TryComp<CartridgeAmmoComponent>(entity, out var cartridge))
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
- files: ["nukeops_start.ogg"]
|
||||
- files: ["nukeops_start.ogg, traitor_start.ogg"]
|
||||
license: "CC-BY-SA-3.0"
|
||||
copyright: "Taken from TG station"
|
||||
source: "https://github.com/tgstation/tgstation/commit/827967c9650c23af64280ad1491405fed8f644c5#diff-6cc910b7cad9ac4333c8d0885fc844746066120b465d8d4ba8f7019169316574"
|
||||
|
||||
@@ -1,41 +1,4 @@
|
||||
Entries:
|
||||
- author: VigersRay
|
||||
changes:
|
||||
- {message: 'Added alert level, instruction and shift duration in PDA!', type: Add}
|
||||
- {message: Fix uknown station name in PDA for latejoin!, type: Fix}
|
||||
id: 3801
|
||||
time: '2023-05-17T20:35:41.0000000+00:00'
|
||||
- author: metalgearsloth
|
||||
changes:
|
||||
- {message: Add lathe recipe for tethergun., type: Add}
|
||||
id: 3802
|
||||
time: '2023-05-18T02:07:11.0000000+00:00'
|
||||
- author: DrSmugleaf
|
||||
changes:
|
||||
- {message: Fixed Next on the admin logs UI resending the same logs., type: Fix}
|
||||
id: 3803
|
||||
time: '2023-05-18T05:51:17.0000000+00:00'
|
||||
- author: FluffiestFloof
|
||||
changes:
|
||||
- {message: Updated the Suit Storage look., type: Tweak}
|
||||
id: 3804
|
||||
time: '2023-05-18T17:52:05.0000000+00:00'
|
||||
- author: EmoGarbage404
|
||||
changes:
|
||||
- {message: Vending machines can now be completely destroyed., type: Fix}
|
||||
id: 3805
|
||||
time: '2023-05-18T23:48:14.0000000+00:00'
|
||||
- author: themias
|
||||
changes:
|
||||
- {message: Mobs that are in critical condition no longer appear as dead on the
|
||||
crew monitor, type: Fix}
|
||||
id: 3806
|
||||
time: '2023-05-18T23:49:55.0000000+00:00'
|
||||
- author: OctoRocket
|
||||
changes:
|
||||
- {message: 'Antifreeze tastes warm now, because it is antifreeze.', type: Tweak}
|
||||
id: 3807
|
||||
time: '2023-05-19T02:21:57.0000000+00:00'
|
||||
- author: metalgearsloth
|
||||
changes:
|
||||
- {message: Disabled zombies preset temporarily until they have more work done.,
|
||||
@@ -2983,3 +2946,40 @@ Entries:
|
||||
- {message: new and improved ban panel, type: Add}
|
||||
id: 4300
|
||||
time: '2023-07-21T11:38:53.0000000+00:00'
|
||||
- author: Errant
|
||||
changes:
|
||||
- {message: Nitrogen tank settings have been adjusted to avoid gas wastage, type: Tweak}
|
||||
id: 4301
|
||||
time: '2023-07-21T19:02:39.0000000+00:00'
|
||||
- author: JimGamemaster
|
||||
changes:
|
||||
- {message: Space Creatures can now float in space, type: Tweak}
|
||||
id: 4302
|
||||
time: '2023-07-21T20:10:21.0000000+00:00'
|
||||
- author: brainfood1183
|
||||
changes:
|
||||
- {message: Strait Jackets can now be used to restrain individuals., type: Add}
|
||||
id: 4303
|
||||
time: '2023-07-22T22:14:25.0000000+00:00'
|
||||
- author: Emisse
|
||||
changes:
|
||||
- {message: Beds and medical beds now heal blunt and cold specifically instead of
|
||||
brute and burn groups., type: Tweak}
|
||||
id: 4304
|
||||
time: '2023-07-23T03:18:06.0000000+00:00'
|
||||
- author: EmoGarbage404
|
||||
changes:
|
||||
- {message: Midround anomaly spawns no longer have a high chance of spawning in
|
||||
escape pods., type: Fix}
|
||||
id: 4305
|
||||
time: '2023-07-23T03:57:13.0000000+00:00'
|
||||
- author: FillerVK
|
||||
changes:
|
||||
- {message: Departure Terminal update., type: Tweak}
|
||||
id: 4306
|
||||
time: '2023-07-23T05:32:04.0000000+00:00'
|
||||
- author: Flareguy
|
||||
changes:
|
||||
- {message: Changed the roundstart traitor sound effect back to the old one., type: Tweak}
|
||||
id: 4307
|
||||
time: '2023-07-23T05:53:01.0000000+00:00'
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
cuffable-component-cannot-interact-message = You can't do that!
|
||||
cuffable-component-cannot-remove-cuffs-too-far-message = You are too far away to remove the cuffs.
|
||||
cuffable-component-cannot-remove-cuffs-too-far-message = You are too far away to remove the restraints.
|
||||
|
||||
cuffable-component-start-uncuffing-self = You start to painfully wriggle out of your cuffs.
|
||||
cuffable-component-start-uncuffing-observer = {$user} starts uncuffing {$target}!
|
||||
cuffable-component-start-uncuffing-target-message = You start uncuffing {$targetName}.
|
||||
cuffable-component-start-uncuffing-by-other-message = {$otherName} starts uncuffing you!
|
||||
cuffable-component-start-uncuffing-self = You start to painfully wriggle out of your restraints.
|
||||
cuffable-component-start-uncuffing-observer = {$user} starts unrestraining {$target}!
|
||||
cuffable-component-start-uncuffing-target-message = You start unrestraining {$targetName}.
|
||||
cuffable-component-start-uncuffing-by-other-message = {$otherName} starts unrestraining you!
|
||||
|
||||
cuffable-component-remove-cuffs-success-message = You successfully remove the cuffs.
|
||||
cuffable-component-remove-cuffs-by-other-success-message = {$otherName} uncuffs your hands.
|
||||
cuffable-component-remove-cuffs-to-other-partial-success-message = You successfully remove the cuffs. {$cuffedHandCount} of {$otherName}'s hands remain cuffed.
|
||||
cuffable-component-remove-cuffs-by-other-partial-success-message = {$otherName} removes your cuffs. {$cuffedHandCount} of your hands remain cuffed.
|
||||
cuffable-component-remove-cuffs-partial-success-message = You successfully remove the cuffs. {$cuffedHandCount} of your hands remain cuffed.
|
||||
cuffable-component-remove-cuffs-fail-message = You fail to remove the cuffs.
|
||||
cuffable-component-remove-cuffs-success-message = You successfully remove the restraints.
|
||||
cuffable-component-remove-cuffs-by-other-success-message = {$otherName} unrestrains your hands.
|
||||
cuffable-component-remove-cuffs-to-other-partial-success-message = You successfully remove the restraints. {$cuffedHandCount} of {$otherName}'s hands remain restrained.
|
||||
cuffable-component-remove-cuffs-by-other-partial-success-message = {$otherName} removes your restraints. {$cuffedHandCount} of your hands remain restrained.
|
||||
cuffable-component-remove-cuffs-partial-success-message = You successfully remove the restraints. {$cuffedHandCount} of your hands remain restrained.
|
||||
cuffable-component-remove-cuffs-fail-message = You fail to remove the restraints.
|
||||
|
||||
# UncuffVerb
|
||||
uncuff-verb-get-data-text = Uncuff
|
||||
# UnrestrainVerb
|
||||
uncuff-verb-get-data-text = Unrestrain
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
handcuff-component-target-self = You start cuffing yourself.
|
||||
handcuff-component-cuffs-broken-error = The cuffs are broken!
|
||||
handcuff-component-target-self = You start restraining yourself.
|
||||
handcuff-component-cuffs-broken-error = The restraints are broken!
|
||||
handcuff-component-target-has-no-hands-error = {$targetName} has no hands!
|
||||
handcuff-component-target-has-no-free-hands-error = {$targetName} has no free hands!
|
||||
handcuff-component-too-far-away-error = You are too far away to use the cuffs!
|
||||
handcuff-component-start-cuffing-observer = {$user} starts cuffing {$target}!
|
||||
handcuff-component-start-cuffing-target-message = You start cuffing {$targetName}.
|
||||
handcuff-component-start-cuffing-by-other-message = {$otherName} starts cuffing you!
|
||||
handcuff-component-cuff-observer-success-message = {$user} cuffs {$target}.
|
||||
handcuff-component-cuff-other-success-message = You successfully cuff {$otherName}.
|
||||
handcuff-component-cuff-by-other-success-message = You have been cuffed by {$otherName}!
|
||||
handcuff-component-cuff-self-success-message = You cuff yourself.
|
||||
handcuff-component-cuff-interrupt-message = You were interrupted while cuffing {$targetName}!
|
||||
handcuff-component-cuff-interrupt-other-message = You interrupt {$otherName} while they are cuffing you!
|
||||
handcuff-component-cuff-interrupt-self-message = You were interrupted while cuffing yourself.
|
||||
handcuff-component-cuff-interrupt-buckled-message = You can't buckle while cuffed!
|
||||
handcuff-component-cuff-interrupt-unbuckled-message = You can't unbuckle while cuffed!
|
||||
handcuff-component-too-far-away-error = You are too far away to use the restraints!
|
||||
handcuff-component-start-cuffing-observer = {$user} starts restraining {$target}!
|
||||
handcuff-component-start-cuffing-target-message = You start restraining {$targetName}.
|
||||
handcuff-component-start-cuffing-by-other-message = {$otherName} starts restraining you!
|
||||
handcuff-component-cuff-observer-success-message = {$user} restrains {$target}.
|
||||
handcuff-component-cuff-other-success-message = You successfully restrain {$otherName}.
|
||||
handcuff-component-cuff-by-other-success-message = You have been restrained by {$otherName}!
|
||||
handcuff-component-cuff-self-success-message = You restrain yourself.
|
||||
handcuff-component-cuff-interrupt-message = You were interrupted while unrestraining {$targetName}!
|
||||
handcuff-component-cuff-interrupt-other-message = You interrupt {$otherName} while they are restraining you!
|
||||
handcuff-component-cuff-interrupt-self-message = You were interrupted while unrestraining yourself.
|
||||
handcuff-component-cuff-interrupt-buckled-message = You can't buckle while restrained!
|
||||
handcuff-component-cuff-interrupt-unbuckled-message = You can't unbuckle while restrained!
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -87,7 +87,7 @@
|
||||
name: nitrogen tank
|
||||
components:
|
||||
- type: GasTank
|
||||
outputPressure: 101.325
|
||||
outputPressure: 21.27825
|
||||
air:
|
||||
volume: 15
|
||||
moles:
|
||||
|
||||
@@ -128,7 +128,7 @@
|
||||
- id: WeaponRevolverInspector
|
||||
- id: DrinkDetFlask
|
||||
- id: SpeedLoaderMagnum
|
||||
- id: ForensicGloves
|
||||
- id: ClothingHandsGlovesForensic
|
||||
|
||||
- type: entity
|
||||
id: ClosetBombFilled
|
||||
|
||||
@@ -343,7 +343,7 @@
|
||||
|
||||
- type: entity
|
||||
parent: ClothingHandsBase
|
||||
id: ForensicGloves
|
||||
id: ClothingHandsGlovesForensic
|
||||
name: forensic gloves
|
||||
description: Do not leave fibers or fingerprints. If you work without them, you're A TERRIBLE DETECTIVE.
|
||||
components:
|
||||
@@ -352,4 +352,3 @@
|
||||
- type: Clothing
|
||||
sprite: Clothing/Hands/Gloves/forensic.rsi
|
||||
- type: FingerprintMask
|
||||
|
||||
|
||||
@@ -145,17 +145,6 @@
|
||||
- type: Clothing
|
||||
sprite: Clothing/OuterClothing/Misc/santa.rsi
|
||||
|
||||
- type: entity
|
||||
parent: ClothingOuterBase
|
||||
id: ClothingOuterStraightjacket
|
||||
name: straight jacket
|
||||
description: A straight jacket.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/OuterClothing/Misc/straight_jacket.rsi
|
||||
- type: Clothing
|
||||
sprite: Clothing/OuterClothing/Misc/straight_jacket.rsi
|
||||
|
||||
# Is this wizard wearing a fanny pack???
|
||||
- type: entity
|
||||
parent: ClothingOuterBase
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
150: Dead
|
||||
- type: Stamina
|
||||
excess: 150
|
||||
- type: MovementAlwaysTouching
|
||||
- type: Bloodstream
|
||||
bloodMaxVolume: 300
|
||||
bloodReagent: Cryoxadone
|
||||
|
||||
@@ -120,11 +120,6 @@
|
||||
- map: ["enum.HumanoidVisualLayers.RFoot"]
|
||||
- map: ["enum.HumanoidVisualLayers.LHand"]
|
||||
- map: ["enum.HumanoidVisualLayers.RHand"]
|
||||
- map: ["enum.HumanoidVisualLayers.Handcuffs"]
|
||||
color: "#ffffff"
|
||||
sprite: Objects/Misc/handcuffs.rsi
|
||||
state: body-overlay-2
|
||||
visible: false
|
||||
- map: [ "id" ]
|
||||
- map: [ "gloves" ]
|
||||
- map: [ "shoes" ]
|
||||
@@ -143,6 +138,11 @@
|
||||
- map: [ "head" ]
|
||||
- map: [ "pocket1" ]
|
||||
- map: [ "pocket2" ]
|
||||
- map: ["enum.HumanoidVisualLayers.Handcuffs"]
|
||||
color: "#ffffff"
|
||||
sprite: Objects/Misc/handcuffs.rsi
|
||||
state: body-overlay-2
|
||||
visible: false
|
||||
- map: [ "clownedon" ] # Dynamically generated
|
||||
sprite: "Effects/creampie.rsi"
|
||||
state: "creampie_human"
|
||||
|
||||
@@ -117,3 +117,24 @@
|
||||
sprite: Objects/Misc/cablecuffs.rsi
|
||||
state: cuff-broken
|
||||
color: forestgreen
|
||||
|
||||
- type: entity
|
||||
parent: Handcuffs
|
||||
id: ClothingOuterStraightjacket
|
||||
name: straitjacket
|
||||
description: Used to restrain those who may cause harm to themselves or others.
|
||||
components:
|
||||
- type: Item
|
||||
size: 20
|
||||
- type: Handcuff
|
||||
cuffedRSI: Clothing/OuterClothing/Misc/straight_jacket.rsi
|
||||
breakoutTime: 100
|
||||
damageOnResist:
|
||||
types:
|
||||
Blunt: 0
|
||||
cuffTime: 10
|
||||
uncuffTime: 10
|
||||
stunBonus: 4
|
||||
- type: Sprite
|
||||
sprite: Clothing/OuterClothing/Misc/straight_jacket.rsi
|
||||
state: icon
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
map: ["enum.GunVisualLayers.Base"]
|
||||
- type: Clothing
|
||||
sprite: Objects/Weapons/Guns/Launchers/china_lake.rsi
|
||||
- type: AmmoCounter
|
||||
- type: Gun
|
||||
fireRate: 1
|
||||
selectedMode: SemiAuto
|
||||
|
||||
@@ -66,6 +66,7 @@
|
||||
slots:
|
||||
- Back
|
||||
- suitStorage
|
||||
- type: AmmoCounter
|
||||
- type: Gun
|
||||
fireRate: 2
|
||||
selectedMode: FullAuto
|
||||
|
||||
@@ -6,11 +6,9 @@
|
||||
components:
|
||||
- type: HealOnBuckle
|
||||
damage:
|
||||
groups:
|
||||
Brute: -0.2 ## 0.1 per
|
||||
Burn: -0.2
|
||||
types:
|
||||
Poison: -0.1
|
||||
Blunt: -0.1
|
||||
- type: Physics
|
||||
bodyType: Static
|
||||
- type: Fixtures
|
||||
@@ -70,11 +68,10 @@
|
||||
state: bed-MED
|
||||
- type: HealOnBuckle
|
||||
damage:
|
||||
groups:
|
||||
Brute: -0.4 ## 0.2 per
|
||||
Burn: -0.4
|
||||
types:
|
||||
Poison: -0.2
|
||||
Cold: -0.4
|
||||
Blunt: -0.2
|
||||
- type: Construction
|
||||
graph: bed
|
||||
node: medicalbed
|
||||
|
||||
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
@@ -11,7 +11,7 @@
|
||||
"name": "icon"
|
||||
},
|
||||
{
|
||||
"name": "equipped-OUTERCLOTHING",
|
||||
"name": "body-overlay-2",
|
||||
"directions": 4
|
||||
},
|
||||
{
|
||||
|
||||
@@ -108,3 +108,6 @@ Intercom: IntercomCommon
|
||||
|
||||
# 2023-07-12
|
||||
ToyAssistant: ToyFigurinePassenger
|
||||
|
||||
# 2023-07-20
|
||||
ForensicGloves: ClothingHandsGlovesForensic
|
||||
|
||||
Submodule RobustToolbox updated: bbc4668f9c...c52db4d3f2
@@ -72,7 +72,6 @@ SERVER_CONTENT_ASSEMBLIES = [
|
||||
SERVER_EXTRA_ASSEMBLIES = [
|
||||
"Npgsql.",
|
||||
"Microsoft",
|
||||
"System.Linq.Async",
|
||||
]
|
||||
|
||||
SERVER_NOT_EXTRA_ASSEMBLIES = [
|
||||
|
||||
Reference in New Issue
Block a user