diff --git a/Content.Client/Alerts/ClientAlertsSystem.cs b/Content.Client/Alerts/ClientAlertsSystem.cs
index 9c4ebb9cd2..223bf7876a 100644
--- a/Content.Client/Alerts/ClientAlertsSystem.cs
+++ b/Content.Client/Alerts/ClientAlertsSystem.cs
@@ -4,7 +4,6 @@ using JetBrains.Annotations;
using Robust.Client.Player;
using Robust.Shared.Player;
using Robust.Shared.Prototypes;
-using Robust.Shared.Timing;
namespace Content.Client.Alerts;
@@ -13,7 +12,6 @@ public sealed class ClientAlertsSystem : AlertsSystem
{
public AlertOrderPrototype? AlertOrder { get; set; }
- [Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
diff --git a/Content.Client/Alerts/UpdateAlertSpriteEvent.cs b/Content.Client/Alerts/UpdateAlertSpriteEvent.cs
new file mode 100644
index 0000000000..4f182c458c
--- /dev/null
+++ b/Content.Client/Alerts/UpdateAlertSpriteEvent.cs
@@ -0,0 +1,21 @@
+using Content.Shared.Alert;
+using Robust.Client.GameObjects;
+
+namespace Content.Client.Alerts;
+
+///
+/// Event raised on an entity with alerts in order to allow it to update visuals for the alert sprite entity.
+///
+[ByRefEvent]
+public record struct UpdateAlertSpriteEvent
+{
+ public Entity SpriteViewEnt;
+
+ public AlertPrototype Alert;
+
+ public UpdateAlertSpriteEvent(Entity spriteViewEnt, AlertPrototype alert)
+ {
+ SpriteViewEnt = spriteViewEnt;
+ Alert = alert;
+ }
+}
diff --git a/Content.Client/Audio/AmbientSoundSystem.cs b/Content.Client/Audio/AmbientSoundSystem.cs
index 9d30cabb1e..0206017bae 100644
--- a/Content.Client/Audio/AmbientSoundSystem.cs
+++ b/Content.Client/Audio/AmbientSoundSystem.cs
@@ -50,7 +50,6 @@ public sealed class AmbientSoundSystem : SharedAmbientSoundSystem
private static AudioParams _params = AudioParams.Default
.WithVariation(0.01f)
.WithLoop(true)
- .WithAttenuation(Attenuation.LinearDistance)
.WithMaxDistance(7f);
///
diff --git a/Content.Client/Audio/ContentAudioSystem.LobbyMusic.cs b/Content.Client/Audio/ContentAudioSystem.LobbyMusic.cs
index 0fdcc7a86d..92c5b7a419 100644
--- a/Content.Client/Audio/ContentAudioSystem.LobbyMusic.cs
+++ b/Content.Client/Audio/ContentAudioSystem.LobbyMusic.cs
@@ -23,8 +23,8 @@ public sealed partial class ContentAudioSystem
[Dependency] private readonly IStateManager _stateManager = default!;
[Dependency] private readonly IResourceCache _resourceCache = default!;
- private readonly AudioParams _lobbySoundtrackParams = new(-5f, 1, "Master", 0, 0, 0, false, 0f);
- private readonly AudioParams _roundEndSoundEffectParams = new(-5f, 1, "Master", 0, 0, 0, false, 0f);
+ private readonly AudioParams _lobbySoundtrackParams = new(-5f, 1, 0, 0, 0, false, 0f);
+ private readonly AudioParams _roundEndSoundEffectParams = new(-5f, 1, 0, 0, 0, false, 0f);
///
/// EntityUid of lobby restart sound component.
diff --git a/Content.Client/Clothing/ClientClothingSystem.cs b/Content.Client/Clothing/ClientClothingSystem.cs
index fbe9d5ec5b..7e78ac7d70 100644
--- a/Content.Client/Clothing/ClientClothingSystem.cs
+++ b/Content.Client/Clothing/ClientClothingSystem.cs
@@ -133,7 +133,7 @@ public sealed class ClientClothingSystem : ClothingSystem
else if (TryComp(uid, out SpriteComponent? sprite))
rsi = sprite.BaseRSI;
- if (rsi == null || rsi.Path == null)
+ if (rsi == null)
return false;
var correctedSlot = slot;
diff --git a/Content.Client/Doors/DoorSystem.cs b/Content.Client/Doors/DoorSystem.cs
index 473ae97059..bc52730b0e 100644
--- a/Content.Client/Doors/DoorSystem.cs
+++ b/Content.Client/Doors/DoorSystem.cs
@@ -4,14 +4,12 @@ using Robust.Client.Animations;
using Robust.Client.GameObjects;
using Robust.Client.ResourceManagement;
using Robust.Shared.Serialization.TypeSerializers.Implementations;
-using Robust.Shared.Timing;
namespace Content.Client.Doors;
public sealed class DoorSystem : SharedDoorSystem
{
[Dependency] private readonly AnimationPlayerSystem _animationSystem = default!;
- [Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly IResourceCache _resourceCache = default!;
public override void Initialize()
diff --git a/Content.Client/Entry/EntryPoint.cs b/Content.Client/Entry/EntryPoint.cs
index 085a0a35f4..bbef67181b 100644
--- a/Content.Client/Entry/EntryPoint.cs
+++ b/Content.Client/Entry/EntryPoint.cs
@@ -108,7 +108,6 @@ namespace Content.Client.Entry
_prototypeManager.RegisterIgnore("gameMap");
_prototypeManager.RegisterIgnore("gameMapPool");
_prototypeManager.RegisterIgnore("lobbyBackground");
- _prototypeManager.RegisterIgnore("advertisementsPack");
_prototypeManager.RegisterIgnore("gamePreset");
_prototypeManager.RegisterIgnore("noiseChannel");
_prototypeManager.RegisterIgnore("spaceBiome");
diff --git a/Content.Client/IconSmoothing/IconSmoothSystem.cs b/Content.Client/IconSmoothing/IconSmoothSystem.cs
index 20a80c42a3..4b02560846 100644
--- a/Content.Client/IconSmoothing/IconSmoothSystem.cs
+++ b/Content.Client/IconSmoothing/IconSmoothSystem.cs
@@ -16,8 +16,6 @@ namespace Content.Client.IconSmoothing
[UsedImplicitly]
public sealed partial class IconSmoothSystem : EntitySystem
{
- [Dependency] private readonly IMapManager _mapManager = default!;
-
private readonly Queue _dirtyEntities = new();
private readonly Queue _anchorChangedEntities = new();
diff --git a/Content.Client/Input/ContentContexts.cs b/Content.Client/Input/ContentContexts.cs
index 03f4f3f38b..589de6d6a7 100644
--- a/Content.Client/Input/ContentContexts.cs
+++ b/Content.Client/Input/ContentContexts.cs
@@ -32,6 +32,7 @@ namespace Content.Client.Input
common.AddFunction(ContentKeyFunctions.ToggleFullscreen);
common.AddFunction(ContentKeyFunctions.MoveStoredItem);
common.AddFunction(ContentKeyFunctions.RotateStoredItem);
+ common.AddFunction(ContentKeyFunctions.SaveItemLocation);
common.AddFunction(ContentKeyFunctions.Point);
common.AddFunction(ContentKeyFunctions.ZoomOut);
common.AddFunction(ContentKeyFunctions.ZoomIn);
diff --git a/Content.Client/Items/Systems/ItemSystem.cs b/Content.Client/Items/Systems/ItemSystem.cs
index e406ba2b55..5e60d06d0c 100644
--- a/Content.Client/Items/Systems/ItemSystem.cs
+++ b/Content.Client/Items/Systems/ItemSystem.cs
@@ -93,7 +93,7 @@ public sealed class ItemSystem : SharedItemSystem
else if (TryComp(uid, out SpriteComponent? sprite))
rsi = sprite.BaseRSI;
- if (rsi == null || rsi.Path == null)
+ if (rsi == null)
return false;
var state = (item.HeldPrefix == null)
diff --git a/Content.Client/Kitchen/UI/GrinderMenu.xaml b/Content.Client/Kitchen/UI/GrinderMenu.xaml
index b83128d004..dacddd0df6 100644
--- a/Content.Client/Kitchen/UI/GrinderMenu.xaml
+++ b/Content.Client/Kitchen/UI/GrinderMenu.xaml
@@ -3,10 +3,12 @@
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
Title="{Loc grinder-menu-title}" MinSize="768 256">
-
-
-
-
+
+
+
+
+
+
diff --git a/Content.Client/Kitchen/UI/GrinderMenu.xaml.cs b/Content.Client/Kitchen/UI/GrinderMenu.xaml.cs
index 6e4b7a7618..f97d8a7330 100644
--- a/Content.Client/Kitchen/UI/GrinderMenu.xaml.cs
+++ b/Content.Client/Kitchen/UI/GrinderMenu.xaml.cs
@@ -24,6 +24,7 @@ namespace Content.Client.Kitchen.UI
_entityManager = entityManager;
_prototypeManager = prototypeManager;
_owner = owner;
+ AutoModeButton.OnPressed += owner.ToggleAutoMode;
GrindButton.OnPressed += owner.StartGrinding;
JuiceButton.OnPressed += owner.StartJuicing;
ChamberContentBox.EjectButton.OnPressed += owner.EjectAll;
@@ -56,6 +57,19 @@ namespace Content.Client.Kitchen.UI
GrindButton.Disabled = !state.CanGrind || !state.Powered;
JuiceButton.Disabled = !state.CanJuice || !state.Powered;
+ switch (state.AutoMode)
+ {
+ case GrinderAutoMode.Grind:
+ AutoModeButton.Text = Loc.GetString("grinder-menu-grind-button");
+ break;
+ case GrinderAutoMode.Juice:
+ AutoModeButton.Text = Loc.GetString("grinder-menu-juice-button");
+ break;
+ default:
+ AutoModeButton.Text = Loc.GetString("grinder-menu-auto-button-off");
+ break;
+ }
+
// TODO move this to a component state and ensure the net ids.
RefreshContentsDisplay(state.ReagentQuantities, _entityManager.GetEntityArray(state.ChamberContents), state.HasBeakerIn);
}
diff --git a/Content.Client/Kitchen/UI/ReagentGrinderBoundUserInterface.cs b/Content.Client/Kitchen/UI/ReagentGrinderBoundUserInterface.cs
index 39b85c261b..e6f108b305 100644
--- a/Content.Client/Kitchen/UI/ReagentGrinderBoundUserInterface.cs
+++ b/Content.Client/Kitchen/UI/ReagentGrinderBoundUserInterface.cs
@@ -52,6 +52,11 @@ namespace Content.Client.Kitchen.UI
_menu?.HandleMessage(message);
}
+ public void ToggleAutoMode(BaseButton.ButtonEventArgs args)
+ {
+ SendMessage(new ReagentGrinderToggleAutoModeMessage());
+ }
+
public void StartGrinding(BaseButton.ButtonEventArgs? _ = null)
{
SendMessage(new ReagentGrinderStartMessage(GrinderProgram.Grind));
diff --git a/Content.Client/LateJoin/LateJoinGui.cs b/Content.Client/LateJoin/LateJoinGui.cs
index 50347bbf64..a646b7903d 100644
--- a/Content.Client/LateJoin/LateJoinGui.cs
+++ b/Content.Client/LateJoin/LateJoinGui.cs
@@ -33,7 +33,7 @@ namespace Content.Client.LateJoin
private readonly SpriteSystem _sprites;
private readonly CrewManifestSystem _crewManifest;
- private readonly Dictionary> _jobButtons = new();
+ private readonly Dictionary>> _jobButtons = new();
private readonly Dictionary> _jobCategories = new();
private readonly List _jobLists = new();
@@ -139,7 +139,7 @@ namespace Content.Client.LateJoin
var jobListScroll = new ScrollContainer()
{
VerticalExpand = true,
- Children = {jobList},
+ Children = { jobList },
Visible = false,
};
@@ -163,11 +163,12 @@ namespace Content.Client.LateJoin
var departments = _prototypeManager.EnumeratePrototypes().ToArray();
Array.Sort(departments, DepartmentUIComparer.Instance);
+ _jobButtons[id] = new Dictionary>();
+
foreach (var department in departments)
{
var departmentName = Loc.GetString($"department-{department.ID}");
_jobCategories[id] = new Dictionary();
- _jobButtons[id] = new Dictionary();
var stationAvailable = _gameTicker.JobsAvailable[id];
var jobsAvailable = new List();
@@ -223,7 +224,13 @@ namespace Content.Client.LateJoin
foreach (var prototype in jobsAvailable)
{
var value = stationAvailable[prototype.ID];
- var jobButton = new JobButton(prototype.ID, value);
+
+ var jobLabel = new Label
+ {
+ Margin = new Thickness(5f, 0, 0, 0)
+ };
+
+ var jobButton = new JobButton(jobLabel, prototype.ID, prototype.LocalizedName, value);
var jobSelector = new BoxContainer
{
@@ -241,14 +248,6 @@ namespace Content.Client.LateJoin
icon.Texture = _sprites.Frame0(jobIcon.Icon);
jobSelector.AddChild(icon);
- var jobLabel = new Label
- {
- Margin = new Thickness(5f, 0, 0, 0),
- Text = value != null ?
- Loc.GetString("late-join-gui-job-slot-capped", ("jobName", prototype.LocalizedName), ("amount", value)) :
- Loc.GetString("late-join-gui-job-slot-uncapped", ("jobName", prototype.LocalizedName)),
- };
-
jobSelector.AddChild(jobLabel);
jobButton.AddChild(jobSelector);
category.AddChild(jobButton);
@@ -280,15 +279,43 @@ namespace Content.Client.LateJoin
jobButton.Disabled = true;
}
- _jobButtons[id][prototype.ID] = jobButton;
+ if (!_jobButtons[id].ContainsKey(prototype.ID))
+ {
+ _jobButtons[id][prototype.ID] = new List();
+ }
+
+ _jobButtons[id][prototype.ID].Add(jobButton);
}
}
}
}
- private void JobsAvailableUpdated(IReadOnlyDictionary> _)
+ private void JobsAvailableUpdated(IReadOnlyDictionary> updatedJobs)
{
- RebuildUI();
+ foreach (var stationEntries in updatedJobs)
+ {
+ if (_jobButtons.ContainsKey(stationEntries.Key))
+ {
+ var jobsAvailable = stationEntries.Value;
+
+ var existingJobEntries = _jobButtons[stationEntries.Key];
+ foreach (var existingJobEntry in existingJobEntries)
+ {
+ if (jobsAvailable.ContainsKey(existingJobEntry.Key))
+ {
+ var updatedJobValue = jobsAvailable[existingJobEntry.Key];
+ foreach (var matchingJobButton in existingJobEntry.Value)
+ {
+ if (matchingJobButton.Amount != updatedJobValue)
+ {
+ matchingJobButton.RefreshLabel(updatedJobValue);
+ matchingJobButton.Disabled |= matchingJobButton.Amount == 0;
+ }
+ }
+ }
+ }
+ }
+ }
}
protected override void Dispose(bool disposing)
@@ -307,14 +334,33 @@ namespace Content.Client.LateJoin
sealed class JobButton : ContainerButton
{
+ public Label JobLabel { get; }
public string JobId { get; }
- public uint? Amount { get; }
+ public string JobLocalisedName { get; }
+ public uint? Amount { get; private set; }
+ private bool _initialised = false;
- public JobButton(string jobId, uint? amount)
+ public JobButton(Label jobLabel, string jobId, string jobLocalisedName, uint? amount)
{
+ JobLabel = jobLabel;
JobId = jobId;
- Amount = amount;
+ JobLocalisedName = jobLocalisedName;
+ RefreshLabel(amount);
AddStyleClass(StyleClassButton);
+ _initialised = true;
+ }
+
+ public void RefreshLabel(uint? amount)
+ {
+ if (Amount == amount && _initialised)
+ {
+ return;
+ }
+ Amount = amount;
+
+ JobLabel.Text = Amount != null ?
+ Loc.GetString("late-join-gui-job-slot-capped", ("jobName", JobLocalisedName), ("amount", Amount)) :
+ Loc.GetString("late-join-gui-job-slot-uncapped", ("jobName", JobLocalisedName));
}
}
}
diff --git a/Content.Client/NPC/PathfindingSystem.cs b/Content.Client/NPC/PathfindingSystem.cs
index 7bf3df1f0b..709601a57b 100644
--- a/Content.Client/NPC/PathfindingSystem.cs
+++ b/Content.Client/NPC/PathfindingSystem.cs
@@ -289,7 +289,6 @@ namespace Content.Client.NPC
var invGridMatrix = gridXform.InvWorldMatrix;
DebugPathPoly? nearest = null;
- var nearestDistance = float.MaxValue;
foreach (var poly in tile)
{
diff --git a/Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs b/Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs
index f0537079b9..aca9efcfe2 100644
--- a/Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs
+++ b/Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs
@@ -183,6 +183,7 @@ namespace Content.Client.Options.UI.Tabs
AddButton(ContentKeyFunctions.SwapHands);
AddButton(ContentKeyFunctions.MoveStoredItem);
AddButton(ContentKeyFunctions.RotateStoredItem);
+ AddButton(ContentKeyFunctions.SaveItemLocation);
AddHeader("ui-options-header-interaction-adv");
AddButton(ContentKeyFunctions.SmartEquipBackpack);
diff --git a/Content.Client/Revenant/RevenantSystem.cs b/Content.Client/Revenant/RevenantSystem.cs
index 6e7d0d2a1b..49d29d8a5f 100644
--- a/Content.Client/Revenant/RevenantSystem.cs
+++ b/Content.Client/Revenant/RevenantSystem.cs
@@ -1,3 +1,5 @@
+using Content.Client.Alerts;
+using Content.Shared.Alert;
using Content.Shared.Revenant;
using Content.Shared.Revenant.Components;
using Robust.Client.GameObjects;
@@ -13,6 +15,7 @@ public sealed class RevenantSystem : EntitySystem
base.Initialize();
SubscribeLocalEvent(OnAppearanceChange);
+ SubscribeLocalEvent(OnUpdateAlert);
}
private void OnAppearanceChange(EntityUid uid, RevenantComponent component, ref AppearanceChangeEvent args)
@@ -36,4 +39,16 @@ public sealed class RevenantSystem : EntitySystem
args.Sprite.LayerSetState(0, component.State);
}
}
+
+ private void OnUpdateAlert(Entity ent, ref UpdateAlertSpriteEvent args)
+ {
+ if (args.Alert.AlertType != AlertType.Essence)
+ return;
+
+ var sprite = args.SpriteViewEnt.Comp;
+ var essence = Math.Clamp(ent.Comp.Essence.Int(), 0, 999);
+ sprite.LayerSetState(RevenantVisualLayers.Digit1, $"{(essence / 100) % 10}");
+ sprite.LayerSetState(RevenantVisualLayers.Digit2, $"{(essence / 10) % 10}");
+ sprite.LayerSetState(RevenantVisualLayers.Digit3, $"{essence % 10}");
+ }
}
diff --git a/Content.Client/Shuttles/UI/BaseShuttleControl.xaml.cs b/Content.Client/Shuttles/UI/BaseShuttleControl.xaml.cs
index fed2a9f171..284c668190 100644
--- a/Content.Client/Shuttles/UI/BaseShuttleControl.xaml.cs
+++ b/Content.Client/Shuttles/UI/BaseShuttleControl.xaml.cs
@@ -88,7 +88,6 @@ public partial class BaseShuttleControl : MapGridControl
var cornerDistance = MathF.Sqrt(WorldRange * WorldRange + WorldRange * WorldRange);
var origin = ScalePosition(-new Vector2(Offset.X, -Offset.Y));
- var distOffset = -24f;
for (var radius = minDistance; radius <= maxDistance; radius *= EquatorialMultiplier)
{
diff --git a/Content.Client/UserInterface/Systems/Alerts/AlertsUIController.cs b/Content.Client/UserInterface/Systems/Alerts/AlertsUIController.cs
index 826bbf199b..3b85972a9b 100644
--- a/Content.Client/UserInterface/Systems/Alerts/AlertsUIController.cs
+++ b/Content.Client/UserInterface/Systems/Alerts/AlertsUIController.cs
@@ -3,6 +3,8 @@ using Content.Client.Gameplay;
using Content.Client.UserInterface.Systems.Alerts.Widgets;
using Content.Client.UserInterface.Systems.Gameplay;
using Content.Shared.Alert;
+using Robust.Client.GameObjects;
+using Robust.Client.Player;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controllers;
@@ -10,6 +12,8 @@ namespace Content.Client.UserInterface.Systems.Alerts;
public sealed class AlertsUIController : UIController, IOnStateEntered, IOnSystemChanged
{
+ [Dependency] private readonly IPlayerManager _player = default!;
+
[UISystemDependency] private readonly ClientAlertsSystem? _alertsSystem = default;
private AlertsUI? UI => UIManager.GetActiveUIWidgetOrNull();
@@ -84,4 +88,16 @@ public sealed class AlertsUIController : UIController, IOnStateEntered(spriteViewEnt, out var sprite))
+ return;
+
+ var ev = new UpdateAlertSpriteEvent((spriteViewEnt, sprite), alert);
+ EntityManager.EventBus.RaiseLocalEvent(player, ref ev);
+ }
}
diff --git a/Content.Client/UserInterface/Systems/Alerts/Controls/AlertControl.cs b/Content.Client/UserInterface/Systems/Alerts/Controls/AlertControl.cs
index 4445bb0cd0..9423f7288d 100644
--- a/Content.Client/UserInterface/Systems/Alerts/Controls/AlertControl.cs
+++ b/Content.Client/UserInterface/Systems/Alerts/Controls/AlertControl.cs
@@ -2,6 +2,8 @@
using Content.Client.Actions.UI;
using Content.Client.Cooldown;
using Content.Shared.Alert;
+using Robust.Client.GameObjects;
+using Robust.Client.Graphics;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Timing;
@@ -33,9 +35,12 @@ namespace Content.Client.UserInterface.Systems.Alerts.Controls
private short? _severity;
private readonly IGameTiming _gameTiming;
- private readonly AnimatedTextureRect _icon;
+ private readonly IEntityManager _entityManager;
+ private readonly SpriteView _icon;
private readonly CooldownGraphic _cooldownGraphic;
+ private EntityUid _spriteViewEntity;
+
///
/// Creates an alert control reflecting the indicated alert + state
///
@@ -44,19 +49,30 @@ namespace Content.Client.UserInterface.Systems.Alerts.Controls
public AlertControl(AlertPrototype alert, short? severity)
{
_gameTiming = IoCManager.Resolve();
+ _entityManager = IoCManager.Resolve();
TooltipSupplier = SupplyTooltip;
Alert = alert;
_severity = severity;
- var specifier = alert.GetIcon(_severity);
- _icon = new AnimatedTextureRect
- {
- DisplayRect = {TextureScale = new Vector2(2, 2)}
- };
- _icon.SetFromSpriteSpecifier(specifier);
+ _spriteViewEntity = _entityManager.Spawn(Alert.AlertViewEntity);
+ if (_entityManager.TryGetComponent(_spriteViewEntity, out var sprite))
+ {
+ var icon = Alert.GetIcon(_severity);
+ if (sprite.LayerMapTryGet(AlertVisualLayers.Base, out var layer))
+ sprite.LayerSetSprite(layer, icon);
+ }
+
+ _icon = new SpriteView
+ {
+ Scale = new Vector2(2, 2)
+ };
+ _icon.SetEntity(_spriteViewEntity);
Children.Add(_icon);
- _cooldownGraphic = new CooldownGraphic();
+ _cooldownGraphic = new CooldownGraphic
+ {
+ MaxSize = new Vector2(64, 64)
+ };
Children.Add(_cooldownGraphic);
}
@@ -72,16 +88,22 @@ namespace Content.Client.UserInterface.Systems.Alerts.Controls
///
public void SetSeverity(short? severity)
{
- if (_severity != severity)
- {
- _severity = severity;
- _icon.SetFromSpriteSpecifier(Alert.GetIcon(_severity));
- }
+ if (_severity == severity)
+ return;
+ _severity = severity;
+
+ if (!_entityManager.TryGetComponent(_spriteViewEntity, out var sprite))
+ return;
+ var icon = Alert.GetIcon(_severity);
+ if (sprite.LayerMapTryGet(AlertVisualLayers.Base, out var layer))
+ sprite.LayerSetSprite(layer, icon);
}
protected override void FrameUpdate(FrameEventArgs args)
{
base.FrameUpdate(args);
+ UserInterfaceManager.GetUIController().UpdateAlertSpriteEntity(_spriteViewEntity, Alert);
+
if (!Cooldown.HasValue)
{
_cooldownGraphic.Visible = false;
@@ -91,5 +113,17 @@ namespace Content.Client.UserInterface.Systems.Alerts.Controls
_cooldownGraphic.FromTime(Cooldown.Value.Start, Cooldown.Value.End);
}
+
+ protected override void Dispose(bool disposing)
+ {
+ base.Dispose(disposing);
+
+ _entityManager.DeleteEntity(_spriteViewEntity);
+ }
+ }
+
+ public enum AlertVisualLayers : byte
+ {
+ Base
}
}
diff --git a/Content.Client/UserInterface/Systems/Storage/Controls/StorageContainer.cs b/Content.Client/UserInterface/Systems/Storage/Controls/StorageContainer.cs
index bd952fe957..e39ac5d322 100644
--- a/Content.Client/UserInterface/Systems/Storage/Controls/StorageContainer.cs
+++ b/Content.Client/UserInterface/Systems/Storage/Controls/StorageContainer.cs
@@ -12,6 +12,7 @@ using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.Timing;
+using Robust.Shared.Utility;
namespace Content.Client.UserInterface.Systems.Storage.Controls;
@@ -355,6 +356,40 @@ public sealed class StorageContainer : BaseWindow
origin,
currentLocation.Rotation);
+ foreach (var locations in storageComponent.SavedLocations)
+ {
+ if (!_entity.TryGetComponent(currentEnt, out var meta) || meta.EntityName != locations.Key)
+ continue;
+
+ float spot = 0;
+ var marked = new List();
+
+ foreach (var location in locations.Value)
+ {
+ var shape = itemSystem.GetAdjustedItemShape(currentEnt, location);
+ var bound = shape.GetBoundingBox();
+
+ var spotFree = storageSystem.ItemFitsInGridLocation(currentEnt, StorageEntity.Value, location);
+
+ if (spotFree)
+ spot++;
+
+ for (var y = bound.Bottom; y <= bound.Top; y++)
+ {
+ for (var x = bound.Left; x <= bound.Right; x++)
+ {
+ if (TryGetBackgroundCell(x, y, out var cell) && shape.Contains(x, y) && !marked.Contains(cell))
+ {
+ marked.Add(cell);
+ cell.ModulateSelfOverride = spotFree
+ ? Color.FromHsv((0.18f, 1 / spot, 0.5f / spot + 0.5f, 1f))
+ : Color.FromHex("#2222CC");
+ }
+ }
+ }
+ }
+ }
+
var validColor = usingInHand ? Color.Goldenrod : Color.FromHex("#1E8000");
for (var y = itemBounding.Bottom; y <= itemBounding.Top; y++)
diff --git a/Content.Client/UserInterface/Systems/Storage/StorageUIController.cs b/Content.Client/UserInterface/Systems/Storage/StorageUIController.cs
index 5f3ae3a2da..b865b54dd0 100644
--- a/Content.Client/UserInterface/Systems/Storage/StorageUIController.cs
+++ b/Content.Client/UserInterface/Systems/Storage/StorageUIController.cs
@@ -240,6 +240,16 @@ public sealed class StorageUIController : UIController, IOnSystemChanged().DoExamine(control.Entity);
diff --git a/Content.Client/VoiceMask/VoiceMaskBoundUserInterface.cs b/Content.Client/VoiceMask/VoiceMaskBoundUserInterface.cs
index 74593b6670..715bc48bb3 100644
--- a/Content.Client/VoiceMask/VoiceMaskBoundUserInterface.cs
+++ b/Content.Client/VoiceMask/VoiceMaskBoundUserInterface.cs
@@ -1,10 +1,13 @@
using Content.Shared.VoiceMask;
using Robust.Client.GameObjects;
+using Robust.Shared.Prototypes;
namespace Content.Client.VoiceMask;
public sealed class VoiceMaskBoundUserInterface : BoundUserInterface
{
+ [Dependency] private readonly IPrototypeManager _proto = default!;
+
[ViewVariables]
private VoiceMaskNameChangeWindow? _window;
@@ -16,11 +19,12 @@ public sealed class VoiceMaskBoundUserInterface : BoundUserInterface
{
base.Open();
- _window = new();
+ _window = new(_proto);
_window.OpenCentered();
_window.OnNameChange += OnNameSelected;
- _window.OnVoiceChange += (value) => SendMessage(new VoiceMaskChangeVoiceMessage(value)); // Corvax-TTS
+ _window.OnVerbChange += verb => SendMessage(new VoiceMaskChangeVerbMessage(verb));
+ _window.OnVoiceChange += voice => SendMessage(new VoiceMaskChangeVoiceMessage(voice)); // Corvax-TTS
_window.OnClose += Close;
}
@@ -36,7 +40,7 @@ public sealed class VoiceMaskBoundUserInterface : BoundUserInterface
return;
}
- _window.UpdateState(cast.Name, cast.Voice); // Corvax-TTS
+ _window.UpdateState(cast.Name, cast.Voice, cast.Verb); // Corvax-TTS
}
protected override void Dispose(bool disposing)
diff --git a/Content.Client/VoiceMask/VoiceMaskNameChangeWindow.xaml b/Content.Client/VoiceMask/VoiceMaskNameChangeWindow.xaml
index 0a4af81fd6..c51834b596 100644
--- a/Content.Client/VoiceMask/VoiceMaskNameChangeWindow.xaml
+++ b/Content.Client/VoiceMask/VoiceMaskNameChangeWindow.xaml
@@ -1,17 +1,22 @@
-
-
+ MinSize="5 30">
+
-
+
+
+
+
+
-
-
-
+
+
+
-
+
diff --git a/Content.Client/VoiceMask/VoiceMaskNameChangeWindow.xaml.cs b/Content.Client/VoiceMask/VoiceMaskNameChangeWindow.xaml.cs
index bbe2143a98..57b40d5087 100644
--- a/Content.Client/VoiceMask/VoiceMaskNameChangeWindow.xaml.cs
+++ b/Content.Client/VoiceMask/VoiceMaskNameChangeWindow.xaml.cs
@@ -1,37 +1,87 @@
using System.Linq;
using Content.Shared.Corvax.TTS;
+using Content.Client.UserInterface.Controls;
+using Content.Shared.Speech;
using Robust.Client.AutoGenerated;
-using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Prototypes;
namespace Content.Client.VoiceMask;
[GenerateTypedNameReferences]
-public sealed partial class VoiceMaskNameChangeWindow : DefaultWindow
+public sealed partial class VoiceMaskNameChangeWindow : FancyWindow
{
- private readonly List _voices; // Corvax-TTS
-
public Action? OnNameChange;
+ public Action? OnVerbChange;
public Action? OnVoiceChange; // Corvax-TTS
- public VoiceMaskNameChangeWindow()
+ private List<(string, string)> _verbs = new();
+ private List _voices = new(); // Corvax-TTS
+
+ private string? _verb;
+
+ public VoiceMaskNameChangeWindow(IPrototypeManager proto)
{
RobustXamlLoader.Load(this);
NameSelectorSet.OnPressed += _ =>
{
- OnNameChange!(NameSelector.Text);
+ OnNameChange?.Invoke(NameSelector.Text);
};
- // Corvax-TTS-Start
+
+ SpeechVerbSelector.OnItemSelected += args =>
+ {
+ OnVerbChange?.Invoke((string?) args.Button.GetItemMetadata(args.Id));
+ SpeechVerbSelector.SelectId(args.Id);
+ };
+
+ ReloadVerbs(proto);
+ ReloadVoices(proto); // Corvax-TTS
+
+ AddVerbs();
+ }
+
+ private void ReloadVerbs(IPrototypeManager proto)
+ {
+ foreach (var verb in proto.EnumeratePrototypes())
+ {
+ _verbs.Add((Loc.GetString(verb.Name), verb.ID));
+ }
+ _verbs.Sort((a, b) => a.Item1.CompareTo(b.Item1));
+ }
+
+ private void AddVerbs()
+ {
+ SpeechVerbSelector.Clear();
+
+ AddVerb(Loc.GetString("chat-speech-verb-name-none"), null);
+ foreach (var (name, id) in _verbs)
+ {
+ AddVerb(name, id);
+ }
+ }
+
+ private void AddVerb(string name, string? verb)
+ {
+ var id = SpeechVerbSelector.ItemCount;
+ SpeechVerbSelector.AddItem(name);
+ if (verb is {} metadata)
+ SpeechVerbSelector.SetItemMetadata(id, metadata);
+
+ if (verb == _verb)
+ SpeechVerbSelector.SelectId(id);
+ }
+
+ // Corvax-TTS-Start
+ private void ReloadVoices(IPrototypeManager proto)
+ {
VoiceSelector.OnItemSelected += args =>
{
VoiceSelector.SelectId(args.Id);
if (VoiceSelector.SelectedMetadata != null)
OnVoiceChange!((string)VoiceSelector.SelectedMetadata);
};
- _voices = IoCManager
- .Resolve()
+ _voices = proto
.EnumeratePrototypes()
.Where(o => o.RoundStart)
.OrderBy(o => Loc.GetString(o.Name))
@@ -42,12 +92,22 @@ public sealed partial class VoiceMaskNameChangeWindow : DefaultWindow
VoiceSelector.AddItem(name);
VoiceSelector.SetItemMetadata(i, _voices[i].ID);
}
- // Corvax-TTS-End
}
+ // Corvax-TTS-End
- public void UpdateState(string name, string voice) // Corvax-TTS
+ public void UpdateState(string name, string voice, string? verb) // Corvax-TTS
{
NameSelector.Text = name;
+ _verb = verb;
+
+ for (int id = 0; id < SpeechVerbSelector.ItemCount; id++)
+ {
+ if (string.Equals(verb, SpeechVerbSelector.GetItemMetadata(id)))
+ {
+ SpeechVerbSelector.SelectId(id);
+ break;
+ }
+ }
// Corvax-TTS-Start
var voiceIdx = _voices.FindIndex(v => v.ID == voice);
diff --git a/Content.IntegrationTests/PoolManager.cs b/Content.IntegrationTests/PoolManager.cs
index 6046ed65e4..b544fe2854 100644
--- a/Content.IntegrationTests/PoolManager.cs
+++ b/Content.IntegrationTests/PoolManager.cs
@@ -306,11 +306,6 @@ public static partial class PoolManager
Pairs[fallback!] = true;
}
- if (fallback == null && _pairId > 8)
- {
- var x = 2;
- }
-
return fallback;
}
}
diff --git a/Content.IntegrationTests/Tests/Body/LungTest.cs b/Content.IntegrationTests/Tests/Body/LungTest.cs
index f2e19849b0..dce3741c98 100644
--- a/Content.IntegrationTests/Tests/Body/LungTest.cs
+++ b/Content.IntegrationTests/Tests/Body/LungTest.cs
@@ -9,7 +9,6 @@ using Robust.Shared.Configuration;
using Robust.Shared.GameObjects;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
-using Robust.Shared.Maths;
using System.Linq;
using System.Numerics;
@@ -61,12 +60,11 @@ namespace Content.IntegrationTests.Tests.Body
var mapManager = server.ResolveDependency();
var entityManager = server.ResolveDependency();
var mapLoader = entityManager.System();
- RespiratorSystem respSys = default;
- MetabolizerSystem metaSys = default;
MapId mapId;
EntityUid? grid = null;
BodyComponent body = default;
+ RespiratorComponent resp = default;
EntityUid human = default;
GridAtmosphereComponent relevantAtmos = default;
var startingMoles = 0.0f;
@@ -99,17 +97,15 @@ namespace Content.IntegrationTests.Tests.Body
await server.WaitAssertion(() =>
{
- var coords = new Vector2(0.5f, -1f);
- var coordinates = new EntityCoordinates(grid.Value, coords);
+ var center = new Vector2(0.5f, 0.5f);
+ var coordinates = new EntityCoordinates(grid.Value, center);
human = entityManager.SpawnEntity("HumanLungDummy", coordinates);
- respSys = entityManager.System();
- metaSys = entityManager.System();
relevantAtmos = entityManager.GetComponent(grid.Value);
- startingMoles = GetMapMoles();
+ startingMoles = 100f; // Hardcoded because GetMapMoles returns 900 here for some reason.
#pragma warning disable NUnit2045
Assert.That(entityManager.TryGetComponent(human, out body), Is.True);
- Assert.That(entityManager.HasComponent(human), Is.True);
+ Assert.That(entityManager.TryGetComponent(human, out resp), Is.True);
#pragma warning restore NUnit2045
});
@@ -118,18 +114,19 @@ namespace Content.IntegrationTests.Tests.Body
var inhaleCycles = 100;
for (var i = 0; i < inhaleCycles; i++)
{
- await server.WaitAssertion(() =>
- {
- // inhale
- respSys.Update(2.0f);
- Assert.That(GetMapMoles(), Is.LessThan(startingMoles));
+ // Breathe in
+ await PoolManager.WaitUntil(server, () => resp.Status == RespiratorStatus.Exhaling);
+ Assert.That(
+ GetMapMoles(), Is.LessThan(startingMoles),
+ "Did not inhale in any gas"
+ );
- // metabolize + exhale
- metaSys.Update(1.0f);
- metaSys.Update(1.0f);
- respSys.Update(2.0f);
- Assert.That(GetMapMoles(), Is.EqualTo(startingMoles).Within(0.0002));
- });
+ // Breathe out
+ await PoolManager.WaitUntil(server, () => resp.Status == RespiratorStatus.Inhaling);
+ Assert.That(
+ GetMapMoles(), Is.EqualTo(startingMoles).Within(0.0002),
+ "Did not exhale as much gas as was inhaled"
+ );
}
await pair.CleanReturnAsync();
diff --git a/Content.IntegrationTests/Tests/Buckle/BuckleTest.cs b/Content.IntegrationTests/Tests/Buckle/BuckleTest.cs
index 6e2a080370..7c700d9fb8 100644
--- a/Content.IntegrationTests/Tests/Buckle/BuckleTest.cs
+++ b/Content.IntegrationTests/Tests/Buckle/BuckleTest.cs
@@ -181,9 +181,8 @@ namespace Content.IntegrationTests.Tests.Buckle
#pragma warning restore NUnit2045
// Move away from the chair
- var xformQuery = entityManager.GetEntityQuery();
- var oldWorldPosition = xformSystem.GetWorldPosition(chair, xformQuery);
- xformSystem.SetWorldPosition(human, oldWorldPosition + new Vector2(1000, 1000), xformQuery);
+ var oldWorldPosition = xformSystem.GetWorldPosition(chair);
+ xformSystem.SetWorldPosition(human, oldWorldPosition + new Vector2(1000, 1000));
// Out of range
#pragma warning disable NUnit2045 // Interdependent asserts.
@@ -193,8 +192,8 @@ namespace Content.IntegrationTests.Tests.Buckle
#pragma warning restore NUnit2045
// Move near the chair
- oldWorldPosition = xformSystem.GetWorldPosition(chair, xformQuery);
- xformSystem.SetWorldPosition(human, oldWorldPosition + new Vector2(0.5f, 0), xformQuery);
+ oldWorldPosition = xformSystem.GetWorldPosition(chair);
+ xformSystem.SetWorldPosition(human, oldWorldPosition + new Vector2(0.5f, 0));
// In range
#pragma warning disable NUnit2045 // Interdependent asserts.
@@ -220,8 +219,8 @@ namespace Content.IntegrationTests.Tests.Buckle
Assert.That(buckleSystem.TryBuckle(human, human, chair, buckleComp: buckle));
// Move away from the chair
- oldWorldPosition = xformSystem.GetWorldPosition(chair, xformQuery);
- xformSystem.SetWorldPosition(human, oldWorldPosition + new Vector2(1, 0), xformQuery);
+ oldWorldPosition = xformSystem.GetWorldPosition(chair);
+ xformSystem.SetWorldPosition(human, oldWorldPosition + new Vector2(1, 0));
});
await server.WaitRunTicks(1);
@@ -371,9 +370,8 @@ namespace Content.IntegrationTests.Tests.Buckle
});
// Move the buckled entity away
- var xformQuery = entityManager.GetEntityQuery();
- var oldWorldPosition = xformSystem.GetWorldPosition(chair, xformQuery);
- xformSystem.SetWorldPosition(human, oldWorldPosition + new Vector2(100, 0), xformQuery);
+ var oldWorldPosition = xformSystem.GetWorldPosition(chair);
+ xformSystem.SetWorldPosition(human, oldWorldPosition + new Vector2(100, 0));
});
await PoolManager.WaitUntil(server, () => !buckle.Buckled, 10);
@@ -383,9 +381,8 @@ namespace Content.IntegrationTests.Tests.Buckle
await server.WaitAssertion(() =>
{
// Move the now unbuckled entity back onto the chair
- var xformQuery = entityManager.GetEntityQuery();
- var oldWorldPosition = xformSystem.GetWorldPosition(chair, xformQuery);
- xformSystem.SetWorldPosition(human, oldWorldPosition, xformQuery);
+ var oldWorldPosition = xformSystem.GetWorldPosition(chair);
+ xformSystem.SetWorldPosition(human, oldWorldPosition);
// Buckle
Assert.That(buckleSystem.TryBuckle(human, human, chair, buckleComp: buckle));
diff --git a/Content.IntegrationTests/Tests/Fluids/PuddleTest.cs b/Content.IntegrationTests/Tests/Fluids/PuddleTest.cs
index 3213bba51f..611af67380 100644
--- a/Content.IntegrationTests/Tests/Fluids/PuddleTest.cs
+++ b/Content.IntegrationTests/Tests/Fluids/PuddleTest.cs
@@ -67,7 +67,7 @@ namespace Content.IntegrationTests.Tests.Fluids
await server.WaitAssertion(() =>
{
- var coordinates = grid.ToCoordinates();
+ var coordinates = grid.Owner.ToCoordinates();
var solution = new Solution("Water", FixedPoint2.New(20));
Assert.That(spillSystem.TrySpillAt(coordinates, solution, out _), Is.False);
diff --git a/Content.IntegrationTests/Tests/GameObjects/Components/ActionBlocking/HandCuffTest.cs b/Content.IntegrationTests/Tests/GameObjects/Components/ActionBlocking/HandCuffTest.cs
index 1d5dd6d34e..c6a8e618cc 100644
--- a/Content.IntegrationTests/Tests/GameObjects/Components/ActionBlocking/HandCuffTest.cs
+++ b/Content.IntegrationTests/Tests/GameObjects/Components/ActionBlocking/HandCuffTest.cs
@@ -58,7 +58,6 @@ namespace Content.IntegrationTests.Tests.GameObjects.Components.ActionBlocking
var cuffableSys = entityManager.System();
var xformSys = entityManager.System();
- var xformQuery = entityManager.GetEntityQuery();
// Spawn the entities
human = entityManager.SpawnEntity("HumanHandcuffDummy", coordinates);
@@ -66,8 +65,8 @@ namespace Content.IntegrationTests.Tests.GameObjects.Components.ActionBlocking
cuffs = entityManager.SpawnEntity("HandcuffsDummy", coordinates);
secondCuffs = entityManager.SpawnEntity("HandcuffsDummy", coordinates);
- var coords = xformSys.GetWorldPosition(otherHuman, xformQuery);
- xformSys.SetWorldPosition(human, coords, xformQuery);
+ var coords = xformSys.GetWorldPosition(otherHuman);
+ xformSys.SetWorldPosition(human, coords);
// Test for components existing
Assert.Multiple(() =>
diff --git a/Content.IntegrationTests/Tests/Power/PowerTest.cs b/Content.IntegrationTests/Tests/Power/PowerTest.cs
index d4e2cde9b0..a6af3e6a65 100644
--- a/Content.IntegrationTests/Tests/Power/PowerTest.cs
+++ b/Content.IntegrationTests/Tests/Power/PowerTest.cs
@@ -176,16 +176,18 @@ namespace Content.IntegrationTests.Tests.Power
var map = mapManager.CreateMap();
var grid = mapManager.CreateGrid(map);
+ var gridOwner = grid.Owner;
+
// Power only works when anchored
for (var i = 0; i < 3; i++)
{
grid.SetTile(new Vector2i(0, i), new Tile(1));
- entityManager.SpawnEntity("CableHV", grid.ToCoordinates(0, i));
+ entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, i));
}
- var generatorEnt = entityManager.SpawnEntity("GeneratorDummy", grid.ToCoordinates());
- var consumerEnt1 = entityManager.SpawnEntity("ConsumerDummy", grid.ToCoordinates(0, 1));
- var consumerEnt2 = entityManager.SpawnEntity("ConsumerDummy", grid.ToCoordinates(0, 2));
+ var generatorEnt = entityManager.SpawnEntity("GeneratorDummy", gridOwner.ToCoordinates());
+ var consumerEnt1 = entityManager.SpawnEntity("ConsumerDummy", gridOwner.ToCoordinates(0, 1));
+ var consumerEnt2 = entityManager.SpawnEntity("ConsumerDummy", gridOwner.ToCoordinates(0, 2));
supplier = entityManager.GetComponent(generatorEnt);
consumer1 = entityManager.GetComponent(consumerEnt1);
@@ -237,16 +239,18 @@ namespace Content.IntegrationTests.Tests.Power
var map = mapManager.CreateMap();
var grid = mapManager.CreateGrid(map);
+ var gridOwner = grid.Owner;
+
// Power only works when anchored
for (var i = 0; i < 3; i++)
{
grid.SetTile(new Vector2i(0, i), new Tile(1));
- entityManager.SpawnEntity("CableHV", grid.ToCoordinates(0, i));
+ entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, i));
}
- var generatorEnt = entityManager.SpawnEntity("GeneratorDummy", grid.ToCoordinates());
- var consumerEnt1 = entityManager.SpawnEntity("ConsumerDummy", grid.ToCoordinates(0, 1));
- var consumerEnt2 = entityManager.SpawnEntity("ConsumerDummy", grid.ToCoordinates(0, 2));
+ var generatorEnt = entityManager.SpawnEntity("GeneratorDummy", gridOwner.ToCoordinates());
+ var consumerEnt1 = entityManager.SpawnEntity("ConsumerDummy", gridOwner.ToCoordinates(0, 1));
+ var consumerEnt2 = entityManager.SpawnEntity("ConsumerDummy", gridOwner.ToCoordinates(0, 2));
supplier = entityManager.GetComponent(generatorEnt);
consumer1 = entityManager.GetComponent(consumerEnt1);
@@ -292,16 +296,17 @@ namespace Content.IntegrationTests.Tests.Power
{
var map = mapManager.CreateMap();
var grid = mapManager.CreateGrid(map);
+ var gridOwner = grid.Owner;
// Power only works when anchored
for (var i = 0; i < 3; i++)
{
grid.SetTile(new Vector2i(0, i), new Tile(1));
- entityManager.SpawnEntity("CableHV", grid.ToCoordinates(0, i));
+ entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, i));
}
- var generatorEnt = entityManager.SpawnEntity("GeneratorDummy", grid.ToCoordinates());
- var consumerEnt = entityManager.SpawnEntity("ConsumerDummy", grid.ToCoordinates(0, 2));
+ var generatorEnt = entityManager.SpawnEntity("GeneratorDummy", gridOwner.ToCoordinates());
+ var consumerEnt = entityManager.SpawnEntity("ConsumerDummy", gridOwner.ToCoordinates(0, 2));
supplier = entityManager.GetComponent(generatorEnt);
consumer = entityManager.GetComponent(consumerEnt);
@@ -383,16 +388,17 @@ namespace Content.IntegrationTests.Tests.Power
{
var map = mapManager.CreateMap();
var grid = mapManager.CreateGrid(map);
+ var gridOwner = grid.Owner;
// Power only works when anchored
for (var i = 0; i < 3; i++)
{
grid.SetTile(new Vector2i(0, i), new Tile(1));
- entityManager.SpawnEntity("CableHV", grid.ToCoordinates(0, i));
+ entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, i));
}
- var generatorEnt = entityManager.SpawnEntity("DischargingBatteryDummy", grid.ToCoordinates());
- var consumerEnt = entityManager.SpawnEntity("ConsumerDummy", grid.ToCoordinates(0, 2));
+ var generatorEnt = entityManager.SpawnEntity("DischargingBatteryDummy", gridOwner.ToCoordinates());
+ var consumerEnt = entityManager.SpawnEntity("ConsumerDummy", gridOwner.ToCoordinates(0, 2));
netBattery = entityManager.GetComponent(generatorEnt);
battery = entityManager.GetComponent(generatorEnt);
@@ -486,17 +492,18 @@ namespace Content.IntegrationTests.Tests.Power
{
var map = mapManager.CreateMap();
var grid = mapManager.CreateGrid(map);
+ var gridOwner = grid.Owner;
// Power only works when anchored
for (var i = 0; i < 3; i++)
{
grid.SetTile(new Vector2i(0, i), new Tile(1));
- entityManager.SpawnEntity("CableHV", grid.ToCoordinates(0, i));
+ entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, i));
}
- var generatorEnt = entityManager.SpawnEntity("GeneratorDummy", grid.ToCoordinates());
- var consumerEnt = entityManager.SpawnEntity("ConsumerDummy", grid.ToCoordinates(0, 1));
- var batteryEnt = entityManager.SpawnEntity("DischargingBatteryDummy", grid.ToCoordinates(0, 2));
+ var generatorEnt = entityManager.SpawnEntity("GeneratorDummy", gridOwner.ToCoordinates());
+ var consumerEnt = entityManager.SpawnEntity("ConsumerDummy", gridOwner.ToCoordinates(0, 1));
+ var batteryEnt = entityManager.SpawnEntity("DischargingBatteryDummy", gridOwner.ToCoordinates(0, 2));
netBattery = entityManager.GetComponent(batteryEnt);
battery = entityManager.GetComponent(batteryEnt);
supplier = entityManager.GetComponent(generatorEnt);
@@ -577,16 +584,17 @@ namespace Content.IntegrationTests.Tests.Power
{
var map = mapManager.CreateMap();
var grid = mapManager.CreateGrid(map);
+ var gridOwner = grid.Owner;
// Power only works when anchored
for (var i = 0; i < 3; i++)
{
grid.SetTile(new Vector2i(0, i), new Tile(1));
- entityManager.SpawnEntity("CableHV", grid.ToCoordinates(0, i));
+ entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, i));
}
- var generatorEnt = entityManager.SpawnEntity("GeneratorDummy", grid.ToCoordinates());
- var batteryEnt = entityManager.SpawnEntity("ChargingBatteryDummy", grid.ToCoordinates(0, 2));
+ var generatorEnt = entityManager.SpawnEntity("GeneratorDummy", gridOwner.ToCoordinates());
+ var batteryEnt = entityManager.SpawnEntity("ChargingBatteryDummy", gridOwner.ToCoordinates(0, 2));
supplier = entityManager.GetComponent(generatorEnt);
var netBattery = entityManager.GetComponent(batteryEnt);
@@ -635,20 +643,21 @@ namespace Content.IntegrationTests.Tests.Power
{
var map = mapManager.CreateMap();
var grid = mapManager.CreateGrid(map);
+ var gridOwner = grid.Owner;
// Power only works when anchored
for (var i = 0; i < 4; i++)
{
grid.SetTile(new Vector2i(0, i), new Tile(1));
- entityManager.SpawnEntity("CableHV", grid.ToCoordinates(0, i));
+ entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, i));
}
- var terminal = entityManager.SpawnEntity("CableTerminal", grid.ToCoordinates(0, 1));
+ var terminal = entityManager.SpawnEntity("CableTerminal", gridOwner.ToCoordinates(0, 1));
entityManager.GetComponent(terminal).LocalRotation = Angle.FromDegrees(180);
- var batteryEnt = entityManager.SpawnEntity("FullBatteryDummy", grid.ToCoordinates(0, 2));
- var supplyEnt = entityManager.SpawnEntity("GeneratorDummy", grid.ToCoordinates(0, 0));
- var consumerEnt = entityManager.SpawnEntity("ConsumerDummy", grid.ToCoordinates(0, 3));
+ var batteryEnt = entityManager.SpawnEntity("FullBatteryDummy", gridOwner.ToCoordinates(0, 2));
+ var supplyEnt = entityManager.SpawnEntity("GeneratorDummy", gridOwner.ToCoordinates(0, 0));
+ var consumerEnt = entityManager.SpawnEntity("ConsumerDummy", gridOwner.ToCoordinates(0, 3));
consumer = entityManager.GetComponent(consumerEnt);
supplier = entityManager.GetComponent(supplyEnt);
@@ -712,20 +721,21 @@ namespace Content.IntegrationTests.Tests.Power
{
var map = mapManager.CreateMap();
var grid = mapManager.CreateGrid(map);
+ var gridOwner = grid.Owner;
// Power only works when anchored
for (var i = 0; i < 4; i++)
{
grid.SetTile(new Vector2i(0, i), new Tile(1));
- entityManager.SpawnEntity("CableHV", grid.ToCoordinates(0, i));
+ entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, i));
}
- var terminal = entityManager.SpawnEntity("CableTerminal", grid.ToCoordinates(0, 1));
+ var terminal = entityManager.SpawnEntity("CableTerminal", gridOwner.ToCoordinates(0, 1));
entityManager.GetComponent(terminal).LocalRotation = Angle.FromDegrees(180);
- var batteryEnt = entityManager.SpawnEntity("FullBatteryDummy", grid.ToCoordinates(0, 2));
- var supplyEnt = entityManager.SpawnEntity("GeneratorDummy", grid.ToCoordinates(0, 0));
- var consumerEnt = entityManager.SpawnEntity("ConsumerDummy", grid.ToCoordinates(0, 3));
+ var batteryEnt = entityManager.SpawnEntity("FullBatteryDummy", gridOwner.ToCoordinates(0, 2));
+ var supplyEnt = entityManager.SpawnEntity("GeneratorDummy", gridOwner.ToCoordinates(0, 0));
+ var consumerEnt = entityManager.SpawnEntity("ConsumerDummy", gridOwner.ToCoordinates(0, 3));
consumer = entityManager.GetComponent(consumerEnt);
supplier = entityManager.GetComponent(supplyEnt);
@@ -787,6 +797,7 @@ namespace Content.IntegrationTests.Tests.Power
{
var map = mapManager.CreateMap();
var grid = mapManager.CreateGrid(map);
+ var gridOwner = grid.Owner;
// Map layout here is
// C - consumer
@@ -800,18 +811,18 @@ namespace Content.IntegrationTests.Tests.Power
for (var i = 0; i < 5; i++)
{
grid.SetTile(new Vector2i(0, i), new Tile(1));
- entityManager.SpawnEntity("CableHV", grid.ToCoordinates(0, i));
+ entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, i));
}
- entityManager.SpawnEntity("CableTerminal", grid.ToCoordinates(0, 2));
- var terminal = entityManager.SpawnEntity("CableTerminal", grid.ToCoordinates(0, 2));
+ entityManager.SpawnEntity("CableTerminal", gridOwner.ToCoordinates(0, 2));
+ var terminal = entityManager.SpawnEntity("CableTerminal", gridOwner.ToCoordinates(0, 2));
entityManager.GetComponent(terminal).LocalRotation = Angle.FromDegrees(180);
- var batteryEnt1 = entityManager.SpawnEntity("FullBatteryDummy", grid.ToCoordinates(0, 1));
- var batteryEnt2 = entityManager.SpawnEntity("FullBatteryDummy", grid.ToCoordinates(0, 3));
- var supplyEnt = entityManager.SpawnEntity("GeneratorDummy", grid.ToCoordinates(0, 2));
- var consumerEnt1 = entityManager.SpawnEntity("ConsumerDummy", grid.ToCoordinates(0, 0));
- var consumerEnt2 = entityManager.SpawnEntity("ConsumerDummy", grid.ToCoordinates(0, 4));
+ var batteryEnt1 = entityManager.SpawnEntity("FullBatteryDummy", gridOwner.ToCoordinates(0, 1));
+ var batteryEnt2 = entityManager.SpawnEntity("FullBatteryDummy", gridOwner.ToCoordinates(0, 3));
+ var supplyEnt = entityManager.SpawnEntity("GeneratorDummy", gridOwner.ToCoordinates(0, 2));
+ var consumerEnt1 = entityManager.SpawnEntity("ConsumerDummy", gridOwner.ToCoordinates(0, 0));
+ var consumerEnt2 = entityManager.SpawnEntity("ConsumerDummy", gridOwner.ToCoordinates(0, 4));
consumer1 = entityManager.GetComponent(consumerEnt1);
consumer2 = entityManager.GetComponent(consumerEnt2);
@@ -888,6 +899,7 @@ namespace Content.IntegrationTests.Tests.Power
{
var map = mapManager.CreateMap();
var grid = mapManager.CreateGrid(map);
+ var gridOwner = grid.Owner;
// Layout is two generators, two batteries, and one load. As to why two: because previously this test
// would fail ONLY if there were more than two batteries present, because each of them tries to supply
@@ -900,16 +912,16 @@ namespace Content.IntegrationTests.Tests.Power
for (var i = -2; i <= 2; i++)
{
grid.SetTile(new Vector2i(0, i), new Tile(1));
- entityManager.SpawnEntity("CableHV", grid.ToCoordinates(0, i));
+ entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, i));
}
- var batteryEnt1 = entityManager.SpawnEntity("FullBatteryDummy", grid.ToCoordinates(0, 2));
- var batteryEnt2 = entityManager.SpawnEntity("FullBatteryDummy", grid.ToCoordinates(0, -2));
+ var batteryEnt1 = entityManager.SpawnEntity("FullBatteryDummy", gridOwner.ToCoordinates(0, 2));
+ var batteryEnt2 = entityManager.SpawnEntity("FullBatteryDummy", gridOwner.ToCoordinates(0, -2));
- var supplyEnt1 = entityManager.SpawnEntity("GeneratorDummy", grid.ToCoordinates(0, 1));
- var supplyEnt2 = entityManager.SpawnEntity("GeneratorDummy", grid.ToCoordinates(0, -1));
+ var supplyEnt1 = entityManager.SpawnEntity("GeneratorDummy", gridOwner.ToCoordinates(0, 1));
+ var supplyEnt2 = entityManager.SpawnEntity("GeneratorDummy", gridOwner.ToCoordinates(0, -1));
- var consumerEnt = entityManager.SpawnEntity("ConsumerDummy", grid.ToCoordinates(0, 0));
+ var consumerEnt = entityManager.SpawnEntity("ConsumerDummy", gridOwner.ToCoordinates(0, 0));
consumer = entityManager.GetComponent(consumerEnt);
supplier1 = entityManager.GetComponent(supplyEnt1);
@@ -981,6 +993,7 @@ namespace Content.IntegrationTests.Tests.Power
{
var map = mapManager.CreateMap();
var grid = mapManager.CreateGrid(map);
+ var gridOwner = grid.Owner;
// Map layout here is
// C - consumer
@@ -994,18 +1007,18 @@ namespace Content.IntegrationTests.Tests.Power
for (var i = 0; i < 5; i++)
{
grid.SetTile(new Vector2i(0, i), new Tile(1));
- entityManager.SpawnEntity("CableHV", grid.ToCoordinates(0, i));
+ entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, i));
}
- entityManager.SpawnEntity("CableTerminal", grid.ToCoordinates(0, 2));
- var terminal = entityManager.SpawnEntity("CableTerminal", grid.ToCoordinates(0, 2));
+ entityManager.SpawnEntity("CableTerminal", gridOwner.ToCoordinates(0, 2));
+ var terminal = entityManager.SpawnEntity("CableTerminal", gridOwner.ToCoordinates(0, 2));
entityManager.GetComponent(terminal).LocalRotation = Angle.FromDegrees(180);
- var batteryEnt1 = entityManager.SpawnEntity("FullBatteryDummy", grid.ToCoordinates(0, 1));
- var batteryEnt2 = entityManager.SpawnEntity("FullBatteryDummy", grid.ToCoordinates(0, 3));
- var supplyEnt = entityManager.SpawnEntity("GeneratorDummy", grid.ToCoordinates(0, 2));
- var consumerEnt1 = entityManager.SpawnEntity("ConsumerDummy", grid.ToCoordinates(0, 0));
- var consumerEnt2 = entityManager.SpawnEntity("ConsumerDummy", grid.ToCoordinates(0, 4));
+ var batteryEnt1 = entityManager.SpawnEntity("FullBatteryDummy", gridOwner.ToCoordinates(0, 1));
+ var batteryEnt2 = entityManager.SpawnEntity("FullBatteryDummy", gridOwner.ToCoordinates(0, 3));
+ var supplyEnt = entityManager.SpawnEntity("GeneratorDummy", gridOwner.ToCoordinates(0, 2));
+ var consumerEnt1 = entityManager.SpawnEntity("ConsumerDummy", gridOwner.ToCoordinates(0, 0));
+ var consumerEnt2 = entityManager.SpawnEntity("ConsumerDummy", gridOwner.ToCoordinates(0, 4));
consumer1 = entityManager.GetComponent(consumerEnt1);
consumer2 = entityManager.GetComponent(consumerEnt2);
@@ -1068,20 +1081,21 @@ namespace Content.IntegrationTests.Tests.Power
{
var map = mapManager.CreateMap();
var grid = mapManager.CreateGrid(map);
+ var gridOwner = grid.Owner;
// Power only works when anchored
for (var i = 0; i < 4; i++)
{
grid.SetTile(new Vector2i(0, i), new Tile(1));
- entityManager.SpawnEntity("CableHV", grid.ToCoordinates(0, i));
+ entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, i));
}
- var terminal = entityManager.SpawnEntity("CableTerminal", grid.ToCoordinates(0, 1));
+ var terminal = entityManager.SpawnEntity("CableTerminal", gridOwner.ToCoordinates(0, 1));
entityManager.GetComponent(terminal).LocalRotation = Angle.FromDegrees(180);
- var batteryEnt = entityManager.SpawnEntity("FullBatteryDummy", grid.ToCoordinates(0, 2));
- var supplyEnt = entityManager.SpawnEntity("GeneratorDummy", grid.ToCoordinates(0, 0));
- var consumerEnt = entityManager.SpawnEntity("ConsumerDummy", grid.ToCoordinates(0, 3));
+ var batteryEnt = entityManager.SpawnEntity("FullBatteryDummy", gridOwner.ToCoordinates(0, 2));
+ var supplyEnt = entityManager.SpawnEntity("GeneratorDummy", gridOwner.ToCoordinates(0, 0));
+ var consumerEnt = entityManager.SpawnEntity("ConsumerDummy", gridOwner.ToCoordinates(0, 3));
consumer = entityManager.GetComponent(consumerEnt);
supplier = entityManager.GetComponent(supplyEnt);
@@ -1153,6 +1167,7 @@ namespace Content.IntegrationTests.Tests.Power
{
var map = mapManager.CreateMap();
var grid = mapManager.CreateGrid(map);
+ var gridOwner = grid.Owner;
// Power only works when anchored
for (var i = 0; i < 4; i++)
@@ -1160,15 +1175,15 @@ namespace Content.IntegrationTests.Tests.Power
grid.SetTile(new Vector2i(0, i), new Tile(1));
}
- var leftEnt = entityManager.SpawnEntity("CableHV", grid.ToCoordinates(0, 0));
- entityManager.SpawnEntity("CableHV", grid.ToCoordinates(0, 1));
- entityManager.SpawnEntity("CableHV", grid.ToCoordinates(0, 2));
- var rightEnt = entityManager.SpawnEntity("CableHV", grid.ToCoordinates(0, 3));
+ var leftEnt = entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, 0));
+ entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, 1));
+ entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, 2));
+ var rightEnt = entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, 3));
- var terminal = entityManager.SpawnEntity("CableTerminal", grid.ToCoordinates(0, 1));
+ var terminal = entityManager.SpawnEntity("CableTerminal", gridOwner.ToCoordinates(0, 1));
entityManager.GetComponent(terminal).LocalRotation = Angle.FromDegrees(180);
- var battery = entityManager.SpawnEntity("FullBatteryDummy", grid.ToCoordinates(0, 2));
+ var battery = entityManager.SpawnEntity("FullBatteryDummy", gridOwner.ToCoordinates(0, 2));
var batteryNodeContainer = entityManager.GetComponent(battery);
if (nodeContainer.TryGetNode(entityManager.GetComponent(leftEnt),
@@ -1216,6 +1231,7 @@ namespace Content.IntegrationTests.Tests.Power
{
var map = mapManager.CreateMap();
var grid = mapManager.CreateGrid(map);
+ var gridOwner = grid.Owner;
// Power only works when anchored
for (var i = 0; i < 3; i++)
@@ -1223,14 +1239,14 @@ namespace Content.IntegrationTests.Tests.Power
grid.SetTile(new Vector2i(0, i), new Tile(1));
}
- entityManager.SpawnEntity("CableHV", grid.ToCoordinates(0, 0));
- entityManager.SpawnEntity("CableHV", grid.ToCoordinates(0, 1));
- entityManager.SpawnEntity("CableMV", grid.ToCoordinates(0, 1));
- entityManager.SpawnEntity("CableMV", grid.ToCoordinates(0, 2));
+ entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, 0));
+ entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, 1));
+ entityManager.SpawnEntity("CableMV", gridOwner.ToCoordinates(0, 1));
+ entityManager.SpawnEntity("CableMV", gridOwner.ToCoordinates(0, 2));
- var generatorEnt = entityManager.SpawnEntity("GeneratorDummy", grid.ToCoordinates(0, 0));
- var substationEnt = entityManager.SpawnEntity("SubstationDummy", grid.ToCoordinates(0, 1));
- var apcEnt = entityManager.SpawnEntity("ApcDummy", grid.ToCoordinates(0, 2));
+ var generatorEnt = entityManager.SpawnEntity("GeneratorDummy", gridOwner.ToCoordinates(0, 0));
+ var substationEnt = entityManager.SpawnEntity("SubstationDummy", gridOwner.ToCoordinates(0, 1));
+ var apcEnt = entityManager.SpawnEntity("ApcDummy", gridOwner.ToCoordinates(0, 2));
var generatorSupplier = entityManager.GetComponent(generatorEnt);
substationNetBattery = entityManager.GetComponent(substationEnt);
@@ -1273,6 +1289,7 @@ namespace Content.IntegrationTests.Tests.Power
{
var map = mapManager.CreateMap();
var grid = mapManager.CreateGrid(map);
+ var gridOwner = grid.Owner;
const int range = 5;
@@ -1282,15 +1299,15 @@ namespace Content.IntegrationTests.Tests.Power
grid.SetTile(new Vector2i(0, i), new Tile(1));
}
- var apcEnt = entityManager.SpawnEntity("ApcDummy", grid.ToCoordinates(0, 0));
- var apcExtensionEnt = entityManager.SpawnEntity("CableApcExtension", grid.ToCoordinates(0, 0));
+ var apcEnt = entityManager.SpawnEntity("ApcDummy", gridOwner.ToCoordinates(0, 0));
+ var apcExtensionEnt = entityManager.SpawnEntity("CableApcExtension", gridOwner.ToCoordinates(0, 0));
// Create a powered receiver in range (range is 0 indexed)
- var powerReceiverEnt = entityManager.SpawnEntity("ApcPowerReceiverDummy", grid.ToCoordinates(0, range - 1));
+ var powerReceiverEnt = entityManager.SpawnEntity("ApcPowerReceiverDummy", gridOwner.ToCoordinates(0, range - 1));
receiver = entityManager.GetComponent(powerReceiverEnt);
// Create an unpowered receiver outside range
- var unpoweredReceiverEnt = entityManager.SpawnEntity("ApcPowerReceiverDummy", grid.ToCoordinates(0, range));
+ var unpoweredReceiverEnt = entityManager.SpawnEntity("ApcPowerReceiverDummy", gridOwner.ToCoordinates(0, range));
unpoweredReceiver = entityManager.GetComponent(unpoweredReceiverEnt);
var battery = entityManager.GetComponent(apcEnt);
diff --git a/Content.IntegrationTests/Tests/PrototypeSaveTest.cs b/Content.IntegrationTests/Tests/PrototypeSaveTest.cs
index 6096c497ef..e4a9c1a840 100644
--- a/Content.IntegrationTests/Tests/PrototypeSaveTest.cs
+++ b/Content.IntegrationTests/Tests/PrototypeSaveTest.cs
@@ -59,7 +59,7 @@ public sealed class PrototypeSaveTest
var tileDefinition = tileDefinitionManager["FloorSteel"]; // Wires n such disable ambiance while under the floor
var tile = new Tile(tileDefinition.TileId);
- var coordinates = grid.ToCoordinates();
+ var coordinates = grid.Owner.ToCoordinates();
grid.SetTile(coordinates, tile);
});
@@ -94,7 +94,7 @@ public sealed class PrototypeSaveTest
await server.WaitAssertion(() =>
{
Assert.That(!mapManager.IsMapInitialized(mapId));
- var testLocation = grid.ToCoordinates();
+ var testLocation = grid.Owner.ToCoordinates();
Assert.Multiple(() =>
{
diff --git a/Content.Server/Administration/Commands/PersistenceSaveCommand.cs b/Content.Server/Administration/Commands/PersistenceSaveCommand.cs
index 2684e85d5f..7ef1932c56 100644
--- a/Content.Server/Administration/Commands/PersistenceSaveCommand.cs
+++ b/Content.Server/Administration/Commands/PersistenceSaveCommand.cs
@@ -1,11 +1,6 @@
-using Content.Server.GameTicking;
-using Content.Server.Ghost.Components;
-using Content.Server.Players;
using Content.Shared.Administration;
using Content.Shared.CCVar;
-using Content.Shared.Ghost;
using Robust.Server.GameObjects;
-using Robust.Server.Player;
using Robust.Shared.Configuration;
using Robust.Shared.Console;
using Robust.Shared.Map;
@@ -17,7 +12,6 @@ namespace Content.Server.Administration.Commands;
public sealed class PersistenceSave : IConsoleCommand
{
[Dependency] private readonly IConfigurationManager _config = default!;
- [Dependency] private readonly IEntityManager _entities = default!;
[Dependency] private readonly IEntitySystemManager _system = default!;
[Dependency] private readonly IMapManager _map = default!;
diff --git a/Content.Server/Administration/Commands/VariantizeCommand.cs b/Content.Server/Administration/Commands/VariantizeCommand.cs
index 7aabd76335..3f9b7efd07 100644
--- a/Content.Server/Administration/Commands/VariantizeCommand.cs
+++ b/Content.Server/Administration/Commands/VariantizeCommand.cs
@@ -3,7 +3,6 @@ using Content.Shared.Maps;
using Robust.Shared.Console;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
-using Robust.Shared.Random;
namespace Content.Server.Administration.Commands;
@@ -11,7 +10,6 @@ namespace Content.Server.Administration.Commands;
public sealed class VariantizeCommand : IConsoleCommand
{
[Dependency] private readonly IEntityManager _entManager = default!;
- [Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly ITileDefinitionManager _tileDefManager = default!;
public string Command => "variantize";
diff --git a/Content.Server/Administration/Managers/AdminManager.cs b/Content.Server/Administration/Managers/AdminManager.cs
index 371755dcef..41171eef73 100644
--- a/Content.Server/Administration/Managers/AdminManager.cs
+++ b/Content.Server/Administration/Managers/AdminManager.cs
@@ -154,7 +154,7 @@ namespace Content.Server.Administration.Managers
plyData.ExplicitlyDeadminned = false;
reg.Data.Active = true;
- if (reg.Data.Stealth)
+ if (!reg.Data.Stealth)
{
_chat.SendAdminAnnouncement(Loc.GetString("admin-manager-self-re-admin-message", ("newAdminName", session.Name)));
}
diff --git a/Content.Server/Advertise/AdvertiseComponent.cs b/Content.Server/Advertise/AdvertiseComponent.cs
deleted file mode 100644
index f36cc7ae1e..0000000000
--- a/Content.Server/Advertise/AdvertiseComponent.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-using Content.Server.Advertisements;
-using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
-
-namespace Content.Server.Advertise
-{
- [RegisterComponent, Access(typeof(AdvertiseSystem))]
- public sealed partial class AdvertiseComponent : Component
- {
- ///
- /// Minimum time in seconds to wait before saying a new ad, in seconds. Has to be larger than or equal to 1.
- ///
- [ViewVariables(VVAccess.ReadWrite)]
- [DataField("minWait")]
- public int MinimumWait { get; private set; } = 8 * 60;
-
- ///
- /// Maximum time in seconds to wait before saying a new ad, in seconds. Has to be larger than or equal
- /// to
- ///
- [ViewVariables(VVAccess.ReadWrite)]
- [DataField("maxWait")]
- public int MaximumWait { get; private set; } = 10 * 60;
-
- ///
- /// The identifier for the advertisements pack prototype.
- ///
- [DataField("pack", customTypeSerializer:typeof(PrototypeIdSerializer), required: true)]
- public string PackPrototypeId { get; private set; } = string.Empty;
-
- ///
- /// The next time an advertisement will be said.
- ///
- [ViewVariables(VVAccess.ReadWrite)]
- public TimeSpan NextAdvertisementTime { get; set; } = TimeSpan.Zero;
-
- ///
- /// Whether the entity will say advertisements or not.
- ///
- [ViewVariables(VVAccess.ReadWrite)]
- public bool Enabled { get; set; } = true;
- }
-}
diff --git a/Content.Server/Advertise/AdvertiseSystem.cs b/Content.Server/Advertise/AdvertiseSystem.cs
deleted file mode 100644
index ab538f3c77..0000000000
--- a/Content.Server/Advertise/AdvertiseSystem.cs
+++ /dev/null
@@ -1,154 +0,0 @@
-using Content.Server.Advertisements;
-using Content.Server.Chat.Systems;
-using Content.Server.Power.Components;
-using Content.Shared.VendingMachines;
-using Robust.Shared.Prototypes;
-using Robust.Shared.Random;
-using Robust.Shared.Timing;
-
-namespace Content.Server.Advertise
-{
- public sealed class AdvertiseSystem : EntitySystem
- {
- [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
- [Dependency] private readonly IRobustRandom _random = default!;
- [Dependency] private readonly IGameTiming _gameTiming = default!;
- [Dependency] private readonly ChatSystem _chat = default!;
-
- ///
- /// The maximum amount of time between checking if advertisements should be displayed
- ///
- private readonly TimeSpan _maximumNextCheckDuration = TimeSpan.FromSeconds(15);
-
- ///
- /// The next time the game will check if advertisements should be displayed
- ///
- private TimeSpan _nextCheckTime = TimeSpan.MaxValue;
-
- public override void Initialize()
- {
- SubscribeLocalEvent(OnComponentInit);
- SubscribeLocalEvent(OnPowerChanged);
-
- SubscribeLocalEvent(OnPowerReceiverEnableChangeAttempt);
- SubscribeLocalEvent(OnVendingEnableChangeAttempt);
-
- // The component inits will lower this.
- _nextCheckTime = TimeSpan.MaxValue;
- }
-
- private void OnComponentInit(EntityUid uid, AdvertiseComponent advertise, ComponentInit args)
- {
- RefreshTimer(uid, advertise);
- }
-
- private void OnPowerChanged(EntityUid uid, AdvertiseComponent advertise, ref PowerChangedEvent args)
- {
- SetEnabled(uid, args.Powered, advertise);
- }
-
- public void RefreshTimer(EntityUid uid, AdvertiseComponent? advertise = null)
- {
- if (!Resolve(uid, ref advertise))
- return;
-
- if (!advertise.Enabled)
- return;
-
- var minDuration = Math.Max(1, advertise.MinimumWait);
- var maxDuration = Math.Max(minDuration, advertise.MaximumWait);
- var waitDuration = TimeSpan.FromSeconds(_random.Next(minDuration, maxDuration));
- var nextTime = _gameTiming.CurTime + waitDuration;
-
- advertise.NextAdvertisementTime = nextTime;
-
- _nextCheckTime = MathHelper.Min(nextTime, _nextCheckTime);
- }
-
- public void SayAdvertisement(EntityUid uid, AdvertiseComponent? advertise = null)
- {
- if (!Resolve(uid, ref advertise))
- return;
-
- if (_prototypeManager.TryIndex(advertise.PackPrototypeId, out AdvertisementsPackPrototype? advertisements))
- _chat.TrySendInGameICMessage(uid, Loc.GetString(_random.Pick(advertisements.Advertisements)), InGameICChatType.Speak, true);
- }
-
- public void SayThankYou(EntityUid uid, AdvertiseComponent? advertise = null)
- {
- if (!Resolve(uid, ref advertise))
- return;
-
- if (_prototypeManager.TryIndex(advertise.PackPrototypeId, out AdvertisementsPackPrototype? advertisements))
- {
- _chat.TrySendInGameICMessage(uid, Loc.GetString(_random.Pick(advertisements.ThankYous), ("name", Name(uid))), InGameICChatType.Speak, true);
- }
- }
-
- public void SetEnabled(EntityUid uid, bool enable, AdvertiseComponent? advertise = null)
- {
- if (!Resolve(uid, ref advertise))
- return;
-
- if (advertise.Enabled == enable)
- return;
-
- var attemptEvent = new AdvertiseEnableChangeAttemptEvent(enable);
- RaiseLocalEvent(uid, attemptEvent);
-
- if (attemptEvent.Cancelled)
- return;
-
- advertise.Enabled = enable;
- RefreshTimer(uid, advertise);
- }
-
- private static void OnPowerReceiverEnableChangeAttempt(EntityUid uid, ApcPowerReceiverComponent component, AdvertiseEnableChangeAttemptEvent args)
- {
- if(args.Enabling && !component.Powered)
- args.Cancel();
- }
-
- private static void OnVendingEnableChangeAttempt(EntityUid uid, VendingMachineComponent component, AdvertiseEnableChangeAttemptEvent args)
- {
- if(args.Enabling && component.Broken)
- args.Cancel();
- }
-
- public override void Update(float frameTime)
- {
- var curTime = _gameTiming.CurTime;
- if (_nextCheckTime > curTime)
- return;
-
- _nextCheckTime = curTime + _maximumNextCheckDuration;
-
- var query = EntityQueryEnumerator();
- while (query.MoveNext(out var uid, out var advert))
- {
- if (!advert.Enabled)
- continue;
-
- // If this isn't advertising yet
- if (advert.NextAdvertisementTime > curTime)
- {
- _nextCheckTime = MathHelper.Min(advert.NextAdvertisementTime, _nextCheckTime);
- continue;
- }
-
- SayAdvertisement(uid, advert);
- RefreshTimer(uid, advert);
- }
- }
- }
-
- public sealed class AdvertiseEnableChangeAttemptEvent : CancellableEntityEventArgs
- {
- public bool Enabling { get; }
-
- public AdvertiseEnableChangeAttemptEvent(bool enabling)
- {
- Enabling = enabling;
- }
- }
-}
diff --git a/Content.Server/Advertise/Components/AdvertiseComponent.cs b/Content.Server/Advertise/Components/AdvertiseComponent.cs
new file mode 100644
index 0000000000..140bc6b902
--- /dev/null
+++ b/Content.Server/Advertise/Components/AdvertiseComponent.cs
@@ -0,0 +1,45 @@
+using Content.Server.Advertise.EntitySystems;
+using Content.Shared.Advertise;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
+
+namespace Content.Server.Advertise.Components;
+
+///
+/// Makes this entity periodically advertise by speaking a randomly selected
+/// message from a specified MessagePack into local chat.
+///
+[RegisterComponent, Access(typeof(AdvertiseSystem))]
+public sealed partial class AdvertiseComponent : Component
+{
+ ///
+ /// Minimum time in seconds to wait before saying a new ad, in seconds. Has to be larger than or equal to 1.
+ ///
+ [DataField]
+ public int MinimumWait { get; private set; } = 8 * 60;
+
+ ///
+ /// Maximum time in seconds to wait before saying a new ad, in seconds. Has to be larger than or equal
+ /// to
+ ///
+ [DataField]
+ public int MaximumWait { get; private set; } = 10 * 60;
+
+ ///
+ /// The identifier for the advertisements pack prototype.
+ ///
+ [DataField(required: true)]
+ public ProtoId Pack { get; private set; }
+
+ ///
+ /// The next time an advertisement will be said.
+ ///
+ [DataField]
+ public TimeSpan NextAdvertisementTime { get; set; } = TimeSpan.Zero;
+
+ ///
+ /// Whether the entity will say advertisements or not.
+ ///
+ [DataField]
+ public bool Enabled { get; set; } = true;
+}
diff --git a/Content.Server/Advertise/Components/SpeakOnUIClosedComponent.cs b/Content.Server/Advertise/Components/SpeakOnUIClosedComponent.cs
new file mode 100644
index 0000000000..2a663b7f89
--- /dev/null
+++ b/Content.Server/Advertise/Components/SpeakOnUIClosedComponent.cs
@@ -0,0 +1,36 @@
+using Content.Shared.Advertise;
+using Robust.Shared.Prototypes;
+
+namespace Content.Server.Advertise.Components;
+
+///
+/// Causes the entity to speak using the Chat system when its ActivatableUI is closed, optionally
+/// requiring that a Flag be set as well.
+///
+[RegisterComponent, Access(typeof(SpeakOnUIClosedSystem))]
+public sealed partial class SpeakOnUIClosedComponent : Component
+{
+ ///
+ /// The identifier for the message pack prototype containing messages to be spoken by this entity.
+ ///
+ [DataField(required: true)]
+ public ProtoId Pack { get; private set; }
+
+ ///
+ /// Is this component active? If false, no messages will be spoken.
+ ///
+ [DataField]
+ public bool Enabled = true;
+
+ ///
+ /// Should messages be spoken only if the is set (true), or every time the UI is closed (false)?
+ ///
+ [DataField]
+ public bool RequireFlag = true;
+
+ ///
+ /// State variable only used if is true. Set with .
+ ///
+ [DataField]
+ public bool Flag;
+}
diff --git a/Content.Server/Advertise/EntitySystems/AdvertiseSystem.cs b/Content.Server/Advertise/EntitySystems/AdvertiseSystem.cs
new file mode 100644
index 0000000000..bb254d11ef
--- /dev/null
+++ b/Content.Server/Advertise/EntitySystems/AdvertiseSystem.cs
@@ -0,0 +1,137 @@
+using Content.Server.Advertise.Components;
+using Content.Server.Chat.Systems;
+using Content.Server.Power.Components;
+using Content.Shared.VendingMachines;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Random;
+using Robust.Shared.Timing;
+
+namespace Content.Server.Advertise.EntitySystems;
+
+public sealed class AdvertiseSystem : EntitySystem
+{
+ [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
+ [Dependency] private readonly IRobustRandom _random = default!;
+ [Dependency] private readonly IGameTiming _gameTiming = default!;
+ [Dependency] private readonly ChatSystem _chat = default!;
+
+ ///
+ /// The maximum amount of time between checking if advertisements should be displayed
+ ///
+ private readonly TimeSpan _maximumNextCheckDuration = TimeSpan.FromSeconds(15);
+
+ ///
+ /// The next time the game will check if advertisements should be displayed
+ ///
+ private TimeSpan _nextCheckTime = TimeSpan.MaxValue;
+
+ public override void Initialize()
+ {
+ SubscribeLocalEvent(OnMapInit);
+ SubscribeLocalEvent(OnPowerChanged);
+
+ SubscribeLocalEvent(OnPowerReceiverEnableChangeAttempt);
+ SubscribeLocalEvent(OnVendingEnableChangeAttempt);
+
+ // The component inits will lower this.
+ _nextCheckTime = TimeSpan.MaxValue;
+ }
+
+ private void OnMapInit(EntityUid uid, AdvertiseComponent advertise, MapInitEvent args)
+ {
+ RefreshTimer(uid, advertise);
+ }
+
+ private void OnPowerChanged(EntityUid uid, AdvertiseComponent advertise, ref PowerChangedEvent args)
+ {
+ SetEnabled(uid, args.Powered, advertise);
+ }
+
+ public void RefreshTimer(EntityUid uid, AdvertiseComponent? advertise = null)
+ {
+ if (!Resolve(uid, ref advertise))
+ return;
+
+ if (!advertise.Enabled)
+ return;
+
+ var minDuration = Math.Max(1, advertise.MinimumWait);
+ var maxDuration = Math.Max(minDuration, advertise.MaximumWait);
+ var waitDuration = TimeSpan.FromSeconds(_random.Next(minDuration, maxDuration));
+ var nextTime = _gameTiming.CurTime + waitDuration;
+
+ advertise.NextAdvertisementTime = nextTime;
+
+ _nextCheckTime = MathHelper.Min(nextTime, _nextCheckTime);
+ }
+
+ public void SayAdvertisement(EntityUid uid, AdvertiseComponent? advertise = null)
+ {
+ if (!Resolve(uid, ref advertise))
+ return;
+
+ if (_prototypeManager.TryIndex(advertise.Pack, out var advertisements))
+ _chat.TrySendInGameICMessage(uid, Loc.GetString(_random.Pick(advertisements.Messages)), InGameICChatType.Speak, hideChat: true);
+ }
+
+ public void SetEnabled(EntityUid uid, bool enable, AdvertiseComponent? advertise = null)
+ {
+ if (!Resolve(uid, ref advertise))
+ return;
+
+ if (advertise.Enabled == enable)
+ return;
+
+ var attemptEvent = new AdvertiseEnableChangeAttemptEvent(enable);
+ RaiseLocalEvent(uid, attemptEvent);
+
+ if (attemptEvent.Cancelled)
+ return;
+
+ advertise.Enabled = enable;
+ RefreshTimer(uid, advertise);
+ }
+
+ private static void OnPowerReceiverEnableChangeAttempt(EntityUid uid, ApcPowerReceiverComponent component, AdvertiseEnableChangeAttemptEvent args)
+ {
+ if (args.Enabling && !component.Powered)
+ args.Cancel();
+ }
+
+ private static void OnVendingEnableChangeAttempt(EntityUid uid, VendingMachineComponent component, AdvertiseEnableChangeAttemptEvent args)
+ {
+ if (args.Enabling && component.Broken)
+ args.Cancel();
+ }
+
+ public override void Update(float frameTime)
+ {
+ var curTime = _gameTiming.CurTime;
+ if (_nextCheckTime > curTime)
+ return;
+
+ _nextCheckTime = curTime + _maximumNextCheckDuration;
+
+ var query = EntityQueryEnumerator();
+ while (query.MoveNext(out var uid, out var advert))
+ {
+ if (!advert.Enabled)
+ continue;
+
+ // If this isn't advertising yet
+ if (advert.NextAdvertisementTime > curTime)
+ {
+ _nextCheckTime = MathHelper.Min(advert.NextAdvertisementTime, _nextCheckTime);
+ continue;
+ }
+
+ SayAdvertisement(uid, advert);
+ RefreshTimer(uid, advert);
+ }
+ }
+}
+
+public sealed class AdvertiseEnableChangeAttemptEvent(bool enabling) : CancellableEntityEventArgs
+{
+ public bool Enabling { get; } = enabling;
+}
diff --git a/Content.Server/Advertise/EntitySystems/SpeakOnUIClosedSystem.cs b/Content.Server/Advertise/EntitySystems/SpeakOnUIClosedSystem.cs
new file mode 100644
index 0000000000..048f59b8d3
--- /dev/null
+++ b/Content.Server/Advertise/EntitySystems/SpeakOnUIClosedSystem.cs
@@ -0,0 +1,58 @@
+using Content.Server.Advertise.Components;
+using Content.Server.Chat.Systems;
+using Content.Server.UserInterface;
+using Content.Shared.Advertise;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Random;
+
+namespace Content.Server.Advertise;
+
+public sealed partial class SpeakOnUIClosedSystem : EntitySystem
+{
+ [Dependency] private readonly IRobustRandom _random = default!;
+ [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
+ [Dependency] private readonly ChatSystem _chat = default!;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnBoundUIClosed);
+ }
+ private void OnBoundUIClosed(Entity entity, ref BoundUIClosedEvent args)
+ {
+ if (!TryComp(entity, out ActivatableUIComponent? activatable) || !args.UiKey.Equals(activatable.Key))
+ return;
+
+ if (entity.Comp.RequireFlag && !entity.Comp.Flag)
+ return;
+
+ TrySpeak((entity, entity.Comp));
+ }
+
+ public bool TrySpeak(Entity entity)
+ {
+ if (!Resolve(entity, ref entity.Comp))
+ return false;
+
+ if (!entity.Comp.Enabled)
+ return false;
+
+ if (!_prototypeManager.TryIndex(entity.Comp.Pack, out MessagePackPrototype? messagePack))
+ return false;
+
+ var message = Loc.GetString(_random.Pick(messagePack.Messages), ("name", Name(entity)));
+ _chat.TrySendInGameICMessage(entity, message, InGameICChatType.Speak, true);
+ entity.Comp.Flag = false;
+ return true;
+ }
+
+ public bool TrySetFlag(Entity entity, bool value = true)
+ {
+ if (!Resolve(entity, ref entity.Comp))
+ return false;
+
+ entity.Comp.Flag = value;
+ return true;
+ }
+}
diff --git a/Content.Server/Advertisements/AdvertisementsPackPrototype.cs b/Content.Server/Advertisements/AdvertisementsPackPrototype.cs
deleted file mode 100644
index 641ab3c56f..0000000000
--- a/Content.Server/Advertisements/AdvertisementsPackPrototype.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-using Robust.Shared.Prototypes;
-
-namespace Content.Server.Advertisements
-{
- [Serializable, Prototype("advertisementsPack")]
- public sealed partial class AdvertisementsPackPrototype : IPrototype
- {
- [ViewVariables]
- [IdDataField]
- public string ID { get; private set; } = default!;
-
- [DataField("advertisements")]
- public List Advertisements { get; private set; } = new();
-
- [DataField("thankyous")]
- public List ThankYous { get; private set; } = new();
- }
-}
diff --git a/Content.Server/Anomaly/AnomalySystem.Generator.cs b/Content.Server/Anomaly/AnomalySystem.Generator.cs
index e03c566593..7aa1a8935f 100644
--- a/Content.Server/Anomaly/AnomalySystem.Generator.cs
+++ b/Content.Server/Anomaly/AnomalySystem.Generator.cs
@@ -103,7 +103,7 @@ public sealed partial class AnomalySystem
var tile = new Vector2i(randomX, randomY);
// no air-blocked areas.
- if (_atmosphere.IsTileSpace(grid, xform.MapUid, tile, mapGridComp: gridComp) ||
+ if (_atmosphere.IsTileSpace(grid, xform.MapUid, tile) ||
_atmosphere.IsTileAirBlocked(grid, tile, mapGridComp: gridComp))
{
continue;
diff --git a/Content.Server/Anomaly/Effects/BluespaceAnomalySystem.cs b/Content.Server/Anomaly/Effects/BluespaceAnomalySystem.cs
index 87c0ba4a4e..dd2da82c9d 100644
--- a/Content.Server/Anomaly/Effects/BluespaceAnomalySystem.cs
+++ b/Content.Server/Anomaly/Effects/BluespaceAnomalySystem.cs
@@ -8,6 +8,7 @@ using Content.Shared.Mobs.Components;
using Content.Shared.Teleportation.Components;
using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
+using Robust.Shared.Collections;
using Robust.Shared.Random;
namespace Content.Server.Anomaly.Effects;
@@ -35,20 +36,19 @@ public sealed class BluespaceAnomalySystem : EntitySystem
var range = component.MaxShuffleRadius * args.Severity;
var mobs = new HashSet>();
_lookup.GetEntitiesInRange(xform.Coordinates, range, mobs);
- var allEnts = new List(mobs.Select(m => m.Owner)) { uid };
- var coords = new List();
+ var allEnts = new ValueList(mobs.Select(m => m.Owner)) { uid };
+ var coords = new ValueList();
foreach (var ent in allEnts)
{
- if (xformQuery.TryGetComponent(ent, out var xf))
- coords.Add(xf.MapPosition.Position);
+ if (xformQuery.TryGetComponent(ent, out var allXform))
+ coords.Add(_xform.GetWorldPosition(allXform));
}
_random.Shuffle(coords);
for (var i = 0; i < allEnts.Count; i++)
{
-
_adminLogger.Add(LogType.Teleport, $"{ToPrettyString(allEnts[i])} has been shuffled to {coords[i]} by the {ToPrettyString(uid)} at {xform.Coordinates}");
- _xform.SetWorldPosition(allEnts[i], coords[i], xformQuery);
+ _xform.SetWorldPosition(allEnts[i], coords[i]);
}
}
diff --git a/Content.Server/Anomaly/Effects/EntityAnomalySystem.cs b/Content.Server/Anomaly/Effects/EntityAnomalySystem.cs
index 7c397d6888..90a655fbba 100644
--- a/Content.Server/Anomaly/Effects/EntityAnomalySystem.cs
+++ b/Content.Server/Anomaly/Effects/EntityAnomalySystem.cs
@@ -2,7 +2,6 @@ using Content.Shared.Anomaly;
using Content.Shared.Anomaly.Components;
using Content.Shared.Anomaly.Effects;
using Content.Shared.Anomaly.Effects.Components;
-using Robust.Shared.Map;
using Robust.Shared.Map.Components;
using Robust.Shared.Physics.Components;
using Robust.Shared.Random;
@@ -12,7 +11,6 @@ namespace Content.Server.Anomaly.Effects;
public sealed class EntityAnomalySystem : SharedEntityAnomalySystem
{
[Dependency] private readonly SharedAnomalySystem _anomaly = default!;
- [Dependency] private readonly IMapManager _map = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly SharedMapSystem _mapSystem = default!;
diff --git a/Content.Server/Anomaly/Effects/GasProducerAnomalySystem.cs b/Content.Server/Anomaly/Effects/GasProducerAnomalySystem.cs
index 2408ad0b3d..7fee8fdb98 100644
--- a/Content.Server/Anomaly/Effects/GasProducerAnomalySystem.cs
+++ b/Content.Server/Anomaly/Effects/GasProducerAnomalySystem.cs
@@ -62,7 +62,7 @@ public sealed class GasProducerAnomalySystem : EntitySystem
if (tilerefs.Length == 0)
return;
- var mixture = _atmosphere.GetTileMixture((uid, xform), grid, true);
+ var mixture = _atmosphere.GetTileMixture((uid, xform), true);
if (mixture != null)
{
mixture.AdjustMoles(gas, mols);
diff --git a/Content.Server/Arcade/BlockGame/BlockGameArcadeSystem.cs b/Content.Server/Arcade/BlockGame/BlockGameArcadeSystem.cs
index 34a5689fd1..ad65c5cca6 100644
--- a/Content.Server/Arcade/BlockGame/BlockGameArcadeSystem.cs
+++ b/Content.Server/Arcade/BlockGame/BlockGameArcadeSystem.cs
@@ -1,5 +1,7 @@
using Content.Server.Power.Components;
using Content.Shared.UserInterface;
+using Content.Server.Advertise;
+using Content.Server.Advertise.Components;
using Content.Shared.Arcade;
using Robust.Server.GameObjects;
using Robust.Shared.Player;
@@ -9,6 +11,7 @@ namespace Content.Server.Arcade.BlockGame;
public sealed class BlockGameArcadeSystem : EntitySystem
{
[Dependency] private readonly UserInterfaceSystem _uiSystem = default!;
+ [Dependency] private readonly SpeakOnUIClosedSystem _speakOnUIClosed = default!;
public override void Initialize()
{
@@ -88,8 +91,6 @@ public sealed class BlockGameArcadeSystem : EntitySystem
component.Spectators.Remove(component.Player);
UpdatePlayerStatus(uid, component.Player, blockGame: component);
}
- else
- component.Player = null;
UpdatePlayerStatus(uid, temp, blockGame: component);
}
@@ -122,6 +123,9 @@ public sealed class BlockGameArcadeSystem : EntitySystem
return;
}
+ if (TryComp(uid, out var speakComponent))
+ _speakOnUIClosed.TrySetFlag((uid, speakComponent));
+
component.Game.ProcessInput(msg.PlayerAction);
}
}
diff --git a/Content.Server/Arcade/SpaceVillainGame/SpaceVillainArcadeSystem.cs b/Content.Server/Arcade/SpaceVillainGame/SpaceVillainArcadeSystem.cs
index d97c94fd99..f60d88ebf7 100644
--- a/Content.Server/Arcade/SpaceVillainGame/SpaceVillainArcadeSystem.cs
+++ b/Content.Server/Arcade/SpaceVillainGame/SpaceVillainArcadeSystem.cs
@@ -1,5 +1,7 @@
using Content.Server.Power.Components;
using Content.Shared.UserInterface;
+using Content.Server.Advertise;
+using Content.Server.Advertise.Components;
using static Content.Shared.Arcade.SharedSpaceVillainArcadeComponent;
using Robust.Server.GameObjects;
using Robust.Shared.Audio;
@@ -13,6 +15,7 @@ public sealed partial class SpaceVillainArcadeSystem : EntitySystem
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly SharedAudioSystem _audioSystem = default!;
[Dependency] private readonly UserInterfaceSystem _uiSystem = default!;
+ [Dependency] private readonly SpeakOnUIClosedSystem _speakOnUIClosed = default!;
public override void Initialize()
{
@@ -79,6 +82,9 @@ public sealed partial class SpaceVillainArcadeSystem : EntitySystem
case PlayerAction.Heal:
case PlayerAction.Recharge:
component.Game.ExecutePlayerAction(uid, msg.PlayerAction, component);
+ // Any sort of gameplay action counts
+ if (TryComp(uid, out var speakComponent))
+ _speakOnUIClosed.TrySetFlag((uid, speakComponent));
break;
case PlayerAction.NewGame:
_audioSystem.PlayPvs(component.NewGameSound, uid, AudioParams.Default.WithVolume(-4f));
diff --git a/Content.Server/Atmos/EntitySystems/AirFilterSystem.cs b/Content.Server/Atmos/EntitySystems/AirFilterSystem.cs
index 416045fc5e..d947e60b6d 100644
--- a/Content.Server/Atmos/EntitySystems/AirFilterSystem.cs
+++ b/Content.Server/Atmos/EntitySystems/AirFilterSystem.cs
@@ -1,8 +1,6 @@
-using Content.Server.Atmos;
using Content.Server.Atmos.Components;
using Content.Server.Atmos.Piping.Components;
using Content.Shared.Atmos;
-using Robust.Shared.GameObjects;
using Robust.Shared.Map;
using System.Diagnostics.CodeAnalysis;
@@ -15,7 +13,6 @@ public sealed class AirFilterSystem : EntitySystem
{
[Dependency] private readonly AtmosphereSystem _atmosphere = default!;
[Dependency] private readonly IMapManager _map = default!;
- [Dependency] private readonly SharedTransformSystem _transform = default!;
public override void Initialize()
{
diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.API.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.API.cs
index cece99cacf..fb94fe414b 100644
--- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.API.cs
+++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.API.cs
@@ -4,7 +4,6 @@ using Content.Server.Atmos.Piping.Components;
using Content.Server.Atmos.Reactions;
using Content.Server.NodeContainer.NodeGroups;
using Content.Shared.Atmos;
-using Robust.Server.GameObjects;
using Robust.Shared.Map.Components;
using Robust.Shared.Utility;
@@ -49,13 +48,7 @@ public partial class AtmosphereSystem
return GetTileMixture(gridUid, mapUid, position, excite);
}
- public bool HasAtmosphere(EntityUid gridUid)
- {
- var ev = new HasAtmosphereMethodEvent(gridUid);
- RaiseLocalEvent(gridUid, ref ev);
-
- return ev.Result;
- }
+ public bool HasAtmosphere(EntityUid gridUid) => _atmosQuery.HasComponent(gridUid);
public bool SetSimulatedGrid(EntityUid gridUid, bool simulated)
{
@@ -91,43 +84,60 @@ public partial class AtmosphereSystem
entity.Comp.InvalidatedCoords.Add(tile);
}
- public GasMixture?[]? GetTileMixtures(EntityUid? gridUid, EntityUid? mapUid, List tiles, bool excite = false)
+ public GasMixture?[]? GetTileMixtures(Entity? grid, Entity? map, List tiles, bool excite = false)
{
- var ev = new GetTileMixturesMethodEvent(gridUid, mapUid, tiles, excite);
+ GasMixture?[]? mixtures = null;
+ var handled = false;
// If we've been passed a grid, try to let it handle it.
- if (gridUid.HasValue)
+ if (grid is {} gridEnt && Resolve(gridEnt, ref gridEnt.Comp))
{
- DebugTools.Assert(_mapManager.IsGrid(gridUid.Value));
- RaiseLocalEvent(gridUid.Value, ref ev, false);
+ handled = true;
+ mixtures = new GasMixture?[tiles.Count];
+
+ for (var i = 0; i < tiles.Count; i++)
+ {
+ var tile = tiles[i];
+ if (!gridEnt.Comp.Tiles.TryGetValue(tile, out var atmosTile))
+ {
+ // need to get map atmosphere
+ handled = false;
+ continue;
+ }
+
+ mixtures[i] = atmosTile.Air;
+
+ if (excite)
+ gridEnt.Comp.InvalidatedCoords.Add(tile);
+ }
}
- if (ev.Handled)
- return ev.Mixtures;
+ if (handled)
+ return mixtures;
// We either don't have a grid, or the event wasn't handled.
// Let the map handle it instead, and also broadcast the event.
- if (mapUid.HasValue)
+ if (map is {} mapEnt && _mapAtmosQuery.Resolve(mapEnt, ref mapEnt.Comp))
{
- DebugTools.Assert(_mapManager.IsMap(mapUid.Value));
- RaiseLocalEvent(mapUid.Value, ref ev, true);
- }
- else
- RaiseLocalEvent(ref ev);
+ mixtures ??= new GasMixture?[tiles.Count];
+ for (var i = 0; i < tiles.Count; i++)
+ {
+ mixtures[i] ??= mapEnt.Comp.Mixture;
+ }
- if (ev.Handled)
- return ev.Mixtures;
+ return mixtures;
+ }
// Default to a space mixture... This is a space game, after all!
- ev.Mixtures ??= new GasMixture?[tiles.Count];
+ mixtures ??= new GasMixture?[tiles.Count];
for (var i = 0; i < tiles.Count; i++)
{
- ev.Mixtures[i] ??= GasMixture.SpaceGas;
+ mixtures[i] ??= GasMixture.SpaceGas;
}
- return ev.Mixtures;
+ return mixtures;
}
- public GasMixture? GetTileMixture (Entity entity, MapGridComponent? grid = null, bool excite = false)
+ public GasMixture? GetTileMixture (Entity entity, bool excite = false)
{
if (!Resolve(entity.Owner, ref entity.Comp))
return null;
@@ -136,32 +146,24 @@ public partial class AtmosphereSystem
return GetTileMixture(entity.Comp.GridUid, entity.Comp.MapUid, indices, excite);
}
- public GasMixture? GetTileMixture(EntityUid? gridUid, EntityUid? mapUid, Vector2i gridTile, bool excite = false)
+ public GasMixture? GetTileMixture(Entity? grid, Entity? map, Vector2i gridTile, bool excite = false)
{
- var ev = new GetTileMixtureMethodEvent(gridUid, mapUid, gridTile, excite);
-
// If we've been passed a grid, try to let it handle it.
- if(gridUid.HasValue)
+ if (grid is {} gridEnt
+ && Resolve(gridEnt, ref gridEnt.Comp, false)
+ && gridEnt.Comp.Tiles.TryGetValue(gridTile, out var tile))
{
- DebugTools.Assert(_mapManager.IsGrid(gridUid.Value));
- RaiseLocalEvent(gridUid.Value, ref ev, false);
+ if (excite)
+ gridEnt.Comp.InvalidatedCoords.Add(gridTile);
+
+ return tile.Air;
}
- if (ev.Handled)
- return ev.Mixture;
-
- // We either don't have a grid, or the event wasn't handled.
- // Let the map handle it instead, and also broadcast the event.
- if(mapUid.HasValue)
- {
- DebugTools.Assert(_mapManager.IsMap(mapUid.Value));
- RaiseLocalEvent(mapUid.Value, ref ev, true);
- }
- else
- RaiseLocalEvent(ref ev);
+ if (map is {} mapEnt && _mapAtmosQuery.Resolve(mapEnt, ref mapEnt.Comp, false))
+ return mapEnt.Comp.Mixture;
// Default to a space mixture... This is a space game, after all!
- return ev.Mixture ?? GasMixture.SpaceGas;
+ return GasMixture.SpaceGas;
}
public ReactionResult ReactTile(EntityUid gridId, Vector2i tile)
@@ -176,66 +178,67 @@ public partial class AtmosphereSystem
public bool IsTileAirBlocked(EntityUid gridUid, Vector2i tile, AtmosDirection directions = AtmosDirection.All, MapGridComponent? mapGridComp = null)
{
- if (!Resolve(gridUid, ref mapGridComp))
+ if (!Resolve(gridUid, ref mapGridComp, false))
return false;
var data = GetAirtightData(gridUid, mapGridComp, tile);
return data.BlockedDirections.IsFlagSet(directions);
}
- public bool IsTileSpace(EntityUid? gridUid, EntityUid? mapUid, Vector2i tile, MapGridComponent? mapGridComp = null)
+ public bool IsTileSpace(Entity? grid, Entity? map, Vector2i tile)
{
- var ev = new IsTileSpaceMethodEvent(gridUid, mapUid, tile, mapGridComp);
+ if (grid is {} gridEnt && _atmosQuery.Resolve(gridEnt, ref gridEnt.Comp, false)
+ && gridEnt.Comp.Tiles.TryGetValue(tile, out var tileAtmos))
+ {
+ return tileAtmos.Space;
+ }
- // Try to let the grid (if any) handle it...
- if (gridUid.HasValue)
- RaiseLocalEvent(gridUid.Value, ref ev, false);
-
- // If we didn't have a grid or the event wasn't handled
- // we let the map know, and also broadcast the event while at it!
- if (mapUid.HasValue && !ev.Handled)
- RaiseLocalEvent(mapUid.Value, ref ev, true);
-
- // We didn't have a map, and the event isn't handled, therefore broadcast the event.
- else if (!mapUid.HasValue && !ev.Handled)
- RaiseLocalEvent(ref ev);
+ if (map is {} mapEnt && _mapAtmosQuery.Resolve(mapEnt, ref mapEnt.Comp, false))
+ return mapEnt.Comp.Space;
// If nothing handled the event, it'll default to true.
// Oh well, this is a space game after all, deal with it!
- return ev.Result;
+ return true;
}
- public bool IsTileMixtureProbablySafe(EntityUid? gridUid, EntityUid mapUid, Vector2i tile)
+ public bool IsTileMixtureProbablySafe(Entity? grid, Entity map, Vector2i tile)
{
- return IsMixtureProbablySafe(GetTileMixture(gridUid, mapUid, tile));
+ return IsMixtureProbablySafe(GetTileMixture(grid, map, tile));
}
- public float GetTileHeatCapacity(EntityUid? gridUid, EntityUid mapUid, Vector2i tile)
+ public float GetTileHeatCapacity(Entity? grid, Entity map, Vector2i tile)
{
- return GetHeatCapacity(GetTileMixture(gridUid, mapUid, tile) ?? GasMixture.SpaceGas);
+ return GetHeatCapacity(GetTileMixture(grid, map, tile) ?? GasMixture.SpaceGas);
}
- public IEnumerable GetAdjacentTiles(EntityUid gridUid, Vector2i tile)
+ public TileMixtureEnumerator GetAdjacentTileMixtures(Entity grid, Vector2i tile, bool includeBlocked = false, bool excite = false)
{
- var ev = new GetAdjacentTilesMethodEvent(gridUid, tile);
- RaiseLocalEvent(gridUid, ref ev);
+ if (!_atmosQuery.Resolve(grid, ref grid.Comp, false))
+ return TileMixtureEnumerator.Empty;
- return ev.Result ?? Enumerable.Empty();
+ return !grid.Comp.Tiles.TryGetValue(tile, out var atmosTile)
+ ? TileMixtureEnumerator.Empty
+ : new(atmosTile.AdjacentTiles);
}
- public IEnumerable GetAdjacentTileMixtures(EntityUid gridUid, Vector2i tile, bool includeBlocked = false, bool excite = false)
- {
- var ev = new GetAdjacentTileMixturesMethodEvent(gridUid, tile, includeBlocked, excite);
- RaiseLocalEvent(gridUid, ref ev);
-
- return ev.Result ?? Enumerable.Empty();
- }
-
- public void HotspotExpose(EntityUid gridUid, Vector2i tile, float exposedTemperature, float exposedVolume,
+ public void HotspotExpose(Entity grid, Vector2i tile, float exposedTemperature, float exposedVolume,
EntityUid? sparkSourceUid = null, bool soh = false)
{
- var ev = new HotspotExposeMethodEvent(gridUid, sparkSourceUid, tile, exposedTemperature, exposedVolume, soh);
- RaiseLocalEvent(gridUid, ref ev);
+ if (!_atmosQuery.Resolve(grid, ref grid.Comp, false))
+ return;
+
+ if (grid.Comp.Tiles.TryGetValue(tile, out var atmosTile))
+ HotspotExpose(grid.Comp, atmosTile, exposedTemperature, exposedVolume, soh, sparkSourceUid);
+ }
+
+ public void HotspotExpose(TileAtmosphere tile, float exposedTemperature, float exposedVolume,
+ EntityUid? sparkSourceUid = null, bool soh = false)
+ {
+ if (!_atmosQuery.TryGetComponent(tile.GridIndex, out var atmos))
+ return;
+
+ DebugTools.Assert(atmos.Tiles.TryGetValue(tile.GridIndices, out var tmp) && tmp == tile);
+ HotspotExpose(atmos, tile, exposedTemperature, exposedVolume, soh, sparkSourceUid);
}
public void HotspotExtinguish(EntityUid gridUid, Vector2i tile)
@@ -253,39 +256,45 @@ public partial class AtmosphereSystem
return ev.Result;
}
- public void AddPipeNet(EntityUid gridUid, PipeNet pipeNet)
+ public bool AddPipeNet(Entity grid, PipeNet pipeNet)
{
- var ev = new AddPipeNetMethodEvent(gridUid, pipeNet);
- RaiseLocalEvent(gridUid, ref ev);
+ return _atmosQuery.Resolve(grid, ref grid.Comp, false) && grid.Comp.PipeNets.Add(pipeNet);
}
- public void RemovePipeNet(EntityUid gridUid, PipeNet pipeNet)
+ public bool RemovePipeNet(Entity grid, PipeNet pipeNet)
{
- var ev = new RemovePipeNetMethodEvent(gridUid, pipeNet);
- RaiseLocalEvent(gridUid, ref ev);
+ return _atmosQuery.Resolve(grid, ref grid.Comp, false) && grid.Comp.PipeNets.Remove(pipeNet);
}
- public bool AddAtmosDevice(EntityUid gridUid, AtmosDeviceComponent device)
+ public bool AddAtmosDevice(Entity grid, Entity device)
{
- // TODO: check device is on grid
+ DebugTools.Assert(device.Comp.JoinedGrid == null);
+ DebugTools.Assert(Transform(device).GridUid == grid);
- var ev = new AddAtmosDeviceMethodEvent(gridUid, device);
- RaiseLocalEvent(gridUid, ref ev);
- return ev.Result;
+ if (!_atmosQuery.Resolve(grid, ref grid.Comp, false))
+ return false;
+
+ if (!grid.Comp.AtmosDevices.Add(device))
+ return false;
+
+ device.Comp.JoinedGrid = grid;
+ return true;
}
- public bool RemoveAtmosDevice(EntityUid gridUid, AtmosDeviceComponent device)
+ public bool RemoveAtmosDevice(Entity grid, Entity device)
{
- // TODO: check device is on grid
+ DebugTools.Assert(device.Comp.JoinedGrid == grid);
- var ev = new RemoveAtmosDeviceMethodEvent(gridUid, device);
- RaiseLocalEvent(gridUid, ref ev);
- return ev.Result;
+ if (!_atmosQuery.Resolve(grid, ref grid.Comp, false))
+ return false;
+
+ if (!grid.Comp.AtmosDevices.Remove(device))
+ return false;
+
+ device.Comp.JoinedGrid = null;
+ return true;
}
- [ByRefEvent] private record struct HasAtmosphereMethodEvent
- (EntityUid Grid, bool Result = false, bool Handled = false);
-
[ByRefEvent] private record struct SetSimulatedGridMethodEvent
(EntityUid Grid, bool Simulated, bool Handled = false);
@@ -295,43 +304,12 @@ public partial class AtmosphereSystem
[ByRefEvent] private record struct GetAllMixturesMethodEvent
(EntityUid Grid, bool Excite = false, IEnumerable? Mixtures = null, bool Handled = false);
- [ByRefEvent] private record struct GetTileMixturesMethodEvent
- (EntityUid? GridUid, EntityUid? MapUid, List Tiles, bool Excite = false, GasMixture?[]? Mixtures = null, bool Handled = false);
-
- [ByRefEvent] private record struct GetTileMixtureMethodEvent
- (EntityUid? GridUid, EntityUid? MapUid, Vector2i Tile, bool Excite = false, GasMixture? Mixture = null, bool Handled = false);
-
[ByRefEvent] private record struct ReactTileMethodEvent
(EntityUid GridId, Vector2i Tile, ReactionResult Result = default, bool Handled = false);
- [ByRefEvent] private record struct IsTileSpaceMethodEvent
- (EntityUid? Grid, EntityUid? Map, Vector2i Tile, MapGridComponent? MapGridComponent = null, bool Result = true, bool Handled = false);
-
- [ByRefEvent] private record struct GetAdjacentTilesMethodEvent
- (EntityUid Grid, Vector2i Tile, IEnumerable? Result = null, bool Handled = false);
-
- [ByRefEvent] private record struct GetAdjacentTileMixturesMethodEvent
- (EntityUid Grid, Vector2i Tile, bool IncludeBlocked, bool Excite,
- IEnumerable? Result = null, bool Handled = false);
-
- [ByRefEvent] private record struct HotspotExposeMethodEvent
- (EntityUid Grid, EntityUid? SparkSourceUid, Vector2i Tile, float ExposedTemperature, float ExposedVolume, bool soh, bool Handled = false);
-
[ByRefEvent] private record struct HotspotExtinguishMethodEvent
(EntityUid Grid, Vector2i Tile, bool Handled = false);
[ByRefEvent] private record struct IsHotspotActiveMethodEvent
(EntityUid Grid, Vector2i Tile, bool Result = false, bool Handled = false);
-
- [ByRefEvent] private record struct AddPipeNetMethodEvent
- (EntityUid Grid, PipeNet PipeNet, bool Handled = false);
-
- [ByRefEvent] private record struct RemovePipeNetMethodEvent
- (EntityUid Grid, PipeNet PipeNet, bool Handled = false);
-
- [ByRefEvent] private record struct AddAtmosDeviceMethodEvent
- (EntityUid Grid, AtmosDeviceComponent Device, bool Result = false, bool Handled = false);
-
- [ByRefEvent] private record struct RemoveAtmosDeviceMethodEvent
- (EntityUid Grid, AtmosDeviceComponent Device, bool Result = false, bool Handled = false);
}
diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Commands.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Commands.cs
index 1c18b8fe29..a5e37398c6 100644
--- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Commands.cs
+++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Commands.cs
@@ -98,7 +98,7 @@ public sealed partial class AtmosphereSystem
continue;
}
- if (tile.Immutable && !IsTileSpace(euid, transform.MapUid, indices, gridComp))
+ if (tile.Immutable && !IsTileSpace(euid, transform.MapUid, indices))
{
tile = new GasMixture(tile.Volume) { Temperature = tile.Temperature };
tileMain.Air = tile;
diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.GridAtmosphere.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.GridAtmosphere.cs
index beddef4be7..bd45030896 100644
--- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.GridAtmosphere.cs
+++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.GridAtmosphere.cs
@@ -20,22 +20,11 @@ public sealed partial class AtmosphereSystem
#region Atmos API Subscriptions
- SubscribeLocalEvent(GridHasAtmosphere);
SubscribeLocalEvent(GridIsSimulated);
SubscribeLocalEvent(GridGetAllMixtures);
- SubscribeLocalEvent(GridGetTileMixture);
- SubscribeLocalEvent(GridGetTileMixtures);
SubscribeLocalEvent(GridReactTile);
- SubscribeLocalEvent(GridIsTileSpace);
- SubscribeLocalEvent(GridGetAdjacentTiles);
- SubscribeLocalEvent(GridGetAdjacentTileMixtures);
- SubscribeLocalEvent(GridHotspotExpose);
SubscribeLocalEvent(GridHotspotExtinguish);
SubscribeLocalEvent(GridIsHotspotActive);
- SubscribeLocalEvent(GridAddPipeNet);
- SubscribeLocalEvent(GridRemovePipeNet);
- SubscribeLocalEvent(GridAddAtmosDevice);
- SubscribeLocalEvent(GridRemoveAtmosDevice);
#endregion
}
@@ -120,15 +109,6 @@ public sealed partial class AtmosphereSystem
}
}
- private void GridHasAtmosphere(EntityUid uid, GridAtmosphereComponent component, ref HasAtmosphereMethodEvent args)
- {
- if (args.Handled)
- return;
-
- args.Result = true;
- args.Handled = true;
- }
-
private void GridIsSimulated(EntityUid uid, GridAtmosphereComponent component, ref IsSimulatedGridMethodEvent args)
{
if (args.Handled)
@@ -167,48 +147,6 @@ public sealed partial class AtmosphereSystem
args.Handled = true;
}
- private void GridGetTileMixture(EntityUid uid, GridAtmosphereComponent component,
- ref GetTileMixtureMethodEvent args)
- {
- if (args.Handled)
- return;
-
- if (!component.Tiles.TryGetValue(args.Tile, out var tile))
- return; // Do NOT handle the event if we don't have that tile, the map will handle it instead.
-
- if (args.Excite)
- component.InvalidatedCoords.Add(args.Tile);
-
- args.Mixture = tile.Air;
- args.Handled = true;
- }
-
- private void GridGetTileMixtures(EntityUid uid, GridAtmosphereComponent component,
- ref GetTileMixturesMethodEvent args)
- {
- if (args.Handled)
- return;
-
- args.Handled = true;
- args.Mixtures = new GasMixture?[args.Tiles.Count];
-
- for (var i = 0; i < args.Tiles.Count; i++)
- {
- var tile = args.Tiles[i];
- if (!component.Tiles.TryGetValue(tile, out var atmosTile))
- {
- // need to get map atmosphere
- args.Handled = false;
- continue;
- }
-
- if (args.Excite)
- component.InvalidatedCoords.Add(tile);
-
- args.Mixtures[i] = atmosTile.Air;
- }
- }
-
private void GridReactTile(EntityUid uid, GridAtmosphereComponent component, ref ReactTileMethodEvent args)
{
if (args.Handled)
@@ -221,67 +159,6 @@ public sealed partial class AtmosphereSystem
args.Handled = true;
}
- private void GridIsTileSpace(EntityUid uid, GridAtmosphereComponent component, ref IsTileSpaceMethodEvent args)
- {
- if (args.Handled)
- return;
-
- // We don't have that tile, so let the map handle it.
- if (!component.Tiles.TryGetValue(args.Tile, out var tile))
- return;
-
- args.Result = tile.Space;
- args.Handled = true;
- }
-
- private void GridGetAdjacentTiles(EntityUid uid, GridAtmosphereComponent component,
- ref GetAdjacentTilesMethodEvent args)
- {
- if (args.Handled)
- return;
-
- if (!component.Tiles.TryGetValue(args.Tile, out var tile))
- return;
-
- IEnumerable EnumerateAdjacent(GridAtmosphereComponent grid, TileAtmosphere t)
- {
- foreach (var adj in t.AdjacentTiles)
- {
- if (adj == null)
- continue;
-
- yield return adj.GridIndices;
- }
- }
-
- args.Result = EnumerateAdjacent(component, tile);
- args.Handled = true;
- }
-
- private void GridGetAdjacentTileMixtures(EntityUid uid, GridAtmosphereComponent component,
- ref GetAdjacentTileMixturesMethodEvent args)
- {
- if (args.Handled)
- return;
-
- if (!component.Tiles.TryGetValue(args.Tile, out var tile))
- return;
-
- IEnumerable EnumerateAdjacent(GridAtmosphereComponent grid, TileAtmosphere t)
- {
- foreach (var adj in t.AdjacentTiles)
- {
- if (adj?.Air == null)
- continue;
-
- yield return adj.Air;
- }
- }
-
- args.Result = EnumerateAdjacent(component, tile);
- args.Handled = true;
- }
-
///
/// Update array of adjacent tiles and the adjacency flags. Optionally activates all tiles with modified adjacencies.
///
@@ -357,18 +234,6 @@ public sealed partial class AtmosphereSystem
return (air, map.Space);
}
- private void GridHotspotExpose(EntityUid uid, GridAtmosphereComponent component, ref HotspotExposeMethodEvent args)
- {
- if (args.Handled)
- return;
-
- if (!component.Tiles.TryGetValue(args.Tile, out var tile))
- return;
-
- HotspotExpose(component, tile, args.ExposedTemperature, args.ExposedVolume, args.soh, args.SparkSourceUid);
- args.Handled = true;
- }
-
private void GridHotspotExtinguish(EntityUid uid, GridAtmosphereComponent component,
ref HotspotExtinguishMethodEvent args)
{
@@ -445,49 +310,6 @@ public sealed partial class AtmosphereSystem
tile.Air.Temperature = totalTemperature / count;
}
- private void GridAddPipeNet(EntityUid uid, GridAtmosphereComponent component, ref AddPipeNetMethodEvent args)
- {
- if (args.Handled)
- return;
-
- args.Handled = component.PipeNets.Add(args.PipeNet);
- }
-
- private void GridRemovePipeNet(EntityUid uid, GridAtmosphereComponent component, ref RemovePipeNetMethodEvent args)
- {
- if (args.Handled)
- return;
-
- args.Handled = component.PipeNets.Remove(args.PipeNet);
- }
-
- private void GridAddAtmosDevice(Entity grid, ref AddAtmosDeviceMethodEvent args)
- {
- if (args.Handled)
- return;
-
- if (!grid.Comp.AtmosDevices.Add((args.Device.Owner, args.Device)))
- return;
-
- args.Device.JoinedGrid = grid;
- args.Handled = true;
- args.Result = true;
- }
-
- private void GridRemoveAtmosDevice(EntityUid uid, GridAtmosphereComponent component,
- ref RemoveAtmosDeviceMethodEvent args)
- {
- if (args.Handled)
- return;
-
- if (!component.AtmosDevices.Remove((args.Device.Owner, args.Device)))
- return;
-
- args.Device.JoinedGrid = null;
- args.Handled = true;
- args.Result = true;
- }
-
///
/// Repopulates all tiles on a grid atmosphere.
///
diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Map.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Map.cs
index ed105c8d33..25b3b801f7 100644
--- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Map.cs
+++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Map.cs
@@ -12,9 +12,6 @@ public partial class AtmosphereSystem
{
SubscribeLocalEvent(OnMapStartup);
SubscribeLocalEvent(OnMapRemove);
- SubscribeLocalEvent(MapIsTileSpace);
- SubscribeLocalEvent(MapGetTileMixture);
- SubscribeLocalEvent(MapGetTileMixtures);
SubscribeLocalEvent(OnMapGetState);
SubscribeLocalEvent(OnGridParentChanged);
}
@@ -31,37 +28,6 @@ public partial class AtmosphereSystem
RefreshAllGridMapAtmospheres(uid);
}
- private void MapIsTileSpace(EntityUid uid, MapAtmosphereComponent component, ref IsTileSpaceMethodEvent args)
- {
- if (args.Handled)
- return;
-
- args.Result = component.Space;
- args.Handled = true;
- }
-
- private void MapGetTileMixture(EntityUid uid, MapAtmosphereComponent component, ref GetTileMixtureMethodEvent args)
- {
- if (args.Handled)
- return;
-
- args.Mixture = component.Mixture;
- args.Handled = true;
- }
-
- private void MapGetTileMixtures(EntityUid uid, MapAtmosphereComponent component, ref GetTileMixturesMethodEvent args)
- {
- if (args.Handled)
- return;
- args.Handled = true;
- args.Mixtures ??= new GasMixture?[args.Tiles.Count];
-
- for (var i = 0; i < args.Tiles.Count; i++)
- {
- args.Mixtures[i] ??= component.Mixture;
- }
- }
-
private void OnMapGetState(EntityUid uid, MapAtmosphereComponent component, ref ComponentGetState args)
{
args.State = new MapAtmosphereComponentState(component.Overlay);
diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs
index d2f40e7716..a553766582 100644
--- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs
+++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs
@@ -42,6 +42,7 @@ public sealed partial class AtmosphereSystem : SharedAtmosphereSystem
private float _exposedTimer = 0f;
private EntityQuery _atmosQuery;
+ private EntityQuery _mapAtmosQuery;
private EntityQuery _airtightQuery;
private EntityQuery _firelockQuery;
private HashSet _entSet = new();
@@ -59,6 +60,7 @@ public sealed partial class AtmosphereSystem : SharedAtmosphereSystem
InitializeGridAtmosphere();
InitializeMap();
+ _mapAtmosQuery = GetEntityQuery();
_atmosQuery = GetEntityQuery();
_airtightQuery = GetEntityQuery();
_firelockQuery = GetEntityQuery();
diff --git a/Content.Server/Atmos/EntitySystems/GasTankSystem.cs b/Content.Server/Atmos/EntitySystems/GasTankSystem.cs
index dfe8447340..aed00432e1 100644
--- a/Content.Server/Atmos/EntitySystems/GasTankSystem.cs
+++ b/Content.Server/Atmos/EntitySystems/GasTankSystem.cs
@@ -1,4 +1,3 @@
-using System.Numerics;
using Content.Server.Atmos.Components;
using Content.Server.Body.Components;
using Content.Server.Body.Systems;
@@ -17,8 +16,6 @@ using Robust.Server.GameObjects;
using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Containers;
-using Robust.Shared.Physics.Systems;
-using Robust.Shared.Player;
using Robust.Shared.Random;
namespace Content.Server.Atmos.EntitySystems
@@ -33,7 +30,6 @@ namespace Content.Server.Atmos.EntitySystems
[Dependency] private readonly SharedContainerSystem _containers = default!;
[Dependency] private readonly SharedActionsSystem _actions = default!;
[Dependency] private readonly UserInterfaceSystem _ui = default!;
- [Dependency] private readonly SharedPhysicsSystem _physics = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly ThrowingSystem _throwing = default!;
diff --git a/Content.Server/Atmos/Piping/Binary/EntitySystems/GasVolumePumpSystem.cs b/Content.Server/Atmos/Piping/Binary/EntitySystems/GasVolumePumpSystem.cs
index 10b9cccc09..8e478bd2b5 100644
--- a/Content.Server/Atmos/Piping/Binary/EntitySystems/GasVolumePumpSystem.cs
+++ b/Content.Server/Atmos/Piping/Binary/EntitySystems/GasVolumePumpSystem.cs
@@ -27,7 +27,6 @@ namespace Content.Server.Atmos.Piping.Binary.EntitySystems
public sealed class GasVolumePumpSystem : EntitySystem
{
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
- [Dependency] private readonly TransformSystem _transformSystem = default!;
[Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
[Dependency] private readonly UserInterfaceSystem _userInterfaceSystem = default!;
[Dependency] private readonly SharedAmbientSoundSystem _ambientSoundSystem = default!;
diff --git a/Content.Server/Atmos/Piping/Components/AtmosDeviceComponent.cs b/Content.Server/Atmos/Piping/Components/AtmosDeviceComponent.cs
index 361e3cbbeb..80461f1beb 100644
--- a/Content.Server/Atmos/Piping/Components/AtmosDeviceComponent.cs
+++ b/Content.Server/Atmos/Piping/Components/AtmosDeviceComponent.cs
@@ -28,7 +28,7 @@ public sealed partial class AtmosDeviceComponent : Component
///
/// If non-null, the grid that this device is part of.
///
- [DataField]
+ [ViewVariables]
public EntityUid? JoinedGrid = null;
///
diff --git a/Content.Server/Atmos/Piping/EntitySystems/AtmosDeviceSystem.cs b/Content.Server/Atmos/Piping/EntitySystems/AtmosDeviceSystem.cs
index f4da68ab53..c15d31f7d6 100644
--- a/Content.Server/Atmos/Piping/EntitySystems/AtmosDeviceSystem.cs
+++ b/Content.Server/Atmos/Piping/EntitySystems/AtmosDeviceSystem.cs
@@ -1,7 +1,9 @@
+using Content.Server.Atmos.Components;
using Content.Server.Atmos.EntitySystems;
using Content.Server.Atmos.Piping.Components;
using JetBrains.Annotations;
using Robust.Shared.Timing;
+using Robust.Shared.Utility;
namespace Content.Server.Atmos.Piping.EntitySystems
{
@@ -32,6 +34,14 @@ namespace Content.Server.Atmos.Piping.EntitySystems
public void JoinAtmosphere(Entity ent)
{
+ if (ent.Comp.JoinedGrid != null)
+ {
+ DebugTools.Assert(HasComp(ent.Comp.JoinedGrid));
+ DebugTools.Assert(Transform(ent).GridUid == ent.Comp.JoinedGrid);
+ DebugTools.Assert(ent.Comp.RequireAnchored == Transform(ent).Anchored);
+ return;
+ }
+
var component = ent.Comp;
var transform = Transform(ent);
@@ -39,7 +49,7 @@ namespace Content.Server.Atmos.Piping.EntitySystems
return;
// Attempt to add device to a grid atmosphere.
- bool onGrid = (transform.GridUid != null) && _atmosphereSystem.AddAtmosDevice(transform.GridUid!.Value, component);
+ bool onGrid = (transform.GridUid != null) && _atmosphereSystem.AddAtmosDevice(transform.GridUid!.Value, ent);
if (!onGrid && component.JoinSystem)
{
@@ -55,7 +65,7 @@ namespace Content.Server.Atmos.Piping.EntitySystems
{
var component = ent.Comp;
// Try to remove the component from an atmosphere, and if not
- if (component.JoinedGrid != null && !_atmosphereSystem.RemoveAtmosDevice(component.JoinedGrid.Value, component))
+ if (component.JoinedGrid != null && !_atmosphereSystem.RemoveAtmosDevice(component.JoinedGrid.Value, ent))
{
// The grid might have been removed but not us... This usually shouldn't happen.
component.JoinedGrid = null;
diff --git a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasCanisterSystem.cs b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasCanisterSystem.cs
index ad647fad1b..170586339d 100644
--- a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasCanisterSystem.cs
+++ b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasCanisterSystem.cs
@@ -13,7 +13,6 @@ using Content.Shared.Atmos;
using Content.Shared.Atmos.Piping.Binary.Components;
using Content.Shared.Containers.ItemSlots;
using Content.Shared.Database;
-using Content.Shared.Hands.EntitySystems;
using Content.Shared.Interaction;
using Content.Shared.Lock;
using Robust.Server.GameObjects;
@@ -29,8 +28,6 @@ public sealed class GasCanisterSystem : EntitySystem
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
- [Dependency] private readonly SharedContainerSystem _container = default!;
- [Dependency] private readonly SharedHandsSystem _hands = default!;
[Dependency] private readonly PopupSystem _popup = default!;
[Dependency] private readonly UserInterfaceSystem _ui = default!;
[Dependency] private readonly NodeContainerSystem _nodeContainer = default!;
diff --git a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasVentScrubberSystem.cs b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasVentScrubberSystem.cs
index 32591e9c54..5afa007e5e 100644
--- a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasVentScrubberSystem.cs
+++ b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasVentScrubberSystem.cs
@@ -77,7 +77,8 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems
return;
// Scrub adjacent tiles too.
- foreach (var adjacent in _atmosphereSystem.GetAdjacentTileMixtures(xform.GridUid.Value, position, false, true))
+ var enumerator = _atmosphereSystem.GetAdjacentTileMixtures(xform.GridUid.Value, position, false, true);
+ while (enumerator.MoveNext(out var adjacent))
{
Scrub(timeDelta, scrubber, adjacent, outlet);
}
diff --git a/Content.Server/Atmos/Portable/PortableScrubberSystem.cs b/Content.Server/Atmos/Portable/PortableScrubberSystem.cs
index f1be5ac515..e986f8f991 100644
--- a/Content.Server/Atmos/Portable/PortableScrubberSystem.cs
+++ b/Content.Server/Atmos/Portable/PortableScrubberSystem.cs
@@ -86,7 +86,8 @@ namespace Content.Server.Atmos.Portable
if (!running)
return;
// widenet
- foreach (var adjacent in _atmosphereSystem.GetAdjacentTileMixtures(xform.GridUid.Value, position, false, true))
+ var enumerator = _atmosphereSystem.GetAdjacentTileMixtures(xform.GridUid.Value, position, false, true);
+ while (enumerator.MoveNext(out var adjacent))
{
Scrub(timeDelta, component, adjacent);
}
diff --git a/Content.Server/Atmos/Reactions/PlasmaFireReaction.cs b/Content.Server/Atmos/Reactions/PlasmaFireReaction.cs
index 9adda3089c..e7ab7835fd 100644
--- a/Content.Server/Atmos/Reactions/PlasmaFireReaction.cs
+++ b/Content.Server/Atmos/Reactions/PlasmaFireReaction.cs
@@ -75,7 +75,7 @@ namespace Content.Server.Atmos.Reactions
var mixTemperature = mixture.Temperature;
if (mixTemperature > Atmospherics.FireMinimumTemperatureToExist)
{
- atmosphereSystem.HotspotExpose(location.GridIndex, location.GridIndices, mixTemperature, mixture.Volume);
+ atmosphereSystem.HotspotExpose(location, mixTemperature, mixture.Volume);
}
}
diff --git a/Content.Server/Atmos/Reactions/TritiumFireReaction.cs b/Content.Server/Atmos/Reactions/TritiumFireReaction.cs
index 37c9741e86..7103859a90 100644
--- a/Content.Server/Atmos/Reactions/TritiumFireReaction.cs
+++ b/Content.Server/Atmos/Reactions/TritiumFireReaction.cs
@@ -60,7 +60,7 @@ namespace Content.Server.Atmos.Reactions
temperature = mixture.Temperature;
if (temperature > Atmospherics.FireMinimumTemperatureToExist)
{
- atmosphereSystem.HotspotExpose(location.GridIndex, location.GridIndices, temperature, mixture.Volume);
+ atmosphereSystem.HotspotExpose(location, temperature, mixture.Volume);
}
}
diff --git a/Content.Server/Atmos/TileMixtureEnumerator.cs b/Content.Server/Atmos/TileMixtureEnumerator.cs
new file mode 100644
index 0000000000..20440032da
--- /dev/null
+++ b/Content.Server/Atmos/TileMixtureEnumerator.cs
@@ -0,0 +1,29 @@
+using System.Diagnostics.CodeAnalysis;
+
+namespace Content.Server.Atmos;
+
+public struct TileMixtureEnumerator
+{
+ public readonly TileAtmosphere?[] Tiles;
+ public int Index = 0;
+
+ public static readonly TileMixtureEnumerator Empty = new(Array.Empty());
+
+ internal TileMixtureEnumerator(TileAtmosphere?[] tiles)
+ {
+ Tiles = tiles;
+ }
+
+ public bool MoveNext([NotNullWhen(true)] out GasMixture? mix)
+ {
+ while (Index < Tiles.Length)
+ {
+ mix = Tiles[Index++]?.Air;
+ if (mix != null)
+ return true;
+ }
+
+ mix = null;
+ return false;
+ }
+}
diff --git a/Content.Server/Bed/BedSystem.cs b/Content.Server/Bed/BedSystem.cs
index 131bd4b182..49021c142f 100644
--- a/Content.Server/Bed/BedSystem.cs
+++ b/Content.Server/Bed/BedSystem.cs
@@ -93,9 +93,8 @@ namespace Content.Server.Bed
if (!this.IsPowered(uid, EntityManager))
return;
- var metabolicEvent = new ApplyMetabolicMultiplierEvent
- {Uid = args.BuckledEntity, Multiplier = component.Multiplier, Apply = args.Buckling};
- RaiseLocalEvent(args.BuckledEntity, metabolicEvent);
+ var metabolicEvent = new ApplyMetabolicMultiplierEvent(args.BuckledEntity, component.Multiplier, args.Buckling);
+ RaiseLocalEvent(args.BuckledEntity, ref metabolicEvent);
}
private void OnPowerChanged(EntityUid uid, StasisBedComponent component, ref PowerChangedEvent args)
@@ -121,9 +120,8 @@ namespace Content.Server.Bed
foreach (var buckledEntity in strap.BuckledEntities)
{
- var metabolicEvent = new ApplyMetabolicMultiplierEvent
- {Uid = buckledEntity, Multiplier = component.Multiplier, Apply = shouldApply};
- RaiseLocalEvent(buckledEntity, metabolicEvent);
+ var metabolicEvent = new ApplyMetabolicMultiplierEvent(buckledEntity, component.Multiplier, shouldApply);
+ RaiseLocalEvent(buckledEntity, ref metabolicEvent);
}
}
}
diff --git a/Content.Server/Bed/Sleep/SleepingSystem.cs b/Content.Server/Bed/Sleep/SleepingSystem.cs
index b497254433..5e4f0eddb5 100644
--- a/Content.Server/Bed/Sleep/SleepingSystem.cs
+++ b/Content.Server/Bed/Sleep/SleepingSystem.cs
@@ -1,5 +1,6 @@
using Content.Server.Popups;
-using Content.Server.Sound.Components;
+using Content.Server.Sound;
+using Content.Shared.Sound.Components;
using Content.Shared.Actions;
using Content.Shared.Audio;
using Content.Shared.Bed.Sleep;
@@ -30,6 +31,7 @@ namespace Content.Server.Bed.Sleep
[Dependency] private readonly PopupSystem _popupSystem = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly StatusEffectsSystem _statusEffectsSystem = default!;
+ [Dependency] private readonly EmitSoundSystem _emitSound = default!;
[ValidatePrototypeId] public const string SleepActionId = "ActionSleep";
@@ -71,8 +73,8 @@ namespace Content.Server.Bed.Sleep
{
emitSound.Sound = sleepSound.Snore;
}
- emitSound.PlayChance = sleepSound.Chance;
- emitSound.RollInterval = sleepSound.Interval;
+ emitSound.MinInterval = sleepSound.Interval;
+ emitSound.MaxInterval = sleepSound.MaxInterval;
emitSound.PopUp = sleepSound.PopUp;
}
@@ -128,7 +130,7 @@ namespace Content.Server.Bed.Sleep
return;
}
if (TryComp(uid, out var spam))
- spam.Enabled = args.NewMobState == MobState.Alive;
+ _emitSound.SetEnabled((uid, spam), args.NewMobState == MobState.Alive);
}
private void AddWakeVerb(EntityUid uid, SleepingComponent component, GetVerbsEvent args)
diff --git a/Content.Server/Body/Commands/AddHandCommand.cs b/Content.Server/Body/Commands/AddHandCommand.cs
index 655d0c88f9..3e006c539c 100644
--- a/Content.Server/Body/Commands/AddHandCommand.cs
+++ b/Content.Server/Body/Commands/AddHandCommand.cs
@@ -34,7 +34,6 @@ namespace Content.Server.Body.Commands
switch (args.Length)
{
case 0:
- {
if (player == null)
{
shell.WriteLine("Only a player can run this command without arguments.");
@@ -50,71 +49,68 @@ namespace Content.Server.Body.Commands
entity = player.AttachedEntity.Value;
hand = _entManager.SpawnEntity(DefaultHandPrototype, _entManager.GetComponent(entity).Coordinates);
break;
- }
case 1:
- {
- if (NetEntity.TryParse(args[0], out var uidNet) && _entManager.TryGetEntity(uidNet, out var uid))
{
+ if (NetEntity.TryParse(args[0], out var uidNet) && _entManager.TryGetEntity(uidNet, out var uid))
+ {
+ if (!_entManager.EntityExists(uid))
+ {
+ shell.WriteLine($"No entity found with uid {uid}");
+ return;
+ }
+
+ entity = uid.Value;
+ hand = _entManager.SpawnEntity(DefaultHandPrototype, _entManager.GetComponent(entity).Coordinates);
+ }
+ else
+ {
+ if (player == null)
+ {
+ shell.WriteLine("You must specify an entity to add a hand to when using this command from the server terminal.");
+ return;
+ }
+
+ if (player.AttachedEntity == null)
+ {
+ shell.WriteLine("You don't have an entity to add a hand to.");
+ return;
+ }
+
+ entity = player.AttachedEntity.Value;
+ hand = _entManager.SpawnEntity(args[0], _entManager.GetComponent(entity).Coordinates);
+ }
+
+ break;
+ }
+ case 2:
+ {
+ if (!NetEntity.TryParse(args[0], out var netEnt) || !_entManager.TryGetEntity(netEnt, out var uid))
+ {
+ shell.WriteLine($"{args[0]} is not a valid entity uid.");
+ return;
+ }
+
if (!_entManager.EntityExists(uid))
{
- shell.WriteLine($"No entity found with uid {uid}");
+ shell.WriteLine($"No entity exists with uid {uid}.");
return;
}
entity = uid.Value;
- hand = _entManager.SpawnEntity(DefaultHandPrototype, _entManager.GetComponent(entity).Coordinates);
- }
- else
- {
- if (player == null)
+
+ if (!_protoManager.HasIndex(args[1]))
{
- shell.WriteLine("You must specify an entity to add a hand to when using this command from the server terminal.");
+ shell.WriteLine($"No hand entity exists with id {args[1]}.");
return;
}
- if (player.AttachedEntity == null)
- {
- shell.WriteLine("You don't have an entity to add a hand to.");
- return;
- }
+ hand = _entManager.SpawnEntity(args[1], _entManager.GetComponent(entity).Coordinates);
- entity = player.AttachedEntity.Value;
- hand = _entManager.SpawnEntity(args[0], _entManager.GetComponent(entity).Coordinates);
+ break;
}
-
- break;
- }
- case 2:
- {
- if (!NetEntity.TryParse(args[0], out var netEnt) || !_entManager.TryGetEntity(netEnt, out var uid))
- {
- shell.WriteLine($"{args[0]} is not a valid entity uid.");
- return;
- }
-
- if (!_entManager.EntityExists(uid))
- {
- shell.WriteLine($"No entity exists with uid {uid}.");
- return;
- }
-
- entity = uid.Value;
-
- if (!_protoManager.HasIndex(args[1]))
- {
- shell.WriteLine($"No hand entity exists with id {args[1]}.");
- return;
- }
-
- hand = _entManager.SpawnEntity(args[1], _entManager.GetComponent(entity).Coordinates);
-
- break;
- }
default:
- {
shell.WriteLine(Help);
return;
- }
}
if (!_entManager.TryGetComponent(entity, out BodyComponent? body) || body.RootContainer.ContainedEntity == null)
@@ -139,7 +135,7 @@ namespace Content.Server.Body.Commands
var slotId = part.GetHashCode().ToString();
- if (!bodySystem.TryCreatePartSlotAndAttach(attachAt.Id, slotId, hand, BodyPartType.Hand,attachAt.Component, part))
+ if (!bodySystem.TryCreatePartSlotAndAttach(attachAt.Id, slotId, hand, BodyPartType.Hand, attachAt.Component, part))
{
shell.WriteError($"Couldn't create a slot with id {slotId} on entity {_entManager.ToPrettyString(entity)}");
return;
diff --git a/Content.Server/Body/Commands/AttachBodyPartCommand.cs b/Content.Server/Body/Commands/AttachBodyPartCommand.cs
index 24604b88b7..82f7161937 100644
--- a/Content.Server/Body/Commands/AttachBodyPartCommand.cs
+++ b/Content.Server/Body/Commands/AttachBodyPartCommand.cs
@@ -103,11 +103,11 @@ namespace Content.Server.Body.Commands
// ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
if (body.RootContainer.ContainedEntity != null)
{
- bodySystem.AttachPartToRoot(bodyId,partUid.Value, body ,part);
+ bodySystem.AttachPartToRoot(bodyId, partUid.Value, body, part);
}
else
{
- var (rootPartId,rootPart) = bodySystem.GetRootPartOrNull(bodyId, body)!.Value;
+ var (rootPartId, rootPart) = bodySystem.GetRootPartOrNull(bodyId, body)!.Value;
if (!bodySystem.TryCreatePartSlotAndAttach(rootPartId, slotId, partUid.Value, part.PartType, rootPart, part))
{
shell.WriteError($"Could not create slot {slotId} on entity {_entManager.ToPrettyString(bodyId)}");
diff --git a/Content.Server/Body/Components/BeingGibbedEvent.cs b/Content.Server/Body/Components/BeingGibbedEvent.cs
index 66b52af47b..a010855f78 100644
--- a/Content.Server/Body/Components/BeingGibbedEvent.cs
+++ b/Content.Server/Body/Components/BeingGibbedEvent.cs
@@ -1,11 +1,7 @@
namespace Content.Server.Body.Components;
-public sealed class BeingGibbedEvent : EntityEventArgs
-{
- public readonly HashSet GibbedParts;
-
- public BeingGibbedEvent(HashSet gibbedParts)
- {
- GibbedParts = gibbedParts;
- }
-}
+///
+/// Raised when a body gets gibbed, before it is deleted.
+///
+[ByRefEvent]
+public readonly record struct BeingGibbedEvent(HashSet GibbedParts);
diff --git a/Content.Server/Body/Components/BloodstreamComponent.cs b/Content.Server/Body/Components/BloodstreamComponent.cs
index 7041df4448..d448c4aab2 100644
--- a/Content.Server/Body/Components/BloodstreamComponent.cs
+++ b/Content.Server/Body/Components/BloodstreamComponent.cs
@@ -1,11 +1,13 @@
using Content.Server.Body.Systems;
using Content.Server.Chemistry.EntitySystems;
using Content.Shared.Chemistry.Components;
+using Content.Shared.Chemistry.Reagent;
using Content.Shared.Damage;
using Content.Shared.Damage.Prototypes;
using Content.Shared.FixedPoint;
using Robust.Shared.Audio;
-using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
namespace Content.Server.Body.Components
{
@@ -16,7 +18,17 @@ namespace Content.Server.Body.Components
public static string DefaultBloodSolutionName = "bloodstream";
public static string DefaultBloodTemporarySolutionName = "bloodstreamTemporary";
- public float AccumulatedFrametime = 0.0f;
+ ///
+ /// The next time that blood level will be updated and bloodloss damage dealt.
+ ///
+ [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))]
+ public TimeSpan NextUpdate;
+
+ ///
+ /// The interval at which this component updates.
+ ///
+ [DataField]
+ public TimeSpan UpdateInterval = TimeSpan.FromSeconds(3);
///
/// How much is this entity currently bleeding?
@@ -32,7 +44,7 @@ namespace Content.Server.Body.Components
public float BleedAmount;
///
- /// How much should bleeding should be reduced every update interval?
+ /// How much should bleeding be reduced every update interval?
///
[DataField]
public float BleedReductionAmount = 0.33f;
@@ -63,18 +75,12 @@ namespace Content.Server.Body.Components
[DataField(required: true)]
public DamageSpecifier BloodlossHealDamage = new();
- ///
- /// How frequently should this bloodstream update, in seconds?
- ///
- [DataField]
- public float UpdateInterval = 3.0f;
-
// TODO shouldn't be hardcoded, should just use some organ simulation like bone marrow or smth.
///
/// How much reagent of blood should be restored each update interval?
///
[DataField]
- public float BloodRefreshAmount = 1.0f;
+ public FixedPoint2 BloodRefreshAmount = 1.0f;
///
/// How much blood needs to be in the temporary solution in order to create a puddle?
@@ -89,8 +95,8 @@ namespace Content.Server.Body.Components
///
/// For example, piercing damage is increased while poison damage is nullified entirely.
///
- [DataField(customTypeSerializer:typeof(PrototypeIdSerializer))]
- public string DamageBleedModifiers = "BloodlossHuman";
+ [DataField]
+ public ProtoId DamageBleedModifiers = "BloodlossHuman";
///
/// The sound to be played when a weapon instantly deals blood loss damage.
@@ -126,7 +132,7 @@ namespace Content.Server.Body.Components
/// Slime-people might use slime as their blood or something like that.
///
[DataField]
- public string BloodReagent = "Blood";
+ public ProtoId BloodReagent = "Blood";
/// Name/Key that is indexed by.
[DataField]
@@ -164,6 +170,6 @@ namespace Content.Server.Body.Components
/// Variable that stores the amount of status time added by having a low blood level.
///
[ViewVariables(VVAccess.ReadWrite)]
- public float StatusTime;
+ public TimeSpan StatusTime;
}
}
diff --git a/Content.Server/Body/Components/InternalsComponent.cs b/Content.Server/Body/Components/InternalsComponent.cs
index 4eda008b0f..18caab8dcf 100644
--- a/Content.Server/Body/Components/InternalsComponent.cs
+++ b/Content.Server/Body/Components/InternalsComponent.cs
@@ -1,4 +1,3 @@
-using System.Threading;
namespace Content.Server.Body.Components
{
///
@@ -7,14 +6,17 @@ namespace Content.Server.Body.Components
[RegisterComponent]
public sealed partial class InternalsComponent : Component
{
- [ViewVariables] public EntityUid? GasTankEntity { get; set; }
- [ViewVariables] public EntityUid? BreathToolEntity { get; set; }
+ [ViewVariables]
+ public EntityUid? GasTankEntity;
+
+ [ViewVariables]
+ public EntityUid? BreathToolEntity;
///
- /// Toggle Internals delay (seconds) when the target is not you.
+ /// Toggle Internals delay when the target is not you.
///
[ViewVariables(VVAccess.ReadWrite)]
- [DataField("delay")]
- public float Delay = 3;
+ [DataField]
+ public TimeSpan Delay = TimeSpan.FromSeconds(3);
}
}
diff --git a/Content.Server/Body/Components/LungComponent.cs b/Content.Server/Body/Components/LungComponent.cs
index 0656ef8fad..46600b3020 100644
--- a/Content.Server/Body/Components/LungComponent.cs
+++ b/Content.Server/Body/Components/LungComponent.cs
@@ -1,4 +1,4 @@
-using Content.Server.Atmos;
+using Content.Server.Atmos;
using Content.Server.Body.Systems;
using Content.Shared.Alert;
using Content.Shared.Atmos;
@@ -11,7 +11,7 @@ public sealed partial class LungComponent : Component
{
[DataField]
[Access(typeof(LungSystem), Other = AccessPermissions.ReadExecute)] // FIXME Friends
- public GasMixture Air { get; set; } = new()
+ public GasMixture Air = new()
{
Volume = 6,
Temperature = Atmospherics.NormalBodyTemperature
diff --git a/Content.Server/Body/Components/MetabolizerComponent.cs b/Content.Server/Body/Components/MetabolizerComponent.cs
index a8c82f3d36..90c99df7db 100644
--- a/Content.Server/Body/Components/MetabolizerComponent.cs
+++ b/Content.Server/Body/Components/MetabolizerComponent.cs
@@ -1,8 +1,8 @@
-using Content.Server.Body.Systems;
+using Content.Server.Body.Systems;
using Content.Shared.Body.Prototypes;
using Content.Shared.FixedPoint;
-using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
-using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Set;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
namespace Content.Server.Body.Components
{
@@ -12,20 +12,24 @@ namespace Content.Server.Body.Components
[RegisterComponent, Access(typeof(MetabolizerSystem))]
public sealed partial class MetabolizerComponent : Component
{
- public float AccumulatedFrametime = 0.0f;
+ ///
+ /// The next time that reagents will be metabolized.
+ ///
+ [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))]
+ public TimeSpan NextUpdate;
///
- /// How often to metabolize reagents, in seconds.
+ /// How often to metabolize reagents.
///
///
[DataField]
- public float UpdateFrequency = 1.0f;
+ public TimeSpan UpdateInterval = TimeSpan.FromSeconds(1);
///
/// From which solution will this metabolizer attempt to metabolize chemicals
///
[DataField("solution")]
- public string SolutionName { get; set; } = BloodstreamComponent.DefaultChemicalsSolutionName;
+ public string SolutionName = BloodstreamComponent.DefaultChemicalsSolutionName;
///
/// Does this component use a solution on it's parent entity (the body) or itself
@@ -39,9 +43,9 @@ namespace Content.Server.Body.Components
///
/// List of metabolizer types that this organ is. ex. Human, Slime, Felinid, w/e.
///
- [DataField(customTypeSerializer:typeof(PrototypeIdHashSetSerializer))]
+ [DataField]
[Access(typeof(MetabolizerSystem), Other = AccessPermissions.ReadExecute)] // FIXME Friends
- public HashSet? MetabolizerTypes = null;
+ public HashSet>? MetabolizerTypes = null;
///
/// Should this metabolizer remove chemicals that have no metabolisms defined?
@@ -72,8 +76,8 @@ namespace Content.Server.Body.Components
[DataDefinition]
public sealed partial class MetabolismGroupEntry
{
- [DataField(required: true, customTypeSerializer:typeof(PrototypeIdSerializer))]
- public string Id = default!;
+ [DataField(required: true)]
+ public ProtoId Id = default!;
[DataField("rateModifier")]
public FixedPoint2 MetabolismRateModifier = 1.0;
diff --git a/Content.Server/Body/Components/RespiratorComponent.cs b/Content.Server/Body/Components/RespiratorComponent.cs
index 9f080a3dd9..4045e21e26 100644
--- a/Content.Server/Body/Components/RespiratorComponent.cs
+++ b/Content.Server/Body/Components/RespiratorComponent.cs
@@ -1,5 +1,6 @@
using Content.Server.Body.Systems;
using Content.Shared.Damage;
+using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
namespace Content.Server.Body.Components
{
@@ -7,36 +8,49 @@ namespace Content.Server.Body.Components
public sealed partial class RespiratorComponent : Component
{
///
- /// Saturation level. Reduced by CycleDelay each tick.
+ /// The next time that this body will inhale or exhale.
+ ///
+ [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))]
+ public TimeSpan NextUpdate;
+
+ ///
+ /// The interval between updates. Each update is either inhale or exhale,
+ /// so a full cycle takes twice as long.
+ ///
+ [DataField]
+ public TimeSpan UpdateInterval = TimeSpan.FromSeconds(2);
+
+ ///
+ /// Saturation level. Reduced by UpdateInterval each tick.
/// Can be thought of as 'how many seconds you have until you start suffocating' in this configuration.
///
- [DataField("saturation")]
+ [DataField]
public float Saturation = 5.0f;
///
/// At what level of saturation will you begin to suffocate?
///
- [DataField("suffocationThreshold")]
+ [DataField]
public float SuffocationThreshold;
- [DataField("maxSaturation")]
+ [DataField]
public float MaxSaturation = 5.0f;
- [DataField("minSaturation")]
+ [DataField]
public float MinSaturation = -2.0f;
// TODO HYPEROXIA?
- [DataField("damage", required: true)]
+ [DataField(required: true)]
[ViewVariables(VVAccess.ReadWrite)]
public DamageSpecifier Damage = default!;
- [DataField("damageRecovery", required: true)]
+ [DataField(required: true)]
[ViewVariables(VVAccess.ReadWrite)]
public DamageSpecifier DamageRecovery = default!;
- [DataField("gaspPopupCooldown")]
- public TimeSpan GaspPopupCooldown { get; private set; } = TimeSpan.FromSeconds(8);
+ [DataField]
+ public TimeSpan GaspPopupCooldown = TimeSpan.FromSeconds(8);
[ViewVariables]
public TimeSpan LastGaspPopupTime;
@@ -55,11 +69,6 @@ namespace Content.Server.Body.Components
[ViewVariables]
public RespiratorStatus Status = RespiratorStatus.Inhaling;
-
- [DataField("cycleDelay")]
- public float CycleDelay = 2.0f;
-
- public float AccumulatedFrametime;
}
}
diff --git a/Content.Server/Body/Components/StomachComponent.cs b/Content.Server/Body/Components/StomachComponent.cs
index fe93468f74..d541ca4d7c 100644
--- a/Content.Server/Body/Components/StomachComponent.cs
+++ b/Content.Server/Body/Components/StomachComponent.cs
@@ -1,21 +1,26 @@
-using Content.Server.Body.Systems;
+using Content.Server.Body.Systems;
using Content.Server.Nutrition.EntitySystems;
using Content.Shared.Chemistry.Components;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.Whitelist;
+using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
namespace Content.Server.Body.Components
{
[RegisterComponent, Access(typeof(StomachSystem), typeof(FoodSystem))]
public sealed partial class StomachComponent : Component
{
- public float AccumulatedFrameTime;
+ ///
+ /// The next time that the stomach will try to digest its contents.
+ ///
+ [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))]
+ public TimeSpan NextUpdate;
///
- /// How fast should this component update, in seconds?
+ /// The interval at which this stomach digests its contents.
///
[DataField]
- public float UpdateInterval = 1.0f;
+ public TimeSpan UpdateInterval = TimeSpan.FromSeconds(1);
///
/// The solution inside of this stomach this transfers reagents to the body.
@@ -30,11 +35,11 @@ namespace Content.Server.Body.Components
public string BodySolutionName = BloodstreamComponent.DefaultChemicalsSolutionName;
///
- /// Time in seconds between reagents being ingested and them being
+ /// Time between reagents being ingested and them being
/// transferred to
///
[DataField]
- public float DigestionDelay = 20;
+ public TimeSpan DigestionDelay = TimeSpan.FromSeconds(20);
///
/// A whitelist for what special-digestible-required foods this stomach is capable of eating.
@@ -54,15 +59,15 @@ namespace Content.Server.Body.Components
public sealed class ReagentDelta
{
public readonly ReagentQuantity ReagentQuantity;
- public float Lifetime { get; private set; }
+ public TimeSpan Lifetime { get; private set; }
public ReagentDelta(ReagentQuantity reagentQuantity)
{
ReagentQuantity = reagentQuantity;
- Lifetime = 0.0f;
+ Lifetime = TimeSpan.Zero;
}
- public void Increment(float delta) => Lifetime += delta;
+ public void Increment(TimeSpan delta) => Lifetime += delta;
}
}
}
diff --git a/Content.Server/Body/Components/ThermalRegulatorComponent.cs b/Content.Server/Body/Components/ThermalRegulatorComponent.cs
index 4acdccf1ba..19b76189e0 100644
--- a/Content.Server/Body/Components/ThermalRegulatorComponent.cs
+++ b/Content.Server/Body/Components/ThermalRegulatorComponent.cs
@@ -1,4 +1,5 @@
using Content.Server.Body.Systems;
+using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
namespace Content.Server.Body.Components;
@@ -6,48 +7,58 @@ namespace Content.Server.Body.Components;
[Access(typeof(ThermalRegulatorSystem))]
public sealed partial class ThermalRegulatorComponent : Component
{
+ ///
+ /// The next time that the body will regulate its heat.
+ ///
+ [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))]
+ public TimeSpan NextUpdate;
+
+ ///
+ /// The interval at which thermal regulation is processed.
+ ///
+ [DataField]
+ public TimeSpan UpdateInterval = TimeSpan.FromSeconds(1);
+
///
/// Heat generated due to metabolism. It's generated via metabolism
///
- [DataField("metabolismHeat")]
- public float MetabolismHeat { get; private set; }
+ [DataField]
+ public float MetabolismHeat;
///
/// Heat output via radiation.
///
- [DataField("radiatedHeat")]
- public float RadiatedHeat { get; private set; }
+ [DataField]
+ public float RadiatedHeat;
///
/// Maximum heat regulated via sweat
///
- [DataField("sweatHeatRegulation")]
- public float SweatHeatRegulation { get; private set; }
+ [DataField]
+ public float SweatHeatRegulation;
///
/// Maximum heat regulated via shivering
///
- [DataField("shiveringHeatRegulation")]
- public float ShiveringHeatRegulation { get; private set; }
+ [DataField]
+ public float ShiveringHeatRegulation;
///
/// Amount of heat regulation that represents thermal regulation processes not
/// explicitly coded.
///
- [DataField("implicitHeatRegulation")]
- public float ImplicitHeatRegulation { get; private set; }
+ [DataField]
+ public float ImplicitHeatRegulation;
///
/// Normal body temperature
///
- [DataField("normalBodyTemperature")]
- public float NormalBodyTemperature { get; private set; }
+ [DataField]
+ public float NormalBodyTemperature;
///
/// Deviation from normal temperature for body to start thermal regulation
///
- [DataField("thermalRegulationTemperatureThreshold")]
- public float ThermalRegulationTemperatureThreshold { get; private set; }
-
- public float AccumulatedFrametime;
+ [DataField]
+ public float ThermalRegulationTemperatureThreshold;
}
diff --git a/Content.Server/Body/Systems/BloodstreamSystem.cs b/Content.Server/Body/Systems/BloodstreamSystem.cs
index f6fdcfedff..9e29fdf756 100644
--- a/Content.Server/Body/Systems/BloodstreamSystem.cs
+++ b/Content.Server/Body/Systems/BloodstreamSystem.cs
@@ -13,7 +13,6 @@ using Content.Shared.Damage;
using Content.Shared.Damage.Prototypes;
using Content.Shared.Drunk;
using Content.Shared.FixedPoint;
-using Content.Shared.IdentityManagement;
using Content.Shared.Mobs.Systems;
using Content.Shared.Popups;
using Content.Shared.Rejuvenate;
@@ -21,11 +20,13 @@ using Content.Shared.Speech.EntitySystems;
using Robust.Server.Audio;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
+using Robust.Shared.Timing;
namespace Content.Server.Body.Systems;
public sealed class BloodstreamSystem : EntitySystem
{
+ [Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IRobustRandom _robustRandom = default!;
[Dependency] private readonly AudioSystem _audio = default!;
@@ -44,6 +45,8 @@ public sealed class BloodstreamSystem : EntitySystem
base.Initialize();
SubscribeLocalEvent(OnComponentInit);
+ SubscribeLocalEvent(OnMapInit);
+ SubscribeLocalEvent(OnUnpaused);
SubscribeLocalEvent(OnDamageChanged);
SubscribeLocalEvent(OnHealthBeingExamined);
SubscribeLocalEvent(OnBeingGibbed);
@@ -53,6 +56,16 @@ public sealed class BloodstreamSystem : EntitySystem
SubscribeLocalEvent(OnRejuvenate);
}
+ private void OnMapInit(Entity ent, ref MapInitEvent args)
+ {
+ ent.Comp.NextUpdate = _gameTiming.CurTime + ent.Comp.UpdateInterval;
+ }
+
+ private void OnUnpaused(Entity ent, ref EntityUnpausedEvent args)
+ {
+ ent.Comp.NextUpdate += args.PausedTime;
+ }
+
private void OnReactionAttempt(Entity entity, ref ReactionAttemptEvent args)
{
if (args.Cancelled)
@@ -83,7 +96,9 @@ public sealed class BloodstreamSystem : EntitySystem
if (args.Name != entity.Comp.BloodSolutionName
&& args.Name != entity.Comp.ChemicalSolutionName
&& args.Name != entity.Comp.BloodTemporarySolutionName)
+ {
return;
+ }
OnReactionAttempt(entity, ref args.Event);
}
@@ -95,12 +110,10 @@ public sealed class BloodstreamSystem : EntitySystem
var query = EntityQueryEnumerator();
while (query.MoveNext(out var uid, out var bloodstream))
{
- bloodstream.AccumulatedFrametime += frameTime;
-
- if (bloodstream.AccumulatedFrametime < bloodstream.UpdateInterval)
+ if (_gameTiming.CurTime < bloodstream.NextUpdate)
continue;
- bloodstream.AccumulatedFrametime -= bloodstream.UpdateInterval;
+ bloodstream.NextUpdate += bloodstream.UpdateInterval;
if (!_solutionContainerSystem.ResolveSolution(uid, bloodstream.BloodSolutionName, ref bloodstream.BloodSolution, out var bloodSolution))
continue;
@@ -128,13 +141,17 @@ public sealed class BloodstreamSystem : EntitySystem
// bloodloss damage is based on the base value, and modified by how low your blood level is.
var amt = bloodstream.BloodlossDamage / (0.1f + bloodPercentage);
- _damageableSystem.TryChangeDamage(uid, amt, false, false);
+ _damageableSystem.TryChangeDamage(uid, amt,
+ ignoreResistances: false, interruptsDoAfters: false);
// Apply dizziness as a symptom of bloodloss.
// The effect is applied in a way that it will never be cleared without being healthy.
// Multiplying by 2 is arbitrary but works for this case, it just prevents the time from running out
- _drunkSystem.TryApplyDrunkenness(uid, bloodstream.UpdateInterval*2, false);
- _stutteringSystem.DoStutter(uid, TimeSpan.FromSeconds(bloodstream.UpdateInterval*2), false);
+ _drunkSystem.TryApplyDrunkenness(
+ uid,
+ (float) bloodstream.UpdateInterval.TotalSeconds * 2,
+ applySlur: false);
+ _stutteringSystem.DoStutter(uid, bloodstream.UpdateInterval * 2, refresh: false);
// storing the drunk and stutter time so we can remove it independently from other effects additions
bloodstream.StatusTime += bloodstream.UpdateInterval * 2;
@@ -142,13 +159,16 @@ public sealed class BloodstreamSystem : EntitySystem
else if (!_mobStateSystem.IsDead(uid))
{
// If they're healthy, we'll try and heal some bloodloss instead.
- _damageableSystem.TryChangeDamage(uid, bloodstream.BloodlossHealDamage * bloodPercentage, true, false);
+ _damageableSystem.TryChangeDamage(
+ uid,
+ bloodstream.BloodlossHealDamage * bloodPercentage,
+ ignoreResistances: true, interruptsDoAfters: false);
// Remove the drunk effect when healthy. Should only remove the amount of drunk and stutter added by low blood level
- _drunkSystem.TryRemoveDrunkenessTime(uid, bloodstream.StatusTime);
- _stutteringSystem.DoRemoveStutterTime(uid, bloodstream.StatusTime);
+ _drunkSystem.TryRemoveDrunkenessTime(uid, bloodstream.StatusTime.TotalSeconds);
+ _stutteringSystem.DoRemoveStutterTime(uid, bloodstream.StatusTime.TotalSeconds);
// Reset the drunk and stutter time to zero
- bloodstream.StatusTime = 0;
+ bloodstream.StatusTime = TimeSpan.Zero;
}
}
}
@@ -167,17 +187,15 @@ public sealed class BloodstreamSystem : EntitySystem
bloodSolution.AddReagent(entity.Comp.BloodReagent, entity.Comp.BloodMaxVolume - bloodSolution.Volume);
}
- private void OnDamageChanged(EntityUid uid, BloodstreamComponent component, DamageChangedEvent args)
+ private void OnDamageChanged(Entity ent, ref DamageChangedEvent args)
{
- if (args.DamageDelta is null)
- return;
-
- // definitely don't make them bleed if they got healed
- if (!args.DamageIncreased)
+ if (args.DamageDelta is null || !args.DamageIncreased)
+ {
return;
+ }
// TODO probably cache this or something. humans get hurt a lot
- if (!_prototypeManager.TryIndex(component.DamageBleedModifiers, out var modifiers))
+ if (!_prototypeManager.TryIndex(ent.Comp.DamageBleedModifiers, out var modifiers))
return;
var bloodloss = DamageSpecifier.ApplyModifierSet(args.DamageDelta, modifiers);
@@ -186,10 +204,10 @@ public sealed class BloodstreamSystem : EntitySystem
return;
// Does the calculation of how much bleed rate should be added/removed, then applies it
- var oldBleedAmount = component.BleedAmount;
+ var oldBleedAmount = ent.Comp.BleedAmount;
var total = bloodloss.GetTotal();
var totalFloat = total.Float();
- TryModifyBleedAmount(uid, totalFloat, component);
+ TryModifyBleedAmount(ent, totalFloat, ent);
///
/// Critical hit. Causes target to lose blood, using the bleed rate modifier of the weapon, currently divided by 5
@@ -199,8 +217,8 @@ public sealed class BloodstreamSystem : EntitySystem
var prob = Math.Clamp(totalFloat / 25, 0, 1);
if (totalFloat > 0 && _robustRandom.Prob(prob))
{
- TryModifyBloodLevel(uid, (-total) / 5, component);
- _audio.PlayPvs(component.InstantBloodSound, uid);
+ TryModifyBloodLevel(ent, (-total) / 5, ent);
+ _audio.PlayPvs(ent.Comp.InstantBloodSound, ent);
}
// Heat damage will cauterize, causing the bleed rate to be reduced.
@@ -210,53 +228,52 @@ public sealed class BloodstreamSystem : EntitySystem
// because it's burn damage that cauterized their wounds.
// We'll play a special sound and popup for feedback.
- _audio.PlayPvs(component.BloodHealedSound, uid);
- _popupSystem.PopupEntity(Loc.GetString("bloodstream-component-wounds-cauterized"), uid,
- uid, PopupType.Medium);
+ _audio.PlayPvs(ent.Comp.BloodHealedSound, ent);
+ _popupSystem.PopupEntity(Loc.GetString("bloodstream-component-wounds-cauterized"), ent,
+ ent, PopupType.Medium);
}
}
///
/// Shows text on health examine, based on bleed rate and blood level.
///
- private void OnHealthBeingExamined(EntityUid uid, BloodstreamComponent component, HealthBeingExaminedEvent args)
+ private void OnHealthBeingExamined(Entity ent, ref HealthBeingExaminedEvent args)
{
// Shows profusely bleeding at half the max bleed rate.
- if (component.BleedAmount > component.MaxBleedAmount / 2)
+ if (ent.Comp.BleedAmount > ent.Comp.MaxBleedAmount / 2)
{
args.Message.PushNewline();
- args.Message.AddMarkup(Loc.GetString("bloodstream-component-profusely-bleeding", ("target", Identity.Entity(uid, EntityManager))));
+ args.Message.AddMarkup(Loc.GetString("bloodstream-component-profusely-bleeding", ("target", ent.Owner)));
}
// Shows bleeding message when bleeding, but less than profusely.
- else if (component.BleedAmount > 0)
+ else if (ent.Comp.BleedAmount > 0)
{
args.Message.PushNewline();
- args.Message.AddMarkup(Loc.GetString("bloodstream-component-bleeding", ("target", Identity.Entity(uid, EntityManager))));
+ args.Message.AddMarkup(Loc.GetString("bloodstream-component-bleeding", ("target", ent.Owner)));
}
// If the mob's blood level is below the damage threshhold, the pale message is added.
- if (GetBloodLevelPercentage(uid, component) < component.BloodlossThreshold)
+ if (GetBloodLevelPercentage(ent, ent) < ent.Comp.BloodlossThreshold)
{
args.Message.PushNewline();
- args.Message.AddMarkup(Loc.GetString("bloodstream-component-looks-pale", ("target", Identity.Entity(uid, EntityManager))));
+ args.Message.AddMarkup(Loc.GetString("bloodstream-component-looks-pale", ("target", ent.Owner)));
}
}
- private void OnBeingGibbed(EntityUid uid, BloodstreamComponent component, BeingGibbedEvent args)
+ private void OnBeingGibbed(Entity ent, ref BeingGibbedEvent args)
{
- SpillAllSolutions(uid, component);
+ SpillAllSolutions(ent, ent);
}
- private void OnApplyMetabolicMultiplier(EntityUid uid, BloodstreamComponent component, ApplyMetabolicMultiplierEvent args)
+ private void OnApplyMetabolicMultiplier(
+ Entity ent,
+ ref ApplyMetabolicMultiplierEvent args)
{
if (args.Apply)
{
- component.UpdateInterval *= args.Multiplier;
+ ent.Comp.UpdateInterval *= args.Multiplier;
return;
}
- component.UpdateInterval /= args.Multiplier;
- // Reset the accumulator properly
- if (component.AccumulatedFrametime >= component.UpdateInterval)
- component.AccumulatedFrametime = component.UpdateInterval;
+ ent.Comp.UpdateInterval /= args.Multiplier;
}
private void OnRejuvenate(Entity entity, ref RejuvenateEvent args)
@@ -275,21 +292,15 @@ public sealed class BloodstreamSystem : EntitySystem
///
public bool TryAddToChemicals(EntityUid uid, Solution solution, BloodstreamComponent? component = null)
{
- if (!Resolve(uid, ref component, false))
- return false;
-
- if (!_solutionContainerSystem.ResolveSolution(uid, component.ChemicalSolutionName, ref component.ChemicalSolution))
- return false;
-
- return _solutionContainerSystem.TryAddSolution(component.ChemicalSolution.Value, solution);
+ return Resolve(uid, ref component, logMissing: false)
+ && _solutionContainerSystem.ResolveSolution(uid, component.ChemicalSolutionName, ref component.ChemicalSolution)
+ && _solutionContainerSystem.TryAddSolution(component.ChemicalSolution.Value, solution);
}
public bool FlushChemicals(EntityUid uid, string excludedReagentID, FixedPoint2 quantity, BloodstreamComponent? component = null)
{
- if (!Resolve(uid, ref component, false))
- return false;
-
- if (!_solutionContainerSystem.ResolveSolution(uid, component.ChemicalSolutionName, ref component.ChemicalSolution, out var chemSolution))
+ if (!Resolve(uid, ref component, logMissing: false)
+ || !_solutionContainerSystem.ResolveSolution(uid, component.ChemicalSolutionName, ref component.ChemicalSolution, out var chemSolution))
return false;
for (var i = chemSolution.Contents.Count - 1; i >= 0; i--)
@@ -306,11 +317,11 @@ public sealed class BloodstreamSystem : EntitySystem
public float GetBloodLevelPercentage(EntityUid uid, BloodstreamComponent? component = null)
{
- if (!Resolve(uid, ref component))
- return 0.0f;
-
- if (!_solutionContainerSystem.ResolveSolution(uid, component.BloodSolutionName, ref component.BloodSolution, out var bloodSolution))
+ if (!Resolve(uid, ref component)
+ || !_solutionContainerSystem.ResolveSolution(uid, component.BloodSolutionName, ref component.BloodSolution, out var bloodSolution))
+ {
return 0.0f;
+ }
return bloodSolution.FillFraction;
}
@@ -328,11 +339,11 @@ public sealed class BloodstreamSystem : EntitySystem
///
public bool TryModifyBloodLevel(EntityUid uid, FixedPoint2 amount, BloodstreamComponent? component = null)
{
- if (!Resolve(uid, ref component, false))
- return false;
-
- if (!_solutionContainerSystem.ResolveSolution(uid, component.BloodSolutionName, ref component.BloodSolution))
+ if (!Resolve(uid, ref component, logMissing: false)
+ || !_solutionContainerSystem.ResolveSolution(uid, component.BloodSolutionName, ref component.BloodSolution))
+ {
return false;
+ }
if (amount >= 0)
return _solutionContainerSystem.TryAddReagent(component.BloodSolution.Value, component.BloodReagent, amount, out _);
@@ -356,9 +367,9 @@ public sealed class BloodstreamSystem : EntitySystem
tempSolution.AddSolution(temp, _prototypeManager);
}
- if (_puddleSystem.TrySpillAt(uid, tempSolution, out var puddleUid, false))
+ if (_puddleSystem.TrySpillAt(uid, tempSolution, out var puddleUid, sound: false))
{
- _forensicsSystem.TransferDna(puddleUid, uid, false);
+ _forensicsSystem.TransferDna(puddleUid, uid, canDnaBeCleaned: false);
}
tempSolution.RemoveAllSolution();
@@ -374,7 +385,7 @@ public sealed class BloodstreamSystem : EntitySystem
///
public bool TryModifyBleedAmount(EntityUid uid, float amount, BloodstreamComponent? component = null)
{
- if (!Resolve(uid, ref component, false))
+ if (!Resolve(uid, ref component, logMissing: false))
return false;
component.BleedAmount += amount;
@@ -424,7 +435,7 @@ public sealed class BloodstreamSystem : EntitySystem
if (_puddleSystem.TrySpillAt(uid, tempSol, out var puddleUid))
{
- _forensicsSystem.TransferDna(puddleUid, uid, false);
+ _forensicsSystem.TransferDna(puddleUid, uid, canDnaBeCleaned: false);
}
}
@@ -433,11 +444,11 @@ public sealed class BloodstreamSystem : EntitySystem
///
public void ChangeBloodReagent(EntityUid uid, string reagent, BloodstreamComponent? component = null)
{
- if (!Resolve(uid, ref component, false))
- return;
-
- if (reagent == component.BloodReagent)
+ if (!Resolve(uid, ref component, logMissing: false)
+ || reagent == component.BloodReagent)
+ {
return;
+ }
if (!_solutionContainerSystem.ResolveSolution(uid, component.BloodSolutionName, ref component.BloodSolution, out var bloodSolution))
{
diff --git a/Content.Server/Body/Systems/BodySystem.cs b/Content.Server/Body/Systems/BodySystem.cs
index 18119909ab..e10158cf35 100644
--- a/Content.Server/Body/Systems/BodySystem.cs
+++ b/Content.Server/Body/Systems/BodySystem.cs
@@ -1,23 +1,17 @@
using Content.Server.Body.Components;
using Content.Server.GameTicking;
using Content.Server.Humanoid;
-using Content.Server.Kitchen.Components;
using Content.Shared.Body.Components;
using Content.Shared.Body.Part;
using Content.Shared.Body.Systems;
using Content.Shared.Humanoid;
-using Content.Shared.Kitchen.Components;
using Content.Shared.Mind;
using Content.Shared.Mobs.Systems;
using Content.Shared.Movement.Events;
+using Content.Shared.Movement.Systems;
using Robust.Shared.Audio;
-using Robust.Shared.Player;
-using Robust.Shared.Random;
using Robust.Shared.Timing;
using System.Numerics;
-using Content.Shared.Gibbing.Components;
-using Content.Shared.Movement.Systems;
-using Robust.Shared.Audio.Systems;
namespace Content.Server.Body.Systems;
@@ -27,10 +21,7 @@ public sealed class BodySystem : SharedBodySystem
[Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly HumanoidAppearanceSystem _humanoidSystem = default!;
[Dependency] private readonly MobStateSystem _mobState = default!;
- [Dependency] private readonly SharedAudioSystem _audio = default!;
- [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
[Dependency] private readonly SharedMindSystem _mindSystem = default!;
- [Dependency] private readonly IRobustRandom _random = default!;
public override void Initialize()
{
@@ -40,7 +31,7 @@ public sealed class BodySystem : SharedBodySystem
SubscribeLocalEvent(OnApplyMetabolicMultiplier);
}
- private void OnRelayMoveInput(EntityUid uid, BodyComponent component, ref MoveInputEvent args)
+ private void OnRelayMoveInput(Entity ent, ref MoveInputEvent args)
{
// If they haven't actually moved then ignore it.
if ((args.Component.HeldMoveButtons &
@@ -49,68 +40,67 @@ public sealed class BodySystem : SharedBodySystem
return;
}
- if (_mobState.IsDead(uid) && _mindSystem.TryGetMind(uid, out var mindId, out var mind))
+ if (_mobState.IsDead(ent) && _mindSystem.TryGetMind(ent, out var mindId, out var mind))
{
mind.TimeOfDeath ??= _gameTiming.RealTime;
- _ticker.OnGhostAttempt(mindId, true, mind: mind);
+ _ticker.OnGhostAttempt(mindId, canReturnGlobal: true, mind: mind);
}
}
- private void OnApplyMetabolicMultiplier(EntityUid uid, BodyComponent component,
- ApplyMetabolicMultiplierEvent args)
+ private void OnApplyMetabolicMultiplier(
+ Entity ent,
+ ref ApplyMetabolicMultiplierEvent args)
{
- foreach (var organ in GetBodyOrgans(uid, component))
+ foreach (var organ in GetBodyOrgans(ent, ent))
{
- RaiseLocalEvent(organ.Id, args);
+ RaiseLocalEvent(organ.Id, ref args);
}
}
protected override void AddPart(
- EntityUid bodyUid,
- EntityUid partUid,
- string slotId,
- BodyPartComponent component,
- BodyComponent? bodyComp = null)
+ Entity bodyEnt,
+ Entity partEnt,
+ string slotId)
{
// TODO: Predict this probably.
- base.AddPart(bodyUid, partUid, slotId, component, bodyComp);
+ base.AddPart(bodyEnt, partEnt, slotId);
- if (TryComp(bodyUid, out var humanoid))
+ if (TryComp(bodyEnt, out var humanoid))
{
- var layer = component.ToHumanoidLayers();
+ var layer = partEnt.Comp.ToHumanoidLayers();
if (layer != null)
{
var layers = HumanoidVisualLayersExtension.Sublayers(layer.Value);
- _humanoidSystem.SetLayersVisibility(bodyUid, layers, true, true, humanoid);
+ _humanoidSystem.SetLayersVisibility(
+ bodyEnt, layers, visible: true, permanent: true, humanoid);
}
}
}
protected override void RemovePart(
- EntityUid bodyUid,
- EntityUid partUid,
- string slotId,
- BodyPartComponent component,
- BodyComponent? bodyComp = null)
+ Entity bodyEnt,
+ Entity partEnt,
+ string slotId)
{
- base.RemovePart(bodyUid, partUid, slotId, component, bodyComp);
+ base.RemovePart(bodyEnt, partEnt, slotId);
- if (!TryComp(bodyUid, out var humanoid))
+ if (!TryComp(bodyEnt, out var humanoid))
return;
- var layer = component.ToHumanoidLayers();
+ var layer = partEnt.Comp.ToHumanoidLayers();
- if (layer == null)
+ if (layer is null)
return;
var layers = HumanoidVisualLayersExtension.Sublayers(layer.Value);
- _humanoidSystem.SetLayersVisibility(bodyUid, layers, false, true, humanoid);
+ _humanoidSystem.SetLayersVisibility(
+ bodyEnt, layers, visible: false, permanent: true, humanoid);
}
public override HashSet GibBody(
EntityUid bodyId,
bool gibOrgans = false,
- BodyComponent? body = null ,
+ BodyComponent? body = null,
bool launchGibs = true,
Vector2? splatDirection = null,
float splatModifier = 1,
@@ -118,19 +108,23 @@ public sealed class BodySystem : SharedBodySystem
SoundSpecifier? gibSoundOverride = null
)
{
- if (!Resolve(bodyId, ref body, false))
- return new HashSet();
-
- if (TerminatingOrDeleted(bodyId) || EntityManager.IsQueuedForDeletion(bodyId))
+ if (!Resolve(bodyId, ref body, logMissing: false)
+ || TerminatingOrDeleted(bodyId)
+ || EntityManager.IsQueuedForDeletion(bodyId))
+ {
return new HashSet();
+ }
var xform = Transform(bodyId);
- if (xform.MapUid == null)
+ if (xform.MapUid is null)
return new HashSet();
var gibs = base.GibBody(bodyId, gibOrgans, body, launchGibs: launchGibs,
splatDirection: splatDirection, splatModifier: splatModifier, splatCone:splatCone);
- RaiseLocalEvent(bodyId, new BeingGibbedEvent(gibs));
+
+ var ev = new BeingGibbedEvent(gibs);
+ RaiseLocalEvent(bodyId, ref ev);
+
QueueDel(bodyId);
return gibs;
diff --git a/Content.Server/Body/Systems/BrainSystem.cs b/Content.Server/Body/Systems/BrainSystem.cs
index abb5497120..86d2cb61ff 100644
--- a/Content.Server/Body/Systems/BrainSystem.cs
+++ b/Content.Server/Body/Systems/BrainSystem.cs
@@ -16,8 +16,8 @@ namespace Content.Server.Body.Systems
{
base.Initialize();
- SubscribeLocalEvent((uid, _, args) => HandleMind(args.Body, uid));
- SubscribeLocalEvent((uid, _, args) => HandleMind(uid, args.OldBody));
+ SubscribeLocalEvent((uid, _, args) => HandleMind(args.Body, uid));
+ SubscribeLocalEvent((uid, _, args) => HandleMind(uid, args.OldBody));
SubscribeLocalEvent(OnPointAttempt);
}
@@ -39,7 +39,7 @@ namespace Content.Server.Body.Systems
_mindSystem.TransferTo(mindId, newEntity, mind: mind);
}
- private void OnPointAttempt(EntityUid uid, BrainComponent component, PointAttemptEvent args)
+ private void OnPointAttempt(Entity ent, ref PointAttemptEvent args)
{
args.Cancel();
}
diff --git a/Content.Server/Body/Systems/InternalsSystem.cs b/Content.Server/Body/Systems/InternalsSystem.cs
index 004dae99b9..972967fb15 100644
--- a/Content.Server/Body/Systems/InternalsSystem.cs
+++ b/Content.Server/Body/Systems/InternalsSystem.cs
@@ -1,7 +1,6 @@
using Content.Server.Atmos.Components;
using Content.Server.Atmos.EntitySystems;
using Content.Server.Body.Components;
-using Content.Server.Hands.Systems;
using Content.Server.Popups;
using Content.Shared.Alert;
using Content.Shared.Atmos;
@@ -11,19 +10,16 @@ using Content.Shared.Internals;
using Content.Shared.Inventory;
using Content.Shared.Verbs;
using Robust.Shared.Containers;
-using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
namespace Content.Server.Body.Systems;
public sealed class InternalsSystem : EntitySystem
{
- [Dependency] private readonly IPrototypeManager _protoManager = default!;
[Dependency] private readonly AlertsSystem _alerts = default!;
[Dependency] private readonly AtmosphereSystem _atmos = default!;
[Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
[Dependency] private readonly GasTankSystem _gasTank = default!;
- [Dependency] private readonly HandsSystem _hands = default!;
[Dependency] private readonly InventorySystem _inventory = default!;
[Dependency] private readonly PopupSystem _popupSystem = default!;
@@ -40,28 +36,36 @@ public sealed class InternalsSystem : EntitySystem
SubscribeLocalEvent(OnDoAfter);
}
- private void OnGetInteractionVerbs(EntityUid uid, InternalsComponent component, GetVerbsEvent args)
+ private void OnGetInteractionVerbs(
+ Entity ent,
+ ref GetVerbsEvent args)
{
- if (!args.CanAccess || !args.CanInteract || args.Hands == null)
+ if (!args.CanAccess || !args.CanInteract || args.Hands is null)
return;
+ var user = args.User;
+
InteractionVerb verb = new()
{
Act = () =>
{
- ToggleInternals(uid, args.User, false, component);
+ ToggleInternals(ent, user, force: false, ent);
},
Message = Loc.GetString("action-description-internals-toggle"),
- Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/VerbIcons/dot.svg.192dpi.png")),
+ Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/dot.svg.192dpi.png")),
Text = Loc.GetString("action-name-internals-toggle"),
};
args.Verbs.Add(verb);
}
- public void ToggleInternals(EntityUid uid, EntityUid user, bool force, InternalsComponent? internals = null)
+ public void ToggleInternals(
+ EntityUid uid,
+ EntityUid user,
+ bool force,
+ InternalsComponent? internals = null)
{
- if (!Resolve(uid, ref internals, false))
+ if (!Resolve(uid, ref internals, logMissing: false))
return;
// Toggle off if they're on
@@ -73,12 +77,12 @@ public sealed class InternalsSystem : EntitySystem
return;
}
- StartToggleInternalsDoAfter(user, uid, internals);
+ StartToggleInternalsDoAfter(user, (uid, internals));
return;
}
// If they're not on then check if we have a mask to use
- if (internals.BreathToolEntity == null)
+ if (internals.BreathToolEntity is null)
{
_popupSystem.PopupEntity(Loc.GetString("internals-no-breath-tool"), uid, user);
return;
@@ -86,7 +90,7 @@ public sealed class InternalsSystem : EntitySystem
var tank = FindBestGasTank(uid);
- if (tank == null)
+ if (tank is null)
{
_popupSystem.PopupEntity(Loc.GetString("internals-no-tank"), uid, user);
return;
@@ -94,20 +98,20 @@ public sealed class InternalsSystem : EntitySystem
if (!force)
{
- StartToggleInternalsDoAfter(user, uid, internals);
+ StartToggleInternalsDoAfter(user, (uid, internals));
return;
}
_gasTank.ConnectToInternals(tank.Value);
}
- private void StartToggleInternalsDoAfter(EntityUid user, EntityUid target, InternalsComponent internals)
+ private void StartToggleInternalsDoAfter(EntityUid user, Entity targetEnt)
{
// Is the target not you? If yes, use a do-after to give them time to respond.
- var isUser = user == target;
- var delay = !isUser ? internals.Delay : 0f;
+ var isUser = user == targetEnt.Owner;
+ var delay = !isUser ? targetEnt.Comp.Delay : TimeSpan.Zero;
- _doAfter.TryStartDoAfter(new DoAfterArgs(EntityManager, user, delay, new InternalsDoAfterEvent(), target, target: target)
+ _doAfter.TryStartDoAfter(new DoAfterArgs(EntityManager, user, delay, new InternalsDoAfterEvent(), targetEnt, target: targetEnt)
{
BreakOnDamage = true,
BreakOnMove = true,
@@ -115,66 +119,64 @@ public sealed class InternalsSystem : EntitySystem
});
}
- private void OnDoAfter(EntityUid uid, InternalsComponent component, InternalsDoAfterEvent args)
+ private void OnDoAfter(Entity ent, ref InternalsDoAfterEvent args)
{
if (args.Cancelled || args.Handled)
return;
- ToggleInternals(uid, args.User, true, component);
+ ToggleInternals(ent, args.User, force: true, ent);
args.Handled = true;
}
- private void OnInternalsStartup(EntityUid uid, InternalsComponent component, ComponentStartup args)
+ private void OnInternalsStartup(Entity ent, ref ComponentStartup args)
{
- _alerts.ShowAlert(uid, AlertType.Internals, GetSeverity(component));
+ _alerts.ShowAlert(ent, AlertType.Internals, GetSeverity(ent));
}
- private void OnInternalsShutdown(EntityUid uid, InternalsComponent component, ComponentShutdown args)
+ private void OnInternalsShutdown(Entity ent, ref ComponentShutdown args)
{
- _alerts.ClearAlert(uid, AlertType.Internals);
+ _alerts.ClearAlert(ent, AlertType.Internals);
}
- private void OnInhaleLocation(EntityUid uid, InternalsComponent component, InhaleLocationEvent args)
+ private void OnInhaleLocation(Entity ent, ref InhaleLocationEvent args)
{
- if (AreInternalsWorking(component))
+ if (AreInternalsWorking(ent))
{
- var gasTank = Comp(component.GasTankEntity!.Value);
- args.Gas = _gasTank.RemoveAirVolume((component.GasTankEntity.Value, gasTank), Atmospherics.BreathVolume);
+ var gasTank = Comp(ent.Comp.GasTankEntity!.Value);
+ args.Gas = _gasTank.RemoveAirVolume((ent.Comp.GasTankEntity.Value, gasTank), Atmospherics.BreathVolume);
// TODO: Should listen to gas tank updates instead I guess?
- _alerts.ShowAlert(uid, AlertType.Internals, GetSeverity(component));
+ _alerts.ShowAlert(ent, AlertType.Internals, GetSeverity(ent));
}
}
public void DisconnectBreathTool(Entity ent)
{
- var (owner, component) = ent;
- var old = component.BreathToolEntity;
- component.BreathToolEntity = null;
+ var old = ent.Comp.BreathToolEntity;
+ ent.Comp.BreathToolEntity = null;
- if (TryComp(old, out BreathToolComponent? breathTool) )
+ if (TryComp(old, out BreathToolComponent? breathTool))
{
_atmos.DisconnectInternals(breathTool);
DisconnectTank(ent);
}
- _alerts.ShowAlert(owner, AlertType.Internals, GetSeverity(component));
+ _alerts.ShowAlert(ent, AlertType.Internals, GetSeverity(ent));
}
public void ConnectBreathTool(Entity ent, EntityUid toolEntity)
{
- var (owner, component) = ent;
- if (TryComp(component.BreathToolEntity, out BreathToolComponent? tool))
+ if (TryComp(ent.Comp.BreathToolEntity, out BreathToolComponent? tool))
{
_atmos.DisconnectInternals(tool);
}
- component.BreathToolEntity = toolEntity;
- _alerts.ShowAlert(owner, AlertType.Internals, GetSeverity(component));
+ ent.Comp.BreathToolEntity = toolEntity;
+ _alerts.ShowAlert(ent, AlertType.Internals, GetSeverity(ent));
}
public void DisconnectTank(InternalsComponent? component)
{
- if (component == null)
+ if (component is null)
return;
if (TryComp(component.GasTankEntity, out GasTankComponent? tank))
@@ -186,46 +188,47 @@ public sealed class InternalsSystem : EntitySystem
public bool TryConnectTank(Entity ent, EntityUid tankEntity)
{
- var component = ent.Comp;
- if (component.BreathToolEntity == null)
+ if (ent.Comp.BreathToolEntity is null)
return false;
- if (TryComp(component.GasTankEntity, out GasTankComponent? tank))
- _gasTank.DisconnectFromInternals((component.GasTankEntity.Value, tank));
+ if (TryComp(ent.Comp.GasTankEntity, out GasTankComponent? tank))
+ _gasTank.DisconnectFromInternals((ent.Comp.GasTankEntity.Value, tank));
- component.GasTankEntity = tankEntity;
- _alerts.ShowAlert(ent, AlertType.Internals, GetSeverity(component));
+ ent.Comp.GasTankEntity = tankEntity;
+ _alerts.ShowAlert(ent, AlertType.Internals, GetSeverity(ent));
return true;
}
public bool AreInternalsWorking(EntityUid uid, InternalsComponent? component = null)
{
- if (!Resolve(uid, ref component, false))
- return false;
-
- return AreInternalsWorking(component);
+ return Resolve(uid, ref component, logMissing: false)
+ && AreInternalsWorking(component);
}
public bool AreInternalsWorking(InternalsComponent component)
{
- return TryComp(component.BreathToolEntity, out BreathToolComponent? breathTool) &&
- breathTool.IsFunctional &&
- TryComp(component.GasTankEntity, out GasTankComponent? _);
+ return TryComp(component.BreathToolEntity, out BreathToolComponent? breathTool)
+ && breathTool.IsFunctional
+ && HasComp(component.GasTankEntity);
}
private short GetSeverity(InternalsComponent component)
{
- if (component.BreathToolEntity == null || !AreInternalsWorking(component))
+ if (component.BreathToolEntity is null || !AreInternalsWorking(component))
return 2;
// If pressure in the tank is below low pressure threshhold, flash warning on internals UI
- if (TryComp(component.GasTankEntity, out var gasTank) && gasTank.IsLowPressure)
+ if (TryComp(component.GasTankEntity, out var gasTank)
+ && gasTank.IsLowPressure)
+ {
return 0;
+ }
return 1;
}
- public Entity? FindBestGasTank(Entity user)
+ public Entity? FindBestGasTank(
+ Entity user)
{
// Prioritise
// 1. back equipped tanks
@@ -233,17 +236,17 @@ public sealed class InternalsSystem : EntitySystem
// 3. in-hand tanks
// 4. pocket/belt tanks
- if (!Resolve(user.Owner, ref user.Comp1, ref user.Comp2, ref user.Comp3))
+ if (!Resolve(user, ref user.Comp1, ref user.Comp2, ref user.Comp3))
return null;
- if (_inventory.TryGetSlotEntity(user.Owner, "back", out var backEntity, user.Comp2, user.Comp3) &&
+ if (_inventory.TryGetSlotEntity(user, "back", out var backEntity, user.Comp2, user.Comp3) &&
TryComp(backEntity, out var backGasTank) &&
_gasTank.CanConnectToInternals(backGasTank))
{
return (backEntity.Value, backGasTank);
}
- if (_inventory.TryGetSlotEntity(user.Owner, "suitstorage", out var entity, user.Comp2, user.Comp3) &&
+ if (_inventory.TryGetSlotEntity(user, "suitstorage", out var entity, user.Comp2, user.Comp3) &&
TryComp(entity, out var gasTank) &&
_gasTank.CanConnectToInternals(gasTank))
{
diff --git a/Content.Server/Body/Systems/LungSystem.cs b/Content.Server/Body/Systems/LungSystem.cs
index 4b60f8814b..e83d3c32a2 100644
--- a/Content.Server/Body/Systems/LungSystem.cs
+++ b/Content.Server/Body/Systems/LungSystem.cs
@@ -1,4 +1,4 @@
-using Content.Server.Atmos.Components;
+using Content.Server.Atmos.Components;
using Content.Server.Atmos.EntitySystems;
using Content.Server.Body.Components;
using Content.Server.Chemistry.Containers.EntitySystems;
@@ -26,21 +26,24 @@ public sealed class LungSystem : EntitySystem
SubscribeLocalEvent(OnMaskToggled);
}
- private void OnGotUnequipped(EntityUid uid, BreathToolComponent component, GotUnequippedEvent args)
+ private void OnGotUnequipped(Entity ent, ref GotUnequippedEvent args)
{
- _atmosphereSystem.DisconnectInternals(component);
+ _atmosphereSystem.DisconnectInternals(ent);
}
- private void OnGotEquipped(EntityUid uid, BreathToolComponent component, GotEquippedEvent args)
+ private void OnGotEquipped(Entity ent, ref GotEquippedEvent args)
{
+ if ((args.SlotFlags & ent.Comp.AllowedSlots) == 0)
+ {
+ return;
+ }
- if ((args.SlotFlags & component.AllowedSlots) == 0) return;
- component.IsFunctional = true;
+ ent.Comp.IsFunctional = true;
if (TryComp(args.Equipee, out InternalsComponent? internals))
{
- component.ConnectedInternalsEntity = args.Equipee;
- _internals.ConnectBreathTool((args.Equipee, internals), uid);
+ ent.Comp.ConnectedInternalsEntity = args.Equipee;
+ _internals.ConnectBreathTool((args.Equipee, internals), ent);
}
}
@@ -81,7 +84,7 @@ public sealed class LungSystem : EntitySystem
if (moles <= 0)
continue;
var reagent = _atmosphereSystem.GasReagents[i];
- if (reagent == null) continue;
+ if (reagent is null) continue;
var amount = moles * Atmospherics.BreathMolesToReagentMultiplier;
solution.AddReagent(reagent, amount);
diff --git a/Content.Server/Body/Systems/MetabolizerSystem.cs b/Content.Server/Body/Systems/MetabolizerSystem.cs
index e5f604f70d..45cba5a195 100644
--- a/Content.Server/Body/Systems/MetabolizerSystem.cs
+++ b/Content.Server/Body/Systems/MetabolizerSystem.cs
@@ -12,11 +12,13 @@ using Content.Shared.Mobs.Systems;
using Robust.Shared.Collections;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
+using Robust.Shared.Timing;
namespace Content.Server.Body.Systems
{
public sealed class MetabolizerSystem : EntitySystem
{
+ [Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
@@ -34,9 +36,21 @@ namespace Content.Server.Body.Systems
_solutionQuery = GetEntityQuery();
SubscribeLocalEvent(OnMetabolizerInit);
+ SubscribeLocalEvent(OnMapInit);
+ SubscribeLocalEvent(OnUnpaused);
SubscribeLocalEvent(OnApplyMetabolicMultiplier);
}
+ private void OnMapInit(Entity ent, ref MapInitEvent args)
+ {
+ ent.Comp.NextUpdate = _gameTiming.CurTime + ent.Comp.UpdateInterval;
+ }
+
+ private void OnUnpaused(Entity ent, ref EntityUnpausedEvent args)
+ {
+ ent.Comp.NextUpdate += args.PausedTime;
+ }
+
private void OnMetabolizerInit(Entity entity, ref ComponentInit args)
{
if (!entity.Comp.SolutionOnBody)
@@ -49,19 +63,17 @@ namespace Content.Server.Body.Systems
}
}
- private void OnApplyMetabolicMultiplier(EntityUid uid, MetabolizerComponent component,
- ApplyMetabolicMultiplierEvent args)
+ private void OnApplyMetabolicMultiplier(
+ Entity ent,
+ ref ApplyMetabolicMultiplierEvent args)
{
if (args.Apply)
{
- component.UpdateFrequency *= args.Multiplier;
+ ent.Comp.UpdateInterval *= args.Multiplier;
return;
}
- component.UpdateFrequency /= args.Multiplier;
- // Reset the accumulator properly
- if (component.AccumulatedFrametime >= component.UpdateFrequency)
- component.AccumulatedFrametime = component.UpdateFrequency;
+ ent.Comp.UpdateInterval /= args.Multiplier;
}
public override void Update(float frameTime)
@@ -78,50 +90,52 @@ namespace Content.Server.Body.Systems
foreach (var (uid, metab) in metabolizers)
{
- metab.AccumulatedFrametime += frameTime;
-
// Only update as frequently as it should
- if (metab.AccumulatedFrametime < metab.UpdateFrequency)
+ if (_gameTiming.CurTime < metab.NextUpdate)
continue;
- metab.AccumulatedFrametime -= metab.UpdateFrequency;
- TryMetabolize(uid, metab);
+ metab.NextUpdate += metab.UpdateInterval;
+ TryMetabolize((uid, metab));
}
}
- private void TryMetabolize(EntityUid uid, MetabolizerComponent meta, OrganComponent? organ = null)
+ private void TryMetabolize(Entity ent)
{
- _organQuery.Resolve(uid, ref organ, false);
+ _organQuery.Resolve(ent, ref ent.Comp2, logMissing: false);
// First step is get the solution we actually care about
+ var solutionName = ent.Comp1.SolutionName;
Solution? solution = null;
Entity? soln = default!;
EntityUid? solutionEntityUid = null;
- SolutionContainerManagerComponent? manager = null;
-
- if (meta.SolutionOnBody)
+ if (ent.Comp1.SolutionOnBody)
{
- if (organ?.Body is { } body)
+ if (ent.Comp2?.Body is { } body)
{
- if (!_solutionQuery.Resolve(body, ref manager, false))
+ if (!_solutionQuery.Resolve(body, ref ent.Comp3, logMissing: false))
return;
- _solutionContainerSystem.TryGetSolution((body, manager), meta.SolutionName, out soln, out solution);
+ _solutionContainerSystem.TryGetSolution((body, ent.Comp3), solutionName, out soln, out solution);
solutionEntityUid = body;
}
}
else
{
- if (!_solutionQuery.Resolve(uid, ref manager, false))
+ if (!_solutionQuery.Resolve(ent, ref ent.Comp3, logMissing: false))
return;
- _solutionContainerSystem.TryGetSolution((uid, manager), meta.SolutionName, out soln, out solution);
- solutionEntityUid = uid;
+ _solutionContainerSystem.TryGetSolution((ent, ent), solutionName, out soln, out solution);
+ solutionEntityUid = ent;
}
- if (solutionEntityUid == null || soln is null || solution is null || solution.Contents.Count == 0)
+ if (solutionEntityUid is null
+ || soln is null
+ || solution is null
+ || solution.Contents.Count == 0)
+ {
return;
+ }
// randomize the reagent list so we don't have any weird quirks
// like alphabetical order or insertion order mattering for processing
@@ -135,9 +149,9 @@ namespace Content.Server.Body.Systems
continue;
var mostToRemove = FixedPoint2.Zero;
- if (proto.Metabolisms == null)
+ if (proto.Metabolisms is null)
{
- if (meta.RemoveEmpty)
+ if (ent.Comp1.RemoveEmpty)
{
solution.RemoveReagent(reagent, FixedPoint2.New(1));
}
@@ -146,15 +160,15 @@ namespace Content.Server.Body.Systems
}
// we're done here entirely if this is true
- if (reagents >= meta.MaxReagentsProcessable)
+ if (reagents >= ent.Comp1.MaxReagentsProcessable)
return;
// loop over all our groups and see which ones apply
- if (meta.MetabolismGroups == null)
+ if (ent.Comp1.MetabolismGroups is null)
continue;
- foreach (var group in meta.MetabolismGroups)
+ foreach (var group in ent.Comp1.MetabolismGroups)
{
if (!proto.Metabolisms.TryGetValue(group.Id, out var entry))
continue;
@@ -169,14 +183,14 @@ namespace Content.Server.Body.Systems
// if it's possible for them to be dead, and they are,
// then we shouldn't process any effects, but should probably
// still remove reagents
- if (EntityManager.TryGetComponent(solutionEntityUid.Value, out var state))
+ if (TryComp(solutionEntityUid.Value, out var state))
{
if (!proto.WorksOnTheDead && _mobStateSystem.IsDead(solutionEntityUid.Value, state))
continue;
}
- var actualEntity = organ?.Body ?? solutionEntityUid.Value;
- var args = new ReagentEffectArgs(actualEntity, uid, solution, proto, mostToRemove,
+ var actualEntity = ent.Comp2?.Body ?? solutionEntityUid.Value;
+ var args = new ReagentEffectArgs(actualEntity, ent, solution, proto, mostToRemove,
EntityManager, null, scale);
// do all effects, if conditions apply
@@ -187,8 +201,14 @@ namespace Content.Server.Body.Systems
if (effect.ShouldLog)
{
- _adminLogger.Add(LogType.ReagentEffect, effect.LogImpact,
- $"Metabolism effect {effect.GetType().Name:effect} of reagent {proto.LocalizedName:reagent} applied on entity {actualEntity:entity} at {Transform(actualEntity).Coordinates:coordinates}");
+ _adminLogger.Add(
+ LogType.ReagentEffect,
+ effect.LogImpact,
+ $"Metabolism effect {effect.GetType().Name:effect}"
+ + $" of reagent {proto.LocalizedName:reagent}"
+ + $" applied on entity {actualEntity:entity}"
+ + $" at {Transform(actualEntity).Coordinates:coordinates}"
+ );
}
effect.Effect(args);
@@ -209,15 +229,25 @@ namespace Content.Server.Body.Systems
}
}
- public sealed class ApplyMetabolicMultiplierEvent : EntityEventArgs
+ [ByRefEvent]
+ public readonly record struct ApplyMetabolicMultiplierEvent(
+ EntityUid Uid,
+ float Multiplier,
+ bool Apply)
{
- // The entity whose metabolism is being modified
- public EntityUid Uid;
+ ///
+ /// The entity whose metabolism is being modified.
+ ///
+ public readonly EntityUid Uid = Uid;
- // What the metabolism's update rate will be multiplied by
- public float Multiplier;
+ ///
+ /// What the metabolism's update rate will be multiplied by.
+ ///
+ public readonly float Multiplier = Multiplier;
- // Apply this multiplier or ignore / reset it?
- public bool Apply;
+ ///
+ /// If true, apply the multiplier. If false, revert it.
+ ///
+ public readonly bool Apply = Apply;
}
}
diff --git a/Content.Server/Body/Systems/RespiratorSystem.cs b/Content.Server/Body/Systems/RespiratorSystem.cs
index 0fd61a9cb7..c7266e2c46 100644
--- a/Content.Server/Body/Systems/RespiratorSystem.cs
+++ b/Content.Server/Body/Systems/RespiratorSystem.cs
@@ -35,9 +35,21 @@ public sealed class RespiratorSystem : EntitySystem
// We want to process lung reagents before we inhale new reagents.
UpdatesAfter.Add(typeof(MetabolizerSystem));
+ SubscribeLocalEvent(OnMapInit);
+ SubscribeLocalEvent(OnUnpaused);
SubscribeLocalEvent(OnApplyMetabolicMultiplier);
}
+ private void OnMapInit(Entity ent, ref MapInitEvent args)
+ {
+ ent.Comp.NextUpdate = _gameTiming.CurTime + ent.Comp.UpdateInterval;
+ }
+
+ private void OnUnpaused(Entity ent, ref EntityUnpausedEvent args)
+ {
+ ent.Comp.NextUpdate += args.PausedTime;
+ }
+
public override void Update(float frameTime)
{
base.Update(frameTime);
@@ -45,17 +57,15 @@ public sealed class RespiratorSystem : EntitySystem
var query = EntityQueryEnumerator();
while (query.MoveNext(out var uid, out var respirator, out var body))
{
+ if (_gameTiming.CurTime < respirator.NextUpdate)
+ continue;
+
+ respirator.NextUpdate += respirator.UpdateInterval;
+
if (_mobState.IsDead(uid))
- {
continue;
- }
- respirator.AccumulatedFrametime += frameTime;
-
- if (respirator.AccumulatedFrametime < respirator.CycleDelay)
- continue;
- respirator.AccumulatedFrametime -= respirator.CycleDelay;
- UpdateSaturation(uid, -respirator.CycleDelay, respirator);
+ UpdateSaturation(uid, -(float) respirator.UpdateInterval.TotalSeconds, respirator);
if (!_mobState.IsIncapacitated(uid)) // cannot breathe in crit.
{
@@ -80,30 +90,30 @@ public sealed class RespiratorSystem : EntitySystem
_popupSystem.PopupEntity(Loc.GetString("lung-behavior-gasp"), uid);
}
- TakeSuffocationDamage(uid, respirator);
+ TakeSuffocationDamage((uid, respirator));
respirator.SuffocationCycles += 1;
continue;
}
- StopSuffocation(uid, respirator);
+ StopSuffocation((uid, respirator));
respirator.SuffocationCycles = 0;
}
}
public void Inhale(EntityUid uid, BodyComponent? body = null)
{
- if (!Resolve(uid, ref body, false))
+ if (!Resolve(uid, ref body, logMissing: false))
return;
var organs = _bodySystem.GetBodyOrganComponents(uid, body);
// Inhale gas
var ev = new InhaleLocationEvent();
- RaiseLocalEvent(uid, ev);
+ RaiseLocalEvent(uid, ref ev, broadcast: false);
- ev.Gas ??= _atmosSys.GetContainingMixture(uid, false, true);
+ ev.Gas ??= _atmosSys.GetContainingMixture(uid, excite: true);
- if (ev.Gas == null)
+ if (ev.Gas is null)
{
return;
}
@@ -122,7 +132,7 @@ public sealed class RespiratorSystem : EntitySystem
public void Exhale(EntityUid uid, BodyComponent? body = null)
{
- if (!Resolve(uid, ref body, false))
+ if (!Resolve(uid, ref body, logMissing: false))
return;
var organs = _bodySystem.GetBodyOrganComponents