From: Nemanja <98561806+EmoGarbage404@users.noreply.github.com> Date: Mon, 10 Apr 2023 04:38:20 +0000 (-0400) Subject: Material Reclaimer (#14969) X-Git-Url: https://git.smokeofanarchy.ru/gitweb.cgi?a=commitdiff_plain;h=57f2a768a07ac12dd30458557070852965d64d4d;p=space-station-14.git Material Reclaimer (#14969) * Material Reclaimer * Fix this test * autostack output, tweak volume, add upgrade examine * whitelist AND blacklist support why not * trying so hard to get this fucking test to work * EmoGarbage delves into MaterialArbitrageTest, never to return * VV and restore cloth to glory * make the system more robust * even more stuff has composition; add blacklist for important items * fix test fails * convert recycling * forgor :sadge: * lol * simply a modiCUM of doc commentary --- diff --git a/Content.Client/Materials/MaterialReclaimerSystem.cs b/Content.Client/Materials/MaterialReclaimerSystem.cs new file mode 100644 index 0000000000..eec55eac3c --- /dev/null +++ b/Content.Client/Materials/MaterialReclaimerSystem.cs @@ -0,0 +1,9 @@ +using Content.Shared.Materials; + +namespace Content.Client.Materials; + +/// +public sealed class MaterialReclaimerSystem : SharedMaterialReclaimerSystem +{ + +} diff --git a/Content.Client/Recycling/RecyclerVisualizer.cs b/Content.Client/Recycling/RecyclerVisualizer.cs deleted file mode 100644 index 856ebffc5e..0000000000 --- a/Content.Client/Recycling/RecyclerVisualizer.cs +++ /dev/null @@ -1,70 +0,0 @@ -using Content.Shared.Conveyor; -using Content.Shared.Recycling; -using JetBrains.Annotations; -using Robust.Client.GameObjects; -using Robust.Shared.GameObjects; -using Robust.Shared.IoC; -using Robust.Shared.Serialization.Manager.Attributes; - -namespace Content.Client.Recycling -{ - [UsedImplicitly] - public sealed class RecyclerVisualizer : AppearanceVisualizer - { - [DataField("state_on")] - private string _stateOn = "grinder-o1"; - - [DataField("state_off")] - private string _stateOff = "grinder-o0"; - - [Obsolete("Subscribe to your component being initialised instead.")] - public override void InitializeEntity(EntityUid entity) - { - base.InitializeEntity(entity); - - var entMan = IoCManager.Resolve(); - if (!entMan.TryGetComponent(entity, out SpriteComponent? sprite) || - !entMan.TryGetComponent(entity, out AppearanceComponent? appearance)) - { - return; - } - - UpdateAppearance(appearance, sprite); - } - - [Obsolete("Subscribe to AppearanceChangeEvent instead.")] - public override void OnChangeData(AppearanceComponent component) - { - base.OnChangeData(component); - - var entities = IoCManager.Resolve(); - if (!entities.TryGetComponent(component.Owner, out SpriteComponent? sprite)) - { - return; - } - - UpdateAppearance(component, sprite); - } - - private void UpdateAppearance(AppearanceComponent component, SpriteComponent sprite) - { - var state = _stateOff; - if (component.TryGetData(ConveyorVisuals.State, out ConveyorState conveyorState) && conveyorState != ConveyorState.Off) - { - state = _stateOn; - } - - if (component.TryGetData(RecyclerVisuals.Bloody, out bool bloody) && bloody) - { - state += "bld"; - } - - sprite.LayerSetState(RecyclerVisualLayers.Main, state); - } - } - - public enum RecyclerVisualLayers : byte - { - Main - } -} diff --git a/Content.IntegrationTests/Tests/MaterialArbitrageTest.cs b/Content.IntegrationTests/Tests/MaterialArbitrageTest.cs index de8b78a55f..406b5aad81 100644 --- a/Content.IntegrationTests/Tests/MaterialArbitrageTest.cs +++ b/Content.IntegrationTests/Tests/MaterialArbitrageTest.cs @@ -14,10 +14,12 @@ using Robust.Shared.GameObjects; using Robust.Shared.Map; using Robust.Shared.Prototypes; using System; -using System.Collections; using System.Collections.Generic; using System.Threading.Tasks; +using Content.Shared.Chemistry.Reagent; using Content.Shared.Construction.Components; +using Content.Shared.FixedPoint; +using Content.Shared.Materials; namespace Content.IntegrationTests.Tests; @@ -31,10 +33,7 @@ public sealed class MaterialArbitrageTest [Test] public async Task NoMaterialArbitrage() { - // TODO check lathe resource prices? - // I CBF doing that atm because I know that will probably fail for most lathe recipies. - - await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings() {NoClient = true}); + await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings {NoClient = true}); var server = pairTracker.Pair.Server; var testMap = await PoolManager.CreateTestMap(pairTracker); @@ -51,8 +50,9 @@ public sealed class MaterialArbitrageTest var compFact = server.ResolveDependency(); var constructionName = compFact.GetComponentName(typeof(ConstructionComponent)); + var compositionName = compFact.GetComponentName(typeof(PhysicalCompositionComponent)); + var materialName = compFact.GetComponentName(typeof(MaterialComponent)); var destructibleName = compFact.GetComponentName(typeof(DestructibleComponent)); - var stackName = compFact.GetComponentName(typeof(StackComponent)); // construct inverted lathe recipe dictionary Dictionary latheRecipes = new(); @@ -84,6 +84,9 @@ public sealed class MaterialArbitrageTest { var materials = new Dictionary(); var graph = protoManager.Index(comp.Graph); + if (graph.Start == null) + continue; + if (!graph.TryPath(graph.Start, comp.Node, out var path) || path.Length == 0) continue; @@ -93,10 +96,25 @@ public sealed class MaterialArbitrageTest var edge = cur.GetEdge(node.Name); cur = node; + if (edge == null) + continue; + foreach (var step in edge.Steps) { - if (step is MaterialConstructionGraphStep materialStep) - materials[materialStep.MaterialPrototypeId] = materialStep.Amount + materials.GetValueOrDefault(materialStep.MaterialPrototypeId); + if (step is not MaterialConstructionGraphStep materialStep) + continue; + + var stackProto = protoManager.Index(materialStep.MaterialPrototypeId); + var spawnProto = protoManager.Index(stackProto.Spawn); + + if (!spawnProto.Components.TryGetValue(materialName, out var matreg)) + continue; + + var mat = (MaterialComponent) matreg.Component; + foreach (var (matId, amount) in mat.Materials) + { + materials[matId] = materialStep.Amount * amount + materials.GetValueOrDefault(matId); + } } } constructionMaterials.Add(id, materials); @@ -136,11 +154,16 @@ public sealed class MaterialArbitrageTest spawnedEnts[key] = spawnedEnts.GetValueOrDefault(key) + value.Max; var spawnProto = protoManager.Index(key); - if (!spawnProto.Components.TryGetValue(stackName, out var reg)) + + // get the amount of each material included in the entity + if (!spawnProto.Components.TryGetValue(materialName, out var matreg)) continue; + var mat = (MaterialComponent) matreg.Component; - var stack = (StackComponent) reg.Component; - spawnedMats[stack.StackTypeId] = value.Max + spawnedMats.GetValueOrDefault(stack.StackTypeId); + foreach (var (matId, amount) in mat.Materials) + { + spawnedMats[matId] = value.Max * amount + spawnedMats.GetValueOrDefault(matId); + } } } } @@ -211,18 +234,21 @@ public sealed class MaterialArbitrageTest continue; var spawnProto = protoManager.Index(spawnCompletion.Prototype); - if (!spawnProto.Components.TryGetValue(stackName, out var reg)) - continue; - var stack = (StackComponent) reg.Component; + if (!spawnProto.Components.TryGetValue(materialName, out var matreg)) + continue; - materials[stack.StackTypeId] = spawnCompletion.Amount + materials.GetValueOrDefault(stack.StackTypeId); + var mat = (MaterialComponent) matreg.Component; + foreach (var (matId, amount) in mat.Materials) + { + materials[matId] = spawnCompletion.Amount * amount + materials.GetValueOrDefault(matId); + } } } deconstructionMaterials.Add(id, materials); } - // This is functionally the same loop as before, but now testinng deconstruction rather than destruction. + // This is functionally the same loop as before, but now testing deconstruction rather than destruction. // This is pretty braindead. In principle construction graphs can have loops and whatnot. Assert.Multiple(async () => @@ -258,6 +284,58 @@ public sealed class MaterialArbitrageTest } }); + // create phyiscal composition dictionary + // this doesn't account for the chemicals in the composition + Dictionary physicalCompositions = new(); + foreach (var proto in protoManager.EnumeratePrototypes()) + { + if (proto.NoSpawn || proto.Abstract) + continue; + + if (!proto.Components.TryGetValue(compositionName, out var composition)) + continue; + + var comp = (PhysicalCompositionComponent) composition.Component; + physicalCompositions.Add(proto.ID, comp); + } + + // This is functionally the same loop as before, but now testing composition rather than destruction or deconstruction. + // This doesn't take into account chemicals generated when deconstructing. Maybe it should. + Assert.Multiple(async () => + { + foreach (var (id, compositionComponent) in physicalCompositions) + { + // Check cargo sell price + var materialPrice = await GetDeconstructedPrice(compositionComponent.MaterialComposition); + var chemicalPrice = await GetChemicalCompositionPrice(compositionComponent.ChemicalComposition); + var sumPrice = materialPrice + chemicalPrice; + var price = await GetPrice(id); + if (sumPrice > 0 && price > 0) + Assert.LessOrEqual(sumPrice, price, $"{id} increases in price after decomposed into raw materials"); + + // Check lathe production + if (latheRecipes.TryGetValue(id, out var recipe)) + { + foreach (var (matId, amount) in recipe.RequiredMaterials) + { + var actualAmount = SharedLatheSystem.AdjustMaterial(amount, recipe.ApplyMaterialDiscount, multiplier); + if (compositionComponent.MaterialComposition.TryGetValue(matId, out var numSpawned)) + Assert.LessOrEqual(numSpawned, actualAmount, $"The physical composition of {id} has more {matId} than required to produce via an (upgraded) lathe."); + } + } + + // Check construction. + if (constructionMaterials.TryGetValue(id, out var constructionMats)) + { + foreach (var (matId, amount) in constructionMats) + { + if (compositionComponent.MaterialComposition.TryGetValue(matId, out var numSpawned)) + Assert.LessOrEqual(numSpawned, amount, $"The physical composition of {id} has more {matId} than required to construct it."); + } + } + } + }); + await server.WaitPost(() => mapManager.DeleteMap(testMap.MapId)); await pairTracker.CleanReturnAsync(); @@ -293,8 +371,20 @@ public sealed class MaterialArbitrageTest double price = 0; foreach (var (id, num) in mats) { - var matProto = protoManager.Index(id).Spawn; - price += num * await GetPrice(matProto); + var matProto = protoManager.Index(id); + price += num * matProto.Price; + } + return price; + } + + + async Task GetChemicalCompositionPrice(Dictionary mats) + { + double price = 0; + foreach (var (id, num) in mats) + { + var reagentProto = protoManager.Index(id); + price += num.Double() * reagentProto.PricePerUnit; } return price; } diff --git a/Content.Server/Cargo/Systems/PricingSystem.cs b/Content.Server/Cargo/Systems/PricingSystem.cs index 6a1125ef36..3d4bd64a4c 100644 --- a/Content.Server/Cargo/Systems/PricingSystem.cs +++ b/Content.Server/Cargo/Systems/PricingSystem.cs @@ -213,7 +213,7 @@ public sealed class PricingSystem : EntitySystem { double price = 0; - if (TryComp(uid, out var material) && !HasComp(uid)) + if (TryComp(uid, out var material)) { var matPrice = GetMaterialPrice(material); if (TryComp(uid, out var stack)) @@ -229,8 +229,7 @@ public sealed class PricingSystem : EntitySystem { double price = 0; - if (prototype.Components.TryGetValue(_factory.GetComponentName(typeof(MaterialComponent)), out var materials) && - !prototype.Components.ContainsKey(_factory.GetComponentName(typeof(StackPriceComponent)))) + if (prototype.Components.TryGetValue(_factory.GetComponentName(typeof(MaterialComponent)), out var materials)) { var materialsComp = (MaterialComponent) materials.Component; var matPrice = GetMaterialPrice(materialsComp); @@ -276,7 +275,8 @@ public sealed class PricingSystem : EntitySystem var price = 0.0; if (TryComp(uid, out var stackPrice) && - TryComp(uid, out var stack)) + TryComp(uid, out var stack) && + !HasComp(uid)) // don't double count material prices { price += stack.Count * stackPrice.Price; } @@ -289,7 +289,8 @@ public sealed class PricingSystem : EntitySystem var price = 0.0; if (prototype.Components.TryGetValue(_factory.GetComponentName(typeof(StackPriceComponent)), out var stackpriceProto) && - prototype.Components.TryGetValue(_factory.GetComponentName(typeof(StackComponent)), out var stackProto)) + prototype.Components.TryGetValue(_factory.GetComponentName(typeof(StackComponent)), out var stackProto) && + !prototype.Components.ContainsKey(_factory.GetComponentName(typeof(MaterialComponent)))) { var stackPrice = (StackPriceComponent) stackpriceProto.Component; var stack = (StackComponent) stackProto.Component; diff --git a/Content.Server/Materials/MaterialReclaimerSystem.cs b/Content.Server/Materials/MaterialReclaimerSystem.cs new file mode 100644 index 0000000000..80c4a40bb6 --- /dev/null +++ b/Content.Server/Materials/MaterialReclaimerSystem.cs @@ -0,0 +1,261 @@ +using System.Linq; +using Content.Server.Chemistry.Components.SolutionManager; +using Content.Server.Chemistry.EntitySystems; +using Content.Server.Construction; +using Content.Server.Fluids.EntitySystems; +using Content.Server.GameTicking; +using Content.Server.Nutrition.Components; +using Content.Server.Players; +using Content.Server.Popups; +using Content.Server.Power.Components; +using Content.Server.Stack; +using Content.Server.Wires; +using Content.Shared.Body.Systems; +using Content.Shared.Chemistry.Components; +using Content.Shared.FixedPoint; +using Content.Shared.IdentityManagement; +using Content.Shared.Interaction; +using Content.Shared.Interaction.Events; +using Content.Shared.Materials; +using Robust.Server.GameObjects; +using Robust.Shared.Player; +using Robust.Shared.Utility; + +namespace Content.Server.Materials; + +/// +public sealed class MaterialReclaimerSystem : SharedMaterialReclaimerSystem +{ + [Dependency] private readonly AppearanceSystem _appearance = default!; + [Dependency] private readonly GameTicker _ticker = default!; + [Dependency] private readonly MaterialStorageSystem _materialStorage = default!; + [Dependency] private readonly PopupSystem _popup = default!; + [Dependency] private readonly SolutionContainerSystem _solutionContainer = default!; + [Dependency] private readonly SharedBodySystem _body = default!; //bobby + [Dependency] private readonly SpillableSystem _spillable = default!; + [Dependency] private readonly StackSystem _stack = default!; + + /// + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnStartup); + SubscribeLocalEvent(OnRefreshParts); + SubscribeLocalEvent(OnUpgradeExamine); + SubscribeLocalEvent(OnPowerChanged); + SubscribeLocalEvent(OnInteractUsing, + before: new []{typeof(WiresSystem), typeof(SolutionTransferSystem)}); + SubscribeLocalEvent(OnSuicide); + SubscribeLocalEvent(OnActivePowerChanged); + } + private void OnStartup(EntityUid uid, MaterialReclaimerComponent component, ComponentStartup args) + { + component.OutputSolution = _solutionContainer.EnsureSolution(uid, component.SolutionContainerId); + } + + private void OnUpgradeExamine(EntityUid uid, MaterialReclaimerComponent component, UpgradeExamineEvent args) + { + args.AddPercentageUpgrade(Loc.GetString("material-reclaimer-upgrade-process-rate"), component.MaterialProcessRate / component.BaseMaterialProcessRate); + } + + private void OnRefreshParts(EntityUid uid, MaterialReclaimerComponent component, RefreshPartsEvent args) + { + var rating = args.PartRatings[component.MachinePartProcessRate] - 1; + component.MaterialProcessRate = component.BaseMaterialProcessRate * MathF.Pow(component.PartRatingProcessRateMultiplier, rating); + Dirty(component); + } + + private void OnPowerChanged(EntityUid uid, MaterialReclaimerComponent component, ref PowerChangedEvent args) + { + AmbientSound.SetAmbience(uid, args.Powered); + component.Powered = args.Powered; + Dirty(component); + } + + private void OnInteractUsing(EntityUid uid, MaterialReclaimerComponent component, InteractUsingEvent args) + { + if (args.Handled) + return; + + // if we're trying to get a solution out of the reclaimer, don't destroy it + if (component.OutputSolution.Contents.Any()) + { + if (TryComp(args.Used, out var managerComponent) && + managerComponent.Solutions.Any(s => s.Value.AvailableVolume > 0)) + { + if (TryComp(args.Used, out var drink) && + !drink.Opened) + return; + + if (TryComp(args.Used, out var transfer) && + transfer.CanReceive) + return; + } + } + + args.Handled = TryStartProcessItem(uid, args.Used, component, args.User); + } + + private void OnSuicide(EntityUid uid, MaterialReclaimerComponent component, SuicideEvent args) + { + if (args.Handled) + return; + + args.SetHandled(SuicideKind.Bloodloss); + var victim = args.Victim; + if (TryComp(victim, out ActorComponent? actor) && + actor.PlayerSession.ContentData()?.Mind is { } mind) + { + _ticker.OnGhostAttempt(mind, false); + if (mind.OwnedEntity is { Valid: true } entity) + { + _popup.PopupEntity(Loc.GetString("recycler-component-suicide-message"), entity); + } + } + + _popup.PopupEntity(Loc.GetString("recycler-component-suicide-message-others", ("victim", Identity.Entity(victim, EntityManager))), + victim, + Filter.PvsExcept(victim, entityManager: EntityManager), true); + + _body.GibBody(victim, true); + _appearance.SetData(uid, RecyclerVisuals.Bloody, true); + } + + private void OnActivePowerChanged(EntityUid uid, ActiveMaterialReclaimerComponent component, ref PowerChangedEvent args) + { + if (!args.Powered) + TryFinishProcessItem(uid, null, component); + } + + /// + public override bool TryFinishProcessItem(EntityUid uid, MaterialReclaimerComponent? component = null, ActiveMaterialReclaimerComponent? active = null) + { + if (!Resolve(uid, ref component, ref active, false)) + return false; + + if (!base.TryFinishProcessItem(uid, component, active)) + return false; + + if (active.ReclaimingContainer.ContainedEntities.FirstOrNull() is not { } item) + return false; + + active.ReclaimingContainer.Remove(item); + Dirty(component); + + // scales the output if the process was interrupted. + var completion = 1f - Math.Clamp((float) Math.Round((active.EndTime - Timing.CurTime) / active.Duration), + 0f, 1f); + Reclaim(uid, item, completion, component); + + return true; + } + + /// + public override void Reclaim(EntityUid uid, + EntityUid item, + float completion = 1f, + MaterialReclaimerComponent? component = null) + { + if (!Resolve(uid, ref component)) + return; + + var xform = Transform(uid); + + SpawnMaterialsFromComposition(uid, item, completion * component.Efficiency, xform: xform); + SpawnChemicalsFromComposition(uid, item, completion, component, xform); + + if (CanGib(uid, item, component)) + { + _body.GibBody(item, true); + _appearance.SetData(uid, RecyclerVisuals.Bloody, true); + } + + QueueDel(item); + } + + private void SpawnMaterialsFromComposition(EntityUid reclaimer, + EntityUid item, + float efficiency, + MaterialStorageComponent? storage = null, + TransformComponent? xform = null, + PhysicalCompositionComponent? composition = null) + { + if (!Resolve(reclaimer, ref storage, ref xform, false)) + return; + + if (!Resolve(item, ref composition, false)) + return; + + foreach (var (material, amount) in composition.MaterialComposition) + { + var outputAmount = (int) (amount * efficiency); + _materialStorage.TryChangeMaterialAmount(reclaimer, material, outputAmount, storage); + } + + foreach (var (storedMaterial, storedAmount) in storage.Storage) + { + var stacks = _materialStorage.SpawnMultipleFromMaterial(storedAmount, storedMaterial, + xform.Coordinates, + out var materialOverflow); + var amountConsumed = storedAmount - materialOverflow; + _materialStorage.TryChangeMaterialAmount(reclaimer, storedMaterial, -amountConsumed, storage); + foreach (var stack in stacks) + { + _stack.TryMergeToContacts(stack); + } + } + } + + private void SpawnChemicalsFromComposition(EntityUid reclaimer, + EntityUid item, + float efficiency, + MaterialReclaimerComponent? reclaimerComponent = null, + TransformComponent? xform = null, + PhysicalCompositionComponent? composition = null) + { + if (!Resolve(reclaimer, ref reclaimerComponent, ref xform)) + return; + + var overflow = new Solution(); + var totalChemicals = new Dictionary(); + + if (Resolve(item, ref composition, false)) + { + foreach (var (key, value) in composition.ChemicalComposition) + { + totalChemicals[key] = totalChemicals.GetValueOrDefault(key) + value; + } + } + + // if the item we inserted has reagents, add it in. + if (TryComp(item, out var solutionContainer)) + { + foreach (var solution in solutionContainer.Solutions.Values) + { + foreach (var quantity in solution.Contents) + { + totalChemicals[quantity.ReagentId] = + totalChemicals.GetValueOrDefault(quantity.ReagentId) + quantity.Quantity; + } + } + } + + foreach (var (reagent, amount) in totalChemicals) + { + var outputAmount = amount * efficiency * reclaimerComponent.Efficiency; + _solutionContainer.TryAddReagent(reclaimer, reclaimerComponent.OutputSolution, reagent, outputAmount, + out var accepted); + var overflowAmount = outputAmount - accepted; + if (overflowAmount > 0) + { + overflow.AddReagent(reagent, overflowAmount); + } + } + + if (overflow.Volume > 0) + { + _spillable.SpillAt(reclaimer, overflow, reclaimerComponent.PuddleId, transformComponent: xform); + } + } +} diff --git a/Content.Server/Materials/MaterialStorageSystem.cs b/Content.Server/Materials/MaterialStorageSystem.cs index 4e4aaeec58..e79a47d067 100644 --- a/Content.Server/Materials/MaterialStorageSystem.cs +++ b/Content.Server/Materials/MaterialStorageSystem.cs @@ -48,9 +48,9 @@ public sealed class MaterialStorageSystem : SharedMaterialStorageSystem return false; if (!base.TryInsertMaterialEntity(user, toInsert, receiver, component)) return false; - _audio.PlayPvs(component.InsertingSound, component.Owner); - _popup.PopupEntity(Loc.GetString("machine-insert-item", ("user", user), ("machine", component.Owner), - ("item", toInsert)), component.Owner); + _audio.PlayPvs(component.InsertingSound, receiver); + _popup.PopupEntity(Loc.GetString("machine-insert-item", ("user", user), ("machine", receiver), + ("item", toInsert)), receiver); QueueDel(toInsert); // Logging @@ -67,16 +67,27 @@ public sealed class MaterialStorageSystem : SharedMaterialStorageSystem /// 1 biomass = 1 biomass in its stack, /// but 100 plasma = 1 sheet of plasma, etc. /// - [PublicAPI] public List SpawnMultipleFromMaterial(int amount, string material, EntityCoordinates coordinates) { + return SpawnMultipleFromMaterial(amount, material, coordinates, out _); + } + + /// + /// Spawn an amount of a material in stack entities. + /// Note the 'amount' is material dependent. + /// 1 biomass = 1 biomass in its stack, + /// but 100 plasma = 1 sheet of plasma, etc. + /// + public List SpawnMultipleFromMaterial(int amount, string material, EntityCoordinates coordinates, out int overflowMaterial) + { + overflowMaterial = 0; if (!_prototypeManager.TryIndex(material, out var stackType)) { Logger.Error("Failed to index material prototype " + material); return new List(); } - return SpawnMultipleFromMaterial(amount, stackType, coordinates); + return SpawnMultipleFromMaterial(amount, stackType, coordinates, out overflowMaterial); } /// @@ -85,8 +96,22 @@ public sealed class MaterialStorageSystem : SharedMaterialStorageSystem /// 1 biomass = 1 biomass in its stack, /// but 100 plasma = 1 sheet of plasma, etc. /// + [PublicAPI] public List SpawnMultipleFromMaterial(int amount, MaterialPrototype materialProto, EntityCoordinates coordinates) { + return SpawnMultipleFromMaterial(amount, materialProto, coordinates, out _); + } + + /// + /// Spawn an amount of a material in stack entities. + /// Note the 'amount' is material dependent. + /// 1 biomass = 1 biomass in its stack, + /// but 100 plasma = 1 sheet of plasma, etc. + /// + public List SpawnMultipleFromMaterial(int amount, MaterialPrototype materialProto, EntityCoordinates coordinates, out int overflowMaterial) + { + overflowMaterial = 0; + if (amount <= 0) return new List(); @@ -96,6 +121,7 @@ public sealed class MaterialStorageSystem : SharedMaterialStorageSystem var materialPerStack = material.Materials[materialProto.ID]; var amountToSpawn = amount / materialPerStack; + overflowMaterial = amount - amountToSpawn * materialPerStack; return _stackSystem.SpawnMultiple(materialProto.StackEntity, amountToSpawn, coordinates); } } diff --git a/Content.Server/Physics/Controllers/ConveyorController.cs b/Content.Server/Physics/Controllers/ConveyorController.cs index 1d18eb70f4..31779ed1a7 100644 --- a/Content.Server/Physics/Controllers/ConveyorController.cs +++ b/Content.Server/Physics/Controllers/ConveyorController.cs @@ -1,8 +1,7 @@ using Content.Server.MachineLinking.Events; using Content.Server.MachineLinking.System; +using Content.Server.Materials; using Content.Server.Power.Components; -using Content.Server.Recycling; -using Content.Server.Recycling.Components; using Content.Shared.Conveyor; using Content.Shared.Maps; using Content.Shared.Physics; @@ -18,7 +17,7 @@ namespace Content.Server.Physics.Controllers; public sealed class ConveyorController : SharedConveyorController { [Dependency] private readonly FixtureSystem _fixtures = default!; - [Dependency] private readonly RecyclerSystem _recycler = default!; + [Dependency] private readonly MaterialReclaimerSystem _materialReclaimer = default!; [Dependency] private readonly SignalLinkerSystem _signalSystem = default!; [Dependency] private readonly SharedBroadphaseSystem _broadphase = default!; [Dependency] private readonly SharedAppearanceSystem _appearance = default!; @@ -105,13 +104,7 @@ public sealed class ConveyorController : SharedConveyorController if (TryComp(uid, out var physics)) _broadphase.RegenerateContacts(physics); - if (TryComp(uid, out var recycler)) - { - if (component.State != ConveyorState.Off) - _recycler.EnableRecycler(recycler); - else - _recycler.DisableRecycler(recycler); - } + _materialReclaimer.SetReclaimerEnabled(uid, component.State != ConveyorState.Off); UpdateAppearance(uid, component); Dirty(component); diff --git a/Content.Server/Recycling/Components/RecyclableComponent.cs b/Content.Server/Recycling/Components/RecyclableComponent.cs deleted file mode 100644 index baa3794423..0000000000 --- a/Content.Server/Recycling/Components/RecyclableComponent.cs +++ /dev/null @@ -1,26 +0,0 @@ -using Robust.Shared.Prototypes; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; - -namespace Content.Server.Recycling.Components -{ - [RegisterComponent, Access(typeof(RecyclerSystem))] - public sealed class RecyclableComponent : Component - { - /// - /// The prototype that will be spawned on recycle. - /// - [DataField("prototype", customTypeSerializer:typeof(PrototypeIdSerializer))] public string? Prototype; - - /// - /// The amount of things that will be spawned on recycle. - /// - [DataField("amount")] public int Amount = 1; - - /// - /// Whether this is "safe" to recycle or not. - /// If this is false, the recycler's safety must be disabled to recycle it. - /// - [DataField("safe")] - public bool Safe { get; set; } = true; - } -} diff --git a/Content.Server/Recycling/Components/RecyclerComponent.cs b/Content.Server/Recycling/Components/RecyclerComponent.cs deleted file mode 100644 index 017c9881c1..0000000000 --- a/Content.Server/Recycling/Components/RecyclerComponent.cs +++ /dev/null @@ -1,34 +0,0 @@ -using Content.Shared.Recycling; -using Robust.Shared.Audio; - -namespace Content.Server.Recycling.Components -{ - // TODO: Add sound and safe beep - [RegisterComponent] - [Access(typeof(RecyclerSystem))] - public sealed class RecyclerComponent : Component - { - [Dependency] private readonly IEntityManager _entMan = default!; - - [DataField("enabled")] - public bool Enabled; - - /// - /// The percentage of material that will be recovered - /// - [ViewVariables(VVAccess.ReadWrite)] - [DataField("efficiency")] - internal float Efficiency = 0.25f; - - /// - /// Default sound to play when recycling - /// - [ViewVariables(VVAccess.ReadWrite)] [DataField("sound")] - public SoundSpecifier? Sound = new SoundPathSpecifier("/Audio/Effects/saw.ogg"); - - // Ratelimit sounds to avoid spam - public TimeSpan LastSound; - - public int ItemsProcessed; - } -} diff --git a/Content.Server/Recycling/RecyclerSystem.cs b/Content.Server/Recycling/RecyclerSystem.cs deleted file mode 100644 index de7c558b4c..0000000000 --- a/Content.Server/Recycling/RecyclerSystem.cs +++ /dev/null @@ -1,199 +0,0 @@ -using Content.Server.Audio; -using Content.Server.Body.Systems; -using Content.Server.GameTicking; -using Content.Server.Players; -using Content.Server.Popups; -using Content.Server.Power.Components; -using Content.Server.Power.EntitySystems; -using Content.Server.Recycling.Components; -using Content.Shared.Audio; -using Content.Shared.Body.Components; -using Content.Shared.Emag.Components; -using Content.Shared.Emag.Systems; -using Content.Shared.Examine; -using Content.Shared.IdentityManagement; -using Content.Shared.Interaction.Events; -using Content.Shared.Recycling; -using Content.Shared.Tag; -using Robust.Server.GameObjects; -using Robust.Shared.Audio; -using Robust.Shared.Physics.Events; -using Robust.Shared.Player; -using Robust.Shared.Timing; - -namespace Content.Server.Recycling -{ - public sealed class RecyclerSystem : EntitySystem - { - [Dependency] private readonly IGameTiming _timing = default!; - [Dependency] private readonly AmbientSoundSystem _ambience = default!; - [Dependency] private readonly BodySystem _bodySystem = default!; - [Dependency] private readonly GameTicker _ticker = default!; - [Dependency] private readonly PopupSystem _popup = default!; - [Dependency] private readonly TagSystem _tags = default!; - [Dependency] private readonly AudioSystem _soundSystem = default!; - [Dependency] private readonly SharedAppearanceSystem _appearanceSystem = default!; - - private const string RecyclerColliderName = "brrt"; - - private const float RecyclerSoundCooldown = 0.8f; - - public override void Initialize() - { - SubscribeLocalEvent(OnExamined); - SubscribeLocalEvent(OnCollide); - SubscribeLocalEvent(OnEmagged); - SubscribeLocalEvent(OnSuicide); - SubscribeLocalEvent(OnPowerChanged); - } - - private void OnExamined(EntityUid uid, RecyclerComponent component, ExaminedEvent args) - { - args.PushMarkup(Loc.GetString("recycler-count-items", ("items", component.ItemsProcessed))); - } - - private void OnSuicide(EntityUid uid, RecyclerComponent component, SuicideEvent args) - { - if (args.Handled) return; - args.SetHandled(SuicideKind.Bloodloss); - var victim = args.Victim; - if (TryComp(victim, out ActorComponent? actor) && - actor.PlayerSession.ContentData()?.Mind is { } mind) - { - _ticker.OnGhostAttempt(mind, false); - if (mind.OwnedEntity is { Valid: true } entity) - { - _popup.PopupEntity(Loc.GetString("recycler-component-suicide-message"), entity); - } - } - - _popup.PopupEntity(Loc.GetString("recycler-component-suicide-message-others", ("victim", Identity.Entity(victim, EntityManager))), - victim, - Filter.PvsExcept(victim, entityManager: EntityManager), true); - - if (TryComp(victim, out var body)) - { - _bodySystem.GibBody(victim, true, body); - } - - Bloodstain(component); - } - - public void EnableRecycler(RecyclerComponent component) - { - if (component.Enabled) return; - - component.Enabled = true; - - if (TryComp(component.Owner, out ApcPowerReceiverComponent? apcPower)) - { - _ambience.SetAmbience(component.Owner, apcPower.Powered); - } - else - { - _ambience.SetAmbience(component.Owner, true); - } - - } - - public void DisableRecycler(RecyclerComponent component) - { - if (!component.Enabled) return; - - component.Enabled = false; - _ambience.SetAmbience(component.Owner, false); - } - - private void OnPowerChanged(EntityUid uid, RecyclerComponent component, ref PowerChangedEvent args) - { - if (component.Enabled) - { - _ambience.SetAmbience(uid, args.Powered); - } - } - - private void OnCollide(EntityUid uid, RecyclerComponent component, ref StartCollideEvent args) - { - if (component.Enabled && args.OurFixture.ID != RecyclerColliderName) - return; - - if (TryComp(uid, out ApcPowerReceiverComponent? apcPower)) - { - if (!apcPower.Powered) - return; - } - - Recycle(component, args.OtherFixture.Body.Owner); - } - - private void Recycle(RecyclerComponent component, EntityUid entity) - { - RecyclableComponent? recyclable = null; - - // Can only recycle things that are tagged trash or recyclable... And also check the safety of the thing to recycle. - if (!_tags.HasAnyTag(entity, "Trash", "Recyclable") && - (!TryComp(entity, out recyclable) || !recyclable.Safe && !HasComp(component.Owner))) - { - return; - } - - // TODO: Prevent collision with recycled items - - // Mobs are a special case! - if (CanGib(component, entity)) - { - _bodySystem.GibBody(entity, true, Comp(entity)); - Bloodstain(component); - return; - } - - if (recyclable == null) - QueueDel(entity); - else - Recycle(recyclable, component.Efficiency); - - if (component.Sound != null && (_timing.CurTime - component.LastSound).TotalSeconds > RecyclerSoundCooldown) - { - _soundSystem.PlayPvs(component.Sound, component.Owner, AudioHelpers.WithVariation(0.01f).WithVolume(-3)); - component.LastSound = _timing.CurTime; - } - - component.ItemsProcessed++; - } - - private bool CanGib(RecyclerComponent component, EntityUid entity) - { - return HasComp(entity) && HasComp(component.Owner) && - this.IsPowered(component.Owner, EntityManager); - } - - public void Bloodstain(RecyclerComponent component) - { - if (EntityManager.TryGetComponent(component.Owner, out AppearanceComponent? appearance)) - { - _appearanceSystem.SetData(component.Owner, RecyclerVisuals.Bloody, true, appearance); - } - } - - private void Recycle(RecyclableComponent component, float efficiency = 1f) - { - if (!string.IsNullOrEmpty(component.Prototype)) - { - var xform = Transform(component.Owner); - - for (var i = 0; i < Math.Max(component.Amount * efficiency, 1); i++) - { - Spawn(component.Prototype, xform.Coordinates); - } - } - - QueueDel(component.Owner); - } - - private void OnEmagged(EntityUid uid, RecyclerComponent component, ref GotEmaggedEvent args) - { - // no fancy conditions - args.Handled = true; - } - } -} diff --git a/Content.Shared/Lathe/LatheComponent.cs b/Content.Shared/Lathe/LatheComponent.cs index 752eec5aba..4cfd94c80f 100644 --- a/Content.Shared/Lathe/LatheComponent.cs +++ b/Content.Shared/Lathe/LatheComponent.cs @@ -85,7 +85,7 @@ namespace Content.Shared.Lathe [DataField("partRatingMaterialUseMultiplier")] public float PartRatingMaterialUseMultiplier = DefaultPartRatingMaterialUseMultiplier; - public const float DefaultPartRatingMaterialUseMultiplier = 0.75f; + public const float DefaultPartRatingMaterialUseMultiplier = 0.85f; #endregion } diff --git a/Content.Shared/Materials/ActiveMaterialReclaimerComponent.cs b/Content.Shared/Materials/ActiveMaterialReclaimerComponent.cs new file mode 100644 index 0000000000..b62be502e3 --- /dev/null +++ b/Content.Shared/Materials/ActiveMaterialReclaimerComponent.cs @@ -0,0 +1,32 @@ +using Robust.Shared.Containers; +using Robust.Shared.GameStates; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; + +namespace Content.Shared.Materials; + +/// +/// Tracker component for the process of reclaiming entities +/// +/// +[RegisterComponent, NetworkedComponent, Access(typeof(SharedMaterialReclaimerSystem))] +public sealed class ActiveMaterialReclaimerComponent : Component +{ + /// + /// Container used to store the item currently being reclaimed + /// + [ViewVariables(VVAccess.ReadWrite)] + public Container ReclaimingContainer = default!; + + /// + /// When the reclaiming process ends. + /// + [DataField("endTime", customTypeSerializer: typeof(TimeOffsetSerializer)), ViewVariables(VVAccess.ReadWrite)] + public TimeSpan EndTime; + + /// + /// The length of the reclaiming process. + /// Used for calculations. + /// + [DataField("duration"), ViewVariables(VVAccess.ReadWrite)] + public TimeSpan Duration; +} diff --git a/Content.Shared/Materials/CollideMaterialReclaimerComponent.cs b/Content.Shared/Materials/CollideMaterialReclaimerComponent.cs new file mode 100644 index 0000000000..4d9b072ad2 --- /dev/null +++ b/Content.Shared/Materials/CollideMaterialReclaimerComponent.cs @@ -0,0 +1,16 @@ +namespace Content.Shared.Materials; + +/// +/// Valid items that collide with an entity with this component +/// will begin to be reclaimed. +/// +/// +[RegisterComponent] +public sealed class CollideMaterialReclaimerComponent : Component +{ + /// + /// The fixture that starts reclaiming on collision. + /// + [DataField("fixtureId")] + public string FixtureId = "brrt"; +} diff --git a/Content.Shared/Materials/MaterialReclaimerComponent.cs b/Content.Shared/Materials/MaterialReclaimerComponent.cs new file mode 100644 index 0000000000..aaaa656f65 --- /dev/null +++ b/Content.Shared/Materials/MaterialReclaimerComponent.cs @@ -0,0 +1,177 @@ +using Content.Shared.Chemistry.Components; +using Content.Shared.Construction.Prototypes; +using Content.Shared.Whitelist; +using Robust.Shared.Audio; +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; + +namespace Content.Shared.Materials; + +/// +/// This is a machine that handles converting entities +/// into the raw materials and chemicals that make them up. +/// +[RegisterComponent, NetworkedComponent, Access(typeof(SharedMaterialReclaimerSystem))] +public sealed class MaterialReclaimerComponent : Component +{ + /// + /// Whether or not the machine has power. We put it here + /// so we can network and predict it. + /// + [DataField("powered"), ViewVariables(VVAccess.ReadWrite)] + public bool Powered; + + /// + /// An "enable" toggle for things like interfacing with machine linking + /// + [DataField("enabled"), ViewVariables(VVAccess.ReadWrite)] + public bool Enabled = true; + + /// + /// How efficiently the materials are reclaimed. + /// In practice, a multiplier per material when calculating the output of the reclaimer. + /// + [DataField("efficiency"), ViewVariables(VVAccess.ReadWrite)] + public float Efficiency = 1f; + + /// + /// Whether or not the process + /// speed scales with the amount of materials being processed + /// or if it's just + /// + [DataField("scaleProcessSpeed")] + public bool ScaleProcessSpeed = true; + + /// + /// How quickly it takes to consume X amount of materials per second. + /// For example, with a rate of 50, an entity with 100 total material takes 2 seconds to process. + /// + [DataField("baseMaterialProcessRate"), ViewVariables(VVAccess.ReadWrite)] + public float BaseMaterialProcessRate = 100f; + + /// + /// How quickly it takes to consume X amount of materials per second. + /// For example, with a rate of 50, an entity with 100 total material takes 2 seconds to process. + /// + [DataField("materialProcessRate"), ViewVariables(VVAccess.ReadWrite)] + public float MaterialProcessRate = 100f; + + /// + /// Machine part whose rating modifies + /// + [DataField("machinePartProcessRate", customTypeSerializer: typeof(PrototypeIdSerializer)), ViewVariables(VVAccess.ReadWrite)] + public string MachinePartProcessRate = "Manipulator"; + + /// + /// How much the machine part quality affects the + /// + [DataField("partRatingProcessRateMultiplier"), ViewVariables(VVAccess.ReadWrite)] + public float PartRatingProcessRateMultiplier = 1.5f; + + /// + /// The minimum amount fo time it can take to process an entity. + /// this value supercedes the calculated one using + /// + [DataField("minimumProcessDuration"), ViewVariables(VVAccess.ReadWrite)] + public TimeSpan MinimumProcessDuration = TimeSpan.FromSeconds(0.5f); + + /// + /// The id of our output solution + /// + [DataField("solutionContainerId"), ViewVariables(VVAccess.ReadWrite)] + public string SolutionContainerId = "output"; + + /// + /// The prototype for the puddle + /// + [DataField("puddleId", customTypeSerializer: typeof(PrototypeIdSerializer)), ViewVariables(VVAccess.ReadWrite)] + public string PuddleId = "PuddleSmear"; + + /// + /// The solution itself. + /// + [ViewVariables(VVAccess.ReadWrite)] + public Solution OutputSolution = default!; + + /// + /// a whitelist for what entities can be inserted into this reclaimer + /// + [DataField("whitelist")] + public EntityWhitelist? Whitelist; + + /// + /// a blacklist for what entities cannot be inserted into this reclaimer + /// + [DataField("blacklist")] + public EntityWhitelist? Blacklist; + + /// + /// The sound played when something is being processed. + /// + [DataField("sound")] + public SoundSpecifier? Sound; + + /// + /// whether or not we cut off the sound early when the reclaiming ends. + /// + [DataField("cutOffSound")] + public bool CutOffSound = true; + + /// + /// When the next sound will be allowed to be played. Used to prevent spam. + /// + [DataField("nextSound", customTypeSerializer: typeof(TimeOffsetSerializer))] + public TimeSpan NextSound; + + /// + /// Minimum time inbetween each + /// + [DataField("soundCooldown")] + public TimeSpan SoundCooldown = TimeSpan.FromSeconds(0.8f); + + public IPlayingAudioStream? Stream; + + /// + /// A counter of how many items have been processed + /// + /// + /// I saw this on the recycler and i'm porting it because it's cute af + /// + [DataField("itemsProcessed")] + public int ItemsProcessed; +} + +[Serializable, NetSerializable] +public sealed class MaterialReclaimerComponentState : ComponentState +{ + public bool Powered; + + public bool Enabled; + + public float MaterialProcessRate; + + public int ItemsProcessed; + + public MaterialReclaimerComponentState(bool powered, bool enabled, float materialProcessRate, int itemsProcessed) + { + Powered = powered; + Enabled = enabled; + MaterialProcessRate = materialProcessRate; + ItemsProcessed = itemsProcessed; + } +} + +[NetSerializable, Serializable] +public enum RecyclerVisuals +{ + Bloody +} + +public enum RecyclerVisualLayers : byte +{ + Main, + Bloody +} diff --git a/Content.Shared/Materials/MaterialStorageComponent.cs b/Content.Shared/Materials/MaterialStorageComponent.cs index 491c4d3cb7..71b4056042 100644 --- a/Content.Shared/Materials/MaterialStorageComponent.cs +++ b/Content.Shared/Materials/MaterialStorageComponent.cs @@ -15,6 +15,12 @@ public sealed class MaterialStorageComponent : Component [DataField("storage", customTypeSerializer: typeof(PrototypeIdDictionarySerializer))] public Dictionary Storage { get; set; } = new(); + /// + /// Whether or not interacting with the materialstorage inserts the material in hand. + /// + [DataField("insertOnInteract")] + public bool InsertOnInteract = true; + /// /// How much material the storage can store in total. /// diff --git a/Content.Shared/Materials/PhysicalCompositionComponent.cs b/Content.Shared/Materials/PhysicalCompositionComponent.cs new file mode 100644 index 0000000000..2d23a8ccf6 --- /dev/null +++ b/Content.Shared/Materials/PhysicalCompositionComponent.cs @@ -0,0 +1,30 @@ +using Content.Shared.Chemistry.Reagent; +using Content.Shared.FixedPoint; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Dictionary; + +namespace Content.Shared.Materials; + +/// +/// This is used for assigning an innate material/chemical composition to an entity. +/// These aren't materials per se, but rather the materials which "make up" an entity. +/// This also isn't something that should exist simultaneously with . +/// +/// +/// The reason for duel material/chemical is for the eventual +/// combination of the two systems. +/// +[RegisterComponent] +public sealed class PhysicalCompositionComponent : Component +{ + /// + /// The materials that "make up" this entity + /// + [DataField("materialComposition", customTypeSerializer: typeof(PrototypeIdDictionarySerializer))] + public Dictionary MaterialComposition = new(); + + /// + /// The chemicals that "make up" this entity + /// + [DataField("chemicalComposition", customTypeSerializer: typeof(PrototypeIdDictionarySerializer))] + public Dictionary ChemicalComposition = new(); +} diff --git a/Content.Shared/Materials/SharedMaterialReclaimerSystem.cs b/Content.Shared/Materials/SharedMaterialReclaimerSystem.cs new file mode 100644 index 0000000000..18a744e80d --- /dev/null +++ b/Content.Shared/Materials/SharedMaterialReclaimerSystem.cs @@ -0,0 +1,249 @@ +using System.Linq; +using Content.Shared.Administration.Logs; +using Content.Shared.Audio; +using Content.Shared.Body.Components; +using Content.Shared.Database; +using Content.Shared.Emag.Components; +using Content.Shared.Emag.Systems; +using Content.Shared.Examine; +using Content.Shared.Mobs.Components; +using Content.Shared.Stacks; +using Robust.Shared.Containers; +using Robust.Shared.GameStates; +using Robust.Shared.Physics.Events; +using Robust.Shared.Timing; + +namespace Content.Shared.Materials; + +/// +/// Handles interactions and logic related to , +/// , and . +/// +public abstract class SharedMaterialReclaimerSystem : EntitySystem +{ + [Dependency] private readonly ISharedAdminLogManager _adminLog = default!; + [Dependency] protected readonly IGameTiming Timing = default!; + [Dependency] protected readonly SharedAmbientSoundSystem AmbientSound = default!; + [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly SharedContainerSystem _container = default!; + + public const string ActiveReclaimerContainerId = "active-material-reclaimer-container"; + + /// + public override void Initialize() + { + SubscribeLocalEvent(OnGetState); + SubscribeLocalEvent(OnHandleState); + SubscribeLocalEvent(OnUnpaused); + SubscribeLocalEvent(OnExamined); + SubscribeLocalEvent(OnEmagged); + SubscribeLocalEvent(OnCollide); + SubscribeLocalEvent(OnActiveStartup); + SubscribeLocalEvent(OnActiveUnpaused); + } + + private void OnGetState(EntityUid uid, MaterialReclaimerComponent component, ref ComponentGetState args) + { + args.State = new MaterialReclaimerComponentState(component.Powered, + component.Enabled, + component.MaterialProcessRate, + component.ItemsProcessed); + } + + private void OnHandleState(EntityUid uid, MaterialReclaimerComponent component, ref ComponentHandleState args) + { + if (args.Current is not MaterialReclaimerComponentState state) + return; + component.Powered = state.Powered; + component.Enabled = state.Enabled; + component.MaterialProcessRate = state.MaterialProcessRate; + component.ItemsProcessed = state.ItemsProcessed; + } + + private void OnUnpaused(EntityUid uid, MaterialReclaimerComponent component, ref EntityUnpausedEvent args) + { + component.NextSound += args.PausedTime; + } + + private void OnExamined(EntityUid uid, MaterialReclaimerComponent component, ExaminedEvent args) + { + args.PushMarkup(Loc.GetString("recycler-count-items", ("items", component.ItemsProcessed))); + } + + private void OnEmagged(EntityUid uid, MaterialReclaimerComponent component, ref GotEmaggedEvent args) + { + args.Handled = true; + } + + private void OnCollide(EntityUid uid, CollideMaterialReclaimerComponent component, ref StartCollideEvent args) + { + if (args.OurFixture.ID != component.FixtureId) + return; + if (!TryComp(uid, out var reclaimer)) + return; + TryStartProcessItem(uid, args.OtherFixture.Body.Owner, reclaimer); + } + + private void OnActiveStartup(EntityUid uid, ActiveMaterialReclaimerComponent component, ComponentStartup args) + { + component.ReclaimingContainer = _container.EnsureContainer(uid, ActiveReclaimerContainerId); + } + + private void OnActiveUnpaused(EntityUid uid, ActiveMaterialReclaimerComponent component, ref EntityUnpausedEvent args) + { + component.EndTime += args.PausedTime; + } + + /// + /// Tries to start processing an item via a . + /// + public bool TryStartProcessItem(EntityUid uid, EntityUid item, MaterialReclaimerComponent? component = null, EntityUid? user = null) + { + if (!Resolve(uid, ref component)) + return false; + + if (!CanStart(uid, component)) + return false; + + if (component.Whitelist != null && !component.Whitelist.IsValid(item) || + HasComp(item) && !CanGib(uid, item, component)) // whitelist? We be gibbing, boy! + return false; + + if (component.Blacklist != null && component.Blacklist.IsValid(item)) + return false; + + if (user != null) + { + _adminLog.Add(LogType.Action, LogImpact.High, + $"{ToPrettyString(user.Value):player} destroyed {ToPrettyString(item)} in the material reclaimer, {ToPrettyString(uid)}"); + } + + if (Timing.CurTime > component.NextSound) + component.Stream = _audio.PlayPvs(component.Sound, uid); + component.NextSound = Timing.CurTime + component.SoundCooldown; + + var duration = GetReclaimingDuration(uid, item, component); + // if it's instant, don't bother with all the active comp stuff. + if (duration == TimeSpan.Zero) + { + Reclaim(uid, item, 1, component); + return true; + } + + var active = EnsureComp(uid); + active.Duration = duration; + active.EndTime = Timing.CurTime + duration; + active.ReclaimingContainer.Insert(item); + return true; + } + + /// + /// Finishes processing an item, freeing up the the reclaimer. + /// + /// + /// This doesn't reclaim the entity itself, but rather ends the formal + /// process started with . + /// The actual reclaiming happens in + /// + public virtual bool TryFinishProcessItem(EntityUid uid, MaterialReclaimerComponent? component = null, ActiveMaterialReclaimerComponent? active = null) + { + if (!Resolve(uid, ref component, ref active, false)) + return false; + + RemCompDeferred(uid, active); + return true; + } + + /// + /// Spawns the materials and chemicals associated + /// with an entity. Also deletes the item. + /// + public virtual void Reclaim(EntityUid uid, + EntityUid item, + float completion = 1f, + MaterialReclaimerComponent? component = null) + { + if (!Resolve(uid, ref component)) + return; + + component.ItemsProcessed++; + if (component.CutOffSound) + component.Stream?.Stop(); + + Dirty(component); + } + + /// + /// Sets the Enabled field on the reclaimer. + /// + public void SetReclaimerEnabled(EntityUid uid, bool enabled, MaterialReclaimerComponent? component = null) + { + if (!Resolve(uid, ref component, false)) + return; + component.Enabled = enabled; + AmbientSound.SetAmbience(uid, enabled && component.Powered); + Dirty(component); + } + + /// + /// Whether or not the specified reclaimer can currently + /// begin reclaiming another entity. + /// + public bool CanStart(EntityUid uid, MaterialReclaimerComponent component) + { + if (HasComp(uid)) + return false; + + return component.Powered && component.Enabled; + } + + /// + /// Whether or not the reclaimer satisfies the conditions + /// allowing it to gib/reclaim a living creature. + /// + public bool CanGib(EntityUid uid, EntityUid victim, MaterialReclaimerComponent component) + { + return component.Powered && + component.Enabled && + HasComp(victim) && + HasComp(uid); + } + + /// + /// Gets the duration of processing a specified entity. + /// Processing is calculated from the sum of the materials within the entity. + /// It does not regard the chemicals within it. + /// + public TimeSpan GetReclaimingDuration(EntityUid reclaimer, + EntityUid item, + MaterialReclaimerComponent? reclaimerComponent = null, + PhysicalCompositionComponent? compositionComponent = null) + { + if (!Resolve(reclaimer, ref reclaimerComponent)) + return TimeSpan.Zero; + + if (!reclaimerComponent.ScaleProcessSpeed || + !Resolve(item, ref compositionComponent, false)) + return reclaimerComponent.MinimumProcessDuration; + + var materialSum = compositionComponent.MaterialComposition.Values.Sum(); + materialSum *= CompOrNull(item)?.Count ?? 1; + var duration = TimeSpan.FromSeconds(materialSum / reclaimerComponent.MaterialProcessRate); + if (duration < reclaimerComponent.MinimumProcessDuration) + duration = reclaimerComponent.MinimumProcessDuration; + return duration; + } + + /// + public override void Update(float frameTime) + { + base.Update(frameTime); + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var uid, out var active, out var reclaimer)) + { + if (Timing.CurTime < active.EndTime) + continue; + TryFinishProcessItem(uid, reclaimer, active); + } + } +} diff --git a/Content.Shared/Materials/SharedMaterialStorageSystem.cs b/Content.Shared/Materials/SharedMaterialStorageSystem.cs index 2ade6b5705..7daea6977b 100644 --- a/Content.Shared/Materials/SharedMaterialStorageSystem.cs +++ b/Content.Shared/Materials/SharedMaterialStorageSystem.cs @@ -252,7 +252,7 @@ public abstract class SharedMaterialStorageSystem : EntitySystem private void OnInteractUsing(EntityUid uid, MaterialStorageComponent component, InteractUsingEvent args) { - if (args.Handled) + if (args.Handled || !component.InsertOnInteract) return; args.Handled = TryInsertMaterialEntity(args.User, args.Used, uid, component); } diff --git a/Content.Shared/Recycling/SharedRecyclerComponent.cs b/Content.Shared/Recycling/SharedRecyclerComponent.cs deleted file mode 100644 index 33cbc5165c..0000000000 --- a/Content.Shared/Recycling/SharedRecyclerComponent.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Robust.Shared.Serialization; - -namespace Content.Shared.Recycling -{ - [NetSerializable, Serializable] - public enum RecyclerVisuals - { - Bloody - } -} diff --git a/Resources/Audio/Ambience/Objects/attributions.yml b/Resources/Audio/Ambience/Objects/attributions.yml index 8322c91a48..c084f551c7 100644 --- a/Resources/Audio/Ambience/Objects/attributions.yml +++ b/Resources/Audio/Ambience/Objects/attributions.yml @@ -1,4 +1,9 @@ - files: ["anomaly_generator.ogg"] license: "CC0-1.0" copyright: "Created by steaq, converted Mono and .ogg by EmoGarbage" - source: "https://freesound.org/people/steaq/sounds/509249/" \ No newline at end of file + source: "https://freesound.org/people/steaq/sounds/509249/" + +- files: ["crushing.ogg"] + license: "CC-BY-4.0" + copyright: "Created by juskiddink, converted Mono and .ogg by EmoGarbage" + source: "https://freesound.org/people/juskiddink/sounds/66956/" \ No newline at end of file diff --git a/Resources/Audio/Ambience/Objects/crushing.ogg b/Resources/Audio/Ambience/Objects/crushing.ogg new file mode 100644 index 0000000000..401ae15f6f Binary files /dev/null and b/Resources/Audio/Ambience/Objects/crushing.ogg differ diff --git a/Resources/Locale/en-US/materials/materials.ftl b/Resources/Locale/en-US/materials/materials.ftl index f3cb457d73..336b7f1206 100644 --- a/Resources/Locale/en-US/materials/materials.ftl +++ b/Resources/Locale/en-US/materials/materials.ftl @@ -18,3 +18,6 @@ materials-plasma = plasma materials-plastic = plastic materials-wood = wood materials-uranium = uranium + +# Material Reclaimer +material-reclaimer-upgrade-process-rate = process rate \ No newline at end of file diff --git a/Resources/Prototypes/Body/Parts/silicon.yml b/Resources/Prototypes/Body/Parts/silicon.yml index 90e682282f..266c1dd5a6 100644 --- a/Resources/Prototypes/Body/Parts/silicon.yml +++ b/Resources/Prototypes/Body/Parts/silicon.yml @@ -16,6 +16,9 @@ - type: Tag tags: - Trash + - type: PhysicalComposition + materialComposition: + Steel: 25 - type: entity id: LeftArmBorg @@ -36,7 +39,6 @@ tags: - Trash - BorgArm - - type: Recyclable - type: entity id: RightArmBorg @@ -57,4 +59,3 @@ tags: - Trash - BorgArm - - type: Recyclable diff --git a/Resources/Prototypes/Catalog/Research/technologies.yml b/Resources/Prototypes/Catalog/Research/technologies.yml index 5c605abffc..f10f43bd7a 100644 --- a/Resources/Prototypes/Catalog/Research/technologies.yml +++ b/Resources/Prototypes/Catalog/Research/technologies.yml @@ -364,6 +364,7 @@ - SheetPlastic - SheetRGlass - SheetGlass1 + - MaterialReclaimerMachineCircuitboard # Electromagnetic Theory Technology Tree diff --git a/Resources/Prototypes/Entities/Clothing/Belt/base_clothingbelt.yml b/Resources/Prototypes/Entities/Clothing/Belt/base_clothingbelt.yml index d23807a1fa..0c400828d8 100644 --- a/Resources/Prototypes/Entities/Clothing/Belt/base_clothingbelt.yml +++ b/Resources/Prototypes/Entities/Clothing/Belt/base_clothingbelt.yml @@ -10,6 +10,11 @@ - type: Clothing slots: [belt] quickEquip: false + - type: PhysicalComposition + materialComposition: + Cloth: 50 + - type: StaticPrice + price: 25 - type: entity abstract: true diff --git a/Resources/Prototypes/Entities/Clothing/Head/misc.yml b/Resources/Prototypes/Entities/Clothing/Head/misc.yml index 1f1a8b4146..b010f1a978 100644 --- a/Resources/Prototypes/Entities/Clothing/Head/misc.yml +++ b/Resources/Prototypes/Entities/Clothing/Head/misc.yml @@ -125,6 +125,9 @@ sprite: Clothing/Head/Misc/cone.rsi - type: Clothing sprite: Clothing/Head/Misc/cone.rsi + - type: PhysicalComposition #you can't just pass up some free plastic! + materialComposition: + Plastic: 100 - type: entity parent: ClothingHeadBase diff --git a/Resources/Prototypes/Entities/Clothing/Head/welding.yml b/Resources/Prototypes/Entities/Clothing/Head/welding.yml index f410104784..94254e625f 100644 --- a/Resources/Prototypes/Entities/Clothing/Head/welding.yml +++ b/Resources/Prototypes/Entities/Clothing/Head/welding.yml @@ -8,6 +8,12 @@ - type: FlashImmunity - type: IdentityBlocker - type: EyeProtection + - type: PhysicalComposition + materialComposition: + Steel: 500 + Glass: 100 + - type: StaticPrice + price: 50 - type: entity parent: WeldingMaskBase diff --git a/Resources/Prototypes/Entities/Clothing/Masks/masks.yml b/Resources/Prototypes/Entities/Clothing/Masks/masks.yml index 3f5d9f8755..1298ac5322 100644 --- a/Resources/Prototypes/Entities/Clothing/Masks/masks.yml +++ b/Resources/Prototypes/Entities/Clothing/Masks/masks.yml @@ -137,7 +137,10 @@ - type: Tag tags: - PetWearable - - type: Recyclable + - type: PhysicalComposition + materialComposition: + Steel: 50 + Plastic: 100 - type: entity parent: ClothingMaskBase diff --git a/Resources/Prototypes/Entities/Clothing/OuterClothing/hardsuits.yml b/Resources/Prototypes/Entities/Clothing/OuterClothing/hardsuits.yml index c3946c6606..08fd95b278 100644 --- a/Resources/Prototypes/Entities/Clothing/OuterClothing/hardsuits.yml +++ b/Resources/Prototypes/Entities/Clothing/OuterClothing/hardsuits.yml @@ -259,6 +259,10 @@ sprintModifier: 0.75 - type: Item size: 100 + - type: Tag + tags: + - WhitelistChameleon + - HighRiskItem - type: ExplosionResistance damageCoefficient: 0.1 - type: ToggleableClothing diff --git a/Resources/Prototypes/Entities/Clothing/Shoes/magboots.yml b/Resources/Prototypes/Entities/Clothing/Shoes/magboots.yml index f8398f93d0..6fc0525604 100644 --- a/Resources/Prototypes/Entities/Clothing/Shoes/magboots.yml +++ b/Resources/Prototypes/Entities/Clothing/Shoes/magboots.yml @@ -58,6 +58,10 @@ sprintModifier: 1 enabled: false - type: NoSlip + - type: Tag + tags: + - WhitelistChameleon + - HighRiskItem - type: StaticPrice price: 750 diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml index bc42856392..5bd5deb20b 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml @@ -824,7 +824,6 @@ tags: - Trash - CannotSuicide - - type: Recyclable - type: Respirator damage: types: @@ -1997,7 +1996,6 @@ tags: - Trash - CannotSuicide - - type: Recyclable - type: Respirator damage: types: diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/silicon.yml b/Resources/Prototypes/Entities/Mobs/NPCs/silicon.yml index e708eb9d9b..5dcc5ec98a 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/silicon.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/silicon.yml @@ -38,8 +38,6 @@ noRot: true drawdepth: Mobs netsync: false - - type: Recyclable - safe: false - type: Faction factions: - SimpleNeutral diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/simplemob.yml b/Resources/Prototypes/Entities/Mobs/NPCs/simplemob.yml index e5e7efcf2c..71ed356e28 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/simplemob.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/simplemob.yml @@ -139,8 +139,6 @@ - type: Polymorphable - type: Pullable - type: Buckle - - type: Recyclable - safe: false - type: StandingState - type: Alerts - type: NameIdentifier diff --git a/Resources/Prototypes/Entities/Mobs/Player/silicon.yml b/Resources/Prototypes/Entities/Mobs/Player/silicon.yml index 8c7181b00c..7a12adb345 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/silicon.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/silicon.yml @@ -56,8 +56,6 @@ - type: Pullable - type: Examiner - type: Puller - - type: Recyclable - safe: false - type: StandingState - type: Alerts - type: Tag diff --git a/Resources/Prototypes/Entities/Mobs/Species/base.yml b/Resources/Prototypes/Entities/Mobs/Species/base.yml index d49205a2a3..fea68b0c2a 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/base.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/base.yml @@ -280,8 +280,6 @@ spawned: - id: FoodMeat amount: 5 - # - type: Recyclable Turns out turning off recycler safeties without considering the instagib is a bad idea - # safe: false - type: Speech speechSounds: Alto - type: Vocal diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks.yml b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks.yml index 6e2d74a855..1e355ec798 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks.yml @@ -72,6 +72,9 @@ damage: types: Blunt: 5 + - type: PhysicalComposition + materialComposition: + Glass: 25 # Transformable container - normal glass - type: entity @@ -2164,7 +2167,6 @@ - type: Tag tags: - Trash - - type: Recyclable - type: SpaceGarbage - type: entity diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_cans.yml b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_cans.yml index 4a40578fd4..b03d917559 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_cans.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_cans.yml @@ -51,10 +51,12 @@ types: Blunt: 0 - type: ItemCooldown - - type: Recyclable - type: SpaceGarbage - type: TrashOnEmpty solution: drink + - type: PhysicalComposition + materialComposition: + Steel: 50 #reduce, reuse, recycle - type: entity parent: DrinkCanBaseFull diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_cups.yml b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_cups.yml index 1d15533407..c91593bfc2 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_cups.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_cups.yml @@ -66,6 +66,9 @@ - type: SolutionContainerVisuals maxFillLevels: 3 fillBaseName: icon- + - type: PhysicalComposition + materialComposition: + Glass: 25 - type: entity parent: DrinkBaseMug @@ -130,6 +133,9 @@ components: - type: Sprite sprite: Objects/Consumable/Drinks/mug_metal.rsi + - type: PhysicalComposition + materialComposition: + Steel: 25 - type: entity parent: DrinkBaseMug diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_flasks.yml b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_flasks.yml index d2a5a52f3c..ae2daac052 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_flasks.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_flasks.yml @@ -7,6 +7,9 @@ - type: Drink - type: Sprite sprite: Objects/Consumable/Drinks/shinyflask.rsi + - type: PhysicalComposition + materialComposition: + Steel: 50 - type: entity parent: DrinkBase diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_special.yml b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_special.yml index 2fbc947041..684681074e 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_special.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_special.yml @@ -29,6 +29,9 @@ interfaces: - key: enum.TransferAmountUiKey.Key type: TransferAmountBoundUserInterface + - type: PhysicalComposition + materialComposition: + Steel: 50 - type: entity parent: DrinkGlassBase diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/trash_drinks.yml b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/trash_drinks.yml index 03b04d7e55..a1a1eef3f3 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/trash_drinks.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/trash_drinks.yml @@ -68,7 +68,9 @@ - type: Tag tags: - Trash - - type: Recyclable + - type: PhysicalComposition + materialComposition: + Glass: 100 - type: SpaceGarbage # Containers diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/bowl.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/bowl.yml index e6392877f3..04693e0596 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/bowl.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/bowl.yml @@ -69,7 +69,9 @@ - type: Tag tags: - Trash - - type: Recyclable + - type: PhysicalComposition + materialComposition: + Glass: 50 - type: SpaceGarbage - type: StaticPrice price: 0 diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/plate.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/plate.yml index 39f2bfa1a8..f5b0ff6880 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/plate.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/plate.yml @@ -45,7 +45,9 @@ - type: Tag tags: - Trash - - type: Recyclable + - type: PhysicalComposition + materialComposition: + Glass: 100 - type: SpaceGarbage - type: entity @@ -61,7 +63,6 @@ - type: Tag tags: - Trash - - type: Recyclable - type: SpaceGarbage # Small Plate @@ -147,5 +148,7 @@ - type: Tag tags: - Trash - - type: Recyclable + - type: PhysicalComposition + materialComposition: + Steel: 100 - type: SpaceGarbage diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/tin.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/tin.yml index 84bbb670be..80129c01e0 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/tin.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/tin.yml @@ -28,6 +28,9 @@ Blunt: 3 - type: Damageable damageContainer: Inorganic + - type: PhysicalComposition + materialComposition: + Steel: 100 - type: entity abstract: true @@ -46,6 +49,9 @@ - type: Tag tags: - Trash + - type: PhysicalComposition + materialComposition: + Steel: 100 # Tins # Need something that you can open these tins with. I suggest a prying or cutting tool. diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/egg.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/egg.yml index 41eb9ca924..9ecfae3324 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/egg.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/egg.yml @@ -110,7 +110,6 @@ tags: - Egg - Trash - - type: Recyclable - type: SpaceGarbage # Egg diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/food_base.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/food_base.yml index 31c120b6aa..a9f0609914 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/food_base.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/food_base.yml @@ -10,7 +10,6 @@ flavors: - food - type: Food - - type: Recyclable - type: SpaceGarbage - type: Sprite netsync: false diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/frozen.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/frozen.yml index c9e973ff14..12b93c35a8 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/frozen.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/frozen.yml @@ -275,5 +275,4 @@ - type: Tag tags: - Trash - - type: Recyclable - type: SpaceGarbage diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/meat.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/meat.yml index 925d5f86ab..8c8c35388d 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/meat.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/meat.yml @@ -225,6 +225,7 @@ - type: Tag tags: - Raw + - HighRiskItem - type: Sprite state: corgi - type: SolutionContainerManager diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/produce.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/produce.yml index 1c8d38aa78..d20aacdc1f 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/produce.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/produce.yml @@ -213,7 +213,6 @@ Quantity: 4 - type: Extractable grindableSolutionName: food - - type: Recyclable - type: SpaceGarbage - type: entity diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/snacks.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/snacks.yml index bfa59aaf64..ee0c29fbe9 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/snacks.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/snacks.yml @@ -387,7 +387,9 @@ - type: Tag tags: - Trash - - type: Recyclable + - type: PhysicalComposition + materialComposition: + Steel: 100 - type: SpaceGarbage - type: StaticPrice price: 0 diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Smokeables/Cigarettes/cartons.yml b/Resources/Prototypes/Entities/Objects/Consumable/Smokeables/Cigarettes/cartons.yml index d7cc6a01fb..52fa3dd50b 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Smokeables/Cigarettes/cartons.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Smokeables/Cigarettes/cartons.yml @@ -24,7 +24,9 @@ - type: Tag tags: - Trash - - type: Recyclable + - type: PhysicalComposition + materialComposition: + Plastic: 50 - type: SpaceGarbage - type: entity diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Smokeables/Cigarettes/cigarette.yml b/Resources/Prototypes/Entities/Objects/Consumable/Smokeables/Cigarettes/cigarette.yml index 65e4772bff..777d396869 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Smokeables/Cigarettes/cigarette.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Smokeables/Cigarettes/cigarette.yml @@ -12,7 +12,6 @@ tags: - Cigarette - Trash - - type: Recyclable - type: SpaceGarbage - type: Clothing sprite: Objects/Consumable/Smokeables/Cigarettes/cigarette.rsi diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Smokeables/Cigarettes/joints.yml b/Resources/Prototypes/Entities/Objects/Consumable/Smokeables/Cigarettes/joints.yml index 0e4a78bca0..42aa84d43d 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Smokeables/Cigarettes/joints.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Smokeables/Cigarettes/joints.yml @@ -12,7 +12,6 @@ tags: - Cigarette - Trash - - type: Recyclable - type: SpaceGarbage - type: Clothing sprite: Objects/Consumable/Smokeables/Cannabis/joint.rsi @@ -45,7 +44,6 @@ tags: - Cigarette - Trash - - type: Recyclable - type: SpaceGarbage - type: Clothing sprite: Objects/Consumable/Smokeables/Cannabis/blunt.rsi diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Smokeables/Cigarettes/packs.yml b/Resources/Prototypes/Entities/Objects/Consumable/Smokeables/Cigarettes/packs.yml index c508333057..0368c599ac 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Smokeables/Cigarettes/packs.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Smokeables/Cigarettes/packs.yml @@ -8,7 +8,9 @@ tags: - CigPack - Trash - - type: Recyclable + - type: PhysicalComposition + materialComposition: + Steel: 50 - type: SpaceGarbage - type: Storage capacity: 6 diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Smokeables/Cigarettes/rolling_paper.yml b/Resources/Prototypes/Entities/Objects/Consumable/Smokeables/Cigarettes/rolling_paper.yml index e62db9e40f..c4b53f45b5 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Smokeables/Cigarettes/rolling_paper.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Smokeables/Cigarettes/rolling_paper.yml @@ -59,7 +59,6 @@ tags: - RollingPaper - Trash - - type: Recyclable - type: SpaceGarbage - type: entity @@ -90,7 +89,6 @@ tags: - CigFilter - Trash - - type: Recyclable - type: entity id: CigaretteFilter1 diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Smokeables/base_smokeables.yml b/Resources/Prototypes/Entities/Objects/Consumable/Smokeables/base_smokeables.yml index ef58235903..c534b73094 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Smokeables/base_smokeables.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Smokeables/base_smokeables.yml @@ -13,7 +13,6 @@ - type: Tag tags: - Trash - - type: Recyclable - type: SpaceGarbage - type: StaticPrice price: 5 @@ -50,14 +49,14 @@ bowl_slot: !type:ContainerSlot - type: ItemSlots - type: SmokingPipe - bowl_slot: + bowl_slot: name: Bowl whitelist: tags: - Smokable - insertSound: + insertSound: path: /Audio/Weapons/Guns/Empty/empty.ogg - ejectSound: + ejectSound: path: /Audio/Weapons/Guns/Empty/empty.ogg - type: SolutionContainerManager solutions: diff --git a/Resources/Prototypes/Entities/Objects/Decoration/present.yml b/Resources/Prototypes/Entities/Objects/Decoration/present.yml index 3a7d059e9f..c5a308591c 100644 --- a/Resources/Prototypes/Entities/Objects/Decoration/present.yml +++ b/Resources/Prototypes/Entities/Objects/Decoration/present.yml @@ -376,5 +376,4 @@ - type: Tag tags: - Trash - - type: Recyclable - type: SpaceGarbage diff --git a/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/base_machineboard.yml b/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/base_machineboard.yml index 0ff99e2902..f11e2021c6 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/base_machineboard.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/base_machineboard.yml @@ -14,3 +14,9 @@ - DroneUsable - type: StaticPrice price: 100 + - type: PhysicalComposition + materialComposition: + Glass: 400 + chemicalComposition: + Silicon: 20 + diff --git a/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/production.yml b/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/production.yml index adc52ac563..4ace8ea4f0 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/production.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/production.yml @@ -466,6 +466,11 @@ materialRequirements: CableMV: 5 CableHV: 5 + - type: PhysicalComposition + materialComposition: + Glass: 200 + chemicalComposition: + Silicon: 20 - type: entity parent: BaseMachineCircuitboard @@ -515,6 +520,11 @@ Capacitor: 1 materialRequirements: CableHV: 5 + - type: PhysicalComposition + materialComposition: + Glass: 200 + chemicalComposition: + Silicon: 20 - type: entity id: ThrusterMachineCircuitboard @@ -555,6 +565,11 @@ Capacitor: 2 materialRequirements: CableHV: 10 + - type: PhysicalComposition + materialComposition: + Glass: 200 + chemicalComposition: + Silicon: 20 - type: entity id: ReagentGrinderMachineCircuitboard @@ -611,6 +626,21 @@ DefaultPrototype: CryostasisBeaker ExamineName: Cryostasis Beaker +- type: entity + id: MaterialReclaimerMachineCircuitboard + parent: BaseMachineCircuitboard + name: material reclaimer machine board + components: + - type: Sprite + state: supply + - type: MachineBoard + prototype: MaterialReclaimer + requirements: + Manipulator: 2 + materialRequirements: + Steel: 5 + Plastic: 5 + - type: entity id: OreProcessorMachineCircuitboard parent: BaseMachineCircuitboard @@ -726,7 +756,7 @@ materialRequirements: Steel: 10 Plasma: 5 - + - type: entity id: BoozeDispenserMachineCircuitboard parent: BaseMachineCircuitboard @@ -766,7 +796,7 @@ - type: entity id: TelecomServerCircuitboard parent: BaseMachineCircuitboard - name: telecommunication server machine board + name: telecommunication server machine board description: A machine printed circuit board for an telecommunication server. components: - type: MachineBoard diff --git a/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/computer.yml b/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/computer.yml index 25e3ef4181..bfe7cfc64e 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/computer.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/computer.yml @@ -13,6 +13,11 @@ - DroneUsable - type: StaticPrice price: 100 + - type: PhysicalComposition + materialComposition: + Glass: 400 + chemicalComposition: + Silicon: 20 - type: entity parent: BaseComputerCircuitboard @@ -68,6 +73,10 @@ prototype: ComputerCargoOrders - type: StaticPrice price: 750 + - type: Tag + tags: + - DroneUsable + - HighRiskItem - type: entity parent: BaseComputerCircuitboard @@ -178,6 +187,10 @@ prototype: ComputerId - type: StaticPrice price: 750 + - type: Tag + tags: + - DroneUsable + - HighRiskItem - type: entity parent: BaseComputerCircuitboard diff --git a/Resources/Prototypes/Entities/Objects/Devices/Electronics/base_electronics.yml b/Resources/Prototypes/Entities/Objects/Devices/Electronics/base_electronics.yml index e4f789f1f3..ec24e4be15 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/Electronics/base_electronics.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/Electronics/base_electronics.yml @@ -14,3 +14,8 @@ - DroneUsable - type: StaticPrice price: 100 + - type: PhysicalComposition + materialComposition: + Glass: 200 + chemicalComposition: + Silicon: 20 diff --git a/Resources/Prototypes/Entities/Objects/Devices/Electronics/power_electronics.yml b/Resources/Prototypes/Entities/Objects/Devices/Electronics/power_electronics.yml index 7adc3a1095..5b48ede4c1 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/Electronics/power_electronics.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/Electronics/power_electronics.yml @@ -10,6 +10,11 @@ sprite: Objects/Misc/module.rsi state: charger_APC netsync: false + - type: PhysicalComposition + materialComposition: + Glass: 50 + chemicalComposition: + Silicon: 20 # Wallmount Substation - type: entity diff --git a/Resources/Prototypes/Entities/Objects/Devices/hand_teleporter.yml b/Resources/Prototypes/Entities/Objects/Devices/hand_teleporter.yml index 55839ada54..0acd4fbf19 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/hand_teleporter.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/hand_teleporter.yml @@ -9,3 +9,6 @@ layers: - state: icon - type: HandTeleporter + - type: Tag + tags: + - HighRiskItem diff --git a/Resources/Prototypes/Entities/Objects/Fun/crayons.yml b/Resources/Prototypes/Entities/Objects/Fun/crayons.yml index 0dc6cb3045..d0856c64f4 100644 --- a/Resources/Prototypes/Entities/Objects/Fun/crayons.yml +++ b/Resources/Prototypes/Entities/Objects/Fun/crayons.yml @@ -10,7 +10,6 @@ - Write - Crayon - Trash - - type: Recyclable - type: SpaceGarbage - type: UserInterface interfaces: diff --git a/Resources/Prototypes/Entities/Objects/Fun/toys.yml b/Resources/Prototypes/Entities/Objects/Fun/toys.yml index 848993121c..ca7504c063 100644 --- a/Resources/Prototypes/Entities/Objects/Fun/toys.yml +++ b/Resources/Prototypes/Entities/Objects/Fun/toys.yml @@ -26,6 +26,11 @@ damage: types: Blunt: 0 + - type: PhysicalComposition + materialComposition: + Cloth: 100 + - type: StaticPrice + price: 5 - type: entity parent: BasePlushie @@ -243,7 +248,6 @@ - type: Sprite state: narplush - - type: entity parent: BasePlushie id: PlushieCarp @@ -356,55 +360,66 @@ - type: entity parent: BaseItem + id: BaseFigurine + name: figurine + description: A small miniature. + abstract: true + components: + - type: Sprite + sprite: Objects/Fun/toys.rsi + netsync: false + - type: PhysicalComposition + materialComposition: + Plastic: 100 + - type: StaticPrice + price: 10 + +- type: entity + parent: BaseFigurine id: ToyAi name: AI toy description: A scaled-down toy AI core. components: - type: Sprite - sprite: Objects/Fun/toys.rsi state: AI - type: entity - parent: BaseItem + parent: BaseFigurine id: ToyNuke name: nuke toy description: A plastic model of a Nuclear Fission Explosive. No uranium included... probably. components: - type: Sprite - sprite: Objects/Fun/toys.rsi state: nuketoy - type: entity - parent: BaseItem + parent: BaseFigurine id: ToyAssistant # TODO rename but needs map changes name: passenger toy description: Grey tide world wide! components: - type: Sprite - sprite: Objects/Fun/toys.rsi state: doll - type: Item sprite: Objects/Fun/toys.rsi heldPrefix: doll - type: entity - parent: BaseItem + parent: BaseFigurine id: ToyGriffin name: griffin toy description: An action figure modeled after 'The Griffin', criminal mastermind. components: - type: Sprite - sprite: Objects/Fun/toys.rsi state: griffinprize - type: entity - parent: BaseItem + parent: BaseFigurine id: ToyHonk name: H.O.N.K. toy description: Mini-Mecha action figure! 'Mecha No. 6/12' is written on the back. components: - type: Sprite - sprite: Objects/Fun/toys.rsi state: honkprize - type: entity @@ -423,125 +438,111 @@ path: /Audio/Items/Toys/ian.ogg - type: entity - parent: BaseItem + parent: BaseFigurine id: ToyMarauder name: marauder toy description: Mini-Mecha action figure! 'Mecha No. 7/12' is written on the back. components: - type: Sprite - sprite: Objects/Fun/toys.rsi state: marauderprize - type: entity - parent: BaseItem + parent: BaseFigurine id: ToyMauler name: mauler toy description: Mini-Mecha action figure! 'Mecha No. 9/12' is written on the back. components: - type: Sprite - sprite: Objects/Fun/toys.rsi state: maulerprize - type: entity - parent: BaseItem + parent: BaseFigurine id: ToyGygax name: gygax toy description: Mini-Mecha action figure! 'Mecha No. 4/12' is written on the back. components: - type: Sprite - sprite: Objects/Fun/toys.rsi state: gygaxtoy - type: entity - parent: BaseItem + parent: BaseFigurine id: ToyOdysseus name: odysseus toy description: Mini-Mecha action figure! 'Mecha No. 10/12' is written on the back. components: - type: Sprite - sprite: Objects/Fun/toys.rsi state: odysseusprize - type: entity - parent: BaseItem + parent: BaseFigurine id: ToyOwlman name: owl toy description: An action figure modeled after 'The Owl', defender of justice. components: - type: Sprite - sprite: Objects/Fun/toys.rsi state: owlprize - type: entity - parent: BaseItem + parent: BaseFigurine id: ToyDeathRipley name: deathripley toy description: Mini-Mecha action figure! 'Mecha No. 3/12' is written on the back. components: - type: Sprite - sprite: Objects/Fun/toys.rsi state: deathripleytoy - type: entity - parent: BaseItem + parent: BaseFigurine id: ToyPhazon name: phazon toy description: Mini-Mecha action figure! 'Mecha No. 11/12' is written on the back. components: - type: Sprite - sprite: Objects/Fun/toys.rsi state: phazonprize - type: entity - parent: BaseItem + parent: BaseFigurine id: ToyFireRipley name: fire ripley description: Mini-Mecha action figure! 'Mecha No. 2/12' is written on the back. components: - type: Sprite - sprite: Objects/Fun/toys.rsi state: fireripleytoy - type: entity - parent: BaseItem + parent: BaseFigurine id: ToyReticence name: reticence toy description: Mini-Mecha action figure! 'Mecha No. 12/12' is written on the back. components: - type: Sprite - sprite: Objects/Fun/toys.rsi state: reticenceprize - type: entity - parent: BaseItem + parent: BaseFigurine id: ToyRipley name: ripley toy description: Mini-Mecha action figure! 'Mecha No. 1/12' is written on the back. components: - type: Sprite - sprite: Objects/Fun/toys.rsi state: ripleytoy - - type: entity - parent: BaseItem + parent: BaseFigurine id: ToySeraph name: seraph toy description: Mini-Mecha action figure! 'Mecha No. 8/12' is written on the back. components: - type: Sprite - sprite: Objects/Fun/toys.rsi state: seraphprize - - type: entity - parent: BaseItem + parent: BaseFigurine id: ToyDurand name: durand toy description: Mini-Mecha action figure! 'Mecha No. 5/12' is written on the back. components: - type: Sprite - sprite: Objects/Fun/toys.rsi state: durandprize @@ -549,13 +550,12 @@ ### Help i'm sorting these and my previous self let this message here to taunt me aaaaa - type: entity - parent: BaseItem + parent: BaseFigurine id: ToySkeleton name: skeleton toy description: Spooked ya! components: - type: Sprite - sprite: Objects/Fun/toys.rsi state: skeletonprize ## Toyweapons @@ -843,8 +843,6 @@ available: - enum.DamageStateVisualLayers.Base: base: Sixteen - - type: StaticPrice - price: 3 - type: entity parent: BaseItem diff --git a/Resources/Prototypes/Entities/Objects/Materials/Sheets/glass.yml b/Resources/Prototypes/Entities/Objects/Materials/Sheets/glass.yml index 0a0c876e99..e49d6a3207 100644 --- a/Resources/Prototypes/Entities/Objects/Materials/Sheets/glass.yml +++ b/Resources/Prototypes/Entities/Objects/Materials/Sheets/glass.yml @@ -51,8 +51,6 @@ - type: Material materials: Glass: 100 - - type: StackPrice - price: 5 - type: Stack stackType: Glass - type: Sprite diff --git a/Resources/Prototypes/Entities/Objects/Materials/shards.yml b/Resources/Prototypes/Entities/Objects/Materials/shards.yml index 2ae5298d57..a0711122da 100644 --- a/Resources/Prototypes/Entities/Objects/Materials/shards.yml +++ b/Resources/Prototypes/Entities/Objects/Materials/shards.yml @@ -51,7 +51,6 @@ - type: Tag tags: - Trash - - type: Recyclable - type: SpaceGarbage - type: Damageable damageContainer: Inorganic diff --git a/Resources/Prototypes/Entities/Objects/Misc/box.yml b/Resources/Prototypes/Entities/Objects/Misc/box.yml index 5f3e1e6cd9..d893b56cce 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/box.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/box.yml @@ -20,3 +20,8 @@ node: boxcardboard containers: - entity_storage + - type: PhysicalComposition + materialComposition: + Cardboard: 100 + - type: StaticPrice + price: 10 diff --git a/Resources/Prototypes/Entities/Objects/Misc/broken_bottle.yml b/Resources/Prototypes/Entities/Objects/Misc/broken_bottle.yml index 8d7462cc96..e7f2088b64 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/broken_bottle.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/broken_bottle.yml @@ -23,6 +23,8 @@ - type: Tag tags: - Trash - - type: Recyclable + - type: PhysicalComposition + materialComposition: + Glass: 50 - type: SpaceGarbage diff --git a/Resources/Prototypes/Entities/Objects/Misc/dat_fukken_disk.yml b/Resources/Prototypes/Entities/Objects/Misc/dat_fukken_disk.yml index b0fe40562e..30a0065056 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/dat_fukken_disk.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/dat_fukken_disk.yml @@ -18,6 +18,9 @@ - type: WarpPoint follow: true location: nuke disk + - type: Tag + tags: + - HighRiskItem - type: entity name: nuclear authentication disk diff --git a/Resources/Prototypes/Entities/Objects/Misc/handcuffs.yml b/Resources/Prototypes/Entities/Objects/Misc/handcuffs.yml index 6499ceeab1..b21f47cb60 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/handcuffs.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/handcuffs.yml @@ -90,10 +90,12 @@ components: - type: Item size: 2 - - type: Recyclable - type: Tag tags: - Trash + - type: PhysicalComposition + materialComposition: + Plastic: 25 - type: entity name: broken zipties @@ -114,4 +116,4 @@ - type: Sprite sprite: Objects/Misc/cablecuffs.rsi state: cuff-broken - color: forestgreen \ No newline at end of file + color: forestgreen diff --git a/Resources/Prototypes/Entities/Objects/Misc/identification_cards.yml b/Resources/Prototypes/Entities/Objects/Misc/identification_cards.yml index 50da83763b..b1ba64a8f8 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/identification_cards.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/identification_cards.yml @@ -107,6 +107,10 @@ heldPrefix: gold - type: PresetIdCard job: Captain + - type: Tag + tags: + - WhitelistChameleon + - HighRiskItem - type: entity parent: IDCardStandard @@ -548,7 +552,7 @@ - state: idzookeeper - type: PresetIdCard job: Zookeeper - + - type: entity parent: IDCardStandard id: DetectiveIDCard @@ -572,7 +576,7 @@ - state: idcentcom - type: Item heldPrefix: gold - + - type: entity parent: IDCardStandard diff --git a/Resources/Prototypes/Entities/Objects/Misc/paper.yml b/Resources/Prototypes/Entities/Objects/Misc/paper.yml index 4dbe14d202..d35fb1eafb 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/paper.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/paper.yml @@ -31,7 +31,6 @@ - Trash - type: Appearance - type: PaperVisuals - - type: Recyclable - type: entity name: office paper @@ -182,7 +181,9 @@ sprite: Objects/Misc/bureaucracy.rsi heldPrefix: pen size: 2 - - type: Recyclable + - type: PhysicalComposition + materialComposition: + Steel: 25 - type: entity name: Cybersun pen diff --git a/Resources/Prototypes/Entities/Objects/Misc/utensils.yml b/Resources/Prototypes/Entities/Objects/Misc/utensils.yml index ee6d680485..e2891c48bf 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/utensils.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/utensils.yml @@ -10,7 +10,6 @@ - type: Tag tags: - Trash - - type: Recyclable - type: SpaceGarbage - type: entity diff --git a/Resources/Prototypes/Entities/Objects/Power/lights.yml b/Resources/Prototypes/Entities/Objects/Power/lights.yml index a0aa6b4330..ccc3cdb146 100644 --- a/Resources/Prototypes/Entities/Objects/Power/lights.yml +++ b/Resources/Prototypes/Entities/Objects/Power/lights.yml @@ -60,7 +60,9 @@ - type: Tag tags: - Trash - - type: Recyclable + - type: PhysicalComposition + materialComposition: + Glass: 25 - type: SpaceGarbage - type: entity diff --git a/Resources/Prototypes/Entities/Objects/Shields/shields.yml b/Resources/Prototypes/Entities/Objects/Shields/shields.yml index 29ddee84c6..d1668feae5 100644 --- a/Resources/Prototypes/Entities/Objects/Shields/shields.yml +++ b/Resources/Prototypes/Entities/Objects/Shields/shields.yml @@ -43,11 +43,11 @@ - !type:SpawnEntitiesBehavior spawn: SheetSteel: - min: 5 - max: 5 + min: 2 + max: 2 SheetGlass: - min: 5 - max: 5 + min: 2 + max: 2 - type: StaticPrice price: 50 diff --git a/Resources/Prototypes/Entities/Objects/Specific/Medical/hypospray.yml b/Resources/Prototypes/Entities/Objects/Specific/Medical/hypospray.yml index 27361d6b1b..b08a665274 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Medical/hypospray.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Medical/hypospray.yml @@ -22,6 +22,9 @@ delay: 0.5 - type: StaticPrice price: 750 + - type: Tag + tags: + - HighRiskItem - type: entity name: gorlex hypospray @@ -78,7 +81,9 @@ - type: Tag tags: - Trash - - type: Recyclable + - type: PhysicalComposition + materialComposition: + Plastic: 50 - type: SpaceGarbage - type: StaticPrice price: 75 # These are limited supply items. diff --git a/Resources/Prototypes/Entities/Objects/Specific/atmos.yml b/Resources/Prototypes/Entities/Objects/Specific/atmos.yml index 21ce9f46d4..1bb1ae59ca 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/atmos.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/atmos.yml @@ -32,3 +32,7 @@ - DroneUsable - type: StaticPrice price: 80 + - type: PhysicalComposition + materialComposition: + Steel: 400 + Glass: 100 diff --git a/Resources/Prototypes/Entities/Objects/Specific/chemistry-bottles.yml b/Resources/Prototypes/Entities/Objects/Specific/chemistry-bottles.yml index 3c255483d4..73c6a3a08f 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/chemistry-bottles.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/chemistry-bottles.yml @@ -9,7 +9,9 @@ tags: - Bottle - Trash - - type: Recyclable + - type: PhysicalComposition + materialComposition: + Glass: 25 - type: SpaceGarbage - type: Sprite sprite: Objects/Specific/Chemistry/bottle.rsi diff --git a/Resources/Prototypes/Entities/Objects/Tools/bucket.yml b/Resources/Prototypes/Entities/Objects/Tools/bucket.yml index a61b6efb4e..532e838817 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/bucket.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/bucket.yml @@ -58,3 +58,6 @@ - type: Tag tags: - Bucket + - type: PhysicalComposition + materialComposition: + Plastic: 50 diff --git a/Resources/Prototypes/Entities/Objects/Tools/flare.yml b/Resources/Prototypes/Entities/Objects/Tools/flare.yml index 71261cc8a9..e67c8f74a4 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/flare.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/flare.yml @@ -8,7 +8,6 @@ tags: - Flare - Trash - - type: Recyclable - type: SpaceGarbage - type: ExpendableLight spentName: expendable-light-spent-flare-name diff --git a/Resources/Prototypes/Entities/Objects/Tools/gas_tanks.yml b/Resources/Prototypes/Entities/Objects/Tools/gas_tanks.yml index 21b5ebde94..4c8dcda6c6 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/gas_tanks.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/gas_tanks.yml @@ -35,6 +35,11 @@ damage: types: Blunt: 10 + - type: PhysicalComposition + materialComposition: + Steel: 400 + - type: StaticPrice + price: 20 - type: entity parent: GasTankBase @@ -109,6 +114,9 @@ damage: types: Blunt: 5 + - type: PhysicalComposition + materialComposition: + Steel: 100 - type: entity parent: EmergencyOxygenTank diff --git a/Resources/Prototypes/Entities/Objects/Tools/glowstick.yml b/Resources/Prototypes/Entities/Objects/Tools/glowstick.yml index 9b58d9105e..41919ddce6 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/glowstick.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/glowstick.yml @@ -4,7 +4,6 @@ id: GlowstickBase description: Useful for raves and emergencies. components: - - type: Recyclable - type: SpaceGarbage - type: ExpendableLight spentName: expendable-light-spent-green-glowstick-name diff --git a/Resources/Prototypes/Entities/Objects/Tools/jetpacks.yml b/Resources/Prototypes/Entities/Objects/Tools/jetpacks.yml index 388cef6019..cd8da06a32 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/jetpacks.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/jetpacks.yml @@ -147,6 +147,9 @@ - type: Item sprite: Objects/Tanks/Jetpacks/captain.rsi size: 30 + - type: Tag + tags: + - HighRiskItem # Filled captain - type: entity @@ -248,7 +251,7 @@ sprite: Objects/Tanks/Jetpacks/void.rsi slots: - Back - - suitStorage + - suitStorage # Filled void - type: entity diff --git a/Resources/Prototypes/Entities/Objects/Tools/matches.yml b/Resources/Prototypes/Entities/Objects/Tools/matches.yml index 9350cf4da6..3700a1bfb1 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/matches.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/matches.yml @@ -18,7 +18,6 @@ tags: - Matchstick - Trash - - type: Recyclable - type: SpaceGarbage - type: Sprite netsync: false @@ -94,5 +93,4 @@ - type: Tag tags: - Trash - - type: Recyclable - type: SpaceGarbage diff --git a/Resources/Prototypes/Entities/Objects/Tools/tools.yml b/Resources/Prototypes/Entities/Objects/Tools/tools.yml index ac419a7016..9708b7f538 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/tools.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/tools.yml @@ -35,6 +35,9 @@ - type: Item sprite: Objects/Tools/wirecutters.rsi - type: LatticeCutting + - type: PhysicalComposition + materialComposition: + Steel: 100 - type: StaticPrice price: 40 @@ -74,6 +77,9 @@ available: - enum.DamageStateVisualLayers.Base: screwdriver: Rainbow + - type: PhysicalComposition + materialComposition: + Steel: 100 - type: StaticPrice price: 40 @@ -106,6 +112,9 @@ - Anchoring useSound: path: /Audio/Items/ratchet.ogg + - type: PhysicalComposition + materialComposition: + Steel: 100 - type: StaticPrice price: 40 @@ -139,6 +148,9 @@ useSound: path: /Audio/Items/crowbar.ogg - type: TilePrying + - type: PhysicalComposition + materialComposition: + Steel: 100 - type: StaticPrice price: 40 @@ -200,6 +212,10 @@ - type: Tag tags: - DroneUsable + - type: PhysicalComposition + materialComposition: + Steel: 100 + Plastic: 100 - type: StaticPrice price: 60 @@ -242,6 +258,10 @@ path: /Audio/Items/drill_use.ogg changeSound: path: /Audio/Items/change_drill.ogg + - type: PhysicalComposition + materialComposition: + Steel: 300 + Plastic: 100 - type: StaticPrice price: 100 @@ -264,6 +284,10 @@ quickEquip: false slots: - Belt + - type: PhysicalComposition + materialComposition: + Steel: 600 + Plastic: 100 - type: StaticPrice price: 100 @@ -288,6 +312,10 @@ - type: Item sprite: Objects/Tools/rcd.rsi heldPrefix: ammo + - type: PhysicalComposition + materialComposition: + Steel: 100 + Plastic: 100 - type: StaticPrice price: 60 @@ -310,6 +338,12 @@ Blunt: 10 - type: Item sprite: Objects/Tools/shovel.rsi + - type: PhysicalComposition + materialComposition: + Steel: 100 + Wood: 50 + - type: StaticPrice + price: 25 - type: entity name: omnitool diff --git a/Resources/Prototypes/Entities/Objects/Tools/welders.yml b/Resources/Prototypes/Entities/Objects/Tools/welders.yml index fbf43fefa3..0834b192b0 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/welders.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/welders.yml @@ -60,6 +60,9 @@ color: orange - type: Appearance - type: RequiresEyeProtection + - type: PhysicalComposition + materialComposition: + Steel: 200 - type: StaticPrice price: 40 - type: IgnitionSource diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Cartridges/base_cartridge.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Cartridges/base_cartridge.yml index c021eebed6..230be6a76b 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Cartridges/base_cartridge.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Cartridges/base_cartridge.yml @@ -11,5 +11,4 @@ - Cartridge - type: Item size: 1 - - type: Recyclable - type: SpaceGarbage diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/toy.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/toy.yml index 39542eccc2..34a39c1583 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/toy.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/toy.yml @@ -7,9 +7,9 @@ - type: Tag tags: - BulletFoam + - Trash - type: Ammo - type: Sprite sprite: Objects/Fun/toys.rsi layers: - state: foamdart - - type: Recyclable \ No newline at end of file diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml index 2b2f7ed0b0..ba1e9cfa46 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml @@ -390,6 +390,9 @@ steps: 5 zeroVisible: true - type: Appearance + - type: Tag + tags: + - HighRiskItem - type: StaticPrice price: 750 diff --git a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml index f7599c12c9..6bce0ecbf8 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml @@ -306,6 +306,7 @@ - DawInstrumentMachineCircuitboard - CloningConsoleComputerCircuitboard - StasisBedMachineCircuitboard + - MaterialReclaimerMachineCircuitboard - OreProcessorMachineCircuitboard - RipleyCentralElectronics - RipleyPeripheralsElectronics diff --git a/Resources/Prototypes/Entities/Structures/Machines/material_reclaimer.yml b/Resources/Prototypes/Entities/Structures/Machines/material_reclaimer.yml new file mode 100644 index 0000000000..26d4adf09d --- /dev/null +++ b/Resources/Prototypes/Entities/Structures/Machines/material_reclaimer.yml @@ -0,0 +1,101 @@ +- type: entity + parent: [ BaseMachinePowered, ConstructibleMachine ] + id: MaterialReclaimer + name: material reclaimer + description: Cannot reclaim immaterial things, like motivation. + components: + - type: Sprite + sprite: Structures/Machines/material_reclaimer.rsi + snapCardinals: true + netsync: false + layers: + - state: icon + map: ["enum.LatheVisualLayers.IsRunning"] + - state: gear-active + map: ["enum.DamageStateVisualLayers.Base"] + - state: unlit + shader: unshaded + map: ["enum.PowerDeviceVisualLayers.Powered"] + - state: fill-6 + map: ["enum.SolutionContainerLayers.Fill"] + visible: false + - state: panel + map: ["enum.WiresVisualLayers.MaintenancePanel"] + - type: Appearance + - type: SolutionContainerVisuals + maxFillLevels: 6 + fillBaseName: fill- + - type: WiresVisuals + - type: GenericVisualizer + visuals: + enum.PowerDeviceVisuals.Powered: + enum.DamageStateVisualLayers.Base: + True: { state: gear-active} + False: { state: gear-idle } + enum.PowerDeviceVisualLayers.Powered: + True: { visible: true } + False: { visible: false } + - type: LitOnPowered + - type: PointLight + radius: 1.5 + energy: 1.6 + enabled: false + color: "#da824d" + mask: /Textures/Effects/LightMasks/cone.png + autoRot: true + offset: "0, 0.4" + castShadows: false + - type: PowerSwitch + - type: Destructible + thresholds: + - trigger: + !type:DamageTrigger + damage: 100 + behaviors: + - !type:ChangeConstructionNodeBehavior + node: machineFrame + - !type:DoActsBehavior + acts: ["Destruction"] + - type: Machine + board: MaterialReclaimerMachineCircuitboard + - type: Wires + BoardName: "reclaimer" + LayoutId: Reclaimer + - type: MaterialReclaimer + whitelist: + components: + - PhysicalComposition + - SpaceGarbage + tags: + - Trash + - Recyclable + blacklist: + components: + - Material + - PDA + - IdCard + tags: + - HighRiskItem + sound: + path: /Audio/Ambience/Objects/crushing.ogg + params: + volume: 5 + maxdistance: 5 + loop: true + - type: MaterialStorage + insertOnInteract: false + - type: ContainerContainer + containers: + active-material-reclaimer-container: !type:Container + machine_board: !type:Container + machine_parts: !type:Container + - type: SolutionContainerManager + solutions: + output: + maxVol: 100 + - type: DrainableSolution + solution: output + - type: ExaminableSolution + solution: output + - type: StaticPrice + price: 500 diff --git a/Resources/Prototypes/Entities/Structures/Machines/recycler.yml b/Resources/Prototypes/Entities/Structures/Machines/recycler.yml index 6faa94dd3f..49b6e563dd 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/recycler.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/recycler.yml @@ -11,12 +11,11 @@ sound: # TODO: https://freesound.org/people/derjuli/sounds/448133/ CC-NC- path: /Audio/Ambience/Objects/circular_saw.ogg - - type: Physics - type: Fixtures fixtures: - shape: !type:PhysShapeAabb - bounds: "-0.2,-0.2,0.2,0.2" + bounds: "-0.15,-0.15,0.15,0.15" id: brrt hard: false layer: @@ -58,11 +57,58 @@ layers: - state: grinder-o0 map: ["enum.RecyclerVisualLayers.Main"] + - state: grinder-o0bld + map: ["enum.RecyclerVisualLayers.Bloody"] + visible: false - type: Appearance + - type: GenericVisualizer visuals: - - type: RecyclerVisualizer - state_on: grinder-o1 - state_off: grinder-o0 - - type: Recycler + enum.RecyclerVisuals.Bloody: + enum.RecyclerVisualLayers.Main: + True: { visible: false } + False: { visible: true } + enum.RecyclerVisualLayers.Bloody: + True: { visible: true } + False: { visible: false } + enum.ConveyorVisuals.State: + enum.RecyclerVisualLayers.Main: + Forward: { state: grinder-o1 } + Reverse: { state: grinder-o1 } + Off: { state: grinder-o0 } + enum.RecyclerVisualLayers.Bloody: + Forward: { state: grinder-o1bld } + Reverse: { state: grinder-o1bld } + Off: { state: grinder-o0bld } + - type: CollideMaterialReclaimer + - type: MaterialReclaimer + enabled: false + efficiency: 0.25 + scaleProcessSpeed: false #instant! + minimumProcessDuration: 0 + whitelist: + components: + - PhysicalComposition + - SpaceGarbage + tags: + - Trash + - Recyclable + blacklist: + components: + - Material + - PDA + - IdCard + - HumanoidAppearance + tags: + - HighRiskItem + sound: + path: /Audio/Effects/saw.ogg + params: + volume: -3 + cutOffSound: false + - type: SolutionContainerManager + solutions: + output: + maxVol: 0 #exists only for the overflow stuff on material reclaimer + - type: MaterialStorage - type: Conveyor - type: Rotatable \ No newline at end of file diff --git a/Resources/Prototypes/Entities/Structures/Storage/Canisters/gas_canisters.yml b/Resources/Prototypes/Entities/Structures/Storage/Canisters/gas_canisters.yml index 345eea9897..2e89c2f622 100644 --- a/Resources/Prototypes/Entities/Structures/Storage/Canisters/gas_canisters.yml +++ b/Resources/Prototypes/Entities/Structures/Storage/Canisters/gas_canisters.yml @@ -608,7 +608,9 @@ - MachineMask layer: - MachineLayer - - type: Recyclable + - type: PhysicalComposition + materialComposition: + Steel: 500 - type: StaticPrice price: 60 diff --git a/Resources/Prototypes/Entities/Structures/Windows/window.yml b/Resources/Prototypes/Entities/Structures/Windows/window.yml index 2234f3de72..e68dbb8f62 100644 --- a/Resources/Prototypes/Entities/Structures/Windows/window.yml +++ b/Resources/Prototypes/Entities/Structures/Windows/window.yml @@ -169,7 +169,7 @@ graph: WindowDirectional node: windowDirectional - type: StaticPrice - price: 5 + price: 10 - type: entity id: WindowTintedDirectional @@ -193,8 +193,6 @@ state: tinted_window - type: Occluder boundingBox: "-0.5,-0.5,0.5,-0.3" - - type: StaticPrice - price: 5 - type: entity id: WindowFrostedDirectional @@ -213,5 +211,3 @@ - type: Icon sprite: Structures/Windows/directional.rsi state: frosted_window - - type: StaticPrice - price: 5 diff --git a/Resources/Prototypes/Reagents/Materials/materials.yml b/Resources/Prototypes/Reagents/Materials/materials.yml index faaa2523ec..15af26eb47 100644 --- a/Resources/Prototypes/Reagents/Materials/materials.yml +++ b/Resources/Prototypes/Reagents/Materials/materials.yml @@ -12,7 +12,7 @@ name: materials-cardboard icon: { sprite: /Textures/Objects/Materials/materials.rsi, state: cardboard } color: "#70736c" - price: 0.05 + price: 0.005 - type: material id: Cloth diff --git a/Resources/Prototypes/Recipes/Lathes/electronics.yml b/Resources/Prototypes/Recipes/Lathes/electronics.yml index c5aea71800..468c0e5a56 100644 --- a/Resources/Prototypes/Recipes/Lathes/electronics.yml +++ b/Resources/Prototypes/Recipes/Lathes/electronics.yml @@ -292,6 +292,14 @@ Glass: 900 Gold: 100 +- type: latheRecipe + id: MaterialReclaimerMachineCircuitboard + result: MaterialReclaimerMachineCircuitboard + completetime: 4 + materials: + Steel: 100 + Glass: 900 + - type: latheRecipe id: OreProcessorMachineCircuitboard result: OreProcessorMachineCircuitboard diff --git a/Resources/Prototypes/Recipes/Lathes/janitorial.yml b/Resources/Prototypes/Recipes/Lathes/janitorial.yml index 4c537c30e5..1515ccdaad 100644 --- a/Resources/Prototypes/Recipes/Lathes/janitorial.yml +++ b/Resources/Prototypes/Recipes/Lathes/janitorial.yml @@ -18,7 +18,7 @@ result: Bucket completetime: 2 materials: - Steel: 100 + Plastic: 100 - type: latheRecipe id: WetFloorSign diff --git a/Resources/Prototypes/tags.yml b/Resources/Prototypes/tags.yml index bfb69b2448..f7870ccdc6 100644 --- a/Resources/Prototypes/tags.yml +++ b/Resources/Prototypes/tags.yml @@ -302,6 +302,9 @@ - type: Tag id: HidesHair # for headwear. +- type: Tag + id: HighRiskItem + - type: Tag id: Hoe diff --git a/Resources/Textures/Structures/Machines/material_reclaimer.rsi/fill-1.png b/Resources/Textures/Structures/Machines/material_reclaimer.rsi/fill-1.png new file mode 100644 index 0000000000..32efd405d8 Binary files /dev/null and b/Resources/Textures/Structures/Machines/material_reclaimer.rsi/fill-1.png differ diff --git a/Resources/Textures/Structures/Machines/material_reclaimer.rsi/fill-2.png b/Resources/Textures/Structures/Machines/material_reclaimer.rsi/fill-2.png new file mode 100644 index 0000000000..71883d8117 Binary files /dev/null and b/Resources/Textures/Structures/Machines/material_reclaimer.rsi/fill-2.png differ diff --git a/Resources/Textures/Structures/Machines/material_reclaimer.rsi/fill-3.png b/Resources/Textures/Structures/Machines/material_reclaimer.rsi/fill-3.png new file mode 100644 index 0000000000..747e6a3fd5 Binary files /dev/null and b/Resources/Textures/Structures/Machines/material_reclaimer.rsi/fill-3.png differ diff --git a/Resources/Textures/Structures/Machines/material_reclaimer.rsi/fill-4.png b/Resources/Textures/Structures/Machines/material_reclaimer.rsi/fill-4.png new file mode 100644 index 0000000000..e734cce94b Binary files /dev/null and b/Resources/Textures/Structures/Machines/material_reclaimer.rsi/fill-4.png differ diff --git a/Resources/Textures/Structures/Machines/material_reclaimer.rsi/fill-5.png b/Resources/Textures/Structures/Machines/material_reclaimer.rsi/fill-5.png new file mode 100644 index 0000000000..1ed097f5e2 Binary files /dev/null and b/Resources/Textures/Structures/Machines/material_reclaimer.rsi/fill-5.png differ diff --git a/Resources/Textures/Structures/Machines/material_reclaimer.rsi/fill-6.png b/Resources/Textures/Structures/Machines/material_reclaimer.rsi/fill-6.png new file mode 100644 index 0000000000..ab269efd65 Binary files /dev/null and b/Resources/Textures/Structures/Machines/material_reclaimer.rsi/fill-6.png differ diff --git a/Resources/Textures/Structures/Machines/material_reclaimer.rsi/gear-active.png b/Resources/Textures/Structures/Machines/material_reclaimer.rsi/gear-active.png new file mode 100644 index 0000000000..a228b142f4 Binary files /dev/null and b/Resources/Textures/Structures/Machines/material_reclaimer.rsi/gear-active.png differ diff --git a/Resources/Textures/Structures/Machines/material_reclaimer.rsi/gear-idle.png b/Resources/Textures/Structures/Machines/material_reclaimer.rsi/gear-idle.png new file mode 100644 index 0000000000..96a795aaf3 Binary files /dev/null and b/Resources/Textures/Structures/Machines/material_reclaimer.rsi/gear-idle.png differ diff --git a/Resources/Textures/Structures/Machines/material_reclaimer.rsi/icon.png b/Resources/Textures/Structures/Machines/material_reclaimer.rsi/icon.png new file mode 100644 index 0000000000..7ba2ef785e Binary files /dev/null and b/Resources/Textures/Structures/Machines/material_reclaimer.rsi/icon.png differ diff --git a/Resources/Textures/Structures/Machines/material_reclaimer.rsi/meta.json b/Resources/Textures/Structures/Machines/material_reclaimer.rsi/meta.json new file mode 100644 index 0000000000..3e27312a6c --- /dev/null +++ b/Resources/Textures/Structures/Machines/material_reclaimer.rsi/meta.json @@ -0,0 +1,57 @@ +{ + "version": 1, + "license": "CC0-1.0", + "copyright": "Created by EmoGarbage404 (github) for Space Station 14", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "fill-1" + }, + { + "name": "fill-2" + }, + { + "name": "fill-3" + }, + { + "name": "fill-4" + }, + { + "name": "fill-5" + }, + { + "name": "fill-6" + }, + { + "name": "gear-active", + "delays": [ + [ + 0.25, + 0.25, + 0.25 + ] + ] + }, + { + "name": "gear-idle" + }, + { + "name": "icon" + }, + { + "name": "panel" + }, + { + "name": "unlit", + "delays": [ + [ + 0.1, + 1.0 + ] + ] + } + ] +} diff --git a/Resources/Textures/Structures/Machines/material_reclaimer.rsi/panel.png b/Resources/Textures/Structures/Machines/material_reclaimer.rsi/panel.png new file mode 100644 index 0000000000..b3de5c1be1 Binary files /dev/null and b/Resources/Textures/Structures/Machines/material_reclaimer.rsi/panel.png differ diff --git a/Resources/Textures/Structures/Machines/material_reclaimer.rsi/unlit.png b/Resources/Textures/Structures/Machines/material_reclaimer.rsi/unlit.png new file mode 100644 index 0000000000..9c9511af3e Binary files /dev/null and b/Resources/Textures/Structures/Machines/material_reclaimer.rsi/unlit.png differ