diff --git a/Content.Client/Alerts/ClientAlertsSystem.cs b/Content.Client/Alerts/ClientAlertsSystem.cs index 237f24e3ea..223bf7876a 100644 --- a/Content.Client/Alerts/ClientAlertsSystem.cs +++ b/Content.Client/Alerts/ClientAlertsSystem.cs @@ -49,24 +49,23 @@ public IReadOnlyDictionary? ActiveAlerts protected override void AfterShowAlert(Entity alerts) { - if (_playerManager.LocalEntity != alerts.Owner) - return; - - SyncAlerts?.Invoke(this, alerts.Comp.Alerts); + UpdateHud(alerts); } - protected override void AfterClearAlert(Entity alertsComponent) + protected override void AfterClearAlert(Entity alerts) { - if (_playerManager.LocalEntity != alertsComponent.Owner) - return; + UpdateHud(alerts); + } - SyncAlerts?.Invoke(this, alertsComponent.Comp.Alerts); + private void ClientAlertsHandleState(Entity alerts, ref AfterAutoHandleStateEvent args) + { + UpdateHud(alerts); } - private void ClientAlertsHandleState(EntityUid uid, AlertsComponent component, ref AfterAutoHandleStateEvent args) + private void UpdateHud(Entity entity) { - if (_playerManager.LocalEntity == uid) - SyncAlerts?.Invoke(this, component.Alerts); + if (_playerManager.LocalEntity == entity.Owner) + SyncAlerts?.Invoke(this, entity.Comp.Alerts); } private void OnPlayerAttached(EntityUid uid, AlertsComponent component, LocalPlayerAttachedEvent args) 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 @@ protected override void QueueUpdate(EntityUid uid, AmbientSoundComponent ambienc 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 @@ private bool TryGetDefaultVisuals(EntityUid uid, ClothingComponent clothing, str 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.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/IconSmoothing/IconSmoothSystem.cs b/Content.Client/IconSmoothing/IconSmoothSystem.cs index 0ab33c6520..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(); @@ -47,7 +45,7 @@ private void OnStartup(EntityUid uid, IconSmoothComponent component, ComponentSt var xform = Transform(uid); if (xform.Anchored) { - component.LastPosition = _mapManager.TryGetGrid(xform.GridUid, out var grid) + component.LastPosition = TryComp(xform.GridUid, out var grid) ? (xform.GridUid.Value, grid.TileIndicesFor(xform.Coordinates)) : (null, new Vector2i(0, 0)); @@ -134,7 +132,7 @@ public void DirtyNeighbours(EntityUid uid, IconSmoothComponent? comp = null, Tra Vector2i pos; - if (transform.Anchored && _mapManager.TryGetGrid(transform.GridUid, out var grid)) + if (transform.Anchored && TryComp(transform.GridUid, out var grid)) { pos = grid.CoordinatesToTile(transform.Coordinates); } @@ -144,7 +142,7 @@ public void DirtyNeighbours(EntityUid uid, IconSmoothComponent? comp = null, Tra if (comp.LastPosition is not (EntityUid gridId, Vector2i oldPos)) return; - if (!_mapManager.TryGetGrid(gridId, out grid)) + if (!TryComp(gridId, out grid)) return; pos = oldPos; @@ -206,7 +204,7 @@ private void CalculateNewSprite(EntityUid uid, { var directions = DirectionFlag.None; - if (_mapManager.TryGetGrid(xform.GridUid, out grid)) + if (TryComp(xform.GridUid, out grid)) { var pos = grid.TileIndicesFor(xform.Coordinates); @@ -240,7 +238,7 @@ private void CalculateNewSprite(EntityUid uid, if (xform.Anchored) { - if (!_mapManager.TryGetGrid(xform.GridUid, out grid)) + if (!TryComp(xform.GridUid, out grid)) { Log.Error($"Failed to calculate IconSmoothComponent sprite in {uid} because grid {xform.GridUid} was missing."); return; 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 @@ private bool TryGetDefaultVisuals(EntityUid uid, ItemComponent item, string defa 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/Movement/Systems/JetpackSystem.cs b/Content.Client/Movement/Systems/JetpackSystem.cs index f0836ee9b6..b7f5e48821 100644 --- a/Content.Client/Movement/Systems/JetpackSystem.cs +++ b/Content.Client/Movement/Systems/JetpackSystem.cs @@ -4,6 +4,7 @@ using Content.Shared.Movement.Systems; using Robust.Client.GameObjects; using Robust.Shared.Map; +using Robust.Shared.Map.Components; using Robust.Shared.Physics.Components; using Robust.Shared.Timing; @@ -12,7 +13,6 @@ namespace Content.Client.Movement.Systems; public sealed class JetpackSystem : SharedJetpackSystem { [Dependency] private readonly IGameTiming _timing = default!; - [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly ClothingSystem _clothing = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; @@ -75,7 +75,7 @@ private void CreateParticles(EntityUid uid) var coordinates = uidXform.Coordinates; var gridUid = coordinates.GetGridUid(EntityManager); - if (_mapManager.TryGetGrid(gridUid, out var grid)) + if (TryComp(gridUid, out var grid)) { coordinates = new EntityCoordinates(gridUid.Value, grid.WorldToLocal(coordinates.ToMapPos(EntityManager, _transform))); } 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 @@ private void DrawScreen(OverlayDrawArgs args, DrawingHandleScreen screenHandle) var invGridMatrix = gridXform.InvWorldMatrix; DebugPathPoly? nearest = null; - var nearestDistance = float.MaxValue; foreach (var poly in tile) { diff --git a/Content.Client/NodeContainer/NodeVisualizationOverlay.cs b/Content.Client/NodeContainer/NodeVisualizationOverlay.cs index f10eb9ed8b..691bcb41db 100644 --- a/Content.Client/NodeContainer/NodeVisualizationOverlay.cs +++ b/Content.Client/NodeContainer/NodeVisualizationOverlay.cs @@ -80,7 +80,7 @@ private void DrawScreen(in OverlayDrawArgs args) var xform = _entityManager.GetComponent(_entityManager.GetEntity(node.Entity)); - if (!_mapManager.TryGetGrid(xform.GridUid, out var grid)) + if (!_entityManager.TryGetComponent(xform.GridUid, out var grid)) return; var gridTile = grid.TileIndicesFor(xform.Coordinates); @@ -145,7 +145,7 @@ private void DrawWorld(in OverlayDrawArgs overlayDrawArgs) foreach (var (gridId, gridDict) in _gridIndex) { - var grid = _mapManager.GetGrid(gridId); + var grid = _entityManager.GetComponent(gridId); var (_, _, worldMatrix, invMatrix) = _entityManager.GetComponent(gridId).GetWorldPositionRotationMatrixWithInv(); var lCursorBox = invMatrix.TransformBox(cursorBox); diff --git a/Content.Client/Physics/Controllers/MoverController.cs b/Content.Client/Physics/Controllers/MoverController.cs index 7a8a6e39cf..31042854d4 100644 --- a/Content.Client/Physics/Controllers/MoverController.cs +++ b/Content.Client/Physics/Controllers/MoverController.cs @@ -1,6 +1,7 @@ using Content.Shared.Movement.Components; +using Content.Shared.Movement.Pulling.Components; using Content.Shared.Movement.Systems; -using Content.Shared.Pulling.Components; +using Robust.Client.GameObjects; using Robust.Client.Physics; using Robust.Client.Player; using Robust.Shared.Physics.Components; @@ -24,7 +25,7 @@ public override void Initialize() SubscribeLocalEvent(OnUpdatePredicted); SubscribeLocalEvent(OnUpdateRelayTargetPredicted); - SubscribeLocalEvent(OnUpdatePullablePredicted); + SubscribeLocalEvent(OnUpdatePullablePredicted); } private void OnUpdatePredicted(EntityUid uid, InputMoverComponent component, ref UpdateIsPredictedEvent args) @@ -40,7 +41,7 @@ private void OnUpdateRelayTargetPredicted(EntityUid uid, MovementRelayTargetComp args.IsPredicted = true; } - private void OnUpdatePullablePredicted(EntityUid uid, SharedPullableComponent component, ref UpdateIsPredictedEvent args) + private void OnUpdatePullablePredicted(EntityUid uid, PullableComponent component, ref UpdateIsPredictedEvent args) { // Enable prediction if an entity is being pulled by the player. // Disable prediction if an entity is being pulled by some non-player entity. diff --git a/Content.Client/Pulling/PullingSystem.cs b/Content.Client/Pulling/PullingSystem.cs deleted file mode 100644 index 556dadd00d..0000000000 --- a/Content.Client/Pulling/PullingSystem.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Content.Shared.Pulling; -using Content.Shared.Pulling.Components; -using JetBrains.Annotations; -using Robust.Client.Physics; - -namespace Content.Client.Pulling -{ - [UsedImplicitly] - public sealed class PullingSystem : SharedPullingSystem - { - public override void Initialize() - { - base.Initialize(); - - UpdatesAfter.Add(typeof(PhysicsSystem)); - - SubscribeLocalEvent(OnPullableMove); - SubscribeLocalEvent(OnPullableStopMove); - } - } -} diff --git a/Content.Client/Radiation/Overlays/RadiationDebugOverlay.cs b/Content.Client/Radiation/Overlays/RadiationDebugOverlay.cs index 8c721fa777..ef6283b6ff 100644 --- a/Content.Client/Radiation/Overlays/RadiationDebugOverlay.cs +++ b/Content.Client/Radiation/Overlays/RadiationDebugOverlay.cs @@ -4,13 +4,12 @@ using Robust.Client.Graphics; using Robust.Client.ResourceManagement; using Robust.Shared.Enums; -using Robust.Shared.Map; +using Robust.Shared.Map.Components; namespace Content.Client.Radiation.Overlays; public sealed class RadiationDebugOverlay : Overlay { - [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly IEntityManager _entityManager = default!; private readonly RadiationSystem _radiation; @@ -63,7 +62,7 @@ private void DrawScreenRays(OverlayDrawArgs args) { var gridUid = _entityManager.GetEntity(netGrid); - if (!_mapManager.TryGetGrid(gridUid, out var grid)) + if (!_entityManager.TryGetComponent(gridUid, out var grid)) continue; foreach (var (tile, rads) in blockers) @@ -88,7 +87,7 @@ private void DrawScreenResistance(OverlayDrawArgs args) { var gridUid = _entityManager.GetEntity(netGrid); - if (!_mapManager.TryGetGrid(gridUid, out var grid)) + if (!_entityManager.TryGetComponent(gridUid, out var grid)) continue; if (query.TryGetComponent(gridUid, out var trs) && trs.MapID != args.MapId) continue; @@ -127,7 +126,7 @@ private void DrawWorld(in OverlayDrawArgs args) { var gridUid = _entityManager.GetEntity(netGrid); - if (!_mapManager.TryGetGrid(gridUid, out var grid)) + if (!_entityManager.TryGetComponent(gridUid, out var grid)) continue; var (destTile, _) = blockers.Last(); var destWorld = grid.GridTileToWorldPos(destTile); diff --git a/Content.Client/Remotes/EntitySystems/DoorRemoteSystem.cs b/Content.Client/Remotes/EntitySystems/DoorRemoteSystem.cs new file mode 100644 index 0000000000..d6a9057f08 --- /dev/null +++ b/Content.Client/Remotes/EntitySystems/DoorRemoteSystem.cs @@ -0,0 +1,16 @@ +using Content.Client.Remote.UI; +using Content.Client.Items; +using Content.Shared.Remotes.EntitySystems; +using Content.Shared.Remotes.Components; + +namespace Content.Client.Remotes.EntitySystems; + +public sealed class DoorRemoteSystem : SharedDoorRemoteSystem +{ + public override void Initialize() + { + base.Initialize(); + + Subs.ItemStatus(ent => new DoorRemoteStatusControl(ent)); + } +} diff --git a/Content.Client/Remotes/UI/DoorRemoteStatusControl.cs b/Content.Client/Remotes/UI/DoorRemoteStatusControl.cs new file mode 100644 index 0000000000..94589ecdaa --- /dev/null +++ b/Content.Client/Remotes/UI/DoorRemoteStatusControl.cs @@ -0,0 +1,46 @@ +using Content.Client.Message; +using Content.Client.Stylesheets; +using Content.Shared.Remotes.Components; +using Robust.Client.UserInterface; +using Robust.Client.UserInterface.Controls; +using Robust.Shared.Timing; + +namespace Content.Client.Remote.UI; + +public sealed class DoorRemoteStatusControl : Control +{ + private readonly Entity _entity; + private readonly RichTextLabel _label; + + // set to toggle bolts initially just so that it updates on first pickup of remote + private OperatingMode PrevOperatingMode = OperatingMode.placeholderForUiUpdates; + + public DoorRemoteStatusControl(Entity entity) + { + _entity = entity; + _label = new RichTextLabel { StyleClasses = { StyleNano.StyleClassItemStatus } }; + AddChild(_label); + } + + protected override void FrameUpdate(FrameEventArgs args) + { + base.FrameUpdate(args); + + // only updates the UI if any of the details are different than they previously were + if (PrevOperatingMode == _entity.Comp.Mode) + return; + + PrevOperatingMode = _entity.Comp.Mode; + + // Update current volume and injector state + var modeStringLocalized = Loc.GetString(_entity.Comp.Mode switch + { + OperatingMode.OpenClose => "door-remote-open-close-text", + OperatingMode.ToggleBolts => "door-remote-toggle-bolt-text", + OperatingMode.ToggleEmergencyAccess => "door-remote-emergency-access-text", + _ => "door-remote-invalid-text" + }); + + _label.SetMarkup(Loc.GetString("door-remote-mode-label", ("modeString", modeStringLocalized))); + } +} diff --git a/Content.Client/Replay/Spectator/ReplaySpectatorSystem.Blockers.cs b/Content.Client/Replay/Spectator/ReplaySpectatorSystem.Blockers.cs index 86d113defb..2fa862f3df 100644 --- a/Content.Client/Replay/Spectator/ReplaySpectatorSystem.Blockers.cs +++ b/Content.Client/Replay/Spectator/ReplaySpectatorSystem.Blockers.cs @@ -3,7 +3,7 @@ using Content.Shared.Inventory.Events; using Content.Shared.Item; using Content.Shared.Movement.Events; -using Content.Shared.Physics.Pull; +using Content.Shared.Movement.Pulling.Events; using Content.Shared.Throwing; namespace Content.Client.Replay.Spectator; 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 @@ protected void DrawCircles(DrawingHandleScreen handle) 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/Throwing/ThrownItemVisualizerSystem.cs b/Content.Client/Throwing/ThrownItemVisualizerSystem.cs index bbd3673110..b25b4fbb7d 100644 --- a/Content.Client/Throwing/ThrownItemVisualizerSystem.cs +++ b/Content.Client/Throwing/ThrownItemVisualizerSystem.cs @@ -24,7 +24,7 @@ public override void Initialize() private void OnAutoHandleState(EntityUid uid, ThrownItemComponent component, ref AfterAutoHandleStateEvent args) { - if (!TryComp(uid, out var sprite)) + if (!TryComp(uid, out var sprite) || !component.Animate) return; var animationPlayer = EnsureComp(uid); diff --git a/Content.IntegrationTests/Pair/TestMapData.cs b/Content.IntegrationTests/Pair/TestMapData.cs index bdf1208038..343641e161 100644 --- a/Content.IntegrationTests/Pair/TestMapData.cs +++ b/Content.IntegrationTests/Pair/TestMapData.cs @@ -10,9 +10,8 @@ namespace Content.IntegrationTests.Pair; public sealed class TestMapData { public EntityUid MapUid { get; set; } - public EntityUid GridUid { get; set; } - public MapId MapId { get; set; } - public MapGridComponent MapGrid { get; set; } = default!; + public Entity Grid; + public MapId MapId; public EntityCoordinates GridCoords { get; set; } public MapCoordinates MapCoords { get; set; } public TileRef Tile { get; set; } @@ -21,4 +20,4 @@ public sealed class TestMapData public EntityUid CMapUid { get; set; } public EntityUid CGridUid { get; set; } public EntityCoordinates CGridCoords { get; set; } -} \ No newline at end of file +} diff --git a/Content.IntegrationTests/Pair/TestPair.Helpers.cs b/Content.IntegrationTests/Pair/TestPair.Helpers.cs index 554807b2d2..0ea6d3e2dc 100644 --- a/Content.IntegrationTests/Pair/TestPair.Helpers.cs +++ b/Content.IntegrationTests/Pair/TestPair.Helpers.cs @@ -1,5 +1,6 @@ #nullable enable using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using Robust.Shared.GameObjects; using Robust.Shared.Map; @@ -14,36 +15,37 @@ public sealed partial class TestPair /// /// Creates a map, a grid, and a tile, and gives back references to them. /// - public async Task CreateTestMap() + [MemberNotNull(nameof(TestMap))] + public async Task CreateTestMap(bool initialized = true, string tile = "Plating") { + var mapData = new TestMapData(); + TestMap = mapData; await Server.WaitIdleAsync(); var tileDefinitionManager = Server.ResolveDependency(); - var mapData = new TestMapData(); TestMap = mapData; await Server.WaitPost(() => { - mapData.MapId = Server.MapMan.CreateMap(); - mapData.MapUid = Server.MapMan.GetMapEntityId(mapData.MapId); - var mapGrid = Server.MapMan.CreateGridEntity(mapData.MapId); - mapData.MapGrid = mapGrid; - mapData.GridUid = mapGrid.Owner; // Fixing this requires an engine PR. - mapData.GridCoords = new EntityCoordinates(mapData.GridUid, 0, 0); - var plating = tileDefinitionManager["Plating"]; + mapData.MapUid = Server.System().CreateMap(out mapData.MapId, runMapInit: initialized); + mapData.Grid = Server.MapMan.CreateGridEntity(mapData.MapId); + mapData.GridCoords = new EntityCoordinates(mapData.Grid, 0, 0); + var plating = tileDefinitionManager[tile]; var platingTile = new Tile(plating.TileId); - mapData.MapGrid.SetTile(mapData.GridCoords, platingTile); + mapData.Grid.Comp.SetTile(mapData.GridCoords, platingTile); mapData.MapCoords = new MapCoordinates(0, 0, mapData.MapId); - mapData.Tile = mapData.MapGrid.GetAllTiles().First(); + mapData.Tile = mapData.Grid.Comp.GetAllTiles().First(); }); + TestMap = mapData; if (!Settings.Connected) return mapData; await RunTicksSync(10); mapData.CMapUid = ToClientUid(mapData.MapUid); - mapData.CGridUid = ToClientUid(mapData.GridUid); + mapData.CGridUid = ToClientUid(mapData.Grid); mapData.CGridCoords = new EntityCoordinates(mapData.CGridUid, 0, 0); + TestMap = mapData; return mapData; } 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 @@ await testOut.WriteLineAsync( Pairs[fallback!] = true; } - if (fallback == null && _pairId > 8) - { - var x = 2; - } - return fallback; } } diff --git a/Content.IntegrationTests/Tests/Administration/Logs/AddTests.cs b/Content.IntegrationTests/Tests/Administration/Logs/AddTests.cs index 98c7363a6c..772af337a1 100644 --- a/Content.IntegrationTests/Tests/Administration/Logs/AddTests.cs +++ b/Content.IntegrationTests/Tests/Administration/Logs/AddTests.cs @@ -32,8 +32,8 @@ public async Task AddAndGetSingleLog() var guid = Guid.NewGuid(); - var testMap = await pair.CreateTestMap(); - var coordinates = testMap.GridCoords; + await pair.CreateTestMap(); + var coordinates = pair.TestMap.GridCoords; await server.WaitPost(() => { var entity = sEntities.SpawnEntity(null, coordinates); 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.GameObjects; using Robust.Shared.Map; using Robust.Shared.Map.Components; -using Robust.Shared.Maths; using System.Linq; using System.Numerics; @@ -61,12 +60,11 @@ public async Task AirConsistencyTest() 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 @@ float GetMapMoles() 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 @@ await server.WaitAssertion(() => var inhaleCycles = 100; for (var i = 0; i < inhaleCycles; i++) { - await server.WaitAssertion(() => - { - // inhale - respSys.Update(2.0f); - Assert.That(GetMapMoles(), Is.LessThan(startingMoles)); - - // metabolize + exhale - metaSys.Update(1.0f); - metaSys.Update(1.0f); - respSys.Update(2.0f); - Assert.That(GetMapMoles(), Is.EqualTo(startingMoles).Within(0.0002)); - }); + // Breathe in + await PoolManager.WaitUntil(server, () => resp.Status == RespiratorStatus.Exhaling); + Assert.That( + GetMapMoles(), Is.LessThan(startingMoles), + "Did not inhale in any gas" + ); + + // 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 @@ await server.WaitAssertion(() => #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 @@ await server.WaitAssertion(() => #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 @@ await server.WaitAssertion(() => 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 @@ await server.WaitAssertion(() => }); // 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 @@ await server.WaitAssertion(() => 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/DeviceNetwork/DeviceNetworkTest.cs b/Content.IntegrationTests/Tests/DeviceNetwork/DeviceNetworkTest.cs index 26ea726211..b37f7cfa46 100644 --- a/Content.IntegrationTests/Tests/DeviceNetwork/DeviceNetworkTest.cs +++ b/Content.IntegrationTests/Tests/DeviceNetwork/DeviceNetworkTest.cs @@ -212,7 +212,7 @@ public async Task WiredNetworkDeviceSendAndReceive() DeviceNetworkComponent networkComponent1 = null; DeviceNetworkComponent networkComponent2 = null; WiredNetworkComponent wiredNetworkComponent = null; - var grid = testMap.MapGrid; + var grid = testMap.Grid.Comp; var testValue = "test"; var payload = new NetworkPayload diff --git a/Content.IntegrationTests/Tests/Disposal/DisposalUnitTest.cs b/Content.IntegrationTests/Tests/Disposal/DisposalUnitTest.cs index 976fc2eceb..9109fdbe4f 100644 --- a/Content.IntegrationTests/Tests/Disposal/DisposalUnitTest.cs +++ b/Content.IntegrationTests/Tests/Disposal/DisposalUnitTest.cs @@ -163,7 +163,6 @@ public async Task Test() var entityManager = server.ResolveDependency(); var xformSystem = entityManager.System(); var disposalSystem = entityManager.System(); - await server.WaitAssertion(() => { // Spawn the entities @@ -171,8 +170,7 @@ await server.WaitAssertion(() => human = entityManager.SpawnEntity("HumanDisposalDummy", coordinates); wrench = entityManager.SpawnEntity("WrenchDummy", coordinates); disposalUnit = entityManager.SpawnEntity("DisposalUnitDummy", coordinates); - disposalTrunk = entityManager.SpawnEntity("DisposalTrunkDummy", - entityManager.GetComponent(disposalUnit).MapPosition); + disposalTrunk = entityManager.SpawnEntity("DisposalTrunkDummy", coordinates); // Test for components existing unitUid = disposalUnit; @@ -204,10 +202,10 @@ await server.WaitAssertion(() => await server.WaitAssertion(() => { - // Move the disposal trunk away - var xform = entityManager.GetComponent(disposalTrunk); var worldPos = xformSystem.GetWorldPosition(disposalTrunk); - xformSystem.SetWorldPosition(xform, worldPos + new Vector2(1, 0)); + + // Move the disposal trunk away + xformSystem.SetWorldPosition(disposalTrunk, worldPos + new Vector2(1, 0)); // Fail to flush with a mob and an item Flush(disposalUnit, unitComponent, false, disposalSystem, human, wrench); @@ -215,10 +213,12 @@ await server.WaitAssertion(() => await server.WaitAssertion(() => { - // Move the disposal trunk back var xform = entityManager.GetComponent(disposalTrunk); - var worldPos = xformSystem.GetWorldPosition(disposalTrunk); - xformSystem.SetWorldPosition(xform, worldPos - new Vector2(1, 0)); + var worldPos = xformSystem.GetWorldPosition(disposalUnit); + + // Move the disposal trunk back + xformSystem.SetWorldPosition(disposalTrunk, worldPos); + xformSystem.AnchorEntity((disposalTrunk, xform)); // Fail to flush with a mob and an item, no power Flush(disposalUnit, unitComponent, false, disposalSystem, human, wrench); @@ -240,6 +240,7 @@ await server.WaitAssertion(() => // Re-pressurizing Flush(disposalUnit, unitComponent, false, disposalSystem); }); + await pair.CleanReturnAsync(); } } diff --git a/Content.IntegrationTests/Tests/EntityTest.cs b/Content.IntegrationTests/Tests/EntityTest.cs index 152eb72522..d3b1fb4722 100644 --- a/Content.IntegrationTests/Tests/EntityTest.cs +++ b/Content.IntegrationTests/Tests/EntityTest.cs @@ -354,41 +354,18 @@ public async Task AllComponentsOneToOneDeleteTest() await using var pair = await PoolManager.GetServerClient(); var server = pair.Server; - - var mapManager = server.ResolveDependency(); var entityManager = server.ResolveDependency(); var componentFactory = server.ResolveDependency(); - var tileDefinitionManager = server.ResolveDependency(); - var mapSystem = entityManager.System(); var logmill = server.ResolveDependency().GetSawmill("EntityTest"); - Entity grid = default!; - - await server.WaitPost(() => - { - // Create a one tile grid to stave off the grid 0 monsters - var mapId = mapManager.CreateMap(); - - mapManager.AddUninitializedMap(mapId); - - grid = mapManager.CreateGridEntity(mapId); - - var tileDefinition = tileDefinitionManager["Plating"]; - var tile = new Tile(tileDefinition.TileId); - var coordinates = new EntityCoordinates(grid.Owner, Vector2.Zero); - - mapSystem.SetTile(grid.Owner, grid.Comp!, coordinates, tile); - - mapManager.DoMapInitialize(mapId); - }); - + await pair.CreateTestMap(); await server.WaitRunTicks(5); + var testLocation = pair.TestMap.GridCoords; await server.WaitAssertion(() => { Assert.Multiple(() => { - var testLocation = new EntityCoordinates(grid.Owner, Vector2.Zero); foreach (var type in componentFactory.AllRegisteredTypes) { diff --git a/Content.IntegrationTests/Tests/Fluids/FluidSpillTest.cs b/Content.IntegrationTests/Tests/Fluids/FluidSpillTest.cs index 0d852bf2f0..6e88d6928e 100644 --- a/Content.IntegrationTests/Tests/Fluids/FluidSpillTest.cs +++ b/Content.IntegrationTests/Tests/Fluids/FluidSpillTest.cs @@ -72,7 +72,7 @@ await server.WaitPost(() => var puddleOrigin = new Vector2i(0, 0); await server.WaitAssertion(() => { - var grid = mapManager.GetGrid(gridId); + var grid = entityManager.GetComponent(gridId); var solution = new Solution("Blood", FixedPoint2.New(100)); var tileRef = grid.GetTileRef(puddleOrigin); #pragma warning disable NUnit2045 // Interdependent tests @@ -86,7 +86,7 @@ await server.WaitAssertion(() => await server.WaitAssertion(() => { - var grid = mapManager.GetGrid(gridId); + var grid = entityManager.GetComponent(gridId); var puddle = GetPuddleEntity(entityManager, grid, puddleOrigin); #pragma warning disable NUnit2045 // Interdependent tests diff --git a/Content.IntegrationTests/Tests/Fluids/PuddleTest.cs b/Content.IntegrationTests/Tests/Fluids/PuddleTest.cs index 3213bba51f..a9069892df 100644 --- a/Content.IntegrationTests/Tests/Fluids/PuddleTest.cs +++ b/Content.IntegrationTests/Tests/Fluids/PuddleTest.cs @@ -46,17 +46,14 @@ public async Task SpaceNoPuddleTest() var server = pair.Server; var testMap = await pair.CreateTestMap(); + var grid = testMap.Grid.Comp; var entitySystemManager = server.ResolveDependency(); var spillSystem = entitySystemManager.GetEntitySystem(); - MapGridComponent grid = null; - // Remove all tiles await server.WaitPost(() => { - grid = testMap.MapGrid; - foreach (var tile in grid.GetAllTiles()) { grid.SetTile(tile.GridIndices, Tile.Empty); @@ -67,7 +64,7 @@ await server.WaitPost(() => 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 @@ await server.WaitAssertion(() => var cuffableSys = entityManager.System(); var xformSys = entityManager.System(); - var xformQuery = entityManager.GetEntityQuery(); // Spawn the entities human = entityManager.SpawnEntity("HumanHandcuffDummy", coordinates); @@ -66,8 +65,8 @@ await server.WaitAssertion(() => 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/Interaction/InteractionTest.Helpers.cs b/Content.IntegrationTests/Tests/Interaction/InteractionTest.Helpers.cs index 88448e7b80..480fd9cde6 100644 --- a/Content.IntegrationTests/Tests/Interaction/InteractionTest.Helpers.cs +++ b/Content.IntegrationTests/Tests/Interaction/InteractionTest.Helpers.cs @@ -989,7 +989,7 @@ protected void ToggleNeedPower(NetEntity? target = null) /// protected async Task AddGravity(EntityUid? uid = null) { - var target = uid ?? MapData.GridUid; + var target = uid ?? MapData.Grid; await Server.WaitPost(() => { var gravity = SEntMan.EnsureComponent(target); diff --git a/Content.IntegrationTests/Tests/Interaction/InteractionTest.cs b/Content.IntegrationTests/Tests/Interaction/InteractionTest.cs index bed27ba6ef..a4ed31e998 100644 --- a/Content.IntegrationTests/Tests/Interaction/InteractionTest.cs +++ b/Content.IntegrationTests/Tests/Interaction/InteractionTest.cs @@ -184,7 +184,7 @@ public virtual async Task Setup() await Pair.CreateTestMap(); PlayerCoords = SEntMan.GetNetCoordinates(MapData.GridCoords.Offset(new Vector2(0.5f, 0.5f)).WithEntityId(MapData.MapUid, Transform, SEntMan)); TargetCoords = SEntMan.GetNetCoordinates(MapData.GridCoords.Offset(new Vector2(1.5f, 0.5f)).WithEntityId(MapData.MapUid, Transform, SEntMan)); - await SetTile(Plating, grid: MapData.MapGrid); + await SetTile(Plating, grid: MapData.Grid.Comp); // Get player data var sPlayerMan = Server.ResolveDependency(); diff --git a/Content.IntegrationTests/Tests/Interaction/MovementTest.cs b/Content.IntegrationTests/Tests/Interaction/MovementTest.cs index 553b031c2b..dc5aec92cf 100644 --- a/Content.IntegrationTests/Tests/Interaction/MovementTest.cs +++ b/Content.IntegrationTests/Tests/Interaction/MovementTest.cs @@ -31,7 +31,7 @@ public override async Task Setup() for (var i = -Tiles; i <= Tiles; i++) { - await SetTile(Plating, SEntMan.GetNetCoordinates(pCoords.Offset(new Vector2(i, 0))), MapData.MapGrid); + await SetTile(Plating, SEntMan.GetNetCoordinates(pCoords.Offset(new Vector2(i, 0))), MapData.Grid.Comp); } AssertGridCount(1); diff --git a/Content.IntegrationTests/Tests/Linter/StaticFieldValidationTest.cs b/Content.IntegrationTests/Tests/Linter/StaticFieldValidationTest.cs new file mode 100644 index 0000000000..30724b50a6 --- /dev/null +++ b/Content.IntegrationTests/Tests/Linter/StaticFieldValidationTest.cs @@ -0,0 +1,150 @@ +using System.Collections.Generic; +using System.Linq; +using Content.Shared.Tag; +using Robust.Shared.Prototypes; +using Robust.Shared.Reflection; +using Robust.Shared.Serialization.Manager.Attributes; + +namespace Content.IntegrationTests.Tests.Linter; + +/// +/// Verify that the yaml linter successfully validates static fields +/// +[TestFixture] +public sealed class StaticFieldValidationTest +{ + [Test] + public async Task TestStaticFieldValidation() + { + await using var pair = await PoolManager.GetServerClient(); + var protoMan = pair.Server.ProtoMan; + + var protos = new Dictionary>(); + foreach (var kind in protoMan.EnumeratePrototypeKinds()) + { + var ids = protoMan.EnumeratePrototypes(kind).Select(x => x.ID).ToHashSet(); + protos.Add(kind, ids); + } + + Assert.That(protoMan.ValidateStaticFields(typeof(StringValid), protos).Count, Is.Zero); + Assert.That(protoMan.ValidateStaticFields(typeof(StringArrayValid), protos).Count, Is.Zero); + Assert.That(protoMan.ValidateStaticFields(typeof(EntProtoIdValid), protos).Count, Is.Zero); + Assert.That(protoMan.ValidateStaticFields(typeof(EntProtoIdArrayValid), protos).Count, Is.Zero); + Assert.That(protoMan.ValidateStaticFields(typeof(ProtoIdTestValid), protos).Count, Is.Zero); + Assert.That(protoMan.ValidateStaticFields(typeof(ProtoIdArrayValid), protos).Count, Is.Zero); + Assert.That(protoMan.ValidateStaticFields(typeof(ProtoIdListValid), protos).Count, Is.Zero); + Assert.That(protoMan.ValidateStaticFields(typeof(ProtoIdSetValid), protos).Count, Is.Zero); + Assert.That(protoMan.ValidateStaticFields(typeof(PrivateProtoIdArrayValid), protos).Count, Is.Zero); + + Assert.That(protoMan.ValidateStaticFields(typeof(StringInvalid), protos).Count, Is.EqualTo(1)); + Assert.That(protoMan.ValidateStaticFields(typeof(StringArrayInvalid), protos).Count, Is.EqualTo(2)); + Assert.That(protoMan.ValidateStaticFields(typeof(EntProtoIdInvalid), protos).Count, Is.EqualTo(1)); + Assert.That(protoMan.ValidateStaticFields(typeof(EntProtoIdArrayInvalid), protos).Count, Is.EqualTo(2)); + Assert.That(protoMan.ValidateStaticFields(typeof(ProtoIdTestInvalid), protos).Count, Is.EqualTo(1)); + Assert.That(protoMan.ValidateStaticFields(typeof(ProtoIdArrayInvalid), protos).Count, Is.EqualTo(2)); + Assert.That(protoMan.ValidateStaticFields(typeof(ProtoIdListInvalid), protos).Count, Is.EqualTo(2)); + Assert.That(protoMan.ValidateStaticFields(typeof(ProtoIdSetInvalid), protos).Count, Is.EqualTo(2)); + Assert.That(protoMan.ValidateStaticFields(typeof(PrivateProtoIdArrayInvalid), protos).Count, Is.EqualTo(2)); + + await pair.CleanReturnAsync(); + } + + [TestPrototypes] + private const string TestPrototypes = @" +- type: entity + id: StaticFieldTestEnt + +- type: Tag + id: StaticFieldTestTag +"; + + [Reflect(false)] private sealed class StringValid + { + [ValidatePrototypeId] public static string Tag = "StaticFieldTestTag"; + } + + [Reflect(false)] private sealed class StringInvalid + { + [ValidatePrototypeId] public static string Tag = string.Empty; + } + + [Reflect(false)] private sealed class StringArrayValid + { + [ValidatePrototypeId] public static string[] Tag = {"StaticFieldTestTag", "StaticFieldTestTag"}; + } + + [Reflect(false)] private sealed class StringArrayInvalid + { + [ValidatePrototypeId] public static string[] Tag = {string.Empty, "StaticFieldTestTag", string.Empty}; + } + + [Reflect(false)] private sealed class EntProtoIdValid + { + public static EntProtoId Tag = "StaticFieldTestEnt"; + } + + [Reflect(false)] private sealed class EntProtoIdInvalid + { + public static EntProtoId Tag = string.Empty; + } + + [Reflect(false)] private sealed class EntProtoIdArrayValid + { + public static EntProtoId[] Tag = {"StaticFieldTestEnt", "StaticFieldTestEnt"}; + } + + [Reflect(false)] private sealed class EntProtoIdArrayInvalid + { + public static EntProtoId[] Tag = {string.Empty, "StaticFieldTestEnt", string.Empty}; + } + + [Reflect(false)] private sealed class ProtoIdTestValid + { + public static ProtoId Tag = "StaticFieldTestTag"; + } + + [Reflect(false)] private sealed class ProtoIdTestInvalid + { + public static ProtoId Tag = string.Empty; + } + + [Reflect(false)] private sealed class ProtoIdArrayValid + { + public static ProtoId[] Tag = {"StaticFieldTestTag", "StaticFieldTestTag"}; + } + + [Reflect(false)] private sealed class ProtoIdArrayInvalid + { + public static ProtoId[] Tag = {string.Empty, "StaticFieldTestTag", string.Empty}; + } + + [Reflect(false)] private sealed class ProtoIdListValid + { + public static List> Tag = new() {"StaticFieldTestTag", "StaticFieldTestTag"}; + } + + [Reflect(false)] private sealed class ProtoIdListInvalid + { + public static List> Tag = new() {string.Empty, "StaticFieldTestTag", string.Empty}; + } + + [Reflect(false)] private sealed class ProtoIdSetValid + { + public static HashSet> Tag = new() {"StaticFieldTestTag", "StaticFieldTestTag"}; + } + + [Reflect(false)] private sealed class ProtoIdSetInvalid + { + public static HashSet> Tag = new() {string.Empty, "StaticFieldTestTag", string.Empty, " "}; + } + + [Reflect(false)] private sealed class PrivateProtoIdArrayValid + { + private static ProtoId[] Tag = {"StaticFieldTestTag", "StaticFieldTestTag"}; + } + + [Reflect(false)] private sealed class PrivateProtoIdArrayInvalid + { + private static ProtoId[] Tag = {string.Empty, "StaticFieldTestTag", string.Empty}; + } +} 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 @@ await server.WaitAssertion(() => 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 @@ await server.WaitAssertion(() => 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 @@ await server.WaitAssertion(() => { 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 @@ await server.WaitAssertion(() => { 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 @@ await server.WaitAssertion(() => { 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 @@ await server.WaitAssertion(() => { 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 @@ await server.WaitAssertion(() => { 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 @@ await server.WaitAssertion(() => { 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 @@ await server.WaitAssertion(() => { var map = mapManager.CreateMap(); var grid = mapManager.CreateGrid(map); + var gridOwner = grid.Owner; // Map layout here is // C - consumer @@ -800,18 +811,18 @@ await server.WaitAssertion(() => 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 @@ await server.WaitAssertion(() => { 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 @@ await server.WaitAssertion(() => 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 @@ await server.WaitAssertion(() => { var map = mapManager.CreateMap(); var grid = mapManager.CreateGrid(map); + var gridOwner = grid.Owner; // Map layout here is // C - consumer @@ -994,18 +1007,18 @@ await server.WaitAssertion(() => 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 @@ await server.WaitPost(() => { 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 @@ await server.WaitAssertion(() => { 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 @@ await server.WaitAssertion(() => 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 @@ await server.WaitAssertion(() => { 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 @@ await server.WaitAssertion(() => 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 @@ await server.WaitAssertion(() => { var map = mapManager.CreateMap(); var grid = mapManager.CreateGrid(map); + var gridOwner = grid.Owner; const int range = 5; @@ -1282,15 +1299,15 @@ await server.WaitAssertion(() => 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..9e26fa5eaa 100644 --- a/Content.IntegrationTests/Tests/PrototypeSaveTest.cs +++ b/Content.IntegrationTests/Tests/PrototypeSaveTest.cs @@ -38,31 +38,15 @@ public async Task UninitializedSaveTest() var mapManager = server.ResolveDependency(); var entityMan = server.ResolveDependency(); var prototypeMan = server.ResolveDependency(); - var tileDefinitionManager = server.ResolveDependency(); var seriMan = server.ResolveDependency(); var compFact = server.ResolveDependency(); var prototypes = new List(); - MapGridComponent grid = default!; EntityUid uid; - MapId mapId = default; - //Build up test environment - await server.WaitPost(() => - { - // Create a one tile grid to stave off the grid 0 monsters - mapId = mapManager.CreateMap(); - - mapManager.AddUninitializedMap(mapId); - - grid = mapManager.CreateGrid(mapId); - - var tileDefinition = tileDefinitionManager["FloorSteel"]; // Wires n such disable ambiance while under the floor - var tile = new Tile(tileDefinition.TileId); - var coordinates = grid.ToCoordinates(); - - grid.SetTile(coordinates, tile); - }); + await pair.CreateTestMap(false, "FloorSteel"); // Wires n such disable ambiance while under the floor + var mapId = pair.TestMap.MapId; + var grid = pair.TestMap.Grid; await server.WaitRunTicks(5); @@ -94,7 +78,7 @@ await server.WaitPost(() => await server.WaitAssertion(() => { Assert.That(!mapManager.IsMapInitialized(mapId)); - var testLocation = grid.ToCoordinates(); + var testLocation = grid.Owner.ToCoordinates(); Assert.Multiple(() => { diff --git a/Content.IntegrationTests/Tests/Puller/PullerTest.cs b/Content.IntegrationTests/Tests/Puller/PullerTest.cs index ba91f54ff7..87d174f727 100644 --- a/Content.IntegrationTests/Tests/Puller/PullerTest.cs +++ b/Content.IntegrationTests/Tests/Puller/PullerTest.cs @@ -1,6 +1,6 @@ using Content.Shared.Hands.Components; +using Content.Shared.Movement.Pulling.Components; using Content.Shared.Prototypes; -using Content.Shared.Pulling.Components; using Robust.Shared.GameObjects; using Robust.Shared.Prototypes; @@ -29,7 +29,7 @@ await server.WaitAssertion(() => { foreach (var proto in protoManager.EnumeratePrototypes()) { - if (!proto.TryGetComponent(out SharedPullerComponent? puller)) + if (!proto.TryGetComponent(out PullerComponent? puller)) continue; if (!puller.NeedsHands) diff --git a/Content.IntegrationTests/Tests/Shuttle/DockTest.cs b/Content.IntegrationTests/Tests/Shuttle/DockTest.cs index b6fc273570..a1aa462a69 100644 --- a/Content.IntegrationTests/Tests/Shuttle/DockTest.cs +++ b/Content.IntegrationTests/Tests/Shuttle/DockTest.cs @@ -39,7 +39,7 @@ public async Task TestDockingConfig(Vector2 dock1Pos, Vector2 dock2Pos, Angle do await server.WaitAssertion(() => { - entManager.DeleteEntity(map.GridUid); + entManager.DeleteEntity(map.Grid); var grid1 = mapManager.CreateGridEntity(mapId); var grid2 = mapManager.CreateGridEntity(mapId); var grid1Ent = grid1.Owner; @@ -104,7 +104,7 @@ public async Task TestPlanetDock() // Spawn shuttle and affirm no valid docks. await server.WaitAssertion(() => { - entManager.DeleteEntity(map.GridUid); + entManager.DeleteEntity(map.Grid); Assert.That(entManager.System().TryLoad(otherMap.MapId, "/Maps/Shuttles/emergency.yml", out var rootUids)); shuttle = rootUids[0]; diff --git a/Content.IntegrationTests/Tests/Tiles/TileConstructionTests.cs b/Content.IntegrationTests/Tests/Tiles/TileConstructionTests.cs index 0a2af88887..083e817d69 100644 --- a/Content.IntegrationTests/Tests/Tiles/TileConstructionTests.cs +++ b/Content.IntegrationTests/Tests/Tiles/TileConstructionTests.cs @@ -37,7 +37,7 @@ public async Task CutThenPlaceLatticeNewGrid() // Remove grid await SetTile(null); await SetTile(null, PlayerCoords); - Assert.That(MapData.MapGrid.Deleted); + Assert.That(MapData.Grid.Comp.Deleted); AssertGridCount(0); // Place Lattice @@ -70,7 +70,7 @@ public async Task FloorConstructDeconstruct() // Remove grid await SetTile(null); await SetTile(null, PlayerCoords); - Assert.That(MapData.MapGrid.Deleted); + Assert.That(MapData.Grid.Comp.Deleted); AssertGridCount(0); // Space -> Lattice diff --git a/Content.Packaging/ClientPackaging.cs b/Content.Packaging/ClientPackaging.cs index a989ebd968..a66d4ec5b9 100644 --- a/Content.Packaging/ClientPackaging.cs +++ b/Content.Packaging/ClientPackaging.cs @@ -13,7 +13,7 @@ public static class ClientPackaging /// /// Be advised this can be called from server packaging during a HybridACZ build. /// - public static async Task PackageClient(bool skipBuild, IPackageLogger logger) + public static async Task PackageClient(bool skipBuild, string configuration, IPackageLogger logger) { logger.Info("Building client..."); @@ -26,7 +26,7 @@ await ProcessHelpers.RunCheck(new ProcessStartInfo { "build", Path.Combine("Content.Client", "Content.Client.csproj"), - "-c", "Release", + "-c", configuration, "--nologo", "/v:m", "/t:Rebuild", diff --git a/Content.Packaging/CommandLineArgs.cs b/Content.Packaging/CommandLineArgs.cs index 9f2b075535..23f661921e 100644 --- a/Content.Packaging/CommandLineArgs.cs +++ b/Content.Packaging/CommandLineArgs.cs @@ -31,6 +31,11 @@ public sealed class CommandLineArgs /// public bool HybridAcz { get; set; } + /// + /// Configuration used for when packaging the server. (Release, Debug, Tools) + /// + public string Configuration { get; set; } + // CommandLineArgs, 3rd of her name. public static bool TryParse(IReadOnlyList args, [NotNullWhen(true)] out CommandLineArgs? parsed) { @@ -39,6 +44,7 @@ public static bool TryParse(IReadOnlyList args, [NotNullWhen(true)] out var skipBuild = false; var wipeRelease = true; var hybridAcz = false; + var configuration = "Release"; List? platforms = null; using var enumerator = args.GetEnumerator(); @@ -89,6 +95,16 @@ public static bool TryParse(IReadOnlyList args, [NotNullWhen(true)] out platforms ??= new List(); platforms.Add(enumerator.Current); } + else if (arg == "--configuration") + { + if (!enumerator.MoveNext()) + { + Console.WriteLine("No configuration provided"); + return false; + } + + configuration = enumerator.Current; + } else if (arg == "--help") { PrintHelp(); @@ -106,7 +122,7 @@ public static bool TryParse(IReadOnlyList args, [NotNullWhen(true)] out return false; } - parsed = new CommandLineArgs(client.Value, skipBuild, wipeRelease, hybridAcz, platforms); + parsed = new CommandLineArgs(client.Value, skipBuild, wipeRelease, hybridAcz, platforms, configuration); return true; } @@ -120,6 +136,7 @@ private static void PrintHelp() --no-wipe-release Don't wipe the release folder before creating files. --hybrid-acz Use HybridACZ for server builds. --platform Platform for server builds. Default will output several x64 targets. + --configuration Configuration to use for building the server (Release, Debug, Tools). Default is Release. "); } @@ -128,12 +145,14 @@ private CommandLineArgs( bool skipBuild, bool wipeRelease, bool hybridAcz, - List? platforms) + List? platforms, + string configuration) { Client = client; SkipBuild = skipBuild; WipeRelease = wipeRelease; HybridAcz = hybridAcz; Platforms = platforms; + Configuration = configuration; } } diff --git a/Content.Packaging/Program.cs b/Content.Packaging/Program.cs index ba5924ec3e..65c0e0131a 100644 --- a/Content.Packaging/Program.cs +++ b/Content.Packaging/Program.cs @@ -17,11 +17,11 @@ if (parsed.Client) { - await ClientPackaging.PackageClient(parsed.SkipBuild, logger); + await ClientPackaging.PackageClient(parsed.SkipBuild, parsed.Configuration, logger); } else { - await ServerPackaging.PackageServer(parsed.SkipBuild, parsed.HybridAcz, logger, parsed.Platforms); + await ServerPackaging.PackageServer(parsed.SkipBuild, parsed.HybridAcz, logger, parsed.Configuration, parsed.Platforms); } void WipeBin() diff --git a/Content.Packaging/ServerPackaging.cs b/Content.Packaging/ServerPackaging.cs index ba489629f7..d9ca57c4d1 100644 --- a/Content.Packaging/ServerPackaging.cs +++ b/Content.Packaging/ServerPackaging.cs @@ -69,7 +69,7 @@ public static class ServerPackaging "zh-Hant" }; - public static async Task PackageServer(bool skipBuild, bool hybridAcz, IPackageLogger logger, List? platforms = null) + public static async Task PackageServer(bool skipBuild, bool hybridAcz, IPackageLogger logger, string configuration, List? platforms = null) { if (platforms == null) { @@ -82,7 +82,7 @@ public static async Task PackageServer(bool skipBuild, bool hybridAcz, IPackageL // Rather than hosting the client ZIP on the watchdog or on a separate server, // Hybrid ACZ uses the ACZ hosting functionality to host it as part of the status host, // which means that features such as automatic UPnP forwarding still work properly. - await ClientPackaging.PackageClient(skipBuild, logger); + await ClientPackaging.PackageClient(skipBuild, configuration, logger); } // Good variable naming right here. @@ -91,13 +91,13 @@ public static async Task PackageServer(bool skipBuild, bool hybridAcz, IPackageL if (!platforms.Contains(platform.Rid)) continue; - await BuildPlatform(platform, skipBuild, hybridAcz, logger); + await BuildPlatform(platform, skipBuild, hybridAcz, configuration, logger); } } - private static async Task BuildPlatform(PlatformReg platform, bool skipBuild, bool hybridAcz, IPackageLogger logger) + private static async Task BuildPlatform(PlatformReg platform, bool skipBuild, bool hybridAcz, string configuration, IPackageLogger logger) { - logger.Info($"Building project for {platform}..."); + logger.Info($"Building project for {platform.TargetOs}..."); if (!skipBuild) { @@ -108,7 +108,7 @@ await ProcessHelpers.RunCheck(new ProcessStartInfo { "build", Path.Combine("Content.Server", "Content.Server.csproj"), - "-c", "Release", + "-c", configuration, "--nologo", "/v:m", $"/p:TargetOs={platform.TargetOs}", @@ -118,7 +118,7 @@ await ProcessHelpers.RunCheck(new ProcessStartInfo } }); - await PublishClientServer(platform.Rid, platform.TargetOs); + await PublishClientServer(platform.Rid, platform.TargetOs, configuration); } logger.Info($"Packaging {platform.Rid} server..."); @@ -137,7 +137,7 @@ await ProcessHelpers.RunCheck(new ProcessStartInfo logger.Info($"Finished packaging server in {sw.Elapsed}"); } - private static async Task PublishClientServer(string runtime, string targetOs) + private static async Task PublishClientServer(string runtime, string targetOs, string configuration) { await ProcessHelpers.RunCheck(new ProcessStartInfo { @@ -147,7 +147,7 @@ await ProcessHelpers.RunCheck(new ProcessStartInfo "publish", "--runtime", runtime, "--no-self-contained", - "-c", "Release", + "-c", configuration, $"/p:TargetOs={targetOs}", "/p:FullRelease=True", "/m", diff --git a/Content.Server/Administration/Commands/AdminWhoCommand.cs b/Content.Server/Administration/Commands/AdminWhoCommand.cs index 9765e8385f..cf2f8c453c 100644 --- a/Content.Server/Administration/Commands/AdminWhoCommand.cs +++ b/Content.Server/Administration/Commands/AdminWhoCommand.cs @@ -19,6 +19,16 @@ public void Execute(IConsoleShell shell, string argStr, string[] args) var adminMgr = IoCManager.Resolve(); var afk = IoCManager.Resolve(); + var seeStealth = true; + + // If null it (hopefully) means it is being called from the console. + if (shell.Player != null) + { + var playerData = adminMgr.GetAdminData(shell.Player); + + seeStealth = playerData != null && playerData.CanStealth(); + } + var sb = new StringBuilder(); var first = true; foreach (var admin in adminMgr.ActiveAdmins) @@ -30,10 +40,16 @@ public void Execute(IConsoleShell shell, string argStr, string[] args) var adminData = adminMgr.GetAdminData(admin)!; DebugTools.AssertNotNull(adminData); + if (adminData.Stealth && !seeStealth) + continue; + sb.Append(admin.Name); if (adminData.Title is { } title) sb.Append($": [{title}]"); + if (adminData.Stealth) + sb.Append(" (S)"); + if (shell.Player is { } player && adminMgr.HasAdminFlag(player, AdminFlags.Admin)) { if (afk.IsAfk(admin)) 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/PlayGlobalSoundCommand.cs b/Content.Server/Administration/Commands/PlayGlobalSoundCommand.cs index ac55ce8325..f1a5a57aa6 100644 --- a/Content.Server/Administration/Commands/PlayGlobalSoundCommand.cs +++ b/Content.Server/Administration/Commands/PlayGlobalSoundCommand.cs @@ -6,6 +6,7 @@ using Robust.Shared.Console; using Robust.Shared.ContentPack; using Robust.Shared.Player; +using Robust.Shared.Prototypes; namespace Content.Server.Administration.Commands; @@ -14,6 +15,7 @@ public sealed class PlayGlobalSoundCommand : IConsoleCommand { [Dependency] private readonly IEntityManager _entManager = default!; [Dependency] private readonly IPlayerManager _playerManager = default!; + [Dependency] private readonly IPrototypeManager _protoManager = default!; [Dependency] private readonly IResourceManager _res = default!; public string Command => "playglobalsound"; @@ -95,7 +97,7 @@ public CompletionResult GetCompletion(IConsoleShell shell, string[] args) { var hint = Loc.GetString("play-global-sound-command-arg-path"); - var options = CompletionHelper.ContentFilePath(args[0], _res); + var options = CompletionHelper.AudioFilePath(args[0], _protoManager, _res); return CompletionResult.FromHintOptions(options, hint); } diff --git a/Content.Server/Administration/Commands/StealthminCommand.cs b/Content.Server/Administration/Commands/StealthminCommand.cs new file mode 100644 index 0000000000..aa0e77a794 --- /dev/null +++ b/Content.Server/Administration/Commands/StealthminCommand.cs @@ -0,0 +1,34 @@ +using Content.Server.Administration.Managers; +using Content.Shared.Administration; +using JetBrains.Annotations; +using Robust.Shared.Console; +using Robust.Shared.Utility; + +namespace Content.Server.Administration.Commands; + +[UsedImplicitly] +[AdminCommand(AdminFlags.Stealth)] +public sealed class StealthminCommand : LocalizedCommands +{ + public override string Command => "stealthmin"; + + public override void Execute(IConsoleShell shell, string argStr, string[] args) + { + var player = shell.Player; + if (player == null) + { + shell.WriteLine(Loc.GetString("cmd-stealthmin-no-console")); + return; + } + + var mgr = IoCManager.Resolve(); + var adminData = mgr.GetAdminData(player); + + DebugTools.AssertNotNull(adminData); + + if (!adminData!.Stealth) + mgr.Stealth(player); + else + mgr.UnStealth(player); + } +} 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 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 57d6e089bd..8fb28b7ec4 100644 --- a/Content.Server/Administration/Managers/AdminManager.cs +++ b/Content.Server/Administration/Managers/AdminManager.cs @@ -98,6 +98,40 @@ public void DeAdmin(ICommonSession session) UpdateAdminStatus(session); } + public void Stealth(ICommonSession session) + { + if (!_admins.TryGetValue(session, out var reg)) + throw new ArgumentException($"Player {session} is not an admin"); + + if (reg.Data.Stealth) + return; + + var playerData = session.ContentData()!; + playerData.Stealthed = true; + reg.Data.Stealth = true; + + _chat.DispatchServerMessage(session, Loc.GetString("admin-manager-stealthed-message")); + _chat.SendAdminAnnouncement(Loc.GetString("admin-manager-self-de-admin-message", ("exAdminName", session.Name)), AdminFlags.Stealth); + _chat.SendAdminAnnouncement(Loc.GetString("admin-manager-self-enable-stealth", ("stealthAdminName", session.Name)), flagWhitelist: AdminFlags.Stealth); + } + + public void UnStealth(ICommonSession session) + { + if (!_admins.TryGetValue(session, out var reg)) + throw new ArgumentException($"Player {session} is not an admin"); + + if (!reg.Data.Stealth) + return; + + var playerData = session.ContentData()!; + playerData.Stealthed = false; + reg.Data.Stealth = false; + + _chat.DispatchServerMessage(session, Loc.GetString("admin-manager-unstealthed-message")); + _chat.SendAdminAnnouncement(Loc.GetString("admin-manager-self-re-admin-message", ("newAdminName", session.Name)), flagBlacklist: AdminFlags.Stealth); + _chat.SendAdminAnnouncement(Loc.GetString("admin-manager-self-disable-stealth", ("exStealthAdminName", session.Name)), flagWhitelist: AdminFlags.Stealth); + } + public void ReAdmin(ICommonSession session) { if (!_admins.TryGetValue(session, out var reg)) @@ -116,7 +150,16 @@ public void ReAdmin(ICommonSession session) plyData.ExplicitlyDeadminned = false; reg.Data.Active = true; - _chat.SendAdminAnnouncement(Loc.GetString("admin-manager-self-re-admin-message", ("newAdminName", session.Name))); + if (reg.Data.Stealth) + { + _chat.SendAdminAnnouncement(Loc.GetString("admin-manager-self-re-admin-message", ("newAdminName", session.Name))); + } + else + { + _chat.DispatchServerMessage(session, Loc.GetString("admin-manager-stealthed-message")); + _chat.SendAdminAnnouncement(Loc.GetString("admin-manager-self-re-admin-message", + ("newAdminName", session.Name)), flagWhitelist: AdminFlags.Stealth); + } SendPermsChangedEvent(session); UpdateAdminStatus(session); @@ -168,6 +211,9 @@ public async void ReloadAdmin(ICommonSession player) _chat.DispatchServerMessage(player, Loc.GetString("admin-manager-admin-permissions-updated-message")); } + + if (player.ContentData()!.Stealthed) + aData.Stealth = true; } SendPermsChangedEvent(player); @@ -290,9 +336,14 @@ private void PlayerStatusChanged(object? sender, SessionStatusEventArgs e) } else if (e.NewStatus == SessionStatus.Disconnected) { - if (_admins.Remove(e.Session) && _cfg.GetCVar(CCVars.AdminAnnounceLogout)) + if (_admins.Remove(e.Session, out var reg ) && _cfg.GetCVar(CCVars.AdminAnnounceLogout)) { - _chat.SendAdminAnnouncement(Loc.GetString("admin-manager-admin-logout-message", ("name", e.Session.Name))); + if (reg.Data.Stealth) + _chat.SendAdminAnnouncement(Loc.GetString("admin-manager-admin-logout-message", + ("name", e.Session.Name)), flagWhitelist: AdminFlags.Stealth); + else + _chat.SendAdminAnnouncement(Loc.GetString("admin-manager-admin-logout-message", + ("name", e.Session.Name))); } } } @@ -315,13 +366,27 @@ private async void LoginAdminMaybe(ICommonSession session) _admins.Add(session, reg); + if (session.ContentData()!.Stealthed) + reg.Data.Stealth = true; + if (!session.ContentData()?.ExplicitlyDeadminned ?? false) { reg.Data.Active = true; if (_cfg.GetCVar(CCVars.AdminAnnounceLogin)) { - _chat.SendAdminAnnouncement(Loc.GetString("admin-manager-admin-login-message", ("name", session.Name))); + if (reg.Data.Stealth) + { + + _chat.DispatchServerMessage(session, Loc.GetString("admin-manager-stealthed-message")); + _chat.SendAdminAnnouncement(Loc.GetString("admin-manager-admin-login-message", + ("name", session.Name)), flagWhitelist: AdminFlags.Stealth); + } + else + { + _chat.SendAdminAnnouncement(Loc.GetString("admin-manager-admin-login-message", + ("name", session.Name))); + } } SendPermsChangedEvent(session); diff --git a/Content.Server/Administration/Managers/IAdminManager.cs b/Content.Server/Administration/Managers/IAdminManager.cs index a52ec7b099..95967b24ac 100644 --- a/Content.Server/Administration/Managers/IAdminManager.cs +++ b/Content.Server/Administration/Managers/IAdminManager.cs @@ -41,6 +41,16 @@ public interface IAdminManager : ISharedAdminManager /// void ReAdmin(ICommonSession session); + /// + /// Make admin hidden from adminwho. + /// + void Stealth(ICommonSession session); + + /// + /// Unhide admin from adminwho. + /// + void UnStealth(ICommonSession session); + /// /// Re-loads the permissions of an player in case their admin data changed DB-side. /// diff --git a/Content.Server/Alert/Click/StopBeingPulled.cs b/Content.Server/Alert/Click/StopBeingPulled.cs index 2cf076fbee..b02da38ecf 100644 --- a/Content.Server/Alert/Click/StopBeingPulled.cs +++ b/Content.Server/Alert/Click/StopBeingPulled.cs @@ -1,7 +1,7 @@ using Content.Shared.ActionBlocker; using Content.Shared.Alert; -using Content.Shared.Pulling.Components; -using Content.Shared.Pulling; +using Content.Shared.Movement.Pulling.Components; +using Content.Shared.Movement.Pulling.Systems; using JetBrains.Annotations; namespace Content.Server.Alert.Click @@ -20,9 +20,9 @@ public void AlertClicked(EntityUid player) if (!entityManager.System().CanInteract(player, null)) return; - if (entityManager.TryGetComponent(player, out SharedPullableComponent? playerPullable)) + if (entityManager.TryGetComponent(player, out PullableComponent? playerPullable)) { - entityManager.System().TryStopPull(playerPullable); + entityManager.System().TryStopPull(player, playerPullable, user: player); } } } diff --git a/Content.Server/Alert/Click/StopPulling.cs b/Content.Server/Alert/Click/StopPulling.cs index 00a4149598..76f9569429 100644 --- a/Content.Server/Alert/Click/StopPulling.cs +++ b/Content.Server/Alert/Click/StopPulling.cs @@ -1,6 +1,6 @@ using Content.Shared.Alert; -using Content.Shared.Pulling; -using Content.Shared.Pulling.Components; +using Content.Shared.Movement.Pulling.Components; +using Content.Shared.Movement.Pulling.Systems; using JetBrains.Annotations; namespace Content.Server.Alert.Click @@ -15,12 +15,12 @@ public sealed partial class StopPulling : IAlertClick public void AlertClicked(EntityUid player) { var entManager = IoCManager.Resolve(); + var ps = entManager.System(); - var ps = entManager.System(); - var playerTarget = ps.GetPulled(player); - if (playerTarget != default && entManager.TryGetComponent(playerTarget, out SharedPullableComponent? playerPullable)) + if (entManager.TryGetComponent(player, out PullerComponent? puller) && + entManager.TryGetComponent(puller.Pulling, out PullableComponent? pullableComp)) { - ps.TryStopPull(playerPullable); + ps.TryStopPull(puller.Pulling.Value, pullableComp, user: player); } } } diff --git a/Content.Server/Anomaly/AnomalySystem.Generator.cs b/Content.Server/Anomaly/AnomalySystem.Generator.cs index 2053a7bbbe..e03c566593 100644 --- a/Content.Server/Anomaly/AnomalySystem.Generator.cs +++ b/Content.Server/Anomaly/AnomalySystem.Generator.cs @@ -24,7 +24,7 @@ namespace Content.Server.Anomaly; /// public sealed partial class AnomalySystem { - [Dependency] private readonly MapSystem _mapSystem = default!; + [Dependency] private readonly SharedMapSystem _mapSystem = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; private void InitializeGenerator() 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.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 @@ private void OnPulse(EntityUid uid, BluespaceAnomalyComponent component, ref Ano 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.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 a5e42be540..2408ad0b3d 100644 --- a/Content.Server/Anomaly/Effects/GasProducerAnomalySystem.cs +++ b/Content.Server/Anomaly/Effects/GasProducerAnomalySystem.cs @@ -2,11 +2,10 @@ using Content.Server.Anomaly.Components; using Content.Shared.Anomaly.Components; using Content.Shared.Atmos; -using Robust.Server.GameObjects; -using Robust.Shared.Map; using Robust.Shared.Random; using System.Linq; using System.Numerics; +using Robust.Shared.Map.Components; namespace Content.Server.Anomaly.Effects; @@ -16,8 +15,6 @@ namespace Content.Server.Anomaly.Effects; public sealed class GasProducerAnomalySystem : EntitySystem { [Dependency] private readonly AtmosphereSystem _atmosphere = default!; - [Dependency] private readonly TransformSystem _xform = default!; - [Dependency] private readonly IMapManager _map = default!; [Dependency] private readonly IRobustRandom _random = default!; public override void Initialize() @@ -55,7 +52,7 @@ private void ReleaseGas(EntityUid uid, Gas gas, float mols, float radius, int co { var xform = Transform(uid); - if (!_map.TryGetGrid(xform.GridUid, out var grid)) + if (!TryComp(xform.GridUid, out var grid)) return; var localpos = xform.Coordinates.Position; diff --git a/Content.Server/Atmos/Commands/DeleteGasCommand.cs b/Content.Server/Atmos/Commands/DeleteGasCommand.cs index 9e7594c024..f4279db926 100644 --- a/Content.Server/Atmos/Commands/DeleteGasCommand.cs +++ b/Content.Server/Atmos/Commands/DeleteGasCommand.cs @@ -3,7 +3,7 @@ using Content.Shared.Administration; using Content.Shared.Atmos; using Robust.Shared.Console; -using Robust.Shared.Map; +using Robust.Shared.Map.Components; namespace Content.Server.Atmos.Commands { @@ -11,7 +11,6 @@ namespace Content.Server.Atmos.Commands public sealed class DeleteGasCommand : IConsoleCommand { [Dependency] private readonly IEntityManager _entManager = default!; - [Dependency] private readonly IMapManager _mapManager = default!; public string Command => "deletegas"; public string Description => "Removes all gases from a grid, or just of one type if specified."; @@ -119,7 +118,7 @@ public void Execute(IConsoleShell shell, string argStr, string[] args) return; } - if (!_mapManager.TryGetGrid(gridId, out _)) + if (!_entManager.TryGetComponent(gridId, out _)) { shell.WriteLine($"No grid exists with id {gridId}"); return; 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/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.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 @@ public sealed class GasTankSystem : EntitySystem [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/EntitySystems/AtmosPipeAppearanceSystem.cs b/Content.Server/Atmos/Piping/EntitySystems/AtmosPipeAppearanceSystem.cs index 6fbf60f403..10049e273b 100644 --- a/Content.Server/Atmos/Piping/EntitySystems/AtmosPipeAppearanceSystem.cs +++ b/Content.Server/Atmos/Piping/EntitySystems/AtmosPipeAppearanceSystem.cs @@ -3,14 +3,12 @@ using Content.Server.NodeContainer.Nodes; using Content.Shared.Atmos; using Content.Shared.Atmos.Components; -using Robust.Server.GameObjects; -using Robust.Shared.Map; +using Robust.Shared.Map.Components; namespace Content.Server.Atmos.Piping.EntitySystems; public sealed class AtmosPipeAppearanceSystem : EntitySystem { - [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly SharedAppearanceSystem _appearance = default!; public override void Initialize() @@ -31,7 +29,7 @@ private void UpdateAppearance(EntityUid uid, AppearanceComponent? appearance = n if (!Resolve(uid, ref appearance, ref container, ref xform, false)) return; - if (!_mapManager.TryGetGrid(xform.GridUid, out var grid)) + if (!TryComp(xform.GridUid, out var grid)) return; // get connected entities 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.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/GasPortableSystem.cs b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasPortableSystem.cs index b1caa6c197..4ddd19dd45 100644 --- a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasPortableSystem.cs +++ b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasPortableSystem.cs @@ -7,15 +7,14 @@ using Content.Shared.Atmos.Piping.Unary.Components; using Content.Shared.Construction.Components; using JetBrains.Annotations; -using Robust.Server.GameObjects; using Robust.Shared.Map; +using Robust.Shared.Map.Components; namespace Content.Server.Atmos.Piping.Unary.EntitySystems { [UsedImplicitly] public sealed class GasPortableSystem : EntitySystem { - [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly SharedAppearanceSystem _appearance = default!; [Dependency] private readonly NodeContainerSystem _nodeContainer = default!; @@ -58,7 +57,7 @@ public bool FindGasPortIn(EntityUid? gridId, EntityCoordinates coordinates, [Not { port = null; - if (!_mapManager.TryGetGrid(gridId, out var grid)) + if (!TryComp(gridId, out var grid)) return false; foreach (var entityUid in grid.GetLocal(coordinates)) diff --git a/Content.Server/Bed/BedSystem.cs b/Content.Server/Bed/BedSystem.cs index 9e622ba6b8..3bb191fecd 100644 --- a/Content.Server/Bed/BedSystem.cs +++ b/Content.Server/Bed/BedSystem.cs @@ -94,9 +94,8 @@ private void OnBuckleChange(EntityUid uid, StasisBedComponent component, ref Buc 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) @@ -122,9 +121,8 @@ private void UpdateMetabolisms(EntityUid uid, StasisBedComponent component, bool 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/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 @@ public void Execute(IConsoleShell shell, string argStr, string[] args) switch (args.Length) { case 0: - { if (player == null) { shell.WriteLine("Only a player can run this command without arguments."); @@ -50,71 +49,68 @@ public void Execute(IConsoleShell shell, string argStr, string[] args) 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 (!_entManager.EntityExists(uid)) + if (NetEntity.TryParse(args[0], out var uidNet) && _entManager.TryGetEntity(uidNet, out var uid)) { - shell.WriteLine($"No entity found with uid {uid}"); - return; + 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); } - entity = uid.Value; - hand = _entManager.SpawnEntity(DefaultHandPrototype, _entManager.GetComponent(entity).Coordinates); + break; } - else + case 2: { - if (player == null) + if (!NetEntity.TryParse(args[0], out var netEnt) || !_entManager.TryGetEntity(netEnt, out var uid)) { - shell.WriteLine("You must specify an entity to add a hand to when using this command from the server terminal."); + shell.WriteLine($"{args[0]} is not a valid entity uid."); return; } - if (player.AttachedEntity == null) + if (!_entManager.EntityExists(uid)) { - shell.WriteLine("You don't have an entity to add a hand to."); + shell.WriteLine($"No entity exists with uid {uid}."); 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; - } + entity = uid.Value; - if (!_entManager.EntityExists(uid)) - { - shell.WriteLine($"No entity exists with uid {uid}."); - return; - } + if (!_protoManager.HasIndex(args[1])) + { + shell.WriteLine($"No hand entity exists with id {args[1]}."); + return; + } - entity = uid.Value; + hand = _entManager.SpawnEntity(args[1], _entManager.GetComponent(entity).Coordinates); - if (!_protoManager.HasIndex(args[1])) - { - shell.WriteLine($"No hand entity exists with id {args[1]}."); - return; + break; } - - 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 @@ public void Execute(IConsoleShell shell, string argStr, string[] args) 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 @@ public void Execute(IConsoleShell shell, string argStr, string[] args) // 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 @@ public sealed partial class BloodstreamComponent : Component 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 @@ public sealed partial class BloodstreamComponent : Component 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 @@ public sealed partial class BloodstreamComponent : Component [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 @@ public sealed partial class BloodstreamComponent : Component /// /// 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 @@ public sealed partial class BloodstreamComponent : Component /// 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 @@ public sealed partial class BloodstreamComponent : Component /// 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 @@ public sealed partial class MetabolizerComponent : Component /// /// 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 @@ public sealed partial class MetabolizerComponent : Component [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 @@ public sealed partial class RespiratorComponent : Component [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 @@ public sealed partial class StomachComponent : Component 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 @@ public sealed partial class StomachComponent : Component 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.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 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 override void Initialize() base.Initialize(); SubscribeLocalEvent(OnComponentInit); + SubscribeLocalEvent(OnMapInit); + SubscribeLocalEvent(OnUnpaused); SubscribeLocalEvent(OnDamageChanged); SubscribeLocalEvent(OnHealthBeingExamined); SubscribeLocalEvent(OnBeingGibbed); @@ -53,6 +56,16 @@ public override void Initialize() 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 @@ private void OnReactionAttempt(Entity entity, ref Solution 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 override void Update(float frameTime) 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 override void Update(float frameTime) // 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 override void Update(float frameTime) 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 @@ private void OnComponentInit(Entity entity, ref ComponentI 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 @@ private void OnDamageChanged(EntityUid uid, BloodstreamComponent component, Dama 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 @@ private void OnDamageChanged(EntityUid uid, BloodstreamComponent component, Dama 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 @@ private void OnDamageChanged(EntityUid uid, BloodstreamComponent component, Dama // 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 @@ private void OnRejuvenate(Entity entity, ref RejuvenateEve /// 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 bool FlushChemicals(EntityUid uid, string excludedReagentID, FixedPoint2 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 void SetBloodLossThreshold(EntityUid uid, float threshold, BloodstreamCom /// 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 bool TryModifyBloodLevel(EntityUid uid, FixedPoint2 amount, BloodstreamCo 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 bool TryModifyBloodLevel(EntityUid uid, FixedPoint2 amount, BloodstreamCo /// 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 void SpillAllSolutions(EntityUid uid, BloodstreamComponent? component = n if (_puddleSystem.TrySpillAt(uid, tempSol, out var puddleUid)) { - _forensicsSystem.TransferDna(puddleUid, uid, false); + _forensicsSystem.TransferDna(puddleUid, uid, canDnaBeCleaned: false); } } @@ -433,11 +444,11 @@ public void SpillAllSolutions(EntityUid uid, BloodstreamComponent? component = n /// 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..37f78ed81a 100644 --- a/Content.Server/Body/Systems/BodySystem.cs +++ b/Content.Server/Body/Systems/BodySystem.cs @@ -1,23 +1,19 @@ 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.Audio.Systems; 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; @@ -28,9 +24,7 @@ public sealed class BodySystem : SharedBodySystem [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 +34,7 @@ public override void Initialize() 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 +43,67 @@ private void OnRelayMoveInput(EntityUid uid, BodyComponent component, ref MoveIn 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 +111,23 @@ public override HashSet GibBody( 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 @@ public override void Initialize() { 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 @@ private void HandleMind(EntityUid newEntity, EntityUid oldEntity) _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 007cbdf084..9607a808f6 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.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 override void Initialize() 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 void ToggleInternals(EntityUid uid, EntityUid user, bool force, Internals 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 void ToggleInternals(EntityUid uid, EntityUid user, bool force, Internals 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 void ToggleInternals(EntityUid uid, EntityUid user, bool force, Internals 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) { BreakOnUserMove = true, BreakOnDamage = true, @@ -116,66 +120,64 @@ private void StartToggleInternalsDoAfter(EntityUid user, EntityUid target, Inter }); } - 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)) @@ -187,46 +189,47 @@ public void DisconnectTank(InternalsComponent? component) 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 @@ -234,17 +237,17 @@ private short GetSeverity(InternalsComponent component) // 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 override void Initialize() 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 void GasToReagent(EntityUid uid, LungComponent lung) 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 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 @@ public override void Initialize() _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 @@ private void OnMetabolizerInit(Entity entity, ref Componen } } - 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 @@ public override void Update(float frameTime) 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 @@ private void TryMetabolize(EntityUid uid, MetabolizerComponent meta, OrganCompon 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 @@ private void TryMetabolize(EntityUid uid, MetabolizerComponent meta, OrganCompon } // 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 @@ private void TryMetabolize(EntityUid uid, MetabolizerComponent meta, OrganCompon // 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 @@ private void TryMetabolize(EntityUid uid, MetabolizerComponent meta, OrganCompon 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 @@ private void TryMetabolize(EntityUid uid, MetabolizerComponent meta, OrganCompon } } - 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; - - // What the metabolism's update rate will be multiplied by - public float Multiplier; - - // Apply this multiplier or ignore / reset it? - public bool Apply; + /// + /// The entity whose metabolism is being modified. + /// + public readonly EntityUid Uid = Uid; + + /// + /// What the metabolism's update rate will be multiplied by. + /// + public readonly float Multiplier = Multiplier; + + /// + /// 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 override void Initialize() // 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 override void Update(float frameTime) var query = EntityQueryEnumerator(); while (query.MoveNext(out var uid, out var respirator, out var body)) { - if (_mobState.IsDead(uid)) - { + if (_gameTiming.CurTime < respirator.NextUpdate) continue; - } - respirator.AccumulatedFrametime += frameTime; + respirator.NextUpdate += respirator.UpdateInterval; - if (respirator.AccumulatedFrametime < respirator.CycleDelay) + if (_mobState.IsDead(uid)) 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 override void Update(float frameTime) _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 void Inhale(EntityUid uid, BodyComponent? body = null) 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(uid, body); @@ -130,11 +140,11 @@ public void Exhale(EntityUid uid, BodyComponent? body = null) // exhale gas var ev = new ExhaleLocationEvent(); - RaiseLocalEvent(uid, ev, false); + RaiseLocalEvent(uid, ref ev, broadcast: false); - if (ev.Gas == null) + if (ev.Gas is null) { - ev.Gas = _atmosSys.GetContainingMixture(uid, false, true); + ev.Gas = _atmosSys.GetContainingMixture(uid, excite: true); // Walls and grids without atmos comp return null. I guess it makes sense to not be able to exhale in walls, // but this also means you cannot exhale on some grids. @@ -154,37 +164,37 @@ public void Exhale(EntityUid uid, BodyComponent? body = null) _atmosSys.Merge(ev.Gas, outGas); } - private void TakeSuffocationDamage(EntityUid uid, RespiratorComponent respirator) + private void TakeSuffocationDamage(Entity ent) { - if (respirator.SuffocationCycles == 2) - _adminLogger.Add(LogType.Asphyxiation, $"{ToPrettyString(uid):entity} started suffocating"); + if (ent.Comp.SuffocationCycles == 2) + _adminLogger.Add(LogType.Asphyxiation, $"{ToPrettyString(ent):entity} started suffocating"); - if (respirator.SuffocationCycles >= respirator.SuffocationCycleThreshold) + if (ent.Comp.SuffocationCycles >= ent.Comp.SuffocationCycleThreshold) { // TODO: This is not going work with multiple different lungs, if that ever becomes a possibility - var organs = _bodySystem.GetBodyOrganComponents(uid); + var organs = _bodySystem.GetBodyOrganComponents(ent); foreach (var (comp, _) in organs) { - _alertsSystem.ShowAlert(uid, comp.Alert); + _alertsSystem.ShowAlert(ent, comp.Alert); } } - _damageableSys.TryChangeDamage(uid, respirator.Damage, false, false); + _damageableSys.TryChangeDamage(ent, ent.Comp.Damage, interruptsDoAfters: false); } - private void StopSuffocation(EntityUid uid, RespiratorComponent respirator) + private void StopSuffocation(Entity ent) { - if (respirator.SuffocationCycles >= 2) - _adminLogger.Add(LogType.Asphyxiation, $"{ToPrettyString(uid):entity} stopped suffocating"); + if (ent.Comp.SuffocationCycles >= 2) + _adminLogger.Add(LogType.Asphyxiation, $"{ToPrettyString(ent):entity} stopped suffocating"); // TODO: This is not going work with multiple different lungs, if that ever becomes a possibility - var organs = _bodySystem.GetBodyOrganComponents(uid); + var organs = _bodySystem.GetBodyOrganComponents(ent); foreach (var (comp, _) in organs) { - _alertsSystem.ClearAlert(uid, comp.Alert); + _alertsSystem.ClearAlert(ent, comp.Alert); } - _damageableSys.TryChangeDamage(uid, respirator.DamageRecovery); + _damageableSys.TryChangeDamage(ent, ent.Comp.DamageRecovery); } public void UpdateSaturation(EntityUid uid, float amount, @@ -198,35 +208,29 @@ public void UpdateSaturation(EntityUid uid, float amount, Math.Clamp(respirator.Saturation, respirator.MinSaturation, respirator.MaxSaturation); } - private void OnApplyMetabolicMultiplier(EntityUid uid, RespiratorComponent component, - ApplyMetabolicMultiplierEvent args) + private void OnApplyMetabolicMultiplier( + Entity ent, + ref ApplyMetabolicMultiplierEvent args) { if (args.Apply) { - component.CycleDelay *= args.Multiplier; - component.Saturation *= args.Multiplier; - component.MaxSaturation *= args.Multiplier; - component.MinSaturation *= args.Multiplier; + ent.Comp.UpdateInterval *= args.Multiplier; + ent.Comp.Saturation *= args.Multiplier; + ent.Comp.MaxSaturation *= args.Multiplier; + ent.Comp.MinSaturation *= args.Multiplier; return; } // This way we don't have to worry about it breaking if the stasis bed component is destroyed - component.CycleDelay /= args.Multiplier; - component.Saturation /= args.Multiplier; - component.MaxSaturation /= args.Multiplier; - component.MinSaturation /= args.Multiplier; - // Reset the accumulator properly - if (component.AccumulatedFrametime >= component.CycleDelay) - component.AccumulatedFrametime = component.CycleDelay; + ent.Comp.UpdateInterval /= args.Multiplier; + ent.Comp.Saturation /= args.Multiplier; + ent.Comp.MaxSaturation /= args.Multiplier; + ent.Comp.MinSaturation /= args.Multiplier; } } -public sealed class InhaleLocationEvent : EntityEventArgs -{ - public GasMixture? Gas; -} +[ByRefEvent] +public record struct InhaleLocationEvent(GasMixture? Gas); -public sealed class ExhaleLocationEvent : EntityEventArgs -{ - public GasMixture? Gas; -} +[ByRefEvent] +public record struct ExhaleLocationEvent(GasMixture? Gas); diff --git a/Content.Server/Body/Systems/StomachSystem.cs b/Content.Server/Body/Systems/StomachSystem.cs index 4c11244c37..a4c2e8292d 100644 --- a/Content.Server/Body/Systems/StomachSystem.cs +++ b/Content.Server/Body/Systems/StomachSystem.cs @@ -3,32 +3,44 @@ using Content.Shared.Body.Organ; using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.Components.SolutionManager; +using Robust.Shared.Timing; using Robust.Shared.Utility; namespace Content.Server.Body.Systems { public sealed class StomachSystem : EntitySystem { + [Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!; public const string DefaultSolutionName = "stomach"; public override void Initialize() { + 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) { var query = EntityQueryEnumerator(); while (query.MoveNext(out var uid, out var stomach, out var organ, out var sol)) { - stomach.AccumulatedFrameTime += frameTime; - - if (stomach.AccumulatedFrameTime < stomach.UpdateInterval) + if (_gameTiming.CurTime < stomach.NextUpdate) continue; - stomach.AccumulatedFrameTime -= stomach.UpdateInterval; + stomach.NextUpdate += stomach.UpdateInterval; // Get our solutions if (!_solutionContainerSystem.ResolveSolution((uid, sol), DefaultSolutionName, ref stomach.Solution, out var stomachSolution)) @@ -70,49 +82,44 @@ public override void Update(float frameTime) } } - private void OnApplyMetabolicMultiplier(EntityUid uid, StomachComponent component, - ApplyMetabolicMultiplierEvent args) + private void OnApplyMetabolicMultiplier( + Entity ent, + ref ApplyMetabolicMultiplierEvent args) { if (args.Apply) { - component.UpdateInterval *= args.Multiplier; + ent.Comp.UpdateInterval *= args.Multiplier; return; } // This way we don't have to worry about it breaking if the stasis bed component is destroyed - component.UpdateInterval /= args.Multiplier; - // Reset the accumulator properly - if (component.AccumulatedFrameTime >= component.UpdateInterval) - component.AccumulatedFrameTime = component.UpdateInterval; + ent.Comp.UpdateInterval /= args.Multiplier; } - public bool CanTransferSolution(EntityUid uid, Solution solution, + public bool CanTransferSolution( + EntityUid uid, + Solution solution, StomachComponent? stomach = null, SolutionContainerManagerComponent? solutions = null) { - if (!Resolve(uid, ref stomach, ref solutions, false)) - return false; - - if (!_solutionContainerSystem.ResolveSolution((uid, solutions), DefaultSolutionName, ref stomach.Solution, out var stomachSolution)) - return false; - - // TODO: For now no partial transfers. Potentially change by design - if (!stomachSolution.CanAddSolution(solution)) - return false; - - return true; + return Resolve(uid, ref stomach, ref solutions, logMissing: false) + && _solutionContainerSystem.ResolveSolution((uid, solutions), DefaultSolutionName, ref stomach.Solution, out var stomachSolution) + // TODO: For now no partial transfers. Potentially change by design + && stomachSolution.CanAddSolution(solution); } - public bool TryTransferSolution(EntityUid uid, Solution solution, + public bool TryTransferSolution( + EntityUid uid, + Solution solution, StomachComponent? stomach = null, SolutionContainerManagerComponent? solutions = null) { - if (!Resolve(uid, ref stomach, ref solutions, false)) - return false; - - if (!_solutionContainerSystem.ResolveSolution((uid, solutions), DefaultSolutionName, ref stomach.Solution) + if (!Resolve(uid, ref stomach, ref solutions, logMissing: false) + || !_solutionContainerSystem.ResolveSolution((uid, solutions), DefaultSolutionName, ref stomach.Solution) || !CanTransferSolution(uid, solution, stomach, solutions)) + { return false; + } _solutionContainerSystem.TryAddSolution(stomach.Solution.Value, solution); // Add each reagent to ReagentDeltas. Used to track how long each reagent has been in the stomach diff --git a/Content.Server/Body/Systems/ThermalRegulatorSystem.cs b/Content.Server/Body/Systems/ThermalRegulatorSystem.cs index a9556be773..a8bf4184ac 100644 --- a/Content.Server/Body/Systems/ThermalRegulatorSystem.cs +++ b/Content.Server/Body/Systems/ThermalRegulatorSystem.cs @@ -1,73 +1,95 @@ -using Content.Server.Body.Components; +using Content.Server.Body.Components; using Content.Server.Temperature.Components; using Content.Server.Temperature.Systems; using Content.Shared.ActionBlocker; +using Robust.Shared.Timing; namespace Content.Server.Body.Systems; public sealed class ThermalRegulatorSystem : EntitySystem { + [Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly TemperatureSystem _tempSys = default!; [Dependency] private readonly ActionBlockerSystem _actionBlockerSys = default!; + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnMapInit); + SubscribeLocalEvent(OnUnpaused); + } + + 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) { var query = EntityQueryEnumerator(); while (query.MoveNext(out var uid, out var regulator)) { - regulator.AccumulatedFrametime += frameTime; - if (regulator.AccumulatedFrametime < 1) + if (_gameTiming.CurTime < regulator.NextUpdate) continue; - regulator.AccumulatedFrametime -= 1; - ProcessThermalRegulation(uid, regulator); + regulator.NextUpdate += regulator.UpdateInterval; + ProcessThermalRegulation((uid, regulator)); } } /// /// Processes thermal regulation for a mob /// - private void ProcessThermalRegulation(EntityUid uid, ThermalRegulatorComponent comp) + private void ProcessThermalRegulation(Entity ent) { - if (!EntityManager.TryGetComponent(uid, out TemperatureComponent? temperatureComponent)) return; + if (!Resolve(ent, ref ent.Comp2, logMissing: false)) + return; - var totalMetabolismTempChange = comp.MetabolismHeat - comp.RadiatedHeat; + var totalMetabolismTempChange = ent.Comp1.MetabolismHeat - ent.Comp1.RadiatedHeat; // implicit heat regulation - var tempDiff = Math.Abs(temperatureComponent.CurrentTemperature - comp.NormalBodyTemperature); - var heatCapacity = _tempSys.GetHeatCapacity(uid, temperatureComponent); + var tempDiff = Math.Abs(ent.Comp2.CurrentTemperature - ent.Comp1.NormalBodyTemperature); + var heatCapacity = _tempSys.GetHeatCapacity(ent, ent); var targetHeat = tempDiff * heatCapacity; - if (temperatureComponent.CurrentTemperature > comp.NormalBodyTemperature) + if (ent.Comp2.CurrentTemperature > ent.Comp1.NormalBodyTemperature) { - totalMetabolismTempChange -= Math.Min(targetHeat, comp.ImplicitHeatRegulation); + totalMetabolismTempChange -= Math.Min(targetHeat, ent.Comp1.ImplicitHeatRegulation); } else { - totalMetabolismTempChange += Math.Min(targetHeat, comp.ImplicitHeatRegulation); + totalMetabolismTempChange += Math.Min(targetHeat, ent.Comp1.ImplicitHeatRegulation); } - _tempSys.ChangeHeat(uid, totalMetabolismTempChange, true, temperatureComponent); + _tempSys.ChangeHeat(ent, totalMetabolismTempChange, ignoreHeatResistance: true, ent); // recalc difference and target heat - tempDiff = Math.Abs(temperatureComponent.CurrentTemperature - comp.NormalBodyTemperature); + tempDiff = Math.Abs(ent.Comp2.CurrentTemperature - ent.Comp1.NormalBodyTemperature); targetHeat = tempDiff * heatCapacity; // if body temperature is not within comfortable, thermal regulation // processes starts - if (tempDiff > comp.ThermalRegulationTemperatureThreshold) + if (tempDiff > ent.Comp1.ThermalRegulationTemperatureThreshold) return; - if (temperatureComponent.CurrentTemperature > comp.NormalBodyTemperature) + if (ent.Comp2.CurrentTemperature > ent.Comp1.NormalBodyTemperature) { - if (!_actionBlockerSys.CanSweat(uid)) return; - _tempSys.ChangeHeat(uid, -Math.Min(targetHeat, comp.SweatHeatRegulation), true, - temperatureComponent); + if (!_actionBlockerSys.CanSweat(ent)) + return; + + _tempSys.ChangeHeat(ent, -Math.Min(targetHeat, ent.Comp1.SweatHeatRegulation), ignoreHeatResistance: true, ent); } else { - if (!_actionBlockerSys.CanShiver(uid)) return; - _tempSys.ChangeHeat(uid, Math.Min(targetHeat, comp.ShiveringHeatRegulation), true, - temperatureComponent); + if (!_actionBlockerSys.CanShiver(ent)) + return; + + _tempSys.ChangeHeat(ent, Math.Min(targetHeat, ent.Comp1.ShiveringHeatRegulation), ignoreHeatResistance: true, ent); } } } diff --git a/Content.Server/Cargo/Components/StationCargoBountyDatabaseComponent.cs b/Content.Server/Cargo/Components/StationCargoBountyDatabaseComponent.cs index 48c58321b3..d26794a632 100644 --- a/Content.Server/Cargo/Components/StationCargoBountyDatabaseComponent.cs +++ b/Content.Server/Cargo/Components/StationCargoBountyDatabaseComponent.cs @@ -12,7 +12,7 @@ public sealed partial class StationCargoBountyDatabaseComponent : Component /// Maximum amount of bounties a station can have. /// [DataField, ViewVariables(VVAccess.ReadWrite)] - public int MaxBounties = 5; + public int MaxBounties = 6; /// /// A list of all the bounties currently active for a station. diff --git a/Content.Server/Cargo/Systems/CargoSystem.cs b/Content.Server/Cargo/Systems/CargoSystem.cs index 2609d06b55..3d6fc96472 100644 --- a/Content.Server/Cargo/Systems/CargoSystem.cs +++ b/Content.Server/Cargo/Systems/CargoSystem.cs @@ -39,7 +39,6 @@ public sealed partial class CargoSystem : SharedCargoSystem [Dependency] private readonly PricingSystem _pricing = default!; [Dependency] private readonly SharedAppearanceSystem _appearance = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; - [Dependency] private readonly SharedTransformSystem _xformSystem = default!; [Dependency] private readonly ShuttleConsoleSystem _console = default!; [Dependency] private readonly StackSystem _stack = default!; [Dependency] private readonly StationSystem _station = default!; diff --git a/Content.Server/Cargo/Systems/PricingSystem.cs b/Content.Server/Cargo/Systems/PricingSystem.cs index 6fb36c9608..9e1970d63c 100644 --- a/Content.Server/Cargo/Systems/PricingSystem.cs +++ b/Content.Server/Cargo/Systems/PricingSystem.cs @@ -12,7 +12,6 @@ using Content.Shared.Stacks; using Robust.Shared.Console; using Robust.Shared.Containers; -using Robust.Shared.Map; using Robust.Shared.Map.Components; using Robust.Shared.Prototypes; using Robust.Shared.Utility; @@ -27,7 +26,6 @@ public sealed class PricingSystem : EntitySystem { [Dependency] private readonly IComponentFactory _factory = default!; [Dependency] private readonly IConsoleHost _consoleHost = default!; - [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly BodySystem _bodySystem = default!; [Dependency] private readonly MobStateSystem _mobStateSystem = default!; diff --git a/Content.Server/Chat/Managers/ChatManager.cs b/Content.Server/Chat/Managers/ChatManager.cs index 6d54bedf86..d12bbfe53c 100644 --- a/Content.Server/Chat/Managers/ChatManager.cs +++ b/Content.Server/Chat/Managers/ChatManager.cs @@ -125,9 +125,23 @@ public void DispatchServerMessage(ICommonSession player, string message, bool su _adminLogger.Add(LogType.Chat, LogImpact.Low, $"Server message to {player:Player}: {message}"); } - public void SendAdminAnnouncement(string message) + public void SendAdminAnnouncement(string message, AdminFlags? flagBlacklist, AdminFlags? flagWhitelist) { - var clients = _adminManager.ActiveAdmins.Select(p => p.Channel); + var clients = _adminManager.ActiveAdmins.Where(p => + { + var adminData = _adminManager.GetAdminData(p); + + DebugTools.AssertNotNull(adminData); + + if (adminData == null) + return false; + + if (flagBlacklist != null && adminData.HasFlag(flagBlacklist.Value)) + return false; + + return flagWhitelist == null || adminData.HasFlag(flagWhitelist.Value); + + }).Select(p => p.Channel); var wrappedMessage = Loc.GetString("chat-manager-send-admin-announcement-wrap-message", ("adminChannelName", Loc.GetString("chat-manager-admin-channel-name")), ("message", FormattedMessage.EscapeText(message))); diff --git a/Content.Server/Chat/Managers/IChatManager.cs b/Content.Server/Chat/Managers/IChatManager.cs index e5fa8d5f4d..59945bf5ca 100644 --- a/Content.Server/Chat/Managers/IChatManager.cs +++ b/Content.Server/Chat/Managers/IChatManager.cs @@ -1,4 +1,5 @@ using System.Diagnostics.CodeAnalysis; +using Content.Shared.Administration; using Content.Shared.Chat; using Robust.Shared.Network; using Robust.Shared.Player; @@ -21,7 +22,7 @@ public interface IChatManager void TrySendOOCMessage(ICommonSession player, string message, OOCChatType type); void SendHookOOC(string sender, string message); - void SendAdminAnnouncement(string message); + void SendAdminAnnouncement(string message, AdminFlags? flagBlacklist = null, AdminFlags? flagWhitelist = null); void SendAdminAlert(string message); void SendAdminAlert(EntityUid player, string message); diff --git a/Content.Server/Chat/Systems/ChatSystem.cs b/Content.Server/Chat/Systems/ChatSystem.cs index f69c95dfcb..3503ef84ca 100644 --- a/Content.Server/Chat/Systems/ChatSystem.cs +++ b/Content.Server/Chat/Systems/ChatSystem.cs @@ -423,11 +423,11 @@ private void SendEntitySpeak( name = FormattedMessage.EscapeText(name); // The chat message wrapped in a "x says y" string - var wrappedMessage = WrapPublicMessage(source, name, message); + var wrappedMessage = WrapPublicMessage(source, name, message, languageOverride: language); // The chat message obfuscated via language obfuscation var obfuscated = SanitizeInGameICMessage(source, _language.ObfuscateSpeech(message, language), out var emoteStr, true, _configurationManager.GetCVar(CCVars.ChatPunctuation), (!CultureInfo.CurrentCulture.IsNeutralCulture && CultureInfo.CurrentCulture.Parent.Name == "en") || (CultureInfo.CurrentCulture.IsNeutralCulture && CultureInfo.CurrentCulture.Name == "en")); // The language-obfuscated message wrapped in a "x says y" string - var wrappedObfuscated = WrapPublicMessage(source, name, obfuscated); + var wrappedObfuscated = WrapPublicMessage(source, name, obfuscated, languageOverride: language); SendInVoiceRange(ChatChannel.Local, name, message, wrappedMessage, obfuscated, wrappedObfuscated, source, range, languageOverride: language); @@ -514,6 +514,7 @@ private void SendEntityWhisper( // Scenario 1: the listener can clearly understand the message result = perceivedMessage; wrappedMessage = Loc.GetString("chat-manager-entity-whisper-wrap-message", + ("color", language.Color ?? Color.Gray), ("entityName", name), ("message", FormattedMessage.EscapeText(result))); } @@ -523,13 +524,14 @@ private void SendEntityWhisper( // Collisiongroup.Opaque is not ideal for this use. Preferably, there should be a check specifically with "Can Ent1 see Ent2" in mind result = ObfuscateMessageReadability(perceivedMessage); wrappedMessage = Loc.GetString("chat-manager-entity-whisper-wrap-message", - ("entityName", nameIdentity), ("message", FormattedMessage.EscapeText(result))); + ("entityName", nameIdentity), ("color", language.Color ?? Color.Gray), ("message", FormattedMessage.EscapeText(result))); } else { // Scenario 3: If listener is too far and has no line of sight, they can't identify the whisperer's identity result = ObfuscateMessageReadability(perceivedMessage); wrappedMessage = Loc.GetString("chat-manager-entity-whisper-unknown-wrap-message", + ("color", language.Color ?? Color.Gray), ("message", FormattedMessage.EscapeText(result))); } @@ -537,6 +539,7 @@ private void SendEntityWhisper( } var replayWrap = Loc.GetString("chat-manager-entity-whisper-wrap-message", + ("color", language.Color ?? Color.Gray), ("entityName", name), ("message", FormattedMessage.EscapeText(message))); _replay.RecordServerMessage(new ChatMessage(ChatChannel.Whisper, message, replayWrap, GetNetEntity(source), null, MessageRangeHideChatForReplay(range))); @@ -837,15 +840,16 @@ public string SanitizeMessageReplaceWords(string message) /// /// Wraps a message sent by the specified entity into an "x says y" string. /// - public string WrapPublicMessage(EntityUid source, string name, string message) + public string WrapPublicMessage(EntityUid source, string name, string message, LanguagePrototype? languageOverride = null) { + var language = languageOverride ?? _language.GetLanguage(source); var speech = GetSpeechVerb(source, message); - var verbName = Loc.GetString(_random.Pick(speech.SpeechVerbStrings)); return Loc.GetString(speech.Bold ? "chat-manager-entity-say-bold-wrap-message" : "chat-manager-entity-say-wrap-message", + ("color", language.Color ?? Color.White), ("entityName", name), - ("verb", verbName), - ("fontType", speech.FontId), - ("fontSize", speech.FontSize), + ("verb", Loc.GetString(_random.Pick(speech.SpeechVerbStrings))), + ("fontType", language.FontId ?? speech.FontId), + ("fontSize", language.FontSize ?? speech.FontSize), ("message", message)); } diff --git a/Content.Server/Chemistry/Containers/EntitySystems/SolutionContainerSystem.cs b/Content.Server/Chemistry/Containers/EntitySystems/SolutionContainerSystem.cs index 7926121c2b..468212f5ea 100644 --- a/Content.Server/Chemistry/Containers/EntitySystems/SolutionContainerSystem.cs +++ b/Content.Server/Chemistry/Containers/EntitySystems/SolutionContainerSystem.cs @@ -4,7 +4,6 @@ using Content.Shared.FixedPoint; using Robust.Shared.Containers; using Robust.Shared.Map; -using Robust.Shared.Network; using Robust.Shared.Utility; using System.Numerics; @@ -12,8 +11,6 @@ namespace Content.Server.Chemistry.Containers.EntitySystems; public sealed partial class SolutionContainerSystem : SharedSolutionContainerSystem { - [Dependency] private readonly INetManager _netManager = default!; - public override void Initialize() { base.Initialize(); diff --git a/Content.Server/Chemistry/EntitySystems/ReagentDispenserSystem.cs b/Content.Server/Chemistry/EntitySystems/ReagentDispenserSystem.cs index b93498fe31..a8583e6bcb 100644 --- a/Content.Server/Chemistry/EntitySystems/ReagentDispenserSystem.cs +++ b/Content.Server/Chemistry/EntitySystems/ReagentDispenserSystem.cs @@ -1,4 +1,3 @@ -using Content.Server.Administration.Logs; using Content.Server.Chemistry.Components; using Content.Server.Chemistry.Containers.EntitySystems; using Content.Server.Nutrition.EntitySystems; @@ -30,7 +29,6 @@ public sealed class ReagentDispenserSystem : EntitySystem [Dependency] private readonly ItemSlotsSystem _itemSlotsSystem = default!; [Dependency] private readonly UserInterfaceSystem _userInterfaceSystem = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!; - [Dependency] private readonly IAdminLogManager _adminLogger = default!; [Dependency] private readonly OpenableSystem _openable = default!; public override void Initialize() diff --git a/Content.Server/Decals/Commands/EditDecalCommand.cs b/Content.Server/Decals/Commands/EditDecalCommand.cs index baaef1f3f6..2ae814113f 100644 --- a/Content.Server/Decals/Commands/EditDecalCommand.cs +++ b/Content.Server/Decals/Commands/EditDecalCommand.cs @@ -3,6 +3,7 @@ using Content.Shared.Administration; using Robust.Shared.Console; using Robust.Shared.Map; +using Robust.Shared.Map.Components; namespace Content.Server.Decals; @@ -10,7 +11,6 @@ namespace Content.Server.Decals; public sealed class EditDecalCommand : IConsoleCommand { [Dependency] private readonly IEntityManager _entManager = default!; - [Dependency] private readonly IMapManager _mapManager = default!; public string Command => "editdecal"; public string Description => "Edits a decal."; @@ -43,7 +43,7 @@ public void Execute(IConsoleShell shell, string argStr, string[] args) return; } - if (!_mapManager.GridExists(gridId)) + if (!_entManager.HasComponent(gridId)) { shell.WriteError($"No grid with gridId {gridId} exists."); return; diff --git a/Content.Server/Decals/Commands/RemoveDecalCommand.cs b/Content.Server/Decals/Commands/RemoveDecalCommand.cs index 771c66fbbd..6b6a91c9d3 100644 --- a/Content.Server/Decals/Commands/RemoveDecalCommand.cs +++ b/Content.Server/Decals/Commands/RemoveDecalCommand.cs @@ -2,6 +2,7 @@ using Content.Shared.Administration; using Robust.Shared.Console; using Robust.Shared.Map; +using Robust.Shared.Map.Components; using SQLitePCL; namespace Content.Server.Decals.Commands @@ -10,7 +11,6 @@ namespace Content.Server.Decals.Commands public sealed class RemoveDecalCommand : IConsoleCommand { [Dependency] private readonly IEntityManager _entManager = default!; - [Dependency] private readonly IMapManager _mapManager = default!; public string Command => "rmdecal"; public string Description => "removes a decal"; @@ -31,7 +31,7 @@ public void Execute(IConsoleShell shell, string argStr, string[] args) if (!NetEntity.TryParse(args[1], out var rawGridIdNet) || !_entManager.TryGetEntity(rawGridIdNet, out var rawGridId) || - !_mapManager.GridExists(rawGridId)) + !_entManager.HasComponent(rawGridId)) { shell.WriteError("Failed parsing gridId."); return; diff --git a/Content.Server/Decals/DecalSystem.cs b/Content.Server/Decals/DecalSystem.cs index ad225afe22..da95401d20 100644 --- a/Content.Server/Decals/DecalSystem.cs +++ b/Content.Server/Decals/DecalSystem.cs @@ -105,7 +105,7 @@ private void OnGridSplit(ref PostGridSplitEvent ev) return; // Transfer decals over to the new grid. - var enumerator = MapManager.GetGrid(ev.Grid).GetAllTilesEnumerator(); + var enumerator = Comp(ev.Grid).GetAllTilesEnumerator(); var oldChunkCollection = oldComp.ChunkCollection.ChunkCollection; var chunkCollection = newComp.ChunkCollection.ChunkCollection; diff --git a/Content.Server/DeltaV/StationEvents/Events/PirateRadioSpawnRule.cs b/Content.Server/DeltaV/StationEvents/Events/PirateRadioSpawnRule.cs index f0538c47f9..ba042d8966 100644 --- a/Content.Server/DeltaV/StationEvents/Events/PirateRadioSpawnRule.cs +++ b/Content.Server/DeltaV/StationEvents/Events/PirateRadioSpawnRule.cs @@ -39,7 +39,7 @@ protected override void Started(EntityUid uid, PirateRadioSpawnRuleComponent com var xformQuery = GetEntityQuery(); var aabbs = EntityQuery().SelectMany(x => x.Grids.Select(x => - xformQuery.GetComponent(x).WorldMatrix.TransformBox(_mapManager.GetGridComp(x).LocalAABB))) + xformQuery.GetComponent(x).WorldMatrix.TransformBox(_entities.GetComponent(x).LocalAABB))) .ToArray(); if (aabbs.Length < 1) return; var aabb = aabbs[0]; diff --git a/Content.Server/Disposal/Tube/DisposalTubeSystem.cs b/Content.Server/Disposal/Tube/DisposalTubeSystem.cs index 20aa8b6d2c..6c0bced53e 100644 --- a/Content.Server/Disposal/Tube/DisposalTubeSystem.cs +++ b/Content.Server/Disposal/Tube/DisposalTubeSystem.cs @@ -6,20 +6,16 @@ using Content.Server.Disposal.Unit.Components; using Content.Server.Disposal.Unit.EntitySystems; using Content.Server.Popups; -using Content.Server.UserInterface; using Content.Shared.Destructible; using Content.Shared.Disposal.Components; -using Content.Shared.Hands.Components; -using Content.Shared.Movement.Events; using Robust.Server.GameObjects; using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; using Robust.Shared.Containers; -using Robust.Shared.Map; +using Robust.Shared.Map.Components; using Robust.Shared.Physics; using Robust.Shared.Physics.Components; using Robust.Shared.Random; -using Robust.Shared.Timing; using static Content.Shared.Disposal.Components.SharedDisposalRouterComponent; using static Content.Shared.Disposal.Components.SharedDisposalTaggerComponent; @@ -27,8 +23,6 @@ namespace Content.Server.Disposal.Tube { public sealed class DisposalTubeSystem : EntitySystem { - [Dependency] private readonly IGameTiming _gameTiming = default!; - [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly SharedAppearanceSystem _appearanceSystem = default!; [Dependency] private readonly PopupSystem _popups = default!; @@ -349,7 +343,7 @@ private void UpdateAnchored(EntityUid uid, DisposalTubeComponent component, bool var oppositeDirection = nextDirection.GetOpposite(); var xform = Transform(target); - if (!_mapManager.TryGetGrid(xform.GridUid, out var grid)) + if (!TryComp(xform.GridUid, out var grid)) return null; var position = xform.Coordinates; diff --git a/Content.Server/Disposal/Unit/EntitySystems/DisposableSystem.cs b/Content.Server/Disposal/Unit/EntitySystems/DisposableSystem.cs index eb3cda4db9..38e3923803 100644 --- a/Content.Server/Disposal/Unit/EntitySystems/DisposableSystem.cs +++ b/Content.Server/Disposal/Unit/EntitySystems/DisposableSystem.cs @@ -1,4 +1,3 @@ -using System.Linq; using Content.Server.Atmos.EntitySystems; using Content.Server.Disposal.Tube; using Content.Server.Disposal.Tube.Components; @@ -12,14 +11,12 @@ using Robust.Shared.Map.Components; using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Systems; -using Robust.Shared.Random; namespace Content.Server.Disposal.Unit.EntitySystems { public sealed class DisposableSystem : EntitySystem { [Dependency] private readonly ThrowingSystem _throwing = default!; - [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!; [Dependency] private readonly DamageableSystem _damageable = default!; [Dependency] private readonly DisposalUnitSystem _disposalUnitSystem = default!; diff --git a/Content.Server/Dragon/DragonSystem.cs b/Content.Server/Dragon/DragonSystem.cs index 6400472d03..79e5c0a2a9 100644 --- a/Content.Server/Dragon/DragonSystem.cs +++ b/Content.Server/Dragon/DragonSystem.cs @@ -10,18 +10,16 @@ using Content.Shared.Mind.Components; using Content.Shared.Mobs; using Content.Shared.Movement.Systems; -using Robust.Shared.Audio; +using Content.Shared.Zombies; using Robust.Shared.Audio.Systems; -using Robust.Shared.GameStates; using Robust.Shared.Map; -using Robust.Shared.Player; +using Robust.Shared.Map.Components; namespace Content.Server.Dragon; public sealed partial class DragonSystem : EntitySystem { [Dependency] private readonly CarpRiftsConditionSystem _carpRifts = default!; - [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly ITileDefinitionManager _tileDef = default!; [Dependency] private readonly MovementSpeedModifierSystem _movement = default!; [Dependency] private readonly PopupSystem _popup = default!; @@ -138,7 +136,7 @@ private void OnSpawnRift(EntityUid uid, DragonComponent component, DragonSpawnRi var xform = Transform(uid); // Have to be on a grid fam - if (!_mapManager.TryGetGrid(xform.GridUid, out var grid)) + if (!TryComp(xform.GridUid, out var grid)) { _popup.PopupEntity(Loc.GetString("carp-rift-anchor"), uid, uid); return; diff --git a/Content.Server/Electrocution/ElectrocutionSystem.cs b/Content.Server/Electrocution/ElectrocutionSystem.cs index d410c7af96..9d8b7e416e 100644 --- a/Content.Server/Electrocution/ElectrocutionSystem.cs +++ b/Content.Server/Electrocution/ElectrocutionSystem.cs @@ -19,7 +19,6 @@ using Content.Shared.Maps; using Content.Shared.Mobs; using Content.Shared.Popups; -using Content.Shared.Pulling.Components; using Content.Shared.Speech.EntitySystems; using Content.Shared.StatusEffect; using Content.Shared.Stunnable; @@ -32,6 +31,8 @@ using Robust.Shared.Player; using Robust.Shared.Prototypes; using Robust.Shared.Random; +using PullableComponent = Content.Shared.Movement.Pulling.Components.PullableComponent; +using PullerComponent = Content.Shared.Movement.Pulling.Components.PullerComponent; namespace Content.Server.Electrocution; @@ -477,14 +478,14 @@ private void GetChainedElectrocutionTargetsRecurse( all.Add((entity, depth)); visited.Add(entity); - if (TryComp(entity, out var pullable) && + if (TryComp(entity, out var pullable) && pullable.Puller is { Valid: true } pullerId && !visited.Contains(pullerId)) { GetChainedElectrocutionTargetsRecurse(pullerId, depth + 1, visited, all); } - if (TryComp(entity, out var puller) && + if (TryComp(entity, out var puller) && puller.Pulling is { Valid: true } pullingId && !visited.Contains(pullingId)) { diff --git a/Content.Server/Engineering/EntitySystems/SpawnAfterInteractSystem.cs b/Content.Server/Engineering/EntitySystems/SpawnAfterInteractSystem.cs index 61c4937a27..a0bbbdf350 100644 --- a/Content.Server/Engineering/EntitySystems/SpawnAfterInteractSystem.cs +++ b/Content.Server/Engineering/EntitySystems/SpawnAfterInteractSystem.cs @@ -6,14 +6,13 @@ using Content.Shared.Maps; using Content.Shared.Stacks; using JetBrains.Annotations; -using Robust.Shared.Map; +using Robust.Shared.Map.Components; namespace Content.Server.Engineering.EntitySystems { [UsedImplicitly] public sealed class SpawnAfterInteractSystem : EntitySystem { - [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!; [Dependency] private readonly StackSystem _stackSystem = default!; @@ -30,7 +29,7 @@ private async void HandleAfterInteract(EntityUid uid, SpawnAfterInteractComponen return; if (string.IsNullOrEmpty(component.Prototype)) return; - if (!_mapManager.TryGetGrid(args.ClickLocation.GetGridUid(EntityManager), out var grid)) + if (!TryComp(args.ClickLocation.GetGridUid(EntityManager), out var grid)) return; if (!grid.TryGetTileRef(args.ClickLocation, out var tileRef)) return; diff --git a/Content.Server/Explosion/EntitySystems/ExplosionSystem.Airtight.cs b/Content.Server/Explosion/EntitySystems/ExplosionSystem.Airtight.cs index af150c9325..55e8de2632 100644 --- a/Content.Server/Explosion/EntitySystems/ExplosionSystem.Airtight.cs +++ b/Content.Server/Explosion/EntitySystems/ExplosionSystem.Airtight.cs @@ -4,7 +4,6 @@ using Content.Shared.Damage; using Content.Shared.Explosion; using Content.Shared.FixedPoint; -using Robust.Shared.Map; using Robust.Shared.Map.Components; namespace Content.Server.Explosion.EntitySystems; @@ -102,7 +101,7 @@ private void OnAirtightDamaged(EntityUid uid, AirtightComponent airtight, Damage if (!EntityManager.TryGetComponent(uid, out TransformComponent? transform) || !transform.Anchored) return; - if (!_mapManager.TryGetGrid(transform.GridUid, out var grid)) + if (!TryComp(transform.GridUid, out var grid)) return; UpdateAirtightMap(transform.GridUid.Value, grid, grid.CoordinatesToTile(transform.Coordinates)); diff --git a/Content.Server/Explosion/EntitySystems/ExplosionSystem.GridMap.cs b/Content.Server/Explosion/EntitySystems/ExplosionSystem.GridMap.cs index b04642a8db..719a2eca79 100644 --- a/Content.Server/Explosion/EntitySystems/ExplosionSystem.GridMap.cs +++ b/Content.Server/Explosion/EntitySystems/ExplosionSystem.GridMap.cs @@ -23,7 +23,7 @@ public sealed partial class ExplosionSystem : EntitySystem /// private void OnGridStartup(GridStartupEvent ev) { - var grid = _mapManager.GetGrid(ev.EntityUid); + var grid = Comp(ev.EntityUid); Dictionary edges = new(); _gridEdges[ev.EntityUid] = edges; diff --git a/Content.Server/Explosion/EntitySystems/ExplosionSystem.Processing.cs b/Content.Server/Explosion/EntitySystems/ExplosionSystem.Processing.cs index 4a9477e744..ccfcee4612 100644 --- a/Content.Server/Explosion/EntitySystems/ExplosionSystem.Processing.cs +++ b/Content.Server/Explosion/EntitySystems/ExplosionSystem.Processing.cs @@ -1,4 +1,3 @@ -using System.Linq; using System.Numerics; using Content.Shared.CCVar; using Content.Shared.Damage; @@ -17,6 +16,7 @@ using Robust.Shared.Timing; using Robust.Shared.Utility; using TimedDespawnComponent = Robust.Shared.Spawners.TimedDespawnComponent; +using Content.Server.Atmos.EntitySystems; namespace Content.Server.Explosion.EntitySystems; @@ -44,13 +44,6 @@ public sealed partial class ExplosionSystem /// private Explosion? _activeExplosion; - /// - /// While processing an explosion, the "progress" is sent to clients, so that the explosion fireball effect - /// syncs up with the damage. When the tile iteration increments, an update needs to be sent to clients. - /// This integer keeps track of the last value sent to clients. - /// - private int _previousTileIteration; - /// /// This list is used when raising to avoid allocating a new list per event. /// @@ -108,8 +101,6 @@ public override void Update(float frameTime) if (_activeExplosion == null) continue; - _previousTileIteration = 0; - // just a lil nap if (SleepNodeSys) { diff --git a/Content.Server/Explosion/EntitySystems/ExplosionSystem.TileFill.cs b/Content.Server/Explosion/EntitySystems/ExplosionSystem.TileFill.cs index afad0e27e0..a42dd11083 100644 --- a/Content.Server/Explosion/EntitySystems/ExplosionSystem.TileFill.cs +++ b/Content.Server/Explosion/EntitySystems/ExplosionSystem.TileFill.cs @@ -4,6 +4,7 @@ using Content.Shared.Explosion; using Content.Shared.Explosion.Components; using Robust.Shared.Map; +using Robust.Shared.Map.Components; using Robust.Shared.Physics.Components; using Robust.Shared.Timing; @@ -56,7 +57,7 @@ public sealed partial class ExplosionSystem : EntitySystem else if (referenceGrid != null) { // reference grid defines coordinate system that the explosion in space will use - initialTile = _mapManager.GetGrid(referenceGrid.Value).WorldToTile(epicenter.Position); + initialTile = Comp(referenceGrid.Value).WorldToTile(epicenter.Position); } else { @@ -87,7 +88,7 @@ public sealed partial class ExplosionSystem : EntitySystem var spaceAngle = Angle.Zero; if (referenceGrid != null) { - var xform = Transform(_mapManager.GetGrid(referenceGrid.Value).Owner); + var xform = Transform(Comp(referenceGrid.Value).Owner); spaceMatrix = xform.WorldMatrix; spaceAngle = xform.WorldRotation; } @@ -102,7 +103,7 @@ public sealed partial class ExplosionSystem : EntitySystem airtightMap = new(); var initialGridData = new ExplosionGridTileFlood( - _mapManager.GetGrid(epicentreGrid.Value), + Comp(epicentreGrid.Value), airtightMap, maxIntensity, stepSize, @@ -191,7 +192,7 @@ public sealed partial class ExplosionSystem : EntitySystem airtightMap = new(); data = new ExplosionGridTileFlood( - _mapManager.GetGrid(grid), + Comp(grid), airtightMap, maxIntensity, stepSize, diff --git a/Content.Server/Eye/Blinding/EyeProtection/EyeProtectionSystem.cs b/Content.Server/Eye/Blinding/EyeProtection/EyeProtectionSystem.cs index 24ee2b7154..2d54c03b51 100644 --- a/Content.Server/Eye/Blinding/EyeProtection/EyeProtectionSystem.cs +++ b/Content.Server/Eye/Blinding/EyeProtection/EyeProtectionSystem.cs @@ -1,10 +1,8 @@ using Content.Shared.StatusEffect; using Content.Shared.Inventory; -using Content.Shared.Item; using Content.Shared.Eye.Blinding.Components; using Content.Shared.Eye.Blinding.Systems; using Content.Shared.Tools.Components; -using Content.Shared.Item.ItemToggle; using Content.Shared.Item.ItemToggle.Components; namespace Content.Server.Eye.Blinding.EyeProtection @@ -13,7 +11,6 @@ public sealed class EyeProtectionSystem : EntitySystem { [Dependency] private readonly StatusEffectsSystem _statusEffectsSystem = default!; [Dependency] private readonly BlindableSystem _blindingSystem = default!; - [Dependency] private readonly SharedItemToggleSystem _itemToggle = default!; public override void Initialize() { diff --git a/Content.Server/GameTicking/Rules/PiratesRuleSystem.cs b/Content.Server/GameTicking/Rules/PiratesRuleSystem.cs index 98926536b9..128f112304 100644 --- a/Content.Server/GameTicking/Rules/PiratesRuleSystem.cs +++ b/Content.Server/GameTicking/Rules/PiratesRuleSystem.cs @@ -24,6 +24,7 @@ using Robust.Shared.Configuration; using Robust.Shared.Enums; using Robust.Shared.Map; +using Robust.Shared.Map.Components; using Robust.Shared.Player; using Robust.Shared.Prototypes; using Robust.Shared.Random; @@ -180,7 +181,7 @@ private void OnPlayerSpawningEvent(RulePlayerSpawningEvent ev) var aabbs = EntityQuery().SelectMany(x => x.Grids.Select(x => - xformQuery.GetComponent(x).WorldMatrix.TransformBox(_mapManager.GetGridComp(x).LocalAABB))) + xformQuery.GetComponent(x).WorldMatrix.TransformBox(Comp(x).LocalAABB))) .ToArray(); var aabb = aabbs[0]; diff --git a/Content.Server/Gateway/Systems/GatewayGeneratorSystem.cs b/Content.Server/Gateway/Systems/GatewayGeneratorSystem.cs index 7558f7afc0..c934fb66bf 100644 --- a/Content.Server/Gateway/Systems/GatewayGeneratorSystem.cs +++ b/Content.Server/Gateway/Systems/GatewayGeneratorSystem.cs @@ -1,23 +1,16 @@ using System.Linq; -using System.Numerics; using Content.Server.Gateway.Components; using Content.Server.Parallax; using Content.Server.Procedural; -using Content.Server.Salvage; using Content.Shared.CCVar; using Content.Shared.Dataset; using Content.Shared.Maps; -using Content.Shared.Movement.Components; using Content.Shared.Parallax.Biomes; -using Content.Shared.Physics; using Content.Shared.Procedural; using Content.Shared.Salvage; using Robust.Shared.Configuration; using Robust.Shared.Map; using Robust.Shared.Map.Components; -using Robust.Shared.Physics.Collision.Shapes; -using Robust.Shared.Physics.Components; -using Robust.Shared.Physics.Systems; using Robust.Shared.Prototypes; using Robust.Shared.Random; using Robust.Shared.Timing; @@ -40,7 +33,6 @@ public sealed class GatewayGeneratorSystem : EntitySystem [Dependency] private readonly DungeonSystem _dungeon = default!; [Dependency] private readonly GatewaySystem _gateway = default!; [Dependency] private readonly MetaDataSystem _metadata = default!; - [Dependency] private readonly RestrictedRangeSystem _restricted = default!; [Dependency] private readonly SharedMapSystem _maps = default!; [Dependency] private readonly TileSystem _tile = default!; diff --git a/Content.Server/Hands/Systems/HandsSystem.cs b/Content.Server/Hands/Systems/HandsSystem.cs index a0e872dbeb..e836b65838 100644 --- a/Content.Server/Hands/Systems/HandsSystem.cs +++ b/Content.Server/Hands/Systems/HandsSystem.cs @@ -1,6 +1,5 @@ using System.Numerics; using Content.Server.Inventory; -using Content.Server.Pulling; using Content.Server.Stack; using Content.Server.Stunnable; using Content.Shared.ActionBlocker; @@ -11,8 +10,9 @@ using Content.Shared.Hands.EntitySystems; using Content.Shared.Input; using Content.Shared.Inventory.VirtualItem; -using Content.Shared.Physics.Pull; -using Content.Shared.Pulling.Components; +using Content.Shared.Movement.Pulling.Components; +using Content.Shared.Movement.Pulling.Events; +using Content.Shared.Movement.Pulling.Systems; using Content.Shared.Stacks; using Content.Shared.Throwing; using Robust.Shared.GameStates; @@ -84,9 +84,8 @@ private void OnDisarmed(EntityUid uid, HandsComponent component, DisarmedEvent a return; // Break any pulls - if (TryComp(uid, out SharedPullerComponent? puller) && puller.Pulling is EntityUid pulled && - TryComp(pulled, out SharedPullableComponent? pullable)) - _pullingSystem.TryStopPull(pullable); + if (TryComp(uid, out PullerComponent? puller) && TryComp(puller.Pulling, out PullableComponent? pullable)) + _pullingSystem.TryStopPull(puller.Pulling.Value, pullable); if (!_handsSystem.TryDrop(uid, component.ActiveHand!, null, checkActionBlocker: false)) return; @@ -96,17 +95,17 @@ private void OnDisarmed(EntityUid uid, HandsComponent component, DisarmedEvent a private void HandleBodyPartAdded(EntityUid uid, HandsComponent component, ref BodyPartAddedEvent args) { - if (args.Part.PartType != BodyPartType.Hand) + if (args.Part.Comp.PartType != BodyPartType.Hand) return; // If this annoys you, which it should. // Ping Smugleaf. - var location = args.Part.Symmetry switch + var location = args.Part.Comp.Symmetry switch { BodyPartSymmetry.None => HandLocation.Middle, BodyPartSymmetry.Left => HandLocation.Left, BodyPartSymmetry.Right => HandLocation.Right, - _ => throw new ArgumentOutOfRangeException(nameof(args.Part.Symmetry)) + _ => throw new ArgumentOutOfRangeException(nameof(args.Part.Comp.Symmetry)) }; AddHand(uid, args.Slot, location); @@ -114,7 +113,7 @@ private void HandleBodyPartAdded(EntityUid uid, HandsComponent component, ref Bo private void HandleBodyPartRemoved(EntityUid uid, HandsComponent component, ref BodyPartRemovedEvent args) { - if (args.Part.PartType != BodyPartType.Hand) + if (args.Part.Comp.PartType != BodyPartType.Hand) return; RemoveHand(uid, args.Slot); @@ -124,13 +123,13 @@ private void HandleBodyPartRemoved(EntityUid uid, HandsComponent component, ref private void HandlePullStarted(EntityUid uid, HandsComponent component, PullStartedMessage args) { - if (args.Puller.Owner != uid) + if (args.PullerUid != uid) return; - if (TryComp(args.Puller.Owner, out var pullerComp) && !pullerComp.NeedsHands) + if (TryComp(args.PullerUid, out var pullerComp) && !pullerComp.NeedsHands) return; - if (!_virtualItemSystem.TrySpawnVirtualItemInHand(args.Pulled.Owner, uid)) + if (!_virtualItemSystem.TrySpawnVirtualItemInHand(args.PulledUid, uid)) { DebugTools.Assert("Unable to find available hand when starting pulling??"); } @@ -138,7 +137,7 @@ private void HandlePullStarted(EntityUid uid, HandsComponent component, PullStar private void HandlePullStopped(EntityUid uid, HandsComponent component, PullStoppedMessage args) { - if (args.Puller.Owner != uid) + if (args.PullerUid != uid) return; // Try find hand that is doing this pull. @@ -147,8 +146,10 @@ private void HandlePullStopped(EntityUid uid, HandsComponent component, PullStop { if (hand.HeldEntity == null || !TryComp(hand.HeldEntity, out VirtualItemComponent? virtualItem) - || virtualItem.BlockingEntity != args.Pulled.Owner) + || virtualItem.BlockingEntity != args.PulledUid) + { continue; + } QueueDel(hand.HeldEntity.Value); break; diff --git a/Content.Server/ImmovableRod/ImmovableRodSystem.cs b/Content.Server/ImmovableRod/ImmovableRodSystem.cs index 31aa39cf03..429361cd8c 100644 --- a/Content.Server/ImmovableRod/ImmovableRodSystem.cs +++ b/Content.Server/ImmovableRod/ImmovableRodSystem.cs @@ -6,6 +6,7 @@ using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; using Robust.Shared.Map; +using Robust.Shared.Map.Components; using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Events; using Robust.Shared.Physics.Systems; @@ -16,7 +17,6 @@ namespace Content.Server.ImmovableRod; public sealed class ImmovableRodSystem : EntitySystem { [Dependency] private readonly IRobustRandom _random = default!; - [Dependency] private readonly IMapManager _map = default!; [Dependency] private readonly BodySystem _bodySystem = default!; [Dependency] private readonly PopupSystem _popup = default!; @@ -33,7 +33,7 @@ public override void Update(float frameTime) if (!rod.DestroyTiles) continue; - if (!_map.TryGetGrid(trans.GridUid, out var grid)) + if (!TryComp(trans.GridUid, out var grid)) continue; grid.SetTile(trans.Coordinates, Tile.Empty); diff --git a/Content.Server/Implants/SubdermalImplantSystem.cs b/Content.Server/Implants/SubdermalImplantSystem.cs index 8eb2741448..6b58f6eb09 100644 --- a/Content.Server/Implants/SubdermalImplantSystem.cs +++ b/Content.Server/Implants/SubdermalImplantSystem.cs @@ -19,6 +19,8 @@ using Robust.Shared.Physics.Components; using Robust.Shared.Random; using System.Numerics; +using Content.Shared.Movement.Pulling.Components; +using Content.Shared.Movement.Pulling.Systems; namespace Content.Server.Implants; @@ -34,6 +36,7 @@ public sealed class SubdermalImplantSystem : SharedSubdermalImplantSystem [Dependency] private readonly SharedPopupSystem _popup = default!; [Dependency] private readonly SharedTransformSystem _xform = default!; [Dependency] private readonly ForensicsSystem _forensicsSystem = default!; + [Dependency] private readonly PullingSystem _pullingSystem = default!; private EntityQuery _physicsQuery; @@ -98,6 +101,11 @@ private void OnScramImplant(EntityUid uid, SubdermalImplantComponent component, if (!TryComp(uid, out var implant)) return; + // We need stop the user from being pulled so they don't just get "attached" with whoever is pulling them. + // This can for example happen when the user is cuffed and being pulled. + if (TryComp(ent, out var pull) && _pullingSystem.IsPulled(ent, pull)) + _pullingSystem.TryStopPull(ent, pull); + var xform = Transform(ent); var entityCoords = xform.Coordinates.ToMap(EntityManager, _xform); diff --git a/Content.Server/Instruments/InstrumentComponent.cs b/Content.Server/Instruments/InstrumentComponent.cs index 4302ab6791..1b7913386d 100644 --- a/Content.Server/Instruments/InstrumentComponent.cs +++ b/Content.Server/Instruments/InstrumentComponent.cs @@ -1,6 +1,5 @@ using Content.Server.UserInterface; using Content.Shared.Instruments; -using Robust.Server.GameObjects; using Robust.Shared.Player; namespace Content.Server.Instruments; diff --git a/Content.Server/Interaction/InteractionSystem.cs b/Content.Server/Interaction/InteractionSystem.cs index 6692886dae..203781bcda 100644 --- a/Content.Server/Interaction/InteractionSystem.cs +++ b/Content.Server/Interaction/InteractionSystem.cs @@ -1,4 +1,3 @@ -using Content.Shared.ActionBlocker; using Content.Shared.Interaction; using Content.Shared.Storage; using JetBrains.Annotations; @@ -14,7 +13,6 @@ namespace Content.Server.Interaction [UsedImplicitly] public sealed partial class InteractionSystem : SharedInteractionSystem { - [Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!; [Dependency] private readonly SharedContainerSystem _container = default!; [Dependency] private readonly UserInterfaceSystem _uiSystem = default!; diff --git a/Content.Server/Interaction/TilePryCommand.cs b/Content.Server/Interaction/TilePryCommand.cs index 57b07e8181..006a245ead 100644 --- a/Content.Server/Interaction/TilePryCommand.cs +++ b/Content.Server/Interaction/TilePryCommand.cs @@ -4,6 +4,7 @@ using Content.Shared.Maps; using Robust.Shared.Console; using Robust.Shared.Map; +using Robust.Shared.Map.Components; namespace Content.Server.Interaction { @@ -46,7 +47,7 @@ public void Execute(IConsoleShell shell, string argStr, string[] args) var xform = _entities.GetComponent(attached); var playerGrid = xform.GridUid; - if (!mapManager.TryGetGrid(playerGrid, out var mapGrid)) + if (!_entities.TryGetComponent(playerGrid, out var mapGrid)) return; var playerPosition = xform.Coordinates; diff --git a/Content.Server/Language/TranslatorSystem.cs b/Content.Server/Language/TranslatorSystem.cs index 5022e54096..adbfe2d681 100644 --- a/Content.Server/Language/TranslatorSystem.cs +++ b/Content.Server/Language/TranslatorSystem.cs @@ -1,15 +1,12 @@ using System.Linq; -using Content.Server.Language.Events; using Content.Server.Popups; using Content.Server.PowerCell; using Content.Shared.Interaction; using Content.Shared.Interaction.Events; using Content.Shared.Language; -using Content.Shared.Language.Events; using Content.Shared.Language.Systems; using Content.Shared.PowerCell; using Content.Shared.Language.Components.Translators; -using Robust.Shared.Utility; namespace Content.Server.Language; diff --git a/Content.Server/Magic/MagicSystem.cs b/Content.Server/Magic/MagicSystem.cs index 92cd794ce2..8655592471 100644 --- a/Content.Server/Magic/MagicSystem.cs +++ b/Content.Server/Magic/MagicSystem.cs @@ -21,6 +21,7 @@ using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; using Robust.Shared.Map; +using Robust.Shared.Map.Components; using Robust.Shared.Random; using Robust.Shared.Serialization.Manager; using Robust.Shared.Spawners; @@ -217,7 +218,7 @@ private List GetSpawnPositions(TransformComponent casterXform // This is shit but you get the idea. var directionPos = casterXform.Coordinates.Offset(casterXform.LocalRotation.ToWorldVec().Normalized()); - if (!_mapManager.TryGetGrid(casterXform.GridUid, out var mapGrid)) + if (!TryComp(casterXform.GridUid, out var mapGrid)) return new List(); if (!directionPos.TryGetTileRef(out var tileReference, EntityManager, _mapManager)) diff --git a/Content.Server/Mapping/MappingCommand.cs b/Content.Server/Mapping/MappingCommand.cs index 08ba0de833..08f3dcccf9 100644 --- a/Content.Server/Mapping/MappingCommand.cs +++ b/Content.Server/Mapping/MappingCommand.cs @@ -1,17 +1,14 @@ -// ReSharper disable once RedundantUsingDirective -// Used to warn the player in big red letters in debug mode - using System.Linq; using Content.Server.Administration; using Content.Server.GameTicking; using Content.Shared.Administration; using Content.Shared.CCVar; -using Robust.Server.Player; +using Robust.Server.GameObjects; +using Robust.Server.Maps; using Robust.Shared.Configuration; using Robust.Shared.Console; using Robust.Shared.ContentPack; using Robust.Shared.Map; -using Robust.Shared.Utility; namespace Content.Server.Mapping { @@ -19,6 +16,8 @@ namespace Content.Server.Mapping sealed class MappingCommand : IConsoleCommand { [Dependency] private readonly IEntityManager _entities = default!; + [Dependency] private readonly IMapManager _map = default!; + [Dependency] private readonly IConfigurationManager _cfg = default!; public string Command => "mapping"; public string Description => Loc.GetString("cmd-mapping-desc"); @@ -57,13 +56,13 @@ public void Execute(IConsoleShell shell, string argStr, string[] args) shell.WriteError(Loc.GetString("cmd-mapping-warning")); #endif - var mapManager = IoCManager.Resolve(); MapId mapId; + string? toLoad = null; + var mapSys = _entities.System(); // Get the map ID to use if (args.Length is 1 or 2) { - if (!int.TryParse(args[0], out var intMapId)) { shell.WriteError(Loc.GetString("cmd-mapping-failure-integer", ("arg", args[0]))); @@ -79,35 +78,33 @@ public void Execute(IConsoleShell shell, string argStr, string[] args) return; } - if (mapManager.MapExists(mapId)) + if (_map.MapExists(mapId)) { shell.WriteError(Loc.GetString("cmd-mapping-exists", ("mapId", mapId))); return; } - } - else - { - mapId = mapManager.NextMapId(); - } + // either load a map or create a new one. + if (args.Length <= 1) + { + mapSys.CreateMap(mapId, runMapInit: false); + } + else + { + var loadOptions = new MapLoadOptions {StoreMapUids = true}; + _entities.System().TryLoad(mapId, args[1], out _, loadOptions); + } - string? toLoad = null; - // either load a map or create a new one. - if (args.Length <= 1) - { - shell.ExecuteCommand($"addmap {mapId} false"); + // was the map actually created or did it fail somehow? + if (!_map.MapExists(mapId)) + { + shell.WriteError(Loc.GetString("cmd-mapping-error")); + return; + } } else { - toLoad = CommandParsing.Escape(args[1]); - shell.ExecuteCommand($"loadmap {mapId} \"{toLoad}\" 0 0 0 true"); - } - - // was the map actually created? - if (!mapManager.MapExists(mapId)) - { - shell.WriteError(Loc.GetString("cmd-mapping-error")); - return; + mapSys.CreateMap(out mapId, runMapInit: false); } // map successfully created. run misc helpful mapping commands @@ -117,17 +114,15 @@ public void Execute(IConsoleShell shell, string argStr, string[] args) shell.ExecuteCommand("aghost"); } - var cfg = IoCManager.Resolve(); - // don't interrupt mapping with events or auto-shuttle shell.ExecuteCommand("sudo cvar events.enabled false"); shell.ExecuteCommand("sudo cvar shuttle.auto_call_time 0"); - if (cfg.GetCVar(CCVars.AutosaveEnabled)) + if (_cfg.GetCVar(CCVars.AutosaveEnabled)) shell.ExecuteCommand($"toggleautosave {mapId} {toLoad ?? "NEWMAP"}"); shell.ExecuteCommand($"tp 0 0 {mapId}"); shell.RemoteExecuteCommand("mappingclientsidesetup"); - mapManager.SetMapPaused(mapId, true); + _map.SetMapPaused(mapId, true); if (args.Length == 2) shell.WriteLine(Loc.GetString("cmd-mapping-success-load",("mapId",mapId),("path", args[1]))); diff --git a/Content.Server/Mech/Systems/MechSystem.cs b/Content.Server/Mech/Systems/MechSystem.cs index 1012b9727d..f592de9e7e 100644 --- a/Content.Server/Mech/Systems/MechSystem.cs +++ b/Content.Server/Mech/Systems/MechSystem.cs @@ -20,7 +20,6 @@ using Robust.Server.Containers; using Robust.Server.GameObjects; using Robust.Shared.Containers; -using Robust.Shared.Map; using Robust.Shared.Player; namespace Content.Server.Mech.Systems; @@ -33,8 +32,6 @@ public sealed partial class MechSystem : SharedMechSystem [Dependency] private readonly BatterySystem _battery = default!; [Dependency] private readonly ContainerSystem _container = default!; [Dependency] private readonly DamageableSystem _damageable = default!; - [Dependency] private readonly IMapManager _map = default!; - [Dependency] private readonly MapSystem _mapSystem = default!; [Dependency] private readonly SharedDoAfterSystem _doAfter = default!; [Dependency] private readonly SharedPopupSystem _popup = default!; [Dependency] private readonly UserInterfaceSystem _ui = default!; diff --git a/Content.Server/Medical/SuitSensors/SuitSensorSystem.cs b/Content.Server/Medical/SuitSensors/SuitSensorSystem.cs index f19b3d5b81..09497c7136 100644 --- a/Content.Server/Medical/SuitSensors/SuitSensorSystem.cs +++ b/Content.Server/Medical/SuitSensors/SuitSensorSystem.cs @@ -9,7 +9,6 @@ using Content.Server.Station.Systems; using Content.Shared.Damage; using Content.Shared.DeviceNetwork; -using Content.Shared.Emp; using Content.Shared.Examine; using Content.Shared.Inventory.Events; using Content.Shared.Medical.SuitSensor; @@ -27,7 +26,6 @@ public sealed class SuitSensorSystem : EntitySystem { [Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly IRobustRandom _random = default!; - [Dependency] private readonly CrewMonitoringServerSystem _monitoringServerSystem = default!; [Dependency] private readonly DeviceNetworkSystem _deviceNetworkSystem = default!; [Dependency] private readonly IdCardSystem _idCardSystem = default!; [Dependency] private readonly MobStateSystem _mobStateSystem = default!; diff --git a/Content.Server/NPC/HTN/Preconditions/PulledPrecondition.cs b/Content.Server/NPC/HTN/Preconditions/PulledPrecondition.cs index 64a72b13cf..d276be7218 100644 --- a/Content.Server/NPC/HTN/Preconditions/PulledPrecondition.cs +++ b/Content.Server/NPC/HTN/Preconditions/PulledPrecondition.cs @@ -1,4 +1,5 @@ using Content.Shared.Pulling; +using PullingSystem = Content.Shared.Movement.Pulling.Systems.PullingSystem; namespace Content.Server.NPC.HTN.Preconditions; @@ -7,14 +8,14 @@ namespace Content.Server.NPC.HTN.Preconditions; /// public sealed partial class PulledPrecondition : HTNPrecondition { - private SharedPullingSystem _pulling = default!; + private PullingSystem _pulling = default!; [ViewVariables(VVAccess.ReadWrite)] [DataField("isPulled")] public bool IsPulled = true; public override void Initialize(IEntitySystemManager sysManager) { base.Initialize(sysManager); - _pulling = sysManager.GetEntitySystem(); + _pulling = sysManager.GetEntitySystem(); } public override bool IsMet(NPCBlackboard blackboard) diff --git a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/MoveToOperator.cs b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/MoveToOperator.cs index dd35d2112c..e64343fdd8 100644 --- a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/MoveToOperator.cs +++ b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/MoveToOperator.cs @@ -4,6 +4,7 @@ using Content.Server.NPC.Pathfinding; using Content.Server.NPC.Systems; using Robust.Shared.Map; +using Robust.Shared.Map.Components; using Robust.Shared.Physics.Components; namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators; @@ -14,7 +15,6 @@ namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators; public sealed partial class MoveToOperator : HTNOperator, IHtnConditionalShutdown { [Dependency] private readonly IEntityManager _entManager = default!; - [Dependency] private readonly IMapManager _mapManager = default!; private NPCSteeringSystem _steering = default!; private PathfindingSystem _pathfind = default!; private SharedTransformSystem _transform = default!; @@ -85,8 +85,8 @@ public override void Initialize(IEntitySystemManager sysManager) !_entManager.TryGetComponent(owner, out var body)) return (false, null); - if (!_mapManager.TryGetGrid(xform.GridUid, out var ownerGrid) || - !_mapManager.TryGetGrid(targetCoordinates.GetGridUid(_entManager), out var targetGrid)) + if (!_entManager.TryGetComponent(xform.GridUid, out var ownerGrid) || + !_entManager.TryGetComponent(targetCoordinates.GetGridUid(_entManager), out var targetGrid)) { return (false, null); } diff --git a/Content.Server/NPC/Systems/NPCSteeringSystem.Context.cs b/Content.Server/NPC/Systems/NPCSteeringSystem.Context.cs index e7af2c9107..ce10d4f5d5 100644 --- a/Content.Server/NPC/Systems/NPCSteeringSystem.Context.cs +++ b/Content.Server/NPC/Systems/NPCSteeringSystem.Context.cs @@ -58,7 +58,7 @@ private bool IsFreeSpace( // TODO: Ideally for "FreeSpace" we check all entities on the tile and build flags dynamically (pathfinder refactor in future). var ents = _entSetPool.Get(); - _lookup.GetLocalEntitiesIntersecting(node.GraphUid, node.ChunkOrigin, ents, flags: LookupFlags.Static); + _lookup.GetLocalEntitiesIntersecting(node.GraphUid, node.Box.Enlarged(-0.04f), ents, flags: LookupFlags.Static); var result = true; if (ents.Count > 0) @@ -158,42 +158,42 @@ private bool TrySeek( } } + // Check if mapids match. + var targetMap = targetCoordinates.ToMap(EntityManager, _transform); + var ourMap = ourCoordinates.ToMap(EntityManager, _transform); + + if (targetMap.MapId != ourMap.MapId) + { + steering.Status = SteeringStatus.NoPath; + return false; + } + + var direction = targetMap.Position - ourMap.Position; + // Need to be pretty close if it's just a node to make sure LOS for door bashes or the likes. - float arrivalDistance; + bool arrived; if (targetCoordinates.Equals(steering.Coordinates)) { // What's our tolerance for arrival. // If it's a pathfinding node it might be different to the destination. - arrivalDistance = steering.Range; + arrived = direction.Length() <= steering.Range; } // If next node is a free tile then get within its bounds. // This is to avoid popping it too early else if (steering.CurrentPath.TryPeek(out var node) && IsFreeSpace(uid, steering, node)) { - arrivalDistance = MathF.Max(0.05f, MathF.Min(node.Box.Width / 2f, node.Box.Height / 2f) - 0.05f); + arrived = node.Box.Contains(ourCoordinates.Position); } // Try getting into blocked range I guess? // TODO: Consider melee range or the likes. else { - arrivalDistance = SharedInteractionSystem.InteractionRange - 0.05f; + arrived = direction.Length() <= SharedInteractionSystem.InteractionRange - 0.05f; } - // Check if mapids match. - var targetMap = targetCoordinates.ToMap(EntityManager, _transform); - var ourMap = ourCoordinates.ToMap(EntityManager, _transform); - - if (targetMap.MapId != ourMap.MapId) - { - steering.Status = SteeringStatus.NoPath; - return false; - } - - var direction = targetMap.Position - ourMap.Position; - // Are we in range - if (direction.Length() <= arrivalDistance) + if (arrived) { // Node needs some kind of special handling like access or smashing. if (steering.CurrentPath.TryPeek(out var node) && !IsFreeSpace(uid, steering, node)) diff --git a/Content.Server/NPC/Systems/NPCSteeringSystem.Obstacles.cs b/Content.Server/NPC/Systems/NPCSteeringSystem.Obstacles.cs index 70d1e89bc4..3bc4eae9e4 100644 --- a/Content.Server/NPC/Systems/NPCSteeringSystem.Obstacles.cs +++ b/Content.Server/NPC/Systems/NPCSteeringSystem.Obstacles.cs @@ -6,6 +6,7 @@ using Content.Shared.DoAfter; using Content.Shared.Doors.Components; using Content.Shared.NPC; +using Robust.Shared.Map.Components; using Robust.Shared.Physics; using Robust.Shared.Physics.Components; using Robust.Shared.Utility; @@ -201,7 +202,7 @@ private SteeringObstacleStatus TryHandleFlags(EntityUid uid, NPCSteeringComponen private void GetObstacleEntities(PathPoly poly, int mask, int layer, List ents) { // TODO: Can probably re-use this from pathfinding or something - if (!_mapManager.TryGetGrid(poly.GraphUid, out var grid)) + if (!TryComp(poly.GraphUid, out var grid)) { return; } diff --git a/Content.Server/NPC/Systems/NPCSteeringSystem.cs b/Content.Server/NPC/Systems/NPCSteeringSystem.cs index c00375d648..447792b6ff 100644 --- a/Content.Server/NPC/Systems/NPCSteeringSystem.cs +++ b/Content.Server/NPC/Systems/NPCSteeringSystem.cs @@ -45,7 +45,6 @@ public sealed partial class NPCSteeringSystem : SharedNPCSteeringSystem [Dependency] private readonly IAdminManager _admin = default!; [Dependency] private readonly IConfigurationManager _configManager = default!; [Dependency] private readonly IGameTiming _timing = default!; - [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly ClimbSystem _climb = default!; [Dependency] private readonly DoAfterSystem _doAfter = default!; @@ -273,6 +272,8 @@ private void SetDirection(InputMoverComponent component, NPCSteeringComponent st if (clear && value.Equals(Vector2.Zero)) { steering.CurrentPath.Clear(); + Array.Clear(steering.Interest); + Array.Clear(steering.Danger); } component.CurTickSprintMovement = value; diff --git a/Content.Server/Ninja/Systems/StunProviderSystem.cs b/Content.Server/Ninja/Systems/StunProviderSystem.cs index 636037060a..970ca78e2c 100644 --- a/Content.Server/Ninja/Systems/StunProviderSystem.cs +++ b/Content.Server/Ninja/Systems/StunProviderSystem.cs @@ -1,14 +1,11 @@ using Content.Server.Ninja.Events; using Content.Server.Power.EntitySystems; using Content.Shared.Damage; -using Content.Shared.Damage.Prototypes; using Content.Shared.Interaction; using Content.Shared.Ninja.Components; using Content.Shared.Ninja.Systems; using Content.Shared.Popups; using Content.Shared.Stunnable; -using Content.Shared.Whitelist; -using Robust.Shared.Audio; using Robust.Shared.Prototypes; using Robust.Shared.Audio.Systems; using Robust.Shared.Timing; @@ -23,7 +20,6 @@ public sealed class StunProviderSystem : SharedStunProviderSystem [Dependency] private readonly BatterySystem _battery = default!; [Dependency] private readonly DamageableSystem _damageable = default!; [Dependency] private readonly IGameTiming _timing = default!; - [Dependency] private readonly IPrototypeManager _proto = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly SharedNinjaGlovesSystem _gloves = default!; [Dependency] private readonly SharedPopupSystem _popup = default!; diff --git a/Content.Server/NodeContainer/EntitySystems/NodeGroupSystem.cs b/Content.Server/NodeContainer/EntitySystems/NodeGroupSystem.cs index 5e31bd6872..2296de2eb6 100644 --- a/Content.Server/NodeContainer/EntitySystems/NodeGroupSystem.cs +++ b/Content.Server/NodeContainer/EntitySystems/NodeGroupSystem.cs @@ -8,7 +8,7 @@ using JetBrains.Annotations; using Robust.Server.Player; using Robust.Shared.Enums; -using Robust.Shared.Map; +using Robust.Shared.Map.Components; using Robust.Shared.Player; using Robust.Shared.Utility; @@ -25,7 +25,6 @@ public sealed class NodeGroupSystem : EntitySystem [Dependency] private readonly IAdminManager _adminManager = default!; [Dependency] private readonly INodeGroupFactory _nodeGroupFactory = default!; [Dependency] private readonly ILogManager _logManager = default!; - [Dependency] private readonly IMapManager _mapManager = default!; private readonly List _visDeletes = new(); private readonly List _visSends = new(); @@ -343,7 +342,7 @@ private List FloodFillNode(Node rootNode) private IEnumerable GetCompatibleNodes(Node node, EntityQuery xformQuery, EntityQuery nodeQuery) { var xform = xformQuery.GetComponent(node.Owner); - _mapManager.TryGetGrid(xform.GridUid, out var grid); + TryComp(xform.GridUid, out var grid); if (!node.Connectable(EntityManager, xform)) yield break; diff --git a/Content.Server/Nuke/NukeSystem.cs b/Content.Server/Nuke/NukeSystem.cs index d6767cd2de..ad153dcf6b 100644 --- a/Content.Server/Nuke/NukeSystem.cs +++ b/Content.Server/Nuke/NukeSystem.cs @@ -18,6 +18,7 @@ using Robust.Shared.Audio.Systems; using Robust.Shared.Containers; using Robust.Shared.Map; +using Robust.Shared.Map.Components; using Robust.Shared.Player; using Robust.Shared.Random; @@ -28,7 +29,6 @@ public sealed class NukeSystem : EntitySystem [Dependency] private readonly AlertLevelSystem _alertLevel = default!; [Dependency] private readonly ChatSystem _chatSystem = default!; [Dependency] private readonly ExplosionSystem _explosions = default!; - [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly ITileDefinitionManager _tileDefManager = default!; [Dependency] private readonly ItemSlotsSystem _itemSlots = default!; @@ -175,7 +175,7 @@ private async void OnAnchorButtonPressed(EntityUid uid, NukeComponent component, } else { - if (!_mapManager.TryGetGrid(xform.GridUid, out var grid)) + if (!TryComp(xform.GridUid, out var grid)) return; var worldPos = _transform.GetWorldPosition(xform); diff --git a/Content.Server/Nutrition/EntitySystems/CreamPieSystem.cs b/Content.Server/Nutrition/EntitySystems/CreamPieSystem.cs index f8d781bcff..a28679ddbc 100644 --- a/Content.Server/Nutrition/EntitySystems/CreamPieSystem.cs +++ b/Content.Server/Nutrition/EntitySystems/CreamPieSystem.cs @@ -1,12 +1,11 @@ using Content.Server.Chemistry.Containers.EntitySystems; -using Content.Server.Explosion.Components; using Content.Server.Explosion.EntitySystems; using Content.Server.Fluids.EntitySystems; using Content.Server.Nutrition.Components; using Content.Server.Popups; using Content.Shared.Containers.ItemSlots; using Content.Shared.Explosion.Components; -using Content.Shared.Interaction; +using Content.Shared.Nutrition; using Content.Shared.Nutrition.Components; using Content.Shared.Nutrition.EntitySystems; using Content.Shared.Rejuvenate; @@ -32,7 +31,10 @@ public override void Initialize() { base.Initialize(); - SubscribeLocalEvent(OnInteractUsing); + // activate BEFORE entity is deleted and trash is spawned + SubscribeLocalEvent(OnConsume, before: [typeof(FoodSystem)]); + SubscribeLocalEvent(OnSlice); + SubscribeLocalEvent(OnRejuvenate); } @@ -56,7 +58,12 @@ protected override void SplattedCreamPie(EntityUid uid, CreamPieComponent creamP EntityManager.QueueDeleteEntity(uid); } - private void OnInteractUsing(Entity entity, ref InteractUsingEvent args) + private void OnConsume(Entity entity, ref ConsumeDoAfterEvent args) + { + ActivatePayload(entity); + } + + private void OnSlice(Entity entity, ref SliceFoodEvent args) { ActivatePayload(entity); } diff --git a/Content.Server/Nutrition/EntitySystems/SliceableFoodSystem.cs b/Content.Server/Nutrition/EntitySystems/SliceableFoodSystem.cs index e92b046f2e..abb6f393ac 100644 --- a/Content.Server/Nutrition/EntitySystems/SliceableFoodSystem.cs +++ b/Content.Server/Nutrition/EntitySystems/SliceableFoodSystem.cs @@ -1,11 +1,11 @@ using Content.Server.Nutrition; // DeltaV using Content.Server.Chemistry.Containers.EntitySystems; using Content.Server.Nutrition.Components; +using Content.Shared.Nutrition; using Content.Shared.Nutrition.Components; using Content.Shared.Chemistry.Components; using Content.Shared.Examine; using Content.Shared.FixedPoint; -using Content.Shared.Hands.EntitySystems; using Content.Shared.Interaction; using Robust.Server.GameObjects; using Robust.Shared.Audio; @@ -19,7 +19,6 @@ public sealed class SliceableFoodSystem : EntitySystem [Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly SharedContainerSystem _containerSystem = default!; - [Dependency] private readonly SharedHandsSystem _handsSystem = default!; [Dependency] private readonly TransformSystem _xformSystem = default!; public override void Initialize() @@ -67,6 +66,8 @@ private bool TrySliceFood(EntityUid uid, EntityUid user, EntityUid usedItem, FillSlice(sliceUid, lostSolution); _audio.PlayPvs(component.Sound, transform.Coordinates, AudioParams.Default.WithVolume(-2)); + var ev = new SliceFoodEvent(uid, user, usedItem); + RaiseLocalEvent(ev); // Decrease size of item based on count - Could implement in the future // Bug with this currently is the size in a container is not updated diff --git a/Content.Server/Nyanotrasen/Carrying/CarryingSystem.cs b/Content.Server/Nyanotrasen/Carrying/CarryingSystem.cs index 103731b1b0..ff4c097080 100644 --- a/Content.Server/Nyanotrasen/Carrying/CarryingSystem.cs +++ b/Content.Server/Nyanotrasen/Carrying/CarryingSystem.cs @@ -2,12 +2,10 @@ using System.Threading; using Content.Server.DoAfter; using Content.Server.Body.Systems; -using Content.Server.Hands.Systems; using Content.Server.Resist; using Content.Server.Popups; using Content.Server.Inventory; using Content.Server.Nyanotrasen.Item.PseudoItem; -using Content.Shared.Climbing; // Shared instead of Server using Content.Shared.Mobs; using Content.Shared.DoAfter; using Content.Shared.Buckle.Components; @@ -20,14 +18,14 @@ using Content.Shared.Carrying; using Content.Shared.Movement.Events; using Content.Shared.Movement.Systems; -using Content.Shared.Pulling; -using Content.Shared.Pulling.Components; using Content.Shared.Standing; using Content.Shared.ActionBlocker; using Content.Shared.Inventory.VirtualItem; using Content.Shared.Item; using Content.Shared.Throwing; -using Content.Shared.Physics.Pull; +using Content.Shared.Movement.Pulling.Components; +using Content.Shared.Movement.Pulling.Events; +using Content.Shared.Movement.Pulling.Systems; using Content.Shared.Mobs.Systems; using Content.Shared.Nyanotrasen.Item.PseudoItem; using Content.Shared.Storage; @@ -38,17 +36,16 @@ namespace Content.Server.Carrying { public sealed class CarryingSystem : EntitySystem { - [Dependency] private readonly VirtualItemSystem _virtualItemSystem = default!; + [Dependency] private readonly VirtualItemSystem _virtualItemSystem = default!; [Dependency] private readonly CarryingSlowdownSystem _slowdown = default!; [Dependency] private readonly DoAfterSystem _doAfterSystem = default!; [Dependency] private readonly StandingStateSystem _standingState = default!; [Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!; - [Dependency] private readonly SharedPullingSystem _pullingSystem = default!; + [Dependency] private readonly PullingSystem _pullingSystem = default!; [Dependency] private readonly MobStateSystem _mobStateSystem = default!; [Dependency] private readonly EscapeInventorySystem _escapeInventorySystem = default!; [Dependency] private readonly PopupSystem _popupSystem = default!; [Dependency] private readonly MovementSpeedModifierSystem _movementSpeed = default!; - [Dependency] private readonly RespiratorSystem _respirator = default!; [Dependency] private readonly PseudoItemSystem _pseudoItem = default!; public override void Initialize() @@ -280,8 +277,8 @@ private void StartCarryDoAfter(EntityUid carrier, EntityUid carried, CarriableCo private void Carry(EntityUid carrier, EntityUid carried) { - if (TryComp(carried, out var pullable)) - _pullingSystem.TryStopPull(pullable); + if (TryComp(carried, out var pullable)) + _pullingSystem.TryStopPull(carried, pullable); Transform(carrier).AttachToGridOrMap(); Transform(carried).AttachToGridOrMap(); diff --git a/Content.Server/Nyanotrasen/Kitchen/EntitySystems/DeepFryerSystem.cs b/Content.Server/Nyanotrasen/Kitchen/EntitySystems/DeepFryerSystem.cs index aa6de572ce..80c38f4630 100644 --- a/Content.Server/Nyanotrasen/Kitchen/EntitySystems/DeepFryerSystem.cs +++ b/Content.Server/Nyanotrasen/Kitchen/EntitySystems/DeepFryerSystem.cs @@ -86,7 +86,7 @@ public sealed partial class DeepFryerSystem : SharedDeepfryerSystem private static readonly string MobFlavorMeat = "meaty"; private static readonly AudioParams - AudioParamsInsertRemove = new(0.5f, 1f, "Master", 5f, 1.5f, 1f, false, 0f, 0.2f); + AudioParamsInsertRemove = new(0.5f, 1f, 5f, 1.5f, 1f, false, 0f, 0.2f); private ISawmill _sawmill = default!; diff --git a/Content.Server/Objectives/Systems/NinjaConditionsSystem.cs b/Content.Server/Objectives/Systems/NinjaConditionsSystem.cs index 2bd8538af1..888a365a5d 100644 --- a/Content.Server/Objectives/Systems/NinjaConditionsSystem.cs +++ b/Content.Server/Objectives/Systems/NinjaConditionsSystem.cs @@ -1,7 +1,6 @@ using Content.Server.Objectives.Components; using Content.Server.Warps; using Content.Shared.Objectives.Components; -using Content.Shared.Mind; using Content.Shared.Ninja.Components; using Robust.Shared.Random; using Content.Server.Roles; @@ -16,7 +15,6 @@ public sealed class NinjaConditionsSystem : EntitySystem { [Dependency] private readonly MetaDataSystem _metaData = default!; [Dependency] private readonly NumberObjectiveSystem _number = default!; - [Dependency] private readonly SharedMindSystem _mind = default!; [Dependency] private readonly IRobustRandom _random = default!; public override void Initialize() diff --git a/Content.Server/Objectives/Systems/StealConditionSystem.cs b/Content.Server/Objectives/Systems/StealConditionSystem.cs index 02d4ee010b..0fe6f0947c 100644 --- a/Content.Server/Objectives/Systems/StealConditionSystem.cs +++ b/Content.Server/Objectives/Systems/StealConditionSystem.cs @@ -6,11 +6,10 @@ using Robust.Shared.Containers; using Robust.Shared.Prototypes; using Robust.Shared.Random; -using Content.Shared.Pulling.Components; -using Content.Shared.Objectives; using Content.Shared.Mind.Components; using Content.Shared.Mobs.Systems; using Content.Shared.Mobs.Components; +using Content.Shared.Movement.Pulling.Components; namespace Content.Server.Objectives.Systems; @@ -100,19 +99,19 @@ private float GetProgress(MindComponent mind, StealConditionComponent condition) var count = 0; //check pulling object - if (TryComp(mind.OwnedEntity, out var pull)) //TO DO: to make the code prettier? don't like the repetition + if (TryComp(mind.OwnedEntity, out var pull)) //TO DO: to make the code prettier? don't like the repetition { - var pullid = pull.Pulling; - if (pullid != null) + var pulledEntity = pull.Pulling; + if (pulledEntity != null) { // check if this is the item - if (CheckStealTarget(pullid.Value, condition)) count++; + if (CheckStealTarget(pulledEntity.Value, condition)) count++; //we don't check the inventories of sentient entity - if (!TryComp(pullid, out var pullMind)) + if (!HasComp(pulledEntity)) { // if it is a container check its contents - if (_containerQuery.TryGetComponent(pullid, out var containerManager)) + if (_containerQuery.TryGetComponent(pulledEntity, out var containerManager)) stack.Push(containerManager); } } diff --git a/Content.Server/ParticleAccelerator/EntitySystems/ParticleAcceleratorSystem.cs b/Content.Server/ParticleAccelerator/EntitySystems/ParticleAcceleratorSystem.cs index ddc7e2a083..e9b62bc4a8 100644 --- a/Content.Server/ParticleAccelerator/EntitySystems/ParticleAcceleratorSystem.cs +++ b/Content.Server/ParticleAccelerator/EntitySystems/ParticleAcceleratorSystem.cs @@ -2,7 +2,6 @@ using Content.Server.Chat.Managers; using Content.Server.Projectiles; using Robust.Shared.Physics.Systems; -using Robust.Shared.Map; using Robust.Shared.Timing; using Robust.Server.GameObjects; using Robust.Shared.Configuration; @@ -13,7 +12,6 @@ public sealed partial class ParticleAcceleratorSystem : EntitySystem { [Dependency] private readonly IAdminLogManager _adminLogger = default!; [Dependency] private readonly IGameTiming _gameTiming = default!; - [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly IConfigurationManager _cfg = default!; [Dependency] private readonly IChatManager _chat = default!; [Dependency] private readonly ProjectileSystem _projectileSystem = default!; diff --git a/Content.Server/Physics/Controllers/MoverController.cs b/Content.Server/Physics/Controllers/MoverController.cs index c362507f19..759b8ef29c 100644 --- a/Content.Server/Physics/Controllers/MoverController.cs +++ b/Content.Server/Physics/Controllers/MoverController.cs @@ -6,17 +6,16 @@ using Content.Shared.Movement.Systems; using Content.Shared.Shuttles.Components; using Content.Shared.Shuttles.Systems; -using Robust.Shared.Map; using Robust.Shared.Physics.Components; using Robust.Shared.Player; using DroneConsoleComponent = Content.Server.Shuttles.DroneConsoleComponent; using DependencyAttribute = Robust.Shared.IoC.DependencyAttribute; +using Robust.Shared.Map.Components; namespace Content.Server.Physics.Controllers { public sealed class MoverController : SharedMoverController { - [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly ThrusterSystem _thruster = default!; [Dependency] private readonly SharedTransformSystem _xformSystem = default!; @@ -276,7 +275,7 @@ private void HandleShuttleMovement(float frameTime) var gridId = xform.GridUid; // This tries to see if the grid is a shuttle and if the console should work. - if (!_mapManager.TryGetGrid(gridId, out var _) || + if (!TryComp(gridId, out var _) || !shuttleQuery.TryGetComponent(gridId, out var shuttleComponent) || !shuttleComponent.Enabled) continue; diff --git a/Content.Server/Physics/Controllers/PullController.cs b/Content.Server/Physics/Controllers/PullController.cs deleted file mode 100644 index 8f58f807aa..0000000000 --- a/Content.Server/Physics/Controllers/PullController.cs +++ /dev/null @@ -1,207 +0,0 @@ -using System.Numerics; -using Content.Shared.ActionBlocker; -using Content.Shared.Gravity; -using Content.Shared.Pulling; -using Content.Shared.Pulling.Components; -using Content.Shared.Rotatable; -using Robust.Shared.Physics; -using Robust.Shared.Physics.Components; -using Robust.Shared.Physics.Controllers; - -namespace Content.Server.Physics.Controllers -{ - public sealed class PullController : VirtualController - { - // Parameterization for pulling: - // Speeds. Note that the speed is mass-independent (multiplied by mass). - // Instead, tuning to mass is done via the mass values below. - // Note that setting the speed too high results in overshoots (stabilized by drag, but bad) - private const float AccelModifierHigh = 15f; - private const float AccelModifierLow = 60.0f; - // High/low-mass marks. Curve is constant-lerp-constant, i.e. if you can even pull an item, - // you'll always get at least AccelModifierLow and no more than AccelModifierHigh. - private const float AccelModifierHighMass = 70.0f; // roundstart saltern emergency closet - private const float AccelModifierLowMass = 5.0f; // roundstart saltern emergency crowbar - // Used to control settling (turns off pulling). - private const float MaximumSettleVelocity = 0.1f; - private const float MaximumSettleDistance = 0.1f; - // Settle shutdown control. - // Mustn't be too massive, as that causes severe mispredicts *and can prevent it ever resolving*. - // Exists to bleed off "I pulled my crowbar" overshoots. - // Minimum velocity for shutdown to be necessary. This prevents stuff getting stuck b/c too much shutdown. - private const float SettleMinimumShutdownVelocity = 0.25f; - // Distance in which settle shutdown multiplier is at 0. It then scales upwards linearly with closer distances. - private const float SettleShutdownDistance = 1.0f; - // Velocity change of -LinearVelocity * frameTime * this - private const float SettleShutdownMultiplier = 20.0f; - - // How much you must move for the puller movement check to actually hit. - private const float MinimumMovementDistance = 0.005f; - - [Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!; - [Dependency] private readonly SharedPullingSystem _pullableSystem = default!; - [Dependency] private readonly SharedGravitySystem _gravity = default!; - [Dependency] private readonly SharedTransformSystem _transform = default!; - - // TODO: Move this stuff to pullingsystem - /// - /// If distance between puller and pulled entity lower that this threshold, - /// pulled entity will not change its rotation. - /// Helps with small distance jittering - /// - private const float ThresholdRotDistance = 1; - - /// - /// If difference between puller and pulled angle lower that this threshold, - /// pulled entity will not change its rotation. - /// Helps with diagonal movement jittering - /// As of further adjustments, should divide cleanly into 90 degrees - /// - private const float ThresholdRotAngle = 22.5f; - - public override void Initialize() - { - UpdatesAfter.Add(typeof(MoverController)); - SubscribeLocalEvent(OnPullerMove); - - base.Initialize(); - } - - private void OnPullerMove(EntityUid uid, SharedPullerComponent component, ref MoveEvent args) - { - if (component.Pulling is not { } pullable || !TryComp(pullable, out var pullableComponent)) - return; - - UpdatePulledRotation(uid, pullable); - - if (args.NewPosition.EntityId == args.OldPosition.EntityId && - (args.NewPosition.Position - args.OldPosition.Position).LengthSquared() < MinimumMovementDistance * MinimumMovementDistance) - return; - - if (TryComp(pullable, out var physics)) - PhysicsSystem.WakeBody(pullable, body: physics); - - _pullableSystem.StopMoveTo(pullableComponent); - } - - private void UpdatePulledRotation(EntityUid puller, EntityUid pulled) - { - // TODO: update once ComponentReference works with directed event bus. - if (!TryComp(pulled, out RotatableComponent? rotatable)) - return; - - if (!rotatable.RotateWhilePulling) - return; - - var xforms = GetEntityQuery(); - var pulledXform = xforms.GetComponent(pulled); - var pullerXform = xforms.GetComponent(puller); - - var pullerData = TransformSystem.GetWorldPositionRotation(pullerXform, xforms); - var pulledData = TransformSystem.GetWorldPositionRotation(pulledXform, xforms); - - var dir = pullerData.WorldPosition - pulledData.WorldPosition; - if (dir.LengthSquared() > ThresholdRotDistance * ThresholdRotDistance) - { - var oldAngle = pulledData.WorldRotation; - var newAngle = Angle.FromWorldVec(dir); - - var diff = newAngle - oldAngle; - if (Math.Abs(diff.Degrees) > ThresholdRotAngle / 2f) - { - // Ok, so this bit is difficult because ideally it would look like it's snapping to sane angles. - // Otherwise PIANO DOOR STUCK! happens. - // But it also needs to work with station rotation / align to the local parent. - // So... - var baseRotation = pulledData.WorldRotation - pulledXform.LocalRotation; - var localRotation = newAngle - baseRotation; - var localRotationSnapped = Angle.FromDegrees(Math.Floor((localRotation.Degrees / ThresholdRotAngle) + 0.5f) * ThresholdRotAngle); - TransformSystem.SetLocalRotation(pulledXform, localRotationSnapped); - } - } - } - - public override void UpdateBeforeSolve(bool prediction, float frameTime) - { - base.UpdateBeforeSolve(prediction, frameTime); - - foreach (var pullable in _pullableSystem.Moving) - { - // There's a 1-frame delay between stopping moving something and it leaving the Moving set. - // This can include if leaving the Moving set due to not being pulled anymore, - // or due to being deleted. - - if (pullable.Deleted) - continue; - - if (pullable.MovingTo == null) - continue; - - if (pullable.Puller is not {Valid: true} puller) - continue; - - var pullableEnt = pullable.Owner; - var pullableXform = Transform(pullableEnt); - var pullerXform = Transform(puller); - - // Now that's over with... - - var pullerPosition = pullerXform.MapPosition; - var movingTo = pullable.MovingTo.Value.ToMap(EntityManager, _transform); - if (movingTo.MapId != pullerPosition.MapId) - { - _pullableSystem.StopMoveTo(pullable); - continue; - } - - if (!TryComp(pullableEnt, out var physics) || - physics.BodyType == BodyType.Static || - movingTo.MapId != pullableXform.MapID) - { - _pullableSystem.StopMoveTo(pullable); - continue; - } - - var movingPosition = movingTo.Position; - var ownerPosition = pullableXform.MapPosition.Position; - - var diff = movingPosition - ownerPosition; - var diffLength = diff.Length(); - - if (diffLength < MaximumSettleDistance && physics.LinearVelocity.Length() < MaximumSettleVelocity) - { - PhysicsSystem.SetLinearVelocity(pullableEnt, Vector2.Zero, body: physics); - _pullableSystem.StopMoveTo(pullable); - continue; - } - - var impulseModifierLerp = Math.Min(1.0f, Math.Max(0.0f, (physics.Mass - AccelModifierLowMass) / (AccelModifierHighMass - AccelModifierLowMass))); - var impulseModifier = MathHelper.Lerp(AccelModifierLow, AccelModifierHigh, impulseModifierLerp); - var multiplier = diffLength < 1 ? impulseModifier * diffLength : impulseModifier; - // Note the implication that the real rules of physics don't apply to pulling control. - var accel = diff.Normalized() * multiplier; - // Now for the part where velocity gets shutdown... - if (diffLength < SettleShutdownDistance && physics.LinearVelocity.Length() >= SettleMinimumShutdownVelocity) - { - // Shutdown velocity increases as we get closer to centre - var scaling = (SettleShutdownDistance - diffLength) / SettleShutdownDistance; - accel -= physics.LinearVelocity * SettleShutdownMultiplier * scaling; - } - - PhysicsSystem.WakeBody(pullableEnt, body: physics); - - var impulse = accel * physics.Mass * frameTime; - PhysicsSystem.ApplyLinearImpulse(pullableEnt, impulse, body: physics); - - // if the puller is weightless or can't move, then we apply the inverse impulse (Newton's third law). - // doing it under gravity produces an unsatisfying wiggling when pulling. - // If player can't move, assume they are on a chair and we need to prevent pull-moving. - if ((_gravity.IsWeightless(puller) && pullerXform.GridUid == null) || !_actionBlockerSystem.CanMove(puller)) - { - PhysicsSystem.WakeBody(puller); - PhysicsSystem.ApplyLinearImpulse(puller, -impulse); - } - } - } - } -} diff --git a/Content.Server/Polymorph/Systems/PolymorphSystem.cs b/Content.Server/Polymorph/Systems/PolymorphSystem.cs index 66dc9dab99..5fe29dcd30 100644 --- a/Content.Server/Polymorph/Systems/PolymorphSystem.cs +++ b/Content.Server/Polymorph/Systems/PolymorphSystem.cs @@ -32,7 +32,6 @@ public sealed partial class PolymorphSystem : EntitySystem [Dependency] private readonly IPrototypeManager _proto = default!; [Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly ActionsSystem _actions = default!; - [Dependency] private readonly ActionContainerSystem _actionContainer = default!; [Dependency] private readonly AudioSystem _audio = default!; [Dependency] private readonly SharedBuckleSystem _buckle = default!; [Dependency] private readonly ContainerSystem _container = default!; diff --git a/Content.Server/Power/EntitySystems/CableSystem.Placer.cs b/Content.Server/Power/EntitySystems/CableSystem.Placer.cs index c5ca36c3a1..263d626ef5 100644 --- a/Content.Server/Power/EntitySystems/CableSystem.Placer.cs +++ b/Content.Server/Power/EntitySystems/CableSystem.Placer.cs @@ -4,6 +4,7 @@ using Content.Shared.Interaction; using Content.Shared.Maps; using Content.Shared.Stacks; +using Robust.Shared.Map.Components; namespace Content.Server.Power.EntitySystems; @@ -25,7 +26,7 @@ private void OnCablePlacerAfterInteract(Entity placer, ref if (component.CablePrototypeId == null) return; - if(!_mapManager.TryGetGrid(args.ClickLocation.GetGridUid(EntityManager), out var grid)) + if(!TryComp(args.ClickLocation.GetGridUid(EntityManager), out var grid)) return; var snapPos = grid.TileIndicesFor(args.ClickLocation); diff --git a/Content.Server/Power/EntitySystems/CableSystem.cs b/Content.Server/Power/EntitySystems/CableSystem.cs index dd478753be..62eb08d7cb 100644 --- a/Content.Server/Power/EntitySystems/CableSystem.cs +++ b/Content.Server/Power/EntitySystems/CableSystem.cs @@ -5,10 +5,7 @@ using Content.Shared.Database; using Content.Shared.DoAfter; using Content.Shared.Interaction; -using Content.Shared.Tools; -using Content.Shared.Tools.Components; using Robust.Shared.Map; -using System.Xml.Schema; using CableCuttingFinishedEvent = Content.Shared.Tools.Systems.CableCuttingFinishedEvent; using SharedToolSystem = Content.Shared.Tools.Systems.SharedToolSystem; @@ -16,13 +13,11 @@ namespace Content.Server.Power.EntitySystems; public sealed partial class CableSystem : EntitySystem { - [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly ITileDefinitionManager _tileManager = default!; [Dependency] private readonly SharedToolSystem _toolSystem = default!; [Dependency] private readonly StackSystem _stack = default!; [Dependency] private readonly ElectrocutionSystem _electrocutionSystem = default!; [Dependency] private readonly IAdminLogManager _adminLogs = default!; - [Dependency] private readonly PowerMonitoringConsoleSystem _powerMonitoringSystem = default!; public override void Initialize() { diff --git a/Content.Server/Power/EntitySystems/CableVisSystem.cs b/Content.Server/Power/EntitySystems/CableVisSystem.cs index fcf0ae3d58..ec08523d44 100644 --- a/Content.Server/Power/EntitySystems/CableVisSystem.cs +++ b/Content.Server/Power/EntitySystems/CableVisSystem.cs @@ -4,15 +4,13 @@ using Content.Server.Power.Nodes; using Content.Shared.Wires; using JetBrains.Annotations; -using Robust.Server.GameObjects; -using Robust.Shared.Map; +using Robust.Shared.Map.Components; namespace Content.Server.Power.EntitySystems { [UsedImplicitly] public sealed class CableVisSystem : EntitySystem { - [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly SharedAppearanceSystem _appearance = default!; [Dependency] private readonly NodeContainerSystem _nodeContainer = default!; @@ -32,7 +30,7 @@ private void UpdateAppearance(EntityUid uid, CableVisComponent cableVis, ref Nod return; var transform = Transform(uid); - if (!_mapManager.TryGetGrid(transform.GridUid, out var grid)) + if (!TryComp(transform.GridUid, out var grid)) return; var mask = WireVisDirFlags.None; diff --git a/Content.Server/Power/EntitySystems/ExtensionCableSystem.cs b/Content.Server/Power/EntitySystems/ExtensionCableSystem.cs index acfb8ff87b..85e553031f 100644 --- a/Content.Server/Power/EntitySystems/ExtensionCableSystem.cs +++ b/Content.Server/Power/EntitySystems/ExtensionCableSystem.cs @@ -1,6 +1,5 @@ using System.Diagnostics.CodeAnalysis; using Content.Server.Power.Components; -using Robust.Shared.Map; using Robust.Shared.Map.Components; using Robust.Shared.Physics; using Robust.Shared.Physics.Components; @@ -9,8 +8,6 @@ namespace Content.Server.Power.EntitySystems { public sealed class ExtensionCableSystem : EntitySystem { - [Dependency] private readonly IMapManager _mapManager = default!; - public override void Initialize() { base.Initialize(); diff --git a/Content.Server/Power/Generator/PortableGeneratorSystem.cs b/Content.Server/Power/Generator/PortableGeneratorSystem.cs index e8e9c5b45e..e7dfa35178 100644 --- a/Content.Server/Power/Generator/PortableGeneratorSystem.cs +++ b/Content.Server/Power/Generator/PortableGeneratorSystem.cs @@ -1,5 +1,4 @@ using Content.Server.DoAfter; -using Content.Server.NodeContainer.NodeGroups; using Content.Server.Popups; using Content.Server.Power.Components; using Content.Server.Power.EntitySystems; @@ -28,7 +27,6 @@ public sealed class PortableGeneratorSystem : SharedPortableGeneratorSystem [Dependency] private readonly GeneratorSystem _generator = default!; [Dependency] private readonly PowerSwitchableSystem _switchable = default!; [Dependency] private readonly ActiveGeneratorRevvingSystem _revving = default!; - [Dependency] private readonly PowerNetSystem _powerNet = default!; public override void Initialize() { diff --git a/Content.Server/Pulling/PullingSystem.cs b/Content.Server/Pulling/PullingSystem.cs deleted file mode 100644 index 69bb7c9370..0000000000 --- a/Content.Server/Pulling/PullingSystem.cs +++ /dev/null @@ -1,48 +0,0 @@ -using Content.Shared.Input; -using Content.Shared.Pulling; -using Content.Shared.Pulling.Components; -using JetBrains.Annotations; -using Robust.Server.GameObjects; -using Robust.Shared.Input.Binding; -using Robust.Shared.Player; - -namespace Content.Server.Pulling -{ - [UsedImplicitly] - public sealed class PullingSystem : SharedPullingSystem - { - public override void Initialize() - { - base.Initialize(); - - UpdatesAfter.Add(typeof(PhysicsSystem)); - - SubscribeLocalEvent(OnPullableMove); - SubscribeLocalEvent(OnPullableStopMove); - - CommandBinds.Builder - .Bind(ContentKeyFunctions.ReleasePulledObject, InputCmdHandler.FromDelegate(HandleReleasePulledObject)) - .Register(); - } - - private void HandleReleasePulledObject(ICommonSession? session) - { - if (session?.AttachedEntity is not {Valid: true} player) - { - return; - } - - if (!TryGetPulled(player, out var pulled)) - { - return; - } - - if (!EntityManager.TryGetComponent(pulled.Value, out SharedPullableComponent? pullable)) - { - return; - } - - TryStopPull(pullable); - } - } -} diff --git a/Content.Server/Radio/EntitySystems/RadioSystem.cs b/Content.Server/Radio/EntitySystems/RadioSystem.cs index 7ed7574a9a..bfdd49213e 100644 --- a/Content.Server/Radio/EntitySystems/RadioSystem.cs +++ b/Content.Server/Radio/EntitySystems/RadioSystem.cs @@ -115,12 +115,12 @@ public void SendRadioMessage(EntityUid messageSource, string message, RadioChann ? FormattedMessage.EscapeText(message) : message; - var wrappedMessage = WrapRadioMessage(messageSource, channel, name, content); + var wrappedMessage = WrapRadioMessage(messageSource, channel, name, content, language); var msg = new ChatMessage(ChatChannel.Radio, content, wrappedMessage, NetEntity.Invalid, null); // ... you guess it var obfuscated = _language.ObfuscateSpeech(content, language); - var obfuscatedWrapped = WrapRadioMessage(messageSource, channel, name, obfuscated); + var obfuscatedWrapped = WrapRadioMessage(messageSource, channel, name, obfuscated, language); var notUdsMsg = new ChatMessage(ChatChannel.Radio, obfuscated, obfuscatedWrapped, NetEntity.Invalid, null); var ev = new RadioReceiveEvent(messageSource, channel, msg, notUdsMsg, language); @@ -173,13 +173,14 @@ public void SendRadioMessage(EntityUid messageSource, string message, RadioChann _messages.Remove(message); } - private string WrapRadioMessage(EntityUid source, RadioChannelPrototype channel, string name, string message) + private string WrapRadioMessage(EntityUid source, RadioChannelPrototype channel, string name, string message, LanguagePrototype language) { var speech = _chat.GetSpeechVerb(source, message); return Loc.GetString(speech.Bold ? "chat-radio-message-wrap-bold" : "chat-radio-message-wrap", ("color", channel.Color), - ("fontType", speech.FontId), - ("fontSize", speech.FontSize), + ("languageColor", language.Color ?? channel.Color), + ("fontType", language.FontId ?? speech.FontId), + ("fontSize", language.FontSize ?? speech.FontSize), ("verb", Loc.GetString(_random.Pick(speech.SpeechVerbStrings))), ("channel", $"\\[{channel.LocalizedName}\\]"), ("name", name), diff --git a/Content.Server/RatKing/RatKingSystem.cs b/Content.Server/RatKing/RatKingSystem.cs index f676e89ac3..4b82dba335 100644 --- a/Content.Server/RatKing/RatKingSystem.cs +++ b/Content.Server/RatKing/RatKingSystem.cs @@ -11,7 +11,6 @@ using Content.Shared.Nutrition.EntitySystems; using Content.Shared.Pointing; using Content.Shared.RatKing; -using Robust.Server.GameObjects; using Robust.Shared.Map; using Robust.Shared.Random; @@ -26,7 +25,6 @@ public sealed class RatKingSystem : SharedRatKingSystem [Dependency] private readonly HungerSystem _hunger = default!; [Dependency] private readonly NPCSystem _npc = default!; [Dependency] private readonly PopupSystem _popup = default!; - [Dependency] private readonly TransformSystem _xform = default!; public override void Initialize() { diff --git a/Content.Server/Remotes/DoorRemoteComponent.cs b/Content.Server/Remotes/DoorRemoteComponent.cs deleted file mode 100644 index 91cb7ccad1..0000000000 --- a/Content.Server/Remotes/DoorRemoteComponent.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace Content.Server.Remotes -{ - [RegisterComponent] - [Access(typeof(DoorRemoteSystem))] - public sealed partial class DoorRemoteComponent : Component - { - public OperatingMode Mode = OperatingMode.OpenClose; - - public enum OperatingMode : byte - { - OpenClose, - ToggleBolts, - ToggleEmergencyAccess - } - } -} diff --git a/Content.Server/Remotes/DoorRemoteSystem.cs b/Content.Server/Remotes/DoorRemoteSystem.cs index d335911901..e42bc70091 100644 --- a/Content.Server/Remotes/DoorRemoteSystem.cs +++ b/Content.Server/Remotes/DoorRemoteSystem.cs @@ -1,74 +1,43 @@ using Content.Server.Administration.Logs; -using Robust.Shared.Player; using Content.Shared.Interaction; -using Content.Shared.Popups; using Content.Shared.Doors.Components; -using Content.Shared.Doors.Systems; -using Content.Shared.Physics; using Content.Shared.Access.Components; using Content.Server.Doors.Systems; using Content.Server.Power.EntitySystems; using Content.Shared.Database; -using Content.Shared.Interaction.Events; using Content.Shared.Examine; -using static Content.Server.Remotes.DoorRemoteComponent; +using Content.Shared.Remotes.EntitySystems; +using Content.Shared.Remotes.Components; -namespace Content.Server.Remotes +namespace Content.Shared.Remotes { - public sealed class DoorRemoteSystem : EntitySystem + public sealed class DoorRemoteSystem : SharedDoorRemoteSystem { [Dependency] private readonly IAdminLogManager _adminLogger = default!; [Dependency] private readonly AirlockSystem _airlock = default!; - [Dependency] private readonly SharedPopupSystem _popupSystem = default!; [Dependency] private readonly DoorSystem _doorSystem = default!; [Dependency] private readonly SharedInteractionSystem _interactionSystem = default!; [Dependency] private readonly ExamineSystemShared _examine = default!; // I'm so sorry [Dependency] private readonly SharedAirlockSystem _sharedAirlockSystem = default!; - + public override void Initialize() { - SubscribeLocalEvent(OnInHandActivation); - SubscribeLocalEvent(OnBeforeInteract); - } - - public void OnInHandActivation(EntityUid user, DoorRemoteComponent component, UseInHandEvent args) - { - string switchMessageId; - switch (component.Mode) - { - case OperatingMode.OpenClose: - component.Mode = OperatingMode.ToggleBolts; - switchMessageId = "door-remote-switch-state-toggle-bolts"; - break; + base.Initialize(); - // Skip toggle bolts mode and move on from there (to emergency access) - case OperatingMode.ToggleBolts: - component.Mode = OperatingMode.ToggleEmergencyAccess; - switchMessageId = "door-remote-switch-state-toggle-emergency-access"; - break; - - // Skip ToggleEmergencyAccess mode and move on from there (to door toggle) - case OperatingMode.ToggleEmergencyAccess: - component.Mode = OperatingMode.OpenClose; - switchMessageId = "door-remote-switch-state-open-close"; - break; - default: - throw new InvalidOperationException( - $"{nameof(DoorRemoteComponent)} had invalid mode {component.Mode}"); - } - ShowPopupToUser(switchMessageId, args.User); + SubscribeLocalEvent(OnBeforeInteract); } - private void OnBeforeInteract(EntityUid uid, DoorRemoteComponent component, BeforeRangedInteractEvent args) + private void OnBeforeInteract(Entity entity, ref BeforeRangedInteractEvent args) { bool isAirlock = TryComp(args.Target, out var airlockComp); if (args.Handled || args.Target == null || !TryComp(args.Target, out var doorComp) // If it isn't a door we don't use it - // Only able to control doors if they are within your vision and within your max range. - // Not affected by mobs or machines anymore. + // Only able to control doors if they are within your vision and within your max range. + // Not affected by mobs or machines anymore. || !_examine.InRangeUnOccluded(args.User, args.Target.Value, SharedInteractionSystem.MaxRaycastRange, null)) + { return; } @@ -77,7 +46,7 @@ private void OnBeforeInteract(EntityUid uid, DoorRemoteComponent component, Befo if (!this.IsPowered(args.Target.Value, EntityManager)) { - ShowPopupToUser("door-remote-no-power", args.User); + Popup.PopupEntity(Loc.GetString("door-remote-no-power"), args.User, args.User); return; } @@ -85,11 +54,11 @@ private void OnBeforeInteract(EntityUid uid, DoorRemoteComponent component, Befo && !_doorSystem.HasAccess(args.Target.Value, args.Used, doorComp, accessComponent)) { _doorSystem.Deny(args.Target.Value, doorComp, args.User); - ShowPopupToUser("door-remote-denied", args.User); + Popup.PopupEntity(Loc.GetString("door-remote-denied"), args.User, args.User); return; } - switch (component.Mode) + switch (entity.Comp.Mode) { case OperatingMode.OpenClose: if (_doorSystem.TryToggleDoor(args.Target.Value, doorComp, args.Used)) @@ -115,11 +84,8 @@ private void OnBeforeInteract(EntityUid uid, DoorRemoteComponent component, Befo break; default: throw new InvalidOperationException( - $"{nameof(DoorRemoteComponent)} had invalid mode {component.Mode}"); + $"{nameof(DoorRemoteComponent)} had invalid mode {entity.Comp.Mode}"); } } - - private void ShowPopupToUser(string messageId, EntityUid user) => - _popupSystem.PopupEntity(Loc.GetString(messageId), user, user); } } diff --git a/Content.Server/Research/Systems/ResearchStealerSystem.cs b/Content.Server/Research/Systems/ResearchStealerSystem.cs index 5bab6048de..d40134f1e9 100644 --- a/Content.Server/Research/Systems/ResearchStealerSystem.cs +++ b/Content.Server/Research/Systems/ResearchStealerSystem.cs @@ -1,11 +1,13 @@ using Content.Shared.Research.Components; using Content.Shared.Research.Systems; +using Robust.Shared.Random; namespace Content.Server.Research.Systems; public sealed class ResearchStealerSystem : SharedResearchStealerSystem { [Dependency] private readonly SharedResearchSystem _research = default!; + [Dependency] private readonly IRobustRandom _random = default!; public override void Initialize() { @@ -24,16 +26,26 @@ private void OnDoAfter(EntityUid uid, ResearchStealerComponent comp, ResearchSte if (!TryComp(target, out var database)) return; - var ev = new ResearchStolenEvent(uid, target, database.UnlockedTechnologies); + var ev = new ResearchStolenEvent(uid, target, new()); + var count = _random.Next(comp.MinToSteal, comp.MaxToSteal + 1); + for (var i = 0; i < count; i++) + { + if (database.UnlockedTechnologies.Count == 0) + break; + + var toRemove = _random.Pick(database.UnlockedTechnologies); + if (_research.TryRemoveTechnology((target, database), toRemove)) + ev.Techs.Add(toRemove); + } RaiseLocalEvent(uid, ref ev); - // oops, no more advanced lasers! - _research.ClearTechs(target, database); + + args.Handled = true; } } /// -/// Event raised on the user when research is stolen from a R&D server. +/// Event raised on the user when research is stolen from a RND server. /// Techs contains every technology id researched. /// [ByRefEvent] -public record struct ResearchStolenEvent(EntityUid Used, EntityUid Target, List Techs); +public record struct ResearchStolenEvent(EntityUid Used, EntityUid Target, List Techs); diff --git a/Content.Server/Respawn/SpecialRespawnSystem.cs b/Content.Server/Respawn/SpecialRespawnSystem.cs index 2822c94093..2463bcd740 100644 --- a/Content.Server/Respawn/SpecialRespawnSystem.cs +++ b/Content.Server/Respawn/SpecialRespawnSystem.cs @@ -9,13 +9,13 @@ using Content.Shared.Physics; using Content.Shared.Respawn; using Robust.Shared.Map; +using Robust.Shared.Map.Components; using Robust.Shared.Random; namespace Content.Server.Respawn; public sealed class SpecialRespawnSystem : SharedSpecialRespawnSystem { - [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly IAdminLogManager _adminLog = default!; [Dependency] private readonly ITileDefinitionManager _tileDefinitionManager = default!; [Dependency] private readonly AtmosphereSystem _atmosphere = default!; @@ -84,7 +84,7 @@ private void OnTermination(EntityUid uid, SpecialRespawnComponent component, ref if (!component.Respawn || !HasComp(entityGridUid) || entityMapUid == null) return; - if (!_mapManager.TryGetGrid(entityGridUid, out var grid) || MetaData(entityGridUid.Value).EntityLifeStage >= EntityLifeStage.Terminating) + if (!TryComp(entityGridUid, out var grid) || MetaData(entityGridUid.Value).EntityLifeStage >= EntityLifeStage.Terminating) return; if (TryFindRandomTile(entityGridUid.Value, entityMapUid.Value, 10, out var coords)) @@ -146,7 +146,7 @@ public bool TryFindRandomTile(EntityUid targetGrid, EntityUid targetMap, int max { targetCoords = EntityCoordinates.Invalid; - if (!_mapManager.TryGetGrid(targetGrid, out var grid)) + if (!TryComp(targetGrid, out var grid)) return false; var xform = Transform(targetGrid); diff --git a/Content.Server/Revenant/EntitySystems/RevenantSystem.Abilities.cs b/Content.Server/Revenant/EntitySystems/RevenantSystem.Abilities.cs index eb6eb5a426..cd64f043a0 100644 --- a/Content.Server/Revenant/EntitySystems/RevenantSystem.Abilities.cs +++ b/Content.Server/Revenant/EntitySystems/RevenantSystem.Abilities.cs @@ -2,7 +2,6 @@ using Content.Shared.Damage; using Content.Shared.Revenant; using Robust.Shared.Random; -using Robust.Shared.Map; using Content.Shared.Tag; using Content.Server.Storage.Components; using Content.Server.Light.Components; @@ -15,7 +14,6 @@ using Content.Shared.Bed.Sleep; using System.Linq; using System.Numerics; -using Content.Server.Maps; using Content.Server.Revenant.Components; using Content.Shared.DoAfter; using Content.Shared.Emag.Systems; @@ -28,12 +26,12 @@ using Content.Shared.Revenant.Components; using Robust.Shared.Physics.Components; using Robust.Shared.Utility; +using Robust.Shared.Map.Components; namespace Content.Server.Revenant.EntitySystems; public sealed partial class RevenantSystem { - [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly ThrowingSystem _throwing = default!; [Dependency] private readonly EntityStorageSystem _entityStorage = default!; [Dependency] private readonly EmagSystem _emag = default!; @@ -213,7 +211,7 @@ private void OnDefileAction(EntityUid uid, RevenantComponent component, Revenant //var coords = Transform(uid).Coordinates; //var gridId = coords.GetGridUid(EntityManager); var xform = Transform(uid); - if (!_mapManager.TryGetGrid(xform.GridUid, out var map)) + if (!TryComp(xform.GridUid, out var map)) return; var tiles = map.GetTilesIntersecting(Box2.CenteredAround(xform.WorldPosition, new Vector2(component.DefileRadius * 2, component.DefileRadius))).ToArray(); diff --git a/Content.Server/Roles/RemoveRoleCommand.cs b/Content.Server/Roles/RemoveRoleCommand.cs index edb29da624..feba63a253 100644 --- a/Content.Server/Roles/RemoveRoleCommand.cs +++ b/Content.Server/Roles/RemoveRoleCommand.cs @@ -5,14 +5,12 @@ using Content.Shared.Roles.Jobs; using Robust.Server.Player; using Robust.Shared.Console; -using Robust.Shared.Prototypes; namespace Content.Server.Roles { [AdminCommand(AdminFlags.Admin)] public sealed class RemoveRoleCommand : IConsoleCommand { - [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly IEntityManager _entityManager = default!; public string Command => "rmrole"; diff --git a/Content.Server/Salvage/SalvageSystem.Expeditions.cs b/Content.Server/Salvage/SalvageSystem.Expeditions.cs index 7e4a9c9310..36e3a574ea 100644 --- a/Content.Server/Salvage/SalvageSystem.Expeditions.cs +++ b/Content.Server/Salvage/SalvageSystem.Expeditions.cs @@ -162,6 +162,8 @@ private void SpawnMission(SalvageMissionParams missionParams, EntityUid station) _biome, _dungeon, _metaData, + _transform, + _mapSystem, station, missionParams, cancelToken.Token); diff --git a/Content.Server/Salvage/SalvageSystem.cs b/Content.Server/Salvage/SalvageSystem.cs index a1a3b686b2..5a68005dd3 100644 --- a/Content.Server/Salvage/SalvageSystem.cs +++ b/Content.Server/Salvage/SalvageSystem.cs @@ -53,6 +53,7 @@ public sealed partial class SalvageSystem : SharedSalvageSystem [Dependency] private readonly RadioSystem _radioSystem = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; + [Dependency] private readonly SharedMapSystem _mapSystem = default!; [Dependency] private readonly ShuttleSystem _shuttle = default!; [Dependency] private readonly ShuttleConsoleSystem _shuttleConsoles = default!; [Dependency] private readonly StationSystem _station = default!; diff --git a/Content.Server/Salvage/SpawnSalvageMissionJob.cs b/Content.Server/Salvage/SpawnSalvageMissionJob.cs index e2b17b5872..5f7e356830 100644 --- a/Content.Server/Salvage/SpawnSalvageMissionJob.cs +++ b/Content.Server/Salvage/SpawnSalvageMissionJob.cs @@ -46,6 +46,8 @@ public sealed class SpawnSalvageMissionJob : Job private readonly BiomeSystem _biome; private readonly DungeonSystem _dungeon; private readonly MetaDataSystem _metaData; + private readonly SharedTransformSystem _xforms; + private readonly SharedMapSystem _map; public readonly EntityUid Station; private readonly SalvageMissionParams _missionParams; @@ -63,6 +65,8 @@ public SpawnSalvageMissionJob( BiomeSystem biome, DungeonSystem dungeon, MetaDataSystem metaData, + SharedTransformSystem xform, + SharedMapSystem map, EntityUid station, SalvageMissionParams missionParams, CancellationToken cancellation = default) : base(maxTime, cancellation) @@ -75,6 +79,8 @@ public SpawnSalvageMissionJob( _biome = biome; _dungeon = dungeon; _metaData = metaData; + _xforms = xform; + _map = map; Station = station; _missionParams = missionParams; _sawmill = logManager.GetSawmill("salvage_job"); @@ -86,9 +92,7 @@ public SpawnSalvageMissionJob( protected override async Task Process() { _sawmill.Debug("salvage", $"Spawning salvage mission with seed {_missionParams.Seed}"); - var mapId = _mapManager.CreateMap(); - var mapUid = _mapManager.GetMapEntityId(mapId); - _mapManager.AddUninitializedMap(mapId); + var mapUid = _map.CreateMap(out var mapId, runMapInit: false); MetaDataComponent? metadata = null; var grid = _entManager.EnsureComponent(mapUid); var random = new Random(_missionParams.Seed); diff --git a/Content.Server/Sandbox/Commands/ColorNetworkCommand.cs b/Content.Server/Sandbox/Commands/ColorNetworkCommand.cs index 2ab29d1b2f..6ce8edd1d8 100644 --- a/Content.Server/Sandbox/Commands/ColorNetworkCommand.cs +++ b/Content.Server/Sandbox/Commands/ColorNetworkCommand.cs @@ -11,7 +11,6 @@ namespace Content.Server.Sandbox.Commands [AnyCommand] public sealed class ColorNetworkCommand : IConsoleCommand { - [Dependency] private readonly IAdminManager _adminManager = default!; [Dependency] private readonly IEntityManager _entManager = default!; public string Command => "colornetwork"; diff --git a/Content.Server/Shuttles/Systems/ArrivalsSystem.cs b/Content.Server/Shuttles/Systems/ArrivalsSystem.cs index f4dd502b37..ae742cf1f9 100644 --- a/Content.Server/Shuttles/Systems/ArrivalsSystem.cs +++ b/Content.Server/Shuttles/Systems/ArrivalsSystem.cs @@ -1,13 +1,10 @@ using System.Linq; -using System.Numerics; using Content.Server.Administration; using Content.Server.GameTicking; using Content.Server.GameTicking.Events; using Content.Server.Parallax; -using Content.Server.DeviceNetwork; using Content.Server.DeviceNetwork.Components; using Content.Server.DeviceNetwork.Systems; -using Content.Server.Salvage; using Content.Server.Screens.Components; using Content.Server.Shuttles.Components; using Content.Server.Shuttles.Events; @@ -22,7 +19,6 @@ using Content.Shared.Parallax.Biomes; using Content.Shared.Salvage; using Content.Shared.Shuttles.Components; -using Robust.Shared.Spawners; using Content.Shared.Tiles; using Robust.Server.GameObjects; using Robust.Shared.Collections; @@ -51,7 +47,6 @@ public sealed class ArrivalsSystem : EntitySystem [Dependency] private readonly GameTicker _ticker = default!; [Dependency] private readonly MapLoaderSystem _loader = default!; [Dependency] private readonly DeviceNetworkSystem _deviceNetworkSystem = default!; - [Dependency] private readonly RestrictedRangeSystem _restricted = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; [Dependency] private readonly ShuttleSystem _shuttles = default!; [Dependency] private readonly StationSpawningSystem _stationSpawning = default!; diff --git a/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.cs b/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.cs index f8d995b8a4..39b76f7d32 100644 --- a/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.cs +++ b/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.cs @@ -492,7 +492,7 @@ private void AddEmergencyShuttle(EntityUid uid, StationEmergencyShuttleComponent return; } - centcomm.ShuttleIndex += _mapManager.GetGrid(shuttle.Value).LocalAABB.Width + ShuttleSpawnBuffer; + centcomm.ShuttleIndex += Comp(shuttle.Value).LocalAABB.Width + ShuttleSpawnBuffer; // Update indices for all centcomm comps pointing to same map var query = AllEntityQuery(); diff --git a/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs b/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs index e4e4534b0c..cb322ac396 100644 --- a/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs +++ b/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs @@ -559,7 +559,7 @@ private void UpdateHyperspace(float frameTime) private float GetSoundRange(EntityUid uid) { - if (!_mapManager.TryGetGrid(uid, out var grid)) + if (!TryComp(uid, out var grid)) return 4f; return MathF.Max(grid.LocalAABB.Width, grid.LocalAABB.Height) + 12.5f; diff --git a/Content.Server/Shuttles/Systems/ThrusterSystem.cs b/Content.Server/Shuttles/Systems/ThrusterSystem.cs index 1baffd4690..74c42ccbc5 100644 --- a/Content.Server/Shuttles/Systems/ThrusterSystem.cs +++ b/Content.Server/Shuttles/Systems/ThrusterSystem.cs @@ -1,6 +1,5 @@ using System.Numerics; using Content.Server.Audio; -using Content.Server.Construction; using Content.Server.Power.Components; using Content.Server.Power.EntitySystems; using Content.Server.Shuttles.Components; @@ -12,6 +11,7 @@ using Content.Shared.Shuttles.Components; using Content.Shared.Temperature; using Robust.Shared.Map; +using Robust.Shared.Map.Components; using Robust.Shared.Physics.Collision.Shapes; using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Events; @@ -24,7 +24,6 @@ namespace Content.Server.Shuttles.Systems; public sealed class ThrusterSystem : EntitySystem { [Dependency] private readonly IGameTiming _timing = default!; - [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly ITileDefinitionManager _tileDefManager = default!; [Dependency] private readonly AmbientSoundSystem _ambient = default!; [Dependency] private readonly FixtureSystem _fixtureSystem = default!; @@ -95,7 +94,7 @@ private void OnShuttleTileChange(EntityUid uid, ShuttleComponent component, ref return; var tilePos = args.NewTile.GridIndices; - var grid = _mapManager.GetGrid(uid); + var grid = Comp(uid); var xformQuery = GetEntityQuery(); var thrusterQuery = GetEntityQuery(); @@ -436,7 +435,7 @@ private bool NozzleExposed(TransformComponent xform) return true; var (x, y) = xform.LocalPosition + xform.LocalRotation.Opposite().ToWorldVec(); - var tile = _mapManager.GetGrid(xform.GridUid.Value).GetTileRef(new Vector2i((int) Math.Floor(x), (int) Math.Floor(y))); + var tile = Comp(xform.GridUid.Value).GetTileRef(new Vector2i((int) Math.Floor(x), (int) Math.Floor(y))); return tile.Tile.IsSpace(); } diff --git a/Content.Server/Silicons/Laws/SiliconLawSystem.cs b/Content.Server/Silicons/Laws/SiliconLawSystem.cs index 4584a9e88b..010682bc0d 100644 --- a/Content.Server/Silicons/Laws/SiliconLawSystem.cs +++ b/Content.Server/Silicons/Laws/SiliconLawSystem.cs @@ -19,7 +19,6 @@ using Content.Shared.Stunnable; using Content.Shared.Wires; using Robust.Server.GameObjects; -using Robust.Shared.Audio.Systems; using Robust.Shared.Player; using Robust.Shared.Prototypes; using Robust.Shared.Toolshed; @@ -38,7 +37,6 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem [Dependency] private readonly SharedStunSystem _stunSystem = default!; [Dependency] private readonly IEntityManager _entityManager = default!; [Dependency] private readonly SharedRoleSystem _roles = default!; - [Dependency] private readonly SharedAudioSystem _audioSystem = default!; /// public override void Initialize() diff --git a/Content.Server/Singularity/EntitySystems/EventHorizonSystem.cs b/Content.Server/Singularity/EntitySystems/EventHorizonSystem.cs index ba07375699..ed53c3e101 100644 --- a/Content.Server/Singularity/EntitySystems/EventHorizonSystem.cs +++ b/Content.Server/Singularity/EntitySystems/EventHorizonSystem.cs @@ -232,7 +232,7 @@ public void ConsumeEntitiesInContainer(EntityUid hungry, BaseContainer container /// public void ConsumeTile(EntityUid hungry, TileRef tile, EventHorizonComponent eventHorizon) { - ConsumeTiles(hungry, new List<(Vector2i, Tile)>(new[] { (tile.GridIndices, Tile.Empty) }), tile.GridUid, _mapMan.GetGrid(tile.GridUid), eventHorizon); + ConsumeTiles(hungry, new List<(Vector2i, Tile)>(new[] { (tile.GridIndices, Tile.Empty) }), tile.GridUid, Comp(tile.GridUid), eventHorizon); } /// @@ -240,7 +240,7 @@ public void ConsumeTile(EntityUid hungry, TileRef tile, EventHorizonComponent ev /// public void AttemptConsumeTile(EntityUid hungry, TileRef tile, EventHorizonComponent eventHorizon) { - AttemptConsumeTiles(hungry, new TileRef[1] { tile }, tile.GridUid, _mapMan.GetGrid(tile.GridUid), eventHorizon); + AttemptConsumeTiles(hungry, new TileRef[1] { tile }, tile.GridUid, Comp(tile.GridUid), eventHorizon); } /// diff --git a/Content.Server/Singularity/EntitySystems/RadiationCollectorSystem.cs b/Content.Server/Singularity/EntitySystems/RadiationCollectorSystem.cs index 92b963e201..b26ab301c6 100644 --- a/Content.Server/Singularity/EntitySystems/RadiationCollectorSystem.cs +++ b/Content.Server/Singularity/EntitySystems/RadiationCollectorSystem.cs @@ -24,7 +24,6 @@ public sealed class RadiationCollectorSystem : EntitySystem [Dependency] private readonly SharedAppearanceSystem _appearance = default!; [Dependency] private readonly SharedContainerSystem _containerSystem = default!; [Dependency] private readonly UseDelaySystem _useDelay = default!; - [Dependency] private readonly BatterySystem _batterySystem = default!; private const string GasTankContainer = "gas_tank"; diff --git a/Content.Server/Species/Systems/NymphSystem.cs b/Content.Server/Species/Systems/NymphSystem.cs index b7751afbf1..d491b957bf 100644 --- a/Content.Server/Species/Systems/NymphSystem.cs +++ b/Content.Server/Species/Systems/NymphSystem.cs @@ -19,10 +19,10 @@ public override void Initialize() { base.Initialize(); - SubscribeLocalEvent(OnRemovedFromPart); + SubscribeLocalEvent(OnRemovedFromPart); } - private void OnRemovedFromPart(EntityUid uid, NymphComponent comp, RemovedFromPartInBodyEvent args) + private void OnRemovedFromPart(EntityUid uid, NymphComponent comp, ref OrganRemovedFromBodyEvent args) { if (!_timing.IsFirstTimePredicted) return; diff --git a/Content.Server/Spreader/SpreaderSystem.cs b/Content.Server/Spreader/SpreaderSystem.cs index 5b2f3298a2..671c281d1f 100644 --- a/Content.Server/Spreader/SpreaderSystem.cs +++ b/Content.Server/Spreader/SpreaderSystem.cs @@ -18,7 +18,6 @@ namespace Content.Server.Spreader; /// public sealed class SpreaderSystem : EntitySystem { - [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly IPrototypeManager _prototype = default!; [Dependency] private readonly IRobustRandom _robustRandom = default!; [Dependency] private readonly SharedMapSystem _map = default!; diff --git a/Content.Server/Station/Systems/StationJobsSystem.cs b/Content.Server/Station/Systems/StationJobsSystem.cs index a3b7a57354..debac8902e 100644 --- a/Content.Server/Station/Systems/StationJobsSystem.cs +++ b/Content.Server/Station/Systems/StationJobsSystem.cs @@ -25,7 +25,6 @@ public sealed partial class StationJobsSystem : EntitySystem [Dependency] private readonly IConfigurationManager _configurationManager = default!; [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly GameTicker _gameTicker = default!; - [Dependency] private readonly StationSystem _stationSystem = default!; [Dependency] private readonly IPlayerManager _playerManager = default!; /// diff --git a/Content.Server/Station/Systems/StationSystem.cs b/Content.Server/Station/Systems/StationSystem.cs index b9ff8a4339..492f15c8e2 100644 --- a/Content.Server/Station/Systems/StationSystem.cs +++ b/Content.Server/Station/Systems/StationSystem.cs @@ -29,7 +29,6 @@ public sealed class StationSystem : EntitySystem { [Dependency] private readonly IConfigurationManager _configurationManager = default!; [Dependency] private readonly ILogManager _logManager = default!; - [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly IPlayerManager _player = default!; [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly ChatSystem _chatSystem = default!; diff --git a/Content.Server/StationEvents/Components/RampingStationEventSchedulerComponent.cs b/Content.Server/StationEvents/Components/RampingStationEventSchedulerComponent.cs index 53bc8b62a4..282ee5b612 100644 --- a/Content.Server/StationEvents/Components/RampingStationEventSchedulerComponent.cs +++ b/Content.Server/StationEvents/Components/RampingStationEventSchedulerComponent.cs @@ -3,6 +3,30 @@ [RegisterComponent, Access(typeof(RampingStationEventSchedulerSystem))] public sealed partial class RampingStationEventSchedulerComponent : Component { + /// + /// The maximum number by which the event rate will be multiplied when shift time reaches the end time. + /// + [DataField] + public float ChaosModifier = 3f; + + /// + /// The minimum number by which the event rate will be multiplied when the shift has just begun. + /// + [DataField] + public float StartingChaosRatio = 0.1f; + + /// + /// The number by which all event delays will be multiplied. Unlike chaos, remains constant throughout the shift. + /// + [DataField] + public float EventDelayModifier = 1f; + + /// + /// The number by which average expected shift length is multiplied. Higher values lead to slower chaos growth. + /// + public float ShiftLengthModifier = 1f; + + // Everything below is overridden in the RampingStationEventSchedulerSystem based on CVars [DataField("endTime"), ViewVariables(VVAccess.ReadWrite)] public float EndTime; diff --git a/Content.Server/StationEvents/Events/NinjaSpawnRule.cs b/Content.Server/StationEvents/Events/NinjaSpawnRule.cs index c60f3298e7..8ad5c8602e 100644 --- a/Content.Server/StationEvents/Events/NinjaSpawnRule.cs +++ b/Content.Server/StationEvents/Events/NinjaSpawnRule.cs @@ -2,10 +2,8 @@ using Content.Server.Ninja.Systems; using Content.Server.Station.Components; using Content.Server.StationEvents.Components; -using Robust.Server.GameObjects; using Robust.Shared.Map; using Robust.Shared.Map.Components; -using Robust.Shared.Random; namespace Content.Server.StationEvents.Events; @@ -14,7 +12,6 @@ namespace Content.Server.StationEvents.Events; /// public sealed class NinjaSpawnRule : StationEventSystem { - [Dependency] private readonly SpaceNinjaSystem _ninja = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; protected override void Started(EntityUid uid, NinjaSpawnRuleComponent comp, GameRuleComponent gameRule, GameRuleStartedEvent args) diff --git a/Content.Server/StationEvents/RampingStationEventSchedulerSystem.cs b/Content.Server/StationEvents/RampingStationEventSchedulerSystem.cs index 53a98e8b76..aa0c9b214b 100644 --- a/Content.Server/StationEvents/RampingStationEventSchedulerSystem.cs +++ b/Content.Server/StationEvents/RampingStationEventSchedulerSystem.cs @@ -29,15 +29,15 @@ protected override void Started(EntityUid uid, RampingStationEventSchedulerCompo { base.Started(uid, component, gameRule, args); - var avgChaos = _cfg.GetCVar(CCVars.EventsRampingAverageChaos); - var avgTime = _cfg.GetCVar(CCVars.EventsRampingAverageEndTime); + var avgChaos = _cfg.GetCVar(CCVars.EventsRampingAverageChaos) * component.ChaosModifier; + var avgTime = _cfg.GetCVar(CCVars.EventsRampingAverageEndTime) * component.ShiftLengthModifier; // Worlds shittiest probability distribution // Got a complaint? Send them to - component.MaxChaos = _random.NextFloat(avgChaos - avgChaos / 4, avgChaos + avgChaos / 4); + component.MaxChaos = avgChaos * _random.NextFloat(0.75f, 1.25f); // This is in minutes, so *60 for seconds (for the chaos calc) - component.EndTime = _random.NextFloat(avgTime - avgTime / 4, avgTime + avgTime / 4) * 60f; - component.StartingChaos = component.MaxChaos / 10; + component.EndTime = avgTime * _random.NextFloat(0.75f, 1.25f) * 60f; + component.StartingChaos = component.MaxChaos * component.StartingChaosRatio; PickNextEventTime(uid, component); } @@ -68,9 +68,10 @@ public override void Update(float frameTime) private void PickNextEventTime(EntityUid uid, RampingStationEventSchedulerComponent component) { - var mod = GetChaosModifier(uid, component); + component.TimeUntilNextEvent = _random.NextFloat( + _cfg.GetCVar(CCVars.GameEventsRampingMinimumTime), + _cfg.GetCVar(CCVars.GameEventsRampingMaximumTime)); - component.TimeUntilNextEvent = _random.NextFloat(_cfg.GetCVar(CCVars.GameEventsRampingMinimumTime) / mod, - _cfg.GetCVar(CCVars.GameEventsRampingMaximumTime)) / mod; + component.TimeUntilNextEvent *= component.EventDelayModifier / GetChaosModifier(uid, component); } } diff --git a/Content.Server/SubFloor/SubFloorHideSystem.cs b/Content.Server/SubFloor/SubFloorHideSystem.cs index 7820badceb..2767f500f9 100644 --- a/Content.Server/SubFloor/SubFloorHideSystem.cs +++ b/Content.Server/SubFloor/SubFloorHideSystem.cs @@ -1,5 +1,6 @@ using Content.Shared.Construction.Components; using Content.Shared.SubFloor; +using Robust.Shared.Map.Components; namespace Content.Server.SubFloor; @@ -17,7 +18,7 @@ private void OnAnchorAttempt(EntityUid uid, SubFloorHideComponent component, Anc // No teleporting entities through floor tiles when anchoring them. var xform = Transform(uid); - if (MapManager.TryGetGrid(xform.GridUid, out var grid) + if (TryComp(xform.GridUid, out var grid) && HasFloorCover(grid, grid.TileIndicesFor(xform.Coordinates))) { args.Cancel(); diff --git a/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraSpeakerSystem.cs b/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraSpeakerSystem.cs index 7544fc376b..0e694a801e 100644 --- a/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraSpeakerSystem.cs +++ b/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraSpeakerSystem.cs @@ -1,10 +1,7 @@ using Content.Server.Chat.Systems; using Content.Server.Speech; using Content.Shared.Speech; -using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; -using Robust.Shared.Prototypes; -using Robust.Shared.Random; using Robust.Shared.Timing; namespace Content.Server.SurveillanceCamera; @@ -18,8 +15,6 @@ public sealed class SurveillanceCameraSpeakerSystem : EntitySystem [Dependency] private readonly SpeechSoundSystem _speechSound = default!; [Dependency] private readonly ChatSystem _chatSystem = default!; [Dependency] private readonly IGameTiming _gameTiming = default!; - [Dependency] private readonly IPrototypeManager _prototypeManager = default!; - [Dependency] private readonly IRobustRandom _random = default!; /// public override void Initialize() diff --git a/Content.Server/Temperature/Systems/TemperatureSystem.cs b/Content.Server/Temperature/Systems/TemperatureSystem.cs index aca902b9d3..0f57da4b88 100644 --- a/Content.Server/Temperature/Systems/TemperatureSystem.cs +++ b/Content.Server/Temperature/Systems/TemperatureSystem.cs @@ -11,7 +11,6 @@ using Content.Shared.Inventory; using Content.Shared.Rejuvenate; using Content.Shared.Temperature; -using Robust.Server.GameObjects; using Robust.Shared.Physics.Components; namespace Content.Server.Temperature.Systems; @@ -22,7 +21,6 @@ public sealed class TemperatureSystem : EntitySystem [Dependency] private readonly AtmosphereSystem _atmosphere = default!; [Dependency] private readonly DamageableSystem _damageable = default!; [Dependency] private readonly IAdminLogManager _adminLogger = default!; - [Dependency] private readonly TransformSystem _transform = default!; /// /// All the components that will have their damage updated at the end of the tick. diff --git a/Content.Server/Traits/Assorted/ForeignerTraitComponent.cs b/Content.Server/Traits/Assorted/ForeignerTraitComponent.cs new file mode 100644 index 0000000000..e2d74ba5d9 --- /dev/null +++ b/Content.Server/Traits/Assorted/ForeignerTraitComponent.cs @@ -0,0 +1,36 @@ +using Content.Shared.Language; +using Content.Shared.Language.Systems; +using Robust.Shared.Prototypes; + +namespace Content.Server.Traits.Assorted; + +/// +/// When applied to a not-yet-spawned player entity, removes from the lists of their languages +/// and gives them a translator instead. +/// +[RegisterComponent] +public sealed partial class ForeignerTraitComponent : Component +{ + /// + /// The "base" language that is to be removed and substituted with a translator. + /// By default, equals to the fallback language, which is GalacticCommon. + /// + [DataField] + public ProtoId BaseLanguage = SharedLanguageSystem.FallbackLanguagePrototype; + + /// + /// Whether this trait prevents the entity from understanding the base language. + /// + public bool CantUnderstand = true; + + /// + /// Whether this trait prevents the entity from speaking the base language. + /// + public bool CantSpeak = true; + + /// + /// The base translator prototype to use when creating a translator for the entity. + /// + [DataField(required: true)] + public ProtoId BaseTranslator = default!; +} diff --git a/Content.Server/Traits/Assorted/ForeignerTraitSystem.cs b/Content.Server/Traits/Assorted/ForeignerTraitSystem.cs new file mode 100644 index 0000000000..58e974227c --- /dev/null +++ b/Content.Server/Traits/Assorted/ForeignerTraitSystem.cs @@ -0,0 +1,105 @@ +using System.Linq; +using Content.Server.Hands.Systems; +using Content.Server.Language; +using Content.Server.Storage.EntitySystems; +using Content.Shared.Clothing.Components; +using Content.Shared.Inventory; +using Content.Shared.Language; +using Content.Shared.Language.Components; +using Content.Shared.Language.Components.Translators; +using Content.Shared.Storage; +using Robust.Shared.Prototypes; + +namespace Content.Server.Traits.Assorted; + + +public sealed partial class ForeignerTraitSystem : EntitySystem +{ + [Dependency] private readonly EntityManager _entMan = default!; + [Dependency] private readonly HandsSystem _hands = default!; + [Dependency] private readonly InventorySystem _inventory = default!; + [Dependency] private readonly LanguageSystem _languages = default!; + [Dependency] private readonly StorageSystem _storage = default!; + + public override void Initialize() + { + SubscribeLocalEvent(OnSpawn); // TraitSystem adds it after PlayerSpawnCompleteEvent so it's fine + } + + private void OnSpawn(Entity entity, ref ComponentInit args) + { + if (entity.Comp.CantUnderstand && !entity.Comp.CantSpeak) + Log.Warning($"Allowing entity {entity.Owner} to speak a language but not understand it leads to undefined behavior."); + + if (!TryComp(entity, out var knowledge)) + { + Log.Warning($"Entity {entity.Owner} does not have a LanguageKnowledge but has a ForeignerTrait!"); + return; + } + + var alternateLanguage = knowledge.SpokenLanguages.Find(it => it != entity.Comp.BaseLanguage); + if (alternateLanguage == null) + { + Log.Warning($"Entity {entity.Owner} does not have an alternative language to choose from (must have at least one non-GC for ForeignerTrait)!"); + return; + } + + if (TryGiveTranslator(entity.Owner, entity.Comp.BaseTranslator, entity.Comp.BaseLanguage, alternateLanguage, out var translator)) + { + _languages.RemoveLanguage(entity, entity.Comp.BaseLanguage, entity.Comp.CantSpeak, entity.Comp.CantUnderstand, knowledge); + } + } + + /// + /// Tries to create and give the entity a translator to translator that translates speech between the two specified languages. + /// + public bool TryGiveTranslator( + EntityUid uid, + string baseTranslatorPrototype, + ProtoId translatorLanguage, + ProtoId entityLanguage, + out EntityUid result) + { + result = EntityUid.Invalid; + if (translatorLanguage == entityLanguage) + return false; + + var translator = _entMan.SpawnNextToOrDrop(baseTranslatorPrototype, uid); + result = translator; + + if (!TryComp(translator, out var handheld)) + { + handheld = AddComp(translator); + handheld.ToggleOnInteract = true; + handheld.SetLanguageOnInteract = true; + } + + // Allows to speak the specified language and requires entities language. + handheld.SpokenLanguages = [translatorLanguage]; + handheld.UnderstoodLanguages = [translatorLanguage]; + handheld.RequiredLanguages = [entityLanguage]; + + // Try to put it in entities hand + if (_hands.TryPickupAnyHand(uid, translator, false, false, false)) + return true; + + // Try to find a valid clothing slot on the entity and equip the translator there + if (TryComp(translator, out var clothing) + && clothing.Slots != SlotFlags.NONE + && _inventory.TryGetSlots(uid, out var slots) + && slots.Any(it => _inventory.TryEquip(uid, translator, it.Name, true, false))) + return true; + + // Try to put the translator into entities bag, if it has one + if (_inventory.TryGetSlotEntity(uid, "back", out var bag) + && TryComp(bag, out var storage) + && _storage.Insert(bag.Value, translator, out _, null, storage, false, false)) + return true; + + // If all of the above has failed, just drop it at the same location as the entity + // This should ideally never happen, but who knows. + Transform(translator).Coordinates = Transform(uid).Coordinates; + + return true; + } +} diff --git a/Content.Server/Weapons/Ranged/Systems/GunSystem.cs b/Content.Server/Weapons/Ranged/Systems/GunSystem.cs index c471fb00f4..9db00d2949 100644 --- a/Content.Server/Weapons/Ranged/Systems/GunSystem.cs +++ b/Content.Server/Weapons/Ranged/Systems/GunSystem.cs @@ -1,6 +1,5 @@ using System.Linq; using System.Numerics; -using Content.Server.Administration.Logs; using Content.Server.Cargo.Systems; using Content.Server.Interaction; using Content.Server.Power.EntitySystems; @@ -30,7 +29,6 @@ namespace Content.Server.Weapons.Ranged.Systems; public sealed partial class GunSystem : SharedGunSystem { - [Dependency] private readonly IAdminLogManager _adminLogger = default!; [Dependency] private readonly IComponentFactory _factory = default!; [Dependency] private readonly BatterySystem _battery = default!; [Dependency] private readonly DamageExamineSystem _damageExamine = default!; diff --git a/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Systems/ThrowArtifactSystem.cs b/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Systems/ThrowArtifactSystem.cs index 85783b552d..57a30a2fd9 100644 --- a/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Systems/ThrowArtifactSystem.cs +++ b/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Systems/ThrowArtifactSystem.cs @@ -1,12 +1,10 @@ using System.Numerics; -using Content.Server.Maps; using Content.Server.Xenoarchaeology.XenoArtifacts.Effects.Components; using Content.Server.Xenoarchaeology.XenoArtifacts.Events; -using Content.Shared.Ghost; using Content.Shared.Maps; using Content.Shared.Physics; using Content.Shared.Throwing; -using Robust.Shared.Map; +using Robust.Shared.Map.Components; using Robust.Shared.Physics.Components; using Robust.Shared.Random; @@ -14,7 +12,6 @@ namespace Content.Server.Xenoarchaeology.XenoArtifacts.Effects.Systems; public sealed class ThrowArtifactSystem : EntitySystem { - [Dependency] private readonly IMapManager _map = default!; [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly EntityLookupSystem _lookup = default!; [Dependency] private readonly ThrowingSystem _throwing = default!; @@ -29,7 +26,7 @@ public override void Initialize() private void OnActivated(EntityUid uid, ThrowArtifactComponent component, ArtifactActivatedEvent args) { var xform = Transform(uid); - if (_map.TryGetGrid(xform.GridUid, out var grid)) + if (TryComp(xform.GridUid, out var grid)) { var tiles = grid.GetTilesIntersecting( Box2.CenteredAround(xform.WorldPosition, new Vector2(component.Range * 2, component.Range))); diff --git a/Content.Server/Xenoarchaeology/XenoArtifacts/Triggers/Systems/ArtifactGasTriggerSystem.cs b/Content.Server/Xenoarchaeology/XenoArtifacts/Triggers/Systems/ArtifactGasTriggerSystem.cs index 96f1dc3783..00f409f553 100644 --- a/Content.Server/Xenoarchaeology/XenoArtifacts/Triggers/Systems/ArtifactGasTriggerSystem.cs +++ b/Content.Server/Xenoarchaeology/XenoArtifacts/Triggers/Systems/ArtifactGasTriggerSystem.cs @@ -1,7 +1,6 @@ using Content.Server.Atmos.EntitySystems; using Content.Server.Xenoarchaeology.XenoArtifacts.Events; using Content.Server.Xenoarchaeology.XenoArtifacts.Triggers.Components; -using Robust.Server.GameObjects; namespace Content.Server.Xenoarchaeology.XenoArtifacts.Triggers.Systems; @@ -9,7 +8,6 @@ public sealed class ArtifactGasTriggerSystem : EntitySystem { [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!; [Dependency] private readonly ArtifactSystem _artifactSystem = default!; - [Dependency] private readonly TransformSystem _transformSystem = default!; public override void Initialize() { diff --git a/Content.Server/Xenoarchaeology/XenoArtifacts/Triggers/Systems/ArtifactHeatTriggerSystem.cs b/Content.Server/Xenoarchaeology/XenoArtifacts/Triggers/Systems/ArtifactHeatTriggerSystem.cs index 33d1a43c12..5525cdf359 100644 --- a/Content.Server/Xenoarchaeology/XenoArtifacts/Triggers/Systems/ArtifactHeatTriggerSystem.cs +++ b/Content.Server/Xenoarchaeology/XenoArtifacts/Triggers/Systems/ArtifactHeatTriggerSystem.cs @@ -3,7 +3,6 @@ using Content.Shared.Interaction; using Content.Shared.Temperature; using Content.Shared.Weapons.Melee.Events; -using Robust.Server.GameObjects; namespace Content.Server.Xenoarchaeology.XenoArtifacts.Triggers.Systems; @@ -11,7 +10,6 @@ public sealed class ArtifactHeatTriggerSystem : EntitySystem { [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!; [Dependency] private readonly ArtifactSystem _artifactSystem = default!; - [Dependency] private readonly TransformSystem _transformSystem = default!; public override void Initialize() { diff --git a/Content.Server/Xenoarchaeology/XenoArtifacts/Triggers/Systems/ArtifactInteractionTriggerSystem.cs b/Content.Server/Xenoarchaeology/XenoArtifacts/Triggers/Systems/ArtifactInteractionTriggerSystem.cs index 239b674160..9976d56da0 100644 --- a/Content.Server/Xenoarchaeology/XenoArtifacts/Triggers/Systems/ArtifactInteractionTriggerSystem.cs +++ b/Content.Server/Xenoarchaeology/XenoArtifacts/Triggers/Systems/ArtifactInteractionTriggerSystem.cs @@ -1,6 +1,6 @@ using Content.Server.Xenoarchaeology.XenoArtifacts.Triggers.Components; using Content.Shared.Interaction; -using Content.Shared.Physics.Pull; +using Content.Shared.Movement.Pulling.Events; using Content.Shared.Weapons.Melee.Events; namespace Content.Server.Xenoarchaeology.XenoArtifacts.Triggers.Systems; @@ -22,7 +22,7 @@ private void OnPull(EntityUid uid, ArtifactInteractionTriggerComponent component if (!component.PullActivation) return; - _artifactSystem.TryActivateArtifact(uid, args.Puller.Owner); + _artifactSystem.TryActivateArtifact(uid, args.PullerUid); } private void OnAttack(EntityUid uid, ArtifactInteractionTriggerComponent component, AttackedEvent args) diff --git a/Content.Server/Xenoarchaeology/XenoArtifacts/Triggers/Systems/ArtifactPressureTriggerSystem.cs b/Content.Server/Xenoarchaeology/XenoArtifacts/Triggers/Systems/ArtifactPressureTriggerSystem.cs index 4388756cce..8777ab0a8c 100644 --- a/Content.Server/Xenoarchaeology/XenoArtifacts/Triggers/Systems/ArtifactPressureTriggerSystem.cs +++ b/Content.Server/Xenoarchaeology/XenoArtifacts/Triggers/Systems/ArtifactPressureTriggerSystem.cs @@ -1,6 +1,5 @@ using Content.Server.Atmos.EntitySystems; using Content.Server.Xenoarchaeology.XenoArtifacts.Triggers.Components; -using Robust.Server.GameObjects; namespace Content.Server.Xenoarchaeology.XenoArtifacts.Triggers.Systems; @@ -11,7 +10,6 @@ public sealed class ArtifactPressureTriggerSystem : EntitySystem { [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!; [Dependency] private readonly ArtifactSystem _artifactSystem = default!; - [Dependency] private readonly TransformSystem _transformSystem = default!; public override void Update(float frameTime) { diff --git a/Content.Server/Zombies/ZombieSystem.Transform.cs b/Content.Server/Zombies/ZombieSystem.Transform.cs index 21f2508042..c7e29166a0 100644 --- a/Content.Server/Zombies/ZombieSystem.Transform.cs +++ b/Content.Server/Zombies/ZombieSystem.Transform.cs @@ -26,12 +26,12 @@ using Content.Shared.Mobs; using Content.Shared.Mobs.Components; using Content.Shared.Mobs.Systems; +using Content.Shared.Movement.Pulling.Components; using Content.Shared.Movement.Systems; using Content.Shared.Nutrition.AnimalHusbandry; using Content.Shared.Nutrition.Components; using Content.Shared.Popups; using Content.Shared.Roles; -using Content.Shared.Pulling.Components; using Content.Shared.Weapons.Melee; using Content.Shared.Zombies; using Content.Shared.Prying.Components; @@ -280,7 +280,9 @@ public void ZombifyEntity(EntityUid target, MobStateComponent? mobState = null) RemComp(target, handsComp); } - RemComp(target); + // Sloth: What the fuck? + // How long until compregistry lmao. + RemComp(target); // No longer waiting to become a zombie: // Requires deferral because this is (probably) the event which called ZombifyEntity in the first place. diff --git a/Content.Server/Zombies/ZombieSystem.cs b/Content.Server/Zombies/ZombieSystem.cs index bef57eceb3..080bef44e7 100644 --- a/Content.Server/Zombies/ZombieSystem.cs +++ b/Content.Server/Zombies/ZombieSystem.cs @@ -2,9 +2,7 @@ using Content.Server.Body.Systems; using Content.Server.Chat; using Content.Server.Chat.Systems; -using Content.Server.Cloning; using Content.Server.Emoting.Systems; -using Content.Server.Inventory; using Content.Server.Speech.EntitySystems; using Content.Shared.Bed.Sleep; using Content.Shared.Cloning; @@ -31,7 +29,6 @@ public sealed partial class ZombieSystem : SharedZombieSystem [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly BloodstreamSystem _bloodstream = default!; [Dependency] private readonly DamageableSystem _damageable = default!; - [Dependency] private readonly ServerInventorySystem _inv = default!; [Dependency] private readonly ChatSystem _chat = default!; [Dependency] private readonly AutoEmoteSystem _autoEmote = default!; [Dependency] private readonly EmoteOnDamageSystem _emoteOnDamage = default!; diff --git a/Content.Shared/ActionBlocker/ActionBlockerSystem.cs b/Content.Shared/ActionBlocker/ActionBlockerSystem.cs index a914a8f267..f5ed2df227 100644 --- a/Content.Shared/ActionBlocker/ActionBlockerSystem.cs +++ b/Content.Shared/ActionBlocker/ActionBlockerSystem.cs @@ -202,7 +202,7 @@ public bool CanChangeDirection(EntityUid uid) public bool CanShiver(EntityUid uid) { var ev = new ShiverAttemptEvent(uid); - RaiseLocalEvent(uid, ev); + RaiseLocalEvent(uid, ref ev); return !ev.Cancelled; } @@ -210,7 +210,7 @@ public bool CanShiver(EntityUid uid) public bool CanSweat(EntityUid uid) { var ev = new SweatAttemptEvent(uid); - RaiseLocalEvent(uid, ev); + RaiseLocalEvent(uid, ref ev); return !ev.Cancelled; } diff --git a/Content.Shared/Administration/AdminData.cs b/Content.Shared/Administration/AdminData.cs index 5b5873bce3..229edbcd4c 100644 --- a/Content.Shared/Administration/AdminData.cs +++ b/Content.Shared/Administration/AdminData.cs @@ -12,6 +12,11 @@ public sealed class AdminData /// public bool Active; + /// + /// Whether the admin is in stealth mode and won't appear in adminwho to admins without the Stealth flag. + /// + public bool Stealth; + /// /// The admin's title. /// @@ -56,6 +61,14 @@ public bool CanAdminMenu() return HasFlag(AdminFlags.Admin); } + /// + /// Check if this admin can be hidden and see other hidden admins. + /// + public bool CanStealth() + { + return HasFlag(AdminFlags.Stealth); + } + public bool CanAdminReloadPrototypes() { return HasFlag(AdminFlags.Host); diff --git a/Content.Shared/Administration/AdminFlags.cs b/Content.Shared/Administration/AdminFlags.cs index 64cf522faa..9842e638c2 100644 --- a/Content.Shared/Administration/AdminFlags.cs +++ b/Content.Shared/Administration/AdminFlags.cs @@ -96,7 +96,12 @@ public enum AdminFlags : uint MassBan = 1 << 15, /// - /// DeltaV - The ability to whitelist people. Either this permission or +BAN is required for remove. + /// Allows you to remain hidden from adminwho except to other admins with this flag. + /// + Stealth = 1 << 16, + + /// + /// DeltaV - The ability to whitelist people. Either this permission or +BAN is required for remove. /// Whitelist = 1 << 20, diff --git a/Content.Shared/Administration/AdminFrozenSystem.cs b/Content.Shared/Administration/AdminFrozenSystem.cs index 14438cc591..4ec9600b0b 100644 --- a/Content.Shared/Administration/AdminFrozenSystem.cs +++ b/Content.Shared/Administration/AdminFrozenSystem.cs @@ -1,13 +1,10 @@ using Content.Shared.ActionBlocker; using Content.Shared.Interaction.Events; using Content.Shared.Item; -using Content.Shared.Movement; using Content.Shared.Movement.Events; -using Content.Shared.Physics.Pull; -using Content.Shared.Pulling; -using Content.Shared.Pulling.Components; -using Content.Shared.Pulling.Events; -using Content.Shared.Stunnable; +using Content.Shared.Movement.Pulling.Components; +using Content.Shared.Movement.Pulling.Events; +using Content.Shared.Movement.Pulling.Systems; using Content.Shared.Throwing; namespace Content.Shared.Administration; @@ -15,7 +12,7 @@ namespace Content.Shared.Administration; public sealed class AdminFrozenSystem : EntitySystem { [Dependency] private readonly ActionBlockerSystem _blocker = default!; - [Dependency] private readonly SharedPullingSystem _pulling = default!; + [Dependency] private readonly PullingSystem _pulling = default!; public override void Initialize() { @@ -45,9 +42,9 @@ private void OnPullAttempt(EntityUid uid, AdminFrozenComponent component, PullAt private void OnStartup(EntityUid uid, AdminFrozenComponent component, ComponentStartup args) { - if (TryComp(uid, out var pullable)) + if (TryComp(uid, out var pullable)) { - _pulling.TryStopPull(pullable); + _pulling.TryStopPull(uid, pullable); } UpdateCanMove(uid, component, args); diff --git a/Content.Shared/Body/Events/MechanismBodyEvents.cs b/Content.Shared/Body/Events/MechanismBodyEvents.cs index b52a333613..968b172aef 100644 --- a/Content.Shared/Body/Events/MechanismBodyEvents.cs +++ b/Content.Shared/Body/Events/MechanismBodyEvents.cs @@ -1,61 +1,28 @@ -namespace Content.Shared.Body.Events -{ - // All of these events are raised on a mechanism entity when added/removed to a body in different - // ways. - - /// - /// Raised on a mechanism when it is added to a body part. - /// - public sealed class AddedToPartEvent : EntityEventArgs - { - public EntityUid Part; - - public AddedToPartEvent(EntityUid part) - { - Part = part; - } - } - - /// - /// Raised on a mechanism when it is added to a body part within a body. - /// - public sealed class AddedToPartInBodyEvent : EntityEventArgs - { - public EntityUid Body; - public EntityUid Part; - - public AddedToPartInBodyEvent(EntityUid body, EntityUid part) - { - Body = body; - Part = part; - } - } - - /// - /// Raised on a mechanism when it is removed from a body part. - /// - public sealed class RemovedFromPartEvent : EntityEventArgs - { - public EntityUid OldPart; - - public RemovedFromPartEvent(EntityUid oldPart) - { - OldPart = oldPart; - } - } - - /// - /// Raised on a mechanism when it is removed from a body part within a body. - /// - public sealed class RemovedFromPartInBodyEvent : EntityEventArgs - { - public EntityUid OldBody; - public EntityUid OldPart; - - public RemovedFromPartInBodyEvent(EntityUid oldBody, EntityUid oldPart) - { - OldBody = oldBody; - OldPart = oldPart; - } - } -} +namespace Content.Shared.Body.Events; + +// All of these events are raised on a mechanism entity when added/removed to a body in different +// ways. + +/// +/// Raised on a mechanism when it is added to a body part. +/// +[ByRefEvent] +public readonly record struct OrganAddedEvent(EntityUid Part); + +/// +/// Raised on a mechanism when it is added to a body part within a body. +/// +[ByRefEvent] +public readonly record struct OrganAddedToBodyEvent(EntityUid Body, EntityUid Part); + +/// +/// Raised on a mechanism when it is removed from a body part. +/// +[ByRefEvent] +public readonly record struct OrganRemovedEvent(EntityUid OldPart); + +/// +/// Raised on a mechanism when it is removed from a body part within a body. +/// +[ByRefEvent] +public readonly record struct OrganRemovedFromBodyEvent(EntityUid OldBody, EntityUid OldPart); diff --git a/Content.Shared/Body/Events/ShiverAttemptEvent.cs b/Content.Shared/Body/Events/ShiverAttemptEvent.cs index 8c2761f545..e9400bc48d 100644 --- a/Content.Shared/Body/Events/ShiverAttemptEvent.cs +++ b/Content.Shared/Body/Events/ShiverAttemptEvent.cs @@ -1,12 +1,8 @@ -namespace Content.Shared.Body.Events -{ - public sealed class ShiverAttemptEvent : CancellableEntityEventArgs - { - public ShiverAttemptEvent(EntityUid uid) - { - Uid = uid; - } +namespace Content.Shared.Body.Events; - public EntityUid Uid { get; } - } +[ByRefEvent] +public record struct ShiverAttemptEvent(EntityUid Uid) +{ + public readonly EntityUid Uid = Uid; + public bool Cancelled = false; } diff --git a/Content.Shared/Body/Events/SweatAttemptEvent.cs b/Content.Shared/Body/Events/SweatAttemptEvent.cs index 7f4b3fab15..7506538c43 100644 --- a/Content.Shared/Body/Events/SweatAttemptEvent.cs +++ b/Content.Shared/Body/Events/SweatAttemptEvent.cs @@ -1,12 +1,8 @@ -namespace Content.Shared.Body.Events -{ - public sealed class SweatAttemptEvent : CancellableEntityEventArgs - { - public SweatAttemptEvent(EntityUid uid) - { - Uid = uid; - } +namespace Content.Shared.Body.Events; - public EntityUid Uid { get; } - } +[ByRefEvent] +public record struct SweatAttemptEvent(EntityUid Uid) +{ + public readonly EntityUid Uid = Uid; + public bool Cancelled = false; } diff --git a/Content.Shared/Body/Organ/OrganComponent.cs b/Content.Shared/Body/Organ/OrganComponent.cs index 9e1de6b355..3048927b5f 100644 --- a/Content.Shared/Body/Organ/OrganComponent.cs +++ b/Content.Shared/Body/Organ/OrganComponent.cs @@ -1,4 +1,4 @@ -using Content.Shared.Body.Systems; +using Content.Shared.Body.Systems; using Robust.Shared.Containers; using Robust.Shared.GameStates; @@ -11,6 +11,6 @@ public sealed partial class OrganComponent : Component /// /// Relevant body this organ is attached to. /// - [DataField("body"), AutoNetworkedField] + [DataField, AutoNetworkedField] public EntityUid? Body; } diff --git a/Content.Shared/Body/Part/BodyPartEvents.cs b/Content.Shared/Body/Part/BodyPartEvents.cs index 4dbc543fc8..0d8d2c8a26 100644 --- a/Content.Shared/Body/Part/BodyPartEvents.cs +++ b/Content.Shared/Body/Part/BodyPartEvents.cs @@ -1,7 +1,7 @@ -namespace Content.Shared.Body.Part; +namespace Content.Shared.Body.Part; [ByRefEvent] -public readonly record struct BodyPartAddedEvent(string Slot, BodyPartComponent Part); +public readonly record struct BodyPartAddedEvent(string Slot, Entity Part); [ByRefEvent] -public readonly record struct BodyPartRemovedEvent(string Slot, BodyPartComponent Part); +public readonly record struct BodyPartRemovedEvent(string Slot, Entity Part); diff --git a/Content.Shared/Body/Systems/SharedBodySystem.Body.cs b/Content.Shared/Body/Systems/SharedBodySystem.Body.cs index bc7cf63124..1a35afdbe0 100644 --- a/Content.Shared/Body/Systems/SharedBodySystem.Body.cs +++ b/Content.Shared/Body/Systems/SharedBodySystem.Body.cs @@ -9,7 +9,6 @@ using Content.Shared.Gibbing.Events; using Content.Shared.Gibbing.Systems; using Content.Shared.Inventory; -using Content.Shared.Inventory.Events; using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; using Robust.Shared.Containers; @@ -30,8 +29,10 @@ public partial class SharedBodySystem [Dependency] private readonly InventorySystem _inventory = default!; [Dependency] private readonly GibbingSystem _gibbingSystem = default!; [Dependency] private readonly SharedAudioSystem _audioSystem = default!; + private const float GibletLaunchImpulse = 8; private const float GibletLaunchImpulseVariance = 3; + private void InitializeBody() { // Body here to handle root body parts. @@ -43,7 +44,7 @@ private void InitializeBody() SubscribeLocalEvent(OnBodyCanDrag); } - private void OnBodyInserted(EntityUid uid, BodyComponent component, EntInsertedIntoContainerMessage args) + private void OnBodyInserted(Entity ent, ref EntInsertedIntoContainerMessage args) { // Root body part? var slotId = args.Container.ID; @@ -51,21 +52,21 @@ private void OnBodyInserted(EntityUid uid, BodyComponent component, EntInsertedI if (slotId != BodyRootContainerId) return; - var entity = args.Entity; + var insertedUid = args.Entity; - if (TryComp(entity, out BodyPartComponent? childPart)) + if (TryComp(insertedUid, out BodyPartComponent? part)) { - AddPart(uid, entity, slotId, childPart); - RecursiveBodyUpdate(entity, uid, childPart); + AddPart((ent, ent), (insertedUid, part), slotId); + RecursiveBodyUpdate((insertedUid, part), ent); } - if (TryComp(entity, out OrganComponent? organ)) + if (TryComp(insertedUid, out OrganComponent? organ)) { - AddOrgan(entity, uid, uid, organ); + AddOrgan((insertedUid, organ), ent, ent); } } - private void OnBodyRemoved(EntityUid uid, BodyComponent component, EntRemovedFromContainerMessage args) + private void OnBodyRemoved(Entity ent, ref EntRemovedFromContainerMessage args) { // Root body part? var slotId = args.Container.ID; @@ -73,55 +74,55 @@ private void OnBodyRemoved(EntityUid uid, BodyComponent component, EntRemovedFro if (slotId != BodyRootContainerId) return; - var entity = args.Entity; - DebugTools.Assert(!TryComp(entity, out BodyPartComponent? b) || b.Body == uid); - DebugTools.Assert(!TryComp(entity, out OrganComponent? o) || o.Body == uid); + var removedUid = args.Entity; + DebugTools.Assert(!TryComp(removedUid, out BodyPartComponent? b) || b.Body == ent); + DebugTools.Assert(!TryComp(removedUid, out OrganComponent? o) || o.Body == ent); - if (TryComp(entity, out BodyPartComponent? childPart)) + if (TryComp(removedUid, out BodyPartComponent? part)) { - RemovePart(uid, entity, slotId, childPart); - RecursiveBodyUpdate(entity, null, childPart); + RemovePart((ent, ent), (removedUid, part), slotId); + RecursiveBodyUpdate((removedUid, part), null); } - if (TryComp(entity, out OrganComponent? organ)) - RemoveOrgan(entity, uid, organ); + if (TryComp(removedUid, out OrganComponent? organ)) + RemoveOrgan((removedUid, organ), ent); } - private void OnBodyInit(EntityUid bodyId, BodyComponent body, ComponentInit args) + private void OnBodyInit(Entity ent, ref ComponentInit args) { // Setup the initial container. - body.RootContainer = Containers.EnsureContainer(bodyId, BodyRootContainerId); + ent.Comp.RootContainer = Containers.EnsureContainer(ent, BodyRootContainerId); } - private void OnBodyMapInit(EntityUid bodyId, BodyComponent body, MapInitEvent args) + private void OnBodyMapInit(Entity ent, ref MapInitEvent args) { - if (body.Prototype == null) + if (ent.Comp.Prototype is null) return; // One-time setup // Obviously can't run in Init to avoid double-spawns on save / load. - var prototype = Prototypes.Index(body.Prototype.Value); - MapInitBody(bodyId, prototype); + var prototype = Prototypes.Index(ent.Comp.Prototype.Value); + MapInitBody(ent, prototype); } private void MapInitBody(EntityUid bodyEntity, BodyPrototype prototype) { var protoRoot = prototype.Slots[prototype.Root]; - if (protoRoot.Part == null) + if (protoRoot.Part is null) return; // This should already handle adding the entity to the root. - var rootPartEntity = SpawnInContainerOrDrop(protoRoot.Part, bodyEntity, BodyRootContainerId); - var rootPart = Comp(rootPartEntity); + var rootPartUid = SpawnInContainerOrDrop(protoRoot.Part, bodyEntity, BodyRootContainerId); + var rootPart = Comp(rootPartUid); rootPart.Body = bodyEntity; - Dirty(rootPartEntity, rootPart); + Dirty(rootPartUid, rootPart); // Setup the rest of the body entities. - SetupOrgans(rootPartEntity, rootPart, protoRoot.Organs); - MapInitParts(rootPartEntity, prototype); + SetupOrgans((rootPartUid, rootPart), protoRoot.Organs); + MapInitParts(rootPartUid, prototype); } - private void OnBodyCanDrag(EntityUid uid, BodyComponent component, ref CanDragEvent args) + private void OnBodyCanDrag(Entity ent, ref CanDragEvent args) { args.Handled = true; } @@ -169,7 +170,7 @@ private void MapInitParts(EntityUid rootPartId, BodyPrototype prototype) var partSlot = CreatePartSlot(parentEntity, connection, childPartComponent.PartType, parentPartComponent); var cont = Containers.GetContainer(parentEntity, GetPartSlotContainerId(connection)); - if (partSlot == null || !Containers.Insert(childPart, cont)) + if (partSlot is null || !Containers.Insert(childPart, cont)) { Log.Error($"Could not create slot for connection {connection} in body {prototype.ID}"); QueueDel(childPart); @@ -177,7 +178,7 @@ private void MapInitParts(EntityUid rootPartId, BodyPrototype prototype) } // Add organs - SetupOrgans(childPart, childPartComponent, connectionSlot.Organs); + SetupOrgans((childPart, childPartComponent), connectionSlot.Organs); // Enqueue it so we can also get its neighbors. frontier.Enqueue(connection); @@ -185,16 +186,16 @@ private void MapInitParts(EntityUid rootPartId, BodyPrototype prototype) } } - private void SetupOrgans(EntityUid partId, BodyPartComponent partComponent, Dictionary organs) + private void SetupOrgans(Entity ent, Dictionary organs) { foreach (var (organSlotId, organProto) in organs) { - var slot = CreateOrganSlot(organSlotId, partId, partComponent); - SpawnInContainerOrDrop(organProto, partId, GetOrganContainerId(organSlotId)); + var slot = CreateOrganSlot((ent, ent), organSlotId); + SpawnInContainerOrDrop(organProto, ent, GetOrganContainerId(organSlotId)); - if (slot == null) + if (slot is null) { - Log.Error($"Could not create organ for slot {organSlotId} in {ToPrettyString(partId)}"); + Log.Error($"Could not create organ for slot {organSlotId} in {ToPrettyString(ent)}"); } } } @@ -202,12 +203,14 @@ private void SetupOrgans(EntityUid partId, BodyPartComponent partComponent, Dict /// /// Gets all body containers on this entity including the root one. /// - public IEnumerable GetBodyContainers(EntityUid id, BodyComponent? body = null, + public IEnumerable GetBodyContainers( + EntityUid id, + BodyComponent? body = null, BodyPartComponent? rootPart = null) { - if (!Resolve(id, ref body, false) || - body.RootContainer.ContainedEntity == null || - !Resolve(body.RootContainer.ContainedEntity.Value, ref rootPart)) + if (!Resolve(id, ref body, logMissing: false) + || body.RootContainer.ContainedEntity is null + || !Resolve(body.RootContainer.ContainedEntity.Value, ref rootPart)) { yield break; } @@ -223,13 +226,15 @@ public IEnumerable GetBodyContainers(EntityUid id, BodyComponent? /// /// Gets all child body parts of this entity, including the root entity. /// - public IEnumerable<(EntityUid Id, BodyPartComponent Component)> GetBodyChildren(EntityUid? id, BodyComponent? body = null, + public IEnumerable<(EntityUid Id, BodyPartComponent Component)> GetBodyChildren( + EntityUid? id, + BodyComponent? body = null, BodyPartComponent? rootPart = null) { - if (id == null || - !Resolve(id.Value, ref body, false) || - body.RootContainer.ContainedEntity == null || - !Resolve(body.RootContainer.ContainedEntity.Value, ref rootPart)) + if (id is null + || !Resolve(id.Value, ref body, logMissing: false) + || body.RootContainer.ContainedEntity is null + || !Resolve(body.RootContainer.ContainedEntity.Value, ref rootPart)) { yield break; } @@ -240,9 +245,11 @@ public IEnumerable GetBodyContainers(EntityUid id, BodyComponent? } } - public IEnumerable<(EntityUid Id, OrganComponent Component)> GetBodyOrgans(EntityUid? bodyId, BodyComponent? body = null) + public IEnumerable<(EntityUid Id, OrganComponent Component)> GetBodyOrgans( + EntityUid? bodyId, + BodyComponent? body = null) { - if (bodyId == null || !Resolve(bodyId.Value, ref body, false)) + if (bodyId is null || !Resolve(bodyId.Value, ref body, logMissing: false)) yield break; foreach (var part in GetBodyChildren(bodyId, body)) @@ -260,10 +267,15 @@ public IEnumerable GetBodyContainers(EntityUid id, BodyComponent? /// /// /// - public IEnumerable GetBodyAllSlots(EntityUid bodyId, BodyComponent? body = null) + public IEnumerable GetBodyAllSlots( + EntityUid bodyId, + BodyComponent? body = null) { - if (!Resolve(bodyId, ref body, false) || body.RootContainer.ContainedEntity == null) + if (!Resolve(bodyId, ref body, logMissing: false) + || body.RootContainer.ContainedEntity is null) + { yield break; + } foreach (var slot in GetAllBodyPartSlots(body.RootContainer.ContainedEntity.Value)) { @@ -279,12 +291,11 @@ public virtual HashSet GibBody( Vector2? splatDirection = null, float splatModifier = 1, Angle splatCone = default, - SoundSpecifier? gibSoundOverride = null - ) + SoundSpecifier? gibSoundOverride = null) { var gibs = new HashSet(); - if (!Resolve(bodyId, ref body, false)) + if (!Resolve(bodyId, ref body, logMissing: false)) return gibs; var root = GetRootPartOrNull(bodyId, body); @@ -311,7 +322,7 @@ public virtual HashSet GibBody( launchImpulseVariance:GibletLaunchImpulseVariance, launchCone: splatCone); } } - if(TryComp(bodyId, out var inventory)) + if (TryComp(bodyId, out var inventory)) { foreach (var item in _inventory.GetHandOrInventoryEntities(bodyId)) { diff --git a/Content.Shared/Body/Systems/SharedBodySystem.Organs.cs b/Content.Shared/Body/Systems/SharedBodySystem.Organs.cs index fa11390705..efabebfc85 100644 --- a/Content.Shared/Body/Systems/SharedBodySystem.Organs.cs +++ b/Content.Shared/Body/Systems/SharedBodySystem.Organs.cs @@ -1,4 +1,4 @@ -using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.CodeAnalysis; using Content.Shared.Body.Components; using Content.Shared.Body.Events; using Content.Shared.Body.Organ; @@ -9,41 +9,50 @@ namespace Content.Shared.Body.Systems; public partial class SharedBodySystem { - private void AddOrgan(EntityUid uid, EntityUid bodyUid, EntityUid parentPartUid, OrganComponent component) + private void AddOrgan( + Entity organEnt, + EntityUid bodyUid, + EntityUid parentPartUid) { - component.Body = bodyUid; - RaiseLocalEvent(uid, new AddedToPartEvent(parentPartUid)); + organEnt.Comp.Body = bodyUid; + var addedEv = new OrganAddedEvent(parentPartUid); + RaiseLocalEvent(organEnt, ref addedEv); - if (component.Body != null) - RaiseLocalEvent(uid, new AddedToPartInBodyEvent(component.Body.Value, parentPartUid)); + if (organEnt.Comp.Body is not null) + { + var addedInBodyEv = new OrganAddedToBodyEvent(bodyUid, parentPartUid); + RaiseLocalEvent(organEnt, ref addedInBodyEv); + } - Dirty(uid, component); + Dirty(organEnt, organEnt.Comp); } - private void RemoveOrgan(EntityUid uid, EntityUid parentPartUid, OrganComponent component) + private void RemoveOrgan(Entity organEnt, EntityUid parentPartUid) { - RaiseLocalEvent(uid, new RemovedFromPartEvent(parentPartUid)); + var removedEv = new OrganRemovedEvent(parentPartUid); + RaiseLocalEvent(organEnt, ref removedEv); - if (component.Body != null) + if (organEnt.Comp.Body is { Valid: true } bodyUid) { - RaiseLocalEvent(uid, new RemovedFromPartInBodyEvent(component.Body.Value, parentPartUid)); + var removedInBodyEv = new OrganRemovedFromBodyEvent(bodyUid, parentPartUid); + RaiseLocalEvent(organEnt, ref removedInBodyEv); } - component.Body = null; - Dirty(uid, component); + organEnt.Comp.Body = null; + Dirty(organEnt, organEnt.Comp); } /// /// Creates the specified organ slot on the parent entity. /// - private OrganSlot? CreateOrganSlot(string slotId, EntityUid parent, BodyPartComponent? part = null) + private OrganSlot? CreateOrganSlot(Entity parentEnt, string slotId) { - if (!Resolve(parent, ref part, false)) + if (!Resolve(parentEnt, ref parentEnt.Comp, logMissing: false)) return null; - Containers.EnsureContainer(parent, GetOrganContainerId(slotId)); + Containers.EnsureContainer(parentEnt, GetOrganContainerId(slotId)); var slot = new OrganSlot(slotId); - part.Organs.Add(slotId, slot); + parentEnt.Comp.Organs.Add(slotId, slot); return slot; } @@ -58,20 +67,23 @@ public bool TryCreateOrganSlot( { slot = null; - if (parent == null || !Resolve(parent.Value, ref part, false)) + if (parent is null || !Resolve(parent.Value, ref part, logMissing: false)) { return false; } Containers.EnsureContainer(parent.Value, GetOrganContainerId(slotId)); slot = new OrganSlot(slotId); - return part.Organs.TryAdd(slotId,slot.Value); + return part.Organs.TryAdd(slotId, slot.Value); } /// /// Returns whether the slotId exists on the partId. /// - public bool CanInsertOrgan(EntityUid partId, string slotId, BodyPartComponent? part = null) + public bool CanInsertOrgan( + EntityUid partId, + string slotId, + BodyPartComponent? part = null) { return Resolve(partId, ref part) && part.Organs.ContainsKey(slotId); } @@ -79,26 +91,32 @@ public bool CanInsertOrgan(EntityUid partId, string slotId, BodyPartComponent? p /// /// Returns whether the specified organ slot exists on the partId. /// - public bool CanInsertOrgan(EntityUid partId, OrganSlot slot, BodyPartComponent? part = null) + public bool CanInsertOrgan( + EntityUid partId, + OrganSlot slot, + BodyPartComponent? part = null) { return CanInsertOrgan(partId, slot.Id, part); } - public bool InsertOrgan(EntityUid partId, EntityUid organId, string slotId, BodyPartComponent? part = null, OrganComponent? organ = null) + public bool InsertOrgan( + EntityUid partId, + EntityUid organId, + string slotId, + BodyPartComponent? part = null, + OrganComponent? organ = null) { - if (!Resolve(organId, ref organ, false) || - !Resolve(partId, ref part, false) || - !CanInsertOrgan(partId, slotId, part)) + if (!Resolve(organId, ref organ, logMissing: false) + || !Resolve(partId, ref part, logMissing: false) + || !CanInsertOrgan(partId, slotId, part)) { return false; } var containerId = GetOrganContainerId(slotId); - if (!Containers.TryGetContainer(partId, containerId, out var container)) - return false; - - return Containers.Insert(organId, container); + return Containers.TryGetContainer(partId, containerId, out var container) + && Containers.Insert(organId, container); } /// @@ -111,10 +129,8 @@ public bool RemoveOrgan(EntityUid organId, OrganComponent? organ = null) var parent = container.Owner; - if (!HasComp(parent)) - return false; - - return Containers.Remove(organId, container); + return HasComp(parent) + && Containers.Remove(organId, container); } /// @@ -126,8 +142,8 @@ public bool AddOrganToFirstValidSlot( BodyPartComponent? part = null, OrganComponent? organ = null) { - if (!Resolve(partId, ref part, false) || - !Resolve(organId, ref organ, false)) + if (!Resolve(partId, ref part, logMissing: false) + || !Resolve(organId, ref organ, logMissing: false)) { return false; } diff --git a/Content.Shared/Body/Systems/SharedBodySystem.Parts.cs b/Content.Shared/Body/Systems/SharedBodySystem.Parts.cs index e07aac0622..ee79faa0b8 100644 --- a/Content.Shared/Body/Systems/SharedBodySystem.Parts.cs +++ b/Content.Shared/Body/Systems/SharedBodySystem.Parts.cs @@ -1,4 +1,4 @@ -using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.CodeAnalysis; using System.Linq; using Content.Shared.Body.Components; using Content.Shared.Body.Events; @@ -23,52 +23,52 @@ private void InitializeParts() SubscribeLocalEvent(OnBodyPartRemoved); } - private void OnBodyPartInserted(EntityUid uid, BodyPartComponent component, EntInsertedIntoContainerMessage args) + private void OnBodyPartInserted(Entity ent, ref EntInsertedIntoContainerMessage args) { // Body part inserted into another body part. - var entity = args.Entity; + var insertedUid = args.Entity; var slotId = args.Container.ID; - if (component.Body == null) + if (ent.Comp.Body is null) return; - if (TryComp(entity, out BodyPartComponent? childPart)) + if (TryComp(insertedUid, out BodyPartComponent? part)) { - AddPart(component.Body.Value, entity, slotId, childPart); - RecursiveBodyUpdate(entity, component.Body.Value, childPart); + AddPart(ent.Comp.Body.Value, (insertedUid, part), slotId); + RecursiveBodyUpdate((insertedUid, part), ent.Comp.Body.Value); } - if (TryComp(entity, out OrganComponent? organ)) - AddOrgan(entity, component.Body.Value, uid, organ); + if (TryComp(insertedUid, out OrganComponent? organ)) + AddOrgan((insertedUid, organ), ent.Comp.Body.Value, ent); } - private void OnBodyPartRemoved(EntityUid uid, BodyPartComponent component, EntRemovedFromContainerMessage args) + private void OnBodyPartRemoved(Entity ent, ref EntRemovedFromContainerMessage args) { // Body part removed from another body part. - var entity = args.Entity; + var removedUid = args.Entity; var slotId = args.Container.ID; - DebugTools.Assert(!TryComp(entity, out BodyPartComponent? b) || b.Body == component.Body); - DebugTools.Assert(!TryComp(entity, out OrganComponent? o) || o.Body == component.Body); + DebugTools.Assert(!TryComp(removedUid, out BodyPartComponent? b) || b.Body == ent.Comp.Body); + DebugTools.Assert(!TryComp(removedUid, out OrganComponent? o) || o.Body == ent.Comp.Body); - if (TryComp(entity, out BodyPartComponent? childPart) && childPart.Body != null) + if (TryComp(removedUid, out BodyPartComponent? part) && part.Body is not null) { - RemovePart(childPart.Body.Value, entity, slotId, childPart); - RecursiveBodyUpdate(entity, null, childPart); + RemovePart(part.Body.Value, (removedUid, part), slotId); + RecursiveBodyUpdate((removedUid, part), null); } - if (TryComp(entity, out OrganComponent? organ)) - RemoveOrgan(entity, uid, organ); + if (TryComp(removedUid, out OrganComponent? organ)) + RemoveOrgan((removedUid, organ), ent); } - private void RecursiveBodyUpdate(EntityUid uid, EntityUid? bodyUid, BodyPartComponent component) + private void RecursiveBodyUpdate(Entity ent, EntityUid? bodyUid) { - component.Body = bodyUid; - Dirty(uid, component); + ent.Comp.Body = bodyUid; + Dirty(ent, ent.Comp); - foreach (var slotId in component.Organs.Keys) + foreach (var slotId in ent.Comp.Organs.Keys) { - if (!Containers.TryGetContainer(uid, GetOrganContainerId(slotId), out var container)) + if (!Containers.TryGetContainer(ent, GetOrganContainerId(slotId), out var container)) continue; foreach (var organ in container.ContainedEntities) @@ -78,105 +78,108 @@ private void RecursiveBodyUpdate(EntityUid uid, EntityUid? bodyUid, BodyPartComp Dirty(organ, organComp); - if (organComp.Body != null) - RaiseLocalEvent(organ, new RemovedFromPartInBodyEvent(organComp.Body.Value, uid)); + if (organComp.Body is { Valid: true } oldBodyUid) + { + var removedEv = new OrganRemovedFromBodyEvent(oldBodyUid, ent); + RaiseLocalEvent(organ, ref removedEv); + } organComp.Body = bodyUid; - if (bodyUid != null) - RaiseLocalEvent(organ, new AddedToPartInBodyEvent(bodyUid.Value, uid)); + if (bodyUid is not null) + { + var addedEv = new OrganAddedToBodyEvent(bodyUid.Value, ent); + RaiseLocalEvent(organ, ref addedEv); + } } } - foreach (var slotId in component.Children.Keys) + foreach (var slotId in ent.Comp.Children.Keys) { - if (!Containers.TryGetContainer(uid, GetPartSlotContainerId(slotId), out var container)) + if (!Containers.TryGetContainer(ent, GetPartSlotContainerId(slotId), out var container)) continue; - foreach (var containedEnt in container.ContainedEntities) + foreach (var containedUid in container.ContainedEntities) { - if (TryComp(containedEnt, out BodyPartComponent? childPart)) - RecursiveBodyUpdate(containedEnt, bodyUid, childPart); + if (TryComp(containedUid, out BodyPartComponent? childPart)) + RecursiveBodyUpdate((containedUid, childPart), bodyUid); } } } protected virtual void AddPart( - EntityUid bodyUid, - EntityUid partUid, - string slotId, - BodyPartComponent component, - BodyComponent? bodyComp = null) + Entity bodyEnt, + Entity partEnt, + string slotId) { - DebugTools.AssertOwner(partUid, component); - Dirty(partUid, component); - component.Body = bodyUid; + Dirty(partEnt, partEnt.Comp); + partEnt.Comp.Body = bodyEnt; - var ev = new BodyPartAddedEvent(slotId, component); - RaiseLocalEvent(bodyUid, ref ev); + var ev = new BodyPartAddedEvent(slotId, partEnt); + RaiseLocalEvent(bodyEnt, ref ev); - AddLeg(partUid, bodyUid, component, bodyComp); + AddLeg(partEnt, bodyEnt); } protected virtual void RemovePart( - EntityUid bodyUid, - EntityUid partUid, - string slotId, - BodyPartComponent component, - BodyComponent? bodyComp = null) + Entity bodyEnt, + Entity partEnt, + string slotId) { - DebugTools.AssertOwner(partUid, component); - Resolve(bodyUid, ref bodyComp, false); - Dirty(partUid, component); - component.Body = null; + Resolve(bodyEnt, ref bodyEnt.Comp, logMissing: false); + Dirty(partEnt, partEnt.Comp); + partEnt.Comp.Body = null; - var ev = new BodyPartRemovedEvent(slotId, component); - RaiseLocalEvent(bodyUid, ref ev); + var ev = new BodyPartRemovedEvent(slotId, partEnt); + RaiseLocalEvent(bodyEnt, ref ev); - RemoveLeg(partUid, bodyUid, component); - PartRemoveDamage(bodyUid, component, bodyComp); + RemoveLeg(partEnt, bodyEnt); + PartRemoveDamage(bodyEnt, partEnt); } - private void AddLeg(EntityUid uid, EntityUid bodyUid, BodyPartComponent component, BodyComponent? bodyComp = null) + private void AddLeg(Entity legEnt, Entity bodyEnt) { - if (!Resolve(bodyUid, ref bodyComp, false)) + if (!Resolve(bodyEnt, ref bodyEnt.Comp, logMissing: false)) return; - if (component.PartType == BodyPartType.Leg) + if (legEnt.Comp.PartType == BodyPartType.Leg) { - bodyComp.LegEntities.Add(uid); - UpdateMovementSpeed(bodyUid); - Dirty(bodyUid, bodyComp); + bodyEnt.Comp.LegEntities.Add(legEnt); + UpdateMovementSpeed(bodyEnt); + Dirty(bodyEnt, bodyEnt.Comp); } } - private void RemoveLeg(EntityUid uid, EntityUid bodyUid, BodyPartComponent component, BodyComponent? bodyComp = null) + private void RemoveLeg(Entity legEnt, Entity bodyEnt) { - if (!Resolve(bodyUid, ref bodyComp, false)) + if (!Resolve(bodyEnt, ref bodyEnt.Comp, logMissing: false)) return; - if (component.PartType == BodyPartType.Leg) + if (legEnt.Comp.PartType == BodyPartType.Leg) { - bodyComp.LegEntities.Remove(uid); - UpdateMovementSpeed(bodyUid); - Dirty(bodyUid, bodyComp); + bodyEnt.Comp.LegEntities.Remove(legEnt); + UpdateMovementSpeed(bodyEnt); + Dirty(bodyEnt, bodyEnt.Comp); - if (!bodyComp.LegEntities.Any()) + if (!bodyEnt.Comp.LegEntities.Any()) { - Standing.Down(bodyUid); + Standing.Down(bodyEnt); } } } - private void PartRemoveDamage(EntityUid parent, BodyPartComponent component, BodyComponent? bodyComp = null) + private void PartRemoveDamage(Entity bodyEnt, Entity partEnt) { - if (!Resolve(parent, ref bodyComp, false)) + if (!Resolve(bodyEnt, ref bodyEnt.Comp, logMissing: false)) return; - if (!_timing.ApplyingState && component.IsVital && !GetBodyChildrenOfType(parent, component.PartType, bodyComp).Any()) + if (!_timing.ApplyingState + && partEnt.Comp.IsVital + && !GetBodyChildrenOfType(bodyEnt, partEnt.Comp.PartType, bodyEnt.Comp).Any() + ) { // TODO BODY SYSTEM KILL : remove this when wounding and required parts are implemented properly var damage = new DamageSpecifier(Prototypes.Index("Bloodloss"), 300); - Damageable.TryChangeDamage(parent, damage); + Damageable.TryChangeDamage(bodyEnt, damage); } } @@ -212,7 +215,8 @@ private void PartRemoveDamage(EntityUid parent, BodyPartComponent component, Bod var parent = container.Owner; - if (!TryComp(parent, out var parentBody) || !parentBody.Children.ContainsKey(slotId)) + if (!TryComp(parent, out var parentBody) + || !parentBody.Children.ContainsKey(slotId)) return null; return (parent, slotId); @@ -252,7 +256,7 @@ public bool TryGetParentBodyPart( BodyPartType partType, BodyPartComponent? part = null) { - if (!Resolve(partUid, ref part, false)) + if (!Resolve(partUid, ref part, logMissing: false)) return null; Containers.EnsureContainer(partUid, GetPartSlotContainerId(slotId)); @@ -275,8 +279,8 @@ public bool TryCreatePartSlot( { slot = null; - if (partId == null || - !Resolve(partId.Value, ref part, false)) + if (partId is null + || !Resolve(partId.Value, ref part, logMissing: false)) { return false; } @@ -310,24 +314,31 @@ public bool TryCreatePartSlotAndAttach( /// /// Returns true if the partId is the root body container for the specified bodyId. /// - public bool IsPartRoot(EntityUid bodyId, EntityUid partId, BodyComponent? body = null, BodyPartComponent? part = null) + public bool IsPartRoot( + EntityUid bodyId, + EntityUid partId, + BodyComponent? body = null, + BodyPartComponent? part = null) { - if (!Resolve(partId, ref part)|| !Resolve(bodyId, ref body)) - return false; - - return Containers.TryGetContainingContainer(bodyId, partId, out var container) && container.ID == BodyRootContainerId; + return Resolve(partId, ref part) + && Resolve(bodyId, ref body) + && Containers.TryGetContainingContainer(bodyId, partId, out var container) + && container.ID == BodyRootContainerId; } /// /// Returns true if we can attach the partId to the bodyId as the root entity. /// - public bool CanAttachToRoot(EntityUid bodyId, EntityUid partId, BodyComponent? body = null, + public bool CanAttachToRoot( + EntityUid bodyId, + EntityUid partId, + BodyComponent? body = null, BodyPartComponent? part = null) { - return Resolve(bodyId, ref body) && - Resolve(partId, ref part) && - body.RootContainer.ContainedEntity == null && - bodyId != part.Body; + return Resolve(bodyId, ref body) + && Resolve(partId, ref part) + && body.RootContainer.ContainedEntity is null + && bodyId != part.Body; } /// @@ -335,8 +346,11 @@ public bool CanAttachToRoot(EntityUid bodyId, EntityUid partId, BodyComponent? b /// public (EntityUid Entity, BodyPartComponent BodyPart)? GetRootPartOrNull(EntityUid bodyId, BodyComponent? body = null) { - if (!Resolve(bodyId, ref body) || body.RootContainer.ContainedEntity == null) + if (!Resolve(bodyId, ref body) + || body.RootContainer.ContainedEntity is null) + { return null; + } return (body.RootContainer.ContainedEntity.Value, Comp(body.RootContainer.ContainedEntity.Value)); @@ -352,13 +366,9 @@ public bool CanAttachPart( BodyPartComponent? parentPart = null, BodyPartComponent? part = null) { - if (!Resolve(partId, ref part, false) || - !Resolve(parentId, ref parentPart, false)) - { - return false; - } - - return CanAttachPart(parentId, slot.Id, partId, parentPart, part); + return Resolve(partId, ref part, logMissing: false) + && Resolve(parentId, ref parentPart, logMissing: false) + && CanAttachPart(parentId, slot.Id, partId, parentPart, part); } /// @@ -371,16 +381,12 @@ public bool CanAttachPart( BodyPartComponent? parentPart = null, BodyPartComponent? part = null) { - if (!Resolve(partId, ref part, false) || - !Resolve(parentId, ref parentPart, false) || - !parentPart.Children.TryGetValue(slotId, out var parentSlotData)) - { - return false; - } - - return part.PartType == parentSlotData.Type && - Containers.TryGetContainer(parentId, GetPartSlotContainerId(slotId), out var container) && - Containers.CanInsert(partId, container); + return Resolve(partId, ref part, logMissing: false) + && Resolve(parentId, ref parentPart, logMissing: false) + && parentPart.Children.TryGetValue(slotId, out var parentSlotData) + && part.PartType == parentSlotData.Type + && Containers.TryGetContainer(parentId, GetPartSlotContainerId(slotId), out var container) + && Containers.CanInsert(partId, container); } public bool AttachPartToRoot( @@ -389,14 +395,10 @@ public bool AttachPartToRoot( BodyComponent? body = null, BodyPartComponent? part = null) { - if (!Resolve(bodyId, ref body) || - !Resolve(partId, ref part) || - !CanAttachToRoot(bodyId, partId, body, part)) - { - return false; - } - - return Containers.Insert(partId, body.RootContainer); + return Resolve(bodyId, ref body) + && Resolve(partId, ref part) + && CanAttachToRoot(bodyId, partId, body, part) + && Containers.Insert(partId, body.RootContainer); } #endregion @@ -406,20 +408,16 @@ public bool AttachPartToRoot( /// /// Attaches a body part to the specified body part parent. /// - public bool AttachPart( - EntityUid parentPartId, - string slotId, - EntityUid partId, - BodyPartComponent? parentPart = null, - BodyPartComponent? part = null) - { - if (!Resolve(parentPartId, ref parentPart, false) || - !parentPart.Children.TryGetValue(slotId, out var slot)) - { - return false; - } - - return AttachPart(parentPartId, slot, partId, parentPart, part); + public bool AttachPart( + EntityUid parentPartId, + string slotId, + EntityUid partId, + BodyPartComponent? parentPart = null, + BodyPartComponent? part = null) + { + return Resolve(parentPartId, ref parentPart, logMissing: false) + && parentPart.Children.TryGetValue(slotId, out var slot) + && AttachPart(parentPartId, slot, partId, parentPart, part); } /// @@ -432,10 +430,10 @@ public bool AttachPart( BodyPartComponent? parentPart = null, BodyPartComponent? part = null) { - if (!Resolve(parentPartId, ref parentPart, false) || - !Resolve(partId, ref part, false) || - !CanAttachPart(parentPartId, slot.Id, partId, parentPart, part) || - !parentPart.Children.ContainsKey(slot.Id)) + if (!Resolve(parentPartId, ref parentPart, logMissing: false) + || !Resolve(partId, ref part, logMissing: false) + || !CanAttachPart(parentPartId, slot.Id, partId, parentPart, part) + || !parentPart.Children.ContainsKey(slot.Id)) { return false; } @@ -453,13 +451,16 @@ public bool AttachPart( #region Misc - public void UpdateMovementSpeed(EntityUid bodyId, BodyComponent? body = null, MovementSpeedModifierComponent? movement = null) + public void UpdateMovementSpeed( + EntityUid bodyId, + BodyComponent? body = null, + MovementSpeedModifierComponent? movement = null) { - if (!Resolve(bodyId, ref body, ref movement, false)) - return; - - if (body.RequiredLegs <= 0) + if (!Resolve(bodyId, ref body, ref movement, logMissing: false) + || body.RequiredLegs <= 0) + { return; + } var walkSpeed = 0f; var sprintSpeed = 0f; @@ -488,7 +489,7 @@ public void UpdateMovementSpeed(EntityUid bodyId, BodyComponent? body = null, Mo /// public IEnumerable<(EntityUid Id, OrganComponent Component)> GetPartOrgans(EntityUid partId, BodyPartComponent? part = null) { - if (!Resolve(partId, ref part, false)) + if (!Resolve(partId, ref part, logMissing: false)) yield break; foreach (var slotId in part.Organs.Keys) @@ -513,7 +514,7 @@ public void UpdateMovementSpeed(EntityUid bodyId, BodyComponent? body = null, Mo /// public IEnumerable GetPartContainers(EntityUid id, BodyPartComponent? part = null) { - if (!Resolve(id, ref part, false) || + if (!Resolve(id, ref part, logMissing: false) || part.Children.Count == 0) { yield break; @@ -541,9 +542,11 @@ public IEnumerable GetPartContainers(EntityUid id, BodyPartCompon /// /// Returns all body part components for this entity including itself. /// - public IEnumerable<(EntityUid Id, BodyPartComponent Component)> GetBodyPartChildren(EntityUid partId, BodyPartComponent? part = null) + public IEnumerable<(EntityUid Id, BodyPartComponent Component)> GetBodyPartChildren( + EntityUid partId, + BodyPartComponent? part = null) { - if (!Resolve(partId, ref part, false)) + if (!Resolve(partId, ref part, logMissing: false)) yield break; yield return (partId, part); @@ -571,9 +574,11 @@ public IEnumerable GetPartContainers(EntityUid id, BodyPartCompon /// /// Returns all body part slots for this entity. /// - public IEnumerable GetAllBodyPartSlots(EntityUid partId, BodyPartComponent? part = null) + public IEnumerable GetAllBodyPartSlots( + EntityUid partId, + BodyPartComponent? part = null) { - if (!Resolve(partId, ref part, false)) + if (!Resolve(partId, ref part, logMissing: false)) yield break; foreach (var (slotId, slot) in part.Children) @@ -601,7 +606,10 @@ public IEnumerable GetAllBodyPartSlots(EntityUid partId, BodyPartC /// /// Returns true if the bodyId has any parts of this type. /// - public bool BodyHasPartType(EntityUid bodyId, BodyPartType type, BodyComponent? body = null) + public bool BodyHasPartType( + EntityUid bodyId, + BodyPartType type, + BodyComponent? body = null) { return GetBodyChildrenOfType(bodyId, type, body).Any(); } @@ -615,8 +623,8 @@ public bool PartHasChild( BodyPartComponent? parent, BodyPartComponent? child) { - if (!Resolve(parentId, ref parent, false) || - !Resolve(childId, ref child, false)) + if (!Resolve(parentId, ref parent, logMissing: false) + || !Resolve(childId, ref child, logMissing: false)) { return false; } @@ -638,15 +646,11 @@ public bool BodyHasChild( BodyComponent? body = null, BodyPartComponent? part = null) { - if (!Resolve(bodyId, ref body, false) || - body.RootContainer.ContainedEntity == null || - !Resolve(partId, ref part, false) || - !TryComp(body.RootContainer.ContainedEntity, out BodyPartComponent? rootPart)) - { - return false; - } - - return PartHasChild(body.RootContainer.ContainedEntity.Value, partId, rootPart, part); + return Resolve(bodyId, ref body, logMissing: false) + && body.RootContainer.ContainedEntity is not null + && Resolve(partId, ref part, logMissing: false) + && TryComp(body.RootContainer.ContainedEntity, out BodyPartComponent? rootPart) + && PartHasChild(body.RootContainer.ContainedEntity.Value, partId, rootPart, part); } public IEnumerable<(EntityUid Id, BodyPartComponent Component)> GetBodyChildrenOfType( @@ -721,9 +725,11 @@ public bool TryGetBodyPartOrganComponents( /// /// Gets the parent body part and all immediate child body parts for the partId. /// - public IEnumerable GetBodyPartAdjacentParts(EntityUid partId, BodyPartComponent? part = null) + public IEnumerable GetBodyPartAdjacentParts( + EntityUid partId, + BodyPartComponent? part = null) { - if (!Resolve(partId, ref part, false)) + if (!Resolve(partId, ref part, logMissing: false)) yield break; if (TryGetParentBodyPart(partId, out var parentUid, out _)) @@ -745,7 +751,7 @@ public IEnumerable GetBodyPartAdjacentParts(EntityUid partId, BodyPar BodyPartComponent? part = null) where T : IComponent { - if (!Resolve(partId, ref part, false)) + if (!Resolve(partId, ref part, logMissing: false)) yield break; var query = GetEntityQuery(); @@ -762,7 +768,7 @@ public bool TryGetBodyPartAdjacentPartsComponents( BodyPartComponent? part = null) where T : IComponent { - if (!Resolve(partId, ref part, false)) + if (!Resolve(partId, ref part, logMissing: false)) { comps = null; return false; diff --git a/Content.Shared/Buckle/SharedBuckleSystem.Buckle.cs b/Content.Shared/Buckle/SharedBuckleSystem.Buckle.cs index 8172947a03..3355713bb2 100644 --- a/Content.Shared/Buckle/SharedBuckleSystem.Buckle.cs +++ b/Content.Shared/Buckle/SharedBuckleSystem.Buckle.cs @@ -10,7 +10,6 @@ using Content.Shared.Mobs.Components; using Content.Shared.Movement.Events; using Content.Shared.Popups; -using Content.Shared.Pulling.Components; using Content.Shared.Standing; using Content.Shared.Storage.Components; using Content.Shared.Stunnable; @@ -19,6 +18,7 @@ using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Events; using Robust.Shared.Utility; +using PullableComponent = Content.Shared.Movement.Pulling.Components.PullableComponent; namespace Content.Shared.Buckle; @@ -348,11 +348,11 @@ public bool TryBuckle(EntityUid buckleUid, EntityUid userUid, EntityUid strapUid RaiseLocalEvent(ev.BuckledEntity, ref ev); RaiseLocalEvent(ev.StrapEntity, ref ev); - if (TryComp(buckleUid, out var ownerPullable)) + if (TryComp(buckleUid, out var ownerPullable)) { if (ownerPullable.Puller != null) { - _pulling.TryStopPull(ownerPullable); + _pulling.TryStopPull(buckleUid, ownerPullable); } } @@ -361,12 +361,12 @@ public bool TryBuckle(EntityUid buckleUid, EntityUid userUid, EntityUid strapUid _physics.ResetDynamics(buckleUid, physics); } - if (!buckleComp.PullStrap && TryComp(strapUid, out var toPullable)) + if (!buckleComp.PullStrap && TryComp(strapUid, out var toPullable)) { if (toPullable.Puller == buckleUid) { // can't pull it and buckle to it at the same time - _pulling.TryStopPull(toPullable); + _pulling.TryStopPull(strapUid, toPullable); } } diff --git a/Content.Shared/Buckle/SharedBuckleSystem.cs b/Content.Shared/Buckle/SharedBuckleSystem.cs index 8f68335663..67218657e5 100644 --- a/Content.Shared/Buckle/SharedBuckleSystem.cs +++ b/Content.Shared/Buckle/SharedBuckleSystem.cs @@ -15,6 +15,7 @@ using Robust.Shared.Physics.Systems; using Robust.Shared.Player; using Robust.Shared.Timing; +using PullingSystem = Content.Shared.Movement.Pulling.Systems.PullingSystem; namespace Content.Shared.Buckle; @@ -35,7 +36,7 @@ public abstract partial class SharedBuckleSystem : EntitySystem [Dependency] private readonly SharedInteractionSystem _interaction = default!; [Dependency] private readonly SharedJointSystem _joints = default!; [Dependency] private readonly SharedPopupSystem _popup = default!; - [Dependency] private readonly SharedPullingSystem _pulling = default!; + [Dependency] private readonly PullingSystem _pulling = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; [Dependency] private readonly StandingStateSystem _standing = default!; [Dependency] private readonly SharedPhysicsSystem _physics = default!; diff --git a/Content.Shared/Chat/V2/Moderation/ChatCensor.cs b/Content.Shared/Chat/V2/Moderation/ChatCensor.cs new file mode 100644 index 0000000000..b5d6aa0344 --- /dev/null +++ b/Content.Shared/Chat/V2/Moderation/ChatCensor.cs @@ -0,0 +1,59 @@ +using System.Linq; + +namespace Content.Shared.Chat.V2.Moderation; + +public interface IChatCensor +{ + public bool Censor(string input, out string output, char replaceWith = '*'); +} + +public sealed class CompoundChatCensor(IEnumerable censors) : IChatCensor +{ + public bool Censor(string input, out string output, char replaceWith = '*') + { + var censored = false; + + foreach (var censor in censors) + { + if (censor.Censor(input, out output, replaceWith)) + { + censored = true; + } + } + + output = input; + + return censored; + } +} + +public sealed class ChatCensorFactory +{ + private List _censors = new(); + + public void With(IChatCensor censor) + { + _censors.Add(censor); + } + + /// + /// Builds a ChatCensor that combines all the censors that have been added to this. + /// + public IChatCensor Build() + { + return new CompoundChatCensor(_censors.ToArray()); + } + + /// + /// Resets the build state to zero, allowing for different rules to be provided to the next censor(s) built. + /// + /// True if the builder had any setup prior to the reset. + public bool Reset() + { + var notEmpty = _censors.Count > 0; + + _censors = new List(); + + return notEmpty; + } +} diff --git a/Content.Shared/Chat/V2/Moderation/RegexCensor.cs b/Content.Shared/Chat/V2/Moderation/RegexCensor.cs new file mode 100644 index 0000000000..cd47bf0c33 --- /dev/null +++ b/Content.Shared/Chat/V2/Moderation/RegexCensor.cs @@ -0,0 +1,15 @@ +using System.Text.RegularExpressions; + +namespace Content.Shared.Chat.V2.Moderation; + +public sealed class RegexCensor(Regex censorInstruction) : IChatCensor +{ + private readonly Regex _censorInstruction = censorInstruction; + + public bool Censor(string input, out string output, char replaceWith = '*') + { + output = _censorInstruction.Replace(input, replaceWith.ToString()); + + return !string.Equals(input, output); + } +} diff --git a/Content.Shared/Chat/V2/Moderation/SimpleCensor.cs b/Content.Shared/Chat/V2/Moderation/SimpleCensor.cs new file mode 100644 index 0000000000..a6bb70dd9f --- /dev/null +++ b/Content.Shared/Chat/V2/Moderation/SimpleCensor.cs @@ -0,0 +1,340 @@ +using System.Collections.Frozen; +using System.Linq; +using System.Text; +using System.Text.Unicode; + +namespace Content.Shared.Chat.V2.Moderation; + +/// +/// A basic censor. Not bullet-proof. +/// +public sealed class SimpleCensor : IChatCensor +{ + // Common substitution symbols are replaced with one of the characters they commonly substitute. + private bool _shouldSanitizeLeetspeak; + private FrozenDictionary _leetspeakReplacements = FrozenDictionary.Empty; + + // Special characters are replaced with spaces. + private bool _shouldSanitizeSpecialCharacters; + private HashSet _specialCharacterReplacements = []; + + // Censored words are removed unless they're a false positive (e.g. Scunthorpe) + private string[] _censoredWords = Array.Empty(); + private string[] _falsePositives = Array.Empty(); + + // False negatives are censored words that contain a false positives. + private string[] _falseNegatives = Array.Empty(); + + // What unicode ranges are allowed? If this array is empty, don't filter by range. + private UnicodeRange[] _allowedUnicodeRanges= Array.Empty(); + + /// + /// Censors the input string. + /// + /// The input string + /// The output string + /// The character to replace with + /// If output is valid + public bool Censor(string input, out string output, char replaceWith = '*') + { + output = Censor(input, replaceWith); + + return !string.Equals(input, output); + } + + public string Censor(string input, char replaceWith = '*') + { + // We flat-out ban anything not in the allowed unicode ranges, stripping them + input = SanitizeOutBlockedUnicode(input); + + var originalInput = input.ToCharArray(); + + input = SanitizeInput(input); + + var censored = input.ToList(); + + // Remove false negatives + input = CheckProfanity(input, censored, _falseNegatives, replaceWith); + + // Get false positives + var falsePositives = FindFalsePositives(censored, replaceWith); + + // Remove censored words + CheckProfanity(input, censored, _censoredWords, replaceWith); + + // Reconstruct + // Reconstruct false positives + for (var i = 0; i < falsePositives.Length; i++) + { + if (falsePositives[i] != replaceWith) + { + censored[i] = falsePositives[i]; + } + } + + for (var i = 0; i < originalInput.Length; i++) + { + if (originalInput[i] == ' ') + { + censored.Insert(i, ' '); + + continue; + } + + if (_shouldSanitizeSpecialCharacters && _specialCharacterReplacements.Contains(originalInput[i])) + { + censored.Insert(i, originalInput[i]); + + continue; + } + + if (_shouldSanitizeLeetspeak || _shouldSanitizeSpecialCharacters) + { + // detect "()" + if (originalInput[i] == '(' && i != originalInput.Length - 1 && originalInput[i+1] == ')') + { + // censored has now had "o" replaced with "o) so both strings line up again..." + censored.Insert(i+1, censored[i] != replaceWith ? ')' : replaceWith); + } + } + + if (censored[i] != replaceWith) + { + censored[i] = originalInput[i]; + } + } + + // SO says this is fast... + return string.Concat(censored); + } + + /// + /// Adds a l33tsp34k sanitization rule + /// + /// The censor for further configuration + public SimpleCensor WithSanitizeLeetSpeak() + { + _shouldSanitizeLeetspeak = true; + + return BuildCharacterReplacements(); + } + + /// + /// Adds a l33tsp34k sanitization rule + /// + /// The censor for further configuration + public SimpleCensor WithSanitizeSpecialCharacters() + { + _shouldSanitizeSpecialCharacters = true; + + return BuildCharacterReplacements(); + } + + public SimpleCensor WithRanges(UnicodeRange[] ranges) + { + _allowedUnicodeRanges = ranges; + + return this; + } + + public SimpleCensor WithCustomDictionary(string[] naughtyWords) + { + _censoredWords = naughtyWords; + + return this; + } + + public SimpleCensor WithFalsePositives(string[] falsePositives) + { + _falsePositives = falsePositives; + + return this; + } + + public SimpleCensor WithFalseNegatives(string[] falseNegatives) + { + _falseNegatives = falseNegatives; + + return this; + } + + public SimpleCensor WithLeetspeakReplacements(Dictionary replacements) + { + _leetspeakReplacements = replacements.ToFrozenDictionary(); + + return this; + } + + public SimpleCensor WithSpecialCharacterReplacements(Dictionary replacements) + { + _leetspeakReplacements = replacements.ToFrozenDictionary(); + + return this; + } + + private string CheckProfanity(string input, List censored, string[] words, char replaceWith = '*') + { + foreach (var word in words) + { + var wordLength = word.Length; + var endOfFoundWord = 0; + var foundIndex = input.IndexOf(word, endOfFoundWord, StringComparison.OrdinalIgnoreCase); + + while(foundIndex > -1) + { + endOfFoundWord = foundIndex + wordLength; + + for (var i = 0; i < wordLength; i++) + { + censored[foundIndex+i] = replaceWith; + } + + foundIndex = input.IndexOf(word, endOfFoundWord, StringComparison.OrdinalIgnoreCase); + } + } + + return input; + } + + private char[] FindFalsePositives(List chars, char replaceWith = '*') + { + var input = string.Concat(chars); + + var output = Enumerable.Repeat(replaceWith, input.Length).ToArray(); + var inputAsARr = input.ToArray(); + + foreach (var word in _falsePositives) + { + var wordLength = word.Length; + var endOfFoundWord = 0; + var foundIndex = input.IndexOf(word, endOfFoundWord, StringComparison.OrdinalIgnoreCase); + + while(foundIndex > -1) + { + endOfFoundWord = foundIndex + wordLength; + + for (var i = foundIndex; i < endOfFoundWord; i++) + { + output[i] = inputAsARr[i]; + } + + foundIndex = input.IndexOf(word, endOfFoundWord, StringComparison.OrdinalIgnoreCase); + } + } + + return output; + } + + private string SanitizeInput(string input) + { + // "()" is a broad enough trick to beat censors that we we should check for it broadly. + if (_shouldSanitizeLeetspeak || _shouldSanitizeSpecialCharacters) + { + input = input.Replace("()", "o"); + } + + var sb = new StringBuilder(); + + // ReSharper disable once ForeachCanBePartlyConvertedToQueryUsingAnotherGetEnumerator + foreach (var character in input) + { + if (character == ' ' || _shouldSanitizeSpecialCharacters && _specialCharacterReplacements.Contains(character)) + { + continue; + } + + if (_shouldSanitizeLeetspeak && _leetspeakReplacements.TryGetValue(character, out var leetRepl)) + { + sb.Append(leetRepl); + + continue; + } + + sb.Append(character); + } + + return sb.ToString(); + } + + /// + /// Returns a string with all characters not in ISO-8851-1 replaced with question marks + /// + private string SanitizeOutBlockedUnicode(string input) + { + if (_allowedUnicodeRanges.Length <= 0) + { + return input; + } + + var sb = new StringBuilder(); + + foreach (var symbol in input.EnumerateRunes()) + { + // ReSharper disable once LoopCanBeConvertedToQuery + foreach (var range in _allowedUnicodeRanges) + { + if (symbol.Value < range.FirstCodePoint || symbol.Value >= range.FirstCodePoint + range.Length) + continue; + + sb.Append(symbol); + + break; + } + } + + return sb.ToString(); + } + + private SimpleCensor BuildCharacterReplacements() + { + if (_shouldSanitizeSpecialCharacters) + { + _specialCharacterReplacements = + [ + '-', + '_', + '|', + '.', + ',', + '(', + ')', + '<', + '>', + '"', + '`', + '~', + '*', + '&', + '%', + '$', + '#', + '@', + '!', + '?', + '+' + ]; + } + + if (_shouldSanitizeLeetspeak) + { + _leetspeakReplacements = new Dictionary + { + ['4'] = 'a', + ['$'] = 's', + ['!'] = 'i', + ['+'] = 't', + ['#'] = 'h', + ['@'] = 'a', + ['0'] = 'o', + ['1'] = 'i', // also obviously can be l; gamer-words need i's more though. + ['7'] = 'l', + ['3'] = 'e', + ['5'] = 's', + ['9'] = 'g', + ['<'] = 'c' + }.ToFrozenDictionary(); + } + + return this; + } +} diff --git a/Content.Shared/Climbing/Systems/ClimbSystem.cs b/Content.Shared/Climbing/Systems/ClimbSystem.cs index 6a2976a838..fceb6143e1 100644 --- a/Content.Shared/Climbing/Systems/ClimbSystem.cs +++ b/Content.Shared/Climbing/Systems/ClimbSystem.cs @@ -34,7 +34,6 @@ public sealed partial class ClimbSystem : VirtualController [Dependency] private readonly DamageableSystem _damageableSystem = default!; [Dependency] private readonly FixtureSystem _fixtureSystem = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; - [Dependency] private readonly SharedBodySystem _bodySystem = default!; [Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!; [Dependency] private readonly SharedInteractionSystem _interactionSystem = default!; [Dependency] private readonly SharedPopupSystem _popupSystem = default!; diff --git a/Content.Shared/Construction/EntitySystems/AnchorableSystem.cs b/Content.Shared/Construction/EntitySystems/AnchorableSystem.cs index 70bcfbab43..c041cf1ba0 100644 --- a/Content.Shared/Construction/EntitySystems/AnchorableSystem.cs +++ b/Content.Shared/Construction/EntitySystems/AnchorableSystem.cs @@ -6,16 +6,15 @@ using Content.Shared.Database; using Content.Shared.DoAfter; using Content.Shared.Interaction; +using Content.Shared.Movement.Pulling.Components; +using Content.Shared.Movement.Pulling.Systems; using Content.Shared.Popups; -using Content.Shared.Pulling; -using Content.Shared.Pulling.Components; using Content.Shared.Tools; using Content.Shared.Tools.Components; using Robust.Shared.Map; using Robust.Shared.Map.Components; using Robust.Shared.Physics.Components; using Content.Shared.Tag; -using Robust.Shared.Player; using Robust.Shared.Serialization; using Robust.Shared.Utility; using SharedToolSystem = Content.Shared.Tools.Systems.SharedToolSystem; @@ -27,7 +26,7 @@ public sealed partial class AnchorableSystem : EntitySystem [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!; [Dependency] private readonly SharedPopupSystem _popup = default!; - [Dependency] private readonly SharedPullingSystem _pulling = default!; + [Dependency] private readonly PullingSystem _pulling = default!; [Dependency] private readonly SharedToolSystem _tool = default!; [Dependency] private readonly SharedTransformSystem _transformSystem = default!; [Dependency] private readonly TagSystem _tagSystem = default!; @@ -132,9 +131,9 @@ private void OnAnchorComplete(EntityUid uid, AnchorableComponent component, TryA var rot = xform.LocalRotation; xform.LocalRotation = Math.Round(rot / (Math.PI / 2)) * (Math.PI / 2); - if (TryComp(uid, out var pullable) && pullable.Puller != null) + if (TryComp(uid, out var pullable) && pullable.Puller != null) { - _pulling.TryStopPull(pullable); + _pulling.TryStopPull(uid, pullable); } // TODO: Anchoring snaps rn anyway! @@ -175,7 +174,7 @@ private void OnAnchorComplete(EntityUid uid, AnchorableComponent component, TryA public void TryToggleAnchor(EntityUid uid, EntityUid userUid, EntityUid usingUid, AnchorableComponent? anchorable = null, TransformComponent? transform = null, - SharedPullableComponent? pullable = null, + PullableComponent? pullable = null, ToolComponent? usingTool = null) { if (!Resolve(uid, ref transform)) @@ -198,7 +197,7 @@ public void TryToggleAnchor(EntityUid uid, EntityUid userUid, EntityUid usingUid private void TryAnchor(EntityUid uid, EntityUid userUid, EntityUid usingUid, AnchorableComponent? anchorable = null, TransformComponent? transform = null, - SharedPullableComponent? pullable = null, + PullableComponent? pullable = null, ToolComponent? usingTool = null) { if (!Resolve(uid, ref anchorable, ref transform)) @@ -271,7 +270,7 @@ private bool TileFree(EntityCoordinates coordinates, PhysicsComponent anchorBody // Probably ignore CanCollide on the anchoring body? var gridUid = coordinates.GetGridUid(EntityManager); - if (!_mapManager.TryGetGrid(gridUid, out var grid)) + if (!TryComp(gridUid, out var grid)) return false; var tileIndices = grid.TileIndicesFor(coordinates); diff --git a/Content.Shared/Construction/SharedFlatpackSystem.cs b/Content.Shared/Construction/SharedFlatpackSystem.cs index a62488d6f3..8b21bca52a 100644 --- a/Content.Shared/Construction/SharedFlatpackSystem.cs +++ b/Content.Shared/Construction/SharedFlatpackSystem.cs @@ -114,8 +114,7 @@ public void SetupFlatpack(Entity ent, EntityUid? board) if (!Resolve(ent, ref ent.Comp)) return; - EntProtoId machinePrototypeId; - string? entityPrototype; + var machinePrototypeId = new EntProtoId(); if (TryComp(board, out var machineBoard) && machineBoard.Prototype is not null) machinePrototypeId = machineBoard.Prototype; else if (TryComp(board, out var computerBoard) && computerBoard.Prototype is not null) diff --git a/Content.Shared/Coordinates/EntityCoordinatesExtensions.cs b/Content.Shared/Coordinates/EntityCoordinatesExtensions.cs index b9083eabe1..47d359d387 100644 --- a/Content.Shared/Coordinates/EntityCoordinatesExtensions.cs +++ b/Content.Shared/Coordinates/EntityCoordinatesExtensions.cs @@ -1,6 +1,5 @@ using System.Numerics; using Robust.Shared.Map; -using Robust.Shared.Map.Components; namespace Content.Shared.Coordinates { @@ -20,17 +19,5 @@ public static EntityCoordinates ToCoordinates(this EntityUid id, float x, float { return new EntityCoordinates(id, x, y); } - - [Obsolete] - public static EntityCoordinates ToCoordinates(this MapGridComponent grid, float x, float y) - { - return ToCoordinates(grid.Owner, x, y); - } - - [Obsolete] - public static EntityCoordinates ToCoordinates(this MapGridComponent grid) - { - return ToCoordinates(grid.Owner, Vector2.Zero); - } } } diff --git a/Content.Shared/Coordinates/Helpers/SnapgridHelper.cs b/Content.Shared/Coordinates/Helpers/SnapgridHelper.cs index 567a600388..db9ee85a0c 100644 --- a/Content.Shared/Coordinates/Helpers/SnapgridHelper.cs +++ b/Content.Shared/Coordinates/Helpers/SnapgridHelper.cs @@ -22,7 +22,7 @@ public static EntityCoordinates SnapToGrid(this EntityCoordinates coordinates, I return EntityCoordinates.FromMap(coordinates.EntityId, mapPos, xformSys); } - var grid = mapManager.GetGrid(gridId.Value); + var grid = entMan.GetComponent(gridId.Value); var tileSize = grid.TileSize; var localPos = coordinates.WithEntityId(gridId.Value).Position; var x = (int)Math.Floor(localPos.X / tileSize) + tileSize / 2f; diff --git a/Content.Shared/Cuffs/SharedCuffableSystem.cs b/Content.Shared/Cuffs/SharedCuffableSystem.cs index 92f4576c8b..8ee34dbcc5 100644 --- a/Content.Shared/Cuffs/SharedCuffableSystem.cs +++ b/Content.Shared/Cuffs/SharedCuffableSystem.cs @@ -22,9 +22,8 @@ using Content.Shared.Item; using Content.Shared.Mobs.Systems; using Content.Shared.Movement.Events; -using Content.Shared.Physics.Pull; +using Content.Shared.Movement.Pulling.Events; using Content.Shared.Popups; -using Content.Shared.Pulling.Components; using Content.Shared.Pulling.Events; using Content.Shared.Rejuvenate; using Content.Shared.Stunnable; @@ -37,6 +36,7 @@ using Robust.Shared.Network; using Robust.Shared.Player; using Robust.Shared.Serialization; +using PullableComponent = Content.Shared.Movement.Pulling.Components.PullableComponent; namespace Content.Shared.Cuffs { @@ -72,7 +72,7 @@ public override void Initialize() SubscribeLocalEvent(OnCuffsInsertedIntoContainer); SubscribeLocalEvent(OnRejuvenate); SubscribeLocalEvent(OnStartup); - SubscribeLocalEvent(HandleStopPull); + SubscribeLocalEvent(HandleStopPull); SubscribeLocalEvent(HandleMoveAttempt); SubscribeLocalEvent(OnEquipAttempt); SubscribeLocalEvent(OnUnequipAttempt); @@ -184,7 +184,7 @@ public void UpdateCuffState(EntityUid uid, CuffableComponent component) private void OnBeingPulledAttempt(EntityUid uid, CuffableComponent component, BeingPulledAttemptEvent args) { - if (!TryComp(uid, out var pullable)) + if (!TryComp(uid, out var pullable)) return; if (pullable.Puller != null && !component.CanStillInteract) // If we are being pulled already and cuffed, we can't get pulled again. @@ -216,19 +216,19 @@ private void OnPull(EntityUid uid, CuffableComponent component, PullMessage args private void HandleMoveAttempt(EntityUid uid, CuffableComponent component, UpdateCanMoveEvent args) { - if (component.CanStillInteract || !EntityManager.TryGetComponent(uid, out SharedPullableComponent? pullable) || !pullable.BeingPulled) + if (component.CanStillInteract || !EntityManager.TryGetComponent(uid, out PullableComponent? pullable) || !pullable.BeingPulled) return; args.Cancel(); } - private void HandleStopPull(EntityUid uid, CuffableComponent component, StopPullingEvent args) + private void HandleStopPull(EntityUid uid, CuffableComponent component, AttemptStopPullingEvent args) { if (args.User == null || !Exists(args.User.Value)) return; if (args.User.Value == uid && !component.CanStillInteract) - args.Cancel(); + args.Cancelled = true; } private void AddUncuffVerb(EntityUid uid, CuffableComponent component, GetVerbsEvent args) diff --git a/Content.Shared/Disposal/SharedDisposalUnitSystem.cs b/Content.Shared/Disposal/SharedDisposalUnitSystem.cs index 600036a891..9afd683cbd 100644 --- a/Content.Shared/Disposal/SharedDisposalUnitSystem.cs +++ b/Content.Shared/Disposal/SharedDisposalUnitSystem.cs @@ -127,9 +127,6 @@ public virtual bool CanInsert(EntityUid uid, SharedDisposalUnitComponent compone return damageState != null && (!component.MobsCanEnter || _mobState.IsDead(entity, damageState)); } - /// - /// TODO: Proper prediction - /// public abstract void DoInsertDisposalUnit(EntityUid uid, EntityUid toInsert, EntityUid user, SharedDisposalUnitComponent? disposal = null); [Serializable, NetSerializable] diff --git a/Content.Shared/Follower/FollowerSystem.cs b/Content.Shared/Follower/FollowerSystem.cs index 5656778a3f..fc7cccf9bd 100644 --- a/Content.Shared/Follower/FollowerSystem.cs +++ b/Content.Shared/Follower/FollowerSystem.cs @@ -4,8 +4,8 @@ using Content.Shared.Ghost; using Content.Shared.Hands; using Content.Shared.Movement.Events; +using Content.Shared.Movement.Pulling.Events; using Content.Shared.Movement.Systems; -using Content.Shared.Physics.Pull; using Content.Shared.Tag; using Content.Shared.Verbs; using Robust.Shared.Containers; diff --git a/Content.Shared/Friction/TileFrictionController.cs b/Content.Shared/Friction/TileFrictionController.cs index ba4d9fc24f..3583947ee3 100644 --- a/Content.Shared/Friction/TileFrictionController.cs +++ b/Content.Shared/Friction/TileFrictionController.cs @@ -2,8 +2,8 @@ using Content.Shared.CCVar; using Content.Shared.Gravity; using Content.Shared.Movement.Events; +using Content.Shared.Movement.Pulling.Components; using Content.Shared.Movement.Systems; -using Content.Shared.Pulling.Components; using JetBrains.Annotations; using Robust.Shared.Configuration; using Robust.Shared.Map; @@ -23,6 +23,12 @@ public sealed class TileFrictionController : VirtualController [Dependency] private readonly SharedMoverController _mover = default!; [Dependency] private readonly SharedPhysicsSystem _physics = default!; + private EntityQuery _frictionQuery; + private EntityQuery _xformQuery; + private EntityQuery _pullerQuery; + private EntityQuery _pullableQuery; + private EntityQuery _gridQuery; + private float _stopSpeed; private float _frictionModifier; public const float DefaultFriction = 0.3f; @@ -33,18 +39,17 @@ public override void Initialize() Subs.CVar(_configManager, CCVars.TileFrictionModifier, value => _frictionModifier = value, true); Subs.CVar(_configManager, CCVars.StopSpeed, value => _stopSpeed = value, true); + _frictionQuery = GetEntityQuery(); + _xformQuery = GetEntityQuery(); + _pullerQuery = GetEntityQuery(); + _pullableQuery = GetEntityQuery(); + _gridQuery = GetEntityQuery(); } public override void UpdateBeforeMapSolve(bool prediction, PhysicsMapComponent mapComponent, float frameTime) { base.UpdateBeforeMapSolve(prediction, mapComponent, frameTime); - var frictionQuery = GetEntityQuery(); - var xformQuery = GetEntityQuery(); - var pullerQuery = GetEntityQuery(); - var pullableQuery = GetEntityQuery(); - var gridQuery = GetEntityQuery(); - foreach (var body in mapComponent.AwakeBodies) { var uid = body.Owner; @@ -60,16 +65,16 @@ public override void UpdateBeforeMapSolve(bool prediction, PhysicsMapComponent m if (body.LinearVelocity.Equals(Vector2.Zero) && body.AngularVelocity.Equals(0f)) continue; - if (!xformQuery.TryGetComponent(uid, out var xform)) + if (!_xformQuery.TryGetComponent(uid, out var xform)) { Log.Error($"Unable to get transform for {ToPrettyString(uid)} in tilefrictioncontroller"); continue; } - var surfaceFriction = GetTileFriction(uid, body, xform, gridQuery, frictionQuery); + var surfaceFriction = GetTileFriction(uid, body, xform); var bodyModifier = 1f; - if (frictionQuery.TryGetComponent(uid, out var frictionComp)) + if (_frictionQuery.TryGetComponent(uid, out var frictionComp)) { bodyModifier = frictionComp.Modifier; } @@ -82,8 +87,8 @@ public override void UpdateBeforeMapSolve(bool prediction, PhysicsMapComponent m // If we're sandwiched between 2 pullers reduce friction // Might be better to make this dynamic and check how many are in the pull chain? // Either way should be much faster for now. - if (pullerQuery.TryGetComponent(uid, out var puller) && puller.Pulling != null && - pullableQuery.TryGetComponent(uid, out var pullable) && pullable.BeingPulled) + if (_pullerQuery.TryGetComponent(uid, out var puller) && puller.Pulling != null && + _pullableQuery.TryGetComponent(uid, out var pullable) && pullable.BeingPulled) { bodyModifier *= 0.2f; } @@ -163,9 +168,7 @@ private void ReduceAngularVelocity(EntityUid uid, bool prediction, PhysicsCompon private float GetTileFriction( EntityUid uid, PhysicsComponent body, - TransformComponent xform, - EntityQuery gridQuery, - EntityQuery frictionQuery) + TransformComponent xform) { // TODO: Make IsWeightless event-based; we already have grid traversals tracked so just raise events if (_gravity.IsWeightless(uid, body, xform)) @@ -175,9 +178,9 @@ private float GetTileFriction( return 0.0f; // If not on a grid then return the map's friction. - if (!gridQuery.TryGetComponent(xform.GridUid, out var grid)) + if (!_gridQuery.TryGetComponent(xform.GridUid, out var grid)) { - return frictionQuery.TryGetComponent(xform.MapUid, out var friction) + return _frictionQuery.TryGetComponent(xform.MapUid, out var friction) ? friction.Modifier : DefaultFriction; } @@ -197,7 +200,7 @@ private float GetTileFriction( while (anc.MoveNext(out var tileEnt)) { - if (frictionQuery.TryGetComponent(tileEnt, out var friction)) + if (_frictionQuery.TryGetComponent(tileEnt, out var friction)) return friction.Modifier; } diff --git a/Content.Shared/IdentityManagement/Components/IdentityBlockerComponent.cs b/Content.Shared/IdentityManagement/Components/IdentityBlockerComponent.cs index 3857063783..e7a88b6ef2 100644 --- a/Content.Shared/IdentityManagement/Components/IdentityBlockerComponent.cs +++ b/Content.Shared/IdentityManagement/Components/IdentityBlockerComponent.cs @@ -6,6 +6,7 @@ namespace Content.Shared.IdentityManagement.Components; [RegisterComponent, NetworkedComponent] public sealed partial class IdentityBlockerComponent : Component { + [DataField] public bool Enabled = true; /// diff --git a/Content.Shared/Interaction/SharedInteractionSystem.cs b/Content.Shared/Interaction/SharedInteractionSystem.cs index 0e390ecea4..e4864b1f7f 100644 --- a/Content.Shared/Interaction/SharedInteractionSystem.cs +++ b/Content.Shared/Interaction/SharedInteractionSystem.cs @@ -15,10 +15,10 @@ using Content.Shared.Inventory.Events; using Content.Shared.Item; using Content.Shared.Movement.Components; +using Content.Shared.Movement.Pulling.Components; +using Content.Shared.Movement.Pulling.Systems; using Content.Shared.Physics; using Content.Shared.Popups; -using Content.Shared.Pulling; -using Content.Shared.Pulling.Components; using Content.Shared.Tag; using Content.Shared.Timing; using Content.Shared.Verbs; @@ -60,7 +60,7 @@ public abstract partial class SharedInteractionSystem : EntitySystem [Dependency] private readonly SharedVerbSystem _verbSystem = default!; [Dependency] private readonly SharedPopupSystem _popupSystem = default!; [Dependency] private readonly UseDelaySystem _useDelay = default!; - [Dependency] private readonly SharedPullingSystem _pullSystem = default!; + [Dependency] private readonly PullingSystem _pullSystem = default!; [Dependency] private readonly InventorySystem _inventory = default!; [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly TagSystem _tagSystem = default!; @@ -185,10 +185,10 @@ private bool HandleTryPullObject(ICommonSession? session, EntityCoordinates coor if (!InRangeUnobstructed(userEntity.Value, uid, popup: true)) return false; - if (!TryComp(uid, out SharedPullableComponent? pull)) + if (!TryComp(uid, out PullableComponent? pull)) return false; - _pullSystem.TogglePull(userEntity.Value, pull); + _pullSystem.TogglePull(uid, userEntity.Value, pull); return false; } diff --git a/Content.Shared/Language/Components/LanguageKnowledgeComponent.cs b/Content.Shared/Language/Components/LanguageKnowledgeComponent.cs index 0632f5d9cb..ddbdc742be 100644 --- a/Content.Shared/Language/Components/LanguageKnowledgeComponent.cs +++ b/Content.Shared/Language/Components/LanguageKnowledgeComponent.cs @@ -2,6 +2,8 @@ namespace Content.Shared.Language.Components; +// TODO: move to server side, it's never synchronized! + /// /// Stores data about entities' intrinsic language knowledge. /// diff --git a/Content.Shared/Language/LanguagePrototype.cs b/Content.Shared/Language/LanguagePrototype.cs index 9342c07e91..be54b45aa1 100644 --- a/Content.Shared/Language/LanguagePrototype.cs +++ b/Content.Shared/Language/LanguagePrototype.cs @@ -8,6 +8,15 @@ public sealed class LanguagePrototype : IPrototype [IdDataField] public string ID { get; private set; } = default!; + [DataField("color")] + public Color? Color; + + [DataField("fontId")] + public string? FontId; + + [DataField("fontSize")] + public int? FontSize; + /// /// Obfuscation method used by this language. By default, uses /// diff --git a/Content.Shared/Language/Systems/SharedTranslatorSystem.cs b/Content.Shared/Language/Systems/SharedTranslatorSystem.cs index 08a016efa9..4a72de791f 100644 --- a/Content.Shared/Language/Systems/SharedTranslatorSystem.cs +++ b/Content.Shared/Language/Systems/SharedTranslatorSystem.cs @@ -1,3 +1,4 @@ +using System.Linq; using Content.Shared.Examine; using Content.Shared.Toggleable; using Content.Shared.Language.Components.Translators; @@ -17,11 +18,20 @@ public override void Initialize() private void OnExamined(EntityUid uid, HandheldTranslatorComponent component, ExaminedEvent args) { - var state = Loc.GetString(component.Enabled - ? "translator-enabled" - : "translator-disabled"); + var understoodLanguageNames = component.UnderstoodLanguages + .Select(it => Loc.GetString($"language-{it}-name")); + var spokenLanguageNames = component.SpokenLanguages + .Select(it => Loc.GetString($"language-{it}-name")); + var requiredLanguageNames = component.RequiredLanguages + .Select(it => Loc.GetString($"language-{it}-name")); - args.PushMarkup(state); + args.PushMarkup(Loc.GetString("translator-examined-langs-understood", ("languages", string.Join(", ", understoodLanguageNames)))); + args.PushMarkup(Loc.GetString("translator-examined-langs-spoken", ("languages", string.Join(", ", spokenLanguageNames)))); + + args.PushMarkup(Loc.GetString(component.RequiresAllLanguages ? "translator-examined-requires-all" : "translator-examined-requires-any", + ("languages", string.Join(", ", requiredLanguageNames)))); + + args.PushMarkup(Loc.GetString(component.Enabled ? "translator-examined-enabled" : "translator-examined-disabled")); } protected void OnAppearanceChange(EntityUid translator, HandheldTranslatorComponent? comp = null) diff --git a/Content.Shared/Light/Components/SharedExpendableLightComponent.cs b/Content.Shared/Light/Components/SharedExpendableLightComponent.cs index c802700b62..e40174ab78 100644 --- a/Content.Shared/Light/Components/SharedExpendableLightComponent.cs +++ b/Content.Shared/Light/Components/SharedExpendableLightComponent.cs @@ -7,7 +7,7 @@ namespace Content.Shared.Light.Components; [NetworkedComponent] public abstract partial class SharedExpendableLightComponent : Component { - public static readonly AudioParams LoopedSoundParams = new(0, 1, "Master", 62.5f, 1, 1, true, 0.3f); + public static readonly AudioParams LoopedSoundParams = new(0, 1, 62.5f, 1, 1, true, 0.3f); [ViewVariables(VVAccess.ReadOnly)] public ExpendableLightState CurrentState { get; set; } diff --git a/Content.Shared/Maps/TurfHelpers.cs b/Content.Shared/Maps/TurfHelpers.cs index 58a5d133b5..f1c1beef7d 100644 --- a/Content.Shared/Maps/TurfHelpers.cs +++ b/Content.Shared/Maps/TurfHelpers.cs @@ -3,6 +3,7 @@ using System.Runtime.CompilerServices; using Content.Shared.Physics; using Robust.Shared.Map; +using Robust.Shared.Map.Components; using Robust.Shared.Random; namespace Content.Shared.Maps @@ -11,6 +12,22 @@ namespace Content.Shared.Maps // That, or make the interface arguments non-optional so people stop failing to pass them in. public static class TurfHelpers { + /// + /// Attempts to get the turf at map indices with grid id or null if no such turf is found. + /// + public static TileRef GetTileRef(this Vector2i vector2i, EntityUid gridId, IEntityManager? entityManager = null) + { + entityManager ??= IoCManager.Resolve(); + + if (!entityManager.TryGetComponent(gridId, out var grid)) + return default; + + if (!grid.TryGetTileRef(vector2i, out var tile)) + return default; + + return tile; + } + /// /// Attempts to get the turf at a certain coordinates or null if no such turf is found. /// @@ -119,9 +136,8 @@ public static bool IsBlockedTurf(this TileRef turf, bool filterMobs, EntityLooku private static bool GetWorldTileBox(TileRef turf, out Box2Rotated res) { var entManager = IoCManager.Resolve(); - var map = IoCManager.Resolve(); - if (map.TryGetGrid(turf.GridUid, out var tileGrid)) + if (entManager.TryGetComponent(turf.GridUid, out var tileGrid)) { var gridRot = entManager.GetComponent(turf.GridUid).WorldRotation; diff --git a/Content.Shared/Maps/TurfSystem.cs b/Content.Shared/Maps/TurfSystem.cs index a344193f12..ad8b3ddea8 100644 --- a/Content.Shared/Maps/TurfSystem.cs +++ b/Content.Shared/Maps/TurfSystem.cs @@ -13,7 +13,6 @@ public sealed class TurfSystem : EntitySystem { [Dependency] private readonly EntityLookupSystem _entityLookup = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; - [Dependency] private readonly IMapManager _mapMan = default!; /// /// Returns true if a given tile is blocked by physics-enabled entities. @@ -92,7 +91,7 @@ public bool IsTileBlocked(EntityUid gridUid, /// public EntityCoordinates GetTileCenter(TileRef turf) { - var grid = _mapMan.GetGrid(turf.GridUid); + var grid = Comp(turf.GridUid); var center = (turf.GridIndices + new Vector2(0.5f, 0.5f)) * grid.TileSize; return new EntityCoordinates(turf.GridUid, center); } diff --git a/Content.Shared/Materials/SharedMaterialReclaimerSystem.cs b/Content.Shared/Materials/SharedMaterialReclaimerSystem.cs index 5a9ada7f58..50dce3c766 100644 --- a/Content.Shared/Materials/SharedMaterialReclaimerSystem.cs +++ b/Content.Shared/Materials/SharedMaterialReclaimerSystem.cs @@ -1,7 +1,8 @@ -using System.Linq; +using System.Linq; using Content.Shared.Administration.Logs; using Content.Shared.Audio; using Content.Shared.Body.Components; +using Content.Shared.Coordinates; using Content.Shared.Database; using Content.Shared.Emag.Components; using Content.Shared.Emag.Systems; @@ -11,6 +12,7 @@ using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; using Robust.Shared.Containers; +using Robust.Shared.Map; using Robust.Shared.Physics.Events; using Robust.Shared.Timing; @@ -110,6 +112,9 @@ public bool TryStartProcessItem(EntityUid uid, EntityUid item, MaterialReclaimer component.NextSound = Timing.CurTime + component.SoundCooldown; } + var reclaimedEvent = new GotReclaimedEvent(Transform(uid).Coordinates); + RaiseLocalEvent(item, ref reclaimedEvent); + var duration = GetReclaimingDuration(uid, item, component); // if it's instant, don't bother with all the active comp stuff. if (duration == TimeSpan.Zero) @@ -238,3 +243,6 @@ public override void Update(float frameTime) } } } + +[ByRefEvent] +public record struct GotReclaimedEvent(EntityCoordinates ReclaimerCoordinates); diff --git a/Content.Shared/Movement/Pulling/Components/PullableComponent.cs b/Content.Shared/Movement/Pulling/Components/PullableComponent.cs new file mode 100644 index 0000000000..db889e7e3b --- /dev/null +++ b/Content.Shared/Movement/Pulling/Components/PullableComponent.cs @@ -0,0 +1,39 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Movement.Pulling.Components; + +/// +/// Specifies an entity as being pullable by an entity with +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(Systems.PullingSystem))] +public sealed partial class PullableComponent : Component +{ + /// + /// The current entity pulling this component. + /// + [AutoNetworkedField, DataField] + public EntityUid? Puller; + + /// + /// The pull joint. + /// + [AutoNetworkedField, DataField] + public string? PullJointId; + + public bool BeingPulled => Puller != null; + + /// + /// If the physics component has FixedRotation should we keep it upon being pulled + /// + [Access(typeof(Systems.PullingSystem), Other = AccessPermissions.ReadExecute)] + [ViewVariables(VVAccess.ReadWrite), DataField("fixedRotation")] + public bool FixedRotationOnPull; + + /// + /// What the pullable's fixedrotation was set to before being pulled. + /// + [Access(typeof(Systems.PullingSystem), Other = AccessPermissions.ReadExecute)] + [AutoNetworkedField, DataField] + public bool PrevFixedRotation; +} diff --git a/Content.Shared/Movement/Pulling/Components/PullerComponent.cs b/Content.Shared/Movement/Pulling/Components/PullerComponent.cs new file mode 100644 index 0000000000..1fc9b731bd --- /dev/null +++ b/Content.Shared/Movement/Pulling/Components/PullerComponent.cs @@ -0,0 +1,41 @@ +using Content.Shared.Movement.Pulling.Systems; +using Robust.Shared.GameStates; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; + +namespace Content.Shared.Movement.Pulling.Components; + +/// +/// Specifies an entity as being able to pull another entity with +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(PullingSystem))] +public sealed partial class PullerComponent : Component +{ + // My raiding guild + /// + /// Next time the puller can throw what is being pulled. + /// Used to avoid spamming it for infinite spin + velocity. + /// + [DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoNetworkedField] + public TimeSpan NextThrow; + + [DataField] + public TimeSpan ThrowCooldown = TimeSpan.FromSeconds(1); + + // Before changing how this is updated, please see SharedPullerSystem.RefreshMovementSpeed + public float WalkSpeedModifier => Pulling == default ? 1.0f : 0.95f; + + public float SprintSpeedModifier => Pulling == default ? 1.0f : 0.95f; + + /// + /// Entity currently being pulled if applicable. + /// + [AutoNetworkedField, DataField] + public EntityUid? Pulling; + + /// + /// Does this entity need hands to be able to pull something? + /// + [DataField] + public bool NeedsHands = true; +} diff --git a/Content.Shared/Movement/Pulling/Events/AttemptPullEvent.cs b/Content.Shared/Movement/Pulling/Events/AttemptPullEvent.cs new file mode 100644 index 0000000000..b0101c4699 --- /dev/null +++ b/Content.Shared/Movement/Pulling/Events/AttemptPullEvent.cs @@ -0,0 +1,13 @@ +using Robust.Shared.Physics.Components; + +namespace Content.Shared.Movement.Pulling.Events; + +/// +/// Raised directed on puller and pullable to determine if it can be pulled. +/// +public sealed class PullAttemptEvent : PullMessage +{ + public PullAttemptEvent(EntityUid pullerUid, EntityUid pullableUid) : base(pullerUid, pullableUid) { } + + public bool Cancelled { get; set; } +} diff --git a/Content.Shared/Movement/Pulling/Events/AttemptStopPullingEvent.cs b/Content.Shared/Movement/Pulling/Events/AttemptStopPullingEvent.cs new file mode 100644 index 0000000000..cd7edc5f62 --- /dev/null +++ b/Content.Shared/Movement/Pulling/Events/AttemptStopPullingEvent.cs @@ -0,0 +1,10 @@ +namespace Content.Shared.Pulling.Events; + +/// +/// Raised when a request is made to stop pulling an entity. +/// +public record struct AttemptStopPullingEvent(EntityUid? User = null) +{ + public readonly EntityUid? User = User; + public bool Cancelled; +} \ No newline at end of file diff --git a/Content.Shared/Pulling/Events/BeingPulledAttemptEvent.cs b/Content.Shared/Movement/Pulling/Events/BeingPulledAttemptEvent.cs similarity index 100% rename from Content.Shared/Pulling/Events/BeingPulledAttemptEvent.cs rename to Content.Shared/Movement/Pulling/Events/BeingPulledAttemptEvent.cs diff --git a/Content.Shared/Movement/Pulling/Events/PullMessage.cs b/Content.Shared/Movement/Pulling/Events/PullMessage.cs new file mode 100644 index 0000000000..a427e448d5 --- /dev/null +++ b/Content.Shared/Movement/Pulling/Events/PullMessage.cs @@ -0,0 +1,13 @@ +namespace Content.Shared.Movement.Pulling.Events; + +public abstract class PullMessage : EntityEventArgs +{ + public readonly EntityUid PullerUid; + public readonly EntityUid PulledUid; + + protected PullMessage(EntityUid pullerUid, EntityUid pulledUid) + { + PullerUid = pullerUid; + PulledUid = pulledUid; + } +} diff --git a/Content.Shared/Movement/Pulling/Events/PullStartedMessage.cs b/Content.Shared/Movement/Pulling/Events/PullStartedMessage.cs new file mode 100644 index 0000000000..29460e1dfc --- /dev/null +++ b/Content.Shared/Movement/Pulling/Events/PullStartedMessage.cs @@ -0,0 +1,9 @@ +namespace Content.Shared.Movement.Pulling.Events; + +public sealed class PullStartedMessage : PullMessage +{ + public PullStartedMessage(EntityUid pullerUid, EntityUid pullableUid) : + base(pullerUid, pullableUid) + { + } +} diff --git a/Content.Shared/Movement/Pulling/Events/PullStoppedMessage.cs b/Content.Shared/Movement/Pulling/Events/PullStoppedMessage.cs new file mode 100644 index 0000000000..47aa34562f --- /dev/null +++ b/Content.Shared/Movement/Pulling/Events/PullStoppedMessage.cs @@ -0,0 +1,13 @@ +using Robust.Shared.Physics.Components; + +namespace Content.Shared.Movement.Pulling.Events; + +/// +/// Raised directed on both puller and pullable. +/// +public sealed class PullStoppedMessage : PullMessage +{ + public PullStoppedMessage(EntityUid pullerUid, EntityUid pulledUid) : base(pullerUid, pulledUid) + { + } +} diff --git a/Content.Shared/Pulling/Events/StartPullAttemptEvent.cs b/Content.Shared/Movement/Pulling/Events/StartPullAttemptEvent.cs similarity index 100% rename from Content.Shared/Pulling/Events/StartPullAttemptEvent.cs rename to Content.Shared/Movement/Pulling/Events/StartPullAttemptEvent.cs diff --git a/Content.Shared/Movement/Pulling/Systems/PullingSystem.cs b/Content.Shared/Movement/Pulling/Systems/PullingSystem.cs new file mode 100644 index 0000000000..b347c6da16 --- /dev/null +++ b/Content.Shared/Movement/Pulling/Systems/PullingSystem.cs @@ -0,0 +1,494 @@ +using System.Numerics; +using Content.Shared.ActionBlocker; +using Content.Shared.Administration.Logs; +using Content.Shared.Alert; +using Content.Shared.Buckle.Components; +using Content.Shared.Database; +using Content.Shared.Hands; +using Content.Shared.Hands.EntitySystems; +using Content.Shared.Input; +using Content.Shared.Interaction; +using Content.Shared.Movement.Events; +using Content.Shared.Movement.Pulling.Components; +using Content.Shared.Movement.Pulling.Events; +using Content.Shared.Movement.Systems; +using Content.Shared.Pulling.Events; +using Content.Shared.Throwing; +using Content.Shared.Verbs; +using Robust.Shared.Containers; +using Robust.Shared.Input.Binding; +using Robust.Shared.Map; +using Robust.Shared.Physics; +using Robust.Shared.Physics.Components; +using Robust.Shared.Physics.Events; +using Robust.Shared.Physics.Systems; +using Robust.Shared.Player; +using Robust.Shared.Timing; + +namespace Content.Shared.Movement.Pulling.Systems; + +/// +/// Allows one entity to pull another behind them via a physics distance joint. +/// +public sealed class PullingSystem : EntitySystem +{ + [Dependency] private readonly IGameTiming _timing = default!; + [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!; + [Dependency] private readonly ActionBlockerSystem _blocker = default!; + [Dependency] private readonly AlertsSystem _alertsSystem = default!; + [Dependency] private readonly MovementSpeedModifierSystem _modifierSystem = default!; + [Dependency] private readonly SharedJointSystem _joints = default!; + [Dependency] private readonly SharedContainerSystem _containerSystem = default!; + [Dependency] private readonly SharedHandsSystem _handsSystem = default!; + [Dependency] private readonly SharedInteractionSystem _interaction = default!; + [Dependency] private readonly SharedPhysicsSystem _physics = default!; + [Dependency] private readonly SharedTransformSystem _xformSys = default!; + [Dependency] private readonly ThrowingSystem _throwing = default!; + + public override void Initialize() + { + base.Initialize(); + + UpdatesAfter.Add(typeof(SharedPhysicsSystem)); + UpdatesOutsidePrediction = true; + + SubscribeLocalEvent(OnPullableMoveInput); + SubscribeLocalEvent(OnPullableCollisionChange); + SubscribeLocalEvent(OnJointRemoved); + SubscribeLocalEvent>(AddPullVerbs); + SubscribeLocalEvent(OnPullableContainerInsert); + + SubscribeLocalEvent(OnPullerContainerInsert); + SubscribeLocalEvent(OnPullerUnpaused); + SubscribeLocalEvent(OnVirtualItemDeleted); + SubscribeLocalEvent(OnRefreshMovespeed); + + CommandBinds.Builder + .Bind(ContentKeyFunctions.MovePulledObject, new PointerInputCmdHandler(OnRequestMovePulledObject)) + .Bind(ContentKeyFunctions.ReleasePulledObject, InputCmdHandler.FromDelegate(OnReleasePulledObject, handle: false)) + .Register(); + } + + private void OnPullerContainerInsert(Entity ent, ref EntGotInsertedIntoContainerMessage args) + { + if (ent.Comp.Pulling == null) return; + + if (!TryComp(ent.Comp.Pulling.Value, out PullableComponent? pulling)) + return; + + TryStopPull(ent.Comp.Pulling.Value, pulling, ent.Owner); + } + + private void OnPullableContainerInsert(Entity ent, ref EntGotInsertedIntoContainerMessage args) + { + TryStopPull(ent.Owner, ent.Comp); + } + + public override void Shutdown() + { + base.Shutdown(); + CommandBinds.Unregister(); + } + + private void OnPullerUnpaused(EntityUid uid, PullerComponent component, ref EntityUnpausedEvent args) + { + component.NextThrow += args.PausedTime; + } + + private void OnVirtualItemDeleted(EntityUid uid, PullerComponent component, VirtualItemDeletedEvent args) + { + // If client deletes the virtual hand then stop the pull. + if (component.Pulling == null) + return; + + if (component.Pulling != args.BlockingEntity) + return; + + if (EntityManager.TryGetComponent(args.BlockingEntity, out PullableComponent? comp)) + { + TryStopPull(args.BlockingEntity, comp, uid); + } + } + + private void AddPullVerbs(EntityUid uid, PullableComponent component, GetVerbsEvent args) + { + if (!args.CanAccess || !args.CanInteract) + return; + + // Are they trying to pull themselves up by their bootstraps? + if (args.User == args.Target) + return; + + //TODO VERB ICONS add pulling icon + if (component.Puller == args.User) + { + Verb verb = new() + { + Text = Loc.GetString("pulling-verb-get-data-text-stop-pulling"), + Act = () => TryStopPull(uid, component, user: args.User), + DoContactInteraction = false // pulling handle its own contact interaction. + }; + args.Verbs.Add(verb); + } + else if (CanPull(args.User, args.Target)) + { + Verb verb = new() + { + Text = Loc.GetString("pulling-verb-get-data-text"), + Act = () => TryStartPull(args.User, args.Target), + DoContactInteraction = false // pulling handle its own contact interaction. + }; + args.Verbs.Add(verb); + } + } + + private void OnRefreshMovespeed(EntityUid uid, PullerComponent component, RefreshMovementSpeedModifiersEvent args) + { + args.ModifySpeed(component.WalkSpeedModifier, component.SprintSpeedModifier); + } + + private void OnPullableMoveInput(EntityUid uid, PullableComponent component, ref MoveInputEvent args) + { + // If someone moves then break their pulling. + if (!component.BeingPulled) + return; + + var entity = args.Entity; + + if (!_blocker.CanMove(entity)) + return; + + TryStopPull(uid, component, user: uid); + } + + private void OnPullableCollisionChange(EntityUid uid, PullableComponent component, ref CollisionChangeEvent args) + { + // IDK what this is supposed to be. + if (!_timing.ApplyingState && component.PullJointId != null && !args.CanCollide) + { + _joints.RemoveJoint(uid, component.PullJointId); + } + } + + private void OnJointRemoved(EntityUid uid, PullableComponent component, JointRemovedEvent args) + { + // Just handles the joint getting nuked without going through pulling system (valid behavior). + + // Not relevant / pullable state handle it. + if (component.Puller != args.OtherEntity || + args.Joint.ID != component.PullJointId || + _timing.ApplyingState) + { + return; + } + + if (args.Joint.ID != component.PullJointId || component.Puller == null) + return; + + StopPulling(uid, component); + } + + /// + /// Forces pulling to stop and handles cleanup. + /// + private void StopPulling(EntityUid pullableUid, PullableComponent pullableComp) + { + if (!_timing.ApplyingState) + { + if (TryComp(pullableUid, out var pullablePhysics)) + { + _physics.SetFixedRotation(pullableUid, pullableComp.PrevFixedRotation, body: pullablePhysics); + } + } + + var oldPuller = pullableComp.Puller; + pullableComp.PullJointId = null; + pullableComp.Puller = null; + Dirty(pullableUid, pullableComp); + + // No more joints with puller -> force stop pull. + if (TryComp(oldPuller, out var pullerComp)) + { + var pullerUid = oldPuller.Value; + _alertsSystem.ClearAlert(pullerUid, AlertType.Pulling); + pullerComp.Pulling = null; + Dirty(oldPuller.Value, pullerComp); + + // Messaging + var message = new PullStoppedMessage(pullerUid, pullableUid); + _modifierSystem.RefreshMovementSpeedModifiers(pullerUid); + _adminLogger.Add(LogType.Action, LogImpact.Low, $"{ToPrettyString(pullerUid):user} stopped pulling {ToPrettyString(pullableUid):target}"); + + RaiseLocalEvent(pullerUid, message); + RaiseLocalEvent(pullableUid, message); + } + + + _alertsSystem.ClearAlert(pullableUid, AlertType.Pulled); + } + + public bool IsPulled(EntityUid uid, PullableComponent? component = null) + { + return Resolve(uid, ref component, false) && component.BeingPulled; + } + + private bool OnRequestMovePulledObject(ICommonSession? session, EntityCoordinates coords, EntityUid uid) + { + if (session?.AttachedEntity is not { } player || + !player.IsValid()) + { + return false; + } + + if (!TryComp(player, out var pullerComp)) + return false; + + var pulled = pullerComp.Pulling; + + if (!HasComp(pulled)) + return false; + + if (_containerSystem.IsEntityInContainer(player)) + return false; + + // Cooldown buddy + if (_timing.CurTime < pullerComp.NextThrow) + return false; + + pullerComp.NextThrow = _timing.CurTime + pullerComp.ThrowCooldown; + + // Cap the distance + const float range = 2f; + var fromUserCoords = coords.WithEntityId(player, EntityManager); + var userCoords = new EntityCoordinates(player, Vector2.Zero); + + if (!userCoords.InRange(EntityManager, _xformSys, fromUserCoords, range)) + { + var userDirection = fromUserCoords.Position - userCoords.Position; + fromUserCoords = userCoords.Offset(userDirection.Normalized() * range); + } + + Dirty(player, pullerComp); + _throwing.TryThrow(pulled.Value, fromUserCoords, user: player, strength: 4f, animated: false, recoil: false, playSound: false); + return false; + } + + public bool IsPulling(EntityUid puller, PullerComponent? component = null) + { + return Resolve(puller, ref component, false) && component.Pulling != null; + } + + private void OnReleasePulledObject(ICommonSession? session) + { + if (session?.AttachedEntity is not {Valid: true} player) + { + return; + } + + if (!TryComp(player, out PullerComponent? pullerComp) || + !TryComp(pullerComp.Pulling, out PullableComponent? pullableComp)) + { + return; + } + + TryStopPull(pullerComp.Pulling.Value, pullableComp, user: player); + } + + public bool CanPull(EntityUid puller, EntityUid pullableUid, PullerComponent? pullerComp = null) + { + if (!Resolve(puller, ref pullerComp, false)) + { + return false; + } + + if (pullerComp.NeedsHands && !_handsSystem.TryGetEmptyHand(puller, out _)) + { + return false; + } + + if (!_blocker.CanInteract(puller, pullableUid)) + { + return false; + } + + if (!EntityManager.TryGetComponent(pullableUid, out var physics)) + { + return false; + } + + if (physics.BodyType == BodyType.Static) + { + return false; + } + + if (puller == pullableUid) + { + return false; + } + + if (!_containerSystem.IsInSameOrNoContainer(puller, pullableUid)) + { + return false; + } + + if (EntityManager.TryGetComponent(puller, out BuckleComponent? buckle)) + { + // Prevent people pulling the chair they're on, etc. + if (buckle is { PullStrap: false, Buckled: true } && (buckle.LastEntityBuckledTo == pullableUid)) + { + return false; + } + } + + var getPulled = new BeingPulledAttemptEvent(puller, pullableUid); + RaiseLocalEvent(pullableUid, getPulled, true); + var startPull = new StartPullAttemptEvent(puller, pullableUid); + RaiseLocalEvent(puller, startPull, true); + return !startPull.Cancelled && !getPulled.Cancelled; + } + + public bool TogglePull(EntityUid pullableUid, EntityUid pullerUid, PullableComponent pullable) + { + if (pullable.Puller == pullerUid) + { + return TryStopPull(pullableUid, pullable); + } + + return TryStartPull(pullerUid, pullableUid, pullableComp: pullable); + } + + public bool TogglePull(EntityUid pullerUid, PullerComponent puller) + { + if (!TryComp(puller.Pulling, out var pullable)) + return false; + + return TogglePull(puller.Pulling.Value, pullerUid, pullable); + } + + public bool TryStartPull(EntityUid pullerUid, EntityUid pullableUid, EntityUid? user = null, + PullerComponent? pullerComp = null, PullableComponent? pullableComp = null) + { + if (!Resolve(pullerUid, ref pullerComp, false) || + !Resolve(pullableUid, ref pullableComp, false)) + { + return false; + } + + if (pullerComp.Pulling == pullableUid) + return true; + + if (!CanPull(pullerUid, pullableUid)) + return false; + + if (!EntityManager.TryGetComponent(pullerUid, out var pullerPhysics) || + !EntityManager.TryGetComponent(pullableUid, out var pullablePhysics)) + { + return false; + } + + // Ensure that the puller is not currently pulling anything. + var oldPullable = pullerComp.Pulling; + + if (oldPullable != null) + { + // Well couldn't stop the old one. + if (!TryStopPull(oldPullable.Value, pullableComp, user)) + return false; + } + + // Is the pullable currently being pulled by something else? + if (pullableComp.Puller != null) + { + // Uhhh + if (pullableComp.Puller == pullerUid) + return false; + + if (!TryStopPull(pullableUid, pullableComp, pullerUid)) + return false; + } + + var pullAttempt = new PullAttemptEvent(pullerUid, pullableUid); + RaiseLocalEvent(pullerUid, pullAttempt); + + if (pullAttempt.Cancelled) + return false; + + RaiseLocalEvent(pullableUid, pullAttempt); + + if (pullAttempt.Cancelled) + return false; + + // Pulling confirmed + + _interaction.DoContactInteraction(pullableUid, pullerUid); + + // Use net entity so it's consistent across client and server. + pullableComp.PullJointId = $"pull-joint-{GetNetEntity(pullableUid)}"; + + pullerComp.Pulling = pullableUid; + pullableComp.Puller = pullerUid; + + // joint state handling will manage its own state + if (!_timing.ApplyingState) + { + // Joint startup + var union = _physics.GetHardAABB(pullerUid).Union(_physics.GetHardAABB(pullableUid, body: pullablePhysics)); + var length = Math.Max((float) union.Size.X, (float) union.Size.Y) * 0.75f; + + var joint = _joints.CreateDistanceJoint(pullableUid, pullerUid, id: pullableComp.PullJointId); + joint.CollideConnected = false; + // This maximum has to be there because if the object is constrained too closely, the clamping goes backwards and asserts. + joint.MaxLength = Math.Max(1.0f, length); + joint.Length = length * 0.75f; + joint.MinLength = 0f; + joint.Stiffness = 1f; + + _physics.SetFixedRotation(pullableUid, pullableComp.FixedRotationOnPull, body: pullablePhysics); + } + + pullableComp.PrevFixedRotation = pullablePhysics.FixedRotation; + + // Messaging + var message = new PullStartedMessage(pullerUid, pullableUid); + _alertsSystem.ShowAlert(pullerUid, AlertType.Pulling); + _alertsSystem.ShowAlert(pullableUid, AlertType.Pulled); + + RaiseLocalEvent(pullerUid, message); + RaiseLocalEvent(pullableUid, message); + + Dirty(pullerUid, pullerComp); + Dirty(pullableUid, pullableComp); + + _adminLogger.Add(LogType.Action, LogImpact.Low, + $"{ToPrettyString(pullerUid):user} started pulling {ToPrettyString(pullableUid):target}"); + return true; + } + + public bool TryStopPull(EntityUid pullableUid, PullableComponent pullable, EntityUid? user = null) + { + var pullerUidNull = pullable.Puller; + + if (pullerUidNull == null) + return false; + + var msg = new AttemptStopPullingEvent(user); + RaiseLocalEvent(pullableUid, msg, true); + + if (msg.Cancelled) + return false; + + // Stop pulling confirmed! + if (!_timing.ApplyingState) + { + // Joint shutdown + if (pullable.PullJointId != null) + { + _joints.RemoveJoint(pullableUid, pullable.PullJointId); + pullable.PullJointId = null; + } + } + + StopPulling(pullableUid, pullable); + return true; + } +} diff --git a/Content.Shared/Movement/Systems/SharedMoverController.cs b/Content.Shared/Movement/Systems/SharedMoverController.cs index 4d9eedbf7c..79d2e9f255 100644 --- a/Content.Shared/Movement/Systems/SharedMoverController.cs +++ b/Content.Shared/Movement/Systems/SharedMoverController.cs @@ -9,7 +9,7 @@ using Content.Shared.Mobs.Systems; using Content.Shared.Movement.Components; using Content.Shared.Movement.Events; -using Content.Shared.Pulling.Components; +using Content.Shared.StepTrigger.Components; using Content.Shared.Tag; using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; @@ -23,7 +23,7 @@ using Robust.Shared.Physics.Systems; using Robust.Shared.Timing; using Robust.Shared.Utility; -using Content.Shared.StepTrigger.Components; // Delta V-NoShoesSilentFootstepsComponent +using PullableComponent = Content.Shared.Movement.Pulling.Components.PullableComponent; namespace Content.Shared.Movement.Systems { @@ -55,7 +55,7 @@ public abstract partial class SharedMoverController : VirtualController protected EntityQuery ModifierQuery; protected EntityQuery PhysicsQuery; protected EntityQuery RelayQuery; - protected EntityQuery PullableQuery; + protected EntityQuery PullableQuery; protected EntityQuery XformQuery; protected EntityQuery CanMoveInAirQuery; protected EntityQuery NoRotateQuery; @@ -87,7 +87,7 @@ public override void Initialize() RelayTargetQuery = GetEntityQuery(); PhysicsQuery = GetEntityQuery(); RelayQuery = GetEntityQuery(); - PullableQuery = GetEntityQuery(); + PullableQuery = GetEntityQuery(); XformQuery = GetEntityQuery(); NoRotateQuery = GetEntityQuery(); CanMoveInAirQuery = GetEntityQuery(); @@ -378,7 +378,7 @@ private bool IsAroundCollider(SharedPhysicsSystem broadPhaseSystem, TransformCom !otherCollider.CanCollide || ((collider.CollisionMask & otherCollider.CollisionLayer) == 0 && (otherCollider.CollisionMask & collider.CollisionLayer) == 0) || - (TryComp(otherCollider.Owner, out SharedPullableComponent? pullable) && pullable.BeingPulled)) + (TryComp(otherCollider.Owner, out PullableComponent? pullable) && pullable.BeingPulled)) { continue; } @@ -440,7 +440,7 @@ private bool TryGetSound( sound = moverModifier.FootstepSoundCollection; return true; } - + // If got the component in yml and no shoes = no sound. Delta V if (_entities.TryGetComponent(uid, out NoShoesSilentFootstepsComponent? _) & !_inventory.TryGetSlotEntity(uid, "shoes", out var _)) @@ -469,7 +469,7 @@ private bool TryGetFootstepSound( sound = null; // Fallback to the map? - if (!_mapManager.TryGetGrid(xform.GridUid, out var grid)) + if (!TryComp(xform.GridUid, out var grid)) { if (TryComp(xform.MapUid, out var modifier)) { diff --git a/Content.Shared/Nutrition/Events.cs b/Content.Shared/Nutrition/Events.cs index e27603763f..f2936d603d 100644 --- a/Content.Shared/Nutrition/Events.cs +++ b/Content.Shared/Nutrition/Events.cs @@ -53,3 +53,9 @@ public VapeDoAfterEvent(Solution solution, bool forced) public override DoAfterEvent Clone() => this; } + +/// +/// Raised before food is sliced +/// +[ByRefEvent] +public record struct SliceFoodEvent(); diff --git a/Content.Shared/OfferItem/SharedOfferItemSystem.cs b/Content.Shared/OfferItem/SharedOfferItemSystem.cs index c9d7dc5abc..ffea2a67c0 100644 --- a/Content.Shared/OfferItem/SharedOfferItemSystem.cs +++ b/Content.Shared/OfferItem/SharedOfferItemSystem.cs @@ -10,18 +10,18 @@ public abstract partial class SharedOfferItemSystem : EntitySystem public override void Initialize() { - SubscribeLocalEvent(SetInReceiveMode); + SubscribeLocalEvent(SetInReceiveMode); SubscribeLocalEvent(OnMove); InitializeInteractions(); } - private void SetInReceiveMode(EntityUid uid, OfferItemComponent component, AfterInteractUsingEvent args) + private void SetInReceiveMode(EntityUid uid, OfferItemComponent component, InteractUsingEvent args) { if (!TryComp(args.User, out var offerItem)) return; - if (args.User == uid || component.IsInReceiveMode || + if (args.User == uid || component.IsInReceiveMode || !offerItem.IsInOfferMode || (offerItem.IsInReceiveMode && offerItem.Target != uid)) return; @@ -44,6 +44,8 @@ private void SetInReceiveMode(EntityUid uid, OfferItemComponent component, After _popup.PopupEntity(Loc.GetString("offer-item-try-give-target", ("user", Identity.Entity(component.Target.Value, EntityManager)), ("item", Identity.Entity(offerItem.Item.Value, EntityManager))), component.Target.Value, uid); + + args.Handled = true; } private void OnMove(EntityUid uid, OfferItemComponent component, MoveEvent args) diff --git a/Content.Shared/Physics/Controllers/SharedConveyorController.cs b/Content.Shared/Physics/Controllers/SharedConveyorController.cs index ec17df7a24..c9ec77ba1c 100644 --- a/Content.Shared/Physics/Controllers/SharedConveyorController.cs +++ b/Content.Shared/Physics/Controllers/SharedConveyorController.cs @@ -3,6 +3,7 @@ using Content.Shared.Gravity; using Content.Shared.Movement.Systems; using Robust.Shared.Map; +using Robust.Shared.Map.Components; using Robust.Shared.Physics; using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Controllers; @@ -146,7 +147,7 @@ private static Vector2 Convey(Vector2 direction, float speed, float frameTime, V EntityQuery bodyQuery) { // Check if the thing's centre overlaps the grid tile. - var grid = MapManager.GetGrid(xform.GridUid!.Value); + var grid = Comp(xform.GridUid!.Value); var tile = grid.GetTileRef(xform.Coordinates); var conveyorBounds = Lookup.GetLocalBounds(tile, grid.TileSize); diff --git a/Content.Shared/Players/ContentPlayerData.cs b/Content.Shared/Players/ContentPlayerData.cs index e207447987..cc7a7e9780 100644 --- a/Content.Shared/Players/ContentPlayerData.cs +++ b/Content.Shared/Players/ContentPlayerData.cs @@ -1,4 +1,5 @@ -using Content.Shared.GameTicking; +using Content.Shared.Administration; +using Content.Shared.GameTicking; using Content.Shared.Mind; using Robust.Shared.Network; @@ -38,7 +39,12 @@ public sealed class ContentPlayerData public bool ExplicitlyDeadminned { get; set; } /// - /// Nyanotrasen - Are they whitelisted? Lets us avoid async. + /// If true, the admin will not show up in adminwho except to admins with the flag. + /// + public bool Stealthed { get; set; } + + /// + /// Nyanotrasen - Are they whitelisted? Lets us avoid async. /// [ViewVariables] public bool Whitelisted { get; set; } diff --git a/Content.Shared/Pulling/Components/PullableComponent.cs b/Content.Shared/Pulling/Components/PullableComponent.cs deleted file mode 100644 index c5c3068869..0000000000 --- a/Content.Shared/Pulling/Components/PullableComponent.cs +++ /dev/null @@ -1,57 +0,0 @@ -using Robust.Shared.GameStates; -using Robust.Shared.Map; -using Robust.Shared.Serialization; - -namespace Content.Shared.Pulling.Components -{ - // Before you try to add another type than SharedPullingStateManagementSystem, consider the can of worms you may be opening! - [NetworkedComponent, AutoGenerateComponentState] - [Access(typeof(SharedPullingStateManagementSystem))] - [RegisterComponent] - public sealed partial class SharedPullableComponent : Component - { - /// - /// The current entity pulling this component. - /// - [DataField, AutoNetworkedField] - public EntityUid? Puller { get; set; } - - /// - /// The pull joint. - /// - [DataField, AutoNetworkedField] - public string? PullJointId { get; set; } - - public bool BeingPulled => Puller != null; - - [Access(typeof(SharedPullingStateManagementSystem), Other = AccessPermissions.ReadExecute)] // FIXME Friends - public EntityCoordinates? MovingTo { get; set; } - - /// - /// If the physics component has FixedRotation should we keep it upon being pulled - /// - [Access(typeof(SharedPullingSystem), Other = AccessPermissions.ReadExecute)] - [ViewVariables(VVAccess.ReadWrite), DataField("fixedRotation")] - public bool FixedRotationOnPull { get; set; } - - /// - /// What the pullable's fixedrotation was set to before being pulled. - /// - [Access(typeof(SharedPullingSystem), Other = AccessPermissions.ReadExecute)] - [ViewVariables] - public bool PrevFixedRotation; - } - - /// - /// Raised when a request is made to stop pulling an entity. - /// - public sealed class StopPullingEvent : CancellableEntityEventArgs - { - public EntityUid? User { get; } - - public StopPullingEvent(EntityUid? uid = null) - { - User = uid; - } - } -} diff --git a/Content.Shared/Pulling/Components/SharedPullerComponent.cs b/Content.Shared/Pulling/Components/SharedPullerComponent.cs deleted file mode 100644 index 57a86e7f7a..0000000000 --- a/Content.Shared/Pulling/Components/SharedPullerComponent.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Robust.Shared.GameStates; - -namespace Content.Shared.Pulling.Components -{ - [RegisterComponent, NetworkedComponent, AutoGenerateComponentState] - [Access(typeof(SharedPullingStateManagementSystem))] - public sealed partial class SharedPullerComponent : Component - { - // Before changing how this is updated, please see SharedPullerSystem.RefreshMovementSpeed - public float WalkSpeedModifier => Pulling == default ? 1.0f : 0.95f; - - public float SprintSpeedModifier => Pulling == default ? 1.0f : 0.95f; - - [DataField, AutoNetworkedField] - public EntityUid? Pulling { get; set; } - - /// - /// Does this entity need hands to be able to pull something? - /// - [DataField("needsHands")] - public bool NeedsHands = true; - } -} diff --git a/Content.Shared/Pulling/Events/PullAttemptEvent.cs b/Content.Shared/Pulling/Events/PullAttemptEvent.cs deleted file mode 100644 index 6296dc2f14..0000000000 --- a/Content.Shared/Pulling/Events/PullAttemptEvent.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Robust.Shared.Physics.Components; - -namespace Content.Shared.Physics.Pull -{ - public sealed class PullAttemptEvent : PullMessage - { - public PullAttemptEvent(PhysicsComponent puller, PhysicsComponent pulled) : base(puller, pulled) { } - - public bool Cancelled { get; set; } - } -} diff --git a/Content.Shared/Pulling/Events/PullMessage.cs b/Content.Shared/Pulling/Events/PullMessage.cs deleted file mode 100644 index b11de7c170..0000000000 --- a/Content.Shared/Pulling/Events/PullMessage.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Robust.Shared.Physics.Components; - -namespace Content.Shared.Physics.Pull -{ - public abstract class PullMessage : EntityEventArgs - { - public readonly PhysicsComponent Puller; - public readonly PhysicsComponent Pulled; - - protected PullMessage(PhysicsComponent puller, PhysicsComponent pulled) - { - Puller = puller; - Pulled = pulled; - } - } -} diff --git a/Content.Shared/Pulling/Events/PullStartedMessage.cs b/Content.Shared/Pulling/Events/PullStartedMessage.cs deleted file mode 100644 index 0ede284bb0..0000000000 --- a/Content.Shared/Pulling/Events/PullStartedMessage.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Robust.Shared.Physics.Components; - -namespace Content.Shared.Physics.Pull -{ - public sealed class PullStartedMessage : PullMessage - { - public PullStartedMessage(PhysicsComponent puller, PhysicsComponent pulled) : - base(puller, pulled) - { - } - } -} diff --git a/Content.Shared/Pulling/Events/PullStoppedMessage.cs b/Content.Shared/Pulling/Events/PullStoppedMessage.cs deleted file mode 100644 index afcbcb7074..0000000000 --- a/Content.Shared/Pulling/Events/PullStoppedMessage.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Robust.Shared.Physics.Components; - -namespace Content.Shared.Physics.Pull -{ - public sealed class PullStoppedMessage : PullMessage - { - public PullStoppedMessage(PhysicsComponent puller, PhysicsComponent pulled) : base(puller, pulled) - { - } - } -} diff --git a/Content.Shared/Pulling/PullableMoveMessage.cs b/Content.Shared/Pulling/PullableMoveMessage.cs deleted file mode 100644 index 46c6b1291d..0000000000 --- a/Content.Shared/Pulling/PullableMoveMessage.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Content.Shared.Pulling -{ - public sealed class PullableMoveMessage : EntityEventArgs - { - } -} diff --git a/Content.Shared/Pulling/PullableStopMovingMessage.cs b/Content.Shared/Pulling/PullableStopMovingMessage.cs deleted file mode 100644 index 0233e32f2b..0000000000 --- a/Content.Shared/Pulling/PullableStopMovingMessage.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Content.Shared.Pulling -{ - public sealed class PullableStopMovingMessage : EntityEventArgs - { - } -} diff --git a/Content.Shared/Pulling/Systems/SharedPullableSystem.cs b/Content.Shared/Pulling/Systems/SharedPullableSystem.cs deleted file mode 100644 index 3dab476337..0000000000 --- a/Content.Shared/Pulling/Systems/SharedPullableSystem.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Content.Shared.ActionBlocker; -using Content.Shared.Mobs.Systems; -using Content.Shared.Pulling.Components; -using Content.Shared.Movement.Events; - -namespace Content.Shared.Pulling.Systems -{ - public sealed class SharedPullableSystem : EntitySystem - { - [Dependency] private readonly ActionBlockerSystem _blocker = default!; - [Dependency] private readonly MobStateSystem _mobState = default!; - [Dependency] private readonly SharedPullingSystem _pullSystem = default!; - - public override void Initialize() - { - base.Initialize(); - SubscribeLocalEvent(OnRelayMoveInput); - } - - private void OnRelayMoveInput(EntityUid uid, SharedPullableComponent component, ref MoveInputEvent args) - { - var entity = args.Entity; - if (_mobState.IsIncapacitated(entity) || !_blocker.CanMove(entity)) return; - - _pullSystem.TryStopPull(component); - } - } -} diff --git a/Content.Shared/Pulling/Systems/SharedPullerSystem.cs b/Content.Shared/Pulling/Systems/SharedPullerSystem.cs deleted file mode 100644 index e388d7a57c..0000000000 --- a/Content.Shared/Pulling/Systems/SharedPullerSystem.cs +++ /dev/null @@ -1,90 +0,0 @@ -using Content.Shared.Administration.Logs; -using Content.Shared.Alert; -using Content.Shared.Database; -using Content.Shared.Hands; -using Content.Shared.Movement.Systems; -using Content.Shared.Physics.Pull; -using Content.Shared.Pulling.Components; -using JetBrains.Annotations; - -namespace Content.Shared.Pulling.Systems -{ - [UsedImplicitly] - public sealed class SharedPullerSystem : EntitySystem - { - [Dependency] private readonly SharedPullingStateManagementSystem _why = default!; - [Dependency] private readonly SharedPullingSystem _pullSystem = default!; - [Dependency] private readonly MovementSpeedModifierSystem _movementSpeedModifierSystem = default!; - [Dependency] private readonly AlertsSystem _alertsSystem = default!; - [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!; - - public override void Initialize() - { - base.Initialize(); - - SubscribeLocalEvent(PullerHandlePullStarted); - SubscribeLocalEvent(PullerHandlePullStopped); - SubscribeLocalEvent(OnVirtualItemDeleted); - SubscribeLocalEvent(OnRefreshMovespeed); - SubscribeLocalEvent(OnPullerShutdown); - } - - private void OnPullerShutdown(EntityUid uid, SharedPullerComponent component, ComponentShutdown args) - { - _why.ForceDisconnectPuller(component); - } - - private void OnVirtualItemDeleted(EntityUid uid, SharedPullerComponent component, VirtualItemDeletedEvent args) - { - if (component.Pulling == null) - return; - - if (component.Pulling == args.BlockingEntity) - { - if (EntityManager.TryGetComponent(args.BlockingEntity, out var comp)) - { - _pullSystem.TryStopPull(comp, uid); - } - } - } - - private void PullerHandlePullStarted( - EntityUid uid, - SharedPullerComponent component, - PullStartedMessage args) - { - if (args.Puller.Owner != uid) - return; - - _alertsSystem.ShowAlert(component.Owner, AlertType.Pulling); - - RefreshMovementSpeed(component); - } - - private void PullerHandlePullStopped( - EntityUid uid, - SharedPullerComponent component, - PullStoppedMessage args) - { - if (args.Puller.Owner != uid) - return; - - var euid = component.Owner; - if (_alertsSystem.IsShowingAlert(euid, AlertType.Pulling)) - _adminLogger.Add(LogType.Action, LogImpact.Low, $"{ToPrettyString(euid):user} stopped pulling {ToPrettyString(args.Pulled.Owner):target}"); - _alertsSystem.ClearAlert(euid, AlertType.Pulling); - - RefreshMovementSpeed(component); - } - - private void OnRefreshMovespeed(EntityUid uid, SharedPullerComponent component, RefreshMovementSpeedModifiersEvent args) - { - args.ModifySpeed(component.WalkSpeedModifier, component.SprintSpeedModifier); - } - - private void RefreshMovementSpeed(SharedPullerComponent component) - { - _movementSpeedModifierSystem.RefreshMovementSpeedModifiers(component.Owner); - } - } -} diff --git a/Content.Shared/Pulling/Systems/SharedPullingStateManagementSystem.cs b/Content.Shared/Pulling/Systems/SharedPullingStateManagementSystem.cs deleted file mode 100644 index 38ed899889..0000000000 --- a/Content.Shared/Pulling/Systems/SharedPullingStateManagementSystem.cs +++ /dev/null @@ -1,196 +0,0 @@ -using Content.Shared.Physics.Pull; -using Content.Shared.Pulling.Components; -using JetBrains.Annotations; -using Robust.Shared.Map; -using Robust.Shared.Physics; -using Robust.Shared.Physics.Components; -using Robust.Shared.Physics.Systems; -using Robust.Shared.Timing; - -namespace Content.Shared.Pulling -{ - /// - /// This is the core of pulling state management. - /// Because pulling state is such a mess to get right, all writes to pulling state must go through this class. - /// - [UsedImplicitly] - public sealed class SharedPullingStateManagementSystem : EntitySystem - { - [Dependency] private readonly SharedJointSystem _jointSystem = default!; - [Dependency] private readonly SharedPhysicsSystem _physics = default!; - [Dependency] private readonly IGameTiming _timing = default!; - - public override void Initialize() - { - base.Initialize(); - - SubscribeLocalEvent(OnShutdown); - } - - private void OnShutdown(EntityUid uid, SharedPullableComponent component, ComponentShutdown args) - { - if (component.Puller != null) - ForceRelationship(null, component); - } - - // A WARNING: - // The following 2 functions are the most internal part of the pulling system's relationship management. - // They do not expect to be cancellable. - private void ForceDisconnect(SharedPullerComponent puller, SharedPullableComponent pullable) - { - var pullerPhysics = EntityManager.GetComponent(puller.Owner); - var pullablePhysics = EntityManager.GetComponent(pullable.Owner); - - // MovingTo shutdown - ForceSetMovingTo(pullable, null); - - // Joint shutdown - if (!_timing.ApplyingState && // During state-handling, joint component will handle its own state. - pullable.PullJointId != null && - TryComp(puller.Owner, out JointComponent? jointComp)) - { - if (jointComp.GetJoints.TryGetValue(pullable.PullJointId, out var j)) - _jointSystem.RemoveJoint(j); - } - pullable.PullJointId = null; - - // State shutdown - puller.Pulling = null; - pullable.Puller = null; - - // Messaging - var message = new PullStoppedMessage(pullerPhysics, pullablePhysics); - - RaiseLocalEvent(puller.Owner, message, broadcast: false); - - if (Initialized(pullable.Owner)) - RaiseLocalEvent(pullable.Owner, message, true); - - // Networking - Dirty(puller); - Dirty(pullable); - } - - public void ForceRelationship(SharedPullerComponent? puller, SharedPullableComponent? pullable) - { - if (_timing.ApplyingState) - return; - ; - if (pullable != null && puller != null && (puller.Pulling == pullable.Owner)) - { - // Already done - return; - } - - // Start by disconnecting the pullable from whatever it is currently connected to. - var pullableOldPullerE = pullable?.Puller; - if (pullableOldPullerE != null) - { - ForceDisconnect(EntityManager.GetComponent(pullableOldPullerE.Value), pullable!); - } - - // Continue with the puller. - var pullerOldPullableE = puller?.Pulling; - if (pullerOldPullableE != null) - { - ForceDisconnect(puller!, EntityManager.GetComponent(pullerOldPullableE.Value)); - } - - // And now for the actual connection (if any). - - if (puller != null && pullable != null) - { - var pullerPhysics = EntityManager.GetComponent(puller.Owner); - var pullablePhysics = EntityManager.GetComponent(pullable.Owner); - pullable.PullJointId = $"pull-joint-{pullable.Owner}"; - - // State startup - puller.Pulling = pullable.Owner; - pullable.Puller = puller.Owner; - - // joint state handling will manage its own state - if (!_timing.ApplyingState) - { - // Joint startup - var union = _physics.GetHardAABB(puller.Owner).Union(_physics.GetHardAABB(pullable.Owner, body: pullablePhysics)); - var length = Math.Max(union.Size.X, union.Size.Y) * 0.75f; - - var joint = _jointSystem.CreateDistanceJoint(pullablePhysics.Owner, pullerPhysics.Owner, id: pullable.PullJointId); - joint.CollideConnected = false; - // This maximum has to be there because if the object is constrained too closely, the clamping goes backwards and asserts. - joint.MaxLength = Math.Max(1.0f, length); - joint.Length = length * 0.75f; - joint.MinLength = 0f; - joint.Stiffness = 1f; - } - - // Messaging - var message = new PullStartedMessage(pullerPhysics, pullablePhysics); - - RaiseLocalEvent(puller.Owner, message, broadcast: false); - RaiseLocalEvent(pullable.Owner, message, true); - - // Networking - Dirty(puller); - Dirty(pullable); - } - } - - // For OnRemove use only. - public void ForceDisconnectPuller(SharedPullerComponent puller) - { - // DO NOT ADD ADDITIONAL LOGIC IN THIS FUNCTION. Do it in ForceRelationship. - ForceRelationship(puller, null); - } - - // For OnRemove use only. - public void ForceDisconnectPullable(SharedPullableComponent pullable) - { - // DO NOT ADD ADDITIONAL LOGIC IN THIS FUNCTION. Do it in ForceRelationship. - ForceRelationship(null, pullable); - } - - public void ForceSetMovingTo(SharedPullableComponent pullable, EntityCoordinates? movingTo) - { - if (_timing.ApplyingState) - return; - - if (pullable.MovingTo == movingTo) - { - return; - } - - // Don't allow setting a MovingTo if there's no puller. - // The other half of this guarantee (shutting down a MovingTo if the puller goes away) is enforced in ForceRelationship. - if (pullable.Puller == null && movingTo != null) - { - return; - } - - pullable.MovingTo = movingTo; - Dirty(pullable); - - if (movingTo == null) - { - RaiseLocalEvent(pullable.Owner, new PullableStopMovingMessage(), true); - } - else - { - RaiseLocalEvent(pullable.Owner, new PullableMoveMessage(), true); - } - } - - /// - /// Changes if the entity needs a hand in order to be able to pull objects. - /// - public void ChangeHandRequirement(EntityUid uid, bool needsHands, SharedPullerComponent? comp) - { - if (!Resolve(uid, ref comp, false)) - return; - - comp.NeedsHands = needsHands; - - Dirty(uid, comp); - } - } -} diff --git a/Content.Shared/Pulling/Systems/SharedPullingSystem.Actions.cs b/Content.Shared/Pulling/Systems/SharedPullingSystem.Actions.cs deleted file mode 100644 index 1e2bb90c61..0000000000 --- a/Content.Shared/Pulling/Systems/SharedPullingSystem.Actions.cs +++ /dev/null @@ -1,239 +0,0 @@ -using Content.Shared.ActionBlocker; -using Content.Shared.Administration.Logs; -using Content.Shared.Buckle.Components; -using Content.Shared.Database; -using Content.Shared.Hands.EntitySystems; -using Content.Shared.Interaction; -using Content.Shared.Physics.Pull; -using Content.Shared.Pulling.Components; -using Content.Shared.Pulling.Events; -using Robust.Shared.Containers; -using Robust.Shared.Map; -using Robust.Shared.Physics; -using Robust.Shared.Physics.Components; -using Robust.Shared.Physics.Systems; -using Robust.Shared.Timing; -using Robust.Shared.Utility; - -namespace Content.Shared.Pulling -{ - public abstract partial class SharedPullingSystem - { - [Dependency] private readonly ActionBlockerSystem _blocker = default!; - [Dependency] private readonly SharedContainerSystem _containerSystem = default!; - [Dependency] private readonly SharedHandsSystem _handsSystem = default!; - [Dependency] private readonly SharedInteractionSystem _interaction = default!; - [Dependency] private readonly SharedPhysicsSystem _physics = default!; - [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!; - [Dependency] private readonly IGameTiming _timing = default!; - - public bool CanPull(EntityUid puller, EntityUid pulled) - { - if (!EntityManager.TryGetComponent(puller, out var comp)) - { - return false; - } - - if (comp.NeedsHands && !_handsSystem.TryGetEmptyHand(puller, out _)) - { - return false; - } - - if (!_blocker.CanInteract(puller, pulled)) - { - return false; - } - - if (!EntityManager.TryGetComponent(pulled, out var physics)) - { - return false; - } - - if (physics.BodyType == BodyType.Static) - { - return false; - } - - if (puller == pulled) - { - return false; - } - - if(_containerSystem.IsEntityInContainer(puller) || _containerSystem.IsEntityInContainer(pulled)) - { - return false; - } - - if (EntityManager.TryGetComponent(puller, out BuckleComponent? buckle)) - { - // Prevent people pulling the chair they're on, etc. - if (buckle is { PullStrap: false, Buckled: true } && (buckle.LastEntityBuckledTo == pulled)) - { - return false; - } - } - - var getPulled = new BeingPulledAttemptEvent(puller, pulled); - RaiseLocalEvent(pulled, getPulled, true); - var startPull = new StartPullAttemptEvent(puller, pulled); - RaiseLocalEvent(puller, startPull, true); - return (!startPull.Cancelled && !getPulled.Cancelled); - } - - public bool TogglePull(EntityUid puller, SharedPullableComponent pullable) - { - if (pullable.Puller == puller) - { - return TryStopPull(pullable); - } - return TryStartPull(puller, pullable.Owner); - } - - // -- Core attempted actions -- - - public bool TryStopPull(SharedPullableComponent pullable, EntityUid? user = null) - { - if (_timing.ApplyingState) - return false; - - if (!pullable.BeingPulled) - { - return false; - } - - var msg = new StopPullingEvent(user); - RaiseLocalEvent(pullable.Owner, msg, true); - - if (msg.Cancelled) return false; - - // Stop pulling confirmed! - - if (TryComp(pullable.Owner, out var pullablePhysics)) - { - _physics.SetFixedRotation(pullable.Owner, pullable.PrevFixedRotation, body: pullablePhysics); - } - - _pullSm.ForceRelationship(null, pullable); - return true; - } - - public bool TryStartPull(EntityUid puller, EntityUid pullable) - { - if (!EntityManager.TryGetComponent(puller, out SharedPullerComponent? pullerComp)) - { - return false; - } - if (!EntityManager.TryGetComponent(pullable, out SharedPullableComponent? pullableComp)) - { - return false; - } - return TryStartPull(pullerComp, pullableComp); - } - - // The main "start pulling" function. - public bool TryStartPull(SharedPullerComponent puller, SharedPullableComponent pullable) - { - if (_timing.ApplyingState) - return false; - - if (puller.Pulling == pullable.Owner) - return true; - - // Pulling a new object : Perform sanity checks. - - if (!CanPull(puller.Owner, pullable.Owner)) - { - return false; - } - - if (!EntityManager.TryGetComponent(puller.Owner, out var pullerPhysics)) - { - return false; - } - - if (!EntityManager.TryGetComponent(pullable.Owner, out var pullablePhysics)) - { - return false; - } - - // Ensure that the puller is not currently pulling anything. - // If this isn't done, then it happens too late, and the start/stop messages go out of order, - // and next thing you know it thinks it's not pulling anything even though it is! - - var oldPullable = puller.Pulling; - if (oldPullable != null) - { - if (EntityManager.TryGetComponent(oldPullable.Value, out SharedPullableComponent? oldPullableComp)) - { - if (!TryStopPull(oldPullableComp)) - { - return false; - } - } - else - { - Log.Warning("Well now you've done it, haven't you? Someone transferred pulling (onto {0}) while presently pulling something that has no Pullable component (on {1})!", pullable.Owner, oldPullable); - return false; - } - } - - // Ensure that the pullable is not currently being pulled. - // Same sort of reasons as before. - - var oldPuller = pullable.Puller; - if (oldPuller != null) - { - if (!TryStopPull(pullable)) - { - return false; - } - } - - // Continue with pulling process. - - var pullAttempt = new PullAttemptEvent(pullerPhysics, pullablePhysics); - - RaiseLocalEvent(puller.Owner, pullAttempt, broadcast: false); - - if (pullAttempt.Cancelled) - { - return false; - } - - RaiseLocalEvent(pullable.Owner, pullAttempt, true); - - if (pullAttempt.Cancelled) - return false; - - _interaction.DoContactInteraction(pullable.Owner, puller.Owner); - - _pullSm.ForceRelationship(puller, pullable); - pullable.PrevFixedRotation = pullablePhysics.FixedRotation; - _physics.SetFixedRotation(pullable.Owner, pullable.FixedRotationOnPull, body: pullablePhysics); - _adminLogger.Add(LogType.Action, LogImpact.Low, - $"{ToPrettyString(puller.Owner):user} started pulling {ToPrettyString(pullable.Owner):target}"); - return true; - } - - public bool TryMoveTo(SharedPullableComponent pullable, EntityCoordinates to) - { - if (pullable.Puller == null) - { - return false; - } - - if (!EntityManager.HasComponent(pullable.Owner)) - { - return false; - } - - _pullSm.ForceSetMovingTo(pullable, to); - return true; - } - - public void StopMoveTo(SharedPullableComponent pullable) - { - _pullSm.ForceSetMovingTo(pullable, null); - } - } -} diff --git a/Content.Shared/Pulling/Systems/SharedPullingSystem.cs b/Content.Shared/Pulling/Systems/SharedPullingSystem.cs deleted file mode 100644 index 0c139ee9e3..0000000000 --- a/Content.Shared/Pulling/Systems/SharedPullingSystem.cs +++ /dev/null @@ -1,243 +0,0 @@ -using System.Diagnostics.CodeAnalysis; -using Content.Shared.Alert; -using Content.Shared.GameTicking; -using Content.Shared.Input; -using Content.Shared.Physics.Pull; -using Content.Shared.Pulling.Components; -using Content.Shared.Verbs; -using JetBrains.Annotations; -using Robust.Shared.Containers; -using Robust.Shared.Input.Binding; -using Robust.Shared.Map; -using Robust.Shared.Physics; -using Robust.Shared.Physics.Events; -using Robust.Shared.Physics.Systems; -using Robust.Shared.Player; - -namespace Content.Shared.Pulling -{ - [UsedImplicitly] - public abstract partial class SharedPullingSystem : EntitySystem - { - [Dependency] private readonly SharedPullingStateManagementSystem _pullSm = default!; - [Dependency] private readonly AlertsSystem _alertsSystem = default!; - [Dependency] private readonly SharedJointSystem _joints = default!; - - /// - /// A mapping of pullers to the entity that they are pulling. - /// - private readonly Dictionary _pullers = - new(); - - private readonly HashSet _moving = new(); - private readonly HashSet _stoppedMoving = new(); - - public IReadOnlySet Moving => _moving; - - public override void Initialize() - { - base.Initialize(); - - UpdatesOutsidePrediction = true; - - SubscribeLocalEvent(Reset); - SubscribeLocalEvent(OnPullStarted); - SubscribeLocalEvent(OnPullStopped); - SubscribeLocalEvent(HandleContainerInsert); - SubscribeLocalEvent(OnJointRemoved); - SubscribeLocalEvent(OnPullableCollisionChange); - - SubscribeLocalEvent(PullableHandlePullStarted); - SubscribeLocalEvent(PullableHandlePullStopped); - - SubscribeLocalEvent>(AddPullVerbs); - - CommandBinds.Builder - .Bind(ContentKeyFunctions.MovePulledObject, new PointerInputCmdHandler(HandleMovePulledObject)) - .Register(); - } - - private void OnPullableCollisionChange(EntityUid uid, SharedPullableComponent component, ref CollisionChangeEvent args) - { - if (component.PullJointId != null && !args.CanCollide) - { - _joints.RemoveJoint(uid, component.PullJointId); - } - } - - private void OnJointRemoved(EntityUid uid, SharedPullableComponent component, JointRemovedEvent args) - { - if (component.Puller != args.OtherEntity) - return; - - // Do we have some other join with our Puller? - // or alternatively: - // TODO track the relevant joint. - - if (TryComp(uid, out JointComponent? joints)) - { - foreach (var jt in joints.GetJoints.Values) - { - if (jt.BodyAUid == component.Puller || jt.BodyBUid == component.Puller) - return; - } - } - - // No more joints with puller -> force stop pull. - _pullSm.ForceDisconnectPullable(component); - } - - private void AddPullVerbs(EntityUid uid, SharedPullableComponent component, GetVerbsEvent args) - { - if (!args.CanAccess || !args.CanInteract) - return; - - // Are they trying to pull themselves up by their bootstraps? - if (args.User == args.Target) - return; - - //TODO VERB ICONS add pulling icon - if (component.Puller == args.User) - { - Verb verb = new() - { - Text = Loc.GetString("pulling-verb-get-data-text-stop-pulling"), - Act = () => TryStopPull(component, args.User), - DoContactInteraction = false // pulling handle its own contact interaction. - }; - args.Verbs.Add(verb); - } - else if (CanPull(args.User, args.Target)) - { - Verb verb = new() - { - Text = Loc.GetString("pulling-verb-get-data-text"), - Act = () => TryStartPull(args.User, args.Target), - DoContactInteraction = false // pulling handle its own contact interaction. - }; - args.Verbs.Add(verb); - } - } - - // Raise a "you are being pulled" alert if the pulled entity has alerts. - private void PullableHandlePullStarted(EntityUid uid, SharedPullableComponent component, PullStartedMessage args) - { - if (args.Pulled.Owner != uid) - return; - - _alertsSystem.ShowAlert(uid, AlertType.Pulled); - } - - private void PullableHandlePullStopped(EntityUid uid, SharedPullableComponent component, PullStoppedMessage args) - { - if (args.Pulled.Owner != uid) - return; - - _alertsSystem.ClearAlert(uid, AlertType.Pulled); - } - - public bool IsPulled(EntityUid uid, SharedPullableComponent? component = null) - { - return Resolve(uid, ref component, false) && component.BeingPulled; - } - - public override void Update(float frameTime) - { - base.Update(frameTime); - - _moving.ExceptWith(_stoppedMoving); - _stoppedMoving.Clear(); - } - - public void Reset(RoundRestartCleanupEvent ev) - { - _pullers.Clear(); - _moving.Clear(); - _stoppedMoving.Clear(); - } - - private void OnPullStarted(PullStartedMessage message) - { - SetPuller(message.Puller.Owner, message.Pulled.Owner); - } - - private void OnPullStopped(PullStoppedMessage message) - { - RemovePuller(message.Puller.Owner); - } - - protected void OnPullableMove(EntityUid uid, SharedPullableComponent component, PullableMoveMessage args) - { - _moving.Add(component); - } - - protected void OnPullableStopMove(EntityUid uid, SharedPullableComponent component, PullableStopMovingMessage args) - { - _stoppedMoving.Add(component); - } - - // TODO: When Joint networking is less shitcodey fix this to use a dedicated joints message. - private void HandleContainerInsert(EntInsertedIntoContainerMessage message) - { - if (TryComp(message.Entity, out SharedPullableComponent? pullable)) - { - TryStopPull(pullable); - } - - if (TryComp(message.Entity, out SharedPullerComponent? puller)) - { - if (puller.Pulling == null) return; - - if (!TryComp(puller.Pulling.Value, out SharedPullableComponent? pulling)) - return; - - TryStopPull(pulling); - } - } - - private bool HandleMovePulledObject(ICommonSession? session, EntityCoordinates coords, EntityUid uid) - { - if (session?.AttachedEntity is not { } player || - !player.IsValid()) - return false; - - if (!TryGetPulled(player, out var pulled)) - return false; - - if (!TryComp(pulled.Value, out SharedPullableComponent? pullable)) - return false; - - if (_containerSystem.IsEntityInContainer(player)) - return false; - - TryMoveTo(pullable, coords); - - return false; - } - - private void SetPuller(EntityUid puller, EntityUid pulled) - { - _pullers[puller] = pulled; - } - - private bool RemovePuller(EntityUid puller) - { - return _pullers.Remove(puller); - } - - public EntityUid GetPulled(EntityUid by) - { - return _pullers.GetValueOrDefault(by); - } - - public bool TryGetPulled(EntityUid by, [NotNullWhen(true)] out EntityUid? pulled) - { - return (pulled = GetPulled(by)) != null; - } - - public bool IsPulling(EntityUid puller) - { - return _pullers.ContainsKey(puller); - } - } -} diff --git a/Content.Shared/RCD/Systems/RCDSystem.cs b/Content.Shared/RCD/Systems/RCDSystem.cs index 187c8d8a9d..9e78451207 100644 --- a/Content.Shared/RCD/Systems/RCDSystem.cs +++ b/Content.Shared/RCD/Systems/RCDSystem.cs @@ -25,7 +25,6 @@ namespace Content.Shared.RCD.Systems; public sealed class RCDSystem : EntitySystem { [Dependency] private readonly IGameTiming _timing = default!; - [Dependency] private readonly IMapManager _mapMan = default!; [Dependency] private readonly INetManager _net = default!; [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!; [Dependency] private readonly ITileDefinitionManager _tileDefMan = default!; @@ -39,7 +38,7 @@ public sealed class RCDSystem : EntitySystem [Dependency] private readonly TurfSystem _turf = default!; [Dependency] private readonly IGameTiming _gameTiming = default!; - private readonly int RcdModeCount = Enum.GetValues(typeof(RcdMode)).Length; + private readonly int _rcdModeCount = Enum.GetValues(typeof(RcdMode)).Length; public override void Initialize() { @@ -133,7 +132,7 @@ private void OnDoAfterAttempt(EntityUid uid, RCDComponent comp, DoAfterAttemptEv return; } - var mapGrid = _mapMan.GetGrid(gridId.Value); + var mapGrid = Comp(gridId.Value); var tile = mapGrid.GetTileRef(location); if (!IsRCDStillValid(uid, comp, args.Event.User, args.Event.Target, mapGrid, tile, args.Event.StartingMode)) @@ -158,7 +157,7 @@ private void OnDoAfter(EntityUid uid, RCDComponent comp, RCDDoAfterEvent args) return; } - var mapGrid = _mapMan.GetGrid(gridId.Value); + var mapGrid = Comp(gridId.Value); var tile = mapGrid.GetTileRef(location); var snapPos = mapGrid.TileIndicesFor(location); @@ -311,7 +310,7 @@ private void NextMode(EntityUid uid, RCDComponent comp, EntityUid user) _audio.PlayPredicted(comp.SwapModeSound, uid, user); var mode = (int) comp.Mode; - mode = ++mode % RcdModeCount; + mode = ++mode % _rcdModeCount; comp.Mode = (RcdMode) mode; Dirty(comp); diff --git a/Content.Shared/Remotes/Components/DoorRemoteComponent.cs b/Content.Shared/Remotes/Components/DoorRemoteComponent.cs new file mode 100644 index 0000000000..b157596e3b --- /dev/null +++ b/Content.Shared/Remotes/Components/DoorRemoteComponent.cs @@ -0,0 +1,19 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Remotes.Components; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class DoorRemoteComponent : Component +{ + [AutoNetworkedField] + [DataField] + public OperatingMode Mode = OperatingMode.OpenClose; +} + +public enum OperatingMode : byte +{ + OpenClose, + ToggleBolts, + ToggleEmergencyAccess, + placeholderForUiUpdates +} diff --git a/Content.Shared/Remotes/EntitySystems/SharedDoorRemoteSystem.cs b/Content.Shared/Remotes/EntitySystems/SharedDoorRemoteSystem.cs new file mode 100644 index 0000000000..e9bbd27ada --- /dev/null +++ b/Content.Shared/Remotes/EntitySystems/SharedDoorRemoteSystem.cs @@ -0,0 +1,44 @@ +using Content.Shared.Popups; +using Content.Shared.Interaction.Events; +using Content.Shared.Remotes.Components; + +namespace Content.Shared.Remotes.EntitySystems; + +public abstract class SharedDoorRemoteSystem : EntitySystem +{ + [Dependency] protected readonly SharedPopupSystem Popup = default!; + + public override void Initialize() + { + SubscribeLocalEvent(OnInHandActivation); + } + + private void OnInHandActivation(Entity entity, ref UseInHandEvent args) + { + string switchMessageId; + switch (entity.Comp.Mode) + { + case OperatingMode.OpenClose: + entity.Comp.Mode = OperatingMode.ToggleBolts; + switchMessageId = "door-remote-switch-state-toggle-bolts"; + break; + + // Skip toggle bolts mode and move on from there (to emergency access) + case OperatingMode.ToggleBolts: + entity.Comp.Mode = OperatingMode.ToggleEmergencyAccess; + switchMessageId = "door-remote-switch-state-toggle-emergency-access"; + break; + + // Skip ToggleEmergencyAccess mode and move on from there (to door toggle) + case OperatingMode.ToggleEmergencyAccess: + entity.Comp.Mode = OperatingMode.OpenClose; + switchMessageId = "door-remote-switch-state-open-close"; + break; + default: + throw new InvalidOperationException( + $"{nameof(DoorRemoteComponent)} had invalid mode {entity.Comp.Mode}"); + } + Dirty(entity); + Popup.PopupClient(Loc.GetString(switchMessageId), entity, args.User); + } +} diff --git a/Content.Shared/Research/Components/ResearchStealerComponent.cs b/Content.Shared/Research/Components/ResearchStealerComponent.cs index e0331fad1b..df8878e651 100644 --- a/Content.Shared/Research/Components/ResearchStealerComponent.cs +++ b/Content.Shared/Research/Components/ResearchStealerComponent.cs @@ -14,4 +14,16 @@ public sealed partial class ResearchStealerComponent : Component /// [DataField("delay"), ViewVariables(VVAccess.ReadWrite)] public TimeSpan Delay = TimeSpan.FromSeconds(20); + + /// + /// The minimum number of technologies that will be stolen + /// + [DataField] + public int MinToSteal = 4; + + /// + /// The maximum number of technologies that will be stolen + /// + [DataField] + public int MaxToSteal = 8; } diff --git a/Content.Shared/Research/Systems/SharedResearchSystem.cs b/Content.Shared/Research/Systems/SharedResearchSystem.cs index 12f27d0b9c..9819e949b8 100644 --- a/Content.Shared/Research/Systems/SharedResearchSystem.cs +++ b/Content.Shared/Research/Systems/SharedResearchSystem.cs @@ -1,6 +1,7 @@ using System.Linq; using Content.Shared.Research.Components; using Content.Shared.Research.Prototypes; +using JetBrains.Annotations; using Robust.Shared.Prototypes; using Robust.Shared.Random; using Robust.Shared.Utility; @@ -219,16 +220,58 @@ public void TrySetMainDiscipline(TechnologyPrototype prototype, EntityUid uid, T if (!Resolve(uid, ref component)) return; - var discipline = PrototypeManager.Index(prototype.Discipline); + var discipline = PrototypeManager.Index(prototype.Discipline); if (prototype.Tier < discipline.LockoutTier) return; component.MainDiscipline = prototype.Discipline; Dirty(uid, component); } + /// + /// Removes a technology and its recipes from a technology database. + /// + public bool TryRemoveTechnology(Entity entity, ProtoId tech) + { + return TryRemoveTechnology(entity, PrototypeManager.Index(tech)); + } + + /// + /// Removes a technology and its recipes from a technology database. + /// + [PublicAPI] + public bool TryRemoveTechnology(Entity entity, TechnologyPrototype tech) + { + if (!entity.Comp.UnlockedTechnologies.Remove(tech.ID)) + return false; + + // check to make sure we didn't somehow get the recipe from another tech. + // unlikely, but whatever + var recipes = tech.RecipeUnlocks; + foreach (var recipe in recipes) + { + var hasTechElsewhere = false; + foreach (var unlockedTech in entity.Comp.UnlockedTechnologies) + { + var unlockedTechProto = PrototypeManager.Index(unlockedTech); + + if (!unlockedTechProto.RecipeUnlocks.Contains(recipe)) + continue; + hasTechElsewhere = true; + break; + } + + if (!hasTechElsewhere) + entity.Comp.UnlockedRecipes.Remove(recipe); + } + Dirty(entity, entity.Comp); + UpdateTechnologyCards(entity, entity); + return true; + } + /// /// Clear all unlocked technologies from the database. /// + [PublicAPI] public void ClearTechs(EntityUid uid, TechnologyDatabaseComponent? comp = null) { if (!Resolve(uid, ref comp) || comp.UnlockedTechnologies.Count == 0) diff --git a/Content.Shared/Security/Systems/DeployableBarrierSystem.cs b/Content.Shared/Security/Systems/DeployableBarrierSystem.cs index 7b9ce841a9..622edc4b62 100644 --- a/Content.Shared/Security/Systems/DeployableBarrierSystem.cs +++ b/Content.Shared/Security/Systems/DeployableBarrierSystem.cs @@ -1,6 +1,6 @@ using Content.Shared.Lock; -using Content.Shared.Pulling; -using Content.Shared.Pulling.Components; +using Content.Shared.Movement.Pulling.Components; +using Content.Shared.Movement.Pulling.Systems; using Content.Shared.Security.Components; using Robust.Shared.Physics.Systems; @@ -11,7 +11,7 @@ public sealed class DeployableBarrierSystem : EntitySystem [Dependency] private readonly FixtureSystem _fixtures = default!; [Dependency] private readonly SharedPointLightSystem _pointLight = default!; [Dependency] private readonly SharedPhysicsSystem _physics = default!; - [Dependency] private readonly SharedPullingSystem _pulling = default!; + [Dependency] private readonly PullingSystem _pulling = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; public override void Initialize() @@ -54,8 +54,8 @@ private void ToggleBarrierDeploy(EntityUid uid, bool isDeployed, DeployableBarri _physics.SetHard(uid, fixture, false); } - if (TryComp(uid, out SharedPullableComponent? pullable)) - _pulling.TryStopPull(pullable); + if (TryComp(uid, out PullableComponent? pullable)) + _pulling.TryStopPull(uid, pullable); SharedPointLightComponent? pointLight = null; if (_pointLight.ResolveLight(uid, ref pointLight)) diff --git a/Content.Shared/Shuttles/Components/IFFComponent.cs b/Content.Shared/Shuttles/Components/IFFComponent.cs index a7e6ac1152..6bacbd2b5b 100644 --- a/Content.Shared/Shuttles/Components/IFFComponent.cs +++ b/Content.Shared/Shuttles/Components/IFFComponent.cs @@ -10,11 +10,6 @@ namespace Content.Shared.Shuttles.Components; [Access(typeof(SharedShuttleSystem))] public sealed partial class IFFComponent : Component { - /// - /// Should we show IFF by default? - /// - public const bool ShowIFFDefault = true; - public static readonly Color SelfColor = Color.MediumSpringGreen; /// diff --git a/Content.Shared/Shuttles/Systems/SharedShuttleSystem.IFF.cs b/Content.Shared/Shuttles/Systems/SharedShuttleSystem.IFF.cs index ed687d48f4..8231e48e2d 100644 --- a/Content.Shared/Shuttles/Systems/SharedShuttleSystem.IFF.cs +++ b/Content.Shared/Shuttles/Systems/SharedShuttleSystem.IFF.cs @@ -28,11 +28,6 @@ public Color GetIFFColor(EntityUid gridUid, bool self = false, IFFComponent? com public string? GetIFFLabel(EntityUid gridUid, bool self = false, IFFComponent? component = null) { - if (!IFFComponent.ShowIFFDefault) - { - return null; - } - var entName = MetaData(gridUid).EntityName; if (self) diff --git a/Content.Shared/Shuttles/Systems/SharedShuttleSystem.cs b/Content.Shared/Shuttles/Systems/SharedShuttleSystem.cs index 324fd65c86..ca25a49b23 100644 --- a/Content.Shared/Shuttles/Systems/SharedShuttleSystem.cs +++ b/Content.Shared/Shuttles/Systems/SharedShuttleSystem.cs @@ -146,7 +146,6 @@ public bool FTLFree(EntityUid shuttleUid, EntityCoordinates coordinates, Angle a // Just checks if any grids inside of a buffer range at the target position. _grids.Clear(); - var ftlRange = FTLRange; var mapCoordinates = coordinates.ToMap(EntityManager, XformSystem); var ourPos = Maps.GetGridPosition((shuttleUid, shuttlePhysics, shuttleXform)); diff --git a/Content.Shared/Sound/SharedEmitSoundSystem.cs b/Content.Shared/Sound/SharedEmitSoundSystem.cs index 22ba8e0e3e..56a51744ac 100644 --- a/Content.Shared/Sound/SharedEmitSoundSystem.cs +++ b/Content.Shared/Sound/SharedEmitSoundSystem.cs @@ -9,6 +9,7 @@ using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; using Robust.Shared.Map; +using Robust.Shared.Map.Components; using Robust.Shared.Network; using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Events; @@ -25,7 +26,6 @@ public abstract class SharedEmitSoundSystem : EntitySystem { [Dependency] private readonly IGameTiming _timing = default!; [Dependency] private readonly INetManager _netMan = default!; - [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly ITileDefinitionManager _tileDefMan = default!; [Dependency] protected readonly IRobustRandom Random = default!; [Dependency] private readonly SharedAudioSystem _audioSystem = default!; @@ -54,7 +54,7 @@ private void OnEmitSoundOnLand(EntityUid uid, BaseEmitSoundComponent component, { if (!args.PlaySound || !TryComp(uid, out var xform) || - !_mapManager.TryGetGrid(xform.GridUid, out var grid)) + !TryComp(xform.GridUid, out var grid)) { return; } diff --git a/Content.Shared/Storage/EntitySystems/DumpableSystem.cs b/Content.Shared/Storage/EntitySystems/DumpableSystem.cs index 04f7231416..568d9dab3b 100644 --- a/Content.Shared/Storage/EntitySystems/DumpableSystem.cs +++ b/Content.Shared/Storage/EntitySystems/DumpableSystem.cs @@ -19,17 +19,16 @@ public sealed class DumpableSystem : EntitySystem [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; - [Dependency] private readonly SharedContainerSystem _container = default!; [Dependency] private readonly SharedDisposalUnitSystem _disposalUnitSystem = default!; [Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!; [Dependency] private readonly SharedTransformSystem _transformSystem = default!; - private EntityQuery _xformQuery; + private EntityQuery _itemQuery; public override void Initialize() { base.Initialize(); - _xformQuery = GetEntityQuery(); + _itemQuery = GetEntityQuery(); SubscribeLocalEvent(OnAfterInteract, after: new[]{ typeof(SharedEntityStorageSystem) }); SubscribeLocalEvent>(AddDumpVerb); SubscribeLocalEvent>(AddUtilityVerbs); @@ -111,7 +110,7 @@ private void AddUtilityVerbs(EntityUid uid, DumpableComponent dumpable, GetVerbs } } - private void StartDoAfter(EntityUid storageUid, EntityUid? targetUid, EntityUid userUid, DumpableComponent dumpable) + private void StartDoAfter(EntityUid storageUid, EntityUid targetUid, EntityUid userUid, DumpableComponent dumpable) { if (!TryComp(storageUid, out var storage)) return; @@ -120,7 +119,7 @@ private void StartDoAfter(EntityUid storageUid, EntityUid? targetUid, EntityUid foreach (var entity in storage.Container.ContainedEntities) { - if (!TryComp(entity, out var itemComp) || + if (!_itemQuery.TryGetComponent(entity, out var itemComp) || !_prototypeManager.TryIndex(itemComp.Size, out var itemSize)) { continue; @@ -139,33 +138,16 @@ private void StartDoAfter(EntityUid storageUid, EntityUid? targetUid, EntityUid }); } - private void OnDoAfter(EntityUid uid, DumpableComponent component, DoAfterEvent args) + private void OnDoAfter(EntityUid uid, DumpableComponent component, DumpableDoAfterEvent args) { - if (args.Handled || args.Cancelled || !TryComp(uid, out var storage)) + if (args.Handled || args.Cancelled || !TryComp(uid, out var storage) || storage.Container.ContainedEntities.Count == 0) return; - Queue dumpQueue = new(); - foreach (var entity in storage.Container.ContainedEntities) - { - dumpQueue.Enqueue(entity); - } - - if (dumpQueue.Count == 0) - return; - - foreach (var entity in dumpQueue) - { - var transform = Transform(entity); - _container.AttachParentToContainerOrGrid((entity, transform)); - _transformSystem.SetLocalPositionRotation(entity, transform.LocalPosition + _random.NextVector2Box() / 2, _random.NextAngle(), transform); - } - - if (args.Args.Target == null) - return; + var dumpQueue = new Queue(storage.Container.ContainedEntities); var dumped = false; - if (_disposalUnitSystem.HasDisposals(args.Args.Target.Value)) + if (_disposalUnitSystem.HasDisposals(args.Args.Target)) { dumped = true; @@ -174,22 +156,31 @@ private void OnDoAfter(EntityUid uid, DumpableComponent component, DoAfterEvent _disposalUnitSystem.DoInsertDisposalUnit(args.Args.Target.Value, entity, args.Args.User); } } - else if (HasComp(args.Args.Target.Value)) + else if (HasComp(args.Args.Target)) { dumped = true; - var targetPos = _xformQuery.GetComponent(args.Args.Target.Value).LocalPosition; + var targetPos = _transformSystem.GetWorldPosition(args.Args.Target.Value); + + foreach (var entity in dumpQueue) + { + _transformSystem.SetWorldPosition(entity, targetPos + _random.NextVector2Box() / 4); + } + } + else + { + var targetPos = _transformSystem.GetWorldPosition(uid); foreach (var entity in dumpQueue) { - _transformSystem.SetLocalPosition(entity, targetPos + _random.NextVector2Box() / 4); + var transform = Transform(entity); + _transformSystem.SetWorldPositionRotation(entity, targetPos + _random.NextVector2Box() / 4, _random.NextAngle(), transform); } } if (dumped) { - // TODO: Predicted when above predicted - _audio.PlayPvs(component.DumpSound, uid); + _audio.PlayPredicted(component.DumpSound, uid, args.User); } } } diff --git a/Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs b/Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs index 11075b4a4c..799fb7e33e 100644 --- a/Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs +++ b/Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs @@ -3,6 +3,7 @@ using System.Linq; using Content.Shared.ActionBlocker; using Content.Shared.Containers.ItemSlots; +using Content.Shared.Coordinates; using Content.Shared.Destructible; using Content.Shared.DoAfter; using Content.Shared.Hands.Components; @@ -12,6 +13,7 @@ using Content.Shared.Item; using Content.Shared.Lock; using Content.Shared.Nyanotrasen.Item.PseudoItem; +using Content.Shared.Materials; using Content.Shared.Placeable; using Content.Shared.Popups; using Content.Shared.Stacks; @@ -96,6 +98,9 @@ public override void Initialize() SubscribeAllEvent(OnSetItemLocation); SubscribeAllEvent(OnInsertItemIntoLocation); SubscribeAllEvent(OnRemoveItem); + + SubscribeLocalEvent(OnReclaimed); + UpdatePrototypeCache(); } @@ -389,6 +394,11 @@ private void OnDoAfter(EntityUid uid, StorageComponent component, AreaPickupDoAf args.Handled = true; } + private void OnReclaimed(EntityUid uid, StorageComponent storageComp, GotReclaimedEvent args) + { + _containerSystem.EmptyContainer(storageComp.Container, destination: args.ReclaimerCoordinates); + } + private void OnDestroy(EntityUid uid, StorageComponent storageComp, DestructionEventArgs args) { var coordinates = TransformSystem.GetMoverCoordinates(uid); diff --git a/Content.Shared/SubFloor/SharedSubFloorHideSystem.cs b/Content.Shared/SubFloor/SharedSubFloorHideSystem.cs index 02b4e61790..ba78ff651f 100644 --- a/Content.Shared/SubFloor/SharedSubFloorHideSystem.cs +++ b/Content.Shared/SubFloor/SharedSubFloorHideSystem.cs @@ -15,7 +15,6 @@ namespace Content.Shared.SubFloor [UsedImplicitly] public abstract class SharedSubFloorHideSystem : EntitySystem { - [Dependency] protected readonly IMapManager MapManager = default!; [Dependency] private readonly ITileDefinitionManager _tileDefinitionManager = default!; [Dependency] private readonly SharedAmbientSoundSystem _ambientSoundSystem = default!; [Dependency] protected readonly SharedAppearanceSystem Appearance = default!; @@ -93,7 +92,7 @@ private void OnTileChanged(ref TileChangedEvent args) if (args.NewTile.Tile.IsEmpty) return; // Anything that was here will be unanchored anyways. - UpdateTile(MapManager.GetGrid(args.NewTile.GridUid), args.NewTile.GridIndices); + UpdateTile(Comp(args.NewTile.GridUid), args.NewTile.GridIndices); } /// @@ -104,7 +103,7 @@ private void UpdateFloorCover(EntityUid uid, SubFloorHideComponent? component = if (!Resolve(uid, ref component, ref xform)) return; - if (xform.Anchored && MapManager.TryGetGrid(xform.GridUid, out var grid)) + if (xform.Anchored && TryComp(xform.GridUid, out var grid)) component.IsUnderCover = HasFloorCover(grid, grid.TileIndicesFor(xform.Coordinates)); else component.IsUnderCover = false; diff --git a/Content.Shared/Teleportation/Systems/SharedPortalSystem.cs b/Content.Shared/Teleportation/Systems/SharedPortalSystem.cs index ebd8362411..8d67aec518 100644 --- a/Content.Shared/Teleportation/Systems/SharedPortalSystem.cs +++ b/Content.Shared/Teleportation/Systems/SharedPortalSystem.cs @@ -1,9 +1,9 @@ using System.Linq; using Content.Shared.Ghost; +using Content.Shared.Movement.Pulling.Components; +using Content.Shared.Movement.Pulling.Systems; using Content.Shared.Popups; using Content.Shared.Projectiles; -using Content.Shared.Pulling; -using Content.Shared.Pulling.Components; using Content.Shared.Teleportation.Components; using Content.Shared.Verbs; using Robust.Shared.Audio; @@ -28,7 +28,7 @@ public abstract class SharedPortalSystem : EntitySystem [Dependency] private readonly EntityLookupSystem _lookup = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; - [Dependency] private readonly SharedPullingSystem _pulling = default!; + [Dependency] private readonly PullingSystem _pulling = default!; [Dependency] private readonly SharedPopupSystem _popup = default!; private const string PortalFixture = "portalFixture"; @@ -93,15 +93,15 @@ private void OnCollide(EntityUid uid, PortalComponent component, ref StartCollid return; // break pulls before portal enter so we dont break shit - if (TryComp(subject, out var pullable) && pullable.BeingPulled) + if (TryComp(subject, out var pullable) && pullable.BeingPulled) { - _pulling.TryStopPull(pullable); + _pulling.TryStopPull(subject, pullable); } - if (TryComp(subject, out var pulling) - && pulling.Pulling != null && TryComp(pulling.Pulling.Value, out var subjectPulling)) + if (TryComp(subject, out var pullerComp) + && TryComp(pullerComp.Pulling, out var subjectPulling)) { - _pulling.TryStopPull(subjectPulling); + _pulling.TryStopPull(subject, subjectPulling); } // if they came from another portal, just return and wait for them to exit the portal diff --git a/Content.Shared/Throwing/ThrowingSystem.cs b/Content.Shared/Throwing/ThrowingSystem.cs index 0168286338..38772eaf34 100644 --- a/Content.Shared/Throwing/ThrowingSystem.cs +++ b/Content.Shared/Throwing/ThrowingSystem.cs @@ -20,6 +20,11 @@ public sealed class ThrowingSystem : EntitySystem { public const float ThrowAngularImpulse = 5f; + /// + /// Speed cap on rotation in case of click-spam. + /// + public const float ThrowAngularCap = 3f * MathF.PI; + public const float PushbackDefault = 2f; /// @@ -42,15 +47,17 @@ public void TryThrow( float strength = 1.0f, EntityUid? user = null, float pushbackRatio = PushbackDefault, + bool recoil = true, + bool animated = true, bool playSound = true) { - var thrownPos = Transform(uid).MapPosition; - var mapPos = coordinates.ToMap(EntityManager, _transform); + var thrownPos = _transform.GetMapCoordinates(uid); + var mapPos = _transform.ToMapCoordinates(coordinates); if (mapPos.MapId != thrownPos.MapId) return; - TryThrow(uid, mapPos.Position - thrownPos.Position, strength, user, pushbackRatio, playSound); + TryThrow(uid, mapPos.Position - thrownPos.Position, strength, user, pushbackRatio, recoil: recoil, animated: animated, playSound: playSound); } /// @@ -65,6 +72,8 @@ public void TryThrow(EntityUid uid, float strength = 1.0f, EntityUid? user = null, float pushbackRatio = PushbackDefault, + bool recoil = true, + bool animated = true, bool playSound = true) { var physicsQuery = GetEntityQuery(); @@ -72,7 +81,6 @@ public void TryThrow(EntityUid uid, return; var projectileQuery = GetEntityQuery(); - var tagQuery = GetEntityQuery(); TryThrow( uid, @@ -82,8 +90,7 @@ public void TryThrow(EntityUid uid, projectileQuery, strength, user, - pushbackRatio, - playSound); + pushbackRatio, recoil: recoil, animated: animated, playSound: playSound); } /// @@ -101,6 +108,8 @@ public void TryThrow(EntityUid uid, float strength = 1.0f, EntityUid? user = null, float pushbackRatio = PushbackDefault, + bool recoil = true, + bool animated = true, bool playSound = true) { if (strength <= 0 || direction == Vector2Helpers.Infinity || direction == Vector2Helpers.NaN || direction == Vector2.Zero) @@ -116,12 +125,17 @@ public void TryThrow(EntityUid uid, if (projectileQuery.TryGetComponent(uid, out var proj) && !proj.OnlyCollideWhenShot) return; - var comp = new ThrownItemComponent(); - comp.Thrower = user; + var comp = new ThrownItemComponent + { + Thrower = user, + Animate = animated, + }; // Estimate time to arrival so we can apply OnGround status and slow it much faster. var time = direction.Length() / strength; comp.ThrownTime = _gameTiming.CurTime; + // TODO: This is a bandaid, don't do this. + // if you want to force landtime have the caller handle it or add a new method. // did we launch this with something stronger than our hands? if (TryComp(comp.Thrower, out var hands) && strength > hands.ThrowForceMultiplier) comp.LandTime = comp.ThrownTime + TimeSpan.FromSeconds(time); @@ -166,7 +180,8 @@ public void TryThrow(EntityUid uid, if (user == null) return; - _recoil.KickCamera(user.Value, -direction * 0.04f); + if (recoil) + _recoil.KickCamera(user.Value, -direction * 0.04f); // Give thrower an impulse in the other direction if (pushbackRatio != 0.0f && diff --git a/Content.Shared/Throwing/ThrownItemComponent.cs b/Content.Shared/Throwing/ThrownItemComponent.cs index 16c9b13254..f7defaa4aa 100644 --- a/Content.Shared/Throwing/ThrownItemComponent.cs +++ b/Content.Shared/Throwing/ThrownItemComponent.cs @@ -8,6 +8,12 @@ namespace Content.Shared.Throwing [RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true), AutoGenerateComponentPause] public sealed partial class ThrownItemComponent : Component { + /// + /// Should the in-air throwing animation play. + /// + [DataField, AutoNetworkedField] + public bool Animate = true; + /// /// The entity that threw this entity. /// diff --git a/Content.Shared/Throwing/ThrownItemSystem.cs b/Content.Shared/Throwing/ThrownItemSystem.cs index cc50094e3d..ef28db2672 100644 --- a/Content.Shared/Throwing/ThrownItemSystem.cs +++ b/Content.Shared/Throwing/ThrownItemSystem.cs @@ -3,8 +3,7 @@ using Content.Shared.Database; using Content.Shared.Gravity; using Content.Shared.Physics; -using Content.Shared.Physics.Pull; -using Robust.Shared.GameStates; +using Content.Shared.Movement.Pulling.Events; using Robust.Shared.Physics; using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Events; @@ -85,8 +84,8 @@ private void OnSleep(EntityUid uid, ThrownItemComponent thrownItem, ref PhysicsS private void HandlePullStarted(PullStartedMessage message) { // TODO: this isn't directed so things have to be done the bad way - if (EntityManager.TryGetComponent(message.Pulled.Owner, out ThrownItemComponent? thrownItemComponent)) - StopThrow(message.Pulled.Owner, thrownItemComponent); + if (EntityManager.TryGetComponent(message.PulledUid, out ThrownItemComponent? thrownItemComponent)) + StopThrow(message.PulledUid, thrownItemComponent); } public void StopThrow(EntityUid uid, ThrownItemComponent thrownItemComponent) diff --git a/Content.Shared/Tiles/FloorTileSystem.cs b/Content.Shared/Tiles/FloorTileSystem.cs index 1f8408319d..0d368495f1 100644 --- a/Content.Shared/Tiles/FloorTileSystem.cs +++ b/Content.Shared/Tiles/FloorTileSystem.cs @@ -116,7 +116,7 @@ private void OnAfterInteract(EntityUid uid, FloorTileComponent component, AfterI } } } - _mapManager.TryGetGrid(location.EntityId, out var mapGrid); + TryComp(location.EntityId, out var mapGrid); foreach (var currentTile in component.OutputTiles) { diff --git a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Interactions.cs b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Interactions.cs index d47d024de5..274828a208 100644 --- a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Interactions.cs +++ b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Interactions.cs @@ -102,7 +102,7 @@ public void CycleFire(EntityUid uid, GunComponent component, EntityUid? user = n // TODO: Actions need doing for guns anyway. private sealed partial class CycleModeEvent : InstantActionEvent { - public SelectiveFire Mode; + public SelectiveFire Mode = default; } private void OnCycleMode(EntityUid uid, GunComponent component, CycleModeEvent args) diff --git a/Content.Tests/Shared/Chat/V2/Moderation/SimpleCensor.cs b/Content.Tests/Shared/Chat/V2/Moderation/SimpleCensor.cs new file mode 100644 index 0000000000..09870af317 --- /dev/null +++ b/Content.Tests/Shared/Chat/V2/Moderation/SimpleCensor.cs @@ -0,0 +1,162 @@ +using System.Text.Unicode; +using Content.Shared.Chat.V2.Moderation; +using NUnit.Framework; + +namespace Content.Tests.Shared.Chat.V2.Moderation; + +public sealed class SimpleCensorTests +{ + [Test] + public void CanCensorASingleWord() + { + var sut = new SimpleCensor().WithCustomDictionary(["amogus"]); + var output = sut.Censor("hello amogus"); + + Assert.That(output, Is.EqualTo("hello ******")); + } + + // Basics - use custom dictionary + + [Test] + public void CanCensorMultipleWordInstances() + { + var sut= new SimpleCensor().WithCustomDictionary(["amogus"]); + var output = sut.Censor("amogus hello amogus"); + + Assert.That(output, Is.EqualTo("****** hello ******")); + } + + [Test] + public void CanCensorMultipleWords() + { + var sut= new SimpleCensor().WithCustomDictionary(["amogus", "sus"]); + var output = sut.Censor("amogus hello sus"); + + Assert.That(output, Is.EqualTo("****** hello ***")); + } + + [Test] + public void CanUseDifferentCensorSymbols() + { + var sut= new SimpleCensor().WithCustomDictionary(["amogus", "sus"]); + var output = sut.Censor("amogus hello sus", '#'); + + Assert.That(output, Is.EqualTo("###### hello ###")); + } + + [Test] + public void CanCatchCapitalizedWords() + { + var sut= new SimpleCensor().WithCustomDictionary(["amogus", "sus"]); + var output = sut.Censor("AMOGUS hello SUS"); + + Assert.That(output, Is.EqualTo("****** hello ***")); + } + + [Test] + public void CanCatchWordsWithSomeCaptialsInThem() + { + var sut= new SimpleCensor().WithCustomDictionary(["amogus", "sus"]); + var output = sut.Censor("AmoGuS hello SuS"); + + Assert.That(output, Is.EqualTo("****** hello ***")); + } + + [Test] + public void CanCatchWordsHiddenInsideOtherWords() + { + var sut= new SimpleCensor().WithCustomDictionary(["amogus", "sus"]); + var output = sut.Censor("helamoguslo suspicious"); + + Assert.That(output, Is.EqualTo("hel******lo ***picious")); + } + + // Sanitizing Leetspeak + + [Test] + public void CanSanitizeLeetspeak() + { + var sut = new SimpleCensor().WithCustomDictionary(["amogus", "sus"]).WithSanitizeLeetSpeak(); + var output = sut.Censor("am0gu5 hello 5u5"); + + Assert.That(output, Is.EqualTo("****** hello ***")); + } + + [Test] + public void SanitizingLeetspeakOnlyOccursWhenTheWordIsBlocked() + { + var sut = new SimpleCensor().WithCustomDictionary(["amogus", "sus"]).WithSanitizeLeetSpeak(); + var output = sut.Censor("he110"); + + Assert.That(output, Is.EqualTo("he110")); + } + + [Test] + public void CanCatchLeetspeakReplacementsWithMoreThanOneLetter() + { + var sut = new SimpleCensor().WithCustomDictionary(["amogus", "sus"]).WithSanitizeLeetSpeak(); + var output = sut.Censor("am()gu5 hello 5u5"); + + Assert.That(output, Is.EqualTo("******* hello ***")); + } + + // Sanitizing special characters + + [Test] + public void DoesNotSanitizeOutUncensoredSpecialCharacters() + { + var sut = new SimpleCensor().WithCustomDictionary(["amogus", "sus"]).WithSanitizeSpecialCharacters(); + var output = sut.Censor("amogus!hello!sus"); + + Assert.That(output, Is.EqualTo("******!hello!***")); + } + + [Test] + public void DoesSanitizeOutCensoredSpecialCharacters() + { + var sut = new SimpleCensor().WithCustomDictionary(["amogus", "sus"]).WithSanitizeSpecialCharacters(); + var output = sut.Censor("amo!gus hello s?us"); + + Assert.That(output, Is.EqualTo("***!*** hello *?**")); + } + + // Unicode ranges + + [Test] + public void SanitizesOutNonLatinCharaters() + { + var sut = new SimpleCensor().WithRanges([UnicodeRanges.BasicLatin, UnicodeRanges.Latin1Supplement]); + var output = sut.Censor("amogus Україна sus 日本"); + + Assert.That(output, Is.EqualTo("amogus sus ")); + } + + [Test] + public void SanitizesOutNonLatinOrCyrillicCharaters() + { + var sut = new SimpleCensor().WithRanges([UnicodeRanges.BasicLatin, UnicodeRanges.Latin1Supplement, UnicodeRanges.Cyrillic]); + var output = sut.Censor("amogus Україна sus 日本"); + + Assert.That(output, Is.EqualTo("amogus Україна sus ")); + } + + // False positives + [Test] + public void CanHandleFalsePositives() + { + var sut = new SimpleCensor().WithCustomDictionary(["amogus", "sus"]).WithFalsePositives(["amogusus"]); + var output = sut.Censor("amogusus hello amogus hello sus"); + + Assert.That(output, Is.EqualTo("amogusus hello ****** hello ***")); + } + + // False negatives + [Test] + public void CanHandleFalseNegatives() + { + var sut = new SimpleCensor().WithCustomDictionary(["amogus", "sus"]).WithFalsePositives(["amogusus"]).WithFalseNegatives(["susamogusus"]); + var output = sut.Censor("susamogusus hello amogus hello sus amogusus"); + + Assert.That(output, Is.EqualTo("*********** hello ****** hello *** ********")); + } +} diff --git a/Content.YAMLLinter/Program.cs b/Content.YAMLLinter/Program.cs index b7b70bd118..78867fcb8a 100644 --- a/Content.YAMLLinter/Program.cs +++ b/Content.YAMLLinter/Program.cs @@ -97,7 +97,7 @@ await instance.WaitPost(() => yamlErrors[kind] = set; } - fieldErrors = protoMan.ValidateFields(prototypes); + fieldErrors = protoMan.ValidateStaticFields(prototypes); }); return (yamlErrors, fieldErrors); diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 9c472d93e3..49aa0a6c97 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -4367,3 +4367,59 @@ Entries: message: Added system id: 6146 time: '2024-07-06T00:19:35.0000000+00:00' +- author: Velcroboy + changes: + - type: Tweak + message: Changed asteroids to have more ore...and some danger + id: 6147 + time: '2024-07-08T07:03:39.0000000+00:00' +- author: FoxxoTrystan + changes: + - type: Add + message: Languages are now marked in the chat! + id: 6148 + time: '2024-07-09T19:01:38.0000000+00:00' +- author: Spatison + changes: + - type: Fix + message: Food and handcuffs can now be given + id: 6149 + time: '2024-07-09T19:32:11.0000000+00:00' +- author: FoxxoTrrystan + changes: + - type: Tweak + message: >- + Power Resprites! (New SMES, APC, Airlarm, Camera, Substation, LightTube, + Intercom, FireAlarm and Substation) + id: 6150 + time: '2024-07-09T19:37:03.0000000+00:00' +- author: CodedCrow + changes: + - type: Add + message: Plushie + id: 6151 + time: '2024-07-11T17:23:58.0000000+00:00' +- author: osjarw + changes: + - type: Add + message: Wallmount substation electronics can now be created at an autolathe. + id: 6152 + time: '2024-07-11T17:24:30.0000000+00:00' +- author: Mnemotechnician + changes: + - type: Tweak + message: 'Players can now vote on two more gamemodes: Traitors and Hellshift.' + id: 6153 + time: '2024-07-11T17:26:41.0000000+00:00' +- author: Mnemotechnician + changes: + - type: Add + message: >- + Added two new foreigner traits that make your character unable to speak + Galactic Common and give you a translator instead. + - type: Tweak + message: >- + Translators can now be equipped in the neck slot and display useful info + when examined. + id: 6154 + time: '2024-07-12T01:19:09.0000000+00:00' diff --git a/Resources/Credits/GitHub.txt b/Resources/Credits/GitHub.txt index 84796a9466..c3be81504b 100644 --- a/Resources/Credits/GitHub.txt +++ b/Resources/Credits/GitHub.txt @@ -1 +1 @@ -0x6273, 2013HORSEMEATSCANDAL, 20kdc, 21Melkuu, 4dplanner, 612git, 778b, Ablankmann, Acruid, actioninja, adamsong, Admiral-Obvious-001, Adrian16199, Aerocrux, Aexxie, africalimedrop, Agoichi, Ahion, AJCM-git, AjexRose, Alekshhh, AlexMorgan3817, AlmondFlour, AlphaQwerty, Altoids1, amylizzle, ancientpower, ArchPigeon, Arendian, arimah, Arteben, AruMoon, as334, AsikKEsel, asperger-sind, aspiringLich, avghdev, AzzyIsNotHere, BananaFlambe, BasedUser, BGare, BingoJohnson-zz, BismarckShuffle, Bixkitts, Blackern5000, Blazeror, Boaz1111, BobdaBiscuit, brainfood1183, Brandon-Huu, Bribrooo, Bright0, brndd, BubblegumBlue, BYONDFuckery, c4llv07e, CaasGit, CakeQ, CaptainSqrBeard, Carbonhell, Carolyn3114, casperr04, CatTheSystem, Centronias, chairbender, Charlese2, Cheackraze, cheesePizza2, Chief-Engineer, chromiumboy, Chronophylos, clement-or, Clyybber, ColdAutumnRain, Colin-Tel, collinlunn, ComicIronic, coolmankid12345, corentt, crazybrain23, creadth, CrigCrag, Crotalus, CrudeWax, CrzyPotato, Cyberboss, d34d10cc, Daemon, daerSeebaer, dahnte, dakamakat, dakimasu, DamianX, DangerRevolution, daniel-cr, Darkenson, DawBla, dch-GH, Deahaka, DEATHB4DEFEAT, DeathCamel58, deathride58, DebugOk, Decappi, deepdarkdepths, Delete69, deltanedas, DeltaV-Bot, DerbyX, DoctorBeard, DogZeroX, dontbetank, Doru991, DoubleRiceEddiedd, DrMelon, DrSmugleaf, drteaspoon420, DTanxxx, DubiousDoggo, Duddino, Dutch-VanDerLinde, Easypoller, eclips_e, EdenTheLiznerd, EEASAS, Efruit, ElectroSR, elthundercloud, Emisse, EmoGarbage404, Endecc, enumerate0, eoineoineoin, ERORR404V1, Errant-4, estacaoespacialpirata, exincore, exp111, Fahasor, FairlySadPanda, ficcialfaint, Fildrance, FillerVK, Fishfish458, Flareguy, FluffiestFloof, FluidRock, FoLoKe, fooberticus, Fortune117, FoxxoTrystan, freeman2651, Fromoriss, FungiFellow, GalacticChimp, gbasood, Geekyhobo, Genkail, geraeumig, Git-Nivrak, github-actions[bot], gituhabu, GNF54, Golinth, GoodWheatley, Gotimanga, graevy, GreyMario, Guess-My-Name, gusxyz, h3half, Hanzdegloker, Hardly3D, harikattar, Hebiman, Henry12116, HerCoyote23, Hmeister-real, HoofedEar, hord-brayden, hubismal, Hugal31, Hyenh, iacore, IamVelcroboy, icekot8, igorsaux, ike709, Illiux, Ilya246, IlyaElDunaev, Injazz, Insineer, IntegerTempest, Interrobang01, IProduceWidgets, ItsMeThom, j-giebel, Jackal298, Jackrost, jamessimo, janekvap, JerryImMouse, Jessetriesagain, jessicamaybe, Jezithyr, jicksaw, JiimBob, JoeHammad1844, joelhed, JohnGinnane, johnku1, joshepvodka, jproads, Jrpl, juliangiebel, JustArt1m, JustCone14, JustinTether, JustinTrotter, KaiShibaa, kalane15, kalanosh, KEEYNy, Keikiru, Kelrak, kerisargit, keronshb, KIBORG04, Killerqu00, KingFroozy, kira-er, Kit0vras, KittenColony, Kmc2000, Ko4ergaPunk, komunre, koteq, Krunklehorn, Kukutis96513, kxvvv, Lamrr, LankLTE, lapatison, Leander-0, leonardo-dabepis, LetterN, Level10Cybermancer, lever1209, LightVillet, liltenhead, LittleBuilderJane, Lomcastar, LordCarve, LordEclipse, LovelyLophi, LudwigVonChesterfield, Lukasz825700516, lunarcomets, luringens, lvvova1, lzimann, lzk228, M3739, MACMAN2003, Macoron, MagnusCrowe, ManelNavola, matthst, Matz05, MehimoNemo, MeltedPixel, MemeProof, Menshin, Mervill, metalgearsloth, mhamsterr, MilenVolf, Minty642, Mirino97, mirrorcult, misandrie, MishaUnity, MisterMecky, Mith-randalf, Moneyl, Moomoobeef, moony, Morb0, Mr0maks, musicmanvr, Myakot, Myctai, N3X15, Nairodian, Naive817, namespace-Memory, NickPowers43, nikthechampiongr, Nimfar11, Nirnael, nmajask, nok-ko, Nopey, notafet, notquitehadouken, noudoit, noverd, nuke-haus, NULL882, OCOtheOmega, OctoRocket, OldDanceJacket, onoira, Owai-Seek, pali6, Pangogie, patrikturi, PaulRitter, Peptide90, peptron1, Phantom-Lily, PHCodes, PixelTheKermit, PJB3005, Plykiya, pofitlo, pointer-to-null, PolterTzi, PoorMansDreams, potato1234x, ProfanedBane, PrPleGoo, ps3moira, Psychpsyo, psykzz, PuroSlavKing, quatre, QuietlyWhisper, qwerltaz, Radosvik, Radrark, Rainbeon, Rainfey, Rane, ravage123321, rbertoche, Redict, RedlineTriad, RednoWCirabrab, RemberBM, RemieRichards, RemTim, rene-descartes2021, RiceMar1244, RieBi, Rinkashikachi, Rockdtben, rolfero, rosieposieeee, Saakra, Samsterious, SaphireLattice, ScalyChimp, scrato, Scribbles0, Serkket, SethLafuente, ShadowCommander, Shadowtheprotogen546, SignalWalker, SimpleStation14, Simyon264, SirDragooon, Sirionaut, siyengar04, Skarletto, Skrauz, Skyedra, SlamBamActionman, slarticodefast, Slava0135, Snowni, snowsignal, SonicHDC, SoulSloth, SpaceManiac, SpeltIncorrectyl, spoogemonster, ssdaniel24, Stealthbomber16, stellar-novas, StrawberryMoses, SweptWasTaken, Szunti, TadJohnson00, takemysoult, TaralGit, Tayrtahn, tday93, TekuNut, TemporalOroboros, tentekal, tgrkzus, thatrandomcanadianguy, TheArturZh, theashtronaut, thedraccx, themias, Theomund, theOperand, TheShuEd, TimrodDX, Titian3, tkdrg, tmtmtl30, tom-leys, tomasalves8, Tomeno, Tornado-Technology, tosatur, Tryded, TsjipTsjip, Tunguso4ka, TurboTrackerss14, Tyler-IN, Tyzemol, UbaserB, UKNOWH, UnicornOnLSD, Uriende, UristMcDorf, Vaaankas, Varen, VasilisThePikachu, veliebm, Veritius, Verslebas, VigersRay, Visne, VMSolidus, volundr-, Voomra, Vordenburg, vulppine, waylon531, weaversam8, Willhelm53, wixoaGit, WlarusFromDaSpace, wrexbe, xRiriq, yathxyz, Ygg01, YotaXP, YuriyKiss, zach-hill, Zandario, Zap527, ZelteHonor, zerorulez, zionnBE, zlodo, ZNixian, ZoldorfTheWizard, Zumorica, Zymem +0x6273, 2013HORSEMEATSCANDAL, 20kdc, 21Melkuu, 4dplanner, 612git, 778b, Ablankmann, Acruid, actioninja, adamsong, Admiral-Obvious-001, Adrian16199, Aerocrux, Aexxie, africalimedrop, Agoichi, Ahion, AJCM-git, AjexRose, Alekshhh, AlexMorgan3817, AlmondFlour, AlphaQwerty, Altoids1, amylizzle, ancientpower, ArchPigeon, Arendian, arimah, Arteben, AruMoon, as334, AsikKEsel, asperger-sind, aspiringLich, avghdev, AzzyIsNotHere, BananaFlambe, BasedUser, BGare, BingoJohnson-zz, BismarckShuffle, Bixkitts, Blackern5000, Blazeror, Boaz1111, BobdaBiscuit, brainfood1183, Brandon-Huu, Bribrooo, Bright0, brndd, BubblegumBlue, BYONDFuckery, c4llv07e, CaasGit, CakeQ, CaptainSqrBeard, Carbonhell, Carolyn3114, casperr04, CatTheSystem, Centronias, chairbender, Charlese2, Cheackraze, cheesePizza2, Chief-Engineer, chromiumboy, Chronophylos, clement-or, Clyybber, ColdAutumnRain, Colin-Tel, collinlunn, ComicIronic, coolmankid12345, corentt, crazybrain23, creadth, CrigCrag, Crotalus, CrudeWax, CrzyPotato, Cyberboss, d34d10cc, Daemon, daerSeebaer, dahnte, dakamakat, dakimasu, DamianX, DangerRevolution, daniel-cr, Darkenson, DawBla, dch-GH, Deahaka, DEATHB4DEFEAT, DeathCamel58, deathride58, DebugOk, Decappi, deepdarkdepths, Delete69, deltanedas, DeltaV-Bot, DerbyX, DoctorBeard, DogZeroX, dontbetank, Doru991, DoubleRiceEddiedd, DrMelon, DrSmugleaf, drteaspoon420, DTanxxx, DubiousDoggo, Duddino, Dutch-VanDerLinde, Easypoller, eclips_e, EdenTheLiznerd, EEASAS, Efruit, ElectroSR, elthundercloud, Emisse, EmoGarbage404, Endecc, enumerate0, eoineoineoin, ERORR404V1, Errant-4, estacaoespacialpirata, exincore, exp111, Fahasor, FairlySadPanda, ficcialfaint, Fildrance, FillerVK, Fishfish458, Flareguy, FluffiestFloof, FluidRock, FoLoKe, fooberticus, Fortune117, FoxxoTrystan, freeman2651, Fromoriss, FungiFellow, GalacticChimp, gbasood, Geekyhobo, Genkail, geraeumig, Git-Nivrak, github-actions[bot], gituhabu, GNF54, Golinth, GoodWheatley, Gotimanga, graevy, GreyMario, Guess-My-Name, gusxyz, h3half, Hanzdegloker, Hardly3D, harikattar, Hebiman, Henry12116, HerCoyote23, Hmeister-real, HoofedEar, hord-brayden, hubismal, Hugal31, Hyenh, iacore, IamVelcroboy, icekot8, igorsaux, ike709, Illiux, Ilya246, IlyaElDunaev, Injazz, Insineer, IntegerTempest, Interrobang01, IProduceWidgets, ItsMeThom, j-giebel, Jackal298, Jackrost, jamessimo, janekvap, JerryImMouse, Jessetriesagain, jessicamaybe, Jezithyr, jicksaw, JiimBob, JoeHammad1844, joelhed, JohnGinnane, johnku1, joshepvodka, jproads, Jrpl, juliangiebel, JustArt1m, JustCone14, JustinTether, JustinTrotter, KaiShibaa, kalane15, kalanosh, KEEYNy, Keikiru, Kelrak, kerisargit, keronshb, KIBORG04, Killerqu00, KingFroozy, kira-er, Kit0vras, KittenColony, Kmc2000, Ko4ergaPunk, komunre, koteq, Krunklehorn, Kukutis96513, kxvvv, Lamrr, LankLTE, lapatison, Leander-0, leonardo-dabepis, LetterN, Level10Cybermancer, lever1209, LightVillet, liltenhead, LittleBuilderJane, Lomcastar, LordCarve, LordEclipse, LovelyLophi, LudwigVonChesterfield, Lukasz825700516, lunarcomets, luringens, lvvova1, lzimann, lzk228, M3739, MACMAN2003, Macoron, MagnusCrowe, ManelNavola, Matz05, MehimoNemo, MeltedPixel, MemeProof, Menshin, Mervill, metalgearsloth, mhamsterr, MilenVolf, Minty642, Mirino97, mirrorcult, misandrie, MishaUnity, MisterMecky, Mith-randalf, Mnemotechnician, Moneyl, Moomoobeef, moony, Morb0, Mr0maks, musicmanvr, Myakot, Myctai, N3X15, Nairodian, Naive817, namespace-Memory, NickPowers43, nikthechampiongr, Nimfar11, Nirnael, nmajask, nok-ko, Nopey, notafet, notquitehadouken, noudoit, noverd, nuke-haus, NULL882, OCOtheOmega, OctoRocket, OldDanceJacket, onoira, Owai-Seek, pali6, Pangogie, patrikturi, PaulRitter, Peptide90, peptron1, Phantom-Lily, PHCodes, PixelTheKermit, PJB3005, Plykiya, pofitlo, pointer-to-null, PolterTzi, PoorMansDreams, potato1234x, ProfanedBane, PrPleGoo, ps3moira, Psychpsyo, psykzz, PuroSlavKing, quatre, QuietlyWhisper, qwerltaz, Radosvik, Radrark, Rainbeon, Rainfey, Rane, ravage123321, rbertoche, Redict, RedlineTriad, RednoWCirabrab, RemberBM, RemieRichards, RemTim, rene-descartes2021, RiceMar1244, RieBi, Rinkashikachi, Rockdtben, rolfero, rosieposieeee, Saakra, Samsterious, SaphireLattice, ScalyChimp, scrato, Scribbles0, Serkket, SethLafuente, ShadowCommander, Shadowtheprotogen546, SignalWalker, SimpleStation14, Simyon264, SirDragooon, Sirionaut, siyengar04, Skarletto, Skrauz, Skyedra, SlamBamActionman, slarticodefast, Slava0135, Snowni, snowsignal, SonicHDC, SoulSloth, SpaceManiac, SpeltIncorrectyl, spoogemonster, ssdaniel24, Stealthbomber16, stellar-novas, StrawberryMoses, SweptWasTaken, Szunti, TadJohnson00, takemysoult, TaralGit, Tayrtahn, tday93, TekuNut, TemporalOroboros, tentekal, tgrkzus, thatrandomcanadianguy, TheArturZh, theashtronaut, thedraccx, themias, Theomund, theOperand, TheShuEd, TimrodDX, Titian3, tkdrg, tmtmtl30, tom-leys, tomasalves8, Tomeno, Tornado-Technology, tosatur, Tryded, TsjipTsjip, Tunguso4ka, TurboTrackerss14, Tyler-IN, Tyzemol, UbaserB, UKNOWH, UnicornOnLSD, Uriende, UristMcDorf, Vaaankas, Varen, VasilisThePikachu, veliebm, Veritius, Verslebas, VigersRay, Visne, VMSolidus, volundr-, Voomra, Vordenburg, vulppine, waylon531, weaversam8, Willhelm53, wixoaGit, WlarusFromDaSpace, wrexbe, xRiriq, yathxyz, Ygg01, YotaXP, YuriyKiss, zach-hill, Zandario, Zap527, ZelteHonor, zerorulez, zionnBE, zlodo, ZNixian, ZoldorfTheWizard, Zumorica, Zymem diff --git a/Resources/Fonts/Copperplate.otf b/Resources/Fonts/Copperplate.otf new file mode 100644 index 0000000000..40d45aa46b Binary files /dev/null and b/Resources/Fonts/Copperplate.otf differ diff --git a/Resources/Fonts/Mangat.ttf b/Resources/Fonts/Mangat.ttf new file mode 100644 index 0000000000..de4c11beba Binary files /dev/null and b/Resources/Fonts/Mangat.ttf differ diff --git a/Resources/Fonts/Noganas.ttf b/Resources/Fonts/Noganas.ttf new file mode 100644 index 0000000000..afa0c82f03 Binary files /dev/null and b/Resources/Fonts/Noganas.ttf differ diff --git a/Resources/Fonts/RubikBubbles.ttf b/Resources/Fonts/RubikBubbles.ttf new file mode 100644 index 0000000000..a653715c6c Binary files /dev/null and b/Resources/Fonts/RubikBubbles.ttf differ diff --git a/Resources/Locale/en-US/administration/commands/stealthmin-command.ftl b/Resources/Locale/en-US/administration/commands/stealthmin-command.ftl new file mode 100644 index 0000000000..4fb5e52105 --- /dev/null +++ b/Resources/Locale/en-US/administration/commands/stealthmin-command.ftl @@ -0,0 +1,3 @@ +cmd-stealthmin-desc = Toggle whether others can see you in adminwho. +cmd-stealthmin-help = Usage: stealthmin\nUse stealthmin to toggle whether you appear in the output of the adminwho command. +cmd-stealthmin-no-console = You cannot use this command from the server console. diff --git a/Resources/Locale/en-US/administration/managers/admin-manager.ftl b/Resources/Locale/en-US/administration/managers/admin-manager.ftl index b1bbcc4c8c..b70f550fc3 100644 --- a/Resources/Locale/en-US/administration/managers/admin-manager.ftl +++ b/Resources/Locale/en-US/administration/managers/admin-manager.ftl @@ -6,4 +6,8 @@ admin-manager-no-longer-admin-message = You are no longer an admin. admin-manager-admin-permissions-updated-message = Your admin permission have been updated. admin-manager-admin-logout-message = Admin logout: {$name} admin-manager-admin-login-message = Admin login: {$name} -admin-manager-admin-data-host-title = Host \ No newline at end of file +admin-manager-admin-data-host-title = Host +admin-manager-stealthed-message = You are now a hidden admin. +admin-manager-unstealthed-message = You are no longer hidden. +admin-manager-self-enable-stealth = {$stealthAdminName} is now hidden. +admin-manager-self-disable-stealth = {$exStealthAdminName} is no longer hidden. diff --git a/Resources/Locale/en-US/cargo/bounties.ftl b/Resources/Locale/en-US/cargo/bounties.ftl index 63c68de105..b332517c70 100644 --- a/Resources/Locale/en-US/cargo/bounties.ftl +++ b/Resources/Locale/en-US/cargo/bounties.ftl @@ -47,8 +47,24 @@ bounty-item-organs = Organ bounty-item-labeler = Hand labeler bounty-item-warm-cloth = Warm clothes bounty-item-battery = Battery -bounty-lasergun = Laser gun -bounty-food = Meat food +bounty-item-lasergun = Laser gun +bounty-item-food = Meat food +bounty-item-fruit = Fruit +bounty-item-vegetable = Vegetable +bounty-item-chili = Bowl of chili +bounty-item-rollerskates = Roller skates +bounty-item-bedsheet = Bedsheet +bounty-item-bandana = Bandana +bounty-item-steak = Steak +bounty-item-banana = Banana +bounty-item-beer = Beer +bounty-item-hi-viz-vest = Hi-viz vest +bounty-item-torch = Torch +bounty-item-medkit-box = Medkit box +bounty-item-cardboard-box = Cardboard box +bounty-item-wine = Wine bottle +bounty-item-cotton-boll = Cotton boll +bounty-item-microwave-machine-board = Microwave machine board bounty-description-artifact = NanoTrasen is in some hot water for stealing artifacts from non-spacefaring planets. Return one and we'll compensate you for it. bounty-description-baseball-bat = Baseball fever is going on at CentCom! Be a dear and ship them some baseball bats, so that management can live out their childhood dream. @@ -100,3 +116,19 @@ bounty-description-warm-cloth = The Unath construction crew freezes and is unabl bounty-description-battery = As the Arachnid settlement prepares for a solar flare, they are requesting a large shipment of power batteries. We're sending out a request for delivery. bounty-description-lasergun = The Salvage Caravan requests a large shipment of laser weapons to mop up a hive of xenomorphs. bounty-description-food = After the rat king invasion, a neighboring unathi station was left completely without food. A large meat food shipment is needed. +bounty-description-fruit = A heroic monkey helped the chaplain catch a troublemaker hiding in the chapel, and the crew wants to reward him for his good work. +bounty-description-vegetable = The new chef is a vegetarian, and botany can't keep up with their demands. We need some additional veggies to help keep things stocked. +bounty-description-chili = Today's the Centcomm Chili Cookoff, and, well, a few of us forgot to make some. Please help cover for us. +bounty-description-rollerskates = CentComm Security is proposing a new strategy for helping officers win foot pursuits. Send them a couple so they cna learn how bad an idea this is. +bounty-description-bedsheet = Someone in Atmos keeps turning down the heater, and we're all shivering in our beds. Please send us some extra sheets to stay warm. +bounty-description-bandana = Bzzzt... Transmission from prison planet OC-1001: We're... reorganizing our command structure. Send us some bandanas so we can tell gan- I mean, departments apart. +bounty-description-steak = The vegetarian cook is refusing to make us anything with meat, and the lizards are getting restless. Can you smuggle us a few steaks to keep them happy? +bounty-description-banana = Hi station! Botany won't gimme any more. They said slipping the HoS out an open airlock wasn't funny! Can you believe it? Help me out! HONK. +bounty-description-beer = Some nefarious agent has stolen every single drink in the bar. Yes, everything. Help tide us over until we can find them. +bounty-description-hi-viz-vest = The clown stole the AME controller and won't back. It's pretty dark in here. Some hi-viz vests would make seeing each other in the dark a little mroe bearable. +bounty-description-torch = The chef made all the monkeys and kobolds at once, and they rebelled and took over the cargo shuttle. They're demanding supplies and free passage to a jungle planet, and we're giving in to their demands. All they need now is a few torches. +bounty-description-medkit-box = CentComm is putting on a play set in a hospital, and needs some props. Just send us some empty medkit boxes, and the show will go on! +bounty-description-cardobard-box = "The Cardborgs Cometh" is a new play premiering tomorrow, and the costuming team is woefully unprepared. Send us some boxes to work with. +bounty-description-wine = The new librarian and the Quartermaster are falling head over heels for each other after she caught him disassembling the bookshelves for wood. Send a couple bottles of wine (Or cans, if you must) to help make the date go well. +bounty-description-cotton-boll = A massive swarm of mothroaches ate all the paper and cloth on the station. Send us some cotton to help keep our winged crewmembers fed. +bounty-description-microwave-machine-board = Mr. Giggles thought it'd be funny to stick forks in all the kitchen microwaves. Help us replace them before the chefs start making clown burgers. diff --git a/Resources/Locale/en-US/chat/managers/chat-manager.ftl b/Resources/Locale/en-US/chat/managers/chat-manager.ftl index fab815b4f9..2c8b326b07 100644 --- a/Resources/Locale/en-US/chat/managers/chat-manager.ftl +++ b/Resources/Locale/en-US/chat/managers/chat-manager.ftl @@ -21,11 +21,11 @@ chat-manager-whisper-headset-on-message = You can't whisper on the radio! chat-manager-server-wrap-message = [bold]{$message}[/bold] chat-manager-sender-announcement-wrap-message = [font size=14][bold]{$sender} Announcement:[/font][font size=12] {$message}[/bold][/font] -chat-manager-entity-say-wrap-message = [BubbleHeader][Name]{$entityName}[/Name][/BubbleHeader] {$verb}, [font={$fontType} size={$fontSize}]"[BubbleContent]{$message}[/BubbleContent]"[/font] -chat-manager-entity-say-bold-wrap-message = [BubbleHeader][Name]{$entityName}[/Name][/BubbleHeader] {$verb}, [font={$fontType} size={$fontSize}]"[BubbleContent][bold]{$message}[/bold][/BubbleContent]"[/font] +chat-manager-entity-say-wrap-message = [BubbleHeader][Name]{$entityName}[/Name][/BubbleHeader] {$verb}, [font="{$fontType}" size={$fontSize}]"[color={$color}][BubbleContent]{$message}[/BubbleContent][/color]"[/font] +chat-manager-entity-say-bold-wrap-message = [BubbleHeader][Name]{$entityName}[/Name][/BubbleHeader] {$verb}, [font="{$fontType}" size={$fontSize}]"[color={$color}][BubbleContent][bold]{$message}[/bold][/BubbleContent][/color]"[/font] -chat-manager-entity-whisper-wrap-message = [font size=11][italic][BubbleHeader][Name]{$entityName}[/Name][/BubbleHeader] whispers,"[BubbleContent]{$message}[/BubbleContent]"[/italic][/font] -chat-manager-entity-whisper-unknown-wrap-message = [font size=11][italic][BubbleHeader]Someone[/BubbleHeader] whispers, "[BubbleContent]{$message}[/BubbleContent]"[/italic][/font] +chat-manager-entity-whisper-wrap-message = [font size=11][italic][BubbleHeader][Name]{$entityName}[/Name][/BubbleHeader] whispers,"[color={$color}][BubbleContent]{$message}[/BubbleContent][/color]"[/italic][/font] +chat-manager-entity-whisper-unknown-wrap-message = [font size=11][italic][BubbleHeader]Someone[/BubbleHeader] whispers, "[color={$color}][BubbleContent]{$message}[/BubbleContent][/color]"[/italic][/font] # THE() is not used here because the entity and its name can technically be disconnected if a nameOverride is passed... chat-manager-entity-me-wrap-message = [italic]{ PROPER($entity) -> diff --git a/Resources/Locale/en-US/door-remote/door-remote.ftl b/Resources/Locale/en-US/door-remote/door-remote.ftl index bf2fc11861..2c4ccd0805 100644 --- a/Resources/Locale/en-US/door-remote/door-remote.ftl +++ b/Resources/Locale/en-US/door-remote/door-remote.ftl @@ -1,3 +1,12 @@ +## UI +door-remote-open-close-text = Opens and Closes Doors +door-remote-toggle-bolt-text = Toggles Bolts +door-remote-emergency-access-text = Toggles Emergency Access +door-remote-invalid-text = Invalid +door-remote-mode-label = Mode: [color=white]{$modeString}[/color] + +## Entity + door-remote-switch-state-open-close = You switch the remote to open and close doors door-remote-switch-state-toggle-bolts = You switch the remote to toggle bolts door-remote-switch-state-toggle-emergency-access = You switch the remote to toggle emergency access diff --git a/Resources/Locale/en-US/game-ticking/game-presets/preset-survival.ftl b/Resources/Locale/en-US/game-ticking/game-presets/preset-survival.ftl index 231733eabf..0b8fa83ae8 100644 --- a/Resources/Locale/en-US/game-ticking/game-presets/preset-survival.ftl +++ b/Resources/Locale/en-US/game-ticking/game-presets/preset-survival.ftl @@ -1,2 +1,5 @@ survival-title = Survival survival-description = No internal threats, but how long can the station survive increasingly chaotic and frequent events? + +hellshift-title = Hellshift +hellshift-description = The station rolled a "one" in a luck check. Can the crew make it to the end? diff --git a/Resources/Locale/en-US/headset/headset-component.ftl b/Resources/Locale/en-US/headset/headset-component.ftl index a220737f18..75c83643d6 100644 --- a/Resources/Locale/en-US/headset/headset-component.ftl +++ b/Resources/Locale/en-US/headset/headset-component.ftl @@ -1,6 +1,6 @@ # Chat window radio wrap (prefix and postfix) -chat-radio-message-wrap = [color={$color}]{$channel} {$name} {$verb}, [font={$fontType} size={$fontSize}]"{$message}"[/font][/color] -chat-radio-message-wrap-bold = [color={$color}]{$channel} {$name} {$verb}, [font={$fontType} size={$fontSize}][bold]"{$message}"[/bold][/font][/color] +chat-radio-message-wrap = [color={$color}]{$channel} {$name} {$verb}, [font="{$fontType}" size={$fontSize}]"[/color][color={$languageColor}]{$message}[/color][color={$color}]"[/font][/color] +chat-radio-message-wrap-bold = [color={$color}]{$channel} {$name} {$verb}, [font="{$fontType}" size={$fontSize}][bold]"[/color][color={$languageColor}]{$message}[/color][color={$color}]"[/bold][/font][/color] examine-headset-default-channel = Use {$prefix} for the default channel ([color={$color}]{$channel}[/color]). diff --git a/Resources/Locale/en-US/language/translator.ftl b/Resources/Locale/en-US/language/translator.ftl index b2a1e9b2b8..8070d03be2 100644 --- a/Resources/Locale/en-US/language/translator.ftl +++ b/Resources/Locale/en-US/language/translator.ftl @@ -1,8 +1,13 @@ translator-component-shutoff = The {$translator} shuts off. translator-component-turnon = The {$translator} turns on. -translator-enabled = It appears to be active. -translator-disabled = It appears to be disabled. translator-implanter-refuse = The {$implanter} has no effect on {$target}. translator-implanter-success = The {$implanter} successfully injected {$target}. translator-implanter-ready = This implanter appears to be ready to use. translator-implanter-used = This implanter seems empty. + +translator-examined-langs-understood = It can translate from: [color=green]{$languages}[/color]. +translator-examined-langs-spoken = It can translate to: [color=green]{$languages}[/color]. +translator-examined-requires-any = It requires you to know at least one of these languages: [color=yellow]{$languages}[/color]. +translator-examined-requires-all = It requires you to know all of these languages: [color=yellow]{$languages}[/color]. +translator-examined-enabled = It appears to be [color=green]active[/color]. +translator-examined-disabled = It appears to be [color=red]turned off[/color]. diff --git a/Resources/Locale/en-US/store/categories.ftl b/Resources/Locale/en-US/store/categories.ftl index 437fc03ae0..b6abc3e428 100644 --- a/Resources/Locale/en-US/store/categories.ftl +++ b/Resources/Locale/en-US/store/categories.ftl @@ -12,6 +12,7 @@ store-category-implants = Implants store-category-job = Job store-category-armor = Armor store-category-pointless = Pointless +store-category-deception = Deception # Revenant store-category-abilities = Abilities diff --git a/Resources/Locale/en-US/store/uplink-catalog.ftl b/Resources/Locale/en-US/store/uplink-catalog.ftl index 4836a57d6b..592cf59d2f 100644 --- a/Resources/Locale/en-US/store/uplink-catalog.ftl +++ b/Resources/Locale/en-US/store/uplink-catalog.ftl @@ -109,6 +109,9 @@ uplink-holoclown-kit-desc = A joint venture between Cybersun and Honk.co. Contai uplink-holster-name = Shoulder Holster uplink-holster-desc = A deep shoulder holster capable of holding many types of ballistics. +uplink-chest-rig-name = Chest Rig +uplink-chest-rig-desc = Explosion-resistant tactical webbing used for holding traitor goods. + uplink-emag-name = Emag uplink-emag-desc = The business card of the syndicate, this sequencer is able to break open airlocks and tamper with a variety of station devices. Recharges automatically. diff --git a/Resources/Locale/en-US/traits/traits.ftl b/Resources/Locale/en-US/traits/traits.ftl index 80d98a1b3e..24f5f47127 100644 --- a/Resources/Locale/en-US/traits/traits.ftl +++ b/Resources/Locale/en-US/traits/traits.ftl @@ -63,3 +63,13 @@ trait-name-Thieving = Thieving trait-description-Thieving = You are deft with your hands, and talented at convincing people of their belongings. You can identify pocketed items, steal them quieter, and steal ~33% faster. + +trait-name-ForeignerLight = Foreigner (light) +trait-description-ForeignerLight = + You struggle to learn this station's primary language, and as such, cannot speak it. You can, however, comprehend what others say in that language. + To help you overcome this obstacle, you are equipped with a translator that helps you speak in this station's primary language. + +trait-name-Foreigner = Foreigner +trait-description-Foreigner = + For one reason or another you do not speak this station's primary language. + Instead, you have a translator issued to you that only you can use. diff --git a/Resources/Prototypes/Catalog/Bounties/bounties.yml b/Resources/Prototypes/Catalog/Bounties/bounties.yml index 62a3a4162f..c8c35aabfe 100644 --- a/Resources/Prototypes/Catalog/Bounties/bounties.yml +++ b/Resources/Prototypes/Catalog/Bounties/bounties.yml @@ -347,11 +347,11 @@ - type: cargoBounty id: BountyRadio - reward: 7500 + reward: 6500 description: bounty-description-radio entries: - name: bounty-item-radio - amount: 12 + amount: 7 whitelist: components: - Headset @@ -536,7 +536,7 @@ description: bounty-description-lasergun idPrefix: IV entries: - - name: bounty-lasergun + - name: bounty-item-lasergun amount: 6 whitelist: components: @@ -548,8 +548,185 @@ description: bounty-description-food idPrefix: UNTH entries: - - name: bounty-food + - name: bounty-item-food amount: 30 whitelist: tags: - Meat + +- type: cargoBounty + id: BountyFruit + reward: 5000 + description: bounty-description-fruit + entries: + - name: bounty-item-fruit + amount: 12 + whitelist: + tags: + - Fruit + +- type: cargoBounty + id: BountyVegetable + reward: 6000 + description: bounty-description-vegetable + entries: + - name: bounty-item-vegetable + amount: 14 + whitelist: + tags: + - Vegetable + +- type: cargoBounty + id: BountyChili + reward: 5555 + description: bounty-description-chili + entries: + - name: bounty-item-chili + amount: 3 + whitelist: + tags: + - ChiliBowl + +- type: cargoBounty + id: BountyRollerskates + reward: 6500 + description: bounty-description-rollerskates + entries: + - name: bounty-item-rollerskates + amount: 2 + whitelist: + components: + - Skates + +- type: cargoBounty + id: BountyBedsheet + reward: 4100 + description: bounty-description-bedsheet + entries: + - name: bounty-item-bedsheet + amount: 5 + whitelist: + tags: + - Bedsheet + +- type: cargoBounty + id: BountyBandana + reward: 4000 + description: bounty-description-bandana + entries: + - name: bounty-item-bandana + amount: 7 + whitelist: + tags: + - Bandana + +- type: cargoBounty + id: BountySteak + reward: 3200 + description: bounty-description-steak + entries: + - name: bounty-item-steak + amount: 4 + whitelist: + tags: + - Steak + +- type: cargoBounty + id: BountyBanana + reward: 6009 + description: bounty-description-banana + entries: + - name: bounty-item-banana + amount: 9 + whitelist: + tags: + - Banana + +- type: cargoBounty + id: BountyBeer + reward: 3100 + description: bounty-description-beer + entries: + - name: bounty-item-beer + amount: 6 + whitelist: + tags: + - Beer + +- type: cargoBounty + id: BountyHiVizVest + reward: 3030 + description: bounty-description-hi-viz-vest + entries: + - name: bounty-item-hi-viz-vest + amount: 3 + whitelist: + tags: + - HiViz + +- type: cargoBounty + id: BountyTorch + reward: 2220 + description: bounty-description-torch + entries: + - name: bounty-item-torch + amount: 6 + whitelist: + tags: + - Torch + +- type: cargoBounty + id: BountyMedkitBox + reward: 2300 + description: bounty-description-medkit-box + entries: + - name: bounty-item-medkit-box + amount: 4 + whitelist: + tags: + - Medkit + +- type: cargoBounty + id: BountyCardboardBox + reward: 1500 + description: bounty-description-cardobard-box + entries: + - name: bounty-item-cardboard-box + amount: 12 + whitelist: + tags: + - BoxCardboard + +- type: cargoBounty + id: BountyWine + reward: 3000 + description: bounty-description-wine + entries: + - name: bounty-item-wine + amount: 2 + whitelist: + tags: + - Wine + +- type: cargoBounty + id: BountyCottonBoll + reward: 8600 + description: bounty-description-cotton-boll + entries: + - name: bounty-item-cotton-boll + amount: 9 + whitelist: + tags: + - CottonBoll + +- type: cargoBounty + id: BountyMicrowaveMachineBoard + reward: 4000 + description: bounty-description-microwave-machine-board + entries: + - name: bounty-item-microwave-machine-board + amount: 2 + whitelist: + tags: + - MicrowaveMachineBoard + diff --git a/Resources/Prototypes/Catalog/Fills/Boxes/general.yml b/Resources/Prototypes/Catalog/Fills/Boxes/general.yml index 0c810a52f5..d6e2c45939 100644 --- a/Resources/Prototypes/Catalog/Fills/Boxes/general.yml +++ b/Resources/Prototypes/Catalog/Fills/Boxes/general.yml @@ -20,6 +20,9 @@ sound: /Audio/SimpleStation14/Items/Handling/cardboardbox_drop.ogg - type: EmitSoundOnLand sound: /Audio/SimpleStation14/Items/Handling/cardboardbox_drop.ogg + - type: Tag + tags: + - BoxCardboard - type: entity name: mousetrap box diff --git a/Resources/Prototypes/Catalog/Fills/Crates/fun.yml b/Resources/Prototypes/Catalog/Fills/Crates/fun.yml index cc5e3b1d17..26d0f47315 100644 --- a/Resources/Prototypes/Catalog/Fills/Crates/fun.yml +++ b/Resources/Prototypes/Catalog/Fills/Crates/fun.yml @@ -30,6 +30,7 @@ amount: 2 - id: PlushieArachind - id: PlushiePenguin + - id: PlushieArachne - type: entity id: CrateFunLizardPlushieBulk diff --git a/Resources/Prototypes/Catalog/uplink_catalog.yml b/Resources/Prototypes/Catalog/uplink_catalog.yml index a8ebd6e2ba..60fa6c15fd 100644 --- a/Resources/Prototypes/Catalog/uplink_catalog.yml +++ b/Resources/Prototypes/Catalog/uplink_catalog.yml @@ -265,16 +265,6 @@ tags: - NukeOpsUplink -- type: listing - id: UplinkSyndicateBombFake - name: uplink-exploding-syndicate-bomb-fake-name - description: uplink-exploding-syndicate-bomb-fake-desc - productEntity: SyndicateBombFake - cost: - Telecrystal: 4 - categories: - - UplinkExplosives - - type: listing id: UplinkClusterGrenade name: uplink-cluster-grenade-name @@ -787,7 +777,19 @@ cost: Telecrystal: 6 categories: - - UplinkBundles + - UplinkBundles + +- type: listing + id: UplinkSyndicateBombFake + name: uplink-exploding-syndicate-bomb-fake-name + description: uplink-exploding-syndicate-bomb-fake-desc + productEntity: SyndicateBombFake + cost: + Telecrystal: 4 + categories: + - UplinkDeception + +# Disruption - type: listing id: UplinkAmmoBundle @@ -1239,6 +1241,16 @@ # Armor +- type: listing + id: UplinkChestRig + name: uplink-chest-rig-name + description: uplink-chest-rig-desc + productEntity: ClothingBeltMilitaryWebbing + cost: + Telecrystal: 1 + categories: + - UplinkArmor + - type: listing id: UplinkChameleon name: uplink-chameleon-name diff --git a/Resources/Prototypes/DeltaV/Entities/Markers/Spawners/Random/miningrock.yml b/Resources/Prototypes/DeltaV/Entities/Markers/Spawners/Random/miningrock.yml index f4aef8284b..204901d8bd 100644 --- a/Resources/Prototypes/DeltaV/Entities/Markers/Spawners/Random/miningrock.yml +++ b/Resources/Prototypes/DeltaV/Entities/Markers/Spawners/Random/miningrock.yml @@ -17,14 +17,17 @@ - Barricade - MountainRockMining - MountainRock - - RandomCrystalSpawner + - RandomStalagmiteOrCrystal - RandomWallRockSpawner - RandomBasaltRockSpawner + - AsteroidRockOreCrab + - RandomWoodenStructure rareChance: 0.15 - type: entity name: Crystal Spawner id: RandomCrystalSpawner + suffix: 100% parent: MarkerBase components: - type: Sprite @@ -81,4 +84,19 @@ - WallRockBasaltTin - WallRockBasaltUranium - WallRockBasaltArtifactFragment -#Might add chance for no crystal later?? + +- type: entity + id: RandomWoodenStructure + name: wooden wall or support spawner + parent: MarkerBase + components: + - type: Sprite + layers: + - state: red + - sprite: Objects/Decoration/mines.rsi + state: support_wall_broken + - type: RandomSpawner + prototypes: + - RandomWoodenWall + - RandomWoodenSupport + chance: 0.9 diff --git a/Resources/Prototypes/DeltaV/Entities/Structures/Walls/mountain.yml b/Resources/Prototypes/DeltaV/Entities/Structures/Walls/mountain.yml index 43d5675171..575687336a 100644 --- a/Resources/Prototypes/DeltaV/Entities/Structures/Walls/mountain.yml +++ b/Resources/Prototypes/DeltaV/Entities/Structures/Walls/mountain.yml @@ -69,7 +69,7 @@ id: MountainRock parent: BaseStructure name: mountain rock - suffix: un-mineable + suffix: Un-mineable description: A craggy mountain wall. It is too hard to mine. components: - type: Sprite @@ -107,7 +107,7 @@ id: AsteroidAltRockMining parent: AsteroidAltRock name: asteroid rock - suffix: higher ore yield + suffix: Higher Ore Yield description: A rocky asteroid. components: - type: Gatherable @@ -117,3 +117,14 @@ - type: OreVein oreChance: 0.33 oreRarityPrototypeId: RandomOreDistributionStandard + +- type: entity + id: AsteroidRockOreCrab + parent: AsteroidAltRock + name: asteroid rock + suffix: Ore Crab + description: A rocky asteroid. + components: + - type: OreVein + oreChance: 0.33 + oreRarityPrototypeId: OreCrab diff --git a/Resources/Prototypes/Entities/Clothing/Head/bandanas.yml b/Resources/Prototypes/Entities/Clothing/Head/bandanas.yml index 8ee6479ee6..51a56f1f1d 100644 --- a/Resources/Prototypes/Entities/Clothing/Head/bandanas.yml +++ b/Resources/Prototypes/Entities/Clothing/Head/bandanas.yml @@ -20,6 +20,9 @@ - state: icon_mask map: [ "unfoldedLayer" ] visible: false + - type: Tag + tags: + - Bandana - type: entity parent: [ClothingHeadBandBase, ClothingMaskBandBlack] @@ -69,4 +72,4 @@ - type: entity parent: [ClothingHeadBandBase, ClothingMaskBandBrown] id: ClothingHeadBandBrown - name: brown bandana \ No newline at end of file + name: brown bandana diff --git a/Resources/Prototypes/Entities/Clothing/Masks/bandanas.yml b/Resources/Prototypes/Entities/Clothing/Masks/bandanas.yml index 2d65e67982..246b47b800 100644 --- a/Resources/Prototypes/Entities/Clothing/Masks/bandanas.yml +++ b/Resources/Prototypes/Entities/Clothing/Masks/bandanas.yml @@ -24,6 +24,7 @@ visible: false - type: Tag tags: + - Bandana - HidesNose - type: entity diff --git a/Resources/Prototypes/Entities/Clothing/OuterClothing/vests.yml b/Resources/Prototypes/Entities/Clothing/OuterClothing/vests.yml index f49f5f4804..b867abfeed 100644 --- a/Resources/Prototypes/Entities/Clothing/OuterClothing/vests.yml +++ b/Resources/Prototypes/Entities/Clothing/OuterClothing/vests.yml @@ -63,6 +63,9 @@ sprite: Clothing/OuterClothing/Vests/hazard.rsi - type: Clothing sprite: Clothing/OuterClothing/Vests/hazard.rsi + - type: Tag + tags: + - HiViz #(Bartender) vest - type: entity diff --git a/Resources/Prototypes/Entities/Clothing/Shoes/boots.yml b/Resources/Prototypes/Entities/Clothing/Shoes/boots.yml index 241fc45352..fdc49dc061 100644 --- a/Resources/Prototypes/Entities/Clothing/Shoes/boots.yml +++ b/Resources/Prototypes/Entities/Clothing/Shoes/boots.yml @@ -202,7 +202,7 @@ - type: FootstepModifier footstepSoundCollection: collection: FootstepSpurs - + - type: entity parent: ClothingShoesBootsCowboyBrown id: ClothingShoesBootsCowboyBlack @@ -212,7 +212,7 @@ sprite: Clothing/Shoes/Boots/cowboybootsblack.rsi - type: Clothing sprite: Clothing/Shoes/Boots/cowboybootsblack.rsi - + - type: entity parent: ClothingShoesBootsCowboyBrown id: ClothingShoesBootsCowboyWhite @@ -222,7 +222,7 @@ sprite: Clothing/Shoes/Boots/cowboybootswhite.rsi - type: Clothing sprite: Clothing/Shoes/Boots/cowboybootswhite.rsi - + - type: entity parent: ClothingShoesBootsCowboyBrown id: ClothingShoesBootsCowboyFancy @@ -231,4 +231,4 @@ - type: Sprite sprite: Clothing/Shoes/Boots/cowboybootsfancy.rsi - type: Clothing - sprite: Clothing/Shoes/Boots/cowboybootsfancy.rsi \ No newline at end of file + sprite: Clothing/Shoes/Boots/cowboybootsfancy.rsi diff --git a/Resources/Prototypes/Entities/Markers/Spawners/Random/toy.yml b/Resources/Prototypes/Entities/Markers/Spawners/Random/toy.yml index eba1e300ed..d12b85cde4 100644 --- a/Resources/Prototypes/Entities/Markers/Spawners/Random/toy.yml +++ b/Resources/Prototypes/Entities/Markers/Spawners/Random/toy.yml @@ -36,6 +36,7 @@ - PlushieMoth - PlushieMothRandom # Nyanotrasen Random Moth Plushies - PlushieArachind + - PlushieArachne chance: 0.5 offset: 0.2 diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks.yml b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks.yml index 06b0e6fad8..17e2a4df5e 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks.yml @@ -375,6 +375,9 @@ - type: Icon sprite: Objects/Consumable/Drinks/beerglass.rsi state: icon + - type: Tag + tags: + - Beer - type: entity parent: DrinkGlass @@ -949,6 +952,9 @@ - type: Icon sprite: Objects/Consumable/Drinks/iced_beerglass.rsi state: icon + - type: Tag + tags: + - Beer - type: entity parent: DrinkGlass diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_bottles.yml b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_bottles.yml index 07828ff5ba..face999df8 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_bottles.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_bottles.yml @@ -355,6 +355,9 @@ - type: Sprite sprite: Objects/Consumable/Drinks/pwinebottle.rsi - type: Sealable + - type: Tag + tags: + - Wine - type: entity parent: [DrinkBottleVisualsAll, DrinkBottleGlassBaseFull] @@ -501,6 +504,9 @@ - type: Sprite sprite: Objects/Consumable/Drinks/winebottle.rsi - type: Sealable + - type: Tag + tags: + - Wine # Small Bottles @@ -523,6 +529,9 @@ sprite: Objects/Consumable/Drinks/beer.rsi - type: Openable closeable: false + - type: Tag + tags: + - Beer - type: entity parent: [DrinkBottleVisualsAll, DrinkBottleGlassBaseFull] @@ -543,6 +552,9 @@ sprite: Objects/Consumable/Drinks/beer.rsi - type: Openable closeable: false + - type: Tag + tags: + - Beer - type: entity diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_cans.yml b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_cans.yml index b7e3aa3a48..192be68c8c 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_cans.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_cans.yml @@ -188,6 +188,9 @@ sprite: Objects/Consumable/Drinks/rootbeer.rsi - type: Item sprite: Objects/Consumable/Drinks/rootbeer.rsi + - type: Tag + tags: + - Beer - type: entity parent: DrinkCanBaseFull @@ -486,6 +489,9 @@ sprite: Objects/Consumable/Drinks/beer_can.rsi - type: Item sprite: Objects/Consumable/Drinks/beer_can.rsi + - type: Tag + tags: + - Beer - type: entity parent: DrinkCanBaseFull @@ -505,3 +511,6 @@ sprite: Objects/Consumable/Drinks/wine_can.rsi - type: Item sprite: Objects/Consumable/Drinks/wine_can.rsi + - type: Tag + tags: + - Wine diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/Baked/pie.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/Baked/pie.yml index fe88859584..8cd1c5dfab 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/Baked/pie.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/Baked/pie.yml @@ -156,6 +156,8 @@ path: /Audio/Weapons/Guns/Empty/empty.ogg ejectSound: path: /Audio/Weapons/Guns/Empty/empty.ogg + swap: false + disableEject: true - type: Tag tags: - Fruit diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/meat.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/meat.yml index 85de407988..58af9cf3bd 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/meat.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/meat.yml @@ -718,6 +718,7 @@ tags: - Cooked - Meat + - Steak - type: Sprite layers: - state: plain-cooked @@ -774,6 +775,7 @@ tags: - Cooked - Meat + - Steak - type: Sprite layers: - state: product-cooked @@ -942,6 +944,7 @@ tags: - Cooked - Meat + - Steak - type: Sprite layers: - state: goliath-cooked @@ -971,6 +974,7 @@ tags: - Cooked - Meat + - Steak - type: Sprite layers: - state: rouny-cooked @@ -996,6 +1000,7 @@ tags: - Cooked - Meat + - Steak - type: Sprite layers: - state: lizard-cooked diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/produce.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/produce.yml index eec7711d4a..21eb0fb942 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/produce.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/produce.yml @@ -124,6 +124,9 @@ sprite: Objects/Specific/Hydroponics/laughin_pea.rsi - type: Produce seedId: laughinPea + - type: Tag + tags: + - Vegetable - type: entity name: tower-cap log @@ -258,6 +261,7 @@ - type: Tag tags: - Fruit + - Banana - type: entity name: mimana @@ -413,6 +417,7 @@ - type: Tag tags: - Carrot + - Vegetable - type: SolutionContainerManager solutions: food: @@ -458,6 +463,9 @@ sprite: Objects/Specific/Hydroponics/cabbage.rsi - type: Produce seedId: cabbage + - type: Tag + tags: + - Vegetable - type: entity name: garlic @@ -483,6 +491,9 @@ sprite: Objects/Specific/Hydroponics/garlic.rsi - type: Produce seedId: garlic + - type: Tag + tags: + - Vegetable - type: entity name: lemon @@ -658,6 +669,8 @@ - type: Tag tags: - Potato + - Vegetable + - type: entity name: tomato @@ -712,6 +725,7 @@ - type: Tag tags: - Fruit + - Vegetable - type: entity name: blue tomato @@ -756,6 +770,7 @@ - type: Tag tags: - Fruit + - Vegetable - type: entity name: blood tomato @@ -798,6 +813,7 @@ - type: Tag tags: - Fruit # Fuck you they're a fruit + - Vegetable - type: entity name: eggplant @@ -824,6 +840,7 @@ - type: Tag tags: - Fruit + - Vegetable - type: entity name: apple @@ -912,6 +929,7 @@ - type: Tag tags: - Corn + - Vegetable - type: Sprite sprite: Objects/Specific/Hydroponics/corn.rsi - type: Produce @@ -974,6 +992,9 @@ - type: SliceableFood count: 5 slice: FoodOnionSlice + - type: Tag + tags: + - Vegetable - type: entity name: red onion @@ -1002,6 +1023,9 @@ - type: SliceableFood count: 5 slice: FoodOnionRedSlice + - type: Tag + tags: + - Vegetable - type: entity name: chanterelle cluster @@ -1019,6 +1043,9 @@ sprite: Objects/Specific/Hydroponics/chanterelle.rsi - type: Produce seedId: chanterelle + - type: Tag + tags: + - Vegetable # Slices @@ -1129,6 +1156,9 @@ sprite: Objects/Specific/Hydroponics/chili.rsi - type: Produce seedId: chili + - type: Tag + tags: + - Vegetable - type: entity name: chilly pepper @@ -1180,6 +1210,9 @@ seedId: aloe - type: Extractable grindableSolutionName: food + - type: Tag + tags: + - Vegetable - type: entity name: poppy @@ -1459,6 +1492,9 @@ reagents: - ReagentId: MilkSoy Quantity: 5 + - type: Tag + tags: + - Vegetable - type: entity name: spaceman's trumpet @@ -1512,6 +1548,9 @@ reagents: - ReagentId: CarpoToxin Quantity: 2 + - type: Tag + tags: + - Vegetable - type: entity name: watermelon @@ -1604,9 +1643,6 @@ reagents: - ReagentId: JuiceWatermelon Quantity: 4 - - type: Tag - tags: - - Fruit - type: entity name: grapes @@ -1635,6 +1671,9 @@ reagents: - ReagentId: JuiceGrape Quantity: 10 + - type: Tag + tags: + - Fruit - type: entity name: berries @@ -1707,7 +1746,6 @@ tags: - Recyclable - Trash - - Fruit - type: SolutionContainerManager solutions: food: @@ -1746,6 +1784,9 @@ sprite: Objects/Specific/Hydroponics/pea.rsi - type: Produce seedId: pea + - type: Tag + tags: + - Vegetable - type: entity name: pumpkin @@ -1794,6 +1835,7 @@ - type: Tag tags: - Fruit + - Vegetable - type: entity name: cotton boll @@ -1822,3 +1864,4 @@ - type: Tag tags: - ClothMade + - CottonBoll diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/soup.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/soup.yml index 3b080e843b..6b96f3bcb3 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/soup.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/soup.yml @@ -806,6 +806,10 @@ Quantity: 4 - ReagentId: Allicin Quantity: 3 + - type: Tag + tags: + - ChiliBowl + - type: entity name: cold chili @@ -830,6 +834,9 @@ Quantity: 8 - ReagentId: Vitamin Quantity: 4 + - type: Tag + tags: + - ChiliBowl - type: entity name: chili con carnival @@ -860,6 +867,9 @@ Quantity: 4 - ReagentId: Allicin Quantity: 3 + - type: Tag + tags: + - ChiliBowl - type: entity name: monkey's delight diff --git a/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/production.yml b/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/production.yml index c2a1fe6e7d..4cd8a85099 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/production.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/production.yml @@ -1175,9 +1175,9 @@ materialRequirements: Glass: 2 Cable: 2 - - type: ReverseEngineering # Nyano - recipes: - - MicrowaveMachineCircuitboard + - type: Tag + tags: + - MicrowaveMachineBoard - type: entity id: FatExtractorMachineCircuitboard @@ -1433,7 +1433,7 @@ materialRequirements: Steel: 5 CableHV: 5 - + - type: entity id: ShuttleGunPerforatorCircuitboard parent: BaseMachineCircuitboard @@ -1450,7 +1450,7 @@ materialRequirements: Steel: 10 CableHV: 5 - + - type: entity id: ShuttleGunFriendshipCircuitboard parent: BaseMachineCircuitboard @@ -1466,8 +1466,8 @@ Manipulator: 2 materialRequirements: Steel: 7 - CableHV: 5 - + CableHV: 5 + - type: entity id: ShuttleGunDusterCircuitboard parent: BaseMachineCircuitboard @@ -1485,7 +1485,7 @@ Steel: 10 CableHV: 5 Uranium: 2 - + - type: entity id: ShuttleGunKineticCircuitboard parent: BaseMachineCircuitboard @@ -1502,4 +1502,3 @@ materialRequirements: Steel: 5 CableHV: 2 - \ No newline at end of file diff --git a/Resources/Prototypes/Entities/Objects/Devices/translators.yml b/Resources/Prototypes/Entities/Objects/Devices/translators.yml index 664626ea4b..b28541253d 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/translators.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/translators.yml @@ -1,5 +1,5 @@ - type: entity - abstract: true + noSpawn: true id: TranslatorUnpowered parent: BaseItem name: translator @@ -23,9 +23,14 @@ False: { visible: false } - type: HandheldTranslator enabled: false + - type: Clothing # To allow equipping translators on the neck slot + slots: [neck, pocket] + equipDelay: 0.3 + unequipDelay: 0.3 + quickEquip: false # Would conflict - type: entity - abstract: true + noSpawn: true id: Translator parent: [ TranslatorUnpowered, PowerCellSlotMediumItem ] suffix: Powered @@ -34,7 +39,7 @@ drawRate: 1 - type: entity - abstract: true + noSpawn: true id: TranslatorEmpty parent: Translator suffix: Empty @@ -44,6 +49,13 @@ cell_slot: name: power-cell-slot-component-slot-name-default +- type: entity + noSpawn: true + id: TranslatorForeigner + parent: [ Translator, PowerCellSlotHighItem ] + name: foreigner's translator + description: A special-issue translator that helps foreigner's speak and understand this station's primary language. + - type: entity id: CanilunztTranslator diff --git a/Resources/Prototypes/Entities/Objects/Fun/toys.yml b/Resources/Prototypes/Entities/Objects/Fun/toys.yml index 67c6e1194b..9ced553941 100644 --- a/Resources/Prototypes/Entities/Objects/Fun/toys.yml +++ b/Resources/Prototypes/Entities/Objects/Fun/toys.yml @@ -750,6 +750,34 @@ sound: path: /Audio/Voice/Human/malescream_5.ogg +- type: entity + parent: BasePlushie + id: PlushieArachne + name: Arachne plushie + description: A plushie of an Arachne, a half human, half spider creature. Why does it look familiar? + components: + - type: Sprite + state: plushie_arachne + - type: EmitSoundOnUse + sound: + path: /Audio/Voice/Human/womanlaugh.ogg + - type: EmitSoundOnLand + sound: + path: /Audio/Voice/Human/female_sigh.ogg + - type: EmitSoundOnActivate + sound: + path: /Audio/Voice/Human/womanlaugh.ogg + - type: Food + requiresSpecialDigestion: true + useSound: + path: /Audio/Voice/Human/femalescream_4.ogg + - type: MeleeWeapon + soundHit: + path: /Audio/Voice/Human/femalescream_2.ogg + - type: EmitSoundOnTrigger + sound: + path: /Audio/Voice/Human/femalescream_5.ogg + - type: entity parent: BasePlushie id: PlushieMoth @@ -1432,6 +1460,9 @@ reagents: - ReagentId: Nothing Quantity: 100 + - type: Tag + tags: + - Banana - type: entity parent: DrinkBase diff --git a/Resources/Prototypes/Entities/Objects/Misc/bedsheets.yml b/Resources/Prototypes/Entities/Objects/Misc/bedsheets.yml index a4f1e5e687..02ee00a07f 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/bedsheets.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/bedsheets.yml @@ -20,6 +20,9 @@ - neck - type: StaticPrice price: 100 + - type: Tag + tags: + - Bedsheet - type: entity id: BedsheetBlack diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Bombs/funny.yml b/Resources/Prototypes/Entities/Objects/Weapons/Bombs/funny.yml index 4aff7363a4..630354f23d 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Bombs/funny.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Bombs/funny.yml @@ -117,3 +117,6 @@ - id: TrashBananaPeelExplosive sound: path: /Audio/Effects/unwrap.ogg + - type: Tag + tags: + - Banana diff --git a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml index b0c4047ccd..4e87776e9f 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml @@ -157,6 +157,7 @@ - APCElectronics - SMESMachineCircuitboard - SubstationMachineCircuitboard + - WallmountSubstationElectronics - CellRechargerCircuitboard - BorgChargerCircuitboard - WeaponCapacitorRechargerCircuitboard diff --git a/Resources/Prototypes/Entities/Structures/Power/substation.yml b/Resources/Prototypes/Entities/Structures/Power/substation.yml index 94de12be18..04c83bd991 100644 --- a/Resources/Prototypes/Entities/Structures/Power/substation.yml +++ b/Resources/Prototypes/Entities/Structures/Power/substation.yml @@ -244,6 +244,16 @@ - type: Battery maxCharge: 2000000 startingCharge: 2000000 + - type: ContainerFill + containers: + board: [ WallmountSubstationElectronics ] + capacitor: [ CapacitorStockPart ] + powercell: [ PowerCellSmall ] + - type: ContainerContainer + containers: + board: !type:Container + capacitor: !type:Container + powercell: !type:Container # Construction Frame - type: entity diff --git a/Resources/Prototypes/GameRules/roundstart.yml b/Resources/Prototypes/GameRules/roundstart.yml index 9ed1889154..8e518ab2f1 100644 --- a/Resources/Prototypes/GameRules/roundstart.yml +++ b/Resources/Prototypes/GameRules/roundstart.yml @@ -132,6 +132,16 @@ components: - type: RampingStationEventScheduler +- type: entity + id: HellshiftStationEventScheduler + parent: BaseGameRule + noSpawn: true + components: + - type: RampingStationEventScheduler + chaosModifier: 4 # By default, one event each 30-10 seconds after two hours. Changing CVars will cause this to deviate. + startingChaosRatio: 0.025 # Starts as slow as survival, but quickly ramps up + shiftLengthModifier: 2.5 + # variation passes - type: entity id: BasicRoundstartVariation diff --git a/Resources/Prototypes/Language/languages.yml b/Resources/Prototypes/Language/languages.yml index 1a874612c2..048fdc6f24 100644 --- a/Resources/Prototypes/Language/languages.yml +++ b/Resources/Prototypes/Language/languages.yml @@ -38,6 +38,8 @@ # Spoken by slimes. - type: language id: Bubblish + color: "#0077aa" + fontId: RubikBubbles obfuscation: !type:SyllableObfuscation minSyllables: 1 @@ -52,6 +54,8 @@ # Spoken by moths. - type: language id: Moffic + color: "#869b29" + fontId: Copperplate obfuscation: !type:SyllableObfuscation minSyllables: 2 # Replacements are really short @@ -118,6 +122,8 @@ # Spoken by dionas. - type: language id: RootSpeak + color: "#804000" + fontId: Noganas obfuscation: !type:SyllableObfuscation minSyllables: 1 @@ -132,6 +138,8 @@ # A mess of broken Japanese, spoken by Felinds and Oni - type: language id: Nekomimetic + color: "#803B56" + fontId: Manga obfuscation: !type:SyllableObfuscation minSyllables: 1 @@ -189,6 +197,7 @@ # Spoken by the Lizard race. - type: language id: Draconic + color: "#228b22" obfuscation: !type:SyllableObfuscation minSyllables: 2 @@ -282,6 +291,7 @@ # Spoken by the Vulpkanin race. - type: language id: Canilunzt + color: "#b97a57" obfuscation: !type:SyllableObfuscation minSyllables: 1 @@ -314,7 +324,6 @@ - vor - nic - gro - # - lll - enem - zandt - tzch @@ -349,6 +358,7 @@ # The common language of the Sol system. - type: language id: SolCommon + color: "#8282fb" obfuscation: !type:SyllableObfuscation minSyllables: 1 @@ -374,6 +384,7 @@ - type: language id: RobotTalk + fontId: Monospace obfuscation: !type:SyllableObfuscation minSyllables: 1 diff --git a/Resources/Prototypes/Nyanotrasen/Catalog/Cargo/cargo_epistemics.yml b/Resources/Prototypes/Nyanotrasen/Catalog/Cargo/cargo_epistemics.yml index 4be21cec30..d7d0b66538 100644 --- a/Resources/Prototypes/Nyanotrasen/Catalog/Cargo/cargo_epistemics.yml +++ b/Resources/Prototypes/Nyanotrasen/Catalog/Cargo/cargo_epistemics.yml @@ -4,6 +4,6 @@ sprite: Nyanotrasen/Objects/Consumable/Drinks/flaskholywater.rsi state: icon product: CrateHolyWaterKit - cost: 1000 - category: Service + cost: 3000 + category: Epistemics group: market diff --git a/Resources/Prototypes/Objectives/ninja.yml b/Resources/Prototypes/Objectives/ninja.yml index 43def65d7a..f2ac97be58 100644 --- a/Resources/Prototypes/Objectives/ninja.yml +++ b/Resources/Prototypes/Objectives/ninja.yml @@ -39,8 +39,8 @@ sprite: Structures/Machines/server.rsi state: server - type: NumberObjective - min: 5 - max: 10 + min: 9 + max: 13 title: objective-condition-steal-research-title - type: StealResearchCondition diff --git a/Resources/Prototypes/Procedural/biome_templates.yml b/Resources/Prototypes/Procedural/biome_templates.yml index 8897931644..425bcd824a 100644 --- a/Resources/Prototypes/Procedural/biome_templates.yml +++ b/Resources/Prototypes/Procedural/biome_templates.yml @@ -620,7 +620,7 @@ allowedTiles: - FloorAsteroidSand entities: - - AsteroidRock + - RandomRockSpawner #Delta V - Makes Asteroids Great-ish Again - !type:BiomeTileLayer threshold: -1.0 tile: FloorAsteroidSand diff --git a/Resources/Prototypes/Recipes/Construction/Graphs/utilities/wallmount_substation.yml b/Resources/Prototypes/Recipes/Construction/Graphs/utilities/wallmount_substation.yml index 381871f94a..7e4087b20a 100644 --- a/Resources/Prototypes/Recipes/Construction/Graphs/utilities/wallmount_substation.yml +++ b/Resources/Prototypes/Recipes/Construction/Graphs/utilities/wallmount_substation.yml @@ -26,7 +26,13 @@ steps: - material: Cable amount: 5 - doAfter: 2 + doAfter: 0.5 + - material: CableMV + amount: 5 + doAfter: 0.5 + - material: CableHV + amount: 5 + doAfter: 0.5 - tool: Screwing doAfter: 2 @@ -41,12 +47,34 @@ icon: sprite: "Objects/Misc/module.rsi" state: "charger_APC" - doAfter: 1 + doAfter: 0.5 + - anyTags: + - PowerCell + - PowerCellSmall + store: powercell + name: a powercell + icon: + sprite: "Objects/Power/power_cells.rsi" + state: "medium" + doAfter: 0.5 + - tag: CapacitorStockPart + name: a capacitor + store: capacitor + icon: + sprite: "Objects/Misc/stock_parts.rsi" + state: "capacitor" + doAfter: 0.5 - to: frame completed: - !type:GivePrototype prototype: CableApcStack1 amount: 5 + - !type:GivePrototype + prototype: CableMVStack1 + amount: 5 + - !type:GivePrototype + prototype: CableHVStack1 + amount: 5 steps: - tool: Cutting doAfter: 1 diff --git a/Resources/Prototypes/Recipes/Lathes/electronics.yml b/Resources/Prototypes/Recipes/Lathes/electronics.yml index f0c59a0bdf..b6184272dc 100644 --- a/Resources/Prototypes/Recipes/Lathes/electronics.yml +++ b/Resources/Prototypes/Recipes/Lathes/electronics.yml @@ -604,7 +604,7 @@ completetime: 4 materials: Steel: 50 - Glass: 350 + Glass: 450 - type: latheRecipe id: SMESMachineCircuitboard diff --git a/Resources/Prototypes/Store/categories.yml b/Resources/Prototypes/Store/categories.yml index c16972c8a3..11f8d509af 100644 --- a/Resources/Prototypes/Store/categories.yml +++ b/Resources/Prototypes/Store/categories.yml @@ -63,6 +63,11 @@ name: store-category-pointless priority: 9 +- type: storeCategory + id: UplinkDeception + name: store-category-deception + priority: 10 + #revenant - type: storeCategory id: RevenantAbilities diff --git a/Resources/Prototypes/Traits/inconveniences.yml b/Resources/Prototypes/Traits/inconveniences.yml index dcf53d9ab7..8dc0264ffe 100644 --- a/Resources/Prototypes/Traits/inconveniences.yml +++ b/Resources/Prototypes/Traits/inconveniences.yml @@ -26,3 +26,26 @@ fourRandomProb: 0 threeRandomProb: 0 cutRandomProb: 0 + +- type: trait + id: ForeignerLight + category: Mental + points: 1 + requirements: + - !type:TraitGroupExclusionRequirement + prototypes: [ Foreigner ] + components: + - type: ForeignerTrait + cantUnderstand: false # Allows to understand + baseTranslator: TranslatorForeigner + +- type: trait + id: Foreigner + category: Mental + points: 2 + requirements: # TODO: Add a requirement to know at least 1 non-gc language + - !type:TraitGroupExclusionRequirement + prototypes: [ ForeignerLight ] + components: + - type: ForeignerTrait + baseTranslator: TranslatorForeigner diff --git a/Resources/Prototypes/fonts.yml b/Resources/Prototypes/fonts.yml index 03102cd341..92c2947258 100644 --- a/Resources/Prototypes/fonts.yml +++ b/Resources/Prototypes/fonts.yml @@ -45,3 +45,19 @@ - type: font id: Emoji path: /Fonts/NotoEmoji.ttf + +- type: font + id: RubikBubbles + path: /Fonts/RubikBubbles.ttf + +- type: font + id: Copperplate + path: /Fonts/Copperplate.otf + +- type: font + id: Manga + path: /Fonts/Mangat.ttf + +- type: font + id: Noganas + path: /Fonts/Noganas.ttf diff --git a/Resources/Prototypes/game_presets.yml b/Resources/Prototypes/game_presets.yml index e99b51f82c..7d7169bf10 100644 --- a/Resources/Prototypes/game_presets.yml +++ b/Resources/Prototypes/game_presets.yml @@ -9,6 +9,17 @@ - RampingStationEventScheduler - BasicRoundstartVariation +- type: gamePreset + id: SurvivalHellshift + alias: + - hellshift + showInVote: true + name: hellshift-title + description: hellshift-description + rules: + - HellshiftStationEventScheduler + - BasicRoundstartVariation + - type: gamePreset id: AllAtOnce name: all-at-once-title @@ -90,7 +101,7 @@ - traitor name: traitor-title description: traitor-description - showInVote: false + showInVote: true rules: - Traitor - SubGamemodesRule diff --git a/Resources/Prototypes/tags.yml b/Resources/Prototypes/tags.yml index b7fa0fa2b6..e48fa2f2f2 100644 --- a/Resources/Prototypes/tags.yml +++ b/Resources/Prototypes/tags.yml @@ -34,18 +34,30 @@ - type: Tag id: Balloon +- type: Tag + id: Banana + - type: Tag id: BananaPeel +- type: Tag + id: Bandana + - type: Tag id: BaseballBat - type: Tag id: BBQsauce +- type: Tag + id: Bedsheet + - type: Tag id: Bee +- type: Tag + id: Beer + - type: Tag id: BikeHorn @@ -205,6 +217,9 @@ - type: Tag id: Bottle +- type: Tag + id: BoxCardboard + - type: Tag id: BoxHug @@ -350,6 +365,9 @@ - type: Tag id: ChemDispensable # container that can go into the chem dispenser +- type: Tag + id: ChiliBowl + - type: Tag id: Cigarette @@ -386,11 +404,14 @@ - type: Tag id: CluwneHorn -- type: Tag #Ohioans die happy +- type: Tag + id: Coldsauce + +- type: Tag id: Corn - type: Tag - id: Coldsauce + id: CottonBoll - type: Tag id: Cow @@ -683,6 +704,9 @@ - type: Tag id: HighSecDoor +- type: Tag + id: HiViz + - type: Tag id: Hoe @@ -770,9 +794,6 @@ - type: Tag id: MacroBomb -- type: Tag - id: MicroBomb - - type: Tag id: MimeBelt @@ -853,6 +874,12 @@ - type: Tag id: Metal +- type: Tag + id: MicroBomb + +- type: Tag + id: MicrowaveMachineBoard + - type: Tag id: MindShield @@ -1151,6 +1178,9 @@ - type: Tag id: StationMapElectronics +- type: Tag + id: Steak + - type: Tag id: SubdermalImplant @@ -1220,6 +1250,9 @@ - type: Tag id: UraniumGlassShard +- type: Tag + id: Vegetable + - type: Tag id: VimPilot @@ -1259,6 +1292,9 @@ - type: Tag id: Window +- type: Tag + id: Wine + - type: Tag id: WizardWand # that evil vvizard vvand diff --git a/Resources/Textures/Objects/Fun/toys.rsi/meta.json b/Resources/Textures/Objects/Fun/toys.rsi/meta.json index fc92a47936..cae7880e41 100644 --- a/Resources/Textures/Objects/Fun/toys.rsi/meta.json +++ b/Resources/Textures/Objects/Fun/toys.rsi/meta.json @@ -104,6 +104,9 @@ { "name": "plushie_diona" }, + { + "name": "plushie_arachne" + }, { "name": "plushie_human" }, diff --git a/Resources/Textures/Objects/Fun/toys.rsi/plushie_arachne.png b/Resources/Textures/Objects/Fun/toys.rsi/plushie_arachne.png new file mode 100644 index 0000000000..4f72c31ddf Binary files /dev/null and b/Resources/Textures/Objects/Fun/toys.rsi/plushie_arachne.png differ diff --git a/Resources/Textures/Structures/Power/apc.rsi/base.png b/Resources/Textures/Structures/Power/apc.rsi/base.png index 2b42c54935..ea2f17c062 100644 Binary files a/Resources/Textures/Structures/Power/apc.rsi/base.png and b/Resources/Textures/Structures/Power/apc.rsi/base.png differ diff --git a/Resources/Textures/Structures/Power/apc.rsi/broken.png b/Resources/Textures/Structures/Power/apc.rsi/broken.png index 092694c371..4bcd2475cd 100644 Binary files a/Resources/Textures/Structures/Power/apc.rsi/broken.png and b/Resources/Textures/Structures/Power/apc.rsi/broken.png differ diff --git a/Resources/Textures/Structures/Power/apc.rsi/channel0-auto_off.png b/Resources/Textures/Structures/Power/apc.rsi/channel0-auto_off.png index ba84b7d6db..0d181878fc 100644 Binary files a/Resources/Textures/Structures/Power/apc.rsi/channel0-auto_off.png and b/Resources/Textures/Structures/Power/apc.rsi/channel0-auto_off.png differ diff --git a/Resources/Textures/Structures/Power/apc.rsi/channel0-auto_on.png b/Resources/Textures/Structures/Power/apc.rsi/channel0-auto_on.png index 6cce72f795..c7a0d87ccc 100644 Binary files a/Resources/Textures/Structures/Power/apc.rsi/channel0-auto_on.png and b/Resources/Textures/Structures/Power/apc.rsi/channel0-auto_on.png differ diff --git a/Resources/Textures/Structures/Power/apc.rsi/channel0-manual_off.png b/Resources/Textures/Structures/Power/apc.rsi/channel0-manual_off.png index 61ae057d50..4be0bbfb0b 100644 Binary files a/Resources/Textures/Structures/Power/apc.rsi/channel0-manual_off.png and b/Resources/Textures/Structures/Power/apc.rsi/channel0-manual_off.png differ diff --git a/Resources/Textures/Structures/Power/apc.rsi/channel0-manual_on.png b/Resources/Textures/Structures/Power/apc.rsi/channel0-manual_on.png index 6cc48bd1a5..720dc4976a 100644 Binary files a/Resources/Textures/Structures/Power/apc.rsi/channel0-manual_on.png and b/Resources/Textures/Structures/Power/apc.rsi/channel0-manual_on.png differ diff --git a/Resources/Textures/Structures/Power/apc.rsi/channel1-auto_off.png b/Resources/Textures/Structures/Power/apc.rsi/channel1-auto_off.png index b31bed6c6b..7f0a13a7a4 100644 Binary files a/Resources/Textures/Structures/Power/apc.rsi/channel1-auto_off.png and b/Resources/Textures/Structures/Power/apc.rsi/channel1-auto_off.png differ diff --git a/Resources/Textures/Structures/Power/apc.rsi/channel1-auto_on.png b/Resources/Textures/Structures/Power/apc.rsi/channel1-auto_on.png index 959a05cde0..87191be520 100644 Binary files a/Resources/Textures/Structures/Power/apc.rsi/channel1-auto_on.png and b/Resources/Textures/Structures/Power/apc.rsi/channel1-auto_on.png differ diff --git a/Resources/Textures/Structures/Power/apc.rsi/channel1-manual_off.png b/Resources/Textures/Structures/Power/apc.rsi/channel1-manual_off.png index 3bb505ecb8..031213f74a 100644 Binary files a/Resources/Textures/Structures/Power/apc.rsi/channel1-manual_off.png and b/Resources/Textures/Structures/Power/apc.rsi/channel1-manual_off.png differ diff --git a/Resources/Textures/Structures/Power/apc.rsi/channel1-manual_on.png b/Resources/Textures/Structures/Power/apc.rsi/channel1-manual_on.png index bd8b013310..ac5f1c1bef 100644 Binary files a/Resources/Textures/Structures/Power/apc.rsi/channel1-manual_on.png and b/Resources/Textures/Structures/Power/apc.rsi/channel1-manual_on.png differ diff --git a/Resources/Textures/Structures/Power/apc.rsi/channel2-auto_off.png b/Resources/Textures/Structures/Power/apc.rsi/channel2-auto_off.png index 0cca860220..ff8522d2c5 100644 Binary files a/Resources/Textures/Structures/Power/apc.rsi/channel2-auto_off.png and b/Resources/Textures/Structures/Power/apc.rsi/channel2-auto_off.png differ diff --git a/Resources/Textures/Structures/Power/apc.rsi/channel2-auto_on.png b/Resources/Textures/Structures/Power/apc.rsi/channel2-auto_on.png index 56802dc043..4e04387ed3 100644 Binary files a/Resources/Textures/Structures/Power/apc.rsi/channel2-auto_on.png and b/Resources/Textures/Structures/Power/apc.rsi/channel2-auto_on.png differ diff --git a/Resources/Textures/Structures/Power/apc.rsi/channel2-manual_off.png b/Resources/Textures/Structures/Power/apc.rsi/channel2-manual_off.png index 5ac134cb54..2f9802281e 100644 Binary files a/Resources/Textures/Structures/Power/apc.rsi/channel2-manual_off.png and b/Resources/Textures/Structures/Power/apc.rsi/channel2-manual_off.png differ diff --git a/Resources/Textures/Structures/Power/apc.rsi/channel2-manual_on.png b/Resources/Textures/Structures/Power/apc.rsi/channel2-manual_on.png index 5ebec4feee..fb9e2180bb 100644 Binary files a/Resources/Textures/Structures/Power/apc.rsi/channel2-manual_on.png and b/Resources/Textures/Structures/Power/apc.rsi/channel2-manual_on.png differ diff --git a/Resources/Textures/Structures/Power/apc.rsi/display-charging.png b/Resources/Textures/Structures/Power/apc.rsi/display-charging.png index 67e3b3df19..d5e356d943 100644 Binary files a/Resources/Textures/Structures/Power/apc.rsi/display-charging.png and b/Resources/Textures/Structures/Power/apc.rsi/display-charging.png differ diff --git a/Resources/Textures/Structures/Power/apc.rsi/display-full.png b/Resources/Textures/Structures/Power/apc.rsi/display-full.png index 1739853e2b..4a9bd7ed64 100644 Binary files a/Resources/Textures/Structures/Power/apc.rsi/display-full.png and b/Resources/Textures/Structures/Power/apc.rsi/display-full.png differ diff --git a/Resources/Textures/Structures/Power/apc.rsi/display-lack.png b/Resources/Textures/Structures/Power/apc.rsi/display-lack.png index c4c103eeb9..d1d2df4858 100644 Binary files a/Resources/Textures/Structures/Power/apc.rsi/display-lack.png and b/Resources/Textures/Structures/Power/apc.rsi/display-lack.png differ diff --git a/Resources/Textures/Structures/Power/apc.rsi/display-remote.png b/Resources/Textures/Structures/Power/apc.rsi/display-remote.png index be343a987b..07265ab67d 100644 Binary files a/Resources/Textures/Structures/Power/apc.rsi/display-remote.png and b/Resources/Textures/Structures/Power/apc.rsi/display-remote.png differ diff --git a/Resources/Textures/Structures/Power/apc.rsi/emag-unlit.png b/Resources/Textures/Structures/Power/apc.rsi/emag-unlit.png index 2713c5506a..77c2518e63 100644 Binary files a/Resources/Textures/Structures/Power/apc.rsi/emag-unlit.png and b/Resources/Textures/Structures/Power/apc.rsi/emag-unlit.png differ diff --git a/Resources/Textures/Structures/Power/apc.rsi/frame.png b/Resources/Textures/Structures/Power/apc.rsi/frame.png index 7d3529f63f..e4c9c1b31c 100644 Binary files a/Resources/Textures/Structures/Power/apc.rsi/frame.png and b/Resources/Textures/Structures/Power/apc.rsi/frame.png differ diff --git a/Resources/Textures/Structures/Power/apc.rsi/meta.json b/Resources/Textures/Structures/Power/apc.rsi/meta.json index 82f78ccb87..867e5ce0ff 100644 --- a/Resources/Textures/Structures/Power/apc.rsi/meta.json +++ b/Resources/Textures/Structures/Power/apc.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/9c7d509354ee030300f63c701da63c17928c3b3b and modified by Swept", + "copyright": "Taken from TauCetiClassic at commit https://github.com/TauCetiStation/TauCetiClassic/commit/fca7f2a0f9154c0c6c4efc2f8f58441fb9b34759", "size": { "x": 32, "y": 32 diff --git a/Resources/Textures/Structures/Power/apc.rsi/sparks-unlit.png b/Resources/Textures/Structures/Power/apc.rsi/sparks-unlit.png index 212fcb78bf..f442757bea 100644 Binary files a/Resources/Textures/Structures/Power/apc.rsi/sparks-unlit.png and b/Resources/Textures/Structures/Power/apc.rsi/sparks-unlit.png differ diff --git a/Resources/Textures/Structures/Power/apc.rsi/static.png b/Resources/Textures/Structures/Power/apc.rsi/static.png index 43089d0d81..a7137ec2f3 100644 Binary files a/Resources/Textures/Structures/Power/apc.rsi/static.png and b/Resources/Textures/Structures/Power/apc.rsi/static.png differ diff --git a/Resources/Textures/Structures/Power/power.rsi/meta.json b/Resources/Textures/Structures/Power/power.rsi/meta.json index 773a2b5a3e..027655dd35 100644 --- a/Resources/Textures/Structures/Power/power.rsi/meta.json +++ b/Resources/Textures/Structures/Power/power.rsi/meta.json @@ -5,7 +5,7 @@ "y": 32 }, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation", + "copyright": "Taken from tgstation/paradise", "states": [ { "name": "eightdirwire" diff --git a/Resources/Textures/Structures/Power/power.rsi/storage.png b/Resources/Textures/Structures/Power/power.rsi/storage.png index 5f42ce89bc..71e7cf9195 100644 Binary files a/Resources/Textures/Structures/Power/power.rsi/storage.png and b/Resources/Textures/Structures/Power/power.rsi/storage.png differ diff --git a/Resources/Textures/Structures/Power/smes.rsi/meta.json b/Resources/Textures/Structures/Power/smes.rsi/meta.json index 2ca8d1fb22..4b4193ec72 100644 --- a/Resources/Textures/Structures/Power/smes.rsi/meta.json +++ b/Resources/Textures/Structures/Power/smes.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/9c7d509354ee030300f63c701da63c17928c3b3b and modified by Swept", + "copyright": "Taken from Paradise at https://github.com/McRamon/Paradise/blob/b727162ed9dead12de42be5c5b04872934a474e1/icons/obj/power.dmi", "size": { "x": 32, "y": 32 @@ -9,33 +9,9 @@ "states": [ { "name": "smes" - }, - { - "name": "static" - }, - { - "name": "smes-open" - }, - { - "name": "smes-oc0" }, { - "name": "smes-oc1", - "delays": [ - [ - 0.5, - 0.5 - ] - ] - }, - { - "name": "smes-oc2", - "delays": [ - [ - 0.5, - 0.5 - ] - ] + "name": "static" }, { "name": "smes-og1", @@ -62,16 +38,50 @@ "name": "smes-op0" }, { - "name": "smes-op1", + "name": "smes-op1" + }, + { + "name": "smes-op2" + }, + { + "name": "smes-oc1", "delays": [ [ - 1, - 1 + 0.3, + 0.3 ] ] }, { - "name": "smes-op2" + "name": "smes-oc2", + "delays": [ + [ + 0.3, + 0.3 + ] + ] + }, + { + "name": "smes-oc0", + "delays": [ + [ + 0.5, + 0.3 + ] + ] + }, + { + "name": "smes-open", + "delays": [ + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ] + ] } ] } diff --git a/Resources/Textures/Structures/Power/smes.rsi/smes-oc0.png b/Resources/Textures/Structures/Power/smes.rsi/smes-oc0.png index 5579432d3f..9d62074f1d 100644 Binary files a/Resources/Textures/Structures/Power/smes.rsi/smes-oc0.png and b/Resources/Textures/Structures/Power/smes.rsi/smes-oc0.png differ diff --git a/Resources/Textures/Structures/Power/smes.rsi/smes-oc1.png b/Resources/Textures/Structures/Power/smes.rsi/smes-oc1.png index d624672613..10f4c4678e 100644 Binary files a/Resources/Textures/Structures/Power/smes.rsi/smes-oc1.png and b/Resources/Textures/Structures/Power/smes.rsi/smes-oc1.png differ diff --git a/Resources/Textures/Structures/Power/smes.rsi/smes-oc2.png b/Resources/Textures/Structures/Power/smes.rsi/smes-oc2.png index d624672613..10f4c4678e 100644 Binary files a/Resources/Textures/Structures/Power/smes.rsi/smes-oc2.png and b/Resources/Textures/Structures/Power/smes.rsi/smes-oc2.png differ diff --git a/Resources/Textures/Structures/Power/smes.rsi/smes-og1.png b/Resources/Textures/Structures/Power/smes.rsi/smes-og1.png index c65f011a07..472b013ce7 100644 Binary files a/Resources/Textures/Structures/Power/smes.rsi/smes-og1.png and b/Resources/Textures/Structures/Power/smes.rsi/smes-og1.png differ diff --git a/Resources/Textures/Structures/Power/smes.rsi/smes-og2.png b/Resources/Textures/Structures/Power/smes.rsi/smes-og2.png index 0023750405..c2d3dbbc46 100644 Binary files a/Resources/Textures/Structures/Power/smes.rsi/smes-og2.png and b/Resources/Textures/Structures/Power/smes.rsi/smes-og2.png differ diff --git a/Resources/Textures/Structures/Power/smes.rsi/smes-og3.png b/Resources/Textures/Structures/Power/smes.rsi/smes-og3.png index 51df688e4a..263d8e98f7 100644 Binary files a/Resources/Textures/Structures/Power/smes.rsi/smes-og3.png and b/Resources/Textures/Structures/Power/smes.rsi/smes-og3.png differ diff --git a/Resources/Textures/Structures/Power/smes.rsi/smes-og4.png b/Resources/Textures/Structures/Power/smes.rsi/smes-og4.png index ceb3db1bc3..e31794f5c7 100644 Binary files a/Resources/Textures/Structures/Power/smes.rsi/smes-og4.png and b/Resources/Textures/Structures/Power/smes.rsi/smes-og4.png differ diff --git a/Resources/Textures/Structures/Power/smes.rsi/smes-og5.png b/Resources/Textures/Structures/Power/smes.rsi/smes-og5.png index e6c0c8a2ea..26955f70a1 100644 Binary files a/Resources/Textures/Structures/Power/smes.rsi/smes-og5.png and b/Resources/Textures/Structures/Power/smes.rsi/smes-og5.png differ diff --git a/Resources/Textures/Structures/Power/smes.rsi/smes-op0.png b/Resources/Textures/Structures/Power/smes.rsi/smes-op0.png index 573b5c404f..ab0ae9e114 100644 Binary files a/Resources/Textures/Structures/Power/smes.rsi/smes-op0.png and b/Resources/Textures/Structures/Power/smes.rsi/smes-op0.png differ diff --git a/Resources/Textures/Structures/Power/smes.rsi/smes-op1.png b/Resources/Textures/Structures/Power/smes.rsi/smes-op1.png index f5c8e10489..58d8dbf1f5 100644 Binary files a/Resources/Textures/Structures/Power/smes.rsi/smes-op1.png and b/Resources/Textures/Structures/Power/smes.rsi/smes-op1.png differ diff --git a/Resources/Textures/Structures/Power/smes.rsi/smes-op2.png b/Resources/Textures/Structures/Power/smes.rsi/smes-op2.png index af560237f1..58d8dbf1f5 100644 Binary files a/Resources/Textures/Structures/Power/smes.rsi/smes-op2.png and b/Resources/Textures/Structures/Power/smes.rsi/smes-op2.png differ diff --git a/Resources/Textures/Structures/Power/smes.rsi/smes-open.png b/Resources/Textures/Structures/Power/smes.rsi/smes-open.png index 472e3fd720..03868889f6 100644 Binary files a/Resources/Textures/Structures/Power/smes.rsi/smes-open.png and b/Resources/Textures/Structures/Power/smes.rsi/smes-open.png differ diff --git a/Resources/Textures/Structures/Power/smes.rsi/smes.png b/Resources/Textures/Structures/Power/smes.rsi/smes.png index ecfbc4cd58..71e7cf9195 100644 Binary files a/Resources/Textures/Structures/Power/smes.rsi/smes.png and b/Resources/Textures/Structures/Power/smes.rsi/smes.png differ diff --git a/Resources/Textures/Structures/Power/smes.rsi/static.png b/Resources/Textures/Structures/Power/smes.rsi/static.png index 3e52b6c43e..0fcc42db54 100644 Binary files a/Resources/Textures/Structures/Power/smes.rsi/static.png and b/Resources/Textures/Structures/Power/smes.rsi/static.png differ diff --git a/Resources/Textures/Structures/Power/substation.rsi/charging.png b/Resources/Textures/Structures/Power/substation.rsi/charging.png index 538dc2b7a8..fdf01dbe8d 100644 Binary files a/Resources/Textures/Structures/Power/substation.rsi/charging.png and b/Resources/Textures/Structures/Power/substation.rsi/charging.png differ diff --git a/Resources/Textures/Structures/Power/substation.rsi/dead.png b/Resources/Textures/Structures/Power/substation.rsi/dead.png index 9fbff744ca..ba6f81f1a1 100644 Binary files a/Resources/Textures/Structures/Power/substation.rsi/dead.png and b/Resources/Textures/Structures/Power/substation.rsi/dead.png differ diff --git a/Resources/Textures/Structures/Power/substation.rsi/full.png b/Resources/Textures/Structures/Power/substation.rsi/full.png index d179742669..42a670ff23 100644 Binary files a/Resources/Textures/Structures/Power/substation.rsi/full.png and b/Resources/Textures/Structures/Power/substation.rsi/full.png differ diff --git a/Resources/Textures/Structures/Power/substation.rsi/meta.json b/Resources/Textures/Structures/Power/substation.rsi/meta.json index 0125458641..a2ade57116 100644 --- a/Resources/Textures/Structures/Power/substation.rsi/meta.json +++ b/Resources/Textures/Structures/Power/substation.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Drawn by Ubaser.", + "copyright": "Taken from cev-eris at commit https://github.com/discordia-space/CEV-Eris/commit/b63634bc17efe2f09cf06ef0e9a90d24d37f6203, wall modified by Peptide90", "size": { "x": 32, "y": 32 diff --git a/Resources/Textures/Structures/Power/substation.rsi/screen.png b/Resources/Textures/Structures/Power/substation.rsi/screen.png index 60c922c53f..c28bcbceda 100644 Binary files a/Resources/Textures/Structures/Power/substation.rsi/screen.png and b/Resources/Textures/Structures/Power/substation.rsi/screen.png differ diff --git a/Resources/Textures/Structures/Power/substation.rsi/substation.png b/Resources/Textures/Structures/Power/substation.rsi/substation.png index b9d1eb18d8..45524ad8b1 100644 Binary files a/Resources/Textures/Structures/Power/substation.rsi/substation.png and b/Resources/Textures/Structures/Power/substation.rsi/substation.png differ diff --git a/Resources/Textures/Structures/Power/substation.rsi/substation_static.png b/Resources/Textures/Structures/Power/substation.rsi/substation_static.png index 9d5b8598f4..2a1de1a066 100644 Binary files a/Resources/Textures/Structures/Power/substation.rsi/substation_static.png and b/Resources/Textures/Structures/Power/substation.rsi/substation_static.png differ diff --git a/Resources/Textures/Structures/Power/substation.rsi/substation_wall.png b/Resources/Textures/Structures/Power/substation.rsi/substation_wall.png index 155ced7128..8e8ae3fe3c 100644 Binary files a/Resources/Textures/Structures/Power/substation.rsi/substation_wall.png and b/Resources/Textures/Structures/Power/substation.rsi/substation_wall.png differ diff --git a/Resources/Textures/Structures/Power/substation.rsi/substation_wall_static.png b/Resources/Textures/Structures/Power/substation.rsi/substation_wall_static.png index e810e6a5a4..ee24ff45e6 100644 Binary files a/Resources/Textures/Structures/Power/substation.rsi/substation_wall_static.png and b/Resources/Textures/Structures/Power/substation.rsi/substation_wall_static.png differ diff --git a/Resources/Textures/Structures/Wallmounts/Lighting/light_tube.rsi/base.png b/Resources/Textures/Structures/Wallmounts/Lighting/light_tube.rsi/base.png index 02e8764173..0a2e1ae76b 100644 Binary files a/Resources/Textures/Structures/Wallmounts/Lighting/light_tube.rsi/base.png and b/Resources/Textures/Structures/Wallmounts/Lighting/light_tube.rsi/base.png differ diff --git a/Resources/Textures/Structures/Wallmounts/Lighting/light_tube.rsi/broken.png b/Resources/Textures/Structures/Wallmounts/Lighting/light_tube.rsi/broken.png index 9d10428af8..1565cdc86d 100644 Binary files a/Resources/Textures/Structures/Wallmounts/Lighting/light_tube.rsi/broken.png and b/Resources/Textures/Structures/Wallmounts/Lighting/light_tube.rsi/broken.png differ diff --git a/Resources/Textures/Structures/Wallmounts/Lighting/light_tube.rsi/burned.png b/Resources/Textures/Structures/Wallmounts/Lighting/light_tube.rsi/burned.png index 160db7c5cb..7e14e2c2b3 100644 Binary files a/Resources/Textures/Structures/Wallmounts/Lighting/light_tube.rsi/burned.png and b/Resources/Textures/Structures/Wallmounts/Lighting/light_tube.rsi/burned.png differ diff --git a/Resources/Textures/Structures/Wallmounts/Lighting/light_tube.rsi/empty.png b/Resources/Textures/Structures/Wallmounts/Lighting/light_tube.rsi/empty.png index 0f8f9478bd..5ead53beb0 100644 Binary files a/Resources/Textures/Structures/Wallmounts/Lighting/light_tube.rsi/empty.png and b/Resources/Textures/Structures/Wallmounts/Lighting/light_tube.rsi/empty.png differ diff --git a/Resources/Textures/Structures/Wallmounts/Lighting/light_tube.rsi/glow.png b/Resources/Textures/Structures/Wallmounts/Lighting/light_tube.rsi/glow.png index e1258d83dc..50cc6725c7 100644 Binary files a/Resources/Textures/Structures/Wallmounts/Lighting/light_tube.rsi/glow.png and b/Resources/Textures/Structures/Wallmounts/Lighting/light_tube.rsi/glow.png differ diff --git a/Resources/Textures/Structures/Wallmounts/Lighting/light_tube.rsi/meta.json b/Resources/Textures/Structures/Wallmounts/Lighting/light_tube.rsi/meta.json index 4b8aa5fa2f..be5f4a804b 100644 --- a/Resources/Textures/Structures/Wallmounts/Lighting/light_tube.rsi/meta.json +++ b/Resources/Textures/Structures/Wallmounts/Lighting/light_tube.rsi/meta.json @@ -1,11 +1,11 @@ { "version": 1, - "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/c6e3401f2e7e1e55c57060cdf956a98ef1fefc24", "size": { "x": 32, "y": 32 }, + "license": "CC-BY-SA-3.0", + "copyright": "https://github.com/discordia-space/CEV-Eris/blob/2b969adc2dfd3e9621bf3597c5cbffeb3ac8c9f0/icons/obj/lighting.dmi", "states": [ { "name": "broken", @@ -16,14 +16,14 @@ "directions": 4 }, { - "name": "base", + "name": "empty", "directions": 4 }, { - "name": "empty", + "name": "base", "directions": 4 }, - { + { "name": "glow", "directions": 4 } diff --git a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/alarm0.png b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/alarm0.png index 3b714153de..fdc9376d67 100644 Binary files a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/alarm0.png and b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/alarm0.png differ diff --git a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/alarm1.png b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/alarm1.png index e7a2301488..d371695e12 100644 Binary files a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/alarm1.png and b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/alarm1.png differ diff --git a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/alarm2.png b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/alarm2.png index 716536cfcb..9d8640f85b 100644 Binary files a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/alarm2.png and b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/alarm2.png differ diff --git a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/alarm_b1.png b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/alarm_b1.png index fc185734af..5fbc157750 100644 Binary files a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/alarm_b1.png and b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/alarm_b1.png differ diff --git a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/alarm_b2.png b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/alarm_b2.png index 0cdb046606..38b22ccd81 100644 Binary files a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/alarm_b2.png and b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/alarm_b2.png differ diff --git a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/alarm_bitem.png b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/alarm_bitem.png index 192c589f26..6f1292bb05 100644 Binary files a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/alarm_bitem.png and b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/alarm_bitem.png differ diff --git a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/alarmp.png b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/alarmp.png index 793babbbe6..0b3192122b 100644 Binary files a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/alarmp.png and b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/alarmp.png differ diff --git a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/alarmx.png b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/alarmx.png index 0f3e60bc0e..61ecb87ff4 100644 Binary files a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/alarmx.png and b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/alarmx.png differ diff --git a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire0.png b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire0.png index aa9559b7dc..278e5cf03b 100644 Binary files a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire0.png and b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire0.png differ diff --git a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_0.png b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_0.png index 39d4e98971..621410d043 100644 Binary files a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_0.png and b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_0.png differ diff --git a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_1.png b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_1.png index 765fdc6e59..fb775d3098 100644 Binary files a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_1.png and b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_1.png differ diff --git a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_3.png b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_3.png index ad74165ec4..71b96f2130 100644 Binary files a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_3.png and b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_3.png differ diff --git a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_b0.png b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_b0.png index cc554c7394..cfe596102d 100644 Binary files a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_b0.png and b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_b0.png differ diff --git a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_b1.png b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_b1.png index f732817d47..1a620adc14 100644 Binary files a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_b1.png and b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_b1.png differ diff --git a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_b2.png b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_b2.png index d862c40a4b..c199a7ff31 100644 Binary files a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_b2.png and b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_b2.png differ diff --git a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_bitem.png b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_bitem.png index cc2a57c495..5be7e11fc8 100644 Binary files a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_bitem.png and b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_bitem.png differ diff --git a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_emagged.png b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_emagged.png index 310bb89d41..bafb424956 100644 Binary files a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_emagged.png and b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_emagged.png differ diff --git a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_off.png b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_off.png index 8695c8a35d..3eb61db8b6 100644 Binary files a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_off.png and b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_off.png differ diff --git a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_on.png b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_on.png index a98566070e..ce3697456f 100644 Binary files a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_on.png and b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/fire_on.png differ diff --git a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/firex.png b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/firex.png index 5ac3fad6af..dd31be02f8 100644 Binary files a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/firex.png and b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/firex.png differ diff --git a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/meta.json b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/meta.json index 62e0a281bf..7484be2ffe 100644 --- a/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/meta.json +++ b/Resources/Textures/Structures/Wallmounts/air_monitors.rsi/meta.json @@ -1,48 +1,20 @@ { "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from TauCetiClassic at commit https://github.com/TauCetiStation/TauCetiClassic/commit/b7ac5798ae0d411b0cdeaf7efbc4ac86d24b4634, fire_emagged.png edited by github:Morb0", "size": { "x": 32, "y": 32 }, - "copyright": "Taken from tgstation", - "license": "CC-BY-SA-3.0", "states": [ { "name": "alarm0", "directions": 4, "delays": [ - [ - 0.5, - 0.1, - 0.1, - 1.0, - 0.2, - 0.1 - ], - [ - 0.5, - 0.1, - 0.1, - 1.0, - 0.2, - 0.1 - ], - [ - 0.5, - 0.1, - 0.1, - 1.0, - 0.2, - 0.1 - ], - [ - 0.5, - 0.1, - 0.1, - 1.0, - 0.2, - 0.1 - ] + [2.8, 2.8], + [2.8, 2.8], + [2.8, 2.8], + [2.8, 2.8] ] }, { @@ -50,20 +22,20 @@ "directions": 4, "delays": [ [ - 0.5, - 0.5 + 0.6, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, + 0.2, 0.2, 0.2, 0.2, 0.2, 0.6, 0.6, 0.6 ], [ - 0.5, - 0.5 + 0.6, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, + 0.2, 0.2, 0.2, 0.2, 0.2, 0.6, 0.6, 0.6 ], [ - 0.5, - 0.5 + 0.6, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, + 0.2, 0.2, 0.2, 0.2, 0.2, 0.6, 0.6, 0.6 ], [ - 0.5, - 0.5 + 0.6, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, + 0.2, 0.2, 0.2, 0.2, 0.2, 0.6, 0.6, 0.6 ] ] }, @@ -72,20 +44,20 @@ "directions": 4, "delays": [ [ - 0.5, - 0.5 + 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.4, 0.4, 0.4, 0.4, + 0.4, 0.4 ], [ - 0.5, - 0.5 + 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.4, 0.4, 0.4, 0.4, + 0.4, 0.4 ], [ - 0.5, - 0.5 + 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.4, 0.4, 0.4, 0.4, + 0.4, 0.4 ], [ - 0.5, - 0.5 + 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.4, 0.4, 0.4, 0.4, + 0.4, 0.4 ] ] }, @@ -98,7 +70,8 @@ "directions": 4 }, { - "name": "alarm_bitem" + "name": "alarm_bitem", + "directions": 1 }, { "name": "alarmp", @@ -109,17 +82,14 @@ "directions": 4 }, { - "name": "auth_off" + "name": "auth_off", + "directions": 1, + "delays": [[1]] }, { "name": "auth_on", "directions": 1, - "delays": [ - [ - 0.1, - 0.1 - ] - ] + "delays": [[0.1, 0.1]] }, { "name": "fire0", @@ -137,44 +107,20 @@ "name": "fire_2", "directions": 4, "delays": [ - [ - 0.5, - 0.5 - ], - [ - 0.5, - 0.5 - ], - [ - 0.5, - 0.5 - ], - [ - 0.5, - 0.5 - ] + [0.5, 0.5], + [0.5, 0.5], + [0.5, 0.5], + [0.5, 0.5] ] }, { "name": "fire_3", "directions": 4, "delays": [ - [ - 0.5, - 0.5 - ], - [ - 0.5, - 0.5 - ], - [ - 0.5, - 0.5 - ], - [ - 0.5, - 0.5 - ] + [0.3, 0.3], + [0.3, 0.3], + [0.3, 0.3], + [0.3, 0.3] ] }, { @@ -190,67 +136,21 @@ "directions": 4 }, { - "name": "fire_bitem" + "name": "fire_bitem", + "directions": 1 }, { - "name": "fire_detected", + "name": "fire_emagged", "directions": 4, "delays": [ - [ - 0.4, - 0.4 - ], - [ - 0.4, - 0.4 - ], - [ - 0.4, - 0.4 - ], - [ - 0.4, - 0.4 - ] + [0.3, 0.3], + [0.3, 0.3], + [0.3, 0.3], + [0.3, 0.3] ] }, { - "name": "fire_emagged", - "directions": 4, - "delays": [ - [ - 0.5, - 0.5, - 0.3, - 0.5, - 0.2, - 0.5 - ], - [ - 0.5, - 0.5, - 0.3, - 0.5, - 0.2, - 0.5 - ], - [ - 0.5, - 0.5, - 0.3, - 0.5, - 0.2, - 0.5 - ], - [ - 0.5, - 0.5, - 0.3, - 0.5, - 0.2, - 0.5 - ] - ] + "name": "fire_detected" }, { "name": "fire_off", @@ -260,27 +160,14 @@ "name": "fire_on", "directions": 4, "delays": [ - [ - 0.5, - 0.5 - ], - [ - 0.5, - 0.5 - ], - [ - 0.5, - 0.5 - ], - [ - 0.5, - 0.5 - ] + [0.2, 0.2, 0.2, 0.2, 0.2, 0.2], + [0.2, 0.2, 0.2, 0.2, 0.2, 0.2], + [0.2, 0.2, 0.2, 0.2, 0.2, 0.2], + [0.2, 0.2, 0.2, 0.2, 0.2, 0.2] ] }, { - "name": "fire_overlay", - "directions": 4 + "name": "fire_overlay" }, { "name": "firex", diff --git a/Resources/Textures/Structures/Wallmounts/camera.rsi/camera.png b/Resources/Textures/Structures/Wallmounts/camera.rsi/camera.png index 19481d55a0..f3054b57ed 100644 Binary files a/Resources/Textures/Structures/Wallmounts/camera.rsi/camera.png and b/Resources/Textures/Structures/Wallmounts/camera.rsi/camera.png differ diff --git a/Resources/Textures/Structures/Wallmounts/camera.rsi/camera_assembly.png b/Resources/Textures/Structures/Wallmounts/camera.rsi/camera_assembly.png index 44d8460f5f..404e4dad19 100644 Binary files a/Resources/Textures/Structures/Wallmounts/camera.rsi/camera_assembly.png and b/Resources/Textures/Structures/Wallmounts/camera.rsi/camera_assembly.png differ diff --git a/Resources/Textures/Structures/Wallmounts/camera.rsi/camera_emp.png b/Resources/Textures/Structures/Wallmounts/camera.rsi/camera_emp.png index 6a7c1a24c5..59c7f453eb 100644 Binary files a/Resources/Textures/Structures/Wallmounts/camera.rsi/camera_emp.png and b/Resources/Textures/Structures/Wallmounts/camera.rsi/camera_emp.png differ diff --git a/Resources/Textures/Structures/Wallmounts/camera.rsi/camera_in_use.png b/Resources/Textures/Structures/Wallmounts/camera.rsi/camera_in_use.png index 42a6a6e098..3ed85a4a6b 100644 Binary files a/Resources/Textures/Structures/Wallmounts/camera.rsi/camera_in_use.png and b/Resources/Textures/Structures/Wallmounts/camera.rsi/camera_in_use.png differ diff --git a/Resources/Textures/Structures/Wallmounts/camera.rsi/camera_off.png b/Resources/Textures/Structures/Wallmounts/camera.rsi/camera_off.png index 7fa16ed3fd..487a2602aa 100644 Binary files a/Resources/Textures/Structures/Wallmounts/camera.rsi/camera_off.png and b/Resources/Textures/Structures/Wallmounts/camera.rsi/camera_off.png differ diff --git a/Resources/Textures/Structures/Wallmounts/camera.rsi/cameracase.png b/Resources/Textures/Structures/Wallmounts/camera.rsi/cameracase.png index ac3f200d1f..f93042f15f 100644 Binary files a/Resources/Textures/Structures/Wallmounts/camera.rsi/cameracase.png and b/Resources/Textures/Structures/Wallmounts/camera.rsi/cameracase.png differ diff --git a/Resources/Textures/Structures/Wallmounts/camera.rsi/meta.json b/Resources/Textures/Structures/Wallmounts/camera.rsi/meta.json index b8cedc6db6..95d2b24378 100644 --- a/Resources/Textures/Structures/Wallmounts/camera.rsi/meta.json +++ b/Resources/Textures/Structures/Wallmounts/camera.rsi/meta.json @@ -1,73 +1,490 @@ { - "version": 1, - "size": { - "x": 32, - "y": 32 + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from TauCetiClassic at commit https://github.com/TauCetiStation/TauCetiClassic/commit/f878e95210d81e1328b023feb96ec0d0b6113d8c", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "camera", + "directions": 8, + "delays": [ + [ + 0.25, + 0.25, + 0.6, + 0.25, + 0.25, + 0.25, + 0.6, + 0.25, + 0.25 + ], + [ + 0.25, + 0.25, + 0.6, + 0.25, + 0.25, + 0.25, + 0.6, + 0.25, + 0.25 + ], + [ + 0.25, + 0.25, + 0.6, + 0.25, + 0.25, + 0.25, + 0.6, + 0.25, + 0.25 + ], + [ + 0.25, + 0.25, + 0.6, + 0.25, + 0.25, + 0.25, + 0.6, + 0.25, + 0.25 + ], + [ + 0.25, + 0.25, + 0.6, + 0.25, + 0.25, + 0.25, + 0.6, + 0.25, + 0.25 + ], + [ + 0.25, + 0.25, + 0.6, + 0.25, + 0.25, + 0.25, + 0.6, + 0.25, + 0.25 + ], + [ + 0.25, + 0.25, + 0.6, + 0.25, + 0.25, + 0.25, + 0.6, + 0.25, + 0.25 + ], + [ + 0.25, + 0.25, + 0.6, + 0.25, + 0.25, + 0.25, + 0.6, + 0.25, + 0.25 + ] + ] }, - "license": "CC-BY-SA-3.0", - "copyright": "Taken from /tg/station at https://github.com/tgstation/tgstation/commit/6bfe3b2e4fcbcdac9159dc4f0327a82ddf05ba7bi", - "states": [ - { - "name": "camera", - "directions": 1, - "delays": [ - [ 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3 ] - ] - }, - { - "name": "camera_assembly", - "directions": 1 - }, - { - "name": "camera_emp", - "directions": 1, - "delays": [ - [ 0.2, 0.2, 0.1, 0.1 ] - ] - }, - { - "name": "camera_in_use", - "directions": 1, - "delays": [ - [ 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3 ] - ] - }, - { - "name": "camera_off", - "directions": 1 - }, - { - "name": "cameracase", - "directions": 1 - }, - { - "name": "xraycamera", - "directions": 1, - "delays": [ - [ 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3 ] - ] - }, - { - "name": "xraycamera_assembly", - "directions": 1 - }, - { - "name": "xraycamera_emp", - "directions": 1, - "delays": [ - [ 0.2, 0.2, 0.1, 0.1 ] - ] - }, - { - "name": "xraycamera_in_use", - "directions": 1, - "delays": [ - [ 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3 ] - ] - }, - { - "name": "xraycamera_off", - "directions": 1 - } - ] -} \ No newline at end of file + { + "name": "camera_in_use", + "directions": 8, + "delays": [ + [ + 0.25, + 0.25, + 0.6, + 0.25, + 0.25, + 0.25, + 0.6, + 0.25 + ], + [ + 0.25, + 0.25, + 0.6, + 0.25, + 0.25, + 0.25, + 0.6, + 0.25 + ], + [ + 0.25, + 0.25, + 0.6, + 0.25, + 0.25, + 0.25, + 0.6, + 0.25 + ], + [ + 0.25, + 0.25, + 0.6, + 0.25, + 0.25, + 0.25, + 0.6, + 0.25 + ], + [ + 0.25, + 0.25, + 0.6, + 0.25, + 0.25, + 0.25, + 0.6, + 0.25 + ], + [ + 0.25, + 0.25, + 0.6, + 0.25, + 0.25, + 0.25, + 0.6, + 0.25 + ], + [ + 0.25, + 0.25, + 0.6, + 0.25, + 0.25, + 0.25, + 0.6, + 0.25 + ], + [ + 0.25, + 0.25, + 0.6, + 0.25, + 0.25, + 0.25, + 0.6, + 0.25 + ] + ] + }, + { + "name": "camera_off", + "directions": 8 + }, + { + "name": "camera_emp", + "directions": 8, + "delays": [ + [ + 0.2, + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2, + 0.2 + ] + ] + }, + { + "name": "camera_assembly", + "directions": 8 + }, + { + "name": "xraycamera", + "directions": 8, + "delays": [ + [ + 0.25, + 0.25, + 0.6, + 0.25, + 0.25, + 0.25, + 0.6, + 0.25 + ], + [ + 0.25, + 0.25, + 0.6, + 0.25, + 0.25, + 0.25, + 0.6, + 0.25 + ], + [ + 0.25, + 0.25, + 0.6, + 0.25, + 0.25, + 0.25, + 0.6, + 0.25 + ], + [ + 0.25, + 0.25, + 0.6, + 0.25, + 0.25, + 0.25, + 0.6, + 0.25 + ], + [ + 0.25, + 0.25, + 0.6, + 0.25, + 0.25, + 0.25, + 0.6, + 0.25 + ], + [ + 0.25, + 0.25, + 0.6, + 0.25, + 0.25, + 0.25, + 0.6, + 0.25 + ], + [ + 0.25, + 0.25, + 0.6, + 0.25, + 0.25, + 0.25, + 0.6, + 0.25 + ], + [ + 0.25, + 0.25, + 0.6, + 0.25, + 0.25, + 0.25, + 0.6, + 0.25 + ] + ] + }, + { + "name": "xraycamera_emp", + "directions": 8, + "delays": [ + [ + 0.2, + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2, + 0.2 + ] + ] + }, + { + "name": "xraycamera_off", + "directions": 8 + }, + { + "name": "xraycamera_assembly", + "directions": 8 + }, + { + "name": "cameracase" + }, + { + "name": "xraycamera_in_use", + "directions": 8, + "delays": [ + [ + 0.25, + 0.25, + 0.6, + 0.25, + 0.25, + 0.25, + 0.6, + 0.25 + ], + [ + 0.25, + 0.25, + 0.6, + 0.25, + 0.25, + 0.25, + 0.6, + 0.25 + ], + [ + 0.25, + 0.25, + 0.6, + 0.25, + 0.25, + 0.25, + 0.6, + 0.25 + ], + [ + 0.25, + 0.25, + 0.6, + 0.25, + 0.25, + 0.25, + 0.6, + 0.25 + ], + [ + 0.25, + 0.25, + 0.6, + 0.25, + 0.25, + 0.25, + 0.6, + 0.25 + ], + [ + 0.25, + 0.25, + 0.6, + 0.25, + 0.25, + 0.25, + 0.6, + 0.25 + ], + [ + 0.25, + 0.25, + 0.6, + 0.25, + 0.25, + 0.25, + 0.6, + 0.25 + ], + [ + 0.25, + 0.25, + 0.6, + 0.25, + 0.25, + 0.25, + 0.6, + 0.25 + ] + ] + } + ] +} diff --git a/Resources/Textures/Structures/Wallmounts/camera.rsi/xraycamera.png b/Resources/Textures/Structures/Wallmounts/camera.rsi/xraycamera.png index 31d9892d9f..b543be5d7b 100644 Binary files a/Resources/Textures/Structures/Wallmounts/camera.rsi/xraycamera.png and b/Resources/Textures/Structures/Wallmounts/camera.rsi/xraycamera.png differ diff --git a/Resources/Textures/Structures/Wallmounts/camera.rsi/xraycamera_assembly.png b/Resources/Textures/Structures/Wallmounts/camera.rsi/xraycamera_assembly.png index d2f690d3c1..5dfddb08f7 100644 Binary files a/Resources/Textures/Structures/Wallmounts/camera.rsi/xraycamera_assembly.png and b/Resources/Textures/Structures/Wallmounts/camera.rsi/xraycamera_assembly.png differ diff --git a/Resources/Textures/Structures/Wallmounts/camera.rsi/xraycamera_emp.png b/Resources/Textures/Structures/Wallmounts/camera.rsi/xraycamera_emp.png index af6f3e2cec..434dbd575b 100644 Binary files a/Resources/Textures/Structures/Wallmounts/camera.rsi/xraycamera_emp.png and b/Resources/Textures/Structures/Wallmounts/camera.rsi/xraycamera_emp.png differ diff --git a/Resources/Textures/Structures/Wallmounts/camera.rsi/xraycamera_in_use.png b/Resources/Textures/Structures/Wallmounts/camera.rsi/xraycamera_in_use.png index 96dc134c7f..dadc30eba7 100644 Binary files a/Resources/Textures/Structures/Wallmounts/camera.rsi/xraycamera_in_use.png and b/Resources/Textures/Structures/Wallmounts/camera.rsi/xraycamera_in_use.png differ diff --git a/Resources/Textures/Structures/Wallmounts/camera.rsi/xraycamera_off.png b/Resources/Textures/Structures/Wallmounts/camera.rsi/xraycamera_off.png index 9b8a1aed79..487a2602aa 100644 Binary files a/Resources/Textures/Structures/Wallmounts/camera.rsi/xraycamera_off.png and b/Resources/Textures/Structures/Wallmounts/camera.rsi/xraycamera_off.png differ diff --git a/Resources/Textures/Structures/Wallmounts/intercom.rsi/base.png b/Resources/Textures/Structures/Wallmounts/intercom.rsi/base.png index 787af3f538..7ddea57ede 100644 Binary files a/Resources/Textures/Structures/Wallmounts/intercom.rsi/base.png and b/Resources/Textures/Structures/Wallmounts/intercom.rsi/base.png differ diff --git a/Resources/Textures/Structures/Wallmounts/intercom.rsi/broadcasting.png b/Resources/Textures/Structures/Wallmounts/intercom.rsi/broadcasting.png index 0566c70e35..fb01e70861 100644 Binary files a/Resources/Textures/Structures/Wallmounts/intercom.rsi/broadcasting.png and b/Resources/Textures/Structures/Wallmounts/intercom.rsi/broadcasting.png differ diff --git a/Resources/Textures/Structures/Wallmounts/intercom.rsi/build.png b/Resources/Textures/Structures/Wallmounts/intercom.rsi/build.png index cfd5d5fffa..21fc9a1bad 100644 Binary files a/Resources/Textures/Structures/Wallmounts/intercom.rsi/build.png and b/Resources/Textures/Structures/Wallmounts/intercom.rsi/build.png differ diff --git a/Resources/Textures/Structures/Wallmounts/intercom.rsi/meta.json b/Resources/Textures/Structures/Wallmounts/intercom.rsi/meta.json index f5a9d7b89c..d4440c99a0 100644 --- a/Resources/Textures/Structures/Wallmounts/intercom.rsi/meta.json +++ b/Resources/Textures/Structures/Wallmounts/intercom.rsi/meta.json @@ -5,7 +5,7 @@ "y": 32 }, "license": "CC-BY-SA-3.0", - "copyright": "Taken from /tg/station at https://github.com/tgstation/tgstation/commit/6bfe3b2e4fcbcdac9159dc4f0327a82ddf05ba7bi", + "copyright": "Taken from https://github.com/Skyrat-SS13/Skyrat-tg/blob/6e7197f550aac62a165c0a8c6b0835de19342623/modular_skyrat/modules/aesthetics/intercom/icons/intercom.dmi & build state from DenLemp#2965", "states": [ { "name": "base", diff --git a/Resources/Textures/Structures/Wallmounts/intercom.rsi/unshaded.png b/Resources/Textures/Structures/Wallmounts/intercom.rsi/unshaded.png index 7b0bb63072..9c4c3f199e 100644 Binary files a/Resources/Textures/Structures/Wallmounts/intercom.rsi/unshaded.png and b/Resources/Textures/Structures/Wallmounts/intercom.rsi/unshaded.png differ diff --git a/RobustToolbox b/RobustToolbox index 25bbb21dc8..eb63809999 160000 --- a/RobustToolbox +++ b/RobustToolbox @@ -1 +1 @@ -Subproject commit 25bbb21dc868b4e0b43b6d28e899710891b35868 +Subproject commit eb638099999dce3a43d90772ca976ae010d649c0