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

# Conflicts:
#	.github/workflows/build-docfx.yml
This commit is contained in:
Morbo 2022-10-31 15:36:01 +03:00
commit efa9d6561f
128 changed files with 957 additions and 475 deletions

41
.github/workflows/build-docfx.yml vendored Normal file
View file

@ -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 }}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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<TransformComponent>(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;

View file

@ -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<ClientInventoryComponent, VisualsChangedEvent>(OnVisualsChanged);
SubscribeLocalEvent<SpriteComponent, DidUnequipEvent>(OnDidUnequip);
SubscribeLocalEvent<ClientInventoryComponent, AppearanceChangeEvent>(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))

View file

@ -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
{

View file

@ -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
/// <summary>
/// Constructs a new instance of <see cref="ConstructionMenuPresenter" />.
/// </summary>
/// <param name="gameHud">GUI that is being presented to.</param>
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<SpriteSystem>();
_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<SpriteSystem>();
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<ConstructionSystem>();
var constructSystem = _systemManager.GetEntitySystem<ConstructionSystem>();
_placementManager.BeginPlacing(new PlacementInformation()
{

View file

@ -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);

View file

@ -56,17 +56,14 @@ namespace Content.Client.Gameplay
public IList<EntityUid> GetEntitiesUnderPosition(MapCoordinates coordinates)
{
// Find all the entities intersecting our click
var entities = EntitySystem.Get<EntityLookupSystem>().GetEntitiesIntersecting(coordinates.MapId,
Box2.CenteredAround(coordinates.Position, (1, 1)));
var containerSystem = _entitySystemManager.GetEntitySystem<SharedContainerSystem>();
var entities = _entityManager.EntitySysManager.GetEntitySystem<EntityLookupSystem>().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<ClickableComponent?>(entity, out var component)
&& !containerSystem.IsEntityInContainer(entity)
&& component.CheckClick(coordinates.Position, out var drawDepthClicked, out var renderOrder))
{
foundEntities.Add((entity, drawDepthClicked, renderOrder));

View file

@ -25,7 +25,6 @@ public sealed partial class LatheMenu : DefaultWindow
public event Action<string, int>? RecipeQueueAction;
public List<string> Recipes = new();
private List<LatheRecipePrototype> _oldRecipesToShow = new();
public LatheMenu(LatheBoundUserInterface owner)
{
@ -85,6 +84,9 @@ public sealed partial class LatheMenu : DefaultWindow
/// <param name="lathe"></param>
public void PopulateRecipes(EntityUid lathe)
{
if (!_entityManager.TryGetComponent<LatheComponent>(lathe, out var component))
return;
var recipesToShow = new List<LatheRecipePrototype>();
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);
}

View file

@ -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");

View file

@ -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<SpriteComponent>(uid, out var sprite))
return;
UpdateAppearance(uid, VendingMachineVisualState.Normal, component, sprite);
if (!TryComp<AppearanceComponent>(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)

View file

@ -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();
}

View file

@ -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

View file

@ -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<IMapManager>();
var invSystem = IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<InventorySystem>();
mapMan.CreateNewMapEntity(MapId.Nullspace);
var entMgr = IoCManager.Resolve<IEntityManager>();
var container = entMgr.SpawnEntity(null, MapCoordinates.Nullspace);
var container = entMgr.SpawnEntity(null, coordinates);
entMgr.EnsureComponent<ServerInventoryComponent>(container);
entMgr.EnsureComponent<ContainerManagerComponent>(container);
var child = entMgr.SpawnEntity(null, MapCoordinates.Nullspace);
var child = entMgr.SpawnEntity(null, coordinates);
var item = entMgr.EnsureComponent<ClothingComponent>(child);
IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<ClothingSystem>().SetSlots(item.Owner, SlotFlags.HEAD, item);

View file

@ -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<IMapManager>();
var entityManager = server.ResolveDependency<IEntityManager>();
var deviceNetSystem = entityManager.EntitySysManager.GetEntitySystem<DeviceNetworkSystem>();
var deviceNetTestSystem = entityManager.EntitySysManager.GetEntitySystem<DeviceNetworkTestSystem>();
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<IMapManager>();
var entityManager = server.ResolveDependency<IEntityManager>();
var deviceNetSystem = entityManager.EntitySysManager.GetEntitySystem<DeviceNetworkSystem>();
var deviceNetTestSystem = entityManager.EntitySysManager.GetEntitySystem<DeviceNetworkTestSystem>();
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);
});

