diff --git a/Content.IntegrationTests/Tests/EntityTest.cs b/Content.IntegrationTests/Tests/EntityTest.cs index d89a66488b..5966446dd4 100644 --- a/Content.IntegrationTests/Tests/EntityTest.cs +++ b/Content.IntegrationTests/Tests/EntityTest.cs @@ -21,6 +21,7 @@ namespace Content.IntegrationTests.Tests public async Task SpawnTest() { //TODO: Run this test in a for loop, and figure out why garbage is ending up in the Entities list on cleanup. + //If this gets fixed, see also UninitializedSaveTest. await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true, Dirty = true, Destructive = true}); var server = pairTracker.Pair.Server; diff --git a/Content.IntegrationTests/Tests/PrototypeSaveTest.cs b/Content.IntegrationTests/Tests/PrototypeSaveTest.cs new file mode 100644 index 0000000000..617d55069d --- /dev/null +++ b/Content.IntegrationTests/Tests/PrototypeSaveTest.cs @@ -0,0 +1,350 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Content.Shared.Coordinates; +using NUnit.Framework; +using Robust.Shared.GameObjects; +using Robust.Shared.IoC; +using Robust.Shared.Map; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.Manager; +using Robust.Shared.Serialization.Markdown; +using Robust.Shared.Serialization.Markdown.Mapping; +using Robust.Shared.Serialization.Markdown.Validation; +using Robust.Shared.Serialization.Markdown.Value; +using Robust.Shared.Serialization.TypeSerializers.Interfaces; + +namespace Content.IntegrationTests.Tests; + +/// +/// This test ensure that when an entity prototype is spawned into an un-initialized map, its component data is not +/// modified during init. I.e., when the entity is saved to the map, its data is simply the default prototype data (ignoring transform component). +/// +/// +/// If you are here becaus your test is failing, one easy way of figuring out how to fix the prototype is to just +/// spawn it into a new empty map and seeing what the map yml looks like. +/// +[TestFixture] +public sealed class PrototypeSaveTest +{ + private readonly HashSet _ignoredPrototypes = new() + { + "Singularity", // physics collision uses "AllMask" (-1). The flag serializer currently fails to save this because this features un-named bits. + "constructionghost", + + // TODO fix more prototypes + // The rest of these prototypes (probably) shouldn't be getting ignored. + // There should be an issue up tracking all of these prototypes, indicating that still need to get fixed. + "C4", + "WeaponProtoKineticAccelerator", + "WeaponStaffHealing", + "WeaponStaffPolymorphDoor", + "WeaponWandPolymorphCarp", + "WeaponWandPolymorphMonkey", + "WeaponWandFireball", + "WeaponWandDeath", + "WeaponWandPolymorphDoor", + "GlowstickBase", + "GlowstickRed", + "GlowstickPurple", + "GlowstickYellow", + "GlowstickBlue", + "Thruster", + "Gyroscope", + "RemoteSignaller", + "filingCabinet", + "filingCabinetTall", + "filingCabinetDrawer", + "WeaponLauncherChinaLake", + "WeaponLauncherRocket", + "WeaponLauncherMultipleRocket", + "Crematorium", + "JawsOfLife", + "SyndicateJawsOfLife", + "LightReplacer", + "ComputerCloningConsole", + "PowerDrill", + "Omnitool", + "GasPressurePump", + "GasVolumePump", + "GasDualPortVentPump", + "PortableScrubber", + "ParticleAcceleratorControlBox", + "GasFilter", + "GasFilterFlipped", + "GasMixer", + "GasMixerFlipped", + "HospitalCurtainsOpen", + "CargoPallet", + "DisposalHolder", + "ParticlesProjectile", + "AMEController", + "AMEControllerUnanchored", + "MopBucket", + "JanitorialTrolley", + "FloorDrain", + "OrganHumanLungs", + "SprayBottle", + "OrganRatLungs", + "SentientSlimeCore", + "OrganSlimeLungs", + "OrganVoxLungs", + "OrganAnimalLungs", + "Floodlight", + "EmergencyMedipen", + "AntiPoisonMedipen", + "SpaceMedipen", + "HolosignWetFloor", + "HeadSkeleton", + "PoweredlightEmpty", + "Poweredlight", + "PoweredlightLED", + "PoweredlightExterior", + "PoweredlightSodium", + "PoweredSmallLightEmpty", + "PoweredSmallLight", + "PoweredLightPostSmallEmpty", + "PoweredLightPostSmall", + "DeployableBarrier", + "CrateArtifactContainer", + "CloningPod", + "DrinkColaCan", + "FoodBowlBig", + "FoodBowlFancy", + "MachineFrame", + "WeaponImprovisedPneumaticCannon", + "LauncherCreamPie", + "GravityGenerator", + "GravityGeneratorMini", + "FoodCondimentPacket", + "FoodCondimentBottle", + "FoodCondimentBottleSmall", + "Autolathe", + "Protolathe", + "CircuitImprinter", + "SecurityTechFab", + "MedicalTechFab", + "UniformPrinter", + "OreProcessor", + "MedicalScanner", + "KitchenMicrowave", + "MagazinePistolSubMachineGunTopMounted", + "Recycler", + "EpinephrineChemistryBottle", + "RobustHarvestChemistryBottle", + "NocturineChemistryBottle", + "EphedrineChemistryBottle", + "OmnizineChemistryBottle", + "Beaker", + "LargeBeaker", + "CryostasisBeaker", + "BluespaceBeaker", + "Syringe", + "ClusterBang", + "ClusterBangFull", + "CargoTelepad", + "ClothingHeadHatHardhatBlue", + "ClothingHeadHatHardhatOrange", + "ClothingHeadHatHardhatRed", + "ClothingHeadHatHardhatWhite", + "ClothingHeadHatHardhatYellow", + "Vaccinator", + "AirlockExternalShuttleLocked", + "AirlockExternalGlassShuttleLocked", + "AirlockExternalGlassShuttleEmergencyLocked", + "ConveyorBelt", + "ClothingHeadHatChef", + "ClothingHeadHelmetFire", + "ClothingHeadHelmetAtmosFire", + "Bucket", + "CableTerminal", + "AirlockShuttle", + "AirlockGlassShuttle" + }; + + [Test] + public async Task UninitializedSaveTest() + { + // Apparently SpawnTest fails to clean up properly. Due to the similarities, I'll assume this also fails. + await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings { NoClient = true, Dirty = true, Destructive = true }); + var server = pairTracker.Pair.Server; + + var mapManager = server.ResolveDependency(); + var entityMan = server.ResolveDependency(); + var prototypeMan = server.ResolveDependency(); + var tileDefinitionManager = server.ResolveDependency(); + var seriMan = server.ResolveDependency(); + var compFact = server.ResolveDependency(); + + var prototypes = new List(); + IMapGrid grid = default!; + EntityUid uid; + MapId mapId = default; + + //Build up test environment + await server.WaitPost(() => + { + // Create a one tile grid to stave off the grid 0 monsters + mapId = mapManager.CreateMap(); + + mapManager.AddUninitializedMap(mapId); + + grid = mapManager.CreateGrid(mapId); + + var tileDefinition = tileDefinitionManager["UnderPlating"]; + var tile = new Tile(tileDefinition.TileId); + var coordinates = grid.ToCoordinates(); + + grid.SetTile(coordinates, tile); + }); + + await server.WaitRunTicks(5); + + //Generate list of non-abstract prototypes to test + foreach (var prototype in prototypeMan.EnumeratePrototypes()) + { + if (prototype.Abstract) + continue; + + // Currently mobs and such can't be serialized, but they aren't flagged as serializable anyways. + if (!prototype.MapSavable) + continue; + + if (_ignoredPrototypes.Contains(prototype.ID)) + continue; + + if (prototype.SetSuffix == "DEBUG") + continue; + + prototypes.Add(prototype); + } + + var context = new TestEntityUidContext(); + + await server.WaitAssertion(() => + { + Assert.That(!mapManager.IsMapInitialized(mapId)); + var testLocation = grid.ToCoordinates(); + + Assert.Multiple(() => + { + //Iterate list of prototypes to spawn + foreach (var prototype in prototypes) + { + uid = entityMan.SpawnEntity(prototype.ID, testLocation); + server.RunTicks(1); + + // get default prototype data + Dictionary protoData = new(); + try + { + foreach (var (compType, comp) in prototype.Components) + { + protoData.Add(compType, seriMan.WriteValueAs(comp.Component.GetType(), comp.Component, context: context)); + } + } + catch (Exception e) + { + Assert.Fail($"Failed to convert prototype {prototype.ID} into yaml. Exception: {e.Message}"); + continue; + } + + var comps = new HashSet(entityMan.GetComponents(uid)); + var compNames = new HashSet(comps.Count); + foreach (var component in comps) + { + var compType = component.GetType(); + var compName = compFact.GetComponentName(compType); + compNames.Add(compName); + + if (compType == typeof(MetaDataComponent) || compType == typeof(TransformComponent)) + continue; + + MappingDataNode compMapping; + try + { + compMapping = seriMan.WriteValueAs(compType, component, context: context); + } + catch (Exception e) + { + Assert.Fail($"Failed to serialize {compName} component of entity prototype {prototype.ID}. Exception: {e.Message}"); + continue; + } + + if (protoData.TryGetValue(compName, out var protoMapping)) + { + var diff = compMapping.Except(protoMapping); + + if (diff != null && diff.Children.Count != 0) + { + var modComps = string.Join(",", diff.Keys.Select(x => x.ToString())); + Assert.Fail($"Prototype {prototype.ID} modifies component on spawn: {compName}. Modified fields: {modComps}"); + } + } + else + { + Assert.Fail($"Prototype {prototype.ID} gains a component on spawn: {compName}"); + } + } + + // An entity may also remove components on init -> check no components are missing. + foreach (var (compType, comp) in prototype.Components) + { + Assert.That(compNames.Contains(compType), $"Prototype {prototype.ID} removes component {compType} on spawn."); + } + + if (!entityMan.Deleted(uid)) + entityMan.DeleteEntity(uid); + } + }); + }); + await pairTracker.CleanReturnAsync(); + } + + private sealed class TestEntityUidContext : ISerializationContext, + ITypeSerializer, + ITypeReaderWriter + { + public Dictionary<(Type, Type), object> TypeReaders { get; } + public Dictionary TypeWriters { get; } + public Dictionary TypeCopiers => TypeWriters; + public Dictionary<(Type, Type), object> TypeValidators => TypeReaders; + + public TestEntityUidContext() + { + TypeReaders = new() { { (typeof(EntityUid), typeof(ValueDataNode)), this } }; + TypeWriters = new() { { typeof(EntityUid), this } }; + } + + ValidationNode ITypeValidator.Validate(ISerializationManager serializationManager, + ValueDataNode node, IDependencyCollection dependencies, ISerializationContext? context) + { + return new ValidatedValueNode(node); + } + + public DataNode Write(ISerializationManager serializationManager, EntityUid value, bool alwaysWrite = false, + ISerializationContext? context = null) + { + // EntityUids should be nullable and have no initial value. + throw new InvalidOperationException("Serializing prototypes should not attempt to write entity Uids"); + } + + EntityUid ITypeReader.Read(ISerializationManager serializationManager, + ValueDataNode node, + IDependencyCollection dependencies, + bool skipHook, + ISerializationContext? context, EntityUid _) + { + return EntityUid.Invalid; + } + + public EntityUid Copy(ISerializationManager serializationManager, EntityUid source, EntityUid target, + bool skipHook, + ISerializationContext? context = null) + { + return new((int) source); + } + } +} diff --git a/Content.Server/Access/Systems/IdCardSystem.cs b/Content.Server/Access/Systems/IdCardSystem.cs index 53b3aef0af..d823376b2b 100644 --- a/Content.Server/Access/Systems/IdCardSystem.cs +++ b/Content.Server/Access/Systems/IdCardSystem.cs @@ -1,7 +1,3 @@ -using Content.Shared.Hands.Components; -using Content.Shared.Inventory; -using System.Diagnostics.CodeAnalysis; -using System.Linq; using Content.Server.Administration.Logs; using Content.Server.Kitchen.Components; using Content.Server.Popups; @@ -9,11 +5,11 @@ using Content.Shared.Access; using Content.Shared.Access.Components; using Content.Shared.Access.Systems; using Content.Shared.Database; -using Content.Shared.PDA; using Content.Shared.Popups; using Robust.Shared.Player; using Robust.Shared.Prototypes; using Robust.Shared.Random; +using System.Linq; namespace Content.Server.Access.Systems { @@ -27,13 +23,15 @@ namespace Content.Server.Access.Systems public override void Initialize() { base.Initialize(); - SubscribeLocalEvent(OnInit); + SubscribeLocalEvent(OnMapInit); SubscribeLocalEvent(OnMicrowaved); } - private void OnInit(EntityUid uid, IdCardComponent id, ComponentInit args) + private void OnMapInit(EntityUid uid, IdCardComponent id, MapInitEvent args) { - id.OriginalOwnerName ??= EntityManager.GetComponent(id.Owner).EntityName; + // On one hand, these prototypes should default to having the correct name. On the other hand, id cards are + // rarely ever spawned in on their own without an owner, so this is fine. + id.OriginalEntityName ??= EntityManager.GetComponent(id.Owner).EntityName; UpdateEntityName(uid, id); } @@ -139,7 +137,7 @@ namespace Content.Server.Access.Systems if (string.IsNullOrWhiteSpace(id.FullName) && string.IsNullOrWhiteSpace(id.JobTitle)) { - EntityManager.GetComponent(id.Owner).EntityName = id.OriginalOwnerName; + EntityManager.GetComponent(id.Owner).EntityName = id.OriginalEntityName; return; } @@ -147,7 +145,7 @@ namespace Content.Server.Access.Systems var val = string.IsNullOrWhiteSpace(id.FullName) ? Loc.GetString("access-id-card-component-owner-name-job-title-text", - ("originalOwnerName", id.OriginalOwnerName), + ("originalOwnerName", id.OriginalEntityName), ("jobSuffix", jobSuffix)) : Loc.GetString("access-id-card-component-owner-full-name-job-title-text", ("fullName", id.FullName), diff --git a/Content.Server/Access/Systems/IdExaminableSystem.cs b/Content.Server/Access/Systems/IdExaminableSystem.cs index d1edc3f199..2966624368 100644 --- a/Content.Server/Access/Systems/IdExaminableSystem.cs +++ b/Content.Server/Access/Systems/IdExaminableSystem.cs @@ -1,4 +1,4 @@ -using Content.Server.Access.Components; +using Content.Server.Access.Components; using Content.Shared.Access.Components; using Content.Shared.Examine; using Content.Shared.Inventory; @@ -66,7 +66,7 @@ public sealed class IdExaminableSystem : EntitySystem var val = string.IsNullOrWhiteSpace(id.FullName) ? Loc.GetString("access-id-card-component-owner-name-job-title-text", - ("originalOwnerName", id.OriginalOwnerName), + ("originalOwnerName", id.OriginalEntityName), ("jobSuffix", jobSuffix)) : Loc.GetString("access-id-card-component-owner-full-name-job-title-text", ("fullName", id.FullName), diff --git a/Content.Server/Body/Components/BodyPartComponent.cs b/Content.Server/Body/Components/BodyPartComponent.cs index 4f465dda05..f9ea0334d3 100644 --- a/Content.Server/Body/Components/BodyPartComponent.cs +++ b/Content.Server/Body/Components/BodyPartComponent.cs @@ -33,11 +33,11 @@ namespace Content.Server.Body.Components mechanism.Owner.RandomOffset(0.25f); } - protected override void Initialize() + public void MapInitialize() { base.Initialize(); - _mechanismContainer = Owner.EnsureContainer($"{Name}-{nameof(BodyPartComponent)}"); + _mechanismContainer = Owner.EnsureContainer(ContainerId); // This is ran in Startup as entities spawned in Initialize // are not synced to the client since they are assumed to be diff --git a/Content.Server/Body/Systems/BodySystem.cs b/Content.Server/Body/Systems/BodySystem.cs index 161b2d27e2..fca8f0d166 100644 --- a/Content.Server/Body/Systems/BodySystem.cs +++ b/Content.Server/Body/Systems/BodySystem.cs @@ -21,6 +21,7 @@ namespace Content.Server.Body.Systems SubscribeLocalEvent(OnRelayMoveInput); SubscribeLocalEvent(OnApplyMetabolicMultiplier); SubscribeLocalEvent(OnBeingMicrowaved); + SubscribeLocalEvent((_, c, _) => c.MapInitialize()); } private void OnRelayMoveInput(EntityUid uid, BodyComponent component, ref MoveInputEvent args) diff --git a/Content.Server/Disposal/Tube/Components/DisposalTubeComponent.cs b/Content.Server/Disposal/Tube/Components/DisposalTubeComponent.cs index ff60c107c7..3692937930 100644 --- a/Content.Server/Disposal/Tube/Components/DisposalTubeComponent.cs +++ b/Content.Server/Disposal/Tube/Components/DisposalTubeComponent.cs @@ -12,6 +12,8 @@ namespace Content.Server.Disposal.Tube.Components { public abstract class DisposalTubeComponent : Component, IDisposalTubeComponent { + public const string ContainerId = "disposal-tube"; + [Dependency] private readonly IEntityManager _entMan = default!; public static readonly TimeSpan ClangDelay = TimeSpan.FromSeconds(0.5); @@ -135,7 +137,7 @@ namespace Content.Server.Disposal.Tube.Components { base.Initialize(); - Contents = ContainerHelpers.EnsureContainer(Owner, Name); + Contents = ContainerHelpers.EnsureContainer(Owner, ContainerId); Owner.EnsureComponent(); } diff --git a/Content.Server/Disposal/Unit/EntitySystems/DisposalUnitSystem.cs b/Content.Server/Disposal/Unit/EntitySystems/DisposalUnitSystem.cs index 5835c0b4e4..25b78ac030 100644 --- a/Content.Server/Disposal/Unit/EntitySystems/DisposalUnitSystem.cs +++ b/Content.Server/Disposal/Unit/EntitySystems/DisposalUnitSystem.cs @@ -46,6 +46,7 @@ namespace Content.Server.Disposal.Unit.EntitySystems [Dependency] private readonly SharedHandsSystem _handsSystem = default!; [Dependency] private readonly DumpableSystem _dumpableSystem = default!; [Dependency] private readonly TransformSystem _transformSystem = default!; + [Dependency] private readonly SharedContainerSystem _containerSystem = default!; private readonly List _activeDisposals = new(); @@ -293,7 +294,7 @@ namespace Content.Server.Disposal.Unit.EntitySystems private void HandleDisposalInit(EntityUid uid, DisposalUnitComponent component, ComponentInit args) { - component.Container = component.Owner.EnsureContainer(component.Name); + component.Container = _containerSystem.EnsureContainer(uid, SharedDisposalUnitComponent.ContainerId); UpdateInterface(component, component.Powered); diff --git a/Content.Server/Mind/Commands/RenameCommand.cs b/Content.Server/Mind/Commands/RenameCommand.cs index 40c989d226..23b20b95f4 100644 --- a/Content.Server/Mind/Commands/RenameCommand.cs +++ b/Content.Server/Mind/Commands/RenameCommand.cs @@ -62,7 +62,7 @@ public sealed class RenameCommand : IConsoleCommand { foreach (var idCardComponent in entMan.EntityQuery()) { - if (idCardComponent.OriginalOwnerName != oldName) + if (idCardComponent.OriginalEntityName != oldName) continue; idCardSystem.TryChangeFullName(idCardComponent.Owner, name, idCardComponent); } diff --git a/Content.Server/Nutrition/EntitySystems/DrinkSystem.cs b/Content.Server/Nutrition/EntitySystems/DrinkSystem.cs index cd8874c1c3..c5e7e655a8 100644 --- a/Content.Server/Nutrition/EntitySystems/DrinkSystem.cs +++ b/Content.Server/Nutrition/EntitySystems/DrinkSystem.cs @@ -182,9 +182,11 @@ namespace Content.Server.Nutrition.EntitySystems UpdateAppearance(component); - // Synchronize solution in drink - EnsureComp(uid).Solution = component.SolutionName; - EnsureComp(uid).Solution = component.SolutionName; + if (TryComp(uid, out RefillableSolutionComponent? refillComp)) + refillComp.Solution = component.SolutionName; + + if (TryComp(uid, out DrainableSolutionComponent? drainComp)) + drainComp.Solution = component.SolutionName; } private void OnSolutionChange(EntityUid uid, DrinkComponent component, SolutionChangedEvent args) diff --git a/Content.Server/Nutrition/EntitySystems/TrashOnEmptySystem.cs b/Content.Server/Nutrition/EntitySystems/TrashOnEmptySystem.cs index b58a2185dd..c0d57244a1 100644 --- a/Content.Server/Nutrition/EntitySystems/TrashOnEmptySystem.cs +++ b/Content.Server/Nutrition/EntitySystems/TrashOnEmptySystem.cs @@ -30,8 +30,6 @@ namespace Content.Server.Nutrition.EntitySystems public void CheckSolutions(TrashOnEmptyComponent component) { - EntityManager.EnsureComponent(component.Owner); - if (!EntityManager.HasComponent((component).Owner)) return; diff --git a/Content.Server/PDA/Ringer/RingerSystem.cs b/Content.Server/PDA/Ringer/RingerSystem.cs index 95d138a9d2..dd4394149b 100644 --- a/Content.Server/PDA/Ringer/RingerSystem.cs +++ b/Content.Server/PDA/Ringer/RingerSystem.cs @@ -18,7 +18,7 @@ namespace Content.Server.PDA.Ringer base.Initialize(); // General Event Subscriptions - SubscribeLocalEvent(RandomizeRingtone); + SubscribeLocalEvent(RandomizeRingtone); // RingerBoundUserInterface Subscriptions SubscribeLocalEvent(OnSetRingtone); SubscribeLocalEvent(RingerPlayRingtone); @@ -46,7 +46,7 @@ namespace Content.Server.PDA.Ringer UpdateRingerRingtone(ringer, args.Ringtone); } - public void RandomizeRingtone(EntityUid uid, RingerComponent ringer, ComponentInit args) + public void RandomizeRingtone(EntityUid uid, RingerComponent ringer, MapInitEvent args) { // Default to using C pentatonic so it at least sounds not terrible. var notes = new[] diff --git a/Content.Server/Storage/EntitySystems/EntityStorageSystem.cs b/Content.Server/Storage/EntitySystems/EntityStorageSystem.cs index 75ca46aa49..221d359f2c 100644 --- a/Content.Server/Storage/EntitySystems/EntityStorageSystem.cs +++ b/Content.Server/Storage/EntitySystems/EntityStorageSystem.cs @@ -50,7 +50,7 @@ public sealed class EntityStorageSystem : EntitySystem component.Contents.OccludesLight = component.OccludesLight; if (TryComp(uid, out var construction)) - _construction.AddContainer(uid, nameof(EntityStorageComponent), construction); + _construction.AddContainer(uid, ContainerName, construction); if (TryComp(uid, out var placeable)) _placeableSurface.SetPlaceable(uid, component.Open, placeable); diff --git a/Content.Server/Storage/EntitySystems/SecretStashSystem.cs b/Content.Server/Storage/EntitySystems/SecretStashSystem.cs index 484cda4d5a..cc82436683 100644 --- a/Content.Server/Storage/EntitySystems/SecretStashSystem.cs +++ b/Content.Server/Storage/EntitySystems/SecretStashSystem.cs @@ -13,6 +13,7 @@ namespace Content.Server.Storage.EntitySystems { [Dependency] private readonly PopupSystem _popupSystem = default!; [Dependency] private readonly SharedHandsSystem _handsSystem = default!; + [Dependency] private readonly SharedContainerSystem _containerSystem = default!; public override void Initialize() { @@ -31,7 +32,7 @@ namespace Content.Server.Storage.EntitySystems component.SecretPartName = entityName; } - component.ItemContainer = ContainerHelpers.EnsureContainer(uid, "stash", out _); + component.ItemContainer = _containerSystem.EnsureContainer(uid, "stash", out _); } private void OnDestroyed(EntityUid uid, SecretStashComponent component, DestructionEventArgs args) diff --git a/Content.Shared/Access/Components/AccessComponent.cs b/Content.Shared/Access/Components/AccessComponent.cs index b063f9b40c..8cd5146ed8 100644 --- a/Content.Shared/Access/Components/AccessComponent.cs +++ b/Content.Shared/Access/Components/AccessComponent.cs @@ -14,7 +14,10 @@ namespace Content.Shared.Access.Components [Access(typeof(AccessSystem), Other = AccessPermissions.ReadExecute)] // FIXME Friends public HashSet Tags = new(); - [DataField("groups", customTypeSerializer: typeof(PrototypeIdHashSetSerializer))] - public HashSet Groups = new(); + /// + /// Access Groups. These are added to the tags during map init. After map init this will have no effect. + /// + [DataField("groups", readOnly: true, customTypeSerializer: typeof(PrototypeIdHashSetSerializer))] + public readonly HashSet Groups = new(); } } diff --git a/Content.Shared/Access/Components/IdCardComponent.cs b/Content.Shared/Access/Components/IdCardComponent.cs index 43395a7a5c..f63504e157 100644 --- a/Content.Shared/Access/Components/IdCardComponent.cs +++ b/Content.Shared/Access/Components/IdCardComponent.cs @@ -9,8 +9,8 @@ namespace Content.Shared.Access.Components [Access(typeof(SharedIdCardSystem), typeof(SharedPDASystem), typeof(SharedAgentIdCardSystem))] public sealed class IdCardComponent : Component { - [DataField("originalOwnerName")] - public string OriginalOwnerName = default!; + [DataField("originalEntityName")] + public string OriginalEntityName = string.Empty; [DataField("fullName")] [Access(typeof(SharedIdCardSystem), typeof(SharedPDASystem), typeof(SharedAgentIdCardSystem), diff --git a/Content.Shared/Access/Systems/AccessSystem.cs b/Content.Shared/Access/Systems/AccessSystem.cs index c1b2f02317..56e2fcc031 100644 --- a/Content.Shared/Access/Systems/AccessSystem.cs +++ b/Content.Shared/Access/Systems/AccessSystem.cs @@ -12,10 +12,10 @@ namespace Content.Shared.Access.Systems { base.Initialize(); - SubscribeLocalEvent(OnAccessInit); + SubscribeLocalEvent(OnAccessInit); } - private void OnAccessInit(EntityUid uid, AccessComponent component, ComponentInit args) + private void OnAccessInit(EntityUid uid, AccessComponent component, MapInitEvent args) { // Add all tags in groups to the list of tags. foreach (var group in component.Groups) diff --git a/Content.Shared/Body/Components/SharedBodyPartComponent.cs b/Content.Shared/Body/Components/SharedBodyPartComponent.cs index 6d8e360858..5f2b790779 100644 --- a/Content.Shared/Body/Components/SharedBodyPartComponent.cs +++ b/Content.Shared/Body/Components/SharedBodyPartComponent.cs @@ -11,6 +11,8 @@ namespace Content.Shared.Body.Components [NetworkedComponent()] public abstract class SharedBodyPartComponent : Component { + public const string ContainerId = "bodypart"; + [Dependency] private readonly IEntityManager _entMan = default!; private SharedBodyComponent? _body; diff --git a/Content.Shared/Disposal/Components/SharedDisposalUnitComponent.cs b/Content.Shared/Disposal/Components/SharedDisposalUnitComponent.cs index b93c15dcab..493c705d2b 100644 --- a/Content.Shared/Disposal/Components/SharedDisposalUnitComponent.cs +++ b/Content.Shared/Disposal/Components/SharedDisposalUnitComponent.cs @@ -6,6 +6,8 @@ namespace Content.Shared.Disposal.Components [NetworkedComponent] public abstract class SharedDisposalUnitComponent : Component { + public const string ContainerId = "disposal-unit"; + // TODO: Could maybe turn the contact off instead far more cheaply as farseer (though not box2d) had support for it? // Need to suss it out. /// diff --git a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Ballistic.cs b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Ballistic.cs index 56d89a048e..5bc7cf9d5d 100644 --- a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Ballistic.cs +++ b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Ballistic.cs @@ -16,6 +16,7 @@ public abstract partial class SharedGunSystem protected virtual void InitializeBallistic() { SubscribeLocalEvent(OnBallisticInit); + SubscribeLocalEvent(OnBallisticMapInit); SubscribeLocalEvent(OnBallisticTakeAmmo); SubscribeLocalEvent(OnBallisticAmmoCount); SubscribeLocalEvent(OnBallisticGetState); @@ -122,16 +123,12 @@ public abstract partial class SharedGunSystem private void OnBallisticInit(EntityUid uid, BallisticAmmoProviderComponent component, ComponentInit args) { component.Container = Containers.EnsureContainer(uid, "ballistic-ammo"); - component.UnspawnedCount = component.Capacity; + } + private void OnBallisticMapInit(EntityUid uid, BallisticAmmoProviderComponent component, MapInitEvent args) + { if (component.FillProto != null) - { component.UnspawnedCount -= Math.Min(component.UnspawnedCount, component.Container.ContainedEntities.Count); - } - else - { - component.UnspawnedCount = 0; - } } protected int GetBallisticShots(BallisticAmmoProviderComponent component) diff --git a/Resources/Prototypes/Body/Parts/animal.yml b/Resources/Prototypes/Body/Parts/animal.yml index 422736cda8..c2aa321d64 100644 --- a/Resources/Prototypes/Body/Parts/animal.yml +++ b/Resources/Prototypes/Body/Parts/animal.yml @@ -10,6 +10,11 @@ components: - type: Damageable damageContainer: Biological + - type: BodyPart + - type: ContainerContainer + containers: + bodypart: !type:Container + ents: [] # For primates mainly - type: entity diff --git a/Resources/Prototypes/Body/Parts/human.yml b/Resources/Prototypes/Body/Parts/human.yml index 689a104e8a..874b306a4e 100644 --- a/Resources/Prototypes/Body/Parts/human.yml +++ b/Resources/Prototypes/Body/Parts/human.yml @@ -8,6 +8,11 @@ components: - type: Damageable damageContainer: Biological + - type: BodyPart + - type: ContainerContainer + containers: + bodypart: !type:Container + ents: [] - type: entity id: TorsoHuman diff --git a/Resources/Prototypes/Body/Parts/reptilian.yml b/Resources/Prototypes/Body/Parts/reptilian.yml index 1f2183a48d..709bd71ac8 100644 --- a/Resources/Prototypes/Body/Parts/reptilian.yml +++ b/Resources/Prototypes/Body/Parts/reptilian.yml @@ -8,6 +8,11 @@ components: - type: Damageable damageContainer: Biological + - type: BodyPart + - type: ContainerContainer + containers: + bodypart: !type:Container + ents: [] - type: entity id: TorsoReptilian diff --git a/Resources/Prototypes/Body/Parts/silicon.yml b/Resources/Prototypes/Body/Parts/silicon.yml index 581634f985..05eb122dbd 100644 --- a/Resources/Prototypes/Body/Parts/silicon.yml +++ b/Resources/Prototypes/Body/Parts/silicon.yml @@ -6,6 +6,11 @@ components: - type: Damageable damageContainer: Inorganic + - type: BodyPart + - type: ContainerContainer + containers: + bodypart: !type:Container + ents: [] - type: entity id: LeftArmBorg diff --git a/Resources/Prototypes/Body/Parts/skeleton.yml b/Resources/Prototypes/Body/Parts/skeleton.yml index b4e9d2e8a7..9494f6b5c6 100644 --- a/Resources/Prototypes/Body/Parts/skeleton.yml +++ b/Resources/Prototypes/Body/Parts/skeleton.yml @@ -7,6 +7,11 @@ components: - type: Damageable damageContainer: Biological + - type: BodyPart + - type: ContainerContainer + containers: + bodypart: !type:Container + ents: [] - type: entity id: TorsoSkeleton diff --git a/Resources/Prototypes/Body/Parts/slime.yml b/Resources/Prototypes/Body/Parts/slime.yml index 53c8196165..9c3c11747a 100644 --- a/Resources/Prototypes/Body/Parts/slime.yml +++ b/Resources/Prototypes/Body/Parts/slime.yml @@ -7,6 +7,11 @@ components: - type: Damageable damageContainer: Biological + - type: BodyPart + - type: ContainerContainer + containers: + bodypart: !type:Container + ents: [] - type: entity id: TorsoSlime diff --git a/Resources/Prototypes/Body/Parts/vox.yml b/Resources/Prototypes/Body/Parts/vox.yml index e54dbf715f..5bbd4e15fb 100644 --- a/Resources/Prototypes/Body/Parts/vox.yml +++ b/Resources/Prototypes/Body/Parts/vox.yml @@ -8,6 +8,11 @@ components: - type: Damageable damageContainer: Biological + - type: BodyPart + - type: ContainerContainer + containers: + bodypart: !type:Container + ents: [] - type: entity id: TorsoVox diff --git a/Resources/Prototypes/Catalog/Fills/Boxes/ammunition.yml b/Resources/Prototypes/Catalog/Fills/Boxes/ammunition.yml index c1fc8ee73b..9e9cc16cc0 100644 --- a/Resources/Prototypes/Catalog/Fills/Boxes/ammunition.yml +++ b/Resources/Prototypes/Catalog/Fills/Boxes/ammunition.yml @@ -367,10 +367,22 @@ - id: MagazineShotgunIncendiary amount: 6 +# base BallisticAmmoProvider boxes +- type: entity + parent: BoxCardboard + id: BoxAmmoProvider + abstract: true + components: + - type: BallisticAmmoProvider + - type: ContainerContainer + containers: + ballistic-ammo: !type:Container + storagebase: !type:Container + # Shotgun Shells - type: entity name: box of shotgun beanbag cartridges - parent: BoxCardboard + parent: BoxAmmoProvider id: BoxBeanbag description: A box full of beanbag shots, designed for riot shotguns. components: @@ -384,7 +396,7 @@ - type: entity name: box of shotgun lethal cartridges - parent: BoxCardboard + parent: BoxAmmoProvider id: BoxLethalshot description: A box full of lethal pellet shots, designed for riot shotguns. components: @@ -398,7 +410,7 @@ - type: entity name: box of shotgun slug cartridges - parent: BoxCardboard + parent: BoxAmmoProvider id: BoxShotgunSlug description: A box full of shotgun slugs, designed for riot shotguns. components: @@ -412,7 +424,7 @@ - type: entity name: box of shotgun flare cartridges - parent: BoxCardboard + parent: BoxAmmoProvider id: BoxShotgunFlare description: A box full of shotgun flare cartridges, designed for riot shotguns. components: @@ -426,7 +438,7 @@ - type: entity name: box of shotgun incendiary cartridges - parent: BoxCardboard + parent: BoxAmmoProvider id: BoxShotgunIncendiary description: A box full of shotgun incendiary cartridges, designed for riot shotguns. components: @@ -440,7 +452,7 @@ - type: entity name: box of shotgun practice cartridges - parent: BoxCardboard + parent: BoxAmmoProvider id: BoxShotgunPractice description: A box full of shotgun practice cartridges, designed for riot shotguns. components: @@ -454,7 +466,7 @@ - type: entity name: box of tranquilizer cartridges - parent: BoxCardboard + parent: BoxAmmoProvider id: BoxShellTranquilizer description: A box full of tranquilizer cartridges, designed for riot shotguns. components: diff --git a/Resources/Prototypes/Entities/Clothing/Back/backpacks.yml b/Resources/Prototypes/Entities/Clothing/Back/backpacks.yml index 0ca1cb8d9a..335a994a3a 100644 --- a/Resources/Prototypes/Entities/Clothing/Back/backpacks.yml +++ b/Resources/Prototypes/Entities/Clothing/Back/backpacks.yml @@ -15,6 +15,10 @@ - back - type: Storage capacity: 100 + - type: ContainerContainer + containers: + storagebase: !type:Container + ents: [] - type: UserInterface interfaces: - key: enum.StorageUiKey.Key diff --git a/Resources/Prototypes/Entities/Clothing/Back/duffel.yml b/Resources/Prototypes/Entities/Clothing/Back/duffel.yml index 04c44d319f..17d09be0f7 100644 --- a/Resources/Prototypes/Entities/Clothing/Back/duffel.yml +++ b/Resources/Prototypes/Entities/Clothing/Back/duffel.yml @@ -15,6 +15,10 @@ - back - type: Storage capacity: 120 + - type: ContainerContainer + containers: + storagebase: !type:Container + ents: [] - type: ClothingSpeedModifier walkModifier: 1 sprintModifier: 0.9 diff --git a/Resources/Prototypes/Entities/Clothing/Back/satchel.yml b/Resources/Prototypes/Entities/Clothing/Back/satchel.yml index c3c665ca31..5abef34c03 100644 --- a/Resources/Prototypes/Entities/Clothing/Back/satchel.yml +++ b/Resources/Prototypes/Entities/Clothing/Back/satchel.yml @@ -15,6 +15,10 @@ - back - type: Storage capacity: 100 + - type: ContainerContainer + containers: + storagebase: !type:Container + ents: [] - type: UserInterface interfaces: - key: enum.StorageUiKey.Key diff --git a/Resources/Prototypes/Entities/Clothing/Belt/base_clothingbelt.yml b/Resources/Prototypes/Entities/Clothing/Belt/base_clothingbelt.yml index cefc20503d..d23807a1fa 100644 --- a/Resources/Prototypes/Entities/Clothing/Belt/base_clothingbelt.yml +++ b/Resources/Prototypes/Entities/Clothing/Belt/base_clothingbelt.yml @@ -20,6 +20,10 @@ capacity: 40 equipSound: path: /Audio/Items/belt_equip.ogg + - type: ContainerContainer + containers: + storagebase: !type:Container + ents: [] - type: UserInterface interfaces: - key: enum.StorageUiKey.Key diff --git a/Resources/Prototypes/Entities/Clothing/Head/helmets.yml b/Resources/Prototypes/Entities/Clothing/Head/helmets.yml index 4371b826c2..e35486c745 100644 --- a/Resources/Prototypes/Entities/Clothing/Head/helmets.yml +++ b/Resources/Prototypes/Entities/Clothing/Head/helmets.yml @@ -221,6 +221,10 @@ Heat: 0.65 Radiation: 1 - type: IdentityBlocker + - type: ItemSlots + - type: ContainerContainer + containers: + cell_slot: !type:ContainerSlot {} - type: entity parent: ClothingHeadLightBase diff --git a/Resources/Prototypes/Entities/Clothing/OuterClothing/base_clothingouter.yml b/Resources/Prototypes/Entities/Clothing/OuterClothing/base_clothingouter.yml index 75d860235d..a577a9168a 100644 --- a/Resources/Prototypes/Entities/Clothing/OuterClothing/base_clothingouter.yml +++ b/Resources/Prototypes/Entities/Clothing/OuterClothing/base_clothingouter.yml @@ -30,6 +30,10 @@ components: - type: Storage capacity: 10 + - type: ContainerContainer + containers: + storagebase: !type:Container + ents: [] - type: UserInterface interfaces: - key: enum.StorageUiKey.Key @@ -62,6 +66,9 @@ - type: DiseaseProtection protection: 0.05 - type: ToggleableClothing + - type: ContainerContainer + containers: + toggleable-clothing: !type:ContainerSlot {} - type: entity abstract: true diff --git a/Resources/Prototypes/Entities/Clothing/OuterClothing/suits.yml b/Resources/Prototypes/Entities/Clothing/OuterClothing/suits.yml index 23c6a60be1..e80338f302 100644 --- a/Resources/Prototypes/Entities/Clothing/OuterClothing/suits.yml +++ b/Resources/Prototypes/Entities/Clothing/OuterClothing/suits.yml @@ -35,6 +35,9 @@ coefficient: 0.5 - type: ToggleableClothing clothingPrototype: ClothingHeadHelmetEVA + - type: ContainerContainer + containers: + toggleable-clothing: !type:ContainerSlot {} - type: entity parent: ClothingOuterBaseLarge diff --git a/Resources/Prototypes/Entities/Effects/puddle.yml b/Resources/Prototypes/Entities/Effects/puddle.yml index a24b5534b5..d790eeea42 100644 --- a/Resources/Prototypes/Entities/Effects/puddle.yml +++ b/Resources/Prototypes/Entities/Effects/puddle.yml @@ -8,6 +8,8 @@ - type: Sprite drawdepth: FloorObjects - type: SolutionContainerManager + solutions: + puddle: {} - type: Puddle spillSound: path: /Audio/Effects/Fluids/splat.ogg diff --git a/Resources/Prototypes/Entities/Markers/Spawners/Conditional/timed.yml b/Resources/Prototypes/Entities/Markers/Spawners/Conditional/timed.yml index 3c1de0b395..28cec0607f 100644 --- a/Resources/Prototypes/Entities/Markers/Spawners/Conditional/timed.yml +++ b/Resources/Prototypes/Entities/Markers/Spawners/Conditional/timed.yml @@ -8,6 +8,7 @@ - state: blue - texture: Mobs/Species/Human/parts.rsi/full.png - state: ai + - type: Timer - type: TimedSpawner prototypes: - MobSpirate @@ -27,6 +28,7 @@ - state: blue - texture: Mobs/Aliens/Xenos/burrower.rsi/crit.png - state: ai + - type: Timer - type: TimedSpawner prototypes: - MobXeno @@ -45,6 +47,7 @@ - state: blue - texture: Mobs/Animals/mouse.rsi/icon-2.png - state: timed + - type: Timer - type: TimedSpawner prototypes: - MobMouse diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/human.yml b/Resources/Prototypes/Entities/Mobs/NPCs/human.yml index db902e3921..9bfbf528e2 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/human.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/human.yml @@ -51,7 +51,7 @@ - type: entity parent: BaseMobHuman suffix: Dead - save: true + save: false # mobs are currently not saveable. id: SalvageHumanCorpse name: unidentified human description: We barely knew ye. diff --git a/Resources/Prototypes/Entities/Mobs/Player/guardian.yml b/Resources/Prototypes/Entities/Mobs/Player/guardian.yml index db46da8d3e..5ef64f67cb 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/guardian.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/guardian.yml @@ -4,6 +4,7 @@ name: GuardianBase id: MobGuardianBase description: guardian + save: false components: - type: GhostTakeoverAvailable makeSentient: true diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks.yml b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks.yml index 62f709fa79..780edc5391 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks.yml @@ -22,6 +22,8 @@ solution: drink - type: RefillableSolution solution: drink + - type: DrainableSolution + solution: drink - type: UserInterface interfaces: - key: enum.TransferAmountUiKey.Key diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_cans.yml b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_cans.yml index e4d1663d87..0665c6dc56 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_cans.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_cans.yml @@ -27,6 +27,12 @@ - state: icon map: ["enum.DrinkCanVisualLayers.Icon"] netsync: false + - type: FitsInDispenser + solution: drink + - type: DrawableSolution + solution: drink + - type: RefillableSolution + solution: drink - type: DrainableSolution solution: drink - type: Appearance diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_cups.yml b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_cups.yml index 187e83f14c..6ddcfee053 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_cups.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_cups.yml @@ -15,6 +15,8 @@ solution: drink - type: RefillableSolution solution: drink + - type: DrainableSolution + solution: drink - type: SolutionTransfer canChangeTransferAmount: true maxTransferAmount: 10 diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_special.yml b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_special.yml index 56744e95c7..a7c6e1098f 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_special.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_special.yml @@ -16,6 +16,8 @@ solution: drink - type: RefillableSolution solution: drink + - type: DrainableSolution + solution: drink - type: SolutionTransfer canChangeTransferAmount: true - type: Spillable diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/trash_drinks.yml b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/trash_drinks.yml index 4992feed90..010bb73504 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/trash_drinks.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/trash_drinks.yml @@ -19,6 +19,14 @@ isOpen: true - type: Spillable solution: drink + - type: FitsInDispenser + solution: drink + - type: DrawableSolution + solution: drink + - type: RefillableSolution + solution: drink + - type: DrainableSolution + solution: drink - type: UserInterface interfaces: - key: enum.TransferAmountUiKey.Key diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/condiments.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/condiments.yml index 100c6a0a2c..2eca61dda2 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/condiments.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/condiments.yml @@ -11,6 +11,7 @@ components: - type: Drink solution: food + refillable: false openSounds: collection: packetOpenSounds - type: DrawableSolution @@ -19,7 +20,9 @@ solution: food - type: DrainableSolution solution: food - # Note NOT refillable + # Note NOT refillable. + # It be a shame if it turned out ALL drinks were ALWAYS refillable.... ffs. + # Well its fixed now, but I want to share my pain. - type: SolutionContainerManager solutions: food: @@ -331,6 +334,10 @@ solution: food openSounds: collection: pop + - type: RefillableSolution + solution: food + - type: DrainableSolution + solution: food - type: SolutionContainerManager solutions: food: @@ -478,6 +485,10 @@ solution: food openSounds: collection: pop + - type: RefillableSolution + solution: food + - type: DrainableSolution + solution: food - type: SolutionContainerManager solutions: food: diff --git a/Resources/Prototypes/Entities/Objects/Devices/holoprojectors.yml b/Resources/Prototypes/Entities/Objects/Devices/holoprojectors.yml index 1bfa5164dc..e99c0d00d7 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/holoprojectors.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/holoprojectors.yml @@ -8,6 +8,10 @@ - type: ItemCooldown - type: UseDelay delay: 1.0 + - type: ItemSlots + - type: ContainerContainer + containers: + cell_slot: !type:ContainerSlot {} - type: PowerCellSlot cellSlot: startingItem: PowerCellMedium diff --git a/Resources/Prototypes/Entities/Objects/Devices/nuke.yml b/Resources/Prototypes/Entities/Objects/Devices/nuke.yml index c1a04d0599..4be867b7be 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/nuke.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/nuke.yml @@ -48,6 +48,10 @@ - type: StaticPrice price: 50000 # YOU STOLE A NUCLEAR FISSION EXPLOSIVE?! - type: CargoSellBlacklist + - type: ItemSlots + - type: ContainerContainer + containers: + Nuke: !type:ContainerSlot - type: entity parent: NuclearBomb diff --git a/Resources/Prototypes/Entities/Objects/Devices/payload.yml b/Resources/Prototypes/Entities/Objects/Devices/payload.yml index 86575c8563..fce48952e0 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/payload.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/payload.yml @@ -76,6 +76,11 @@ enum.ChemicalPayloadFilledSlots.Left: payload-chemical-left enum.ChemicalPayloadFilledSlots.Right: payload-chemical-right enum.ChemicalPayloadFilledSlots.Both: payload-chemical-armed + - type: ItemSlots + - type: ContainerContainer + containers: + BeakerSlotA: !type:ContainerSlot + BeakerSlotB: !type:ContainerSlot - type: entity name: flash payload diff --git a/Resources/Prototypes/Entities/Objects/Devices/pda.yml b/Resources/Prototypes/Entities/Objects/Devices/pda.yml index 24166704f0..375f57b865 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/pda.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/pda.yml @@ -17,6 +17,11 @@ state: pda - type: Item size: 10 + - type: ContainerContainer + containers: + PDA-id: !type:ContainerSlot {} + PDA-pen: !type:ContainerSlot {} + - type: ItemSlots - type: Clothing quickEquip: false slots: diff --git a/Resources/Prototypes/Entities/Objects/Fun/Instruments/instruments_structures.yml b/Resources/Prototypes/Entities/Objects/Fun/Instruments/instruments_structures.yml index 3f35f6945a..4dd0956442 100644 --- a/Resources/Prototypes/Entities/Objects/Fun/Instruments/instruments_structures.yml +++ b/Resources/Prototypes/Entities/Objects/Fun/Instruments/instruments_structures.yml @@ -147,7 +147,7 @@ state: toms - type: entity - parent: BasePlaceableInstrument + parent: [ BasePlaceableInstrument, ConstructibleMachine] id: DawInstrument name: digital audio workstation description: Cutting edge music technology, straight from the 90s. @@ -161,9 +161,6 @@ map: ["enum.WiresVisualLayers.MaintenancePanel"] - type: Appearance - type: WiresVisuals - - type: Construction - graph: Machine - node: machine - type: Wires BoardName: "DawInstrument" LayoutId: DawInstrument diff --git a/Resources/Prototypes/Entities/Objects/Fun/toys.yml b/Resources/Prototypes/Entities/Objects/Fun/toys.yml index d1ea5e30c1..7bded8bbbf 100644 --- a/Resources/Prototypes/Entities/Objects/Fun/toys.yml +++ b/Resources/Prototypes/Entities/Objects/Fun/toys.yml @@ -491,6 +491,10 @@ capacity: 1 soundInsert: path: /Audio/Weapons/drawbow2.ogg + - type: ContainerContainer + containers: + ballistic-ammo: !type:Container + ents: [] - type: entity parent: BaseItem @@ -530,6 +534,10 @@ autoCycle: true soundInsert: path: /Audio/Weapons/Guns/MagIn/revolver_magin.ogg + - type: ContainerContainer + containers: + ballistic-ammo: !type:Container + ents: [] - type: entity parent: BaseItem diff --git a/Resources/Prototypes/Entities/Objects/Misc/box.yml b/Resources/Prototypes/Entities/Objects/Misc/box.yml index 42f17b3509..0e654d8ae9 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/box.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/box.yml @@ -12,3 +12,6 @@ - type: Storage capacity: 30 size: 10 + - type: ContainerContainer + containers: + storagebase: !type:Container diff --git a/Resources/Prototypes/Entities/Objects/Misc/fluff_lights.yml b/Resources/Prototypes/Entities/Objects/Misc/fluff_lights.yml index 47bfb9f0d0..222e1d6607 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/fluff_lights.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/fluff_lights.yml @@ -7,6 +7,7 @@ - type: HandheldLight addPrefix: true - type: PowerCellSlot + - type: ItemSlots - type: ContainerContainer containers: cell_slot: !type:ContainerSlot @@ -16,6 +17,7 @@ - type: Item sprite: Objects/Misc/Lights/lights.rsi size: 20 + heldPrefix: off - type: PointLight netsync: false enabled: false diff --git a/Resources/Prototypes/Entities/Objects/Specific/Medical/morgue.yml b/Resources/Prototypes/Entities/Objects/Specific/Medical/morgue.yml index 4d76dbdd3b..d9232130c1 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Medical/morgue.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Medical/morgue.yml @@ -67,6 +67,11 @@ False: {visible: false} - type: Pullable - type: AntiRottingContainer + - type: ItemSlots + - type: ContainerContainer + containers: + entity_storage: !type:Container + paper_label: !type:ContainerSlot - type: entity id: BodyBag_Folded diff --git a/Resources/Prototypes/Entities/Objects/Specific/Xenoarchaeology/artifact_equipment.yml b/Resources/Prototypes/Entities/Objects/Specific/Xenoarchaeology/artifact_equipment.yml index c448d6c7a2..5480298774 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Xenoarchaeology/artifact_equipment.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Xenoarchaeology/artifact_equipment.yml @@ -67,3 +67,8 @@ - type: StorageVisualizer state_open: artifact_container_open state_closed: artifact_container_door + - type: ItemSlots + - type: ContainerContainer + containers: + entity_storage: !type:Container + paper_label: !type:ContainerSlot diff --git a/Resources/Prototypes/Entities/Objects/Tools/flashlights.yml b/Resources/Prototypes/Entities/Objects/Tools/flashlights.yml index bb436edf6c..c19d3b631c 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/flashlights.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/flashlights.yml @@ -31,6 +31,7 @@ - type: ContainerContainer containers: cell_slot: !type:ContainerSlot + - type: ItemSlots - type: Sprite sprite: Objects/Tools/flashlight.rsi netsync: false diff --git a/Resources/Prototypes/Entities/Objects/Tools/lantern.yml b/Resources/Prototypes/Entities/Objects/Tools/lantern.yml index fb8e4e4d37..94b6711b3b 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/lantern.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/lantern.yml @@ -30,6 +30,10 @@ - type: PowerCellSlot cellSlot: startingItem: PowerCellMedium + - type: ItemSlots + - type: ContainerContainer + containers: + cell_slot: !type:ContainerSlot {} - type: entity name: extra-bright lantern diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Boxes/antimaterial.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Boxes/antimaterial.yml index bc01ce9637..ce891be9a9 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Boxes/antimaterial.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Boxes/antimaterial.yml @@ -19,3 +19,7 @@ steps: 2 zeroVisible: false - type: Appearance + - type: ContainerContainer + containers: + ballistic-ammo: !type:Container + ents: [] diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Boxes/toy.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Boxes/toy.yml index 39904580fa..5678975927 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Boxes/toy.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Boxes/toy.yml @@ -11,6 +11,10 @@ capacity: 30 - type: Sprite netsync: false + - type: ContainerContainer + containers: + ballistic-ammo: !type:Container + ents: [] # Boxes - type: entity diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/SpeedLoaders/magnum.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/SpeedLoaders/magnum.yml index 2dfe35663e..89e915f376 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/SpeedLoaders/magnum.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/SpeedLoaders/magnum.yml @@ -11,6 +11,10 @@ capacity: 6 - type: Sprite netsync: false + - type: ContainerContainer + containers: + ballistic-ammo: !type:Container + ents: [] - type: entity id: SpeedLoaderMagnum diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/SpeedLoaders/pistol.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/SpeedLoaders/pistol.yml index 4fb7b912c9..8e3841ad8c 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/SpeedLoaders/pistol.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/SpeedLoaders/pistol.yml @@ -12,6 +12,10 @@ - type: Sprite netsync: false sprite: Objects/Weapons/Guns/Ammunition/SpeedLoaders/Pistol/pistol_speed_loader.rsi + - type: ContainerContainer + containers: + ballistic-ammo: !type:Container + ents: [] - type: entity id: SpeedLoaderPistol diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/SpeedLoaders/rifle_light.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/SpeedLoaders/rifle_light.yml index e3bfbc35e7..846c79da90 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/SpeedLoaders/rifle_light.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/SpeedLoaders/rifle_light.yml @@ -22,3 +22,7 @@ steps: 6 zeroVisible: false - type: Appearance + - type: ContainerContainer + containers: + ballistic-ammo: !type:Container + ents: [] diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/SpeedLoaders/toy.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/SpeedLoaders/toy.yml index a505992d06..e6fb23a304 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/SpeedLoaders/toy.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/SpeedLoaders/toy.yml @@ -21,6 +21,10 @@ steps: 7 zeroVisible: false - type: Appearance + - type: ContainerContainer + containers: + ballistic-ammo: !type:Container + ents: [] - type: entity id: SpeedLoaderCap diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/HMGs/hmgs.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/HMGs/hmgs.yml index 6a40806850..957aa63004 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/HMGs/hmgs.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/HMGs/hmgs.yml @@ -44,3 +44,7 @@ steps: 4 zeroVisible: true - type: Appearance + - type: ContainerContainer + containers: + ballistic-ammo: !type:Container + ents: [] diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/projectiles.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/projectiles.yml index fc26a02171..f00aa20d92 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/projectiles.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/projectiles.yml @@ -37,14 +37,24 @@ angularDamping: 0 - type: Fixtures fixtures: - - shape: + - id: projectile + shape: !type:PhysShapeAabb bounds: "-0.1,-0.1,0.1,0.1" hard: false - id: projectile mask: - Impassable - BulletImpassable + - &flybyfixture + id: fly-by + shape: !type:PhysShapeCircle + radius: 1.5 + layer: + - Impassable + - MidImpassable + - HighImpassable + - LowImpassable + hard: False - type: Projectile impactEffect: BulletImpactEffect damage: @@ -76,6 +86,7 @@ mask: - Impassable - BulletImpassable + - *flybyfixture - type: entity id: BaseBulletHighVelocity @@ -142,6 +153,7 @@ mask: - Impassable - BulletImpassable + - *flybyfixture - type: Ammo - type: StaminaDamageOnCollide damage: 30 @@ -178,6 +190,7 @@ mask: - Impassable - Opaque + - *flybyfixture - type: Projectile # soundHit: Waiting on serv3 damage: diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Revolvers/revolvers.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Revolvers/revolvers.yml index a33e5b5011..5418ecb364 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Revolvers/revolvers.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Revolvers/revolvers.yml @@ -17,12 +17,17 @@ - SemiAuto soundGunshot: path: /Audio/Weapons/Guns/Gunshots/revolver.ogg + - type: ContainerContainer + containers: + revolver-ammo: !type:Container - type: RevolverAmmoProvider whitelist: tags: - CartridgeMagnum proto: CartridgeMagnum capacity: 7 + chambers: [ True, True, True, True, True, True, True ] + ammoSlots: [ null, null, null, null, null, null, null ] soundEject: path: /Audio/Weapons/Guns/MagOut/revolver_magout.ogg soundInsert: @@ -46,6 +51,8 @@ sprite: Objects/Weapons/Guns/Revolvers/deckard.rsi - type: RevolverAmmoProvider capacity: 5 + chambers: [ True, True, True, True, True ] + ammoSlots: [ null, null, null, null, null ] - type: MagazineVisuals magState: mag steps: 4 @@ -64,6 +71,8 @@ sprite: Objects/Weapons/Guns/Revolvers/inspector.rsi - type: RevolverAmmoProvider capacity: 6 + chambers: [ True, True, True, True, True, True ] + ammoSlots: [ null, null, null, null, null, null ] - type: entity name: Mateba @@ -75,8 +84,6 @@ sprite: Objects/Weapons/Guns/Revolvers/mateba.rsi - type: Item sprite: Objects/Weapons/Guns/Revolvers/mateba.rsi - - type: RevolverAmmoProvider - capacity: 7 - type: Gun soundGunshot: path: /Audio/Weapons/Guns/Gunshots/mateba.ogg @@ -104,5 +111,10 @@ sprite: Objects/Weapons/Guns/Revolvers/pirate_revolver.rsi - type: Gun fireRate: 1 + - type: ContainerContainer + containers: + revolver-ammo: !type:Container - type: RevolverAmmoProvider capacity: 5 + chambers: [ True, True, True, True, True ] + ammoSlots: [ null, null, null, null, null ] diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Shotguns/shotguns.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Shotguns/shotguns.yml index 4b73e00fd4..a37916deb8 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Shotguns/shotguns.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Shotguns/shotguns.yml @@ -31,6 +31,10 @@ proto: ShellShotgun soundInsert: path: /Audio/Weapons/Guns/MagIn/shotgun_insert.ogg + - type: ContainerContainer + containers: + ballistic-ammo: !type:Container + ents: [] - type: entity name: Bulldog diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Snipers/snipers.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Snipers/snipers.yml index 7bc77a499e..6baa1e83cd 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Snipers/snipers.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Snipers/snipers.yml @@ -27,6 +27,10 @@ whitelist: tags: - CartridgeLightRifle + - type: ContainerContainer + containers: + ballistic-ammo: !type:Container + ents: [] - type: entity name: Kardashev-Mosin diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/flare_gun.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/flare_gun.yml index 8be9fef539..c08ab11d42 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/flare_gun.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/flare_gun.yml @@ -27,3 +27,7 @@ capacity: 1 soundInsert: path: /Audio/Weapons/Guns/MagIn/shotgun_insert.ogg + - type: ContainerContainer + containers: + ballistic-ammo: !type:Container + ents: [] diff --git a/Resources/Prototypes/Entities/Objects/base_item.yml b/Resources/Prototypes/Entities/Objects/base_item.yml index 5e90746d13..71372ab368 100644 --- a/Resources/Prototypes/Entities/Objects/base_item.yml +++ b/Resources/Prototypes/Entities/Objects/base_item.yml @@ -22,6 +22,7 @@ - type: Physics bodyType: Dynamic fixedRotation: false + canCollide: false # most entities start asleep. - type: Fixtures fixtures: - shape: @@ -48,4 +49,8 @@ interfaces: - key: enum.StorageUiKey.Key type: StorageBoundUserInterface + - type: ContainerContainer + containers: + storagebase: !type:Container + ents: [] diff --git a/Resources/Prototypes/Entities/Structures/Dispensers/base_structuredispensers.yml b/Resources/Prototypes/Entities/Structures/Dispensers/base_structuredispensers.yml index a4840f2fa6..c2855fb121 100644 --- a/Resources/Prototypes/Entities/Structures/Dispensers/base_structuredispensers.yml +++ b/Resources/Prototypes/Entities/Structures/Dispensers/base_structuredispensers.yml @@ -1,6 +1,7 @@ - type: entity abstract: true id: ReagentDispenserBase + parent: ConstructibleMachine placement: mode: SnapgridCenter components: @@ -52,3 +53,9 @@ whitelist: components: - FitsInDispenser + - type: ItemSlots + - type: ContainerContainer + containers: + machine_board: !type:Container + machine_parts: !type:Container + ReagentDispenser-beaker: !type:ContainerSlot diff --git a/Resources/Prototypes/Entities/Structures/Dispensers/chem.yml b/Resources/Prototypes/Entities/Structures/Dispensers/chem.yml index 7074cbbfd3..9596a58ead 100644 --- a/Resources/Prototypes/Entities/Structures/Dispensers/chem.yml +++ b/Resources/Prototypes/Entities/Structures/Dispensers/chem.yml @@ -12,9 +12,6 @@ emagPack: ChemDispenserEmaggedInventory - type: ApcPowerReceiver - type: ExtensionCableReceiver - - type: Construction - graph: Machine - node: machine - type: Destructible thresholds: - trigger: diff --git a/Resources/Prototypes/Entities/Structures/Doors/Firelocks/firelock.yml b/Resources/Prototypes/Entities/Structures/Doors/Firelocks/firelock.yml index 7581e6c749..3ddafe00bc 100644 --- a/Resources/Prototypes/Entities/Structures/Doors/Firelocks/firelock.yml +++ b/Resources/Prototypes/Entities/Structures/Doors/Firelocks/firelock.yml @@ -85,10 +85,14 @@ interfaces: - key: enum.WiresUiKey.Key type: WiresBoundUserInterface + - type: Physics + canCollide: false - type: Airtight fixVacuum: true + airBlocked: false noAirWhenFullyAirBlocked: true - type: Occluder + enabled: false - type: Construction graph: Firelock node: Firelock @@ -126,6 +130,7 @@ sprite: Structures/Doors/edge_door_hazard.rsi - type: Airtight fixVacuum: true + airBlocked: false noAirWhenFullyAirBlocked: false airBlockedDirection: - South @@ -143,3 +148,5 @@ enabled: false - type: Door occludes: false + - type: Physics + canCollide: false diff --git a/Resources/Prototypes/Entities/Structures/Doors/Shutter/blast_door.yml b/Resources/Prototypes/Entities/Structures/Doors/Shutter/blast_door.yml index b4e42fd2ca..861b48fa0f 100644 --- a/Resources/Prototypes/Entities/Structures/Doors/Shutter/blast_door.yml +++ b/Resources/Prototypes/Entities/Structures/Doors/Shutter/blast_door.yml @@ -33,3 +33,9 @@ components: - type: Door state: Open + - type: Occluder + enabled: false + - type: Physics + canCollide: false + - type: Airtight + airBlocked: false diff --git a/Resources/Prototypes/Entities/Structures/Doors/Shutter/shutters.yml b/Resources/Prototypes/Entities/Structures/Doors/Shutter/shutters.yml index fb4a9e96d6..31a9348d31 100644 --- a/Resources/Prototypes/Entities/Structures/Doors/Shutter/shutters.yml +++ b/Resources/Prototypes/Entities/Structures/Doors/Shutter/shutters.yml @@ -66,6 +66,11 @@ key: walls mode: NoSprite - type: DoorSignalControl + - type: SignalReceiver + inputs: + Open: [] + Close: [] + Toggle: [] - type: InteractionPopup interactSuccessString: comp-window-knock messagePerceivedByOthers: comp-window-knock @@ -127,6 +132,12 @@ - type: Construction graph: Shutters node: ShuttersRadiation + - type: Occluder + enabled: false + - type: Physics + canCollide: false + - type: Airtight + airBlocked: false - type: entity id: ShuttersWindow @@ -154,6 +165,10 @@ - type: Construction graph: Shutters node: ShuttersWindow + - type: Physics + canCollide: false + - type: Airtight + airBlocked: false # Frame for construction - type: entity diff --git a/Resources/Prototypes/Entities/Structures/Furniture/potted_plants.yml b/Resources/Prototypes/Entities/Structures/Furniture/potted_plants.yml index 2f30188dad..86efb68868 100644 --- a/Resources/Prototypes/Entities/Structures/Furniture/potted_plants.yml +++ b/Resources/Prototypes/Entities/Structures/Furniture/potted_plants.yml @@ -25,6 +25,9 @@ - type: PottedPlantHide - type: SecretStash secretPartName: the plant + - type: ContainerContainer + containers: + stash: !type:ContainerSlot {} - type: Pullable - type: Damageable damageContainer: Inorganic # The pot. Not the plant. Or is it plastic? diff --git a/Resources/Prototypes/Entities/Structures/Furniture/toilet.yml b/Resources/Prototypes/Entities/Structures/Furniture/toilet.yml index 94f8711e02..b906ce0557 100644 --- a/Resources/Prototypes/Entities/Structures/Furniture/toilet.yml +++ b/Resources/Prototypes/Entities/Structures/Furniture/toilet.yml @@ -18,6 +18,9 @@ - type: Toilet - type: SecretStash secretPartName: the toilet cistern + - type: ContainerContainer + containers: + stash: !type:ContainerSlot {} - type: SolutionContainerManager solutions: toilet: @@ -28,6 +31,7 @@ graph: Toilet node: toilet - type: Appearance + - type: entity id: ToiletDirtyWater parent: ToiletEmpty diff --git a/Resources/Prototypes/Entities/Structures/Machines/Computers/base_structurecomputers.yml b/Resources/Prototypes/Entities/Structures/Machines/Computers/base_structurecomputers.yml index 9f22ed81e9..d66c499153 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/Computers/base_structurecomputers.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/Computers/base_structurecomputers.yml @@ -49,3 +49,7 @@ - type: EmitSoundOnUIOpen sound: collection: Keyboard + - type: ContainerContainer + containers: + board: !type:Container + ents: [] diff --git a/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml b/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml index b935b1fc2f..329451bba4 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml @@ -382,6 +382,12 @@ - type: Tag tags: - EmagImmune + - type: ItemSlots + - type: ContainerContainer + containers: + board: !type:Container + IdCardConsole-privilegedId: !type:ContainerSlot + IdCardConsole-targetId: !type:ContainerSlot - type: entity parent: BaseComputer diff --git a/Resources/Prototypes/Entities/Structures/Machines/base_structuremachines.yml b/Resources/Prototypes/Entities/Structures/Machines/base_structuremachines.yml index f944f13a58..aac464e2b9 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/base_structuremachines.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/base_structuremachines.yml @@ -43,3 +43,19 @@ - type: ApcPowerReceiver powerLoad: 1000 - type: ExtensionCableReceiver + +- type: entity + abstract: true + id: ConstructibleMachine + components: + - type: Machine + - type: ContainerContainer + containers: + machine_board: !type:Container + machine_parts: !type:Container + - type: Construction + graph: Machine + node: machine + containers: + - machine_parts + - machine_board diff --git a/Resources/Prototypes/Entities/Structures/Machines/chem_master.yml b/Resources/Prototypes/Entities/Structures/Machines/chem_master.yml index ce34ea4a5a..08509f13bd 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/chem_master.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/chem_master.yml @@ -1,6 +1,6 @@ - type: entity id: chem_master - parent: BaseMachinePowered + parent: [ BaseMachinePowered, ConstructibleMachine ] name: ChemMaster 4000 description: An industrial grade chemical manipulator with pill and bottle production included. placement: @@ -60,7 +60,12 @@ - type: Machine board: ChemMasterMachineCircuitboard - type: MaterialStorage - - type: Construction - graph: Machine - node: machine - + - type: ContainerContainer + containers: + machine_board: !type:Container + machine_parts: !type:Container + ChemMaster-beaker: !type:ContainerSlot + - type: ItemSlots + - type: SolutionContainerManager + solutions: + buffer: {} diff --git a/Resources/Prototypes/Entities/Structures/Machines/cloning_machine.yml b/Resources/Prototypes/Entities/Structures/Machines/cloning_machine.yml index 9c5be27cec..7784117f29 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/cloning_machine.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/cloning_machine.yml @@ -1,6 +1,6 @@ - type: entity id: CloningPod - parent: BaseMachinePowered + parent: [ BaseMachinePowered, ConstructibleMachine ] name: cloning pod description: A Cloning Pod. 50% reliable. components: @@ -25,9 +25,6 @@ - MachineMask layer: - MachineLayer - - type: Construction - graph: Machine - node: machine - type: Destructible thresholds: - trigger: diff --git a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml index 87e213238c..43af5b8ca4 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml @@ -1,5 +1,5 @@ - type: entity - parent: BaseMachinePowered + parent: [ BaseMachinePowered, ConstructibleMachine ] id: Autolathe name: autolathe description: It produces items using metal and glass. @@ -34,9 +34,6 @@ - MachineMask layer: - MachineLayer - - type: Construction - graph: Machine - node: machine - type: Destructible thresholds: - trigger: @@ -86,7 +83,7 @@ - Ingot - type: entity - parent: BaseMachinePowered + parent: [ BaseMachinePowered, ConstructibleMachine ] id: Protolathe name: protolathe description: Converts raw materials into useful objects. @@ -122,9 +119,6 @@ layer: - MachineLayer - type: ResearchClient - - type: Construction - graph: Machine - node: machine - type: Destructible thresholds: - trigger: diff --git a/Resources/Prototypes/Entities/Structures/Machines/medical_scanner.yml b/Resources/Prototypes/Entities/Structures/Machines/medical_scanner.yml index 467cd0fea3..a0822036fa 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/medical_scanner.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/medical_scanner.yml @@ -1,6 +1,6 @@ - type: entity id: MedicalScanner - parent: BaseMachinePowered + parent: [ BaseMachinePowered, ConstructibleMachine ] name: medical scanner description: A bulky medical scanner. components: @@ -28,9 +28,6 @@ - MachineMask layer: - MachineLayer - - type: Construction - graph: Machine - node: machine - type: Destructible thresholds: - trigger: diff --git a/Resources/Prototypes/Entities/Structures/Machines/reagent_grinder.yml b/Resources/Prototypes/Entities/Structures/Machines/reagent_grinder.yml index 25cabeccae..0853198298 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/reagent_grinder.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/reagent_grinder.yml @@ -42,3 +42,8 @@ drawdepth: SmallObjects - type: ApcPowerReceiver powerLoad: 300 + - type: ItemSlots + - type: ContainerContainer + containers: + ReagentGrinder-reagentContainerContainer: !type:ContainerSlot + ReagentGrinder-entityContainerContainer: !type:Container diff --git a/Resources/Prototypes/Entities/Structures/Machines/surveillance_camera_routers.yml b/Resources/Prototypes/Entities/Structures/Machines/surveillance_camera_routers.yml index 84f88db3e3..70491adbd8 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/surveillance_camera_routers.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/surveillance_camera_routers.yml @@ -1,6 +1,6 @@ - type: entity abstract: true - parent: BaseMachinePowered + parent: [ BaseMachinePowered, ConstructibleMachine ] id: SurveillanceCameraRouterBase name: camera router description: A surveillance camera router. It routes. Perhaps. @@ -14,9 +14,6 @@ interfaces: - key: enum.SurveillanceCameraSetupUiKey.Router type: SurveillanceCameraSetupBoundUi - - type: Construction - graph: Machine - node: machine - type: Machine board: SurveillanceCameraRouterCircuitboard - type: Sprite @@ -105,7 +102,7 @@ subnetFrequency: SurveillanceCameraGeneral - type: entity - parent: BaseMachinePowered + parent: [ BaseMachinePowered, ConstructibleMachine ] id: SurveillanceCameraWirelessRouterBase name: wireless camera router description: A wireless surveillance camera router. It routes. Perhaps. @@ -120,9 +117,6 @@ interfaces: - key: enum.SurveillanceCameraSetupUiKey.Router type: SurveillanceCameraSetupBoundUi - - type: Construction - graph: Machine - node: machine - type: Machine board: SurveillanceCameraWirelessRouterCircuitboard - type: Sprite diff --git a/Resources/Prototypes/Entities/Structures/Machines/wireless_surveillance_camera.yml b/Resources/Prototypes/Entities/Structures/Machines/wireless_surveillance_camera.yml index d5f6c049db..1a96812418 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/wireless_surveillance_camera.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/wireless_surveillance_camera.yml @@ -1,13 +1,10 @@ - type: entity abstract: true - parent: BaseStructureDynamic + parent: [ BaseStructureDynamic, ConstructibleMachine ] id: SurveillanceWirelessCameraBase name: wireless camera description: A camera. It's watching you. Kinda. components: - - type: Construction - graph: Machine - node: machine - type: InteractionOutline - type: Eye - type: WirelessNetworkConnection diff --git a/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/miners.yml b/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/miners.yml index 8ffc122857..0e0225a865 100644 --- a/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/miners.yml +++ b/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/miners.yml @@ -9,6 +9,7 @@ - type: Clickable - type: InteractionOutline - type: Physics + - type: Fixtures - type: Transform anchored: true - type: Damageable diff --git a/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/pipes.yml b/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/pipes.yml index 0f1fcf5445..2bda18bcee 100644 --- a/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/pipes.yml +++ b/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/pipes.yml @@ -15,6 +15,7 @@ damageContainer: Inorganic damageModifierSet: Metallic - type: SubFloorHide + - type: CollideOnAnchor - type: PipeAppearance - type: Anchorable - type: Rotatable diff --git a/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/unary.yml b/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/unary.yml index 2963e17f6f..558fdaec14 100644 --- a/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/unary.yml +++ b/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/unary.yml @@ -15,6 +15,7 @@ !type:PipeNode nodeGroupID: Pipe pipeDirection: South + - type: CollideOnAnchor - type: entity parent: GasUnaryBase @@ -184,7 +185,7 @@ - enum.LightLayers.Unshaded - type: entity - parent: BaseMachinePowered + parent: [ BaseMachinePowered, ConstructibleMachine ] id: BaseGasThermoMachine name: thermomachine abstract: true @@ -207,9 +208,6 @@ - type: ActivatableUI inHandsOnly: false key: enum.ThermomachineUiKey.Key - - type: Construction - graph: Machine - node: machine - type: Wires BoardName: "Thermomachine" LayoutId: Thermomachine @@ -244,10 +242,6 @@ mode: Freezer - type: Machine board: ThermomachineFreezerMachineCircuitBoard - - type: ContainerContainer - containers: - machine_parts: !type:Container - machine_board: !type:Container - type: entity parent: BaseGasThermoMachine @@ -273,7 +267,3 @@ mode: Heater - type: Machine board: ThermomachineHeaterMachineCircuitBoard - - type: ContainerContainer - containers: - machine_parts: !type:Container - machine_board: !type:Container diff --git a/Resources/Prototypes/Entities/Structures/Piping/Disposal/pipes.yml b/Resources/Prototypes/Entities/Structures/Piping/Disposal/pipes.yml index 9ace34faf5..b276055439 100644 --- a/Resources/Prototypes/Entities/Structures/Piping/Disposal/pipes.yml +++ b/Resources/Prototypes/Entities/Structures/Piping/Disposal/pipes.yml @@ -49,6 +49,11 @@ node: broken - type: Rotatable - type: Pullable + - type: CollideOnAnchor + - type: ContainerContainer + containers: + disposal-tube: !type:Container + ents: [] - type: entity id: DisposalHolder diff --git a/Resources/Prototypes/Entities/Structures/Piping/Disposal/units.yml b/Resources/Prototypes/Entities/Structures/Piping/Disposal/units.yml index e017b41bea..744cd5a4a2 100644 --- a/Resources/Prototypes/Entities/Structures/Piping/Disposal/units.yml +++ b/Resources/Prototypes/Entities/Structures/Piping/Disposal/units.yml @@ -70,6 +70,10 @@ interfaces: - key: enum.DisposalUnitUiKey.Key type: DisposalUnitBoundUserInterface + - type: ContainerContainer + containers: + disposal-unit: !type:Container + ents: [] - type: entity id: DisposalUnit diff --git a/Resources/Prototypes/Entities/Structures/Power/Generation/Singularity/emitter.yml b/Resources/Prototypes/Entities/Structures/Power/Generation/Singularity/emitter.yml index f430c6d5cd..5f777dff7b 100644 --- a/Resources/Prototypes/Entities/Structures/Power/Generation/Singularity/emitter.yml +++ b/Resources/Prototypes/Entities/Structures/Power/Generation/Singularity/emitter.yml @@ -1,6 +1,7 @@ - type: entity id: Emitter name: emitter + parent: ConstructibleMachine description: A heavy duty industrial laser. Shoots non-stop when turned on. placement: mode: SnapgridCenter @@ -70,8 +71,5 @@ locked: false - type: AccessReader access: [[ "Engineering" ]] - - type: Construction - graph: Machine - node: machine - type: Machine board: EmitterCircuitboard diff --git a/Resources/Prototypes/Entities/Structures/Power/Generation/generators.yml b/Resources/Prototypes/Entities/Structures/Power/Generation/generators.yml index 9a659a181f..1b0d6f6673 100644 --- a/Resources/Prototypes/Entities/Structures/Power/Generation/generators.yml +++ b/Resources/Prototypes/Entities/Structures/Power/Generation/generators.yml @@ -151,7 +151,7 @@ supplyRate: 3000 - type: entity - parent: BaseGenerator + parent: [ BaseGenerator, ConstructibleMachine ] id: GeneratorPlasma suffix: Plasma, 5kW components: @@ -160,21 +160,14 @@ - type: Sprite sprite: Structures/Power/Generation/portable_generator.rsi state: portgen0_1 - - type: Construction - graph: Machine - node: machine - type: Wires BoardName: "GeneratorPlasma" LayoutId: GeneratorPlasma - type: Machine board: GeneratorPlasmaMachineCircuitboard - - type: ContainerContainer - containers: - machine_parts: !type:Container - machine_board: !type:Container - type: entity - parent: BaseGenerator + parent: [ BaseGenerator, ConstructibleMachine ] id: GeneratorUranium suffix: Uranium, 15kW components: @@ -183,18 +176,11 @@ - type: Sprite sprite: Structures/Power/Generation/portable_generator.rsi state: portgen1_1 - - type: Construction - graph: Machine - node: machine - type: Wires BoardName: "GeneratorUranium" LayoutId: GeneratorUranium - type: Machine board: GeneratorUraniumMachineCircuitboard - - type: ContainerContainer - containers: - machine_parts: !type:Container - machine_board: !type:Container - type: entity parent: BaseGeneratorWallmount diff --git a/Resources/Prototypes/Entities/Structures/Power/cables.yml b/Resources/Prototypes/Entities/Structures/Power/cables.yml index 2bf3f428ea..91ae5d1cfe 100644 --- a/Resources/Prototypes/Entities/Structures/Power/cables.yml +++ b/Resources/Prototypes/Entities/Structures/Power/cables.yml @@ -26,6 +26,7 @@ - !type:DoActsBehavior acts: ["Destruction"] - type: SubFloorHide + - type: CollideOnAnchor - type: AmbientSound enabled: false # Leaving as false because 90% of them are set to this. - type: Appearance diff --git a/Resources/Prototypes/Entities/Structures/Power/chargers.yml b/Resources/Prototypes/Entities/Structures/Power/chargers.yml index 0dbbc9c6a0..eb4c8d8195 100644 --- a/Resources/Prototypes/Entities/Structures/Power/chargers.yml +++ b/Resources/Prototypes/Entities/Structures/Power/chargers.yml @@ -38,6 +38,10 @@ - MachineMask layer: - HighImpassable + - type: ItemSlots + - type: ContainerContainer + containers: + charger-slot: !type:ContainerSlot - type: entity name: recharger diff --git a/Resources/Prototypes/Entities/Structures/Power/smes.yml b/Resources/Prototypes/Entities/Structures/Power/smes.yml index 9328d35934..7376574210 100644 --- a/Resources/Prototypes/Entities/Structures/Power/smes.yml +++ b/Resources/Prototypes/Entities/Structures/Power/smes.yml @@ -2,7 +2,7 @@ - type: entity abstract: true id: BaseSMES - parent: BaseMachine + parent: [ BaseMachine, ConstructibleMachine ] name: SMES description: A high-capacity superconducting magnetic energy storage (SMES) unit. placement: @@ -51,18 +51,11 @@ energy: 1.6 color: "#c9c042" castShadows: false - - type: Construction - graph: Machine - node: machine - type: Wires BoardName: "SMES" LayoutId: SMES - type: Machine board: SMESMachineCircuitboard - - type: ContainerContainer - containers: - machine_parts: !type:Container - machine_board: !type:Container - type: StationInfiniteBatteryTarget # SMES' in use diff --git a/Resources/Prototypes/Entities/Structures/Power/substation.yml b/Resources/Prototypes/Entities/Structures/Power/substation.yml index ec67a2dda0..4b00ff4c6c 100644 --- a/Resources/Prototypes/Entities/Structures/Power/substation.yml +++ b/Resources/Prototypes/Entities/Structures/Power/substation.yml @@ -2,7 +2,7 @@ - type: entity abstract: true id: BaseSubstation - parent: BaseMachine + parent: [ BaseMachine, ConstructibleMachine ] name: substation description: Reduces the voltage of electricity put into it. placement: @@ -43,9 +43,6 @@ maxChargeRate: 5000 supplyRampTolerance: 5000 supplyRampRate: 1000 - - type: Construction - graph: Machine - node: machine - type: Destructible thresholds: - trigger: @@ -73,10 +70,6 @@ LayoutId: Substation - type: Machine board: SubstationMachineCircuitboard - - type: ContainerContainer - containers: - machine_parts: !type:Container - machine_board: !type:Container - type: StationInfiniteBatteryTarget # Compact Wall Substation Base diff --git a/Resources/Prototypes/Entities/Structures/Storage/Crates/base_structurecrates.yml b/Resources/Prototypes/Entities/Structures/Storage/Crates/base_structurecrates.yml index 219dec801e..7c774a9948 100644 --- a/Resources/Prototypes/Entities/Structures/Storage/Crates/base_structurecrates.yml +++ b/Resources/Prototypes/Entities/Structures/Storage/Crates/base_structurecrates.yml @@ -34,6 +34,7 @@ capacity: 500 - type: Weldable - type: PlaceableSurface + isPlaceable: false # defaults to closed. - type: Damageable damageContainer: Inorganic damageModifierSet: Metallic @@ -61,6 +62,7 @@ containers: entity_storage: !type:Container paper_label: !type:ContainerSlot + - type: ItemSlots - type: entity id: CrateBaseSecure @@ -97,6 +99,7 @@ capacity: 500 - type: Weldable - type: PlaceableSurface + isPlaceable: false # defaults to closed. - type: Damageable damageContainer: Inorganic damageModifierSet: StrongMetallic @@ -123,3 +126,10 @@ - type: Construction graph: CrateSecure node: cratesecure + containers: + - entity_storage + - type: ContainerContainer + containers: + entity_storage: !type:Container + paper_label: !type:ContainerSlot + - type: ItemSlots diff --git a/Resources/Prototypes/Entities/Structures/Storage/Crates/crates.yml b/Resources/Prototypes/Entities/Structures/Storage/Crates/crates.yml index 9ea6adf105..e5736ac0c2 100644 --- a/Resources/Prototypes/Entities/Structures/Storage/Crates/crates.yml +++ b/Resources/Prototypes/Entities/Structures/Storage/Crates/crates.yml @@ -23,7 +23,8 @@ - type: Construction graph: CrateGenericSteel node: crategenericsteel - + containers: + - entity_storage - type: entity id: CratePlastic @@ -50,6 +51,8 @@ - type: Construction graph: CratePlastic node: crateplastic + containers: + - entity_storage - type: entity id: CrateFreezer @@ -76,6 +79,8 @@ - type: Construction graph: CrateGenericSteel node: crategenericsteel + containers: + - entity_storage - type: AntiRottingContainer - type: entity @@ -103,6 +108,8 @@ - type: Construction graph: CrateGenericSteel node: crategenericsteel + containers: + - entity_storage - type: entity id: CrateMedical @@ -129,6 +136,8 @@ - type: Construction graph: CrateGenericSteel node: crategenericsteel + containers: + - entity_storage - type: entity id: CrateRadiation @@ -156,6 +165,8 @@ - type: Construction graph: CrateGenericSteel node: crategenericsteel + containers: + - entity_storage - type: entity id: CrateInternals @@ -182,6 +193,8 @@ - type: Construction graph: CrateGenericSteel node: crategenericsteel + containers: + - entity_storage - type: entity id: CrateElectrical @@ -208,6 +221,8 @@ - type: Construction graph: CrateGenericSteel node: crategenericsteel + containers: + - entity_storage - type: entity id: CrateEngineering @@ -234,6 +249,8 @@ - type: Construction graph: CrateGenericSteel node: crategenericsteel + containers: + - entity_storage - type: entity id: CrateScience @@ -260,6 +277,8 @@ - type: Construction graph: CrateGenericSteel node: crategenericsteel + containers: + - entity_storage - type: entity id: CrateSurgery @@ -286,6 +305,8 @@ - type: Construction graph: CrateGenericSteel node: crategenericsteel + containers: + - entity_storage # Secure Crates @@ -629,4 +650,6 @@ - type: Construction graph: CrateLivestock node: cratelivestock + containers: + - entity_storage diff --git a/Resources/Prototypes/Entities/Structures/Wallmounts/extinguisher_cabinet.yml b/Resources/Prototypes/Entities/Structures/Wallmounts/extinguisher_cabinet.yml index d3c32f3b8b..47440c409f 100644 --- a/Resources/Prototypes/Entities/Structures/Wallmounts/extinguisher_cabinet.yml +++ b/Resources/Prototypes/Entities/Structures/Wallmounts/extinguisher_cabinet.yml @@ -31,6 +31,10 @@ - type: ItemCabinetVisuals openState: open closedState: closed + - type: ItemSlots + - type: ContainerContainer + containers: + ItemCabinet: !type:ContainerSlot placement: mode: SnapgridCenter diff --git a/Resources/Prototypes/Entities/Structures/Wallmounts/fireaxe_cabinet.yml b/Resources/Prototypes/Entities/Structures/Wallmounts/fireaxe_cabinet.yml index 14911afb58..b86353c024 100644 --- a/Resources/Prototypes/Entities/Structures/Wallmounts/fireaxe_cabinet.yml +++ b/Resources/Prototypes/Entities/Structures/Wallmounts/fireaxe_cabinet.yml @@ -35,6 +35,10 @@ closedState: glass - type: AccessReader access: [["Atmospherics"]] + - type: ItemSlots + - type: ContainerContainer + containers: + ItemCabinet: !type:ContainerSlot placement: mode: SnapgridCenter diff --git a/Resources/Prototypes/Entities/Structures/Wallmounts/switch.yml b/Resources/Prototypes/Entities/Structures/Wallmounts/switch.yml index f0fb1c63f6..5dfb21d0da 100644 --- a/Resources/Prototypes/Entities/Structures/Wallmounts/switch.yml +++ b/Resources/Prototypes/Entities/Structures/Wallmounts/switch.yml @@ -22,6 +22,11 @@ - type: Construction graph: SignalSwitchGraph node: SignalSwitchNode + - type: Fixtures + - type: SignalTransmitter + outputs: + On: [] + Off: [] - type: entity id: SignalButton @@ -49,6 +54,10 @@ - type: Construction graph: SignalButtonGraph node: SignalButtonNode + - type: Fixtures + - type: SignalTransmitter + outputs: + Pressed: [] - type: entity id: ApcNetSwitch @@ -79,6 +88,7 @@ - type: Construction graph: LightSwitchGraph node: LightSwitchNode + - type: Fixtures - type: entity id: TwoWayLever @@ -120,3 +130,9 @@ - type: Construction graph: LeverGraph node: LeverNode + - type: Fixtures + - type: SignalTransmitter + outputs: + Left: [] + Right: [] + Middle: [] diff --git a/Resources/Prototypes/Entities/Structures/hydro_tray.yml b/Resources/Prototypes/Entities/Structures/hydro_tray.yml index acc70706c8..27150b379e 100644 --- a/Resources/Prototypes/Entities/Structures/hydro_tray.yml +++ b/Resources/Prototypes/Entities/Structures/hydro_tray.yml @@ -1,6 +1,6 @@ - type: entity name: hydroponics tray - parent: hydroponicsSoil + parent: [ hydroponicsSoil, ConstructibleMachine] id: hydroponicsTray description: An interstellar-grade space farmplot allowing for rapid growth and selective breeding of crops. Just... keep in mind the space weeds. components: @@ -66,9 +66,6 @@ False: { visible: false } - type: PlantHolder drawWarnings: true - - type: Construction - graph: Machine - node: machine - type: Destructible thresholds: - trigger: