Merge remote-tracking branch 'upstream/master' into upstream-sync

This commit is contained in:
Morbo 2022-12-25 20:25:04 +03:00
commit 13d74575f3
260 changed files with 6147 additions and 3330 deletions

View file

@ -1,8 +1,4 @@
using System;
using Content.Shared.Administration;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Log;
using Robust.Shared.Network;
using Robust.Shared.Prototypes;
@ -21,19 +17,20 @@ public sealed class GamePrototypeLoadManager : IGamePrototypeLoadManager
private void LoadGamePrototype(GamePrototypeLoadMessage message)
{
_prototypeManager.LoadString(message.PrototypeData, true);
var changed = new Dictionary<Type, HashSet<string>>();
_prototypeManager.LoadString(message.PrototypeData, true, changed);
_prototypeManager.ResolveResults();
_prototypeManager.ReloadPrototypes(changed);
_localizationManager.ReloadLocalizations();
GamePrototypeLoaded?.Invoke();
Logger.InfoS("adminbus", "Loaded adminbus prototype data.");
}
public void SendGamePrototype(string prototype)
{
var msg = _netManager.CreateNetMessage<GamePrototypeLoadMessage>();
msg.PrototypeData = prototype;
var msg = new GamePrototypeLoadMessage
{
PrototypeData = prototype
};
_netManager.ClientSendMessage(msg);
}
public event Action? GamePrototypeLoaded;
}

View file

@ -1,11 +0,0 @@
using Content.Shared.Buckle.Components;
namespace Content.Client.Buckle;
[RegisterComponent]
[ComponentReference(typeof(SharedBuckleComponent))]
[Access(typeof(BuckleSystem))]
public sealed class BuckleComponent : SharedBuckleComponent
{
public int? OriginalDrawDepth { get; set; }
}

View file

@ -1,4 +1,3 @@
using Content.Client.Buckle.Strap;
using Content.Client.Rotation;
using Content.Shared.ActionBlocker;
using Content.Shared.Buckle;
@ -12,15 +11,14 @@ namespace Content.Client.Buckle
internal sealed class BuckleSystem : SharedBuckleSystem
{
[Dependency] private readonly ActionBlockerSystem _actionBlocker = default!;
[Dependency] private readonly AppearanceSystem AppearanceSystem = default!;
[Dependency] private readonly RotationVisualizerSystem RotationVisualizerSystem = default!;
[Dependency] private readonly AppearanceSystem _appearanceSystem = default!;
[Dependency] private readonly RotationVisualizerSystem _rotationVisualizerSystem = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<BuckleComponent, ComponentHandleState>(OnBuckleHandleState);
SubscribeLocalEvent<StrapComponent, ComponentHandleState>(OnStrapHandleState);
SubscribeLocalEvent<BuckleComponent, AppearanceChangeEvent>(OnAppearanceChange);
}
@ -65,22 +63,10 @@ namespace Content.Client.Buckle
}
}
private void OnStrapHandleState(EntityUid uid, StrapComponent component, ref ComponentHandleState args)
{
if (args.Current is not StrapComponentState state)
return;
component.Position = state.Position;
component.BuckleOffsetUnclamped = state.BuckleOffsetClamped;
component.BuckledEntities.Clear();
component.BuckledEntities.UnionWith(state.BuckledEntities);
component.MaxBuckleDistance = state.MaxBuckleDistance;
}
private void OnAppearanceChange(EntityUid uid, BuckleComponent component, ref AppearanceChangeEvent args)
{
if (!AppearanceSystem.TryGetData<int>(uid, StrapVisuals.RotationAngle, out var angle, args.Component) ||
!AppearanceSystem.TryGetData<bool>(uid, BuckleVisuals.Buckled, out var buckled, args.Component) ||
if (!_appearanceSystem.TryGetData<int>(uid, StrapVisuals.RotationAngle, out var angle, args.Component) ||
!_appearanceSystem.TryGetData<bool>(uid, BuckleVisuals.Buckled, out var buckled, args.Component) ||
!buckled ||
args.Sprite == null)
{
@ -88,7 +74,7 @@ namespace Content.Client.Buckle
}
// Animate strapping yourself to something at a given angle
RotationVisualizerSystem.AnimateSpriteRotation(args.Sprite, Angle.FromDegrees(angle), 0.125f);
_rotationVisualizerSystem.AnimateSpriteRotation(args.Sprite, Angle.FromDegrees(angle), 0.125f);
}
}
}

View file

@ -1,10 +0,0 @@
using Content.Shared.Buckle.Components;
namespace Content.Client.Buckle.Strap;
[RegisterComponent]
[ComponentReference(typeof(SharedStrapComponent))]
[Access(typeof(BuckleSystem))]
public sealed class StrapComponent : SharedStrapComponent
{
}

View file

@ -6,10 +6,3 @@ public sealed class CartridgeLoaderSystem : SharedCartridgeLoaderSystem
{
//Empty client system for component replication
}
[RegisterComponent]
[ComponentReference(typeof(SharedCartridgeLoaderComponent))]
public sealed class CartridgeLoaderComponent : SharedCartridgeLoaderComponent
{
}

View file

@ -2,7 +2,7 @@
using System.Text.RegularExpressions;
using Robust.Client.GameObjects;
using Robust.Shared.GameObjects;
using static Content.Shared.Configurable.SharedConfigurationComponent;
using static Content.Shared.Configurable.ConfigurationComponent;
namespace Content.Client.Configurable.UI
{

View file

@ -4,7 +4,7 @@ using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.Localization;
using Robust.Shared.Maths;
using static Content.Shared.Configurable.SharedConfigurationComponent;
using static Content.Shared.Configurable.ConfigurationComponent;
using static Robust.Client.UserInterface.Controls.BaseButton;
using static Robust.Client.UserInterface.Controls.BoxContainer;

View file

@ -20,7 +20,7 @@ public sealed partial class DecalPlacerWindow : DefaultWindow
private PaletteColorPicker? _picker;
private Dictionary<string, Texture>? _decals;
private SortedDictionary<string, Texture>? _decals;
private string? _selected;
private Color _color = Color.White;
private bool _useColor;
@ -170,7 +170,7 @@ public sealed partial class DecalPlacerWindow : DefaultWindow
public void Populate(IEnumerable<DecalPrototype> prototypes)
{
_decals = new Dictionary<string, Texture>();
_decals = new SortedDictionary<string, Texture>();
foreach (var decalPrototype in prototypes)
{
if (decalPrototype.ShowMenu)

View file

@ -1,13 +0,0 @@
using Content.Shared.Ensnaring.Components;
namespace Content.Client.Ensnaring.Components;
[RegisterComponent]
[ComponentReference(typeof(SharedEnsnareableComponent))]
public sealed class EnsnareableComponent : SharedEnsnareableComponent
{
[DataField("sprite")]
public string? Sprite;
[DataField("state")]
public string? State;
}

View file

@ -1,9 +1,3 @@
using Content.Shared.Ensnaring.Components;
namespace Content.Client.Ensnaring.Components;
[RegisterComponent]
[ComponentReference(typeof(SharedEnsnaringComponent))]
public sealed class EnsnaringComponent : SharedEnsnaringComponent
{
}

View file

@ -1,5 +1,5 @@
using Content.Client.Ensnaring.Components;
using Content.Shared.Ensnaring;
using Content.Shared.Ensnaring.Components;
using Robust.Client.GameObjects;
namespace Content.Client.Ensnaring.Visualizers;

View file

@ -1,9 +1,7 @@
using Content.Shared.Flash;
using Robust.Client.Graphics;
using Robust.Client.Player;
using Robust.Shared.GameObjects;
using Robust.Shared.GameStates;
using Robust.Shared.IoC;
using Robust.Shared.Timing;
namespace Content.Client.Flash

View file

@ -1,12 +0,0 @@
using Content.Shared.Flash;
using Robust.Shared.Analyzers;
using Robust.Shared.GameObjects;
namespace Content.Client.Flash
{
[ComponentReference(typeof(SharedFlashableComponent))]
[RegisterComponent, Access(typeof(FlashSystem))]
public sealed class FlashableComponent : SharedFlashableComponent
{
}
}

View file

@ -1,15 +0,0 @@
using Content.Shared.Humanoid;
using Content.Shared.Humanoid.Markings;
using Content.Shared.Humanoid.Prototypes;
namespace Content.Client.Humanoid;
[RegisterComponent]
public sealed class HumanoidComponent : SharedHumanoidComponent
{
[ViewVariables] public List<Marking> CurrentMarkings = new();
public Dictionary<HumanoidVisualLayers, HumanoidSpeciesSpriteLayer> BaseLayers = new();
public string LastSpecies = default!;
}

View file

@ -108,23 +108,23 @@ public sealed class HumanoidVisualizerSystem : VisualizerSystem<HumanoidComponen
SpriteComponent sprite)
{
// skip this entire thing if both sets are empty
if (humanoid.CurrentMarkings.Count == 0 && newMarkings.Count == 0)
if (humanoid.CurrentClientMarkings.Count == 0 && newMarkings.Count == 0)
{
return;
}
var dirtyMarkings = new List<int>();
var dirtyRangeStart = humanoid.CurrentMarkings.Count == 0 ? 0 : -1;
var dirtyRangeStart = humanoid.CurrentClientMarkings.Count == 0 ? 0 : -1;
// edge cases:
// humanoid.CurrentMarkings < newMarkings.Count
// humanoid.CurrentClientMarkings < newMarkings.Count
// - check if count matches this condition before diffing
// - if count is unequal, set dirty range to start from humanoid.CurrentMarkings.Count
// humanoid.CurrentMarkings > newMarkings.Count, no dirty markings
// - if count is unequal, set dirty range to start from humanoid.CurrentClientMarkings.Count
// humanoid.CurrentClientMarkings > newMarkings.Count, no dirty markings
// - break count upon meeting this condition
// - clear markings from newMarkings.Count to humanoid.CurrentMarkings.Count - newMarkings.Count
// - clear markings from newMarkings.Count to humanoid.CurrentClientMarkings.Count - newMarkings.Count
for (var i = 0; i < humanoid.CurrentMarkings.Count; i++)
for (var i = 0; i < humanoid.CurrentClientMarkings.Count; i++)
{
// if we've reached the end of the new set of markings,
// then that means it's time to finish
@ -135,7 +135,7 @@ public sealed class HumanoidVisualizerSystem : VisualizerSystem<HumanoidComponen
// if the marking is different here, set the range start to i and break, we need
// to rebuild all markings starting from i
if (humanoid.CurrentMarkings[i].MarkingId != newMarkings[i].MarkingId)
if (humanoid.CurrentClientMarkings[i].MarkingId != newMarkings[i].MarkingId)
{
dirtyRangeStart = i;
break;
@ -146,7 +146,7 @@ public sealed class HumanoidVisualizerSystem : VisualizerSystem<HumanoidComponen
// however: if the hidden layers are set to dirty, then we need to
// instead just add every single marking, since we don't know ahead of time
// where these markings go
if (humanoid.CurrentMarkings[i] != newMarkings[i] || layersDirty)
if (humanoid.CurrentClientMarkings[i] != newMarkings[i] || layersDirty)
{
dirtyMarkings.Add(i);
}
@ -162,49 +162,49 @@ public sealed class HumanoidVisualizerSystem : VisualizerSystem<HumanoidComponen
ApplyMarking(uid, dirtyMarking, newMarkings[i].MarkingColors, newMarkings[i].Visible, humanoid, sprite);
}
if (humanoid.CurrentMarkings.Count < newMarkings.Count && dirtyRangeStart < 0)
if (humanoid.CurrentClientMarkings.Count < newMarkings.Count && dirtyRangeStart < 0)
{
dirtyRangeStart = humanoid.CurrentMarkings.Count;
dirtyRangeStart = humanoid.CurrentClientMarkings.Count;
}
if (dirtyRangeStart >= 0)
{
var range = newMarkings.GetRange(dirtyRangeStart, newMarkings.Count - dirtyRangeStart);
if (humanoid.CurrentMarkings.Count > 0)
if (humanoid.CurrentClientMarkings.Count > 0)
{
var oldRange = humanoid.CurrentMarkings.GetRange(dirtyRangeStart, humanoid.CurrentMarkings.Count - dirtyRangeStart);
var oldRange = humanoid.CurrentClientMarkings.GetRange(dirtyRangeStart, humanoid.CurrentClientMarkings.Count - dirtyRangeStart);
ClearMarkings(uid, oldRange, humanoid, sprite);
}
ApplyMarkings(uid, range, humanoid, sprite);
}
else if (humanoid.CurrentMarkings.Count != newMarkings.Count)
else if (humanoid.CurrentClientMarkings.Count != newMarkings.Count)
{
if (newMarkings.Count == 0)
{
ClearAllMarkings(uid, humanoid, sprite);
}
else if (humanoid.CurrentMarkings.Count > newMarkings.Count)
else if (humanoid.CurrentClientMarkings.Count > newMarkings.Count)
{
var rangeStart = newMarkings.Count;
var rangeCount = humanoid.CurrentMarkings.Count - newMarkings.Count;
var range = humanoid.CurrentMarkings.GetRange(rangeStart, rangeCount);
var rangeCount = humanoid.CurrentClientMarkings.Count - newMarkings.Count;
var range = humanoid.CurrentClientMarkings.GetRange(rangeStart, rangeCount);
ClearMarkings(uid, range, humanoid, sprite);
}
}
if (dirtyMarkings.Count > 0 || dirtyRangeStart >= 0 || humanoid.CurrentMarkings.Count != newMarkings.Count)
if (dirtyMarkings.Count > 0 || dirtyRangeStart >= 0 || humanoid.CurrentClientMarkings.Count != newMarkings.Count)
{
humanoid.CurrentMarkings = newMarkings;
humanoid.CurrentClientMarkings = newMarkings;
}
}
private void ClearAllMarkings(EntityUid uid, HumanoidComponent humanoid,
SpriteComponent spriteComp)
{
ClearMarkings(uid, humanoid.CurrentMarkings, humanoid, spriteComp);
ClearMarkings(uid, humanoid.CurrentClientMarkings, humanoid, spriteComp);
}
private void ClearMarkings(EntityUid uid, List<Marking> markings, HumanoidComponent humanoid,

View file

@ -120,7 +120,7 @@ namespace Content.Client.Inventory
}
// snare-removal button. This is just the old button before the change to item slots. It is pretty out of place.
if (_entMan.TryGetComponent(Owner.Owner, out SharedEnsnareableComponent? snare) && snare.IsEnsnared)
if (_entMan.TryGetComponent(Owner.Owner, out EnsnareableComponent? snare) && snare.IsEnsnared)
{
var button = new Button()
{

View file

@ -0,0 +1,7 @@
using Content.Shared.DragDrop;
using Content.Shared.Medical.Cryogenics;
namespace Content.Client.Medical.Cryogenics;
[RegisterComponent]
public sealed class CryoPodComponent : SharedCryoPodComponent { }

View file

@ -0,0 +1,83 @@
using Content.Shared.Destructible;
using Content.Shared.Emag.Systems;
using Content.Shared.Medical.Cryogenics;
using Content.Shared.Verbs;
using Robust.Client.GameObjects;
using DrawDepth = Content.Shared.DrawDepth.DrawDepth;
namespace Content.Client.Medical.Cryogenics;
public sealed class CryoPodSystem: SharedCryoPodSystem
{
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<CryoPodComponent, ComponentInit>(OnComponentInit);
SubscribeLocalEvent<CryoPodComponent, GetVerbsEvent<AlternativeVerb>>(AddAlternativeVerbs);
SubscribeLocalEvent<CryoPodComponent, GotEmaggedEvent>(OnEmagged);
SubscribeLocalEvent<CryoPodComponent, DoInsertCryoPodEvent>(DoInsertCryoPod);
SubscribeLocalEvent<CryoPodComponent, DoInsertCancelledCryoPodEvent>(DoInsertCancelCryoPod);
SubscribeLocalEvent<CryoPodComponent, CryoPodPryFinished>(OnCryoPodPryFinished);
SubscribeLocalEvent<CryoPodComponent, CryoPodPryInterrupted>(OnCryoPodPryInterrupted);
SubscribeLocalEvent<CryoPodComponent, AppearanceChangeEvent>(OnAppearanceChange);
SubscribeLocalEvent<InsideCryoPodComponent, ComponentStartup>(OnCryoPodInsertion);
SubscribeLocalEvent<InsideCryoPodComponent, ComponentRemove>(OnCryoPodRemoval);
}
private void OnCryoPodInsertion(EntityUid uid, InsideCryoPodComponent component, ComponentStartup args)
{
if (!TryComp<SpriteComponent>(uid, out var spriteComponent))
{
return;
}
component.PreviousOffset = spriteComponent.Offset;
spriteComponent.Offset = new Vector2(0, 1);
}
private void OnCryoPodRemoval(EntityUid uid, InsideCryoPodComponent component, ComponentRemove args)
{
if (!TryComp<SpriteComponent>(uid, out var spriteComponent))
{
return;
}
spriteComponent.Offset = component.PreviousOffset;
}
private void OnAppearanceChange(EntityUid uid, SharedCryoPodComponent component, ref AppearanceChangeEvent args)
{
if (args.Sprite == null)
{
return;
}
if (!args.Component.TryGetData(SharedCryoPodComponent.CryoPodVisuals.ContainsEntity, out bool isOpen)
|| !args.Component.TryGetData(SharedCryoPodComponent.CryoPodVisuals.IsOn, out bool isOn))
{
return;
}
if (isOpen)
{
args.Sprite.LayerSetState(CryoPodVisualLayers.Base, "pod-open");
args.Sprite.LayerSetVisible(CryoPodVisualLayers.Cover, false);
args.Sprite.DrawDepth = (int) DrawDepth.Objects;
}
else
{
args.Sprite.DrawDepth = (int) DrawDepth.Mobs;
args.Sprite.LayerSetState(CryoPodVisualLayers.Base, isOn ? "pod-on" : "pod-off");
args.Sprite.LayerSetState(CryoPodVisualLayers.Cover, isOn ? "cover-on" : "cover-off");
args.Sprite.LayerSetVisible(CryoPodVisualLayers.Cover, true);
}
}
}
public enum CryoPodVisualLayers : byte
{
Base,
Cover,
}

View file

@ -1,9 +0,0 @@
using Content.Client.Movement.Systems;
using Content.Shared.Climbing;
namespace Content.Client.Movement.Components;
[RegisterComponent]
[Access(typeof(ClimbSystem))]
[ComponentReference(typeof(SharedClimbableComponent))]
public sealed class ClimbableComponent : SharedClimbableComponent { }

View file

@ -1,9 +0,0 @@
using Content.Client.Movement.Systems;
using Content.Shared.Climbing;
namespace Content.Client.Movement.Components;
[RegisterComponent]
[Access(typeof(ClimbSystem))]
[ComponentReference(typeof(SharedClimbingComponent))]
public sealed class ClimbingComponent : SharedClimbingComponent { }

View file

@ -1,5 +1,4 @@
using Content.Client.Interactable;
using Content.Client.Movement.Components;
using Content.Shared.Climbing;
using Content.Shared.DragDrop;
using Robust.Shared.GameStates;
@ -18,14 +17,14 @@ public sealed class ClimbSystem : SharedClimbSystem
private static void OnClimbingState(EntityUid uid, ClimbingComponent component, ref ComponentHandleState args)
{
if (args.Current is not SharedClimbingComponent.ClimbModeComponentState climbModeState)
if (args.Current is not ClimbingComponent.ClimbModeComponentState climbModeState)
return;
component.IsClimbing = climbModeState.Climbing;
component.OwnerIsTransitioning = climbModeState.IsTransitioning;
}
protected override void OnCanDragDropOn(EntityUid uid, SharedClimbableComponent component, CanDragDropOnEvent args)
protected override void OnCanDragDropOn(EntityUid uid, ClimbableComponent component, CanDragDropOnEvent args)
{
base.OnCanDragDropOn(uid, component, args);

View file

@ -1,6 +1,10 @@
using Content.Shared.CCVar;
using Content.Shared.Popups;
using Robust.Client.Graphics;
using Robust.Client.ResourceManagement;
using Robust.Client.UserInterface;
using Robust.Shared;
using Robust.Shared.Configuration;
using Robust.Shared.Enums;
using Robust.Shared.Prototypes;
@ -11,7 +15,9 @@ namespace Content.Client.Popups;
/// </summary>
public sealed class PopupOverlay : Overlay
{
private readonly IConfigurationManager _configManager;
private readonly IEntityManager _entManager;
private readonly IUserInterfaceManager _uiManager;
private readonly PopupSystem _popup;
private readonly ShaderInstance _shader;
@ -21,9 +27,17 @@ public sealed class PopupOverlay : Overlay
public override OverlaySpace Space => OverlaySpace.ScreenSpace;
public PopupOverlay(IEntityManager entManager, IPrototypeManager protoManager, IResourceCache cache, PopupSystem popup)
public PopupOverlay(
IConfigurationManager configManager,
IEntityManager entManager,
IPrototypeManager protoManager,
IResourceCache cache,
IUserInterfaceManager uiManager,
PopupSystem popup)
{
_configManager = configManager;
_entManager = entManager;
_uiManager = uiManager;
_popup = popup;
_shader = protoManager.Index<ShaderPrototype>("unshaded").Instance();
@ -39,14 +53,18 @@ public sealed class PopupOverlay : Overlay
args.DrawingHandle.SetTransform(Matrix3.Identity);
args.DrawingHandle.UseShader(_shader);
var scale = _configManager.GetCVar(CVars.DisplayUIScale);
DrawWorld(args.ScreenHandle, args);
DrawScreen(args.ScreenHandle, args);
if (scale == 0f)
scale = _uiManager.DefaultUIScale;
DrawWorld(args.ScreenHandle, args, scale);
DrawScreen(args.ScreenHandle, args, scale);
args.DrawingHandle.UseShader(null);
}
private void DrawWorld(DrawingHandleScreen worldHandle, OverlayDrawArgs args)
private void DrawWorld(DrawingHandleScreen worldHandle, OverlayDrawArgs args, float scale)
{
if (_popup.WorldLabels.Count == 0)
return;
@ -64,11 +82,11 @@ public sealed class PopupOverlay : Overlay
continue;
var pos = matrix.Transform(mapPos.Position);
DrawPopup(popup, worldHandle, pos);
DrawPopup(popup, worldHandle, pos, scale);
}
}
private void DrawScreen(DrawingHandleScreen screenHandle, OverlayDrawArgs args)
private void DrawScreen(DrawingHandleScreen screenHandle, OverlayDrawArgs args, float scale)
{
foreach (var popup in _popup.CursorLabels)
{
@ -76,18 +94,17 @@ public sealed class PopupOverlay : Overlay
if (popup.InitialPos.Window != args.ViewportControl?.Window?.Id)
continue;
DrawPopup(popup, screenHandle, popup.InitialPos.Position);
DrawPopup(popup, screenHandle, popup.InitialPos.Position, scale);
}
}
private void DrawPopup(PopupSystem.PopupLabel popup, DrawingHandleScreen handle, Vector2 position)
private void DrawPopup(PopupSystem.PopupLabel popup, DrawingHandleScreen handle, Vector2 position, float scale)
{
const float alphaMinimum = 0.5f;
var alpha = MathF.Min(1f, 1f - (popup.TotalTime - alphaMinimum) / (PopupSystem.PopupLifetime - alphaMinimum));
var updatedPosition = position - new Vector2(0f, 20f * (popup.TotalTime * popup.TotalTime + popup.TotalTime));
var font = _smallFont;
var dimensions = Vector2.Zero;
var color = Color.White.WithAlpha(alpha);
switch (popup.Type)
@ -113,7 +130,7 @@ public sealed class PopupOverlay : Overlay
break;
}
dimensions = handle.GetDimensions(font, popup.Text, 1f);
handle.DrawString(font, updatedPosition - dimensions / 2f, popup.Text, color.WithAlpha(alpha));
var dimensions = handle.GetDimensions(font, popup.Text, scale);
handle.DrawString(font, updatedPosition - dimensions / 2f, popup.Text, scale, color.WithAlpha(alpha));
}
}

View file

@ -4,6 +4,8 @@ using Robust.Client.Graphics;
using Robust.Client.Input;
using Robust.Client.Player;
using Robust.Client.ResourceManagement;
using Robust.Client.UserInterface;
using Robust.Shared.Configuration;
using Robust.Shared.Map;
using Robust.Shared.Player;
using Robust.Shared.Players;
@ -14,11 +16,13 @@ namespace Content.Client.Popups
{
public sealed class PopupSystem : SharedPopupSystem
{
[Dependency] private readonly IConfigurationManager _configManager = default!;
[Dependency] private readonly IInputManager _inputManager = default!;
[Dependency] private readonly IOverlayManager _overlay = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IPrototypeManager _prototype = default!;
[Dependency] private readonly IResourceCache _resource = default!;
[Dependency] private readonly IUserInterfaceManager _uiManager = default!;
public IReadOnlyList<WorldPopupLabel> WorldLabels => _aliveWorldLabels;
public IReadOnlyList<CursorPopupLabel> CursorLabels => _aliveCursorLabels;
@ -35,7 +39,7 @@ namespace Content.Client.Popups
SubscribeNetworkEvent<PopupEntityEvent>(OnPopupEntityEvent);
SubscribeNetworkEvent<RoundRestartCleanupEvent>(OnRoundRestart);
_overlay
.AddOverlay(new PopupOverlay(EntityManager, _prototype, _resource, this));
.AddOverlay(new PopupOverlay(_configManager, EntityManager, _prototype, _resource, _uiManager, this));
}
public override void Shutdown()

View file

@ -1,8 +0,0 @@
using Content.Shared.Projectiles;
namespace Content.Client.Projectiles
{
[RegisterComponent]
[ComponentReference(typeof(SharedProjectileComponent))]
public sealed class ProjectileComponent : SharedProjectileComponent {}
}

View file

@ -1,7 +0,0 @@
using Content.Shared.Singularity.Components;
namespace Content.Client.Singularity.Components;
[RegisterComponent]
[ComponentReference(typeof(SharedContainmentFieldComponent))]
public sealed class ContainmentFieldComponent : SharedContainmentFieldComponent { }

View file

@ -1,6 +0,0 @@
using Content.Shared.Singularity.Components;
namespace Content.Client.Singularity.Components;
[RegisterComponent]
[ComponentReference(typeof(SharedContainmentFieldGeneratorComponent))]
public sealed class ContainmentFieldGeneratorComponent : SharedContainmentFieldGeneratorComponent { }

View file

@ -1,13 +0,0 @@
using Content.Shared.Singularity.Components;
using Content.Client.Singularity.EntitySystems;
namespace Content.Client.Singularity.Components;
/// <summary>
/// The client-side version of <see cref="SharedSingularityComponent"/>.
/// Primarily managed by <see cref="SingularitySystem"/>.
/// </summary>
[RegisterComponent]
[ComponentReference(typeof(SharedSingularityComponent))]
public sealed class SingularityComponent : SharedSingularityComponent
{}

View file

@ -14,7 +14,7 @@ public sealed class SingularitySystem : SharedSingularitySystem
{
base.Initialize();
SubscribeLocalEvent<SharedSingularityComponent, ComponentHandleState>(HandleSingularityState);
SubscribeLocalEvent<SingularityComponent, ComponentHandleState>(HandleSingularityState);
}
/// <summary>
@ -23,7 +23,7 @@ public sealed class SingularitySystem : SharedSingularitySystem
/// <param name="uid">The uid of the singularity to sync.</param>
/// <param name="comp">The state of the singularity to sync.</param>
/// <param name="args">The event arguments including the state to sync the singularity with.</param>
private void HandleSingularityState(EntityUid uid, SharedSingularityComponent comp, ref ComponentHandleState args)
private void HandleSingularityState(EntityUid uid, SingularityComponent comp, ref ComponentHandleState args)
{
if (args.Current is not SingularityComponentState state)
return;

View file

@ -1,18 +0,0 @@
using Content.Client.Items.Components;
using Content.Client.Message;
using Content.Client.Stylesheets;
using Content.Shared.Stacks;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Timing;
namespace Content.Client.Stack
{
[RegisterComponent, Access(typeof(StackSystem), typeof(StackStatusControl))]
[ComponentReference(typeof(SharedStackComponent))]
public sealed class StackComponent : SharedStackComponent
{
[ViewVariables]
public bool UiUpdateNeeded { get; set; }
}
}

View file

@ -1,5 +1,6 @@
using Content.Client.Message;
using Content.Client.Stylesheets;
using Content.Shared.Stacks;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Timing;

View file

@ -18,7 +18,7 @@ namespace Content.Client.Stack
args.Controls.Add(new StackStatusControl(component));
}
public override void SetCount(EntityUid uid, int amount, SharedStackComponent? component = null)
public override void SetCount(EntityUid uid, int amount, StackComponent? component = null)
{
if (!Resolve(uid, ref component))
return;

View file

@ -7,17 +7,6 @@ using Robust.Shared.Timing;
namespace Content.Client.Tools.Components
{
[RegisterComponent]
[ComponentReference(typeof(SharedMultipleToolComponent))]
public sealed class MultipleToolComponent : SharedMultipleToolComponent
{
[ViewVariables(VVAccess.ReadWrite)]
public bool UiUpdateNeeded;
[DataField("statusShowBehavior")]
public bool StatusShowBehavior = true;
}
public sealed class MultipleToolStatusControl : Control
{
private readonly MultipleToolComponent _parent;

View file

@ -20,7 +20,7 @@ namespace Content.Client.Tools
}
public override void SetMultipleTool(EntityUid uid,
SharedMultipleToolComponent? multiple = null,
MultipleToolComponent? multiple = null,
ToolComponent? tool = null,
bool playSound = false,
EntityUid? user = null)
@ -29,7 +29,7 @@ namespace Content.Client.Tools
return;
base.SetMultipleTool(uid, multiple, tool, playSound, user);
((MultipleToolComponent)multiple).UiUpdateNeeded = true;
multiple.UiUpdateNeeded = true;
// TODO replace this with appearance + visualizer
// in order to convert this to a specifier, the manner in which the sprite is specified in yaml needs to be updated.

View file

@ -1,60 +0,0 @@
using Content.Shared.VendingMachines;
namespace Content.Client.VendingMachines;
[RegisterComponent]
[ComponentReference(typeof(SharedVendingMachineComponent))]
[Access(typeof(VendingMachineSystem))]
public sealed class VendingMachineComponent : SharedVendingMachineComponent
{
/// <summary>
/// RSI state for when the vending machine is unpowered.
/// Will be displayed on the layer <see cref="VendingMachineVisualLayers.Base"/>
/// </summary>
[DataField("offState")]
public string? OffState;
/// <summary>
/// RSI state for the screen of the vending machine
/// Will be displayed on the layer <see cref="VendingMachineVisualLayers.Screen"/>
/// </summary>
[DataField("screenState")]
public string? ScreenState;
/// <summary>
/// RSI state for the vending machine's normal state. Usually a looping animation.
/// Will be displayed on the layer <see cref="VendingMachineVisualLayers.BaseUnshaded"/>
/// </summary>
[DataField("normalState")]
public string? NormalState;
/// <summary>
/// RSI state for the vending machine's eject animation.
/// Will be displayed on the layer <see cref="VendingMachineVisualLayers.BaseUnshaded"/>
/// </summary>
[DataField("ejectState")]
public string? EjectState;
/// <summary>
/// RSI state for the vending machine's deny animation. Will either be played once as sprite flick
/// or looped depending on how <see cref="LoopDenyAnimation"/> is set.
/// Will be displayed on the layer <see cref="VendingMachineVisualLayers.BaseUnshaded"/>
/// </summary>
[DataField("denyState")]
public string? DenyState;
/// <summary>
/// RSI state for when the vending machine is unpowered.
/// Will be displayed on the layer <see cref="VendingMachineVisualLayers.Base"/>
/// </summary>
[DataField("brokenState")]
public string? BrokenState;
/// <summary>
/// If set to <c>true</c> (default) will loop the animation of the <see cref="DenyState"/> for the duration
/// of <see cref="SharedVendingMachineComponent.DenyDelay"/>. If set to <c>false</c> will play a sprite
/// flick animation for the state and then linger on the final frame until the end of the delay.
/// </summary>
[DataField("loopDeny")]
public bool LoopDenyAnimation = true;
}

View file

@ -137,19 +137,3 @@ public sealed class VendingMachineSystem : SharedVendingMachineSystem
sprite.LayerSetVisible(actualLayer, false);
}
}
public enum VendingMachineVisualLayers : byte
{
/// <summary>
/// Off / Broken. The other layers will overlay this if the machine is on.
/// </summary>
Base,
/// <summary>
/// Normal / Deny / Eject
/// </summary>
BaseUnshaded,
/// <summary>
/// Screens that are persistent (where the machine is not off or broken)
/// </summary>
Screen
}

View file

@ -1,9 +1,7 @@
using Content.Client.Projectiles;
using Content.Shared.Projectiles;
using Content.Shared.Weapons.Ranged.Components;
using Content.Shared.Weapons.Ranged.Systems;
using Robust.Client.Player;
using Robust.Shared.Audio;
using Robust.Shared.Physics.Dynamics;
using Robust.Shared.Physics.Events;
using Robust.Shared.Player;
using Robust.Shared.Random;

View file

@ -17,7 +17,6 @@ public sealed class TetherGunSystem : SharedTetherGunSystem
[Dependency] private readonly IEyeManager _eyeManager = default!;
[Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly IInputManager _inputManager = default!;
[Dependency] private readonly EntityLookupSystem _lookup = default!;
[Dependency] private readonly InputSystem _inputSystem = default!;
public bool Enabled { get; set; }
@ -85,15 +84,10 @@ public sealed class TetherGunSystem : SharedTetherGunSystem
if (gameState is GameplayState game)
{
EntityUid? uid;
var uid = game.GetEntityUnderPosition(mousePos);
foreach (var ent in _lookup.GetEntitiesIntersecting(mousePos, LookupFlags.Approximate | LookupFlags.Static))
{
uid = game.GetEntityUnderPosition(mousePos);
if (uid != null)
StartDragging(uid.Value, mousePos);
}
if (uid != null)
StartDragging(uid.Value, mousePos);
}
if (_dragging == null)

View file

@ -1,11 +1,11 @@
using System.Threading.Tasks;
using Content.Server.Body.Systems;
using Content.Server.Buckle.Components;
using Content.Server.Buckle.Systems;
using Content.Server.Hands.Components;
using Content.Shared.ActionBlocker;
using Content.Shared.Body.Components;
using Content.Shared.Body.Part;
using Content.Shared.Buckle.Components;
using Content.Shared.Hands.EntitySystems;
using Content.Shared.Standing;
using NUnit.Framework;

View file

@ -2,6 +2,7 @@
using System.Threading.Tasks;
using Content.Server.Climbing.Components;
using Content.Shared.Climbing;
using NUnit.Framework;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;

View file

@ -54,7 +54,6 @@ public sealed class PrototypeSaveTest
"SignalSwitch",
"SignalButton",
"ApcNetSwitch",
"TetherEntity",
"SignalButtonExt1",
"SignalButtonExt2",
"SignalButtonExt3",

View file

@ -27,7 +27,7 @@ public sealed class ClearBluespaceLockerLinks : IConsoleCommand
var entityManager = IoCManager.Resolve<IEntityManager>();
if (entityManager.TryGetComponent<EntityStorageComponent>(entityUid, out var originComponent))
if (entityManager.TryGetComponent<BluespaceLockerComponent>(entityUid, out var originComponent))
entityManager.RemoveComponent(entityUid, originComponent);
}
}

View file

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

View file

@ -17,7 +17,7 @@ public sealed class GamePrototypeLoadManager : IGamePrototypeLoadManager
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly ILocalizationManager _localizationManager = default!;
private readonly List<string> LoadedPrototypes = new();
private readonly List<string> _loadedPrototypes = new();
public void Initialize()
{
@ -30,8 +30,6 @@ public sealed class GamePrototypeLoadManager : IGamePrototypeLoadManager
}
public event Action? GamePrototypeLoaded;
private void ClientLoadsPrototype(GamePrototypeLoadMessage message)
{
var player = _playerManager.GetSessionByChannel(message.MsgChannel);
@ -48,23 +46,28 @@ public sealed class GamePrototypeLoadManager : IGamePrototypeLoadManager
private void LoadPrototypeData(string prototypeData)
{
LoadedPrototypes.Add(prototypeData);
var msg = new GamePrototypeLoadMessage();
msg.PrototypeData = prototypeData;
_loadedPrototypes.Add(prototypeData);
var msg = new GamePrototypeLoadMessage
{
PrototypeData = prototypeData
};
_netManager.ServerSendToAll(msg); // everyone load it up!
_prototypeManager.LoadString(prototypeData, true); // server needs it too.
var changed = new Dictionary<Type, HashSet<string>>();
_prototypeManager.LoadString(prototypeData, true, changed); // server needs it too.
_prototypeManager.ResolveResults();
_prototypeManager.ReloadPrototypes(changed);
_localizationManager.ReloadLocalizations();
GamePrototypeLoaded?.Invoke();
}
private void NetManagerOnConnected(object? sender, NetChannelArgs e)
{
// Just dump all the prototypes on connect, before them missing could be an issue.
foreach (var prototype in LoadedPrototypes)
foreach (var prototype in _loadedPrototypes)
{
var msg = new GamePrototypeLoadMessage();
msg.PrototypeData = prototype;
var msg = new GamePrototypeLoadMessage
{
PrototypeData = prototype
};
e.Channel.SendMessage(msg);
}
}

View file

@ -25,6 +25,7 @@ using Content.Shared.Damage;
using Content.Shared.Database;
using Content.Shared.Inventory;
using Content.Shared.PDA;
using Content.Shared.Stacks;
using Content.Shared.Verbs;
using Content.Shared.Weapons.Ranged.Components;
using Robust.Server.GameObjects;

View file

@ -14,6 +14,7 @@ using Content.Server.Prayer;
using Content.Server.Xenoarchaeology.XenoArtifacts;
using Content.Server.Xenoarchaeology.XenoArtifacts.Triggers.Components;
using Content.Shared.Administration;
using Content.Shared.Configurable;
using Content.Shared.Database;
using Content.Shared.GameTicking;
using Content.Shared.Interaction.Helpers;
@ -27,7 +28,7 @@ using Robust.Shared.Console;
using Robust.Shared.Map;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;
using static Content.Shared.Configurable.SharedConfigurationComponent;
using static Content.Shared.Configurable.ConfigurationComponent;
namespace Content.Server.Administration.Systems
{

View file

@ -3,6 +3,7 @@ using Content.Server.Chat;
using Content.Server.Chat.Systems;
using Content.Server.Power.Components;
using Content.Server.VendingMachines;
using Content.Shared.VendingMachines;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using Robust.Shared.Timing;

View file

@ -1,6 +1,6 @@
using Content.Server.Ensnaring;
using Content.Server.Ensnaring.Components;
using Content.Shared.Alert;
using Content.Shared.Ensnaring.Components;
using JetBrains.Annotations;
namespace Content.Server.Alert.Click;

View file

@ -2,7 +2,6 @@ using Content.Server.Actions;
using Content.Server.Bed.Components;
using Content.Server.Bed.Sleep;
using Content.Server.Body.Systems;
using Content.Server.Buckle.Components;
using Content.Server.MobState;
using Content.Server.Power.Components;
using Content.Server.Power.EntitySystems;

View file

@ -1,38 +0,0 @@
using Content.Server.Buckle.Systems;
using Content.Shared.Buckle.Components;
namespace Content.Server.Buckle.Components;
/// <summary>
/// Component that handles sitting entities into <see cref="StrapComponent"/>s.
/// </summary>
[RegisterComponent]
[ComponentReference(typeof(SharedBuckleComponent))]
[Access(typeof(BuckleSystem))]
public sealed class BuckleComponent : SharedBuckleComponent
{
/// <summary>
/// The amount of time that must pass for this entity to
/// be able to unbuckle after recently buckling.
/// </summary>
[DataField("delay")]
public TimeSpan UnbuckleDelay = TimeSpan.FromSeconds(0.25f);
/// <summary>
/// The time that this entity buckled at.
/// </summary>
[ViewVariables] public TimeSpan BuckleTime;
/// <summary>
/// The strap that this component is buckled to.
/// </summary>
[ViewVariables]
public StrapComponent? BuckledTo { get; set; }
/// <summary>
/// The amount of space that this entity occupies in a
/// <see cref="StrapComponent"/>.
/// </summary>
[DataField("size")]
public int Size = 100;
}

View file

@ -1,57 +0,0 @@
using Content.Server.Buckle.Systems;
using Content.Shared.Alert;
using Content.Shared.Buckle.Components;
using Robust.Shared.Audio;
namespace Content.Server.Buckle.Components;
[RegisterComponent]
[ComponentReference(typeof(SharedStrapComponent))]
[Access(typeof(BuckleSystem))]
public sealed class StrapComponent : SharedStrapComponent
{
/// <summary>
/// The angle in degrees to rotate the player by when they get strapped
/// </summary>
[DataField("rotation")]
public int Rotation { get; set; }
/// <summary>
/// The size of the strap which is compared against when buckling entities
/// </summary>
[DataField("size")]
public int Size { get; set; } = 100;
/// <summary>
/// If disabled, nothing can be buckled on this object, and it will unbuckle anything that's already buckled
/// </summary>
public bool Enabled { get; set; } = true;
/// <summary>
/// You can specify the offset the entity will have after unbuckling.
/// </summary>
[DataField("unbuckleOffset", required: false)]
public Vector2 UnbuckleOffset = Vector2.Zero;
/// <summary>
/// The sound to be played when a mob is buckled
/// </summary>
[DataField("buckleSound")]
public SoundSpecifier BuckleSound { get; } = new SoundPathSpecifier("/Audio/Effects/buckle.ogg");
/// <summary>
/// The sound to be played when a mob is unbuckled
/// </summary>
[DataField("unbuckleSound")]
public SoundSpecifier UnbuckleSound { get; } = new SoundPathSpecifier("/Audio/Effects/unbuckle.ogg");
/// <summary>
/// ID of the alert to show when buckled
/// </summary>
[DataField("buckledAlertType")]
public AlertType BuckledAlertType { get; } = AlertType.Buckled;
/// <summary>
/// The sum of the sizes of all the buckled entities in this strap
/// </summary>
public int OccupiedSize { get; set; }
}

View file

@ -1,5 +1,4 @@
using System.Diagnostics.CodeAnalysis;
using Content.Server.Buckle.Components;
using Content.Server.Storage.Components;
using Content.Shared.Alert;
using Content.Shared.Bed.Sleep;
@ -14,7 +13,6 @@ using Content.Shared.Stunnable;
using Content.Shared.Vehicle.Components;
using Content.Shared.Verbs;
using Robust.Shared.GameStates;
using Robust.Shared.Player;
namespace Content.Server.Buckle.Systems;

View file

@ -1,5 +1,4 @@
using System.Linq;
using Content.Server.Buckle.Components;
using Content.Server.Construction.Completions;
using Content.Shared.Buckle.Components;
using Content.Shared.Destructible;

View file

@ -10,6 +10,7 @@ using Content.Shared.Body.Components;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.Materials;
using Content.Shared.MobState.Components;
using Content.Shared.Stacks;
using Robust.Shared.Console;
using Robust.Shared.Containers;
using Robust.Shared.Map;

View file

@ -1,18 +0,0 @@
using Content.Shared.CartridgeLoader;
using Robust.Shared.Serialization.TypeSerializers.Implementations;
namespace Content.Server.CartridgeLoader;
[RegisterComponent]
[ComponentReference(typeof(SharedCartridgeLoaderComponent))]
public sealed class CartridgeLoaderComponent : SharedCartridgeLoaderComponent
{
/// <summary>
/// The maximum amount of programs that can be installed on the cartridge loader entity
/// </summary>
[DataField("diskSpace")]
public int DiskSpace = 5;
[DataField("uiKey", readOnly: true, required: true, customTypeSerializer: typeof(EnumSerializer))]
public Enum UiKey = default!;
}

View file

@ -241,13 +241,13 @@ public sealed class CartridgeLoaderSystem : SharedCartridgeLoaderSystem
loader.BackgroundPrograms.Remove(cartridgeUid);
}
protected override void OnItemInserted(EntityUid uid, SharedCartridgeLoaderComponent loader, EntInsertedIntoContainerMessage args)
protected override void OnItemInserted(EntityUid uid, Shared.CartridgeLoader.CartridgeLoaderComponent loader, EntInsertedIntoContainerMessage args)
{
RaiseLocalEvent(args.Entity, new CartridgeAddedEvent(uid));
base.OnItemInserted(uid, loader, args);
}
protected override void OnItemRemoved(EntityUid uid, SharedCartridgeLoaderComponent loader, EntRemovedFromContainerMessage args)
protected override void OnItemRemoved(EntityUid uid, Shared.CartridgeLoader.CartridgeLoaderComponent loader, EntRemovedFromContainerMessage args)
{
var deactivate = loader.BackgroundPrograms.Remove(args.Entity);

View file

@ -0,0 +1,7 @@
namespace Content.Server.Chemistry.Components;
[RegisterComponent]
public sealed class ActiveSolutionHeaterComponent : Component
{
}

View file

@ -0,0 +1,19 @@
namespace Content.Server.Chemistry.Components;
[RegisterComponent]
public sealed class SolutionHeaterComponent : Component
{
public readonly string BeakerSlotId = "beakerSlot";
[DataField("heatPerSecond")]
public float HeatPerSecond = 120;
[ViewVariables(VVAccess.ReadWrite)]
public float HeatMultiplier = 1;
[DataField("machinePartHeatPerSecond")]
public string MachinePartHeatPerSecond = "Laser";
[DataField("partRatingHeatMultiplier")]
public float PartRatingHeatMultiplier = 1.5f;
}

View file

@ -16,7 +16,7 @@ namespace Content.Server.Chemistry.EntitySystems
var coordinates = Transform(owner).Coordinates;
_adminLogger.Add(LogType.ChemicalReaction, reaction.Impact,
AdminLogger.Add(LogType.ChemicalReaction, reaction.Impact,
$"Chemical reaction {reaction.ID:reaction} occurred with strength {unitReactions:strength} on entity {ToPrettyString(owner):metabolizer} at {coordinates}");
SoundSystem.Play(reaction.Sound.GetSound(), Filter.Pvs(owner, entityManager:EntityManager), owner);

View file

@ -0,0 +1,65 @@
using Content.Server.Chemistry.Components;
using Content.Server.Chemistry.Components.SolutionManager;
using Content.Server.Construction;
using Content.Server.Power.Components;
using Content.Shared.Containers.ItemSlots;
namespace Content.Server.Chemistry.EntitySystems;
public sealed class SolutionHeaterSystem : EntitySystem
{
[Dependency] private readonly ItemSlotsSystem _itemSlots = default!;
[Dependency] private readonly SolutionContainerSystem _solution = default!;
/// <inheritdoc/>
public override void Initialize()
{
SubscribeLocalEvent<SolutionHeaterComponent, PowerChangedEvent>(OnPowerChanged);
SubscribeLocalEvent<SolutionHeaterComponent, RefreshPartsEvent>(OnRefreshParts);
SubscribeLocalEvent<SolutionHeaterComponent, UpgradeExamineEvent>(OnUpgradeExamine);
}
private void OnPowerChanged(EntityUid uid, SolutionHeaterComponent component, ref PowerChangedEvent args)
{
if (args.Powered)
{
EnsureComp<ActiveSolutionHeaterComponent>(uid);
}
else
{
RemComp<ActiveSolutionHeaterComponent>(uid);
}
}
private void OnRefreshParts(EntityUid uid, SolutionHeaterComponent component, RefreshPartsEvent args)
{
var heatRating = args.PartRatings[component.MachinePartHeatPerSecond] - 1;
component.HeatMultiplier = MathF.Pow(component.PartRatingHeatMultiplier, heatRating);
}
private void OnUpgradeExamine(EntityUid uid, SolutionHeaterComponent component, UpgradeExamineEvent args)
{
args.AddPercentageUpgrade("solution-heater-upgrade-heat", component.HeatMultiplier);
}
public override void Update(float frameTime)
{
base.Update(frameTime);
foreach (var (_, heater) in EntityQuery<ActiveSolutionHeaterComponent, SolutionHeaterComponent>())
{
if (_itemSlots.GetItemOrNull(heater.Owner, heater.BeakerSlotId) is not { } item)
continue;
if (!TryComp<SolutionContainerManagerComponent>(item, out var solution))
continue;
var energy = heater.HeatPerSecond * heater.HeatMultiplier * frameTime;
foreach (var s in solution.Solutions.Values)
{
_solution.AddThermalEnergy(solution.Owner, s, energy);
}
}
}
}

View file

@ -66,7 +66,7 @@ public sealed class ClimbSystem : SharedClimbSystem
SubscribeLocalEvent<GlassTableComponent, ClimbedOnEvent>(OnGlassClimbed);
}
protected override void OnCanDragDropOn(EntityUid uid, SharedClimbableComponent component, CanDragDropOnEvent args)
protected override void OnCanDragDropOn(EntityUid uid, ClimbableComponent component, CanDragDropOnEvent args)
{
base.OnCanDragDropOn(uid, component, args);
@ -166,6 +166,7 @@ public sealed class ClimbSystem : SharedClimbSystem
return;
climbing.IsClimbing = true;
Dirty(climbing);
MoveEntityToward(uid, climbable, physics, climbing);
// we may potentially need additional logic since we're forcing a player onto a climbable
@ -265,6 +266,7 @@ public sealed class ClimbSystem : SharedClimbSystem
climbing.IsClimbing = false;
climbing.OwnerIsTransitioning = false;
Dirty(climbing);
}
/// <summary>
@ -275,7 +277,7 @@ public sealed class ClimbSystem : SharedClimbSystem
/// <param name="target">The object that is being vaulted</param>
/// <param name="reason">The reason why it cant be dropped</param>
/// <returns></returns>
private bool CanVault(SharedClimbableComponent component, EntityUid user, EntityUid target, out string reason)
private bool CanVault(ClimbableComponent component, EntityUid user, EntityUid target, out string reason)
{
if (!_actionBlockerSystem.CanInteract(user, target))
{
@ -311,7 +313,7 @@ public sealed class ClimbSystem : SharedClimbSystem
/// <param name="target">The object that is being vaulted onto</param>
/// <param name="reason">The reason why it cant be dropped</param>
/// <returns></returns>
private bool CanVault(SharedClimbableComponent component, EntityUid user, EntityUid dragged, EntityUid target,
private bool CanVault(ClimbableComponent component, EntityUid user, EntityUid dragged, EntityUid target,
out string reason)
{
if (!_actionBlockerSystem.CanInteract(user, dragged) || !_actionBlockerSystem.CanInteract(user, target))
@ -353,7 +355,7 @@ public sealed class ClimbSystem : SharedClimbSystem
private static void OnClimbingGetState(EntityUid uid, ClimbingComponent component, ref ComponentGetState args)
{
args.State = new SharedClimbingComponent.ClimbModeComponentState(component.IsClimbing, component.OwnerIsTransitioning);
args.State = new ClimbingComponent.ClimbModeComponentState(component.IsClimbing, component.OwnerIsTransitioning);
}
private void OnGlassClimbed(EntityUid uid, GlassTableComponent component, ClimbedOnEvent args)
@ -401,7 +403,7 @@ public sealed class ClimbSystem : SharedClimbSystem
_actionBlockerSystem.UpdateCanMove(uid);
// Transition back to KinematicController after BufferTime
climbing.Owner.SpawnTimer((int) (SharedClimbingComponent.BufferTime * 1000), () =>
climbing.Owner.SpawnTimer((int) (ClimbingComponent.BufferTime * 1000), () =>
{
if (climbing.Deleted) return;
physics.BodyType = BodyType.KinematicController;

View file

@ -1,49 +0,0 @@
using Content.Shared.CCVar;
using Content.Shared.Climbing;
using Content.Shared.Damage;
using Robust.Shared.Audio;
namespace Content.Server.Climbing.Components;
[RegisterComponent]
[ComponentReference(typeof(SharedClimbableComponent))]
public sealed class ClimbableComponent : SharedClimbableComponent
{
/// <summary>
/// The time it takes to climb onto the entity.
/// </summary>
[DataField("delay")]
public float ClimbDelay = 0.8f;
/// <summary>
/// If set, people can bonk on this if <see cref="CCVars.GameTableBonk"/> is set or if they are clumsy.
/// </summary>
[DataField("bonk")] public bool Bonk = false;
/// <summary>
/// Chance of bonk triggering if the user is clumsy.
/// </summary>
[DataField("bonkClumsyChance")]
public float BonkClumsyChance = 0.75f;
/// <summary>
/// Sound to play when bonking.
/// </summary>
/// <seealso cref="Bonk"/>
[DataField("bonkSound")]
public SoundSpecifier? BonkSound;
/// <summary>
/// How long to stun players on bonk, in seconds.
/// </summary>
/// <seealso cref="Bonk"/>
[DataField("bonkTime")]
public float BonkTime = 2;
/// <summary>
/// How much damage to apply on bonk.
/// </summary>
/// <seealso cref="Bonk"/>
[DataField("bonkDamage")]
public DamageSpecifier? BonkDamage;
}

View file

@ -1,35 +0,0 @@
using Content.Shared.Climbing;
namespace Content.Server.Climbing.Components;
[RegisterComponent]
[ComponentReference(typeof(SharedClimbingComponent))]
[Access(typeof(ClimbSystem))]
public sealed class ClimbingComponent : SharedClimbingComponent
{
[ViewVariables(VVAccess.ReadWrite)]
public override bool IsClimbing
{
get => base.IsClimbing;
set
{
if (base.IsClimbing == value) return;
base.IsClimbing = value;
Dirty();
}
}
public override bool OwnerIsTransitioning
{
get => base.OwnerIsTransitioning;
set
{
if (value == base.OwnerIsTransitioning) return;
base.OwnerIsTransitioning = value;
Dirty();
}
}
[ViewVariables]
public Dictionary<string, int> DisabledFixtureMasks { get; } = new();
}

View file

@ -22,6 +22,7 @@ using Content.Server.Construction.Components;
using Content.Server.Materials;
using Content.Server.Stack;
using Content.Server.Jobs;
using Content.Shared.Humanoid;
using Content.Shared.Humanoid.Prototypes;
using Robust.Server.GameObjects;
using Robust.Server.Containers;

View file

@ -1,16 +0,0 @@
using Content.Shared.Configurable;
using Content.Shared.Tools;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
namespace Content.Server.Configurable;
[RegisterComponent]
[ComponentReference(typeof(SharedConfigurationComponent))]
public sealed class ConfigurationComponent : SharedConfigurationComponent
{
[DataField("config")]
public readonly Dictionary<string, string> Config = new();
[DataField("qualityNeeded", customTypeSerializer: typeof(PrototypeIdSerializer<ToolQualityPrototype>))]
public string QualityNeeded = "Pulsing";
}

View file

@ -1,8 +1,9 @@
using Content.Shared.Configurable;
using Content.Shared.Interaction;
using Content.Shared.Tools.Components;
using Robust.Server.GameObjects;
using Robust.Shared.Containers;
using static Content.Shared.Configurable.SharedConfigurationComponent;
using static Content.Shared.Configurable.ConfigurationComponent;
namespace Content.Server.Configurable;

View file

@ -2,6 +2,7 @@ using Content.Server.Stack;
using Content.Shared.Construction;
using Content.Shared.Hands.EntitySystems;
using Content.Shared.Prototypes;
using Content.Shared.Stacks;
using JetBrains.Annotations;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;

View file

@ -1,6 +1,7 @@
using Content.Server.Stack;
using Content.Shared.Construction;
using Content.Shared.Prototypes;
using Content.Shared.Stacks;
using JetBrains.Annotations;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;

View file

@ -3,6 +3,7 @@ using Content.Server.Stack;
using Content.Shared.Construction;
using Content.Shared.Examine;
using Content.Shared.Interaction;
using Content.Shared.Stacks;
using Content.Shared.Tag;
using Robust.Server.GameObjects;
using Robust.Shared.Containers;

View file

@ -2,6 +2,7 @@ using Content.Server.Construction.Components;
using Content.Server.Tools;
using Content.Server.Stack;
using Content.Shared.Interaction;
using Content.Shared.Stacks;
using Content.Shared.Tools.Components;
namespace Content.Server.Construction

View file

@ -1,4 +1,5 @@
using Content.Server.VendingMachines;
using Content.Shared.VendingMachines;
namespace Content.Server.Destructible.Thresholds.Behaviors
{

View file

@ -1,5 +1,6 @@
using Content.Server.Stack;
using Content.Shared.Prototypes;
using Content.Shared.Stacks;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Dictionary;

View file

@ -1,6 +1,6 @@
using Content.Server.Bed.Components;
using Content.Server.Buckle.Components;
using Content.Shared.Bed.Sleep;
using Content.Shared.Buckle.Components;
using Content.Shared.Disease;
namespace Content.Server.Disease.Cures

View file

@ -11,7 +11,6 @@ using System.Threading;
using Content.Server.Chat.Systems;
using Content.Server.GameTicking;
using Content.Server.GameTicking.Rules;
using Content.Server.Humanoid;
using Content.Server.NPC;
using Content.Shared.Damage;
using Content.Shared.Dragon;
@ -22,6 +21,7 @@ using Robust.Shared.GameStates;
using Robust.Shared.Map;
using Robust.Shared.Random;
using Content.Server.NPC.Systems;
using Content.Shared.Humanoid;
namespace Content.Server.Dragon
{

View file

@ -60,7 +60,7 @@ namespace Content.Server.Engineering.EntitySystems
if (component.Deleted || Deleted(component.Owner))
return;
if (EntityManager.TryGetComponent<SharedStackComponent?>(component.Owner, out var stackComp)
if (EntityManager.TryGetComponent<StackComponent?>(component.Owner, out var stackComp)
&& component.RemoveOnInteract && !_stackSystem.Use(uid, 1, stackComp))
{
return;

View file

@ -1,13 +0,0 @@
using Content.Shared.Ensnaring.Components;
using Robust.Shared.Containers;
namespace Content.Server.Ensnaring.Components;
[RegisterComponent]
[ComponentReference(typeof(SharedEnsnareableComponent))]
public sealed class EnsnareableComponent : SharedEnsnareableComponent
{
/// <summary>
/// The container where the <see cref="EnsnaringComponent"/> entity will be stored
/// </summary>
public Container Container = default!;
}

View file

@ -1,43 +1,5 @@
using System.Threading;
using Content.Shared.Ensnaring.Components;
namespace Content.Server.Ensnaring.Components;
[RegisterComponent]
[ComponentReference(typeof(SharedEnsnaringComponent))]
public sealed class EnsnaringComponent : SharedEnsnaringComponent
{
/// <summary>
/// Should movement cancel breaking out?
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
[DataField("canMoveBreakout")]
public bool CanMoveBreakout;
public CancellationTokenSource? CancelToken;
}
/// <summary>
/// Used for the do after event to free the entity that owns the <see cref="EnsnareableComponent"/>
/// </summary>
public sealed class FreeEnsnareDoAfterComplete : EntityEventArgs
{
public readonly EntityUid EnsnaringEntity;
public FreeEnsnareDoAfterComplete(EntityUid ensnaringEntity)
{
EnsnaringEntity = ensnaringEntity;
}
}
/// <summary>
/// Used for the do after event when it fails to free the entity that owns the <see cref="EnsnareableComponent"/>
/// </summary>
public sealed class FreeEnsnareDoAfterCancel : EntityEventArgs
{
public readonly EntityUid EnsnaringEntity;
public FreeEnsnareDoAfterCancel(EntityUid ensnaringEntity)
{
EnsnaringEntity = ensnaringEntity;
}
}

View file

@ -1,12 +1,10 @@
using System.Threading;
using Content.Server.DoAfter;
using Content.Server.Ensnaring.Components;
using Content.Shared.Alert;
using Content.Shared.Ensnaring.Components;
using Content.Shared.IdentityManagement;
using Content.Shared.StepTrigger.Systems;
using Content.Shared.Throwing;
using Robust.Shared.Player;
namespace Content.Server.Ensnaring;

View file

@ -1,11 +1,9 @@
using Content.Server.Ensnaring.Components;
using Content.Server.Popups;
using Content.Shared.Ensnaring;
using Content.Shared.Ensnaring.Components;
using Content.Shared.Popups;
using Robust.Server.Containers;
using Robust.Shared.Containers;
using Robust.Shared.Player;
namespace Content.Server.Ensnaring;

View file

@ -1,10 +0,0 @@
using Content.Shared.Flash;
namespace Content.Server.Flash.Components
{
[ComponentReference(typeof(SharedFlashableComponent))]
[RegisterComponent, Access(typeof(FlashSystem))]
public sealed class FlashableComponent : SharedFlashableComponent
{
}
}

View file

@ -1,7 +1,7 @@
using System.Linq;
using Content.Server.Buckle.Components;
using Content.Server.Buckle.Systems;
using Content.Server.Storage.Components;
using Content.Shared.Buckle.Components;
using Content.Shared.Foldable;
using Content.Shared.Verbs;
using JetBrains.Annotations;

View file

@ -3,7 +3,6 @@ using Content.Server.Actions;
using Content.Server.Chat.Managers;
using Content.Server.Disease;
using Content.Server.Disease.Components;
using Content.Server.Humanoid;
using Content.Server.Mind.Components;
using Content.Server.MobState;
using Content.Server.Players;
@ -14,6 +13,7 @@ using Content.Server.Traitor;
using Content.Server.Zombies;
using Content.Shared.Actions.ActionTypes;
using Content.Shared.CCVar;
using Content.Shared.Humanoid;
using Content.Shared.MobState;
using Content.Shared.MobState.Components;
using Content.Shared.Preferences;
@ -21,7 +21,6 @@ using Content.Shared.Roles;
using Content.Shared.Zombies;
using Robust.Server.Player;
using Robust.Shared.Configuration;
using Robust.Shared.Player;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using Robust.Shared.Utility;

View file

@ -15,6 +15,7 @@ using Content.Shared.Input;
using Content.Shared.Inventory;
using Content.Shared.Physics.Pull;
using Content.Shared.Pulling.Components;
using Content.Shared.Stacks;
using Content.Shared.Throwing;
using JetBrains.Annotations;
using Robust.Server.Player;

View file

@ -1,4 +1,6 @@
using Content.Server.Hands.Systems;
using Content.Server.Administration.Logs;
using Content.Server.Hands.Systems;
using Content.Shared.Database;
using Content.Shared.Examine;
using Content.Shared.Interaction.Events;
using Content.Shared.Item;
@ -20,6 +22,7 @@ public sealed class RandomGiftSystem : EntitySystem
[Dependency] private readonly IComponentFactory _componentFactory = default!;
[Dependency] private readonly IPrototypeManager _prototype = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
private readonly List<string> _possibleGiftsSafe = new();
private readonly List<string> _possibleGiftsUnsafe = new();
@ -54,6 +57,7 @@ public sealed class RandomGiftSystem : EntitySystem
var coords = Transform(args.User).Coordinates;
var handsEnt = Spawn(component.SelectedEntity, coords);
_adminLogger.Add(LogType.EntitySpawn, LogImpact.Low, $"{ToPrettyString(args.User)} used {ToPrettyString(component.Owner)} which spawned {ToPrettyString(handsEnt)}");
EnsureComp<ItemComponent>(handsEnt); // For insane mode.
if (component.Wrapper is not null)
Spawn(component.Wrapper, coords);

View file

@ -1,38 +0,0 @@
using Content.Shared.Humanoid;
using Content.Shared.Humanoid.Markings;
using Content.Shared.Preferences;
using Robust.Shared.Enums;
namespace Content.Server.Humanoid;
[RegisterComponent]
public sealed class HumanoidComponent : SharedHumanoidComponent
{
public MarkingSet CurrentMarkings = new();
/// <summary>
/// Any custom base layers this humanoid might have. See:
/// limb transplants (potentially), robotic arms, etc.
/// Stored on the server, this is merged in the client into
/// all layer settings.
/// </summary>
[ViewVariables(VVAccess.ReadOnly)]
public Dictionary<HumanoidVisualLayers, CustomBaseLayerInfo> CustomBaseLayers = new();
public HashSet<HumanoidVisualLayers> PermanentlyHidden = new();
public HashSet<HumanoidVisualLayers> AllHiddenLayers
{
get
{
var result = new HashSet<HumanoidVisualLayers>(HiddenLayers);
result.UnionWith(PermanentlyHidden);
return result;
}
}
// Couldn't these be somewhere else?
[ViewVariables] public Gender Gender = default!;
[ViewVariables] public int Age = 18;
}

View file

@ -1,4 +1,5 @@
using Content.Server.CharacterAppearance.Components;
using Content.Shared.Humanoid;
using Content.Shared.Preferences;
namespace Content.Server.Humanoid.Systems;

View file

@ -1,13 +1,12 @@
using Content.Server.Access.Systems;
using Content.Server.Administration.Logs;
using Content.Server.Humanoid;
using Content.Shared.Database;
using Content.Shared.Hands;
using Content.Shared.Humanoid;
using Content.Shared.IdentityManagement;
using Content.Shared.IdentityManagement.Components;
using Content.Shared.Inventory;
using Content.Shared.Inventory.Events;
using Content.Shared.Preferences;
using Robust.Shared.Enums;
using Robust.Shared.GameObjects.Components.Localization;

View file

@ -12,6 +12,7 @@ using Content.Shared.Interaction;
using Content.Shared.Kitchen;
using Content.Shared.Popups;
using Content.Shared.Random.Helpers;
using Content.Shared.Stacks;
using JetBrains.Annotations;
using Robust.Server.GameObjects;
using Robust.Shared.Audio;

View file

@ -1,6 +1,7 @@
using System.Linq;
using Content.Server.Humanoid;
using Content.Server.UserInterface;
using Content.Shared.Humanoid;
using Content.Shared.Humanoid.Markings;
using Content.Shared.MagicMirror;
using Robust.Server.GameObjects;

View file

@ -7,6 +7,7 @@ using Content.Server.Mech.Systems;
using Content.Shared.Interaction;
using Content.Shared.Mech;
using Content.Shared.Mech.Equipment.Components;
using Content.Shared.MobState.Components;
using Content.Shared.Wall;
using Robust.Shared.Containers;
using Robust.Shared.Map;
@ -115,17 +116,17 @@ public sealed class MechGrabberSystem : EntitySystem
private void OnInteract(EntityUid uid, MechGrabberComponent component, InteractNoHandEvent args)
{
if (args.Handled || args.Target == null)
if (args.Handled || args.Target is not {} target)
return;
var xform = Transform(args.Target.Value);
if (xform.Anchored || HasComp<WallMountComponent>(args.Target.Value))
var xform = Transform(target);
if (xform.Anchored || HasComp<WallMountComponent>(target) || HasComp<MobStateComponent>(target))
return;
if (component.ItemContainer.ContainedEntities.Count >= component.MaxContents)
return;
if (!TryComp<MechComponent>(args.User, out var mech))
if (!TryComp<MechComponent>(args.User, out var mech) || mech.PilotSlot.ContainedEntity == target)
return;
if (mech.Energy + component.GrabEnergyDelta < 0)
@ -134,17 +135,17 @@ public sealed class MechGrabberSystem : EntitySystem
if (component.Token != null)
return;
if (!_interaction.InRangeUnobstructed(args.User, args.Target.Value))
if (!_interaction.InRangeUnobstructed(args.User, target))
return;
args.Handled = true;
component.Token = new();
component.AudioStream = _audio.PlayPvs(component.GrabSound, uid);
_doAfter.DoAfter(new DoAfterEventArgs(args.User, component.GrabDelay, component.Token.Token, args.Target, uid)
_doAfter.DoAfter(new DoAfterEventArgs(args.User, component.GrabDelay, component.Token.Token, target, uid)
{
BreakOnTargetMove = true,
BreakOnUserMove = true,
UsedFinishedEvent = new MechGrabberGrabFinishedEvent(args.Target.Value),
UsedFinishedEvent = new MechGrabberGrabFinishedEvent(target),
UsedCancelledEvent = new MechGrabberGrabCancelledEvent()
});
}

View file

@ -4,6 +4,7 @@ using Content.Server.Atmos.EntitySystems;
using Content.Server.DoAfter;
using Content.Server.Mech.Components;
using Content.Server.Power.Components;
using Content.Server.Tools;
using Content.Server.Wires;
using Content.Shared.Damage;
using Content.Shared.FixedPoint;
@ -52,6 +53,7 @@ public sealed class MechSystem : SharedMechSystem
SubscribeLocalEvent<MechComponent, DamageChangedEvent>(OnDamageChanged);
SubscribeLocalEvent<MechComponent, MechEquipmentRemoveMessage>(OnRemoveEquipmentMessage);
SubscribeLocalEvent<MechPilotComponent, ToolUserAttemptUseEvent>(OnToolUseAttempt);
SubscribeLocalEvent<MechPilotComponent, InhaleLocationEvent>(OnInhale);
SubscribeLocalEvent<MechPilotComponent, ExhaleLocationEvent>(OnExhale);
SubscribeLocalEvent<MechPilotComponent, AtmosExposedGetAirEvent>(OnExpose);
@ -137,6 +139,12 @@ public sealed class MechSystem : SharedMechSystem
ToggleMechUi(uid, component);
}
private void OnToolUseAttempt(EntityUid uid, MechPilotComponent component, ref ToolUserAttemptUseEvent args)
{
if (args.Target == component.Mech)
args.Cancelled = true;
}
private void OnAlternativeVerb(EntityUid uid, MechComponent component, GetVerbsEvent<AlternativeVerb> args)
{
if (!args.CanAccess || !args.CanInteract || component.Broken)

View file

@ -17,12 +17,11 @@ using Content.Server.Body.Components;
using Content.Server.Climbing;
using Content.Server.Construction;
using Content.Server.DoAfter;
using Content.Server.Humanoid;
using Content.Server.Mind.Components;
using Content.Server.Stack;
using Content.Shared.Humanoid;
using Content.Shared.Interaction.Events;
using Content.Shared.Popups;
using Robust.Shared.Player;
using Robust.Shared.Random;
using Robust.Shared.Configuration;
using Robust.Server.Player;

View file

@ -0,0 +1,16 @@
using Content.Server.Atmos;
using Content.Shared.Atmos;
using Content.Shared.Medical.Cryogenics;
namespace Content.Server.Medical.Components;
[RegisterComponent]
public sealed class CryoPodComponent: SharedCryoPodComponent
{
/// <summary>
/// Local air buffer that will be mixed with the pipenet, if one exists, per tick.
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
[DataField("gasMixture")]
public GasMixture Air { get; set; } = new(Atmospherics.OneAtmosphere);
}

View file

@ -0,0 +1,59 @@
using Content.Server.Medical.Components;
using Content.Server.Wires;
using Content.Shared.Medical.Cryogenics;
using Content.Shared.Wires;
namespace Content.Server.Medical;
/// <summary>
/// Causes a failure in the cryo pod ejection system when cut. A crowbar will be needed to pry open the pod.
/// </summary>
[DataDefinition]
public sealed class CryoPodEjectLockWireAction: BaseWireAction
{
[DataField("color")]
private Color _statusColor = Color.Red;
[DataField("name")]
private string _text = "LOCK";
public override object? StatusKey { get; } = CryoPodWireActionKey.Key;
public override bool Cut(EntityUid user, Wire wire)
{
if (EntityManager.TryGetComponent<CryoPodComponent>(wire.Owner, out var cryoPodComponent) && !cryoPodComponent.PermaLocked)
{
cryoPodComponent.Locked = true;
}
return true;
}
public override bool Mend(EntityUid user, Wire wire)
{
if (EntityManager.TryGetComponent<CryoPodComponent>(wire.Owner, out var cryoPodComponent) && !cryoPodComponent.PermaLocked)
{
cryoPodComponent.Locked = false;
}
return true;
}
public override bool Pulse(EntityUid user, Wire wire)
{
return true;
}
public override StatusLightData? GetStatusLightData(Wire wire)
{
StatusLightState lightState = StatusLightState.Off;
if (EntityManager.TryGetComponent<CryoPodComponent>(wire.Owner, out var cryoPodComponent) && cryoPodComponent.Locked)
{
lightState = StatusLightState.On; //TODO figure out why this doesn't get updated when the pod is emagged
}
return new StatusLightData(
_statusColor,
lightState,
_text);
}
}

View file

@ -0,0 +1,267 @@
using System.Threading;
using Content.Server.Atmos;
using Content.Server.Atmos.EntitySystems;
using Content.Server.Atmos.Piping.Components;
using Content.Server.Atmos.Piping.Unary.EntitySystems;
using Content.Server.Body.Components;
using Content.Server.Body.Systems;
using Content.Server.Chemistry.Components.SolutionManager;
using Content.Server.Chemistry.EntitySystems;
using Content.Server.Climbing;
using Content.Server.DoAfter;
using Content.Server.Medical.Components;
using Content.Server.NodeContainer;
using Content.Server.NodeContainer.NodeGroups;
using Content.Server.NodeContainer.Nodes;
using Content.Server.Power.Components;
using Content.Server.Tools;
using Content.Server.UserInterface;
using Content.Shared.Chemistry;
using Content.Shared.Chemistry.Components;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.Containers.ItemSlots;
using Content.Shared.Destructible;
using Content.Shared.DragDrop;
using Content.Shared.Emag.Systems;
using Content.Shared.Examine;
using Content.Shared.Interaction;
using Content.Shared.Medical.Cryogenics;
using Content.Shared.MedicalScanner;
using Content.Shared.Tools.Components;
using Content.Shared.Verbs;
using Robust.Server.GameObjects;
using Robust.Shared.Timing;
namespace Content.Server.Medical;
public sealed partial class CryoPodSystem: SharedCryoPodSystem
{
[Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
[Dependency] private readonly GasCanisterSystem _gasCanisterSystem = default!;
[Dependency] private readonly ClimbSystem _climbSystem = default!;
[Dependency] private readonly ItemSlotsSystem _itemSlotsSystem = default!;
[Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!;
[Dependency] private readonly BloodstreamSystem _bloodstreamSystem = default!;
[Dependency] private readonly UserInterfaceSystem _userInterfaceSystem = default!;
[Dependency] private readonly DoAfterSystem _doAfterSystem = default!;
[Dependency] private readonly UserInterfaceSystem _uiSystem = default!;
[Dependency] private readonly ToolSystem _toolSystem = default!;
[Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly MetaDataSystem _metaDataSystem = default!;
[Dependency] private readonly ReactiveSystem _reactiveSystem = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<CryoPodComponent, ComponentInit>(OnComponentInit);
SubscribeLocalEvent<CryoPodComponent, GetVerbsEvent<AlternativeVerb>>(AddAlternativeVerbs);
SubscribeLocalEvent<CryoPodComponent, GotEmaggedEvent>(OnEmagged);
SubscribeLocalEvent<CryoPodComponent, DoInsertCryoPodEvent>(DoInsertCryoPod);
SubscribeLocalEvent<CryoPodComponent, DoInsertCancelledCryoPodEvent>(DoInsertCancelCryoPod);
SubscribeLocalEvent<CryoPodComponent, CryoPodPryFinished>(OnCryoPodPryFinished);
SubscribeLocalEvent<CryoPodComponent, CryoPodPryInterrupted>(OnCryoPodPryInterrupted);
SubscribeLocalEvent<CryoPodComponent, AtmosDeviceUpdateEvent>(OnCryoPodUpdateAtmosphere);
SubscribeLocalEvent<CryoPodComponent, DragDropEvent>(HandleDragDropOn);
SubscribeLocalEvent<CryoPodComponent, InteractUsingEvent>(OnInteractUsing);
SubscribeLocalEvent<CryoPodComponent, ExaminedEvent>(OnExamined);
SubscribeLocalEvent<CryoPodComponent, PowerChangedEvent>(OnPowerChanged);
SubscribeLocalEvent<CryoPodComponent, GasAnalyzerScanEvent>(OnGasAnalyzed);
SubscribeLocalEvent<CryoPodComponent, ActivatableUIOpenAttemptEvent>(OnActivateUIAttempt);
SubscribeLocalEvent<CryoPodComponent, AfterActivatableUIOpenEvent>(OnActivateUI);
}
public override void Update(float frameTime)
{
base.Update(frameTime);
var curTime = _gameTiming.CurTime;
var bloodStreamQuery = GetEntityQuery<BloodstreamComponent>();
var metaDataQuery = GetEntityQuery<MetaDataComponent>();
var itemSlotsQuery = GetEntityQuery<ItemSlotsComponent>();
var fitsInDispenserQuery = GetEntityQuery<FitsInDispenserComponent>();
var solutionContainerManagerQuery = GetEntityQuery<SolutionContainerManagerComponent>();
foreach (var (_, cryoPod) in EntityQuery<ActiveCryoPodComponent, CryoPodComponent>())
{
metaDataQuery.TryGetComponent(cryoPod.Owner, out var metaDataComponent);
if (curTime < cryoPod.NextInjectionTime + _metaDataSystem.GetPauseTime(cryoPod.Owner, metaDataComponent))
continue;
cryoPod.NextInjectionTime = curTime + TimeSpan.FromSeconds(cryoPod.BeakerTransferTime);
if (
!itemSlotsQuery.TryGetComponent(cryoPod.Owner, out var itemSlotsComponent)
|| !fitsInDispenserQuery.TryGetComponent(cryoPod.Owner, out var fitsInDispenserComponent)
|| !solutionContainerManagerQuery.TryGetComponent(cryoPod.Owner, out var solutionContainerManagerComponent))
{
continue;
}
var container = _itemSlotsSystem.GetItemOrNull(cryoPod.Owner, cryoPod.SolutionContainerName, itemSlotsComponent);
var patient = cryoPod.BodyContainer.ContainedEntity;
if (container != null
&& container.Value.Valid
&& patient != null
&& _solutionContainerSystem.TryGetFitsInDispenser(container.Value, out var containerSolution, dispenserFits: fitsInDispenserComponent, solutionManager: solutionContainerManagerComponent))
{
if (!bloodStreamQuery.TryGetComponent(patient, out var bloodstream))
{
continue;
}
var solutionToInject = _solutionContainerSystem.SplitSolution(container.Value, containerSolution, cryoPod.BeakerTransferAmount);
_bloodstreamSystem.TryAddToChemicals(patient.Value, solutionToInject, bloodstream);
_reactiveSystem.DoEntityReaction(patient.Value, solutionToInject, ReactionMethod.Injection);
}
}
}
public override void EjectBody(EntityUid uid, SharedCryoPodComponent? cryoPodComponent)
{
if (!Resolve(uid, ref cryoPodComponent))
return;
if (cryoPodComponent.BodyContainer.ContainedEntity is not {Valid: true} contained)
return;
base.EjectBody(uid, cryoPodComponent);
_climbSystem.ForciblySetClimbing(contained, uid);
}
#region Interaction
private void HandleDragDropOn(EntityUid uid, CryoPodComponent cryoPodComponent, DragDropEvent args)
{
if (cryoPodComponent.BodyContainer.ContainedEntity != null)
{
return;
}
if (cryoPodComponent.DragDropCancelToken != null)
{
cryoPodComponent.DragDropCancelToken.Cancel();
cryoPodComponent.DragDropCancelToken = null;
return;
}
cryoPodComponent.DragDropCancelToken = new CancellationTokenSource();
var doAfterArgs = new DoAfterEventArgs(args.User, cryoPodComponent.EntryDelay, cryoPodComponent.DragDropCancelToken.Token, uid, args.Dragged)
{
BreakOnDamage = true,
BreakOnStun = true,
BreakOnTargetMove = true,
BreakOnUserMove = true,
NeedHand = false,
TargetFinishedEvent = new DoInsertCryoPodEvent(args.Dragged),
TargetCancelledEvent = new DoInsertCancelledCryoPodEvent()
};
_doAfterSystem.DoAfter(doAfterArgs);
args.Handled = true;
}
private void OnActivateUIAttempt(EntityUid uid, CryoPodComponent cryoPodComponent, ActivatableUIOpenAttemptEvent args)
{
if (args.Cancelled)
{
return;
}
var containedEntity = cryoPodComponent.BodyContainer.ContainedEntity;
if (containedEntity == null || containedEntity == args.User || !HasComp<ActiveCryoPodComponent>(uid))
{
args.Cancel();
}
}
private void OnActivateUI(EntityUid uid, CryoPodComponent cryoPodComponent, AfterActivatableUIOpenEvent args)
{
_userInterfaceSystem.TrySendUiMessage(
uid,
SharedHealthAnalyzerComponent.HealthAnalyzerUiKey.Key,
new SharedHealthAnalyzerComponent.HealthAnalyzerScannedUserMessage(cryoPodComponent.BodyContainer.ContainedEntity));
}
private void OnInteractUsing(EntityUid uid, CryoPodComponent cryoPodComponent, InteractUsingEvent args)
{
if (args.Handled || !cryoPodComponent.Locked || cryoPodComponent.BodyContainer.ContainedEntity == null)
return;
if (TryComp(args.Used, out ToolComponent? tool)
&& tool.Qualities.Contains("Prying")) // Why aren't those enums?
{
if (cryoPodComponent.IsPrying)
return;
cryoPodComponent.IsPrying = true;
_toolSystem.UseTool(args.Used, args.User, uid, 0f,
cryoPodComponent.PryDelay, "Prying",
new CryoPodPryFinished(), new CryoPodPryInterrupted(), uid);
args.Handled = true;
}
}
private void OnExamined(EntityUid uid, CryoPodComponent component, ExaminedEvent args)
{
var container = _itemSlotsSystem.GetItemOrNull(component.Owner, component.SolutionContainerName);
if (args.IsInDetailsRange && container != null && _solutionContainerSystem.TryGetFitsInDispenser(container.Value, out var containerSolution))
{
args.PushMarkup(Loc.GetString("cryo-pod-examine", ("beaker", Name(container.Value))));
if (containerSolution.CurrentVolume == 0)
{
args.PushMarkup(Loc.GetString("cryo-pod-empty-beaker"));
}
}
}
private void OnPowerChanged(EntityUid uid, CryoPodComponent component, ref PowerChangedEvent args)
{
// Needed to avoid adding/removing components on a deleted entity
if (Terminating(uid))
{
return;
}
if (args.Powered)
{
EnsureComp<ActiveCryoPodComponent>(uid);
}
else
{
RemComp<ActiveCryoPodComponent>(uid);
_uiSystem.TryCloseAll(uid, SharedHealthAnalyzerComponent.HealthAnalyzerUiKey.Key);
}
UpdateAppearance(uid, component);
}
#endregion
#region Atmos handler
private void OnCryoPodUpdateAtmosphere(EntityUid uid, CryoPodComponent cryoPod, AtmosDeviceUpdateEvent args)
{
if (!TryComp(uid, out NodeContainerComponent? nodeContainer))
return;
if (!nodeContainer.TryGetNode(cryoPod.PortName, out PortablePipeNode? portNode))
return;
_atmosphereSystem.React(cryoPod.Air, portNode);
if (portNode.NodeGroup is PipeNet {NodeCount: > 1} net)
{
_gasCanisterSystem.MixContainerWithPipeNet(cryoPod.Air, net.Air);
}
}
private void OnGasAnalyzed(EntityUid uid, CryoPodComponent component, GasAnalyzerScanEvent args)
{
var gasMixDict = new Dictionary<string, GasMixture?> { { Name(uid), component.Air } };
// If it's connected to a port, include the port side
if (TryComp(uid, out NodeContainerComponent? nodeContainer))
{
if(nodeContainer.TryGetNode(component.PortName, out PipeNode? port))
gasMixDict.Add(component.PortName, port.Air);
}
args.GasMixtures = gasMixDict;
}
#endregion
}

View file

@ -123,7 +123,7 @@ public sealed class HealingSystem : EntitySystem
return false;
}
if (TryComp<SharedStackComponent>(component.Owner, out var stack) && stack.Count < 1)
if (TryComp<StackComponent>(component.Owner, out var stack) && stack.Count < 1)
return false;
component.CancelToken = new CancellationTokenSource();

View file

@ -0,0 +1,47 @@
using Content.Server.Atmos.EntitySystems;
using Content.Server.Medical.Components;
using Content.Shared.Medical.Cryogenics;
namespace Content.Server.Medical
{
public sealed partial class CryoPodSystem
{
public override void InitializeInsideCryoPod()
{
base.InitializeInsideCryoPod();
// Atmos overrides
SubscribeLocalEvent<InsideCryoPodComponent, InhaleLocationEvent>(OnInhaleLocation);
SubscribeLocalEvent<InsideCryoPodComponent, ExhaleLocationEvent>(OnExhaleLocation);
SubscribeLocalEvent<InsideCryoPodComponent, AtmosExposedGetAirEvent>(OnGetAir);
}
#region Atmos handlers
private void OnGetAir(EntityUid uid, InsideCryoPodComponent component, ref AtmosExposedGetAirEvent args)
{
if (TryComp<CryoPodComponent>(Transform(uid).ParentUid, out var cryoPodComponent))
{
args.Gas = cryoPodComponent.Air;
args.Handled = true;
}
}
private void OnInhaleLocation(EntityUid uid, InsideCryoPodComponent component, InhaleLocationEvent args)
{
if (TryComp<CryoPodComponent>(Transform(uid).ParentUid, out var cryoPodComponent))
{
args.Gas = cryoPodComponent.Air;
}
}
private void OnExhaleLocation(EntityUid uid, InsideCryoPodComponent component, ExhaleLocationEvent args)
{
if (TryComp<CryoPodComponent>(Transform(uid).ParentUid, out var cryoPodComponent))
{
args.Gas = cryoPodComponent.Air;
}
}
#endregion
}
}

View file

@ -36,20 +36,6 @@ public sealed class NPCSteeringComponent : Component
#endregion
/// <summary>
/// How many times per second we're allowed to update our steering frequency.
/// </summary>
public const byte SteerFrequency = 10;
/// <summary>
/// Last time the NPC steered.
/// </summary>
[ViewVariables]
public TimeSpan LastTimeSteer;
[ViewVariables]
public Vector2 LastSteer;
/// <summary>
/// Have we currently requested a path.
/// </summary>

View file

@ -61,6 +61,20 @@ public sealed class HTNSystem : EntitySystem
private void OnLoad()
{
// Clear all NPCs in case they're hanging onto stale tasks
foreach (var comp in EntityQuery<HTNComponent>(true))
{
comp.PlanningToken?.Cancel();
comp.PlanningToken = null;
if (comp.Plan != null)
{
var currentOperator = comp.Plan.CurrentOperator;
currentOperator.Shutdown(comp.Blackboard, HTNOperatorStatus.Failed);
comp.Plan = null;
}
}
// Add dependencies for all operators.
// We put code on operators as I couldn't think of a clean way to put it on systems.
foreach (var compound in _prototypeManager.EnumeratePrototypes<HTNCompoundTask>())

View file

@ -394,7 +394,8 @@ public sealed partial class NPCSteeringSystem
(layer & otherBody.CollisionMask) == 0x0 ||
!factionQuery.TryGetComponent(ent, out var otherFaction) ||
!_faction.IsFriendly(uid, ent, ourFaction, otherFaction) ||
Vector2.Dot(otherBody.LinearVelocity, ourVelocity) < 0f)
// Use <= 0 so we ignore stationary friends in case.
Vector2.Dot(otherBody.LinearVelocity, ourVelocity) <= 0f)
{
continue;
}
@ -415,7 +416,7 @@ public sealed partial class NPCSteeringSystem
obstacleDirection = offsetRot.RotateVec(obstacleDirection);
var norm = obstacleDirection.Normalized;
var weight = obstableDistance <= agentRadius ? 1f : (detectionRadius - obstableDistance) / detectionRadius;
weight *= 1.5f;
weight *= 1f;
for (var i = 0; i < InterestDirections; i++)
{

View file

@ -41,7 +41,6 @@ namespace Content.Server.NPC.Systems
[Dependency] private readonly IAdminManager _admin = default!;
[Dependency] private readonly IConfigurationManager _configManager = default!;
[Dependency] private readonly IDependencyCollection _dependencies = default!;
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly IParallelManager _parallel = default!;
@ -79,8 +78,8 @@ namespace Content.Server.NPC.Systems
}
UpdatesBefore.Add(typeof(SharedPhysicsSystem));
_configManager.OnValueChanged(CCVars.NPCEnabled, SetNPCEnabled);
_configManager.OnValueChanged(CCVars.NPCPathfinding, SetNPCPathfinding);
_configManager.OnValueChanged(CCVars.NPCEnabled, SetNPCEnabled, true);
_configManager.OnValueChanged(CCVars.NPCPathfinding, SetNPCPathfinding, true);
SubscribeLocalEvent<NPCSteeringComponent, ComponentShutdown>(OnSteeringShutdown);
SubscribeNetworkEvent<RequestNPCSteeringDebugEvent>(OnDebugRequest);
@ -90,9 +89,11 @@ namespace Content.Server.NPC.Systems
{
if (!obj)
{
foreach (var (_, mover) in EntityQuery<NPCSteeringComponent, InputMoverComponent>())
foreach (var (comp, mover) in EntityQuery<NPCSteeringComponent, InputMoverComponent>())
{
mover.CurTickSprintMovement = Vector2.Zero;
comp.PathfindToken?.Cancel();
comp.PathfindToken = null;
}
}
@ -117,6 +118,7 @@ namespace Content.Server.NPC.Systems
{
base.Shutdown();
_configManager.UnsubValueChanged(CCVars.NPCEnabled, SetNPCEnabled);
_configManager.UnsubValueChanged(CCVars.NPCPathfinding, SetNPCPathfinding);
}
private void OnDebugRequest(RequestNPCSteeringDebugEvent msg, EntitySessionEventArgs args)
@ -204,12 +206,18 @@ namespace Content.Server.NPC.Systems
var npcs = EntityQuery<NPCSteeringComponent, ActiveNPCComponent, InputMoverComponent, TransformComponent>()
.ToArray();
foreach (var (steering, _, mover, xform) in npcs)
var options = new ParallelOptions
{
MaxDegreeOfParallelism = _parallel.ParallelProcessCount,
};
Parallel.For(0, npcs.Length, options, i =>
{
var (steering, _, mover, xform) = npcs[i];
Steer(steering, mover, xform, modifierQuery, bodyQuery, xformQuery, frameTime);
steering.LastSteer = mover.CurTickSprintMovement;
}
});
if (_subscribedSessions.Count > 0)
{
@ -278,8 +286,7 @@ namespace Content.Server.NPC.Systems
return;
}
// TODO: Pause time
// Need it on the paused event which needs an engine PR.
/* If you wish to not steer every tick A) Add pause support B) fix overshoots to prevent dancing
var nextSteer = steering.LastTimeSteer + TimeSpan.FromSeconds(1f / NPCSteeringComponent.SteerFrequency);
if (nextSteer > _timing.CurTime)
@ -287,8 +294,8 @@ namespace Content.Server.NPC.Systems
SetDirection(mover, steering, steering.LastSteer, false);
return;
}
*/
steering.LastTimeSteer = _timing.CurTime;
var uid = mover.Owner;
var interest = steering.Interest;
var danger = steering.Danger;
@ -300,7 +307,6 @@ namespace Content.Server.NPC.Systems
var offsetRot = -_mover.GetParentGridAngle(mover);
modifierQuery.TryGetComponent(uid, out var modifier);
var moveSpeed = GetSprintSpeed(steering.Owner, modifier);
var tickMove = moveSpeed * frameTime;
var body = bodyQuery.GetComponent(uid);
var dangerPoints = steering.DangerPoints;
dangerPoints.Clear();
@ -322,7 +328,7 @@ namespace Content.Server.NPC.Systems
DebugTools.Assert(!float.IsNaN(interest[0]));
// Avoid static objects like walls
CollisionAvoidance(uid, offsetRot, worldPos, agentRadius, tickMove, layer, mask, xform, danger, dangerPoints, bodyQuery, xformQuery);
CollisionAvoidance(uid, offsetRot, worldPos, agentRadius, moveSpeed, layer, mask, xform, danger, dangerPoints, bodyQuery, xformQuery);
DebugTools.Assert(!float.IsNaN(danger[0]));
Separation(uid, offsetRot, worldPos, agentRadius, layer, mask, body, xform, danger, bodyQuery, xformQuery);

Some files were not shown because too many files have changed in this diff Show more