View file

@ -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

View file

@ -37,7 +37,6 @@ namespace Content.IntegrationTests.Tests.DoAfter
await server.WaitPost(() =>
{
var tickTime = 1.0f / IoCManager.Resolve<IGameTiming>().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<IGameTiming>().TickRate;
mapManager.CreateNewMapEntity(MapId.Nullspace);
var mob = entityManager.SpawnEntity("Dummy", MapCoordinates.Nullspace);
var cancelToken = new CancellationTokenSource();

View file

@ -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));

View file

@ -43,8 +43,6 @@ namespace Content.IntegrationTests.Tests.GameObjects.Components.Movement
await server.WaitAssertion(() =>
{
var mapManager = IoCManager.Resolve<IMapManager>();
mapManager.CreateNewMapEntity(MapId.Nullspace);
var entityManager = IoCManager.Resolve<IEntityManager>();
// Spawn the entities

View file

@ -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<IEntitySystemManager>().GetEntitySystem<InventorySystem>();
var mapMan = IoCManager.Resolve<IMapManager>();
mapMan.CreateNewMapEntity(MapId.Nullspace);
var entityMan = IoCManager.Resolve<IEntityManager>();
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 _));

View file

@ -52,9 +52,6 @@ namespace Content.IntegrationTests.Tests
{
var mapMan = IoCManager.Resolve<IMapManager>();
var systemMan = IoCManager.Resolve<IEntitySystemManager>();
mapMan.CreateNewMapEntity(MapId.Nullspace);
var human = sEntities.SpawnEntity("InventoryStunnableDummy", MapCoordinates.Nullspace);
var invSystem = systemMan.GetEntitySystem<InventorySystem>();

View file

@ -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<IPlayerManager>().ServerSessions.Single();
var mapMan = IoCManager.Resolve<IMapManager>();
map = mapMan.CreateMap();
var grid = mapMan.CreateGrid(map);
var entMgr = IoCManager.Resolve<IServerEntityManager>();
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<IMapManager>();
mapMan.DeleteMap(map);
mapMan.DeleteMap(testMap.MapId);
});
await PoolManager.RunTicksSync(pairTracker.Pair, 5);

View file

@ -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]

View file

@ -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");
});

View file

@ -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<TagComponent>(sTagDummy);
});

View file

@ -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;

View file

@ -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;

View file

@ -14,5 +14,12 @@ namespace Content.Server.Chemistry.Components
[DataField("transferEfficiency")]
private float _transferEfficiency = 1f;
/// <summary>
/// Solution to inject from.
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
[DataField("solution")]
public string Solution { get; set; } = "default";
}
}

View file

@ -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);
}
}
}

View file

@ -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;
}
/// <summary>

View file

@ -63,7 +63,7 @@ namespace Content.Server.Construction.Commands
}
var changed = 0;
var tagSystem = EntitySystem.Get<TagSystem>();
var tagSystem = entityManager.EntitySysManager.GetEntitySystem<TagSystem>();
foreach (var child in xformQuery.GetComponent(grid.GridEntityId).ChildEntities)
{

View file

@ -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<IEntityManager>();
EntityUid? gridId;
string tileIdA = "";
string tileIdB = "";
string tileIdA;
string tileIdB;
switch (args.Length)
{

View file

@ -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} <gridId> | {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<ITileDefinitionManager>();
var tagSystem = EntitySystem.Get<TagSystem>();
var underplating = tileDefinitionManager[TilePrototypeID];
var tagSystem = entityManager.EntitySysManager.GetEntitySystem<TagSystem>();
var underplating = tileDefinitionManager[TilePrototypeId];
var underplatingTile = new Tile(underplating.TileId);
var changed = 0;
foreach (var child in entityManager.GetComponent<TransformComponent>(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;
}

View file

@ -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)
{

View file

@ -11,7 +11,7 @@ namespace Content.Server.Construction.Completions
if (userUid == null)
return;
EntitySystem.Get<ElectrocutionSystem>().TryDoElectrifiedAct(uid, userUid.Value);
entityManager.EntitySysManager.GetEntitySystem<ElectrocutionSystem>().TryDoElectrifiedAct(uid, userUid.Value);
}
}
}

View file

@ -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<MachineFrameSystem>().IsComplete(machineFrame))
if (!entityManager.EntitySysManager.GetEntitySystem<MachineFrameSystem>().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<ContainerSystem>();
var transform = entityManager.GetComponent<TransformComponent>(uid);
var machine = entityManager.SpawnEntity(boardComponent.Prototype, transform.Coordinates);
entityManager.GetComponent<TransformComponent>(machine).LocalRotation = transform.LocalRotation;
var boardContainer = machine.EnsureContainer<Container>(MachineFrameComponent.BoardContainerName, out var existed);
var boardContainer = containerSys.EnsureContainer<Container>(machine, MachineFrameComponent.BoardContainerName, out var existed);
if (existed)
{
// Clean that up...
boardContainer.CleanContainer();
containerSys.CleanContainer(boardContainer);
}
var partContainer = machine.EnsureContainer<Container>(MachineFrameComponent.PartContainerName, out existed);
var partContainer = containerSys.EnsureContainer<Container>(machine, MachineFrameComponent.PartContainerName, out existed);
if (existed)
{
// Clean that up, too...
partContainer.CleanContainer();
containerSys.CleanContainer(partContainer);
}
boardContainer.Insert(board);

View file

@ -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)
{

View file

@ -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<ContainerSystem>();
if (!containerSys.TryGetContainer(uid, Container, out var container))
return;
foreach (var contained in container.ContainedEntities.ToArray())
{

View file

@ -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<TransformComponent>(uid);
var containerSys = entityManager.EntitySysManager.GetEntitySystem<ContainerSystem>();
foreach (var container in containerManager.GetAllContainers())
{
container.EmptyContainer(true, transform.Coordinates);
containerSys.EmptyContainer(container, true, transform.Coordinates);
}
}
}

View file

@ -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<ContainerSystem>();
var transform = entityManager.GetComponent<TransformComponent>(uid);
foreach (var contained in container.ContainedEntities.ToArray())
{
container.ForceRemove(contained);
var cTransform = entityManager.GetComponent<TransformComponent>(contained);
cTransform.Coordinates = transform.Coordinates;
cTransform.AttachToGridOrMap();
}
containerSys.EmptyContainer(container, true, transform.Coordinates, true);
}
}
}

View file

@ -12,7 +12,7 @@ namespace Content.Server.Construction.Completions
{
if (entityManager.TryGetComponent<MachineFrameComponent>(uid, out var machineFrame))
{
EntitySystem.Get<MachineFrameSystem>().RegenerateProgress(machineFrame);
entityManager.EntitySysManager.GetEntitySystem<MachineFrameSystem>().RegenerateProgress(machineFrame);
}
}
}

View file

@ -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)
{

View file

@ -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<IRobustRandom>().NextGaussian(1, Variation);
SoundSystem.Play(Sound.GetSound(), Filter.Pvs(uid, entityManager: entityManager), uid, AudioParams.WithPitchScale(scale));
entityManager.EntitySysManager.GetEntitySystem<SharedAudioSystem>()
.PlayPvs(Sound, uid, AudioParams.WithPitchScale(scale));
}
}
}

View file

@ -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)

View file

@ -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);

View file

@ -12,7 +12,7 @@ namespace Content.Server.Construction.Completions
public void PerformAction(EntityUid uid, EntityUid? userUid, IEntityManager entityManager)
{
EntitySystem.Get<StackSystem>().SetCount(uid, Amount);
entityManager.EntitySysManager.GetEntitySystem<StackSystem>().SetCount(uid, Amount);
}
}
}

View file

@ -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<TransformComponent>(uid);
transform.Coordinates = transform.Coordinates.SnapToGrid(entityManager);
if (!transform.Anchored)
transform.Coordinates = transform.Coordinates.SnapToGrid(entityManager);
if (SouthRotation)
{

View file

@ -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);
}

View file

@ -11,7 +11,7 @@ namespace Content.Server.Construction.Components
public sealed class WelderRefinableComponent : Component
{
[DataField("refineResult")]
public HashSet<string>? RefineResult = new() { };
public HashSet<string>? RefineResult = new();
[DataField("refineTime")]
public float RefineTime = 2f;

View file

@ -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<MetaDataComponent>(entity).EntityName)) + "\n");
else
args.PushMarkup(Loc.GetString("construction-examine-condition-airlock-unbolt", ("entityName", entMan.GetComponent<MetaDataComponent>(entity).EntityName)) + "\n");

View file

@ -47,7 +47,8 @@ namespace Content.Server.Construction.Conditions
return false;
var indices = transform.Coordinates.ToVector2i(entityManager, IoCManager.Resolve<IMapManager>());
var entities = indices.GetEntitiesInTile(transform.GridUid.Value, LookupFlags.Approximate | LookupFlags.Anchored, EntitySystem.Get<EntityLookupSystem>());
var lookup = entityManager.EntitySysManager.GetEntitySystem<EntityLookupSystem>();
var entities = indices.GetEntitiesInTile(transform.GridUid.Value, LookupFlags.Approximate | LookupFlags.Anchored, lookup);
foreach (var ent in entities)
{

View file

@ -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<MetaDataComponent>(entity).EntityName)) + "\n");
else
args.PushMarkup(Loc.GetString("construction-examine-condition-door-unweld", ("entityName", entMan.GetComponent<MetaDataComponent>(entity).EntityName)) + "\n");

View file

@ -25,14 +25,16 @@ namespace Content.Server.Construction.Conditions
if (!entityManager.TryGetComponent(uid, out MachineFrameComponent? machineFrame))
return false;
return EntitySystem.Get<MachineFrameSystem>().IsComplete(machineFrame);
return entityManager.EntitySysManager.GetEntitySystem<MachineFrameSystem>().IsComplete(machineFrame);
}
public bool DoExamine(ExaminedEvent args)
{
var entity = args.Examined;
if (!IoCManager.Resolve<IEntityManager>().TryGetComponent<MachineFrameComponent?>(entity, out var machineFrame))
var entityManager = IoCManager.Resolve<IEntityManager>();
if (!entityManager.TryGetComponent<MachineFrameComponent?>(entity, out var machineFrame))
return false;
if (!machineFrame.HasBoard)
@ -41,18 +43,20 @@ namespace Content.Server.Construction.Conditions
return true;
}
if (EntitySystem.Get<MachineFrameSystem>().IsComplete(machineFrame)) return false;
if (entityManager.EntitySysManager.GetEntitySystem<MachineFrameSystem>().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),

View file

@ -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");

View file

@ -7,6 +7,8 @@ namespace Content.Server.Construction;
public sealed partial class ConstructionSystem
{
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
private void InitializeComputer()
{
SubscribeLocalEvent<ComputerComponent, ComponentInit>(OnCompInit);
@ -19,10 +21,9 @@ public sealed partial class ConstructionSystem
// Let's ensure the container manager and container are here.
_container.EnsureContainer<Container>(uid, "board");
if (TryComp<ApcPowerReceiverComponent>(uid, out var powerReceiver) &&
TryComp<AppearanceComponent>(uid, out var appearance))
if (TryComp<ApcPowerReceiverComponent>(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<AppearanceComponent>(uid, out var appearance))
{
appearance.SetData(ComputerVisuals.Powered, args.Powered);
}
_appearance.SetData(uid, ComputerVisuals.Powered, args.Powered);
}
/// <summary>

View file

@ -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<Container>(newUid, container, newContainerManager);
var otherContainer = _container.EnsureContainer<Container>(newUid, container, newContainerManager);
for (var i = ourContainer.ContainedEntities.Count - 1; i >= 0; i--)
{

View file

@ -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<ConstructionPrototype, ConstructionGuide> _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;
}
}

View file

@ -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<EntityUid?> Construct(EntityUid user, string materialContainer, ConstructionGraphPrototype graph, ConstructionGraphEdge edge, ConstructionGraphNode targetNode)
{
// We need a place to hold our construction items!
var container = ContainerHelpers.EnsureContainer<Container>(user, materialContainer, out var existed);
var container = _container.EnsureContainer<Container>(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<Container>(user!, random.ToString(), out var existed);
var c = _container.EnsureContainer<Container>(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<Container>(newEntity, name);
var newCont = _container.EnsureContainer<Container>(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<ActionBlockerSystem>().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<HandsComponent>(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;
}
}

View file

@ -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<Container>(uid, store).Insert(insert);
_container.EnsureContainer<Container>(uid, store).Insert(insert);
}
else
{

View file

@ -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!;

View file

@ -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<MachineBoardComponent?>(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<AppearanceComponent?>(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<MachineBoardComponent>(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);

View file

@ -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)

View file

@ -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<ToolComponent>(args.Used))
return;
// check if someone is already welding object

View file

@ -109,11 +109,11 @@ namespace Content.Server.Damage.Commands
EntityUid target;
var entMan = IoCManager.Resolve<IEntityManager>();
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;
}
}

View file

@ -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<TransformComponent>(holder.Owner).Coordinates = origin.Offset(newPosition);
// This is some supreme shit code.
EntityManager.GetComponent<TransformComponent>(holder.Owner).Coordinates = origin.Offset(newPosition).WithEntityId(currentTube.Owner); ;
continue;
}

View file

@ -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);
}

View file

@ -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<GameRulePrototype>(Prototype));
return;
}
var minPlayers = _cfg.GetCVar(CCVars.TraitorMinPlayers);
if (!ev.Forced && ev.Players.Length < minPlayers)
{

View file

@ -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<IPlayerSession>();
foreach (var player in allPlayers)
{
if (player.AttachedEntity != null)
if (player.AttachedEntity != null && HasComp<DiseaseCarrierComponent>(player.AttachedEntity))
{
playerList.Add(player);

View file

@ -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");
}

View file

@ -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<MachinePartPrototype>))]
public string MachinePartCookTimeMultiplier = "Laser";
[DataField("cookTimeScalingConstant")]
public float CookTimeScalingConstant = 0.5f;
[DataField("failureResult", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
public string BadRecipeEntityId = "FoodBadRecipe";

View file

@ -53,6 +53,7 @@ namespace Content.Server.Kitchen.EntitySystems
SubscribeLocalEvent<MicrowaveComponent, BreakageEventArgs>(OnBreak);
SubscribeLocalEvent<MicrowaveComponent, PowerChangedEvent>(OnPowerChanged);
SubscribeLocalEvent<MicrowaveComponent, SuicideEvent>(OnSuicide);
SubscribeLocalEvent<MicrowaveComponent, RefreshPartsEvent>(OnRefreshParts);
SubscribeLocalEvent<MicrowaveComponent, MicrowaveStartCookMessage>((u,c,_) => Wzhzhzh(u,c));
SubscribeLocalEvent<MicrowaveComponent, MicrowaveEjectMessage>(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<ActiveMicrowaveComponent>(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);
}

View file

@ -7,9 +7,15 @@ namespace Content.Server.Lathe.Components;
public sealed class LatheProducingComponent : Component
{
/// <summary>
/// How much production time has passed, in seconds.
/// The time at which production began
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
public float AccumulatedTime;
public TimeSpan StartTime;
/// <summary>
/// How long it takes to produce the recipe.
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
public TimeSpan ProductionLength;
}

View file

@ -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<LatheComponent, GetMaterialWhitelistEvent>(OnGetWhitelist);
SubscribeLocalEvent<LatheComponent, MapInitEvent>(OnMapInit);
SubscribeLocalEvent<LatheComponent, PowerChangedEvent>(OnPowerChanged);
SubscribeLocalEvent<LatheComponent, RefreshPartsEvent>(OnPartsRefresh);
SubscribeLocalEvent<LatheComponent, LatheQueueRecipeMessage>(OnLatheQueueRecipeMessage);
SubscribeLocalEvent<LatheComponent, LatheSyncRequestMessage>(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<LatheProducingComponent>(uid);
var lathe = EnsureComp<LatheProducingComponent>(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);

View file

@ -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;
/// <summary>
/// counts the number of consecutive shots fired.
/// </summary>
[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");
/// <summary>
/// The entity that is spawned when the emitter fires.
/// </summary>
[DataField("boltType"), ViewVariables]
public string BoltType = "EmitterBolt";
/// <summary>
/// The current amount of power being used.
/// </summary>
[DataField("powerUseActive"), ViewVariables]
public int PowerUseActive = 600;
/// <summary>
/// The base amount of power that is consumed.
/// Used in machine part rating calculations.
/// </summary>
[DataField("basePowerUseActive"), ViewVariables(VVAccess.ReadWrite)]
public int BasePowerUseActive = 600;
/// <summary>
/// Multiplier that is applied to the basePowerUseActive
/// to get the actual power use.
/// </summary>
[DataField("powerUseMultiplier")]
public float PowerUseMultiplier = 0.75f;
/// <summary>
/// The machine part used to reduce the power use of the machine.
/// </summary>
[DataField("machinePartPowerUse", customTypeSerializer: typeof(PrototypeIdSerializer<MachinePartPrototype>))]
public string MachinePartPowerUse = "Capacitor";
/// <summary>
/// The amount of shots that are fired in a single "burst"
/// </summary>
[DataField("fireBurstSize"), ViewVariables]
public int FireBurstSize = 3;
/// <summary>
/// The time between each shot during a burst.
/// </summary>
[DataField("fireInterval"), ViewVariables]
public TimeSpan FireInterval = TimeSpan.FromSeconds(2);
/// <summary>
/// The base amount of time between each shot during a burst.
/// </summary>
[DataField("baseFireInterval"), ViewVariables(VVAccess.ReadWrite)]
public TimeSpan BaseFireInterval = TimeSpan.FromSeconds(2);
/// <summary>
/// The current minimum delay between bursts.
/// </summary>
[DataField("fireBurstDelayMin"), ViewVariables]
public TimeSpan FireBurstDelayMin = TimeSpan.FromSeconds(4);
/// <summary>
/// The current maximum delay between bursts.
/// </summary>
[DataField("fireBurstDelayMax"), ViewVariables]
public TimeSpan FireBurstDelayMax = TimeSpan.FromSeconds(10);
/// <summary>
/// The base minimum delay between shot bursts.
/// Used for machine part rating calculations.
/// </summary>
[DataField("baseFireBurstDelayMin"), ViewVariables]
public TimeSpan BaseFireBurstDelayMin = TimeSpan.FromSeconds(4);
/// <summary>
/// The base maximum delay between shot bursts.
/// Used for machine part rating calculations.
/// </summary>
[DataField("baseFireBurstDelayMax"), ViewVariables]
public TimeSpan BaseFireBurstDelayMax = TimeSpan.FromSeconds(10);
/// <summary>
/// The multiplier for the base delay between shot bursts as well as
/// the fire interval
/// </summary>
[DataField("fireRateMultiplier"), ViewVariables(VVAccess.ReadWrite)]
public float FireRateMultiplier = 0.8f;
/// <summary>
/// The machine part that affects burst delay.
/// </summary>
[DataField("machinePartFireRate", customTypeSerializer: typeof(PrototypeIdSerializer<MachinePartPrototype>))]
public string MachinePartFireRate = "Laser";
}
}

View file

@ -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<EmitterComponent, PowerConsumerReceivedChanged>(ReceivedChanged);
SubscribeLocalEvent<EmitterComponent, InteractHandEvent>(OnInteractHand);
SubscribeLocalEvent<EmitterComponent, RefreshPartsEvent>(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<PowerConsumerComponent>(component.Owner, out var powerConsumer)) powerConsumer.DrawRate = 0;
if (TryComp<PowerConsumerComponent>(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<PowerConsumerComponent>(component.Owner, out var powerConsumer)) powerConsumer.DrawRate = component.PowerUseActive;
if (TryComp<PowerConsumerComponent>(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<ProjectileSystem>().SetShooter(projectileComponent, component.Owner);
_projectile.SetShooter(projectileComponent, component.Owner);
physicsComponent
.LinearVelocity = EntityManager.GetComponent<TransformComponent>(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<AppearanceComponent>(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);
}
}
}

View file

@ -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.
/// </remarks>
public Dictionary<NetUserId, (string, EntityUid)> AssignJobs(Dictionary<NetUserId, HumanoidCharacterProfile> profiles, IReadOnlyList<EntityUid> stations, bool useRoundStartJobs = true)
public Dictionary<NetUserId, (string?, EntityUid)> AssignJobs(Dictionary<NetUserId, HumanoidCharacterProfile> profiles, IReadOnlyList<EntityUid> stations, bool useRoundStartJobs = true)
{
DebugTools.Assert(stations.Count > 0);
InitializeRoundStart();
if (profiles.Count == 0)
return new Dictionary<NetUserId, (string, EntityUid)>();
return new Dictionary<NetUserId, (string?, EntityUid)>();
// We need to modify this collection later, so make a copy of it.
profiles = profiles.ShallowClone();
// Player <-> (job, station)
var assigned = new Dictionary<NetUserId, (string, EntityUid)>(profiles.Count);
var assigned = new Dictionary<NetUserId, (string?, EntityUid)>(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<EntityUid, Dictionary<string, uint?>>();
@ -273,7 +272,7 @@ public sealed partial class StationJobsSystem
/// <param name="allPlayersToAssign">All players that might need an overflow assigned.</param>
/// <param name="profiles">Player character profiles.</param>
/// <param name="stations">The stations to consider for spawn location.</param>
public void AssignOverflowJobs(ref Dictionary<NetUserId, (string, EntityUid)> assignedJobs,
public void AssignOverflowJobs(ref Dictionary<NetUserId, (string?, EntityUid)> assignedJobs,
IEnumerable<NetUserId> allPlayersToAssign, IReadOnlyDictionary<NetUserId, HumanoidCharacterProfile> profiles, IReadOnlyList<EntityUid> 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)

View file

@ -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<BloodstreamComponent>();

View file

@ -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"
};

View file

@ -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"
};

View file

@ -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",
};

View file

@ -13,15 +13,13 @@ namespace Content.Shared.Construction.Conditions
public List<string> 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;
}

View file

@ -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<TransformComponent>(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();
}

View file

@ -36,6 +36,5 @@ public abstract class SharedAnchorableSystem : EntitySystem
ToolComponent? usingTool = null)
{
// Thanks tool system.
return;
}
}

