diff --git a/.github/workflows/build-docfx.yml b/.github/workflows/build-docfx.yml new file mode 100644 index 0000000000..68439cb6de --- /dev/null +++ b/.github/workflows/build-docfx.yml @@ -0,0 +1,41 @@ +name: Build & Publish Docfx + +on: + schedule: + - cron: "0 0 * * 0" + +jobs: + docfx: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Setup submodule + run: | + git submodule update --init --recursive + - name: Pull engine updates + uses: space-wizards/submodule-dependency@v0.1.5 + - name: Update Engine Submodules + run: | + cd RobustToolbox/ + git submodule update --init --recursive + - name: Setup .NET Core + uses: actions/setup-dotnet@v3 + with: + dotnet-version: 6.0.x + + - name: Install dependencies + run: dotnet restore + + - name: Build Project + run: dotnet build --no-restore /p:WarningsAsErrors=nullable + + - name: Build DocFX + uses: nikeee/docfx-action@v1.0.0 + with: + args: Content.Docfx/docfx.json + + - name: Publish Docfx Documentation on GitHub Pages + uses: maxheld83/ghpages@master + env: + BUILD_DIR: Content.Docfx/_content-site + GH_PAT: ${{ secrets.GH_PAT }} diff --git a/.github/workflows/build-test-debug.yml b/.github/workflows/build-test-debug.yml index d8128c0369..336293f3e4 100644 --- a/.github/workflows/build-test-debug.yml +++ b/.github/workflows/build-test-debug.yml @@ -49,7 +49,7 @@ jobs: git submodule update --init --recursive - name: Setup .NET Core - uses: actions/setup-dotnet@v1 + uses: actions/setup-dotnet@v3 with: dotnet-version: 6.0.x diff --git a/.github/workflows/build-test-release.yml b/.github/workflows/build-test-release.yml index 0eb56e033c..37dfe31c19 100644 --- a/.github/workflows/build-test-release.yml +++ b/.github/workflows/build-test-release.yml @@ -49,7 +49,7 @@ jobs: git submodule update --init --recursive - name: Setup .NET Core - uses: actions/setup-dotnet@v1 + uses: actions/setup-dotnet@v3 with: dotnet-version: 6.0.x diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 48b7460a80..263e8bf721 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -17,7 +17,7 @@ jobs: with: submodules: 'recursive' - name: Setup .NET Core - uses: actions/setup-dotnet@v1 + uses: actions/setup-dotnet@v3 with: dotnet-version: 6.0.100 diff --git a/.github/workflows/test-packaging.yml b/.github/workflows/test-packaging.yml index 36cb68abcc..d86c902b75 100644 --- a/.github/workflows/test-packaging.yml +++ b/.github/workflows/test-packaging.yml @@ -45,7 +45,7 @@ jobs: git submodule update --init --recursive - name: Setup .NET Core - uses: actions/setup-dotnet@v1 + uses: actions/setup-dotnet@v3 with: dotnet-version: 6.0.x diff --git a/.github/workflows/update-wiki.yml b/.github/workflows/update-wiki.yml index 068e515241..35fd92f36a 100644 --- a/.github/workflows/update-wiki.yml +++ b/.github/workflows/update-wiki.yml @@ -36,7 +36,7 @@ jobs: git submodule update --init --recursive - name: Setup .NET Core - uses: actions/setup-dotnet@v1 + uses: actions/setup-dotnet@v3 with: dotnet-version: 6.0.100 diff --git a/.github/workflows/yaml-linter.yml b/.github/workflows/yaml-linter.yml index da768c4dbf..bd4364e848 100644 --- a/.github/workflows/yaml-linter.yml +++ b/.github/workflows/yaml-linter.yml @@ -17,7 +17,7 @@ jobs: cd RobustToolbox/ git submodule update --init --recursive - name: Setup .NET Core - uses: actions/setup-dotnet@v1 + uses: actions/setup-dotnet@v3 with: dotnet-version: 6.0.100 - name: Install dependencies diff --git a/Content.Client/Buckle/BuckleComponent.cs b/Content.Client/Buckle/BuckleComponent.cs index 1bc43c3ce9..dd36dcf454 100644 --- a/Content.Client/Buckle/BuckleComponent.cs +++ b/Content.Client/Buckle/BuckleComponent.cs @@ -46,7 +46,12 @@ namespace Content.Client.Buckle return; } + // Adjust draw depth when the chair faces north so that the seat back is drawn over the player. + // Reset the draw depth when rotated in any other direction. // TODO when ECSing, make this a visualizer + // This code was written before rotatable viewports were introduced, so hard-coding Direction.North + // and comparing it against LocalRotation now breaks this in other rotations. This is a FIXME, but + // better to get it working for most people before we look at a more permanent solution. if (_buckled && LastEntityBuckledTo != null && EntMan.GetComponent(LastEntityBuckledTo.Value).LocalRotation.GetCardinalDir() == Direction.North && @@ -57,7 +62,8 @@ namespace Content.Client.Buckle return; } - if (_originalDrawDepth.HasValue && !_buckled) + // If here, we're not turning north and should restore the saved draw depth. + if (_originalDrawDepth.HasValue) { ownerSprite.DrawDepth = _originalDrawDepth.Value; _originalDrawDepth = null; diff --git a/Content.Client/Clothing/ClientClothingSystem.cs b/Content.Client/Clothing/ClientClothingSystem.cs index e9a417b5a1..3af58fded4 100644 --- a/Content.Client/Clothing/ClientClothingSystem.cs +++ b/Content.Client/Clothing/ClientClothingSystem.cs @@ -1,7 +1,7 @@ -using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; using Content.Client.Inventory; +using Content.Client.Humanoid; using Content.Shared.Clothing; using Content.Shared.Clothing.Components; using Content.Shared.Clothing.EntitySystems; @@ -42,8 +42,9 @@ public sealed class ClientClothingSystem : ClothingSystem {"pocket2", "POCKET2"}, }; - [Dependency] private IResourceCache _cache = default!; - [Dependency] private InventorySystem _inventorySystem = default!; + [Dependency] private readonly IResourceCache _cache = default!; + [Dependency] private readonly InventorySystem _inventorySystem = default!; + [Dependency] private readonly AppearanceSystem _appearance = default!; public override void Initialize() { @@ -53,6 +54,33 @@ public sealed class ClientClothingSystem : ClothingSystem SubscribeLocalEvent(OnVisualsChanged); SubscribeLocalEvent(OnDidUnequip); + SubscribeLocalEvent(OnAppearanceUpdate); + } + + private void OnAppearanceUpdate(EntityUid uid, ClientInventoryComponent component, ref AppearanceChangeEvent args) + { + // May need to update jumpsuit stencils if the sex changed. Also required to properly set the stencil on init + // when sex is first loaded from the profile. + if (!TryComp(uid, out SpriteComponent? sprite) || !sprite.LayerMapTryGet(HumanoidVisualLayers.StencilMask, out var layer)) + return; + + if (!args.AppearanceData.TryGetValue(HumanoidVisualizerKey.Key, out object? obj) + || obj is not HumanoidVisualizerData data + || data.Sex != Sex.Female + || !_inventorySystem.TryGetSlotEntity(uid, "jumpsuit", out var suit, component) + || !TryComp(suit, out ClothingComponent? clothing)) + { + sprite.LayerSetVisible(layer, false); + return; + } + + sprite.LayerSetState(layer, clothing.FemaleMask switch + { + FemaleClothingMask.NoMask => "female_none", + FemaleClothingMask.UniformTop => "female_top", + _ => "female_full", + }); + sprite.LayerSetVisible(layer, true); } private void OnGetVisuals(EntityUid uid, ClothingComponent item, GetEquipmentVisualsEvent args) @@ -188,14 +216,22 @@ public sealed class ClientClothingSystem : ClothingSystem if(!Resolve(equipee, ref inventory, ref sprite) || !Resolve(equipment, ref clothingComponent, false)) return; - if (slot == "jumpsuit" && sprite.LayerMapTryGet(HumanoidVisualLayers.StencilMask, out _)) + if (slot == "jumpsuit" && sprite.LayerMapTryGet(HumanoidVisualLayers.StencilMask, out var suitLayer)) { - sprite.LayerSetState(HumanoidVisualLayers.StencilMask, clothingComponent.FemaleMask switch + if (_appearance.TryGetData(equipee, HumanoidVisualizerKey.Key, out object? obj) + && obj is HumanoidVisualizerData data + && data.Sex == Sex.Female) { - FemaleClothingMask.NoMask => "female_none", - FemaleClothingMask.UniformTop => "female_top", - _ => "female_full", - }); + sprite.LayerSetState(suitLayer, clothingComponent.FemaleMask switch + { + FemaleClothingMask.NoMask => "female_none", + FemaleClothingMask.UniformTop => "female_top", + _ => "female_full", + }); + sprite.LayerSetVisible(suitLayer, true); + } + else + sprite.LayerSetVisible(suitLayer, false); } if (!_inventorySystem.TryGetSlot(equipee, slot, out var slotDef, inventory)) diff --git a/Content.Client/Construction/MachineFrameVisualizer.cs b/Content.Client/Construction/MachineFrameVisualizer.cs index fc19bfbbd4..f0bcbf4df3 100644 --- a/Content.Client/Construction/MachineFrameVisualizer.cs +++ b/Content.Client/Construction/MachineFrameVisualizer.cs @@ -1,8 +1,6 @@ using Content.Shared.Construction; using JetBrains.Annotations; using Robust.Client.GameObjects; -using Robust.Shared.GameObjects; -using Robust.Shared.IoC; namespace Content.Client.Construction { diff --git a/Content.Client/Construction/UI/ConstructionMenuPresenter.cs b/Content.Client/Construction/UI/ConstructionMenuPresenter.cs index f403eb74cb..d5c2147ea9 100644 --- a/Content.Client/Construction/UI/ConstructionMenuPresenter.cs +++ b/Content.Client/Construction/UI/ConstructionMenuPresenter.cs @@ -1,6 +1,8 @@ using System.Linq; using Content.Client.UserInterface.Systems.MenuBar.Widgets; using Content.Shared.Construction.Prototypes; +using Robust.Client.GameObjects; +using Robust.Client.Graphics; using Robust.Client.Placement; using Robust.Client.UserInterface; using Robust.Client.UserInterface.Controls; @@ -67,7 +69,6 @@ namespace Content.Client.Construction.UI /// /// Constructs a new instance of . /// - /// GUI that is being presented to. public ConstructionMenuPresenter() { // This is a lot easier than a factory @@ -203,8 +204,9 @@ namespace Content.Client.Construction.UI private void PopulateInfo(ConstructionPrototype prototype) { + var spriteSys = _systemManager.GetEntitySystem(); _constructionView.ClearRecipeInfo(); - _constructionView.SetRecipeInfo(prototype.Name, prototype.Description, prototype.Icon.Frame0(), prototype.Type != ConstructionType.Item); + _constructionView.SetRecipeInfo(prototype.Name, prototype.Description, spriteSys.Frame0(prototype.Icon), prototype.Type != ConstructionType.Item); var stepList = _constructionView.RecipeStepList; GenerateStepList(prototype, stepList); @@ -215,19 +217,24 @@ namespace Content.Client.Construction.UI if (_constructionSystem?.GetGuide(prototype) is not { } guide) return; + var spriteSys = _systemManager.GetEntitySystem(); + foreach (var entry in guide.Entries) { var text = entry.Arguments != null ? Loc.GetString(entry.Localization, entry.Arguments) : Loc.GetString(entry.Localization); if (entry.EntryNumber is {} number) + { text = Loc.GetString("construction-presenter-step-wrapper", ("step-number", number), ("text", text)); + } // The padding needs to be applied regardless of text length... (See PadLeft documentation) text = text.PadLeft(text.Length + entry.Padding); - stepList.AddItem(text, entry.Icon?.Frame0(), false); + var icon = entry.Icon != null ? spriteSys.Frame0(entry.Icon) : Texture.Transparent; + stepList.AddItem(text, icon, false); } } @@ -281,7 +288,7 @@ namespace Content.Client.Construction.UI { if (_selected == null || _selected.Type != ConstructionType.Structure) return; - var constructSystem = EntitySystem.Get(); + var constructSystem = _systemManager.GetEntitySystem(); _placementManager.BeginPlacing(new PlacementInformation() { diff --git a/Content.Client/Entry/EntryPoint.cs b/Content.Client/Entry/EntryPoint.cs index b8f9694214..86f412a69c 100644 --- a/Content.Client/Entry/EntryPoint.cs +++ b/Content.Client/Entry/EntryPoint.cs @@ -143,7 +143,6 @@ namespace Content.Client.Entry _ghostKick.Initialize(); _extendedDisconnectInformation.Initialize(); _playTimeTracking.Initialize(); - _baseClient.PlayerJoinedServer += (_, _) => { _mapManager.CreateNewMapEntity(MapId.Nullspace);}; //AUTOSCALING default Setup! _configManager.SetCVar("interface.resolutionAutoScaleUpperCutoffX", 1080); diff --git a/Content.Client/Gameplay/GameplayStateBase.cs b/Content.Client/Gameplay/GameplayStateBase.cs index 43397fbd10..f0d76fe1b1 100644 --- a/Content.Client/Gameplay/GameplayStateBase.cs +++ b/Content.Client/Gameplay/GameplayStateBase.cs @@ -56,17 +56,14 @@ namespace Content.Client.Gameplay public IList GetEntitiesUnderPosition(MapCoordinates coordinates) { // Find all the entities intersecting our click - var entities = EntitySystem.Get().GetEntitiesIntersecting(coordinates.MapId, - Box2.CenteredAround(coordinates.Position, (1, 1))); - - var containerSystem = _entitySystemManager.GetEntitySystem(); + var entities = _entityManager.EntitySysManager.GetEntitySystem().GetEntitiesIntersecting(coordinates.MapId, + Box2.CenteredAround(coordinates.Position, (1, 1)), LookupFlags.Uncontained | LookupFlags.Approximate); // Check the entities against whether or not we can click them var foundEntities = new List<(EntityUid clicked, int drawDepth, uint renderOrder)>(); foreach (var entity in entities) { if (_entityManager.TryGetComponent(entity, out var component) - && !containerSystem.IsEntityInContainer(entity) && component.CheckClick(coordinates.Position, out var drawDepthClicked, out var renderOrder)) { foundEntities.Add((entity, drawDepthClicked, renderOrder)); diff --git a/Content.Client/Lathe/UI/LatheMenu.xaml.cs b/Content.Client/Lathe/UI/LatheMenu.xaml.cs index 5a68494e1f..c5e99e1cb7 100644 --- a/Content.Client/Lathe/UI/LatheMenu.xaml.cs +++ b/Content.Client/Lathe/UI/LatheMenu.xaml.cs @@ -25,7 +25,6 @@ public sealed partial class LatheMenu : DefaultWindow public event Action? RecipeQueueAction; public List Recipes = new(); - private List _oldRecipesToShow = new(); public LatheMenu(LatheBoundUserInterface owner) { @@ -85,6 +84,9 @@ public sealed partial class LatheMenu : DefaultWindow /// public void PopulateRecipes(EntityUid lathe) { + if (!_entityManager.TryGetComponent(lathe, out var component)) + return; + var recipesToShow = new List(); foreach (var recipe in Recipes) { @@ -106,7 +108,6 @@ public sealed partial class LatheMenu : DefaultWindow quantity = 1; RecipeList.Children.Clear(); - _oldRecipesToShow = recipesToShow; foreach (var prototype in recipesToShow) { StringBuilder sb = new(); @@ -121,7 +122,7 @@ public sealed partial class LatheMenu : DefaultWindow else sb.Append('\n'); - sb.Append(amount); + sb.Append((int) (amount * component.MaterialUseMultiplier)); sb.Append(' '); sb.Append(proto.Name); } diff --git a/Content.Client/UserInterface/Systems/Chat/ChatUIController.cs b/Content.Client/UserInterface/Systems/Chat/ChatUIController.cs index 65be3202c3..d37f179b0c 100644 --- a/Content.Client/UserInterface/Systems/Chat/ChatUIController.cs +++ b/Content.Client/UserInterface/Systems/Chat/ChatUIController.cs @@ -437,7 +437,7 @@ public sealed class ChatUIController : UIController CanSendChannels |= ChatSelectChannel.Admin; } - SelectableChannels = CanSendChannels & ~ChatSelectChannel.Console; + SelectableChannels = CanSendChannels; // Necessary so that we always have a channel to fall back to. DebugTools.Assert((CanSendChannels & ChatSelectChannel.OOC) != 0, "OOC must always be available"); diff --git a/Content.Client/VendingMachines/VendingMachineSystem.cs b/Content.Client/VendingMachines/VendingMachineSystem.cs index cb9878b119..c18c29fc27 100644 --- a/Content.Client/VendingMachines/VendingMachineSystem.cs +++ b/Content.Client/VendingMachines/VendingMachineSystem.cs @@ -7,6 +7,7 @@ namespace Content.Client.VendingMachines; public sealed class VendingMachineSystem : SharedVendingMachineSystem { [Dependency] private readonly AnimationPlayerSystem _animationPlayer = default!; + [Dependency] private readonly SharedAppearanceSystem _appearanceSystem = default!; public override void Initialize() { @@ -21,7 +22,14 @@ public sealed class VendingMachineSystem : SharedVendingMachineSystem if (!TryComp(uid, out var sprite)) return; - UpdateAppearance(uid, VendingMachineVisualState.Normal, component, sprite); + if (!TryComp(uid, out var appearance) || + !_appearanceSystem.TryGetData(uid, VendingMachineVisuals.VisualState, out var visualStateObject, appearance) || + visualStateObject is not VendingMachineVisualState visualState) + { + visualState = VendingMachineVisualState.Normal; + } + + UpdateAppearance(uid, visualState, component, sprite); } private void OnAppearanceChange(EntityUid uid, VendingMachineComponent component, ref AppearanceChangeEvent args) diff --git a/Content.Client/Verbs/VerbSystem.cs b/Content.Client/Verbs/VerbSystem.cs index ce158af506..f62f13d37a 100644 --- a/Content.Client/Verbs/VerbSystem.cs +++ b/Content.Client/Verbs/VerbSystem.cs @@ -1,14 +1,9 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Linq; using Content.Client.CombatMode; using Content.Client.ContextMenu.UI; using Content.Client.Examine; using Content.Client.Gameplay; using Content.Client.Popups; using Content.Client.Verbs.UI; -using Content.Client.Viewport; using Content.Shared.Examine; using Content.Shared.GameTicking; using Content.Shared.Tag; @@ -18,11 +13,10 @@ using Robust.Client.GameObjects; using Robust.Client.Graphics; using Robust.Client.Player; using Robust.Client.State; -using Robust.Shared.Containers; -using Robust.Shared.GameObjects; -using Robust.Shared.IoC; using Robust.Shared.Map; using Robust.Shared.Utility; +using System.Diagnostics.CodeAnalysis; +using System.Linq; namespace Content.Client.Verbs { @@ -77,9 +71,9 @@ namespace Content.Client.Verbs VerbMenu?.Dispose(); } - public override void Update(float frameTime) + public override void FrameUpdate(float frameTime) { - base.Update(frameTime); + base.FrameUpdate(frameTime); EntityMenu?.Update(); } diff --git a/Content.IntegrationTests/Tests/Commands/RejuvenateTest.cs b/Content.IntegrationTests/Tests/Commands/RejuvenateTest.cs index fb163bf13a..df47a8770f 100644 --- a/Content.IntegrationTests/Tests/Commands/RejuvenateTest.cs +++ b/Content.IntegrationTests/Tests/Commands/RejuvenateTest.cs @@ -42,8 +42,6 @@ namespace Content.IntegrationTests.Tests.Commands await server.WaitAssertion(() => { - mapManager.CreateNewMapEntity(MapId.Nullspace); - var human = entManager.SpawnEntity("DamageableDummy", MapCoordinates.Nullspace); // Sanity check diff --git a/Content.IntegrationTests/Tests/DeleteInventoryTest.cs b/Content.IntegrationTests/Tests/DeleteInventoryTest.cs index 0303b12c2f..4542f7ebfc 100644 --- a/Content.IntegrationTests/Tests/DeleteInventoryTest.cs +++ b/Content.IntegrationTests/Tests/DeleteInventoryTest.cs @@ -21,6 +21,8 @@ namespace Content.IntegrationTests.Tests { await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true}); var server = pairTracker.Pair.Server; + var testMap = await PoolManager.CreateTestMap(pairTracker); + var coordinates = testMap.GridCoords; await server.WaitAssertion(() => { @@ -28,14 +30,12 @@ namespace Content.IntegrationTests.Tests var mapMan = IoCManager.Resolve(); var invSystem = IoCManager.Resolve().GetEntitySystem(); - mapMan.CreateNewMapEntity(MapId.Nullspace); - var entMgr = IoCManager.Resolve(); - var container = entMgr.SpawnEntity(null, MapCoordinates.Nullspace); + var container = entMgr.SpawnEntity(null, coordinates); entMgr.EnsureComponent(container); entMgr.EnsureComponent(container); - var child = entMgr.SpawnEntity(null, MapCoordinates.Nullspace); + var child = entMgr.SpawnEntity(null, coordinates); var item = entMgr.EnsureComponent(child); IoCManager.Resolve().GetEntitySystem().SetSlots(item.Owner, SlotFlags.HEAD, item); diff --git a/Content.IntegrationTests/Tests/DeviceNetwork/DeviceNetworkTest.cs b/Content.IntegrationTests/Tests/DeviceNetwork/DeviceNetworkTest.cs index 3627327292..7484b1b55b 100644 --- a/Content.IntegrationTests/Tests/DeviceNetwork/DeviceNetworkTest.cs +++ b/Content.IntegrationTests/Tests/DeviceNetwork/DeviceNetworkTest.cs @@ -73,8 +73,6 @@ namespace Content.IntegrationTests.Tests.DeviceNetwork }; await server.WaitAssertion(() => { - mapManager.CreateNewMapEntity(MapId.Nullspace); - device1 = entityManager.SpawnEntity("DummyNetworkDevice", MapCoordinates.Nullspace); Assert.That(entityManager.TryGetComponent(device1, out networkComponent1), Is.True); @@ -106,13 +104,14 @@ namespace Content.IntegrationTests.Tests.DeviceNetwork { await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true, ExtraPrototypes = Prototypes}); var server = pairTracker.Pair.Server; + var testMap = await PoolManager.CreateTestMap(pairTracker); + var coordinates = testMap.GridCoords; var mapManager = server.ResolveDependency(); var entityManager = server.ResolveDependency(); var deviceNetSystem = entityManager.EntitySysManager.GetEntitySystem(); var deviceNetTestSystem = entityManager.EntitySysManager.GetEntitySystem(); - EntityUid device1 = default; EntityUid device2 = default; DeviceNetworkComponent networkComponent1 = null; @@ -128,16 +127,14 @@ namespace Content.IntegrationTests.Tests.DeviceNetwork }; await server.WaitAssertion(() => { - mapManager.CreateNewMapEntity(MapId.Nullspace); - - device1 = entityManager.SpawnEntity("DummyWirelessNetworkDevice", MapCoordinates.Nullspace); + device1 = entityManager.SpawnEntity("DummyWirelessNetworkDevice", coordinates); Assert.That(entityManager.TryGetComponent(device1, out networkComponent1), Is.True); Assert.That(entityManager.TryGetComponent(device1, out wirelessNetworkComponent), Is.True); Assert.That(networkComponent1.ReceiveFrequency != null, Is.True); Assert.That(networkComponent1.Address, Is.Not.EqualTo(string.Empty)); - device2 = entityManager.SpawnEntity("DummyWirelessNetworkDevice", new MapCoordinates(new Robust.Shared.Maths.Vector2(0,50), MapId.Nullspace)); + device2 = entityManager.SpawnEntity("DummyWirelessNetworkDevice", new MapCoordinates(new Robust.Shared.Maths.Vector2(0,50), testMap.MapId)); Assert.That(entityManager.TryGetComponent(device2, out networkComponent2), Is.True); Assert.That(networkComponent2.ReceiveFrequency != null, Is.True); @@ -179,19 +176,20 @@ namespace Content.IntegrationTests.Tests.DeviceNetwork { await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true, ExtraPrototypes = Prototypes}); var server = pairTracker.Pair.Server; + var testMap = await PoolManager.CreateTestMap(pairTracker); + var coordinates = testMap.GridCoords; var mapManager = server.ResolveDependency(); var entityManager = server.ResolveDependency(); var deviceNetSystem = entityManager.EntitySysManager.GetEntitySystem(); var deviceNetTestSystem = entityManager.EntitySysManager.GetEntitySystem(); - EntityUid device1 = default; EntityUid device2 = default; DeviceNetworkComponent networkComponent1 = null; DeviceNetworkComponent networkComponent2 = null; WiredNetworkComponent wiredNetworkComponent = null; - IMapGrid grid = null; + IMapGrid grid = testMap.MapGrid; var testValue = "test"; var payload = new NetworkPayload @@ -205,17 +203,14 @@ namespace Content.IntegrationTests.Tests.DeviceNetwork await server.WaitIdleAsync(); await server.WaitAssertion(() => { - var map = mapManager.CreateNewMapEntity(MapId.Nullspace); - grid = mapManager.CreateGrid(MapId.Nullspace); - - device1 = entityManager.SpawnEntity("DummyWiredNetworkDevice", MapCoordinates.Nullspace); + device1 = entityManager.SpawnEntity("DummyWiredNetworkDevice", coordinates); Assert.That(entityManager.TryGetComponent(device1, out networkComponent1), Is.True); Assert.That(entityManager.TryGetComponent(device1, out wiredNetworkComponent), Is.True); Assert.That(networkComponent1.ReceiveFrequency != null, Is.True); Assert.That(networkComponent1.Address, Is.Not.EqualTo(string.Empty)); - device2 = entityManager.SpawnEntity("DummyWiredNetworkDevice", new MapCoordinates(new Robust.Shared.Maths.Vector2(0, 2), MapId.Nullspace)); + device2 = entityManager.SpawnEntity("DummyWiredNetworkDevice", coordinates); Assert.That(entityManager.TryGetComponent(device2, out networkComponent2), Is.True); Assert.That(networkComponent2.ReceiveFrequency != null, Is.True); @@ -232,7 +227,7 @@ namespace Content.IntegrationTests.Tests.DeviceNetwork await server.WaitAssertion(() => { //CollectionAssert.AreNotEqual(deviceNetTestSystem.LastPayload, payload); - entityManager.SpawnEntity("CableApcExtension", grid.MapToGrid(new MapCoordinates(new Robust.Shared.Maths.Vector2(0, 1), MapId.Nullspace))); + entityManager.SpawnEntity("CableApcExtension", coordinates); deviceNetSystem.QueuePacket(device1, networkComponent2.Address, payload, networkComponent2.ReceiveFrequency.Value); }); diff --git a/Content.IntegrationTests/Tests/Disposal/DisposalUnitTest.cs b/Content.IntegrationTests/Tests/Disposal/DisposalUnitTest.cs index 650780c05f..60dbfbde96 100644 --- a/Content.IntegrationTests/Tests/Disposal/DisposalUnitTest.cs +++ b/Content.IntegrationTests/Tests/Disposal/DisposalUnitTest.cs @@ -84,6 +84,10 @@ namespace Content.IntegrationTests.Tests.Disposal - type: Physics bodyType: KinematicController - type: Fixtures + fixtures: + - shape: + !type:PhysShapeCircle + radius: 0.35 - type: DoAfter - type: entity @@ -97,6 +101,10 @@ namespace Content.IntegrationTests.Tests.Disposal - type: Physics bodyType: Dynamic - type: Fixtures + fixtures: + - shape: + !type:PhysShapeCircle + radius: 0.35 - type: DoAfter - type: entity @@ -111,6 +119,10 @@ namespace Content.IntegrationTests.Tests.Disposal - type: Physics bodyType: Static - type: Fixtures + fixtures: + - shape: + !type:PhysShapeCircle + radius: 0.35 - type: entity name: DisposalTrunkDummy diff --git a/Content.IntegrationTests/Tests/DoAfter/DoAfterServerTest.cs b/Content.IntegrationTests/Tests/DoAfter/DoAfterServerTest.cs index 96c7b3db74..7a6c3f7f87 100644 --- a/Content.IntegrationTests/Tests/DoAfter/DoAfterServerTest.cs +++ b/Content.IntegrationTests/Tests/DoAfter/DoAfterServerTest.cs @@ -37,7 +37,6 @@ namespace Content.IntegrationTests.Tests.DoAfter await server.WaitPost(() => { var tickTime = 1.0f / IoCManager.Resolve().TickRate; - mapManager.CreateNewMapEntity(MapId.Nullspace); var mob = entityManager.SpawnEntity("Dummy", MapCoordinates.Nullspace); var cancelToken = new CancellationTokenSource(); var args = new DoAfterEventArgs(mob, tickTime / 2, cancelToken.Token); @@ -67,7 +66,6 @@ namespace Content.IntegrationTests.Tests.DoAfter await server.WaitPost(() => { var tickTime = 1.0f / IoCManager.Resolve().TickRate; - mapManager.CreateNewMapEntity(MapId.Nullspace); var mob = entityManager.SpawnEntity("Dummy", MapCoordinates.Nullspace); var cancelToken = new CancellationTokenSource(); diff --git a/Content.IntegrationTests/Tests/Doors/AirlockTest.cs b/Content.IntegrationTests/Tests/Doors/AirlockTest.cs index 719b50a809..7d50ce2a33 100644 --- a/Content.IntegrationTests/Tests/Doors/AirlockTest.cs +++ b/Content.IntegrationTests/Tests/Doors/AirlockTest.cs @@ -60,8 +60,6 @@ namespace Content.IntegrationTests.Tests.Doors await server.WaitAssertion(() => { - mapManager.CreateNewMapEntity(MapId.Nullspace); - airlock = entityManager.SpawnEntity("AirlockDummy", MapCoordinates.Nullspace); Assert.True(entityManager.TryGetComponent(airlock, out doorComponent)); diff --git a/Content.IntegrationTests/Tests/GameObjects/Components/Movement/ClimbUnitTest.cs b/Content.IntegrationTests/Tests/GameObjects/Components/Movement/ClimbUnitTest.cs index 55db8be0b4..5033c50e31 100644 --- a/Content.IntegrationTests/Tests/GameObjects/Components/Movement/ClimbUnitTest.cs +++ b/Content.IntegrationTests/Tests/GameObjects/Components/Movement/ClimbUnitTest.cs @@ -43,8 +43,6 @@ namespace Content.IntegrationTests.Tests.GameObjects.Components.Movement await server.WaitAssertion(() => { var mapManager = IoCManager.Resolve(); - mapManager.CreateNewMapEntity(MapId.Nullspace); - var entityManager = IoCManager.Resolve(); // Spawn the entities diff --git a/Content.IntegrationTests/Tests/HumanInventoryUniformSlotsTest.cs b/Content.IntegrationTests/Tests/HumanInventoryUniformSlotsTest.cs index bc1cce5222..f6a4d9dc3a 100644 --- a/Content.IntegrationTests/Tests/HumanInventoryUniformSlotsTest.cs +++ b/Content.IntegrationTests/Tests/HumanInventoryUniformSlotsTest.cs @@ -60,6 +60,8 @@ namespace Content.IntegrationTests.Tests { await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true, ExtraPrototypes = Prototypes}); var server = pairTracker.Pair.Server; + var testMap = await PoolManager.CreateTestMap(pairTracker); + var coordinates = testMap.GridCoords; EntityUid human = default; EntityUid uniform = default; @@ -72,16 +74,13 @@ namespace Content.IntegrationTests.Tests { invSystem = IoCManager.Resolve().GetEntitySystem(); var mapMan = IoCManager.Resolve(); - - mapMan.CreateNewMapEntity(MapId.Nullspace); - var entityMan = IoCManager.Resolve(); - human = entityMan.SpawnEntity("HumanDummy", MapCoordinates.Nullspace); - uniform = entityMan.SpawnEntity("UniformDummy", MapCoordinates.Nullspace); - idCard = entityMan.SpawnEntity("IDCardDummy", MapCoordinates.Nullspace); - pocketItem = entityMan.SpawnEntity("FlashlightDummy", MapCoordinates.Nullspace); - var tooBigItem = entityMan.SpawnEntity("ToolboxDummy", MapCoordinates.Nullspace); + human = entityMan.SpawnEntity("HumanDummy", coordinates); + uniform = entityMan.SpawnEntity("UniformDummy", coordinates); + idCard = entityMan.SpawnEntity("IDCardDummy", coordinates); + pocketItem = entityMan.SpawnEntity("FlashlightDummy", coordinates); + var tooBigItem = entityMan.SpawnEntity("ToolboxDummy", coordinates); Assert.That(invSystem.CanEquip(human, uniform, "jumpsuit", out _)); diff --git a/Content.IntegrationTests/Tests/InventoryHelpersTest.cs b/Content.IntegrationTests/Tests/InventoryHelpersTest.cs index 5ef3c2990d..6a7d8c8c13 100644 --- a/Content.IntegrationTests/Tests/InventoryHelpersTest.cs +++ b/Content.IntegrationTests/Tests/InventoryHelpersTest.cs @@ -52,9 +52,6 @@ namespace Content.IntegrationTests.Tests { var mapMan = IoCManager.Resolve(); var systemMan = IoCManager.Resolve(); - - mapMan.CreateNewMapEntity(MapId.Nullspace); - var human = sEntities.SpawnEntity("InventoryStunnableDummy", MapCoordinates.Nullspace); var invSystem = systemMan.GetEntitySystem(); diff --git a/Content.IntegrationTests/Tests/MindEntityDeletionTest.cs b/Content.IntegrationTests/Tests/MindEntityDeletionTest.cs index 5c84e1ff2f..f760c86a9f 100644 --- a/Content.IntegrationTests/Tests/MindEntityDeletionTest.cs +++ b/Content.IntegrationTests/Tests/MindEntityDeletionTest.cs @@ -124,25 +124,18 @@ namespace Content.IntegrationTests.Tests { await using var pairTracker = await PoolManager.GetServerClient(); var server = pairTracker.Pair.Server; + var testMap = await PoolManager.CreateTestMap(pairTracker); + var coordinates = testMap.GridCoords; EntityUid playerEnt = default; Mind mind = null; - MapId map = default; await server.WaitAssertion(() => { var player = IoCManager.Resolve().ServerSessions.Single(); var mapMan = IoCManager.Resolve(); - - map = mapMan.CreateMap(); - var grid = mapMan.CreateGrid(map); - var entMgr = IoCManager.Resolve(); - - mapMan.CreateNewMapEntity(MapId.Nullspace); - - playerEnt = entMgr.SpawnEntity(null, grid.ToCoordinates()); - + playerEnt = entMgr.SpawnEntity(null, coordinates); mind = new Mind(player.UserId); mind.ChangeOwningPlayer(player.UserId); @@ -156,8 +149,7 @@ namespace Content.IntegrationTests.Tests await server.WaitPost(() => { var mapMan = IoCManager.Resolve(); - - mapMan.DeleteMap(map); + mapMan.DeleteMap(testMap.MapId); }); await PoolManager.RunTicksSync(pairTracker.Pair, 5); diff --git a/Content.IntegrationTests/Tests/PrototypeSaveTest.cs b/Content.IntegrationTests/Tests/PrototypeSaveTest.cs index d5d7114bea..91f26e3f33 100644 --- a/Content.IntegrationTests/Tests/PrototypeSaveTest.cs +++ b/Content.IntegrationTests/Tests/PrototypeSaveTest.cs @@ -103,7 +103,6 @@ public sealed class PrototypeSaveTest "CrateArtifactContainer", "CloningPod", "DrinkColaCan", - "MachineFrame", "WeaponImprovisedPneumaticCannon", "LauncherCreamPie", "GravityGenerator", @@ -127,7 +126,38 @@ public sealed class PrototypeSaveTest "ClothingHeadHatChef", "Bucket", "AirlockShuttle", - "AirlockGlassShuttle" + "AirlockGlassShuttle", + // The followjng are all fixture-less phsyics entities that set can-collide to false on init. + "CarpRift", + "GasMinerOxygen", + "GasMinerNitrogen", + "GasMinerCarbonDioxide", + "GasMinerPlasma", + "GasMinerTritium", + "GasMinerWaterVapor", + "GasMinerMiasma", + "GasMinerNitrousOxide", + "SignalSwitch", + "SignalButton", + "ApcNetSwitch", + "TetherEntity", + "SignalButtonExt1", + "SignalButtonExt2", + "SignalButtonExt3", + "SignalButtonBridge", + "SignalButtonWindows", + "GrilleBroken", + "BaseGeneratorWallmountFrame", + "GeneratorWallmountBasic", + "GeneratorWallmountAPU", + "Lightning", + "LightningRevenant", + "ChargedLightning", + "SuperchargedLightning", + "HyperchargedLightning", + "BaseSubstationWall", + "SubstationWallBasic", + "BaseSubstationWallFrame" }; [Test] diff --git a/Content.IntegrationTests/Tests/Station/StationJobsTest.cs b/Content.IntegrationTests/Tests/Station/StationJobsTest.cs index 11b09c1552..b8be6b807e 100644 --- a/Content.IntegrationTests/Tests/Station/StationJobsTest.cs +++ b/Content.IntegrationTests/Tests/Station/StationJobsTest.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; @@ -157,7 +157,6 @@ public sealed class StationJobsTest var station = EntityUid.Invalid; await server.WaitPost(() => { - mapManager.CreateNewMapEntity(MapId.Nullspace); station = stationSystem.InitializeNewStation(fooStationProto.Stations["Station"], null, $"Foo Station"); }); diff --git a/Content.IntegrationTests/Tests/Tag/TagTest.cs b/Content.IntegrationTests/Tests/Tag/TagTest.cs index 4a025f752c..5f949a5080 100644 --- a/Content.IntegrationTests/Tests/Tag/TagTest.cs +++ b/Content.IntegrationTests/Tests/Tag/TagTest.cs @@ -1,4 +1,4 @@ -#nullable enable +#nullable enable using System.Collections.Generic; using System.Threading.Tasks; using Content.Shared.Tag; @@ -57,7 +57,6 @@ namespace Content.IntegrationTests.Tests.Tag await server.WaitPost(() => { - sMapManager.CreateNewMapEntity(MapId.Nullspace); sTagDummy = sEntityManager.SpawnEntity(TagEntityId, MapCoordinates.Nullspace); sTagComponent = sEntityManager.GetComponent(sTagDummy); }); diff --git a/Content.Server/Atmos/EntitySystems/AirtightSystem.cs b/Content.Server/Atmos/EntitySystems/AirtightSystem.cs index 99054cd2d0..b42e8d6a8a 100644 --- a/Content.Server/Atmos/EntitySystems/AirtightSystem.cs +++ b/Content.Server/Atmos/EntitySystems/AirtightSystem.cs @@ -91,6 +91,9 @@ namespace Content.Server.Atmos.EntitySystems public void SetAirblocked(AirtightComponent airtight, bool airblocked, TransformComponent? xform = null) { + if (airtight.AirBlocked == airblocked) + return; + if (!Resolve(airtight.Owner, ref xform)) return; airtight.AirBlocked = airblocked; diff --git a/Content.Server/Cargo/Systems/CargoSystem.Shuttle.cs b/Content.Server/Cargo/Systems/CargoSystem.Shuttle.cs index f5c2e85cdb..00e0bb8f81 100644 --- a/Content.Server/Cargo/Systems/CargoSystem.Shuttle.cs +++ b/Content.Server/Cargo/Systems/CargoSystem.Shuttle.cs @@ -316,10 +316,12 @@ public sealed partial class CargoSystem foreach (var pallet in GetCargoPallets(component)) { // Containers should already get the sell price of their children so can skip those. - foreach (var ent in _lookup.GetEntitiesIntersecting(pallet.Owner, LookupFlags.Anchored | LookupFlags.Approximate)) + foreach (var ent in _lookup.GetEntitiesIntersecting(pallet.Owner, LookupFlags.Dynamic | LookupFlags.Sundries | LookupFlags.Approximate)) { - // Don't re-sell anything, sell anything anchored (e.g. light fixtures), or anything blacklisted - // (e.g. players). + // Dont sell: + // - anything already being sold + // - anything anchored (e.g. light fixtures) + // - anything blacklisted (e.g. players). if (toSell.Contains(ent) || (xformQuery.TryGetComponent(ent, out var xform) && xform.Anchored)) continue; diff --git a/Content.Server/Chemistry/Components/MeleeChemicalInjectorComponent.cs b/Content.Server/Chemistry/Components/MeleeChemicalInjectorComponent.cs index 0bc5b3ae04..4b855f759a 100644 --- a/Content.Server/Chemistry/Components/MeleeChemicalInjectorComponent.cs +++ b/Content.Server/Chemistry/Components/MeleeChemicalInjectorComponent.cs @@ -14,5 +14,12 @@ namespace Content.Server.Chemistry.Components [DataField("transferEfficiency")] private float _transferEfficiency = 1f; + + /// + /// Solution to inject from. + /// + [ViewVariables(VVAccess.ReadWrite)] + [DataField("solution")] + public string Solution { get; set; } = "default"; } } diff --git a/Content.Server/Clothing/ClothingSystem.cs b/Content.Server/Clothing/ClothingSystem.cs index 288c3f7ac5..93223838f6 100644 --- a/Content.Server/Clothing/ClothingSystem.cs +++ b/Content.Server/Clothing/ClothingSystem.cs @@ -20,8 +20,7 @@ public sealed class ServerClothingSystem : ClothingSystem if (args.Slot == "head" && _tagSystem.HasTag(args.Equipment, "HidesHair")) { - _humanoidSystem.SetLayersVisibility(args.Equipee, - HumanoidVisualLayersExtension.Sublayers(HumanoidVisualLayers.Head), false); + _humanoidSystem.ToggleHiddenLayer(args.Equipee, HumanoidVisualLayers.Hair); } } @@ -34,8 +33,7 @@ public sealed class ServerClothingSystem : ClothingSystem if (args.Slot == "head" && _tagSystem.HasTag(args.Equipment, "HidesHair")) { - _humanoidSystem.SetLayersVisibility(args.Equipee, - HumanoidVisualLayersExtension.Sublayers(HumanoidVisualLayers.Head), true); + _humanoidSystem.ToggleHiddenLayer(args.Equipee, HumanoidVisualLayers.Hair); } } } diff --git a/Content.Server/Construction/AnchorableSystem.cs b/Content.Server/Construction/AnchorableSystem.cs index 93b8b1acf4..0995242728 100644 --- a/Content.Server/Construction/AnchorableSystem.cs +++ b/Content.Server/Construction/AnchorableSystem.cs @@ -51,9 +51,9 @@ namespace Content.Server.Construction component.CancelToken = null; var xform = Transform(uid); - RaiseLocalEvent(uid, new BeforeUnanchoredEvent(args.User, args.Using), false); + RaiseLocalEvent(uid, new BeforeUnanchoredEvent(args.User, args.Using)); xform.Anchored = false; - RaiseLocalEvent(uid, new UserUnanchoredEvent(args.User, args.Using), false); + RaiseLocalEvent(uid, new UserUnanchoredEvent(args.User, args.Using)); _popup.PopupEntity(Loc.GetString("anchorable-unanchored"), uid, Filter.Pvs(uid, entityManager: EntityManager)); @@ -93,9 +93,9 @@ namespace Content.Server.Construction if (component.Snap) xform.Coordinates = xform.Coordinates.SnapToGrid(EntityManager, _mapManager); - RaiseLocalEvent(uid, new BeforeAnchoredEvent(args.User, args.Using), false); + RaiseLocalEvent(uid, new BeforeAnchoredEvent(args.User, args.Using)); xform.Anchored = true; - RaiseLocalEvent(uid, new UserAnchoredEvent(args.User, args.Using), false); + RaiseLocalEvent(uid, new UserAnchoredEvent(args.User, args.Using)); _popup.PopupEntity(Loc.GetString("anchorable-anchored"), uid, Filter.Pvs(uid, entityManager: EntityManager)); @@ -155,16 +155,13 @@ namespace Content.Server.Construction // Need to cast the event or it will be raised as BaseAnchoredAttemptEvent. if (anchoring) - RaiseLocalEvent(uid, (AnchorAttemptEvent) attempt, false); + RaiseLocalEvent(uid, (AnchorAttemptEvent) attempt); else - RaiseLocalEvent(uid, (UnanchorAttemptEvent) attempt, false); + RaiseLocalEvent(uid, (UnanchorAttemptEvent) attempt); anchorable.Delay += attempt.Delay; - if (attempt.Cancelled) - return false; - - return true; + return !attempt.Cancelled; } /// diff --git a/Content.Server/Construction/Commands/FixRotationsCommand.cs b/Content.Server/Construction/Commands/FixRotationsCommand.cs index 1bacaf3f8f..8d933ef04c 100644 --- a/Content.Server/Construction/Commands/FixRotationsCommand.cs +++ b/Content.Server/Construction/Commands/FixRotationsCommand.cs @@ -63,7 +63,7 @@ namespace Content.Server.Construction.Commands } var changed = 0; - var tagSystem = EntitySystem.Get(); + var tagSystem = entityManager.EntitySysManager.GetEntitySystem(); foreach (var child in xformQuery.GetComponent(grid.GridEntityId).ChildEntities) { diff --git a/Content.Server/Construction/Commands/TileReplaceCommand.cs b/Content.Server/Construction/Commands/TileReplaceCommand.cs index 82d27f10e3..3794dfd424 100644 --- a/Content.Server/Construction/Commands/TileReplaceCommand.cs +++ b/Content.Server/Construction/Commands/TileReplaceCommand.cs @@ -1,11 +1,8 @@ using Content.Server.Administration; using Content.Shared.Administration; -using Content.Shared.Maps; -using Content.Shared.Tag; using Robust.Server.Player; using Robust.Shared.Console; using Robust.Shared.Map; -using Robust.Shared.Prototypes; namespace Content.Server.Construction.Commands; @@ -22,8 +19,8 @@ sealed class TileReplaceCommand : IConsoleCommand var player = shell.Player as IPlayerSession; var entityManager = IoCManager.Resolve(); EntityUid? gridId; - string tileIdA = ""; - string tileIdB = ""; + string tileIdA; + string tileIdB; switch (args.Length) { diff --git a/Content.Server/Construction/Commands/TileWallsCommand.cs b/Content.Server/Construction/Commands/TileWallsCommand.cs index 9b85f3d9da..12e592eb0b 100644 --- a/Content.Server/Construction/Commands/TileWallsCommand.cs +++ b/Content.Server/Construction/Commands/TileWallsCommand.cs @@ -5,7 +5,6 @@ using Content.Shared.Tag; using Robust.Server.Player; using Robust.Shared.Console; using Robust.Shared.Map; -using Robust.Shared.Prototypes; namespace Content.Server.Construction.Commands { @@ -17,7 +16,7 @@ namespace Content.Server.Construction.Commands public string Description => "Puts an underplating tile below every wall on a grid."; public string Help => $"Usage: {Command} | {Command}"; - public const string TilePrototypeID = "Plating"; + public const string TilePrototypeId = "Plating"; public const string WallTag = "Wall"; public void Execute(IConsoleShell shell, string argStr, string[] args) @@ -65,8 +64,8 @@ namespace Content.Server.Construction.Commands } var tileDefinitionManager = IoCManager.Resolve(); - var tagSystem = EntitySystem.Get(); - var underplating = tileDefinitionManager[TilePrototypeID]; + var tagSystem = entityManager.EntitySysManager.GetEntitySystem(); + var underplating = tileDefinitionManager[TilePrototypeId]; var underplatingTile = new Tile(underplating.TileId); var changed = 0; foreach (var child in entityManager.GetComponent(grid.GridEntityId).ChildEntities) @@ -91,7 +90,7 @@ namespace Content.Server.Construction.Commands var tile = grid.GetTileRef(childTransform.Coordinates); var tileDef = (ContentTileDefinition) tileDefinitionManager[tile.Tile.TypeId]; - if (tileDef.ID == TilePrototypeID) + if (tileDef.ID == TilePrototypeId) { continue; } diff --git a/Content.Server/Construction/Completions/AddContainer.cs b/Content.Server/Construction/Completions/AddContainer.cs index deccd281a3..882c5c2a52 100644 --- a/Content.Server/Construction/Completions/AddContainer.cs +++ b/Content.Server/Construction/Completions/AddContainer.cs @@ -7,7 +7,7 @@ namespace Content.Server.Construction.Completions [DataDefinition] public sealed class AddContainer : IGraphAction { - [DataField("container")] public string? Container { get; private set; } = null; + [DataField("container")] public string? Container { get; private set; } public void PerformAction(EntityUid uid, EntityUid? userUid, IEntityManager entityManager) { diff --git a/Content.Server/Construction/Completions/AttemptElectrocute.cs b/Content.Server/Construction/Completions/AttemptElectrocute.cs index 3d4000f755..cabb792552 100644 --- a/Content.Server/Construction/Completions/AttemptElectrocute.cs +++ b/Content.Server/Construction/Completions/AttemptElectrocute.cs @@ -11,7 +11,7 @@ namespace Content.Server.Construction.Completions if (userUid == null) return; - EntitySystem.Get().TryDoElectrifiedAct(uid, userUid.Value); + entityManager.EntitySysManager.GetEntitySystem().TryDoElectrifiedAct(uid, userUid.Value); } } } diff --git a/Content.Server/Construction/Completions/BuildMachine.cs b/Content.Server/Construction/Completions/BuildMachine.cs index 230613e260..917d0ab887 100644 --- a/Content.Server/Construction/Completions/BuildMachine.cs +++ b/Content.Server/Construction/Completions/BuildMachine.cs @@ -2,6 +2,7 @@ using System.Linq; using Content.Server.Construction.Components; using Content.Shared.Construction; using JetBrains.Annotations; +using Robust.Server.Containers; using Robust.Shared.Containers; namespace Content.Server.Construction.Completions @@ -24,7 +25,7 @@ namespace Content.Server.Construction.Completions return; } - if (!EntitySystem.Get().IsComplete(machineFrame)) + if (!entityManager.EntitySysManager.GetEntitySystem().IsComplete(machineFrame)) { Logger.Warning($"Machine frame entity {uid} doesn't have all required parts to be built! Aborting build machine action."); return; @@ -57,24 +58,25 @@ namespace Content.Server.Construction.Completions entBoardContainer.Remove(board); + var containerSys = entityManager.EntitySysManager.GetEntitySystem(); var transform = entityManager.GetComponent(uid); var machine = entityManager.SpawnEntity(boardComponent.Prototype, transform.Coordinates); entityManager.GetComponent(machine).LocalRotation = transform.LocalRotation; - var boardContainer = machine.EnsureContainer(MachineFrameComponent.BoardContainerName, out var existed); + var boardContainer = containerSys.EnsureContainer(machine, MachineFrameComponent.BoardContainerName, out var existed); if (existed) { // Clean that up... - boardContainer.CleanContainer(); + containerSys.CleanContainer(boardContainer); } - var partContainer = machine.EnsureContainer(MachineFrameComponent.PartContainerName, out existed); + var partContainer = containerSys.EnsureContainer(machine, MachineFrameComponent.PartContainerName, out existed); if (existed) { // Clean that up, too... - partContainer.CleanContainer(); + containerSys.CleanContainer(partContainer); } boardContainer.Insert(board); diff --git a/Content.Server/Construction/Completions/ConditionalAction.cs b/Content.Server/Construction/Completions/ConditionalAction.cs index 13fe62e4f6..d2827c5ecb 100644 --- a/Content.Server/Construction/Completions/ConditionalAction.cs +++ b/Content.Server/Construction/Completions/ConditionalAction.cs @@ -7,13 +7,13 @@ namespace Content.Server.Construction.Completions [DataDefinition] public sealed class ConditionalAction : IGraphAction { - [DataField("passUser")] public bool PassUser { get; } = false; + [DataField("passUser")] public bool PassUser { get; } - [DataField("condition", required:true)] public IGraphCondition? Condition { get; } = null; + [DataField("condition", required:true)] public IGraphCondition? Condition { get; } - [DataField("action", required:true)] public IGraphAction? Action { get; } = null; + [DataField("action", required:true)] public IGraphAction? Action { get; } - [DataField("else")] public IGraphAction? Else { get; } = null; + [DataField("else")] public IGraphAction? Else { get; } public void PerformAction(EntityUid uid, EntityUid? userUid, IEntityManager entityManager) { diff --git a/Content.Server/Construction/Completions/DeleteEntitiesInContainer.cs b/Content.Server/Construction/Completions/DeleteEntitiesInContainer.cs index 4f22aba61d..0b030447ac 100644 --- a/Content.Server/Construction/Completions/DeleteEntitiesInContainer.cs +++ b/Content.Server/Construction/Completions/DeleteEntitiesInContainer.cs @@ -1,5 +1,6 @@ using System.Linq; using Content.Shared.Construction; +using Robust.Server.Containers; using Robust.Shared.Containers; namespace Content.Server.Construction.Completions @@ -11,10 +12,12 @@ namespace Content.Server.Construction.Completions public void PerformAction(EntityUid uid, EntityUid? userUid, IEntityManager entityManager) { - if (string.IsNullOrEmpty(Container)) return; - // TODO CONSTRUCTION: Use the new ContainerSystem methods here. - if (!entityManager.TryGetComponent(uid, out ContainerManagerComponent? containerMan)) return; - if (!containerMan.TryGetContainer(Container, out var container)) return; + if (string.IsNullOrEmpty(Container)) + return; + var containerSys = entityManager.EntitySysManager.GetEntitySystem(); + + if (!containerSys.TryGetContainer(uid, Container, out var container)) + return; foreach (var contained in container.ContainedEntities.ToArray()) { diff --git a/Content.Server/Construction/Completions/EmptyAllContainers.cs b/Content.Server/Construction/Completions/EmptyAllContainers.cs index 77a71c51c4..9cf5c9f83c 100644 --- a/Content.Server/Construction/Completions/EmptyAllContainers.cs +++ b/Content.Server/Construction/Completions/EmptyAllContainers.cs @@ -1,5 +1,6 @@ using Content.Shared.Construction; using JetBrains.Annotations; +using Robust.Server.Containers; using Robust.Shared.Containers; namespace Content.Server.Construction.Completions @@ -14,9 +15,10 @@ namespace Content.Server.Construction.Completions return; var transform = entityManager.GetComponent(uid); + var containerSys = entityManager.EntitySysManager.GetEntitySystem(); foreach (var container in containerManager.GetAllContainers()) { - container.EmptyContainer(true, transform.Coordinates); + containerSys.EmptyContainer(container, true, transform.Coordinates); } } } diff --git a/Content.Server/Construction/Completions/EmptyContainer.cs b/Content.Server/Construction/Completions/EmptyContainer.cs index ebb80a749b..88c3b807bd 100644 --- a/Content.Server/Construction/Completions/EmptyContainer.cs +++ b/Content.Server/Construction/Completions/EmptyContainer.cs @@ -1,6 +1,7 @@ using System.Linq; using Content.Shared.Construction; using JetBrains.Annotations; +using Robust.Server.Containers; using Robust.Shared.Containers; namespace Content.Server.Construction.Completions @@ -16,15 +17,9 @@ namespace Content.Server.Construction.Completions if (!entityManager.TryGetComponent(uid, out ContainerManagerComponent? containerManager) || !containerManager.TryGetContainer(Container, out var container)) return; - // TODO: Use container system methods. + var containerSys = entityManager.EntitySysManager.GetEntitySystem(); var transform = entityManager.GetComponent(uid); - foreach (var contained in container.ContainedEntities.ToArray()) - { - container.ForceRemove(contained); - var cTransform = entityManager.GetComponent(contained); - cTransform.Coordinates = transform.Coordinates; - cTransform.AttachToGridOrMap(); - } + containerSys.EmptyContainer(container, true, transform.Coordinates, true); } } } diff --git a/Content.Server/Construction/Completions/MachineFrameRegenerateProgress.cs b/Content.Server/Construction/Completions/MachineFrameRegenerateProgress.cs index 1abb3f72cf..425c95bc0d 100644 --- a/Content.Server/Construction/Completions/MachineFrameRegenerateProgress.cs +++ b/Content.Server/Construction/Completions/MachineFrameRegenerateProgress.cs @@ -12,7 +12,7 @@ namespace Content.Server.Construction.Completions { if (entityManager.TryGetComponent(uid, out var machineFrame)) { - EntitySystem.Get().RegenerateProgress(machineFrame); + entityManager.EntitySysManager.GetEntitySystem().RegenerateProgress(machineFrame); } } } diff --git a/Content.Server/Construction/Completions/MoveContainer.cs b/Content.Server/Construction/Completions/MoveContainer.cs index c2fdb0ae75..77d11c7e85 100644 --- a/Content.Server/Construction/Completions/MoveContainer.cs +++ b/Content.Server/Construction/Completions/MoveContainer.cs @@ -10,8 +10,8 @@ namespace Content.Server.Construction.Completions [DataDefinition] public sealed class MoveContainer : IGraphAction { - [DataField("from")] public string? FromContainer { get; } = null; - [DataField("to")] public string? ToContainer { get; } = null; + [DataField("from")] public string? FromContainer { get; } + [DataField("to")] public string? ToContainer { get; } public void PerformAction(EntityUid uid, EntityUid? userUid, IEntityManager entityManager) { diff --git a/Content.Server/Construction/Completions/PlaySound.cs b/Content.Server/Construction/Completions/PlaySound.cs index 69f95ab456..28ebc2e19a 100644 --- a/Content.Server/Construction/Completions/PlaySound.cs +++ b/Content.Server/Construction/Completions/PlaySound.cs @@ -1,7 +1,6 @@ using Content.Shared.Construction; using JetBrains.Annotations; using Robust.Shared.Audio; -using Robust.Shared.Player; using Robust.Shared.Random; namespace Content.Server.Construction.Completions @@ -22,7 +21,8 @@ namespace Content.Server.Construction.Completions public void PerformAction(EntityUid uid, EntityUid? userUid, IEntityManager entityManager) { var scale = (float) IoCManager.Resolve().NextGaussian(1, Variation); - SoundSystem.Play(Sound.GetSound(), Filter.Pvs(uid, entityManager: entityManager), uid, AudioParams.WithPitchScale(scale)); + entityManager.EntitySysManager.GetEntitySystem() + .PlayPvs(Sound, uid, AudioParams.WithPitchScale(scale)); } } } diff --git a/Content.Server/Construction/Completions/PopupUser.cs b/Content.Server/Construction/Completions/PopupUser.cs index 2638af23fb..f975fec3a6 100644 --- a/Content.Server/Construction/Completions/PopupUser.cs +++ b/Content.Server/Construction/Completions/PopupUser.cs @@ -9,7 +9,7 @@ namespace Content.Server.Construction.Completions [DataDefinition] public sealed class PopupUser : IGraphAction { - [DataField("cursor")] public bool Cursor { get; } = false; + [DataField("cursor")] public bool Cursor { get; } [DataField("text")] public string Text { get; } = string.Empty; public void PerformAction(EntityUid uid, EntityUid? userUid, IEntityManager entityManager) diff --git a/Content.Server/Construction/Completions/RaiseEvent.cs b/Content.Server/Construction/Completions/RaiseEvent.cs index ca03de7d3d..2d28ae5c52 100644 --- a/Content.Server/Construction/Completions/RaiseEvent.cs +++ b/Content.Server/Construction/Completions/RaiseEvent.cs @@ -7,7 +7,7 @@ namespace Content.Server.Construction.Completions public sealed class RaiseEvent : IGraphAction { [DataField("event", required:true)] - public EntityEventArgs? Event { get; } = null; + public EntityEventArgs? Event { get; } [DataField("directed")] public bool Directed { get; } = true; @@ -21,7 +21,7 @@ namespace Content.Server.Construction.Completions return; if(Directed) - entityManager.EventBus.RaiseLocalEvent(uid, (object)Event, false); + entityManager.EventBus.RaiseLocalEvent(uid, (object)Event); if(Broadcast) entityManager.EventBus.RaiseEvent(EventSource.Local, (object)Event); diff --git a/Content.Server/Construction/Completions/SetStackCount.cs b/Content.Server/Construction/Completions/SetStackCount.cs index ad2242ae73..48f255102b 100644 --- a/Content.Server/Construction/Completions/SetStackCount.cs +++ b/Content.Server/Construction/Completions/SetStackCount.cs @@ -12,7 +12,7 @@ namespace Content.Server.Construction.Completions public void PerformAction(EntityUid uid, EntityUid? userUid, IEntityManager entityManager) { - EntitySystem.Get().SetCount(uid, Amount); + entityManager.EntitySysManager.GetEntitySystem().SetCount(uid, Amount); } } } diff --git a/Content.Server/Construction/Completions/SnapToGrid.cs b/Content.Server/Construction/Completions/SnapToGrid.cs index 7d2c35a872..2ef0663972 100644 --- a/Content.Server/Construction/Completions/SnapToGrid.cs +++ b/Content.Server/Construction/Completions/SnapToGrid.cs @@ -8,12 +8,14 @@ namespace Content.Server.Construction.Completions [DataDefinition] public sealed class SnapToGrid : IGraphAction { - [DataField("southRotation")] public bool SouthRotation { get; private set; } = false; + [DataField("southRotation")] public bool SouthRotation { get; private set; } public void PerformAction(EntityUid uid, EntityUid? userUid, IEntityManager entityManager) { var transform = entityManager.GetComponent(uid); - transform.Coordinates = transform.Coordinates.SnapToGrid(entityManager); + + if (!transform.Anchored) + transform.Coordinates = transform.Coordinates.SnapToGrid(entityManager); if (SouthRotation) { diff --git a/Content.Server/Construction/Completions/SpriteChange.cs b/Content.Server/Construction/Completions/SpriteChange.cs index a7cc7c339b..ea42bd110a 100644 --- a/Content.Server/Construction/Completions/SpriteChange.cs +++ b/Content.Server/Construction/Completions/SpriteChange.cs @@ -14,12 +14,15 @@ namespace Content.Server.Construction.Completions public void PerformAction(EntityUid uid, EntityUid? userUid, IEntityManager entityManager) { - if (SpriteSpecifier == null || SpriteSpecifier == SpriteSpecifier.Invalid) return; + if (SpriteSpecifier == null || SpriteSpecifier == SpriteSpecifier.Invalid) + return; - if (!entityManager.TryGetComponent(uid, out SpriteComponent? sprite)) return; + if (!entityManager.TryGetComponent(uid, out SpriteComponent? sprite)) + return; // That layer doesn't exist, we do nothing. - if (sprite.LayerCount <= Layer) return; + if (sprite.LayerCount <= Layer) + return; sprite.LayerSetSprite(Layer, SpriteSpecifier); } diff --git a/Content.Server/Construction/Components/WelderRefinableComponent.cs b/Content.Server/Construction/Components/WelderRefinableComponent.cs index da7160130f..a2bca0f430 100644 --- a/Content.Server/Construction/Components/WelderRefinableComponent.cs +++ b/Content.Server/Construction/Components/WelderRefinableComponent.cs @@ -11,7 +11,7 @@ namespace Content.Server.Construction.Components public sealed class WelderRefinableComponent : Component { [DataField("refineResult")] - public HashSet? RefineResult = new() { }; + public HashSet? RefineResult = new(); [DataField("refineTime")] public float RefineTime = 2f; diff --git a/Content.Server/Construction/Conditions/AirlockBolted.cs b/Content.Server/Construction/Conditions/AirlockBolted.cs index fad84c2213..4d130da573 100644 --- a/Content.Server/Construction/Conditions/AirlockBolted.cs +++ b/Content.Server/Construction/Conditions/AirlockBolted.cs @@ -30,7 +30,7 @@ namespace Content.Server.Construction.Conditions if (airlock.BoltsDown != Value) { - if (Value == true) + if (Value) args.PushMarkup(Loc.GetString("construction-examine-condition-airlock-bolt", ("entityName", entMan.GetComponent(entity).EntityName)) + "\n"); else args.PushMarkup(Loc.GetString("construction-examine-condition-airlock-unbolt", ("entityName", entMan.GetComponent(entity).EntityName)) + "\n"); diff --git a/Content.Server/Construction/Conditions/ComponentInTile.cs b/Content.Server/Construction/Conditions/ComponentInTile.cs index 5479c33081..d2f6209ca4 100644 --- a/Content.Server/Construction/Conditions/ComponentInTile.cs +++ b/Content.Server/Construction/Conditions/ComponentInTile.cs @@ -47,7 +47,8 @@ namespace Content.Server.Construction.Conditions return false; var indices = transform.Coordinates.ToVector2i(entityManager, IoCManager.Resolve()); - var entities = indices.GetEntitiesInTile(transform.GridUid.Value, LookupFlags.Approximate | LookupFlags.Anchored, EntitySystem.Get()); + var lookup = entityManager.EntitySysManager.GetEntitySystem(); + var entities = indices.GetEntitiesInTile(transform.GridUid.Value, LookupFlags.Approximate | LookupFlags.Anchored, lookup); foreach (var ent in entities) { diff --git a/Content.Server/Construction/Conditions/DoorWelded.cs b/Content.Server/Construction/Conditions/DoorWelded.cs index 648f1ad3de..3e3042e497 100644 --- a/Content.Server/Construction/Conditions/DoorWelded.cs +++ b/Content.Server/Construction/Conditions/DoorWelded.cs @@ -31,7 +31,7 @@ namespace Content.Server.Construction.Conditions var isWelded = door.State == DoorState.Welded; if (isWelded != Welded) { - if (Welded == true) + if (Welded) args.PushMarkup(Loc.GetString("construction-examine-condition-door-weld", ("entityName", entMan.GetComponent(entity).EntityName)) + "\n"); else args.PushMarkup(Loc.GetString("construction-examine-condition-door-unweld", ("entityName", entMan.GetComponent(entity).EntityName)) + "\n"); diff --git a/Content.Server/Construction/Conditions/MachineFrameComplete.cs b/Content.Server/Construction/Conditions/MachineFrameComplete.cs index af205926d6..449418d5e5 100644 --- a/Content.Server/Construction/Conditions/MachineFrameComplete.cs +++ b/Content.Server/Construction/Conditions/MachineFrameComplete.cs @@ -25,14 +25,16 @@ namespace Content.Server.Construction.Conditions if (!entityManager.TryGetComponent(uid, out MachineFrameComponent? machineFrame)) return false; - return EntitySystem.Get().IsComplete(machineFrame); + return entityManager.EntitySysManager.GetEntitySystem().IsComplete(machineFrame); } public bool DoExamine(ExaminedEvent args) { var entity = args.Examined; - if (!IoCManager.Resolve().TryGetComponent(entity, out var machineFrame)) + var entityManager = IoCManager.Resolve(); + + if (!entityManager.TryGetComponent(entity, out var machineFrame)) return false; if (!machineFrame.HasBoard) @@ -41,18 +43,20 @@ namespace Content.Server.Construction.Conditions return true; } - if (EntitySystem.Get().IsComplete(machineFrame)) return false; + if (entityManager.EntitySysManager.GetEntitySystem().IsComplete(machineFrame)) + return false; args.Message.AddMarkup(Loc.GetString("construction-condition-machine-frame-requirement-label") + "\n"); foreach (var (part, required) in machineFrame.Requirements) { var amount = required - machineFrame.Progress[part]; - if(amount == 0) continue; + if(amount == 0) + continue; args.Message.AddMarkup(Loc.GetString("construction-condition-machine-frame-required-element-entry", ("amount", amount), - ("elementName", Loc.GetString(part.ToString()))) + ("elementName", Loc.GetString(part))) + "\n"); } @@ -60,11 +64,12 @@ namespace Content.Server.Construction.Conditions { var amount = required - machineFrame.MaterialProgress[material]; - if(amount == 0) continue; + if(amount == 0) + continue; args.Message.AddMarkup(Loc.GetString("construction-condition-machine-frame-required-element-entry", ("amount", amount), - ("elementName", Loc.GetString(material.ToString()))) + ("elementName", Loc.GetString(material))) + "\n"); } @@ -72,7 +77,8 @@ namespace Content.Server.Construction.Conditions { var amount = info.Amount - machineFrame.ComponentProgress[compName]; - if(amount == 0) continue; + if(amount == 0) + continue; args.Message.AddMarkup(Loc.GetString("construction-condition-machine-frame-required-element-entry", ("amount", info.Amount), @@ -84,7 +90,8 @@ namespace Content.Server.Construction.Conditions { var amount = info.Amount - machineFrame.TagProgress[tagName]; - if(amount == 0) continue; + if(amount == 0) + continue; args.Message.AddMarkup(Loc.GetString("construction-condition-machine-frame-required-element-entry", ("amount", info.Amount), diff --git a/Content.Server/Construction/Conditions/StorageWelded.cs b/Content.Server/Construction/Conditions/StorageWelded.cs index a634db79cd..8bc54de1d2 100644 --- a/Content.Server/Construction/Conditions/StorageWelded.cs +++ b/Content.Server/Construction/Conditions/StorageWelded.cs @@ -31,7 +31,7 @@ namespace Content.Server.Construction.Conditions if (entityStorage.IsWeldedShut != Welded) { - if (Welded == true) + if (Welded) args.PushMarkup(Loc.GetString("construction-examine-condition-door-weld", ("entityName", metaData.EntityName)) + "\n"); else args.PushMarkup(Loc.GetString("construction-examine-condition-door-unweld", ("entityName", metaData.EntityName)) + "\n"); diff --git a/Content.Server/Construction/ConstructionSystem.Computer.cs b/Content.Server/Construction/ConstructionSystem.Computer.cs index f536ef8109..df96c0a6f8 100644 --- a/Content.Server/Construction/ConstructionSystem.Computer.cs +++ b/Content.Server/Construction/ConstructionSystem.Computer.cs @@ -7,6 +7,8 @@ namespace Content.Server.Construction; public sealed partial class ConstructionSystem { + [Dependency] private readonly SharedAppearanceSystem _appearance = default!; + private void InitializeComputer() { SubscribeLocalEvent(OnCompInit); @@ -19,10 +21,9 @@ public sealed partial class ConstructionSystem // Let's ensure the container manager and container are here. _container.EnsureContainer(uid, "board"); - if (TryComp(uid, out var powerReceiver) && - TryComp(uid, out var appearance)) + if (TryComp(uid, out var powerReceiver)) { - appearance.SetData(ComputerVisuals.Powered, powerReceiver.Powered); + _appearance.SetData(uid, ComputerVisuals.Powered, powerReceiver.Powered); } } @@ -33,10 +34,7 @@ public sealed partial class ConstructionSystem private void OnCompPowerChange(EntityUid uid, ComputerComponent component, ref PowerChangedEvent args) { - if (TryComp(uid, out var appearance)) - { - appearance.SetData(ComputerVisuals.Powered, args.Powered); - } + _appearance.SetData(uid, ComputerVisuals.Powered, args.Powered); } /// diff --git a/Content.Server/Construction/ConstructionSystem.Graph.cs b/Content.Server/Construction/ConstructionSystem.Graph.cs index 835dcf058e..152ae66011 100644 --- a/Content.Server/Construction/ConstructionSystem.Graph.cs +++ b/Content.Server/Construction/ConstructionSystem.Graph.cs @@ -11,8 +11,6 @@ namespace Content.Server.Construction { public sealed partial class ConstructionSystem { - [Dependency] private readonly ContainerSystem _containerSystem = default!; - private void InitializeGraphs() { } @@ -329,11 +327,11 @@ namespace Content.Server.Construction // Transfer all construction-owned containers from the old entity to the new one. foreach (var container in construction.Containers) { - if (!_containerSystem.TryGetContainer(uid, container, out var ourContainer, containerManager)) + if (!_container.TryGetContainer(uid, container, out var ourContainer, containerManager)) continue; // NOTE: Only Container is supported by Construction! - var otherContainer = _containerSystem.EnsureContainer(newUid, container, newContainerManager); + var otherContainer = _container.EnsureContainer(newUid, container, newContainerManager); for (var i = ourContainer.ContainedEntities.Count - 1; i >= 0; i--) { diff --git a/Content.Server/Construction/ConstructionSystem.Guided.cs b/Content.Server/Construction/ConstructionSystem.Guided.cs index b366705774..7e28110755 100644 --- a/Content.Server/Construction/ConstructionSystem.Guided.cs +++ b/Content.Server/Construction/ConstructionSystem.Guided.cs @@ -5,11 +5,14 @@ using Content.Shared.Construction.Steps; using Content.Shared.Examine; using Content.Shared.Popups; using Content.Shared.Verbs; +using Robust.Shared.Player; namespace Content.Server.Construction { public sealed partial class ConstructionSystem { + [Dependency] private readonly SharedPopupSystem _popup = default!; + private readonly Dictionary _guideCache = new(); private void InitializeGuided() @@ -49,11 +52,11 @@ namespace Content.Server.Construction if (component.TargetNode == null) { // Maybe check, but on the flip-side a better solution might be to not make it undeconstructible in the first place, no? - component.Owner.PopupMessage(args.User, Loc.GetString("deconstructible-verb-activate-no-target-text")); + _popup.PopupEntity(Loc.GetString("deconstructible-verb-activate-no-target-text"), uid, Filter.Entities(uid)); } else { - component.Owner.PopupMessage(args.User, Loc.GetString("deconstructible-verb-activate-text")); + _popup.PopupEntity(Loc.GetString("deconstructible-verb-activate-text"), args.User, Filter.Entities(args.User)); } }; @@ -94,7 +97,6 @@ namespace Content.Server.Construction if (!preventStepExamine && component.StepIndex < edge.Steps.Count) edge.Steps[component.StepIndex].DoExamine(args); - return; } } diff --git a/Content.Server/Construction/ConstructionSystem.Initial.cs b/Content.Server/Construction/ConstructionSystem.Initial.cs index 543a4264c9..0b2d200c87 100644 --- a/Content.Server/Construction/ConstructionSystem.Initial.cs +++ b/Content.Server/Construction/ConstructionSystem.Initial.cs @@ -1,7 +1,6 @@ using System.IO; using System.Linq; using System.Threading.Tasks; -using Content.Server.Administration.Logs; using Content.Server.Construction.Components; using Content.Server.DoAfter; using Content.Server.Hands.Components; @@ -15,8 +14,8 @@ using Content.Shared.Database; using Content.Shared.Hands.EntitySystems; using Content.Shared.Interaction; using Content.Shared.Inventory; -using Content.Shared.Popups; using Robust.Shared.Containers; +using Robust.Shared.Player; using Robust.Shared.Players; using Robust.Shared.Timing; @@ -80,9 +79,11 @@ namespace Content.Server.Construction var pos = Transform(user).MapPosition; - foreach (var near in _lookupSystem.GetEntitiesInRange(user, 2f, LookupFlags.Approximate)) + foreach (var near in _lookupSystem.GetEntitiesInRange(pos, 2f, LookupFlags.Contained | LookupFlags.Dynamic | LookupFlags.Sundries | LookupFlags.Approximate)) { - if (_interactionSystem.InRangeUnobstructed(pos, near, 2f) && _containerSystem.IsInSameOrParentContainer(user, near)) + if (near == user) + continue; + if (_interactionSystem.InRangeUnobstructed(pos, near, 2f) && _container.IsInSameOrParentContainer(user, near)) yield return near; } } @@ -91,11 +92,11 @@ namespace Content.Server.Construction private async Task Construct(EntityUid user, string materialContainer, ConstructionGraphPrototype graph, ConstructionGraphEdge edge, ConstructionGraphNode targetNode) { // We need a place to hold our construction items! - var container = ContainerHelpers.EnsureContainer(user, materialContainer, out var existed); + var container = _container.EnsureContainer(user, materialContainer, out var existed); if (existed) { - user.PopupMessageCursor(Loc.GetString("construction-system-construct-cannot-start-another-construction")); + _popup.PopupCursor(Loc.GetString("construction-system-construct-cannot-start-another-construction"), Filter.Entities(user)); return null; } @@ -107,15 +108,16 @@ namespace Content.Server.Construction // But I'd rather do this shit than risk having collisions with other containers. Container GetContainer(string name) { - if (containers!.ContainsKey(name)) + if (containers.ContainsKey(name)) return containers[name]; while (true) { var random = _robustRandom.Next(); - var c = ContainerHelpers.EnsureContainer(user!, random.ToString(), out var existed); + var c = _container.EnsureContainer(user, random.ToString(), out var exists); - if (existed) continue; + if (exists) + continue; containers[name] = c; return c; @@ -124,12 +126,12 @@ namespace Content.Server.Construction void FailCleanup() { - foreach (var entity in container!.ContainedEntities.ToArray()) + foreach (var entity in container.ContainedEntities.ToArray()) { container.Remove(entity); } - foreach (var cont in containers!.Values) + foreach (var cont in containers.Values) { foreach (var entity in cont.ContainedEntities.ToArray()) { @@ -143,8 +145,8 @@ namespace Content.Server.Construction void ShutdownContainers() { - container!.Shutdown(); - foreach (var c in containers!.Values.ToArray()) + container.Shutdown(); + foreach (var c in containers.Values.ToArray()) { c.Shutdown(); } @@ -219,7 +221,7 @@ namespace Content.Server.Construction if (failed) { - user.PopupMessageCursor(Loc.GetString("construction-system-construct-no-materials")); + _popup.PopupCursor(Loc.GetString("construction-system-construct-no-materials"), Filter.Entities(user)); FailCleanup(); return null; } @@ -255,7 +257,7 @@ namespace Content.Server.Construction // We preserve the containers... foreach (var (name, cont) in containers) { - var newCont = ContainerHelpers.EnsureContainer(newEntity, name); + var newCont = _container.EnsureContainer(newEntity, name); foreach (var entity in cont.ContainedEntities.ToArray()) { @@ -306,10 +308,11 @@ namespace Content.Server.Construction var targetNode = constructionGraph.Nodes[constructionPrototype.TargetNode]; var pathFind = constructionGraph.Path(startNode.Name, targetNode.Name); - if (args.SenderSession.AttachedEntity is not {Valid: true} user || - !Get().CanInteract(user, null)) return; + if (args.SenderSession.AttachedEntity is not {Valid: true} user || !_actionBlocker.CanInteract(user, null)) + return; - if (!EntityManager.TryGetComponent(user, out HandsComponent? hands)) return; + if (!HasComp(user)) + return; foreach (var condition in constructionPrototype.Conditions) { @@ -318,14 +321,18 @@ namespace Content.Server.Construction } if (pathFind == null) + { throw new InvalidDataException( $"Can't find path from starting node to target node in construction! Recipe: {ev.PrototypeName}"); + } var edge = startNode.GetEdge(pathFind[0].Name); if (edge == null) + { throw new InvalidDataException( $"Can't find edge from starting node to the next node in pathfinding! Recipe: {ev.PrototypeName}"); + } // No support for conditions here! @@ -370,9 +377,9 @@ namespace Content.Server.Construction return; } - if (user.IsInContainer()) + if (_container.IsEntityInContainer(user)) { - user.PopupMessageCursor(Loc.GetString("construction-system-inside-container")); + _popup.PopupCursor(Loc.GetString("construction-system-inside-container"), Filter.Entities(user)); return; } @@ -385,7 +392,7 @@ namespace Content.Server.Construction { if (!set.Add(ev.Ack)) { - user.PopupMessageCursor(Loc.GetString("construction-system-already-building")); + _popup.PopupCursor(Loc.GetString("construction-system-already-building"), Filter.Entities(user)); return; } } diff --git a/Content.Server/Construction/ConstructionSystem.Interactions.cs b/Content.Server/Construction/ConstructionSystem.Interactions.cs index ae3351234a..f55c8b5b77 100644 --- a/Content.Server/Construction/ConstructionSystem.Interactions.cs +++ b/Content.Server/Construction/ConstructionSystem.Interactions.cs @@ -340,7 +340,7 @@ namespace Content.Server.Construction construction.Containers.Add(store); // The container doesn't necessarily need to exist, so we ensure it. - _containerSystem.EnsureContainer(uid, store).Insert(insert); + _container.EnsureContainer(uid, store).Insert(insert); } else { diff --git a/Content.Server/Construction/ConstructionSystem.cs b/Content.Server/Construction/ConstructionSystem.cs index 677ad197b9..2de4145829 100644 --- a/Content.Server/Construction/ConstructionSystem.cs +++ b/Content.Server/Construction/ConstructionSystem.cs @@ -4,7 +4,7 @@ using Content.Server.Stack; using Content.Server.Tools; using Content.Shared.Construction; using JetBrains.Annotations; -using Robust.Shared.Containers; +using Robust.Server.Containers; using Robust.Shared.Prototypes; using Robust.Shared.Random; @@ -20,7 +20,7 @@ namespace Content.Server.Construction [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly IRobustRandom _robustRandom = default!; [Dependency] private readonly DoAfterSystem _doAfterSystem = default!; - [Dependency] private readonly SharedContainerSystem _container = default!; + [Dependency] private readonly ContainerSystem _container = default!; [Dependency] private readonly StackSystem _stackSystem = default!; [Dependency] private readonly ToolSystem _toolSystem = default!; diff --git a/Content.Server/Construction/MachineFrameSystem.cs b/Content.Server/Construction/MachineFrameSystem.cs index 5e3a9ff09e..ef904ce784 100644 --- a/Content.Server/Construction/MachineFrameSystem.cs +++ b/Content.Server/Construction/MachineFrameSystem.cs @@ -4,12 +4,14 @@ using Content.Shared.Construction; using Content.Shared.Examine; using Content.Shared.Interaction; using Content.Shared.Tag; +using Robust.Server.GameObjects; using Robust.Shared.Containers; namespace Content.Server.Construction; public sealed class MachineFrameSystem : EntitySystem { + [Dependency] private readonly AppearanceSystem _appearance = default!; [Dependency] private readonly IComponentFactory _factory = default!; [Dependency] private readonly SharedContainerSystem _container = default!; [Dependency] private readonly TagSystem _tag = default!; @@ -47,7 +49,7 @@ public sealed class MachineFrameSystem : EntitySystem { if (!component.HasBoard && TryComp(args.Used, out var machineBoard)) { - if (args.Used.TryRemoveFromContainer()) + if (_container.TryRemoveFromContainer(args.Used)) { // Valid board! component.BoardContainer.Insert(args.Used); @@ -55,8 +57,7 @@ public sealed class MachineFrameSystem : EntitySystem // Setup requirements and progress... ResetProgressAndRequirements(component, machineBoard); - if (TryComp(uid, out var appearance)) - appearance.SetData(MachineFrameVisuals.State, 2); + _appearance.SetData(uid, MachineFrameVisuals.State, 2); if (TryComp(uid, out ConstructionComponent? construction)) { @@ -73,7 +74,7 @@ public sealed class MachineFrameSystem : EntitySystem return; if (component.Progress[machinePart.PartType] != component.Requirements[machinePart.PartType] - && args.Used.TryRemoveFromContainer() && component.PartContainer.Insert(args.Used)) + && _container.TryRemoveFromContainer(args.Used) && component.PartContainer.Insert(args.Used)) { component.Progress[machinePart.PartType]++; args.Handled = true; @@ -127,7 +128,8 @@ public sealed class MachineFrameSystem : EntitySystem if (!HasComp(args.Used, registration.Type)) continue; - if (!args.Used.TryRemoveFromContainer() || !component.PartContainer.Insert(args.Used)) continue; + if (!_container.TryRemoveFromContainer(args.Used) || !component.PartContainer.Insert(args.Used)) + continue; component.ComponentProgress[compName]++; args.Handled = true; return; @@ -141,7 +143,8 @@ public sealed class MachineFrameSystem : EntitySystem if (!_tag.HasTag(args.Used, tagName)) continue; - if (!args.Used.TryRemoveFromContainer() || !component.PartContainer.Insert(args.Used)) continue; + if (!_container.TryRemoveFromContainer(args.Used) || !component.PartContainer.Insert(args.Used)) + continue; component.TagProgress[tagName]++; args.Handled = true; return; @@ -216,11 +219,9 @@ public sealed class MachineFrameSystem : EntitySystem public void RegenerateProgress(MachineFrameComponent component) { - AppearanceComponent? appearance; - if (!component.HasBoard) { - if (TryComp(component.Owner, out appearance)) appearance.SetData(MachineFrameVisuals.State, 1); + _appearance.SetData(component.Owner, MachineFrameVisuals.State, 1); component.TagRequirements.Clear(); component.MaterialRequirements.Clear(); @@ -239,7 +240,7 @@ public sealed class MachineFrameSystem : EntitySystem if (!TryComp(board, out var machineBoard)) return; - if (TryComp(component.Owner, out appearance)) appearance.SetData(MachineFrameVisuals.State, 2); + _appearance.SetData(component.Owner, MachineFrameVisuals.State, 2); ResetProgressAndRequirements(component, machineBoard); diff --git a/Content.Server/Construction/MachinePartSystem.cs b/Content.Server/Construction/MachinePartSystem.cs index acd6695269..b282a9a2e8 100644 --- a/Content.Server/Construction/MachinePartSystem.cs +++ b/Content.Server/Construction/MachinePartSystem.cs @@ -24,7 +24,7 @@ namespace Content.Server.Construction { args.PushMarkup(Loc.GetString("machine-board-component-required-element-entry-text", ("amount", amount), - ("requiredElement", Loc.GetString(part.ToString())))); + ("requiredElement", Loc.GetString(part)))); } foreach (var (material, amount) in component.MaterialRequirements) diff --git a/Content.Server/Construction/RefiningSystem.cs b/Content.Server/Construction/RefiningSystem.cs index 2d92c1bd80..c259837255 100644 --- a/Content.Server/Construction/RefiningSystem.cs +++ b/Content.Server/Construction/RefiningSystem.cs @@ -19,7 +19,7 @@ namespace Content.Server.Construction private async void OnInteractUsing(EntityUid uid, WelderRefinableComponent component, InteractUsingEvent args) { // check if object is welder - if (!TryComp(args.Used, out ToolComponent? tool)) + if (!HasComp(args.Used)) return; // check if someone is already welding object diff --git a/Content.Server/Damage/Commands/HurtCommand.cs b/Content.Server/Damage/Commands/HurtCommand.cs index ab5f4f4c8a..8e00ad14b2 100644 --- a/Content.Server/Damage/Commands/HurtCommand.cs +++ b/Content.Server/Damage/Commands/HurtCommand.cs @@ -109,11 +109,11 @@ namespace Content.Server.Damage.Commands EntityUid target; var entMan = IoCManager.Resolve(); - if (args.Length == 5) + if (args.Length == 4) { - if (!EntityUid.TryParse(args[4], out target) || !entMan.EntityExists(target)) + if (!EntityUid.TryParse(args[3], out target) || !entMan.EntityExists(target)) { - shell.WriteLine(Loc.GetString("damage-command-error-euid", ("arg", args[4]))); + shell.WriteLine(Loc.GetString("damage-command-error-euid", ("arg", args[3]))); return; } } diff --git a/Content.Server/Disposal/Unit/EntitySystems/DisposableSystem.cs b/Content.Server/Disposal/Unit/EntitySystems/DisposableSystem.cs index 273e98c290..b562deff01 100644 --- a/Content.Server/Disposal/Unit/EntitySystems/DisposableSystem.cs +++ b/Content.Server/Disposal/Unit/EntitySystems/DisposableSystem.cs @@ -105,7 +105,6 @@ namespace Content.Server.Disposal.Unit.EntitySystems } // Insert into next tube - holderTransform.Coordinates = new EntityCoordinates(toUid, Vector2.Zero); if (!to.Contents.Insert(holder.Owner)) { ExitDisposals(holderUid, holder, holderTransform); @@ -117,7 +116,6 @@ namespace Content.Server.Disposal.Unit.EntitySystems holder.PreviousTube = holder.CurrentTube; holder.PreviousDirection = holder.CurrentDirection; } - holderTransform.Coordinates = toTransform.Coordinates; holder.CurrentTube = to; holder.CurrentDirection = to.NextDirection(holder); holder.StartingTime = 0.1f; @@ -168,7 +166,8 @@ namespace Content.Server.Disposal.Unit.EntitySystems var destination = holder.CurrentDirection.ToVec(); var newPosition = destination * progress; - EntityManager.GetComponent(holder.Owner).Coordinates = origin.Offset(newPosition); + // This is some supreme shit code. + EntityManager.GetComponent(holder.Owner).Coordinates = origin.Offset(newPosition).WithEntityId(currentTube.Owner); ; continue; } diff --git a/Content.Server/GameTicking/GameTicker.Spawning.cs b/Content.Server/GameTicking/GameTicker.Spawning.cs index 90b5410572..74bcd05095 100644 --- a/Content.Server/GameTicking/GameTicker.Spawning.cs +++ b/Content.Server/GameTicking/GameTicker.Spawning.cs @@ -67,9 +67,17 @@ namespace Content.Server.GameTicking // Calculate extended access for stations. var stationJobCounts = _stationSystem.Stations.ToDictionary(e => e, _ => 0); - foreach (var (_, (_, station)) in assignedJobs) + foreach (var (netUser, (job, station)) in assignedJobs) { - stationJobCounts[station] += 1; + if (job == null) + { + var playerSession = _playerManager.GetSessionByUserId(netUser); + _chatManager.DispatchServerMessage(playerSession, Loc.GetString("job-not-available-wait-in-lobby")); + } + else + { + stationJobCounts[station] += 1; + } } _stationJobs.CalcExtendedAccess(stationJobCounts); @@ -77,6 +85,9 @@ namespace Content.Server.GameTicking // Spawn everybody in! foreach (var (player, (job, station)) in assignedJobs) { + if (job == null) + continue; + SpawnPlayer(_playerManager.GetSessionByUserId(player), profiles[player], station, job, false); } diff --git a/Content.Server/GameTicking/Rules/TraitorRuleSystem.cs b/Content.Server/GameTicking/Rules/TraitorRuleSystem.cs index 24f413dceb..dcb3b5dcad 100644 --- a/Content.Server/GameTicking/Rules/TraitorRuleSystem.cs +++ b/Content.Server/GameTicking/Rules/TraitorRuleSystem.cs @@ -71,13 +71,6 @@ public sealed class TraitorRuleSystem : GameRuleSystem if (!RuleAdded) return; - // If the current preset doesn't explicitly contain the traitor game rule, just carry on and remove self. - if (_gameTicker.Preset?.Rules.Contains(Prototype) ?? false) - { - _gameTicker.EndGameRule(_prototypeManager.Index(Prototype)); - return; - } - var minPlayers = _cfg.GetCVar(CCVars.TraitorMinPlayers); if (!ev.Forced && ev.Players.Length < minPlayers) { diff --git a/Content.Server/GameTicking/Rules/ZombieRuleSystem.cs b/Content.Server/GameTicking/Rules/ZombieRuleSystem.cs index 0ae42b23a8..e587810a12 100644 --- a/Content.Server/GameTicking/Rules/ZombieRuleSystem.cs +++ b/Content.Server/GameTicking/Rules/ZombieRuleSystem.cs @@ -2,7 +2,7 @@ using System.Linq; using Content.Server.Actions; using Content.Server.Chat.Managers; using Content.Server.Disease; -using Content.Server.GameTicking.Rules.Configurations; +using Content.Server.Disease.Components; using Content.Server.Humanoid; using Content.Server.Mind.Components; using Content.Server.MobState; @@ -14,7 +14,6 @@ using Content.Server.Traitor; using Content.Server.Zombies; using Content.Shared.Actions.ActionTypes; using Content.Shared.CCVar; -using Content.Shared.FixedPoint; using Content.Shared.MobState; using Content.Shared.MobState.Components; using Content.Shared.Preferences; @@ -236,7 +235,7 @@ public sealed class ZombieRuleSystem : GameRuleSystem var prefList = new List(); foreach (var player in allPlayers) { - if (player.AttachedEntity != null) + if (player.AttachedEntity != null && HasComp(player.AttachedEntity)) { playerList.Add(player); diff --git a/Content.Server/Humanoid/Systems/HumanoidSystem.cs b/Content.Server/Humanoid/Systems/HumanoidSystem.cs index 0cd90643f1..0e2f6f1bd4 100644 --- a/Content.Server/Humanoid/Systems/HumanoidSystem.cs +++ b/Content.Server/Humanoid/Systems/HumanoidSystem.cs @@ -509,10 +509,14 @@ public sealed partial class HumanoidSystem : SharedHumanoidSystem } if (age < speciesPrototype.YoungAge) + { return Loc.GetString("identity-age-young"); + } if (age < speciesPrototype.OldAge) - Loc.GetString("identity-age-middle-aged"); + { + return Loc.GetString("identity-age-middle-aged"); + } return Loc.GetString("identity-age-old"); } diff --git a/Content.Server/Kitchen/Components/MicrowaveComponent.cs b/Content.Server/Kitchen/Components/MicrowaveComponent.cs index 1a613aad15..726da379bf 100644 --- a/Content.Server/Kitchen/Components/MicrowaveComponent.cs +++ b/Content.Server/Kitchen/Components/MicrowaveComponent.cs @@ -1,3 +1,4 @@ +using Content.Shared.Construction.Prototypes; using Robust.Shared.Audio; using Robust.Shared.Containers; using Robust.Shared.Prototypes; @@ -8,8 +9,13 @@ namespace Content.Server.Kitchen.Components [RegisterComponent] public sealed class MicrowaveComponent : Component { - [DataField("cookTimeMultiplier")] - public int CookTimeMultiplier = 1; //For upgrades and stuff I guess? don't ask me. + [DataField("cookTimeMultiplier"), ViewVariables(VVAccess.ReadWrite)] + public float CookTimeMultiplier = 1; + [DataField("machinePartCookTimeMultiplier", customTypeSerializer: typeof(PrototypeIdSerializer))] + public string MachinePartCookTimeMultiplier = "Laser"; + [DataField("cookTimeScalingConstant")] + public float CookTimeScalingConstant = 0.5f; + [DataField("failureResult", customTypeSerializer: typeof(PrototypeIdSerializer))] public string BadRecipeEntityId = "FoodBadRecipe"; diff --git a/Content.Server/Kitchen/EntitySystems/MicrowaveSystem.cs b/Content.Server/Kitchen/EntitySystems/MicrowaveSystem.cs index 05dda98cd3..6355b378d7 100644 --- a/Content.Server/Kitchen/EntitySystems/MicrowaveSystem.cs +++ b/Content.Server/Kitchen/EntitySystems/MicrowaveSystem.cs @@ -53,6 +53,7 @@ namespace Content.Server.Kitchen.EntitySystems SubscribeLocalEvent(OnBreak); SubscribeLocalEvent(OnPowerChanged); SubscribeLocalEvent(OnSuicide); + SubscribeLocalEvent(OnRefreshParts); SubscribeLocalEvent((u,c,_) => Wzhzhzh(u,c)); SubscribeLocalEvent(OnEjectMessage); @@ -269,6 +270,12 @@ namespace Content.Server.Kitchen.EntitySystems UpdateUserInterfaceState(uid, component); } + private void OnRefreshParts(EntityUid uid, MicrowaveComponent component, RefreshPartsEvent args) + { + var cookRating = args.PartRatings[component.MachinePartCookTimeMultiplier]; + component.CookTimeMultiplier = MathF.Pow(component.CookTimeScalingConstant, cookRating - 1); + } + public void UpdateUserInterfaceState(EntityUid uid, MicrowaveComponent component) { var ui = _userInterface.GetUiOrNull(uid, MicrowaveUiKey.Key); @@ -371,7 +378,7 @@ namespace Content.Server.Kitchen.EntitySystems _audio.PlayPvs(component.StartCookingSound, uid); var activeComp = AddComp(uid); //microwave is now cooking activeComp.CookTimeRemaining = component.CurrentCookTimerTime * component.CookTimeMultiplier; - activeComp.TotalTime = component.CurrentCookTimerTime * component.CookTimeMultiplier; + activeComp.TotalTime = component.CurrentCookTimerTime; //this doesn't scale so that we can have the "actual" time activeComp.PortionedRecipe = portionedRecipe; UpdateUserInterfaceState(uid, component); } diff --git a/Content.Server/Lathe/Components/LatheProducingComponent.cs b/Content.Server/Lathe/Components/LatheProducingComponent.cs index bd646e49da..e991dc4248 100644 --- a/Content.Server/Lathe/Components/LatheProducingComponent.cs +++ b/Content.Server/Lathe/Components/LatheProducingComponent.cs @@ -7,9 +7,15 @@ namespace Content.Server.Lathe.Components; public sealed class LatheProducingComponent : Component { /// - /// How much production time has passed, in seconds. + /// The time at which production began /// [ViewVariables(VVAccess.ReadWrite)] - public float AccumulatedTime; + public TimeSpan StartTime; + + /// + /// How long it takes to produce the recipe. + /// + [ViewVariables(VVAccess.ReadWrite)] + public TimeSpan ProductionLength; } diff --git a/Content.Server/Lathe/LatheSystem.cs b/Content.Server/Lathe/LatheSystem.cs index bab1165098..3eff78ca14 100644 --- a/Content.Server/Lathe/LatheSystem.cs +++ b/Content.Server/Lathe/LatheSystem.cs @@ -10,17 +10,20 @@ using Robust.Server.GameObjects; using Robust.Shared.Prototypes; using JetBrains.Annotations; using System.Linq; +using Content.Server.Construction; using Content.Server.Materials; using Content.Server.Power.Components; using Content.Server.Power.EntitySystems; using Content.Server.UserInterface; using Robust.Server.Player; +using Robust.Shared.Timing; namespace Content.Server.Lathe { [UsedImplicitly] public sealed class LatheSystem : SharedLatheSystem { + [Dependency] private readonly IGameTiming _timing = default!; [Dependency] private readonly IPrototypeManager _proto = default!; [Dependency] private readonly SharedAppearanceSystem _appearance = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; @@ -35,6 +38,7 @@ namespace Content.Server.Lathe SubscribeLocalEvent(OnGetWhitelist); SubscribeLocalEvent(OnMapInit); SubscribeLocalEvent(OnPowerChanged); + SubscribeLocalEvent(OnPartsRefresh); SubscribeLocalEvent(OnLatheQueueRecipeMessage); SubscribeLocalEvent(OnLatheSyncRequestMessage); @@ -65,9 +69,7 @@ namespace Content.Server.Lathe if (lathe.CurrentRecipe == null) continue; - comp.AccumulatedTime += frameTime; - - if (comp.AccumulatedTime >= (float) lathe.CurrentRecipe.CompleteTime.TotalSeconds) + if ( _timing.CurTime - comp.StartTime >= comp.ProductionLength) FinishProducing(comp.Owner, lathe); } } @@ -132,7 +134,7 @@ namespace Content.Server.Lathe foreach (var (mat, amount) in recipe.RequiredMaterials) { - _materialStorage.TryChangeMaterialAmount(uid, mat, -amount); + _materialStorage.TryChangeMaterialAmount(uid, mat, (int) (-amount * component.MaterialUseMultiplier)); } component.Queue.Add(recipe); @@ -149,7 +151,9 @@ namespace Content.Server.Lathe var recipe = component.Queue.First(); component.Queue.RemoveAt(0); - EnsureComp(uid); + var lathe = EnsureComp(uid); + lathe.StartTime = _timing.CurTime; + lathe.ProductionLength = recipe.CompleteTime * component.TimeMultiplier; component.CurrentRecipe = recipe; _audio.PlayPvs(component.ProducingSound, component.Owner); @@ -166,7 +170,7 @@ namespace Content.Server.Lathe if (comp.CurrentRecipe != null) Spawn(comp.CurrentRecipe.Result, Transform(uid).Coordinates); comp.CurrentRecipe = null; - prodComp.AccumulatedTime = 0; + prodComp.StartTime = _timing.CurTime; if (!TryStartProducing(uid, comp)) { @@ -257,6 +261,17 @@ namespace Content.Server.Lathe } } + private void OnPartsRefresh(EntityUid uid, LatheComponent component, RefreshPartsEvent args) + { + var printTimeRating = args.PartRatings[component.MachinePartPrintTime]; + var materialUseRating = args.PartRatings[component.MachinePartMaterialUse]; + + component.TimeMultiplier = MathF.Pow(component.PartRatingPrintTimeMultiplier, printTimeRating - 1); + component.MaterialUseMultiplier = MathF.Pow(component.PartRatingMaterialUseMultiplier, materialUseRating - 1); + Dirty(component); + } + + protected override bool HasRecipe(EntityUid uid, LatheRecipePrototype recipe, LatheComponent component) { return GetAvailableRecipes(component).Contains(recipe.ID); diff --git a/Content.Server/Singularity/Components/EmitterComponent.cs b/Content.Server/Singularity/Components/EmitterComponent.cs index eab75d81fe..a99cf7c32e 100644 --- a/Content.Server/Singularity/Components/EmitterComponent.cs +++ b/Content.Server/Singularity/Components/EmitterComponent.cs @@ -1,5 +1,7 @@ using System.Threading; +using Content.Shared.Construction.Prototypes; using Robust.Shared.Audio; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; namespace Content.Server.Singularity.Components { @@ -18,14 +20,102 @@ namespace Content.Server.Singularity.Components public const float Volume = 0.5f; public const float Distance = 6f; - [ViewVariables] public int FireShotCounter; + /// + /// counts the number of consecutive shots fired. + /// + [ViewVariables] + public int FireShotCounter; - [ViewVariables] [DataField("fireSound")] public SoundSpecifier FireSound = new SoundPathSpecifier("/Audio/Weapons/emitter.ogg"); - [ViewVariables] [DataField("boltType")] public string BoltType = "EmitterBolt"; - [ViewVariables] [DataField("powerUseActive")] public int PowerUseActive = 500; - [ViewVariables] [DataField("fireBurstSize")] public int FireBurstSize = 3; - [ViewVariables] [DataField("fireInterval")] public TimeSpan FireInterval = TimeSpan.FromSeconds(2); - [ViewVariables] [DataField("fireBurstDelayMin")] public TimeSpan FireBurstDelayMin = TimeSpan.FromSeconds(2); - [ViewVariables] [DataField("fireBurstDelayMax")] public TimeSpan FireBurstDelayMax = TimeSpan.FromSeconds(10); + [DataField("fireSound"), ViewVariables] + public SoundSpecifier FireSound = new SoundPathSpecifier("/Audio/Weapons/emitter.ogg"); + + /// + /// The entity that is spawned when the emitter fires. + /// + [DataField("boltType"), ViewVariables] + public string BoltType = "EmitterBolt"; + + /// + /// The current amount of power being used. + /// + [DataField("powerUseActive"), ViewVariables] + public int PowerUseActive = 600; + + /// + /// The base amount of power that is consumed. + /// Used in machine part rating calculations. + /// + [DataField("basePowerUseActive"), ViewVariables(VVAccess.ReadWrite)] + public int BasePowerUseActive = 600; + + /// + /// Multiplier that is applied to the basePowerUseActive + /// to get the actual power use. + /// + [DataField("powerUseMultiplier")] + public float PowerUseMultiplier = 0.75f; + + /// + /// The machine part used to reduce the power use of the machine. + /// + [DataField("machinePartPowerUse", customTypeSerializer: typeof(PrototypeIdSerializer))] + public string MachinePartPowerUse = "Capacitor"; + + /// + /// The amount of shots that are fired in a single "burst" + /// + [DataField("fireBurstSize"), ViewVariables] + public int FireBurstSize = 3; + + /// + /// The time between each shot during a burst. + /// + [DataField("fireInterval"), ViewVariables] + public TimeSpan FireInterval = TimeSpan.FromSeconds(2); + + /// + /// The base amount of time between each shot during a burst. + /// + [DataField("baseFireInterval"), ViewVariables(VVAccess.ReadWrite)] + public TimeSpan BaseFireInterval = TimeSpan.FromSeconds(2); + + /// + /// The current minimum delay between bursts. + /// + [DataField("fireBurstDelayMin"), ViewVariables] + public TimeSpan FireBurstDelayMin = TimeSpan.FromSeconds(4); + + /// + /// The current maximum delay between bursts. + /// + [DataField("fireBurstDelayMax"), ViewVariables] + public TimeSpan FireBurstDelayMax = TimeSpan.FromSeconds(10); + + /// + /// The base minimum delay between shot bursts. + /// Used for machine part rating calculations. + /// + [DataField("baseFireBurstDelayMin"), ViewVariables] + public TimeSpan BaseFireBurstDelayMin = TimeSpan.FromSeconds(4); + + /// + /// The base maximum delay between shot bursts. + /// Used for machine part rating calculations. + /// + [DataField("baseFireBurstDelayMax"), ViewVariables] + public TimeSpan BaseFireBurstDelayMax = TimeSpan.FromSeconds(10); + + /// + /// The multiplier for the base delay between shot bursts as well as + /// the fire interval + /// + [DataField("fireRateMultiplier"), ViewVariables(VVAccess.ReadWrite)] + public float FireRateMultiplier = 0.8f; + + /// + /// The machine part that affects burst delay. + /// + [DataField("machinePartFireRate", customTypeSerializer: typeof(PrototypeIdSerializer))] + public string MachinePartFireRate = "Laser"; } } diff --git a/Content.Server/Singularity/EntitySystems/EmitterSystem.cs b/Content.Server/Singularity/EntitySystems/EmitterSystem.cs index 91f68b8346..93b6b78b6b 100644 --- a/Content.Server/Singularity/EntitySystems/EmitterSystem.cs +++ b/Content.Server/Singularity/EntitySystems/EmitterSystem.cs @@ -1,12 +1,12 @@ using System.Threading; using Content.Server.Administration.Logs; +using Content.Server.Construction; using Content.Server.Power.Components; using Content.Server.Power.EntitySystems; using Content.Server.Projectiles; using Content.Server.Projectiles.Components; using Content.Server.Singularity.Components; using Content.Server.Storage.Components; -using Content.Shared.Audio; using Content.Shared.Database; using Content.Shared.Interaction; using Content.Shared.Popups; @@ -27,6 +27,10 @@ namespace Content.Server.Singularity.EntitySystems { [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly IAdminLogManager _adminLogger = default!; + [Dependency] private readonly SharedAppearanceSystem _appearance = default!; + [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly SharedPopupSystem _popup = default!; + [Dependency] private readonly ProjectileSystem _projectile = default!; public override void Initialize() { @@ -34,6 +38,7 @@ namespace Content.Server.Singularity.EntitySystems SubscribeLocalEvent(ReceivedChanged); SubscribeLocalEvent(OnInteractHand); + SubscribeLocalEvent(OnRefreshParts); } private void OnInteractHand(EntityUid uid, EmitterComponent component, InteractHandEvent args) @@ -41,7 +46,8 @@ namespace Content.Server.Singularity.EntitySystems args.Handled = true; if (EntityManager.TryGetComponent(uid, out LockComponent? lockComp) && lockComp.Locked) { - component.Owner.PopupMessage(args.User, Loc.GetString("comp-emitter-access-locked", ("target", component.Owner))); + _popup.PopupEntity(Loc.GetString("comp-emitter-access-locked", + ("target", component.Owner)), uid, Filter.Entities(args.User)); return; } @@ -50,12 +56,14 @@ namespace Content.Server.Singularity.EntitySystems if (!component.IsOn) { SwitchOn(component); - component.Owner.PopupMessage(args.User, Loc.GetString("comp-emitter-turned-on", ("target", component.Owner))); + _popup.PopupEntity(Loc.GetString("comp-emitter-turned-on", + ("target", component.Owner)), uid, Filter.Entities(args.User)); } else { SwitchOff(component); - component.Owner.PopupMessage(args.User, Loc.GetString("comp-emitter-turned-off", ("target", component.Owner))); + _popup.PopupEntity(Loc.GetString("comp-emitter-turned-off", + ("target", component.Owner)), uid, Filter.Entities(args.User)); } _adminLogger.Add(LogType.Emitter, @@ -64,7 +72,8 @@ namespace Content.Server.Singularity.EntitySystems } else { - component.Owner.PopupMessage(args.User, Loc.GetString("comp-emitter-not-anchored", ("target", component.Owner))); + _popup.PopupEntity(Loc.GetString("comp-emitter-not-anchored", + ("target", component.Owner)), uid, Filter.Entities(args.User)); } } @@ -88,10 +97,23 @@ namespace Content.Server.Singularity.EntitySystems } } + private void OnRefreshParts(EntityUid uid, EmitterComponent component, RefreshPartsEvent args) + { + var powerUseRating = args.PartRatings[component.MachinePartPowerUse]; + var fireRateRating = args.PartRatings[component.MachinePartFireRate]; + + component.PowerUseActive = (int) (component.BasePowerUseActive * MathF.Pow(component.PowerUseMultiplier, powerUseRating - 1)); + + component.FireInterval = component.BaseFireInterval * MathF.Pow(component.FireRateMultiplier, fireRateRating - 1); + component.FireBurstDelayMin = component.BaseFireBurstDelayMin * MathF.Pow(component.FireRateMultiplier, fireRateRating - 1); + component.FireBurstDelayMax = component.BaseFireBurstDelayMax * MathF.Pow(component.FireRateMultiplier, fireRateRating - 1); + } + public void SwitchOff(EmitterComponent component) { component.IsOn = false; - if (TryComp(component.Owner, out var powerConsumer)) powerConsumer.DrawRate = 0; + if (TryComp(component.Owner, out var powerConsumer)) + powerConsumer.DrawRate = 0; PowerOff(component); UpdateAppearance(component); } @@ -99,7 +121,8 @@ namespace Content.Server.Singularity.EntitySystems public void SwitchOn(EmitterComponent component) { component.IsOn = true; - if (TryComp(component.Owner, out var powerConsumer)) powerConsumer.DrawRate = component.PowerUseActive; + if (TryComp(component.Owner, out var powerConsumer)) + powerConsumer.DrawRate = component.PowerUseActive; // Do not directly PowerOn(). // OnReceivedPowerChanged will get fired due to DrawRate change which will turn it on. UpdateAppearance(component); @@ -140,7 +163,8 @@ namespace Content.Server.Singularity.EntitySystems private void ShotTimerCallback(EmitterComponent component) { - if (component.Deleted) return; + if (component.Deleted) + return; // Any power-off condition should result in the timer for this method being cancelled // and thus not firing @@ -189,7 +213,7 @@ namespace Content.Server.Singularity.EntitySystems return; } - Get().SetShooter(projectileComponent, component.Owner); + _projectile.SetShooter(projectileComponent, component.Owner); physicsComponent .LinearVelocity = EntityManager.GetComponent(component.Owner).WorldRotation.ToWorldVec() * 20f; @@ -198,17 +222,12 @@ namespace Content.Server.Singularity.EntitySystems // TODO: Move to projectile's code. Timer.Spawn(3000, () => EntityManager.DeleteEntity(projectile)); - SoundSystem.Play(component.FireSound.GetSound(), Filter.Pvs(component.Owner), - component.Owner, AudioHelpers.WithVariation(EmitterComponent.Variation).WithVolume(EmitterComponent.Volume).WithMaxDistance(EmitterComponent.Distance)); + _audio.PlayPvs(component.FireSound, component.Owner, + AudioParams.Default.WithVariation(EmitterComponent.Variation).WithVolume(EmitterComponent.Volume).WithMaxDistance(EmitterComponent.Distance)); } private void UpdateAppearance(EmitterComponent component) { - if (!TryComp(component.Owner, out var appearanceComponent)) - { - return; - } - EmitterVisualState state; if (component.IsPowered) { @@ -222,8 +241,7 @@ namespace Content.Server.Singularity.EntitySystems { state = EmitterVisualState.Off; } - - appearanceComponent.SetData(EmitterVisuals.VisualState, state); + _appearance.SetData(component.Owner, EmitterVisuals.VisualState, state); } } } diff --git a/Content.Server/Station/Systems/StationJobsSystem.Roundstart.cs b/Content.Server/Station/Systems/StationJobsSystem.Roundstart.cs index 4d30330dbe..a618e74c26 100644 --- a/Content.Server/Station/Systems/StationJobsSystem.Roundstart.cs +++ b/Content.Server/Station/Systems/StationJobsSystem.Roundstart.cs @@ -1,7 +1,6 @@ -using System.Linq; +using System.Linq; using Content.Server.Administration.Managers; using Content.Server.Players.PlayTimeTracking; -using Content.Server.Roles; using Content.Server.Station.Components; using Content.Shared.Preferences; using Content.Shared.Roles; @@ -52,20 +51,20 @@ public sealed partial class StationJobsSystem /// as there may end up being more round-start slots than available slots, which can cause weird behavior. /// A warning to all who enter ye cursed lands: This function is long and mildly incomprehensible. Best used without touching. /// - public Dictionary AssignJobs(Dictionary profiles, IReadOnlyList stations, bool useRoundStartJobs = true) + public Dictionary AssignJobs(Dictionary profiles, IReadOnlyList stations, bool useRoundStartJobs = true) { DebugTools.Assert(stations.Count > 0); InitializeRoundStart(); if (profiles.Count == 0) - return new Dictionary(); + return new Dictionary(); // We need to modify this collection later, so make a copy of it. profiles = profiles.ShallowClone(); // Player <-> (job, station) - var assigned = new Dictionary(profiles.Count); + var assigned = new Dictionary(profiles.Count); // The jobs left on the stations. This collection is modified as jobs are assigned to track what's available. var stationJobs = new Dictionary>(); @@ -273,7 +272,7 @@ public sealed partial class StationJobsSystem /// All players that might need an overflow assigned. /// Player character profiles. /// The stations to consider for spawn location. - public void AssignOverflowJobs(ref Dictionary assignedJobs, + public void AssignOverflowJobs(ref Dictionary assignedJobs, IEnumerable allPlayersToAssign, IReadOnlyDictionary profiles, IReadOnlyList stations) { var givenStations = stations.ToList(); @@ -289,8 +288,11 @@ public sealed partial class StationJobsSystem var profile = profiles[player]; if (profile.PreferenceUnavailable != PreferenceUnavailableMode.SpawnAsOverflow) + { + assignedJobs.Add(player, (null, EntityUid.Invalid)); continue; - + } + _random.Shuffle(givenStations); foreach (var station in givenStations) diff --git a/Content.Server/Weapons/Melee/MeleeWeaponSystem.cs b/Content.Server/Weapons/Melee/MeleeWeaponSystem.cs index b9ba62da4b..526d8513f2 100644 --- a/Content.Server/Weapons/Melee/MeleeWeaponSystem.cs +++ b/Content.Server/Weapons/Melee/MeleeWeaponSystem.cs @@ -155,13 +155,13 @@ public sealed class MeleeWeaponSystem : SharedMeleeWeaponSystem // If the user is using a long-range weapon, this probably shouldn't be happening? But I'll interpret melee as a // somewhat messy scuffle. See also, heavy attacks. - _interaction.DoContactInteraction(user, ev.Target); + _interaction.DoContactInteraction(user, ev.Target); // For stuff that cares about it being attacked. RaiseLocalEvent(ev.Target.Value, new AttackedEvent(component.Owner, user, targetXform.Coordinates)); var modifiedDamage = DamageSpecifier.ApplyModifierSets(damage + hitEvent.BonusDamage + itemDamage.BonusDamage, hitEvent.ModifiersList); - var damageResult = _damageable.TryChangeDamage(ev.Target, modifiedDamage); + var damageResult = _damageable.TryChangeDamage(ev.Target, modifiedDamage, origin:user); if (damageResult != null && damageResult.Total > FixedPoint2.Zero) { @@ -277,7 +277,7 @@ public sealed class MeleeWeaponSystem : SharedMeleeWeaponSystem { RaiseLocalEvent(entity, new AttackedEvent(component.Owner, user, ev.Coordinates)); - var damageResult = _damageable.TryChangeDamage(entity, modifiedDamage); + var damageResult = _damageable.TryChangeDamage(entity, modifiedDamage, origin:user); if (damageResult != null && damageResult.Total > FixedPoint2.Zero) { @@ -555,7 +555,7 @@ public sealed class MeleeWeaponSystem : SharedMeleeWeaponSystem private void OnChemicalInjectorHit(EntityUid owner, MeleeChemicalInjectorComponent comp, MeleeHitEvent args) { - if (!_solutions.TryGetInjectableSolution(owner, out var solutionContainer)) + if (!_solutions.TryGetSolution(owner, comp.Solution, out var solutionContainer)) return; var hitBloodstreams = new List(); diff --git a/Content.Shared/Construction/Conditions/EmptyOrWindowValidInTile.cs b/Content.Shared/Construction/Conditions/EmptyOrWindowValidInTile.cs index f5a984102c..0f0852204e 100644 --- a/Content.Shared/Construction/Conditions/EmptyOrWindowValidInTile.cs +++ b/Content.Shared/Construction/Conditions/EmptyOrWindowValidInTile.cs @@ -27,9 +27,9 @@ namespace Content.Shared.Construction.Conditions return result; } - public ConstructionGuideEntry? GenerateGuideEntry() + public ConstructionGuideEntry GenerateGuideEntry() { - return new ConstructionGuideEntry() + return new ConstructionGuideEntry { Localization = "construction-guide-condition-empty-or-window-valid-in-tile" }; diff --git a/Content.Shared/Construction/Conditions/NoWindowsInTile.cs b/Content.Shared/Construction/Conditions/NoWindowsInTile.cs index 4ceb3feed7..8ee95809a0 100644 --- a/Content.Shared/Construction/Conditions/NoWindowsInTile.cs +++ b/Content.Shared/Construction/Conditions/NoWindowsInTile.cs @@ -22,9 +22,9 @@ namespace Content.Shared.Construction.Conditions return true; } - public ConstructionGuideEntry? GenerateGuideEntry() + public ConstructionGuideEntry GenerateGuideEntry() { - return new ConstructionGuideEntry() + return new ConstructionGuideEntry { Localization = "construction-step-condition-no-windows-in-tile" }; diff --git a/Content.Shared/Construction/Conditions/TileNotBlocked.cs b/Content.Shared/Construction/Conditions/TileNotBlocked.cs index 02fecafd21..cf6d3435cd 100644 --- a/Content.Shared/Construction/Conditions/TileNotBlocked.cs +++ b/Content.Shared/Construction/Conditions/TileNotBlocked.cs @@ -21,9 +21,9 @@ namespace Content.Shared.Construction.Conditions return !tileRef.Value.IsBlockedTurf(_filterMobs); } - public ConstructionGuideEntry? GenerateGuideEntry() + public ConstructionGuideEntry GenerateGuideEntry() { - return new ConstructionGuideEntry() + return new ConstructionGuideEntry { Localization = "construction-step-condition-tile-not-blocked", }; diff --git a/Content.Shared/Construction/Conditions/TileType.cs b/Content.Shared/Construction/Conditions/TileType.cs index 8a4421168e..60385b0ff3 100644 --- a/Content.Shared/Construction/Conditions/TileType.cs +++ b/Content.Shared/Construction/Conditions/TileType.cs @@ -13,15 +13,13 @@ namespace Content.Shared.Construction.Conditions public List TargetTiles { get; } = new(); [DataField("guideText")] - public string? GuideText = null; + public string? GuideText; [DataField("guideIcon")] - public SpriteSpecifier? GuideIcon = null; + public SpriteSpecifier? GuideIcon; public bool Condition(EntityUid user, EntityCoordinates location, Direction direction) { - if (TargetTiles == null) return true; - var tileFound = location.GetTileRef(); if (tileFound == null) @@ -30,9 +28,8 @@ namespace Content.Shared.Construction.Conditions var tile = tileFound.Value.Tile.GetContentTileDefinition(); foreach (var targetTile in TargetTiles) { - if (tile.ID == targetTile) { + if (tile.ID == targetTile) return true; - } } return false; } diff --git a/Content.Shared/Construction/Conditions/WallmountCondition.cs b/Content.Shared/Construction/Conditions/WallmountCondition.cs index 8639a52a35..f75b946547 100644 --- a/Content.Shared/Construction/Conditions/WallmountCondition.cs +++ b/Content.Shared/Construction/Conditions/WallmountCondition.cs @@ -51,7 +51,7 @@ namespace Content.Shared.Construction.Conditions // check that we didn't try to build wallmount that facing another adjacent wall var rAdjWall = new CollisionRay(objWorldPosition, directionWithOffset.Normalized, (int) CollisionGroup.Impassable); var adjWallRaycastResults = physics.IntersectRayWithPredicate(entManager.GetComponent(user).MapID, rAdjWall, maxLength: 0.5f, - predicate: (e) => e == targetWall.Value.HitEntity || !tagSystem.HasTag(e, "Wall")); + predicate: e => e == targetWall.Value.HitEntity || !tagSystem.HasTag(e, "Wall")); return !adjWallRaycastResults.Any(); } diff --git a/Content.Shared/Construction/EntitySystems/SharedAnchorableSystem.cs b/Content.Shared/Construction/EntitySystems/SharedAnchorableSystem.cs index 398a8c51d5..7c8a8620f9 100644 --- a/Content.Shared/Construction/EntitySystems/SharedAnchorableSystem.cs +++ b/Content.Shared/Construction/EntitySystems/SharedAnchorableSystem.cs @@ -36,6 +36,5 @@ public abstract class SharedAnchorableSystem : EntitySystem ToolComponent? usingTool = null) { // Thanks tool system. - return; } } diff --git a/Content.Shared/Construction/Steps/ArbitraryInsertConstructionGraphStep.cs b/Content.Shared/Construction/Steps/ArbitraryInsertConstructionGraphStep.cs index ff057b2ff0..a6a7719fbe 100644 --- a/Content.Shared/Construction/Steps/ArbitraryInsertConstructionGraphStep.cs +++ b/Content.Shared/Construction/Steps/ArbitraryInsertConstructionGraphStep.cs @@ -7,7 +7,7 @@ namespace Content.Shared.Construction.Steps { [DataField("name")] public string Name { get; private set; } = string.Empty; - [DataField("icon")] public SpriteSpecifier? Icon { get; private set; } = null; + [DataField("icon")] public SpriteSpecifier? Icon { get; private set; } public override void DoExamine(ExaminedEvent examinedEvent) { @@ -19,7 +19,7 @@ namespace Content.Shared.Construction.Steps public override ConstructionGuideEntry GenerateGuideEntry() { - return new ConstructionGuideEntry() + return new ConstructionGuideEntry { Localization = "construction-presenter-arbitrary-step", Arguments = new (string, object)[]{("name", Name)}, diff --git a/Content.Shared/Construction/Steps/ConstructionGraphStepTypeSerializer.cs b/Content.Shared/Construction/Steps/ConstructionGraphStepTypeSerializer.cs index 7cd2b57947..b113afe384 100644 --- a/Content.Shared/Construction/Steps/ConstructionGraphStepTypeSerializer.cs +++ b/Content.Shared/Construction/Steps/ConstructionGraphStepTypeSerializer.cs @@ -57,7 +57,8 @@ namespace Content.Shared.Construction.Steps { var type = GetType(node); - if (type == null) return new ErrorNode(node, "No construction graph step type found.", true); + if (type == null) + return new ErrorNode(node, "No construction graph step type found."); return serializationManager.ValidateNode(type, node, context); } diff --git a/Content.Shared/Construction/Steps/MultipleTagsConstructionGraphStep.cs b/Content.Shared/Construction/Steps/MultipleTagsConstructionGraphStep.cs index da55054a8e..59b371000d 100644 --- a/Content.Shared/Construction/Steps/MultipleTagsConstructionGraphStep.cs +++ b/Content.Shared/Construction/Steps/MultipleTagsConstructionGraphStep.cs @@ -25,7 +25,7 @@ namespace Content.Shared.Construction.Steps if (!entityManager.TryGetComponent(uid, out TagComponent? tags)) return false; - var tagSystem = EntitySystem.Get(); + var tagSystem = entityManager.EntitySysManager.GetEntitySystem(); if (_allTags != null && !tagSystem.HasAllTags(tags, _allTags)) return false; // We don't have all the tags needed. diff --git a/Content.Shared/Damage/Systems/DamageableSystem.cs b/Content.Shared/Damage/Systems/DamageableSystem.cs index c12246e6a6..bd6b0c1da7 100644 --- a/Content.Shared/Damage/Systems/DamageableSystem.cs +++ b/Content.Shared/Damage/Systems/DamageableSystem.cs @@ -189,7 +189,7 @@ namespace Content.Shared.Damage if (!delta.Empty) { - DamageChanged(damageable, delta, interruptsDoAfters); + DamageChanged(damageable, delta, interruptsDoAfters, origin); } return delta; diff --git a/Content.Shared/Humanoid/SharedHumanoidSystem.cs b/Content.Shared/Humanoid/SharedHumanoidSystem.cs index 423e3e117e..0bdcf19761 100644 --- a/Content.Shared/Humanoid/SharedHumanoidSystem.cs +++ b/Content.Shared/Humanoid/SharedHumanoidSystem.cs @@ -30,19 +30,8 @@ public abstract class SharedHumanoidSystem : EntitySystem { var data = new HumanoidVisualizerData(species, customBaseLayer, skinColor, sex, visLayers, markings); - // Locally raise an event for this, because there might be some systems interested - // in this. - RaiseLocalEvent(uid, new HumanoidAppearanceUpdateEvent(data), true); + // This should raise a HumanoidAppearanceUpdateEvent, but that requires this component to be made networked and + // I cbf doing that atm. _appearance.SetData(uid, HumanoidVisualizerKey.Key, data); } } - -public sealed class HumanoidAppearanceUpdateEvent : EntityEventArgs -{ - public HumanoidVisualizerData Data { get; } - - public HumanoidAppearanceUpdateEvent(HumanoidVisualizerData data) - { - Data = data; - } -} diff --git a/Content.Shared/Interaction/SharedInteractionSystem.cs b/Content.Shared/Interaction/SharedInteractionSystem.cs index 6be9761a9e..45b8e9c204 100644 --- a/Content.Shared/Interaction/SharedInteractionSystem.cs +++ b/Content.Shared/Interaction/SharedInteractionSystem.cs @@ -1013,6 +1013,10 @@ namespace Content.Shared.Interaction if (uidB == null || args?.Handled == false) return; + // Entities may no longer exist (banana was eaten, or human was exploded)? + if (!Exists(uidA) || !Exists(uidB)) + return; + RaiseLocalEvent(uidA, new ContactInteractionEvent(uidB.Value)); RaiseLocalEvent(uidB.Value, new ContactInteractionEvent(uidA)); } diff --git a/Content.Shared/Lathe/LatheComponent.cs b/Content.Shared/Lathe/LatheComponent.cs index 0b070dc0b8..0c3fb5c69f 100644 --- a/Content.Shared/Lathe/LatheComponent.cs +++ b/Content.Shared/Lathe/LatheComponent.cs @@ -1,6 +1,8 @@ +using Content.Shared.Construction.Prototypes; using Content.Shared.Research.Prototypes; using Robust.Shared.Audio; using Robust.Shared.GameStates; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List; namespace Content.Shared.Lathe @@ -56,7 +58,43 @@ namespace Content.Shared.Lathe [ViewVariables] public LatheRecipePrototype? CurrentRecipe; + #region MachineUpgrading + /// + /// A modifier that changes how long it takes to print a recipe + /// + [ViewVariables(VVAccess.ReadWrite)] + public float TimeMultiplier = 1; + /// + /// The machine part that reduces how long it takes to print a recipe. + /// + [DataField("machinePartPrintSpeed", customTypeSerializer: typeof(PrototypeIdSerializer))] + public string MachinePartPrintTime = "Manipulator"; + + /// + /// The value that is used to calculate the modified + /// + [DataField("partRatingPrintTimeMultiplier")] + public float PartRatingPrintTimeMultiplier = 0.5f; + + /// + /// A modifier that changes how much of a material is needed to print a recipe + /// + [ViewVariables(VVAccess.ReadWrite)] + public float MaterialUseMultiplier = 1; + + /// + /// The machine part that reduces how much material it takes to print a recipe. + /// + [DataField("machinePartMaterialUse", customTypeSerializer: typeof(PrototypeIdSerializer))] + public string MachinePartMaterialUse = "MatterBin"; + + /// + /// The value that is used to calculate the modifier + /// + [DataField("partRatingMaterialUseMultiplier")] + public float PartRatingMaterialUseMultiplier = 0.75f; + #endregion } public sealed class LatheGetRecipesEvent : EntityEventArgs diff --git a/Content.Shared/Lathe/SharedLatheSystem.cs b/Content.Shared/Lathe/SharedLatheSystem.cs index 3814299218..f009570fea 100644 --- a/Content.Shared/Lathe/SharedLatheSystem.cs +++ b/Content.Shared/Lathe/SharedLatheSystem.cs @@ -1,7 +1,9 @@ using Content.Shared.Materials; using Content.Shared.Research.Prototypes; using JetBrains.Annotations; +using Robust.Shared.GameStates; using Robust.Shared.Prototypes; +using Robust.Shared.Serialization; namespace Content.Shared.Lathe; @@ -13,6 +15,26 @@ public abstract class SharedLatheSystem : EntitySystem [Dependency] private readonly IPrototypeManager _proto = default!; [Dependency] private readonly SharedMaterialStorageSystem _materialStorage = default!; + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnGetState); + SubscribeLocalEvent(OnHandleState); + } + + private void OnGetState(EntityUid uid, LatheComponent component, ref ComponentGetState args) + { + args.State = new LatheComponentState(component.MaterialUseMultiplier); + } + + private void OnHandleState(EntityUid uid, LatheComponent component, ref ComponentHandleState args) + { + if (args.Current is not LatheComponentState state) + return; + component.MaterialUseMultiplier = state.MaterialUseMultiplier; + } + [PublicAPI] public bool CanProduce(EntityUid uid, string recipe, int amount = 1, LatheComponent? component = null) { @@ -28,7 +50,7 @@ public abstract class SharedLatheSystem : EntitySystem foreach (var (material, needed) in recipe.RequiredMaterials) { - if (_materialStorage.GetMaterialAmount(component.Owner, material) < (amount * needed)) + if (_materialStorage.GetMaterialAmount(component.Owner, material) < amount * needed * component.MaterialUseMultiplier) return false; } return true; @@ -36,3 +58,14 @@ public abstract class SharedLatheSystem : EntitySystem protected abstract bool HasRecipe(EntityUid uid, LatheRecipePrototype recipe, LatheComponent component); } + +[Serializable, NetSerializable] +public sealed class LatheComponentState : ComponentState +{ + public float MaterialUseMultiplier; + + public LatheComponentState(float materialUseMultiplier) + { + MaterialUseMultiplier = materialUseMultiplier; + } +} diff --git a/Content.Shared/StepTrigger/Systems/StepTriggerSystem.cs b/Content.Shared/StepTrigger/Systems/StepTriggerSystem.cs index 89ec548fd5..bf08b7c915 100644 --- a/Content.Shared/StepTrigger/Systems/StepTriggerSystem.cs +++ b/Content.Shared/StepTrigger/Systems/StepTriggerSystem.cs @@ -2,7 +2,6 @@ using Content.Shared.StepTrigger.Components; using Robust.Shared.Collections; using Robust.Shared.GameStates; using Robust.Shared.Physics.Components; -using Robust.Shared.Physics.Dynamics; using Robust.Shared.Physics.Events; namespace Content.Shared.StepTrigger.Systems; @@ -103,6 +102,9 @@ public sealed class StepTriggerSystem : EntitySystem { var otherUid = args.OtherFixture.Body.Owner; + if (!args.OtherFixture.Hard) + return; + if (!CanTrigger(uid, otherUid, component)) return; diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 92e12a3cb0..7b9241276a 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,115 +1,4 @@ Entries: -- author: ElectroJr - changes: - - {message: Fixed various visuals for held & equipped items., type: Fix} - id: 2038 - time: '2022-07-29T01:02:09.0000000+00:00' -- author: corentt - changes: - - {message: Syringes can be put in medical belts, type: Add} - id: 2039 - time: '2022-07-29T01:23:11.0000000+00:00' -- author: Rane - changes: - - {message: Miasma is no longer visible until it's approaching dangerous levels., - type: Tweak} - id: 2040 - time: '2022-07-29T03:13:56.0000000+00:00' -- author: ElectroJr - changes: - - {message: Fixed footsteps and bike horn honking sounds having the wrong pitch - scale., type: Fix} - id: 2041 - time: '2022-07-29T16:22:19.0000000+00:00' -- author: Rane - changes: - - {message: Bloodloss now makes you dizzy., type: Add} - id: 2042 - time: '2022-07-31T02:24:24.0000000+00:00' -- author: Peptide90 - changes: - - {message: Adds a new salvage equipment vendor to be added to maps., type: Add} - id: 2043 - time: '2022-07-31T02:31:51.0000000+00:00' -- author: EmoGarbage404 - changes: - - {message: The sound effect for walking in snow has been replaced., type: Tweak} - id: 2044 - time: '2022-07-31T02:36:49.0000000+00:00' -- author: EmoGarbage404 - changes: - - {message: Firesuits no longer protect against space., type: Fix} - id: 2045 - time: '2022-07-31T02:44:50.0000000+00:00' -- author: Myctai - changes: - - {message: syndicate shoulder holster will now accept melee weapons, type: Fix} - id: 2046 - time: '2022-07-31T02:48:05.0000000+00:00' -- author: jessicamaybe - changes: - - {message: You can now see the station time in the lobby screen, type: Add} - id: 2047 - time: '2022-07-31T02:55:43.0000000+00:00' -- author: CormosLemming - changes: - - {message: Popcorn sprite now has the proper number on it., type: Fix} - id: 2048 - time: '2022-07-31T02:56:04.0000000+00:00' -- author: ElectroJr - changes: - - {message: Fixed a bug that enabled people to keep breathing using gas tanks that - had been unequipped., type: Fix} - id: 2049 - time: '2022-07-31T02:56:26.0000000+00:00' -- author: Peptide90 - changes: - - {message: Desk lamps and floodlights are now heavier., type: Tweak} - id: 2050 - time: '2022-07-31T02:56:42.0000000+00:00' -- author: GoodWheatley - changes: - - {message: nuke disk now takes up 5 space instead of 12, type: Tweak} - id: 2051 - time: '2022-07-31T02:58:19.0000000+00:00' -- author: Deahaka - changes: - - {message: Added donut-vend., type: Add} - id: 2052 - time: '2022-07-31T02:58:57.0000000+00:00' -- author: notafet - changes: - - {message: Passive gates now equalize pressure instantly and come with a built-in - gas flow meter., type: Tweak} - id: 2053 - time: '2022-07-31T03:00:35.0000000+00:00' -- author: Rane - changes: - - {message: Added the syndicate reinforcement teleporter to the uplink., type: Add} - id: 2054 - time: '2022-07-31T03:01:29.0000000+00:00' -- author: ElectroJr - changes: - - {message: Fixed some some hardsuit helmet icons not showing up in the inventory - and actions UI, type: Fix} - id: 2055 - time: '2022-07-31T03:02:12.0000000+00:00' -- author: Pancake - changes: - - {message: Beware the monkey wizard., type: Add} - id: 2056 - time: '2022-07-31T03:12:06.0000000+00:00' -- author: Myctai - changes: - - {message: New Barozine overdose threshold is at 30 units (with same effects), - type: Tweak} - - {message: 'Space medipen now comes with 20 units of Barozine (and keeps it''s - 10 units of Leporazine), giving you about extra 30 seconds to find spacesuit - of some kind, oxygen not included!', type: Tweak} - - {message: Poisoning and brute healing aspect of Barozine were replaced with very - minor burn damage, type: Tweak} - id: 2057 - time: '2022-07-31T03:15:09.0000000+00:00' - author: ike709 changes: - {message: 'Added a new space ambience song, "Drifting" by qwerty', type: Add} @@ -2945,3 +2834,122 @@ Entries: - {message: Hopefully fix the server crashing very often., type: Fix} id: 2537 time: '2022-10-29T16:22:22.417732+00:00' +- author: Scribbles0 + changes: + - {message: A mini jetpack crate can now be found in cargo's ordering catalog., + type: Add} + - {message: Mini jetpacks now have slightly more air capacity., type: Tweak} + - {message: Fixed certain mini jetpacks having the capacity of a normal jetpack., + type: Fix} + id: 2538 + time: '2022-10-30T05:54:03.0000000+00:00' +- author: notafet + changes: + - {message: Chairs are drawn correctly when rotated., type: Fix} + id: 2539 + time: '2022-10-30T05:58:24.0000000+00:00' +- author: Nairod + changes: + - {message: Added the mass scanner and power monitoring computer boards to the circuit + imprinter., type: Add} + id: 2540 + time: '2022-10-30T06:00:00.0000000+00:00' +- author: Mervill + changes: + - {message: Fixed Vending Machines not showing their damage sprite in most cases., + type: Fix} + id: 2541 + time: '2022-10-30T06:12:05.0000000+00:00' +- author: EmoGarbage404 + changes: + - {message: Added machine part upgrades for emitters. Have fun blasting holes into + things quicker., type: Add} + - {message: Slightly increased emitter power consumption and minimum burst delay., + type: Tweak} + id: 2542 + time: '2022-10-30T06:53:31.0000000+00:00' +- author: Nairod + changes: + - {message: 'Added Norepinephric Acid, the blindness inducing chemical.', type: Add} + id: 2543 + time: '2022-10-30T07:10:00.0000000+00:00' +- author: EmoGarbage404 + changes: + - {message: Lathes can now be upgraded to print faster and to consume fewer materials + per print., type: Add} + id: 2544 + time: '2022-10-30T07:12:11.0000000+00:00' +- author: EmoGarbage404 + changes: + - {message: Added machine upgrades for microwaves., type: Add} + id: 2545 + time: '2022-10-30T07:14:20.0000000+00:00' +- author: DeathCamel57 + changes: + - {message: Console chat hotkey works again., type: Fix} + id: 2546 + time: '2022-10-30T07:18:41.0000000+00:00' +- author: JustinTrotter + changes: + - {message: added minor delay to curtain open/close time, type: Tweak} + id: 2547 + time: '2022-10-30T07:34:01.0000000+00:00' +- author: Carbonhell + changes: + - {message: Examining a humanoid with an age between 30 and 60 years old now properly + shows them as middle-aged instead of old., type: Fix} + id: 2548 + time: '2022-10-30T18:54:20.0000000+00:00' +- author: Interrobang01 + changes: + - {message: Made it easier to see codewords in the character menu and syndicate + agent briefing., type: Tweak} + - {message: The Syndicate hates Nanotrasen slightly more., type: Tweak} + id: 2549 + time: '2022-10-30T18:56:41.0000000+00:00' +- author: Rane + changes: + - {message: Fixed several items of clothing making your entire head invisible., + type: Fix} + id: 2550 + time: '2022-10-30T18:58:36.0000000+00:00' +- author: aklos + changes: + - {message: Flying mobs no longer run into mousetraps and glass shards, type: Fix} + id: 2551 + time: '2022-10-30T19:55:07.0000000+00:00' +- author: ElectroJr + changes: + - {message: Fixed some entity lookup / physics bugs. Hopefully the game should be + a bit more stable now., type: Fix} + id: 2552 + time: '2022-10-30T23:17:28.0000000+00:00' +- author: EmoGarbage404 + changes: + - {message: skeletons can no longer have hair., type: Fix} + id: 2553 + time: '2022-10-31T00:04:30.0000000+00:00' +- author: Rane + changes: + - {message: Fixed the sprite modifications for female humanoids jumpsuit slot clothes., + type: Fix} + id: 2554 + time: '2022-10-31T00:06:17.0000000+00:00' +- author: Rane + changes: + - {message: Traitor mode will now work on its own rather than only in secret., type: Fix} + id: 2555 + time: '2022-10-31T02:02:42.0000000+00:00' +- author: Rane + changes: + - {message: 'You can no longer use nettles, space snakes, and so on as injectors. + The only injecting melee weapon that lets you use your own reagents is spears.', + type: Fix} + id: 2556 + time: '2022-10-31T02:04:51.0000000+00:00' +- author: ElectroJr + changes: + - {message: Fixed being unable to craft certain items., type: Fix} + - {message: Maybe fixed cargo shuttle not properly selling items., type: Fix} + id: 2557 + time: '2022-10-31T02:26:05.0000000+00:00' diff --git a/Resources/Locale/en-US/game-ticking/game-presets/preset-nukeops.ftl b/Resources/Locale/en-US/game-ticking/game-presets/preset-nukeops.ftl index 4becfeef9d..ed25a8599c 100644 --- a/Resources/Locale/en-US/game-ticking/game-presets/preset-nukeops.ftl +++ b/Resources/Locale/en-US/game-ticking/game-presets/preset-nukeops.ftl @@ -1,7 +1,9 @@ nukeops-title = Nuclear Operatives nukeops-description = Nuclear operatives have targeted the station. Try to keep them from arming and detonating the nuke by protecting the nuke disk! -nukeops-welcome = You are a nuclear operative. Your goal is to blow up {$station}, and ensure that it is nothing but a pile of rubble. Your bosses, the Syndicate, have provided you with the tools you'll need for the task. +nukeops-welcome = + You are a nuclear operative. Your goal is to blow up {$station}, and ensure that it is nothing but a pile of rubble. Your bosses, the Syndicate, have provided you with the tools you'll need for the task. + Death to Nanotrasen! nukeops-opsmajor = Syndicate major victory! nukeops-opsminor = Syndicate minor victory! diff --git a/Resources/Locale/en-US/game-ticking/game-presets/preset-traitor.ftl b/Resources/Locale/en-US/game-ticking/game-presets/preset-traitor.ftl index ed49fb68c1..11d27e65f6 100644 --- a/Resources/Locale/en-US/game-ticking/game-presets/preset-traitor.ftl +++ b/Resources/Locale/en-US/game-ticking/game-presets/preset-traitor.ftl @@ -39,5 +39,13 @@ traitor-death-match-end-round-description-entry = {$originalName}'s PDA, with {$ ## TraitorRole # TraitorRole -traitor-role-greeting = You are a syndicate agent. Your objectives and codewords are listed in the character menu. Use the uplink loaded into your PDA to buy the tools you'll need for this mission. -traitor-role-codewords = Codewords can be used in regular conversation to identify yourself discretely to other syndicate agents. The syndicate codewords are: {$codewords} +traitor-role-greeting = + You are a syndicate agent. + Your objectives and codewords are listed in the character menu. + Use the uplink loaded into your PDA to buy the tools you'll need for this mission. + Death to Nanotrasen! +traitor-role-codewords = + The codewords are: + {$codewords}. + Codewords can be used in regular conversation to identify yourself discretely to other syndicate agents. + Listen for them, and keep them secret. diff --git a/Resources/Locale/en-US/job/job.ftl b/Resources/Locale/en-US/job/job.ftl index ebcc3a76ab..d999c0d92d 100644 --- a/Resources/Locale/en-US/job/job.ftl +++ b/Resources/Locale/en-US/job/job.ftl @@ -3,3 +3,4 @@ job-greet-introduce-job-name = Your role is: {$jobName}. job-greet-important-disconnect-admin-notify = You are playing a job that is important for Game Progression. If you have to disconnect, please notify the admins via ahelp. job-greet-supervisors-warning = As the {$jobName} you answer directly to {$supervisors}. Special circumstances may change this. job-greet-crew-shortages = As this station was initially staffed with a skeleton crew, additional access has been added to your ID card. +job-not-available-wait-in-lobby = The round has started, but you did not receive any of your preferred job roles (or have no preferred job roles selected) and chose to remain in the lobby. You can change this behavior on the customization screen. \ No newline at end of file diff --git a/Resources/Locale/en-US/prototypes/catalog/cargo/cargo-engineering.ftl b/Resources/Locale/en-US/prototypes/catalog/cargo/cargo-engineering.ftl index 183a4c15a9..c6e0ce5493 100644 --- a/Resources/Locale/en-US/prototypes/catalog/cargo/cargo-engineering.ftl +++ b/Resources/Locale/en-US/prototypes/catalog/cargo/cargo-engineering.ftl @@ -15,3 +15,6 @@ ent-EngineeringElectricalSupplies = { ent-CrateEngineeringElectricalSupplies } ent-EngineeringJetpack = { ent-CrateEngineeringJetpack } .desc = { ent-CrateEngineeringJetpack.desc } + +ent-EngineeringMiniJetpack = { ent-CrateEngineeringMiniJetpack } + .desc = { ent-CrateEngineeringMiniJetpack.desc } \ No newline at end of file diff --git a/Resources/Locale/en-US/prototypes/catalog/fills/crates/engineering-crates.ftl b/Resources/Locale/en-US/prototypes/catalog/fills/crates/engineering-crates.ftl index 52ed2f2cc3..79bd852472 100644 --- a/Resources/Locale/en-US/prototypes/catalog/fills/crates/engineering-crates.ftl +++ b/Resources/Locale/en-US/prototypes/catalog/fills/crates/engineering-crates.ftl @@ -24,3 +24,6 @@ ent-CrateEngineeringElectricalSupplies = Electrical Supplies Crate ent-CrateEngineeringJetpack = Jetpack crate .desc = Two jetpacks for those who don't know how to use fire extinguishers. + +ent-CrateEngineeringMiniJetpack = Mini jetpack crate + .desc = Two mini jetpacks for those who want an extra challenge. \ No newline at end of file diff --git a/Resources/Locale/en-US/reagents/generic.ftl b/Resources/Locale/en-US/reagents/generic.ftl index c96e03d4d8..cda4e434d3 100644 --- a/Resources/Locale/en-US/reagents/generic.ftl +++ b/Resources/Locale/en-US/reagents/generic.ftl @@ -1,3 +1,6 @@ ### Messages that can be utilized by multiple reagents. generic-reagent-effect-burning-insides = You feel your insides burning up! +generic-reagent-effect-burning-eyes = Your eyes begin to slightly burn. +generic-reagent-effect-burning-eyes-a-bit = Your eyes burn a bit. +generic-reagent-effect-tearing-up = Your eyes start to tear up. \ No newline at end of file diff --git a/Resources/Locale/en-US/reagents/meta/narcotics.ftl b/Resources/Locale/en-US/reagents/meta/narcotics.ftl index 8d913894cc..146288a30a 100644 --- a/Resources/Locale/en-US/reagents/meta/narcotics.ftl +++ b/Resources/Locale/en-US/reagents/meta/narcotics.ftl @@ -24,3 +24,6 @@ reagent-desc-nocturine = Makes you feel very tired and unable to stand up. Basic reagent-name-mute-toxin = mute toxin reagent-desc-mute-toxin = Makes you unable to talk while metabolizing. + +reagent-name-norepinephric-acid = norepinephric acid +reagent-desc-norepinephric-acid = Makes you unable to see while metabolizing. \ No newline at end of file diff --git a/Resources/Locale/en-US/reagents/norepinephricacid.ftl b/Resources/Locale/en-US/reagents/norepinephricacid.ftl new file mode 100644 index 0000000000..da06315c0b --- /dev/null +++ b/Resources/Locale/en-US/reagents/norepinephricacid.ftl @@ -0,0 +1,8 @@ +norepinephricacid-effect-eyelids = Your eyelids are rapidly twitching. +norepinephricacid-effect-eyes-itch = Your eyes feel itchy. +norepinephricacid-effect-vision-fade = You feel your vision fading. +norepinephricacid-effect-vision-fail = You can feel your vision failing you. +norepinephricacid-effect-eye-pain = You feel a deep pain in your eyes! +norepinephricacid-effect-blindness = Your eyes cease function! +norepinephricacid-effect-darkness = You are plunged into a world of darkness! +norepinephricacid-effect-eye-disconnect = Your eyes feel like they're disconnecting! \ No newline at end of file diff --git a/Resources/Prototypes/Catalog/Cargo/cargo_engineering.yml b/Resources/Prototypes/Catalog/Cargo/cargo_engineering.yml index ef0c8b1da3..512900da8c 100644 --- a/Resources/Prototypes/Catalog/Cargo/cargo_engineering.yml +++ b/Resources/Prototypes/Catalog/Cargo/cargo_engineering.yml @@ -57,3 +57,13 @@ cost: 1000 category: Engineering group: market + +- type: cargoProduct + id: EngineeringMiniJetpack + icon: + sprite: Objects/Tanks/Jetpacks/mini.rsi + state: icon + product: CrateEngineeringMiniJetpack + cost: 750 + category: Engineering + group: market \ No newline at end of file diff --git a/Resources/Prototypes/Catalog/Fills/Crates/engineering.yml b/Resources/Prototypes/Catalog/Fills/Crates/engineering.yml index 9124e07630..303a3ec1f4 100644 --- a/Resources/Prototypes/Catalog/Fills/Crates/engineering.yml +++ b/Resources/Prototypes/Catalog/Fills/Crates/engineering.yml @@ -96,3 +96,12 @@ contents: - id: JetpackBlue amount: 2 + +- type: entity + id: CrateEngineeringMiniJetpack + parent: CrateGenericSteel + components: + - type: StorageFill + contents: + - id: JetpackMini + amount: 2 diff --git a/Resources/Prototypes/Catalog/Research/technologies.yml b/Resources/Prototypes/Catalog/Research/technologies.yml index b886fb6d09..ac447e4bfa 100644 --- a/Resources/Prototypes/Catalog/Research/technologies.yml +++ b/Resources/Prototypes/Catalog/Research/technologies.yml @@ -291,6 +291,7 @@ unlockedRecipes: - ShuttleConsoleCircuitboard - Drone + - RadarConsoleCircuitboard # Electromagnetic Theory Technology Tree @@ -317,6 +318,7 @@ - SubstationMachineCircuitboard - HydroponicsTrayMachineCircuitboard - SolarControlComputerCircuitboard + - PowerComputerCircuitboard - GeneratorPlasmaMachineCircuitboard - Signaller - SignalTrigger diff --git a/Resources/Prototypes/Entities/Clothing/Uniforms/base_clothinguniforms.yml b/Resources/Prototypes/Entities/Clothing/Uniforms/base_clothinguniforms.yml index ac934f74c3..2adcc212b0 100644 --- a/Resources/Prototypes/Entities/Clothing/Uniforms/base_clothinguniforms.yml +++ b/Resources/Prototypes/Entities/Clothing/Uniforms/base_clothinguniforms.yml @@ -9,6 +9,10 @@ slots: [innerclothing] equipSound: path: /Audio/Items/jumpsuit_equip.ogg + clothingVisuals: + jumpsuit: + - state: equipped-INNERCLOTHING + shader: StencilDraw - type: Butcherable butcheringType: Knife spawned: diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/simplemob.yml b/Resources/Prototypes/Entities/Mobs/NPCs/simplemob.yml index eef2e0cd5b..d5fd4c4824 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/simplemob.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/simplemob.yml @@ -136,7 +136,6 @@ - type: Polymorphable - type: Pullable - type: Buckle - - type: DiseaseCarrier - type: Recyclable safe: false - type: StandingState diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/spacetick.yml b/Resources/Prototypes/Entities/Mobs/NPCs/spacetick.yml index 96abaaf59f..8124ddec4c 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/spacetick.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/spacetick.yml @@ -60,19 +60,14 @@ damage: groups: Brute: 2 - - type: MeleeChemicalInjector - type: SolutionContainerManager solutions: melee: reagents: - ReagentId: Toxin Quantity: 5 - - type: RefillableSolution + - type: MeleeChemicalInjector solution: melee - - type: InjectableSolution - solution: melee - - type: SolutionTransfer - maxTransferAmount: 5 - type: GhostTakeoverAvailable prob: 0.33 makeSentient: true diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/xeno.yml b/Resources/Prototypes/Entities/Mobs/NPCs/xeno.yml index ae92371085..8fe666334a 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/xeno.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/xeno.yml @@ -370,19 +370,14 @@ damage: types: Piercing: 5 - - type: MeleeChemicalInjector - type: SolutionContainerManager solutions: melee: reagents: - ReagentId: Toxin Quantity: 50 - - type: RefillableSolution + - type: MeleeChemicalInjector solution: melee - - type: InjectableSolution - solution: melee - - type: SolutionTransfer - maxTransferAmount: 3 - type: Fixtures fixtures: - shape: diff --git a/Resources/Prototypes/Entities/Mobs/Species/base.yml b/Resources/Prototypes/Entities/Mobs/Species/base.yml index dcfb2c7982..1ed322cee0 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/base.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/base.yml @@ -105,7 +105,7 @@ - map: [ "enum.HumanoidVisualLayers.RLeg" ] - map: [ "enum.HumanoidVisualLayers.LLeg" ] - shader: StencilClear - sprite: Mobs/Species/Human/parts.rsi + sprite: Mobs/Species/Human/parts.rsi #PJB on stencil clear being on the left leg: "...this is 'fine'" -https://github.com/space-wizards/space-station-14/pull/12217#issuecomment-1291677115 state: l_leg - shader: StencilMask map: [ "enum.HumanoidVisualLayers.StencilMask" ] @@ -113,7 +113,6 @@ state: female_full visible: false - map: [ "jumpsuit" ] - shader: StencilDraw - map: [ "enum.HumanoidVisualLayers.LHand" ] - map: [ "enum.HumanoidVisualLayers.RHand" ] - map: [ "enum.HumanoidVisualLayers.LFoot" ] @@ -321,7 +320,6 @@ state: female_full visible: false - map: [ "jumpsuit" ] - shader: StencilDraw - map: [ "enum.HumanoidVisualLayers.LHand" ] - map: [ "enum.HumanoidVisualLayers.RHand" ] - map: [ "enum.HumanoidVisualLayers.LFoot" ] diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/produce.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/produce.yml index 065ff98e64..e16e356e72 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/produce.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/produce.yml @@ -132,10 +132,9 @@ seedId: nettle - type: MeleeChemicalInjector transferAmount: 6 #To OD someone you would need 2 nettles and about 6-7 hits, the DOT is likely to crit them if they are running away with almost no health + solution: food - type: Extractable grindableSolutionName: food - - type: InjectableSolution - solution: food - type: entity name: banana diff --git a/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/production.yml b/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/production.yml index c90b978dbd..0ef1403436 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/production.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/production.yml @@ -94,8 +94,7 @@ prototype: UniformPrinter requirements: MatterBin: 1 - Manipulator: 1 - Laser: 1 + Laser: 2 - type: entity id: VaccinatorMachineCircuitboard @@ -485,7 +484,7 @@ - type: MachineBoard prototype: KitchenMicrowave requirements: - MatterBin: 1 + Capacitor: 1 Laser: 1 materialRequirements: Glass: 2 diff --git a/Resources/Prototypes/Entities/Objects/Tools/jetpacks.yml b/Resources/Prototypes/Entities/Objects/Tools/jetpacks.yml index a687ef7d83..8429a94b27 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/jetpacks.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/jetpacks.yml @@ -180,6 +180,10 @@ slots: - Back - suitStorage + - type: GasTank + outputPressure: 42.6 + air: + volume: 4 # Filled mini - type: entity @@ -192,10 +196,10 @@ outputPressure: 42.6 air: temperature: 293.15 - volume: 2 + volume: 4 moles: - - 0.161 - - 0.161 + - 0.747 + - 0.747 #Empty security - type: entity diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Melee/spear.yml b/Resources/Prototypes/Entities/Objects/Weapons/Melee/spear.yml index 4460328371..cbb1316a30 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Melee/spear.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Melee/spear.yml @@ -32,11 +32,12 @@ graph: Spear node: spear - type: ItemCooldown - - type: MeleeChemicalInjector - type: SolutionContainerManager solutions: melee: maxVol: 5 + - type: MeleeChemicalInjector + solution: melee - type: RefillableSolution solution: melee - type: InjectableSolution diff --git a/Resources/Prototypes/Entities/Structures/Decoration/curtains.yml b/Resources/Prototypes/Entities/Structures/Decoration/curtains.yml index cabde9f9df..4bccf3d1a5 100644 --- a/Resources/Prototypes/Entities/Structures/Decoration/curtains.yml +++ b/Resources/Prototypes/Entities/Structures/Decoration/curtains.yml @@ -27,9 +27,9 @@ performCollisionCheck: false bumpOpen: false clickOpen: true - closeTimeOne: 0.1 + closeTimeOne: 0.5 closeTimeTwo: 0.1 - openTimeOne: 0.1 + openTimeOne: 0.5 openTimeTwo: 0.1 openSound: path: /Audio/Effects/curtain_openclose.ogg diff --git a/Resources/Prototypes/Entities/Structures/Machines/frame.yml b/Resources/Prototypes/Entities/Structures/Machines/frame.yml index e300a9d47b..d694aa4aa3 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/frame.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/frame.yml @@ -29,6 +29,10 @@ - type: Construction graph: Machine node: missingWires + - type: ContainerContainer + containers: + machine_board: !type:Container + machine_parts: !type:Container - type: Damageable damageContainer: Inorganic damageModifierSet: Metallic @@ -76,6 +80,7 @@ - type: Construction graph: Machine node: machineFrame + defaultTarget: machine - type: Damageable damageContainer: Inorganic damageModifierSet: Metallic @@ -90,6 +95,10 @@ - !type:DoActsBehavior acts: ["Destruction"] - type: MachineFrame + - type: ContainerContainer + containers: + machine_board: !type:Container + machine_parts: !type:Container - type: Sprite netsync: false sprite: Structures/Machines/parts.rsi diff --git a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml index 17473ef826..b7f3d5efd5 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml @@ -277,12 +277,14 @@ - SurveillanceWirelessCameraAnchoredCircuitboard - HydroponicsTrayMachineCircuitboard - SolarControlComputerCircuitboard + - PowerComputerCircuitboard - AutolatheMachineCircuitboard - ProtolatheMachineCircuitboard - ReagentGrinderMachineCircuitboard - MicrowaveMachineCircuitboard - UniformPrinterMachineCircuitboard - ShuttleConsoleCircuitboard + - RadarConsoleCircuitboard - CircuitImprinterMachineCircuitboard - DawInstrumentMachineCircuitboard - CloningConsoleComputerCircuitboard @@ -375,6 +377,7 @@ - type: Lathe idleState: icon runningState: icon + machinePartPrintSpeed: Laser dynamicRecipes: - HandheldHealthAnalyzer - ClothingHandsGlovesLatex diff --git a/Resources/Prototypes/Entities/Structures/Machines/microwave.yml b/Resources/Prototypes/Entities/Structures/Machines/microwave.yml index bdef9b808b..64ad1d560d 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/microwave.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/microwave.yml @@ -59,6 +59,9 @@ acts: ["Breakage"] - type: ApcPowerReceiver powerLoad: 400 + - type: UpgradePowerDraw + powerDrawMultiplier: 0.75 + scaling: Exponential - type: Machine board: MicrowaveMachineCircuitboard - type: ContainerContainer diff --git a/Resources/Prototypes/Reagents/narcotics.yml b/Resources/Prototypes/Reagents/narcotics.yml index c531b90b0c..7b96e8c4fb 100644 --- a/Resources/Prototypes/Reagents/narcotics.yml +++ b/Resources/Prototypes/Reagents/narcotics.yml @@ -205,3 +205,47 @@ - !type:GenericStatusEffect key: Muted component: Muted + +- type: reagent + id: NorepinephricAcid + name: reagent-name-norepinephric-acid + group: Narcotics + desc: reagent-desc-norepinephric-acid + physicalDesc: reagent-physical-desc-milky + flavor: salty + color: "#96a8b5" + boilingPoint: 255.0 + meltingPoint: 36.0 + metabolisms: + Narcotic: + effects: + - !type:PopupMessage + type: Local + messages: + - generic-reagent-effect-burning-eyes + - generic-reagent-effect-burning-eyes-a-bit + - generic-reagent-effect-tearing-up + - norepinephricacid-effect-eyelids + - norepinephricacid-effect-eyes-itch + - norepinephricacid-effect-vision-fade + - norepinephricacid-effect-vision-fail + probability: 0.08 + - !type:PopupMessage + visualType: MediumCaution + type: Local + messages: + - norepinephricacid-effect-eye-disconnect + - norepinephricacid-effect-eye-pain + - norepinephricacid-effect-darkness + - norepinephricacid-effect-blindness + conditions: + - !type:ReagentThreshold + min: 20 + probability: 0.03 + #If anyone wants to add a light dimming or grayscale effect when under 20u, be my guest + - !type:GenericStatusEffect + key: TemporaryBlindness + component: TemporaryBlindness + conditions: + - !type:ReagentThreshold + min: 20 \ No newline at end of file diff --git a/Resources/Prototypes/Recipes/Lathes/electronics.yml b/Resources/Prototypes/Recipes/Lathes/electronics.yml index 1f47c08584..308c368c63 100644 --- a/Resources/Prototypes/Recipes/Lathes/electronics.yml +++ b/Resources/Prototypes/Recipes/Lathes/electronics.yml @@ -205,6 +205,15 @@ Glass: 900 Gold: 100 +- type: latheRecipe + id: RadarConsoleCircuitboard + icon: Objects/Misc/module.rsi/id_mod.png + result: RadarConsoleCircuitboard + completetime: 4 + materials: + Steel: 100 + Glass: 900 + - type: latheRecipe id: DawInstrumentMachineCircuitboard icon: Objects/Misc/module.rsi/id_mod.png @@ -315,6 +324,15 @@ Steel: 100 Glass: 900 +- type: latheRecipe + id: PowerComputerCircuitboard + icon: Objects/Misc/module.rsi/id_mod.png + result: PowerComputerCircuitboard + completetime: 4 + materials: + Steel: 100 + Glass: 900 + - type: latheRecipe id: CloningConsoleComputerCircuitboard icon: Objects/Misc/module.rsi/id_mod.png diff --git a/Resources/Prototypes/Recipes/Reactions/chemicals.yml b/Resources/Prototypes/Recipes/Reactions/chemicals.yml index 505e8b6bbe..caacb0ef55 100644 --- a/Resources/Prototypes/Recipes/Reactions/chemicals.yml +++ b/Resources/Prototypes/Recipes/Reactions/chemicals.yml @@ -348,4 +348,17 @@ Ash: amount: 1 products: - Charcoal: 1 \ No newline at end of file + Charcoal: 1 + +- type: reaction + id: NorepinephricAcid + impact: Medium + reactants: + Uranium: + amount: 2 + Hydrogen: + amount: 1 + Oxygen: + amount: 1 + products: + NorepinephricAcid: 2 \ No newline at end of file diff --git a/Resources/Prototypes/Species/skeleton.yml b/Resources/Prototypes/Species/skeleton.yml index a5ae1bdd25..b0e41ca30b 100644 --- a/Resources/Prototypes/Species/skeleton.yml +++ b/Resources/Prototypes/Species/skeleton.yml @@ -14,8 +14,6 @@ id: MobSkeletonSprites sprites: Head: MobSkeletonHead - Hair: MobHumanoidAnyMarking - FacialHair: MobHumanoidAnyMarking Chest: MobSkeletonTorso LArm: MobSkeletonLArm RArm: MobSkeletonRArm diff --git a/Resources/clientCommandPerms.yml b/Resources/clientCommandPerms.yml index d1d0168612..e5d3b6f5ca 100644 --- a/Resources/clientCommandPerms.yml +++ b/Resources/clientCommandPerms.yml @@ -27,6 +27,7 @@ - gc_mode - resetent - resetallents + - cvar - Flags: DEBUG Commands: diff --git a/RobustToolbox b/RobustToolbox index 26c85725a5..03acded657 160000 --- a/RobustToolbox +++ b/RobustToolbox @@ -1 +1 @@ -Subproject commit 26c85725a5b810a8ca2b48a3761fa55a1ec17495 +Subproject commit 03acded657f709d9ce2ccec75b034837e140b435