View file

@ -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)},

View file

@ -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);
}

View file

@ -25,7 +25,7 @@ namespace Content.Shared.Construction.Steps
if (!entityManager.TryGetComponent(uid, out TagComponent? tags))
return false;
var tagSystem = EntitySystem.Get<TagSystem>();
var tagSystem = entityManager.EntitySysManager.GetEntitySystem<TagSystem>();
if (_allTags != null && !tagSystem.HasAllTags(tags, _allTags))
return false; // We don't have all the tags needed.

View file

@ -189,7 +189,7 @@ namespace Content.Shared.Damage
if (!delta.Empty)
{
DamageChanged(damageable, delta, interruptsDoAfters);
DamageChanged(damageable, delta, interruptsDoAfters, origin);
}
return delta;

View file

@ -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;
}
}

View file

@ -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));
}

View file

@ -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
/// <summary>
/// A modifier that changes how long it takes to print a recipe
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
public float TimeMultiplier = 1;
/// <summary>
/// The machine part that reduces how long it takes to print a recipe.
/// </summary>
[DataField("machinePartPrintSpeed", customTypeSerializer: typeof(PrototypeIdSerializer<MachinePartPrototype>))]
public string MachinePartPrintTime = "Manipulator";
/// <summary>
/// The value that is used to calculate the modified <see cref="TimeMultiplier"/>
/// </summary>
[DataField("partRatingPrintTimeMultiplier")]
public float PartRatingPrintTimeMultiplier = 0.5f;
/// <summary>
/// A modifier that changes how much of a material is needed to print a recipe
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
public float MaterialUseMultiplier = 1;
/// <summary>
/// The machine part that reduces how much material it takes to print a recipe.
/// </summary>
[DataField("machinePartMaterialUse", customTypeSerializer: typeof(PrototypeIdSerializer<MachinePartPrototype>))]
public string MachinePartMaterialUse = "MatterBin";
/// <summary>
/// The value that is used to calculate the modifier <see cref="MaterialUseMultiplier"/>
/// </summary>
[DataField("partRatingMaterialUseMultiplier")]
public float PartRatingMaterialUseMultiplier = 0.75f;
#endregion
}
public sealed class LatheGetRecipesEvent : EntityEventArgs

View file

@ -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<LatheComponent, ComponentGetState>(OnGetState);
SubscribeLocalEvent<LatheComponent, ComponentHandleState>(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;
}
}

View file

@ -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;

View file

@ -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'

View file

@ -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!

View file

@ -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.

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