diff --git a/Content.Server/Medical/BiomassReclaimer/BiomassReclaimerComponent.cs b/Content.Server/Medical/BiomassReclaimer/BiomassReclaimerComponent.cs
index 25378bb3ede..61d36f98b96 100644
--- a/Content.Server/Medical/BiomassReclaimer/BiomassReclaimerComponent.cs
+++ b/Content.Server/Medical/BiomassReclaimer/BiomassReclaimerComponent.cs
@@ -15,7 +15,7 @@ public sealed partial class BiomassReclaimerComponent : Component
///
/// The interval for .
///
- [ViewVariables(VVAccess.ReadWrite), DataField("randomMessInterval")]
+ [ViewVariables(VVAccess.ReadWrite), DataField]
public TimeSpan RandomMessInterval = TimeSpan.FromSeconds(5);
///
@@ -28,9 +28,10 @@ public sealed partial class BiomassReclaimerComponent : Component
///
/// Amount of biomass that the mob being processed will yield.
/// This is calculated from the YieldPerUnitMass.
+ /// Also stores non-integer leftovers.
///
[ViewVariables]
- public int CurrentExpectedYield = default;
+ public float CurrentExpectedYield = 0f;
///
/// The reagent that will be spilled while processing a mob.
@@ -49,6 +50,18 @@ public sealed partial class BiomassReclaimerComponent : Component
[DataField, ViewVariables(VVAccess.ReadWrite)]
public float YieldPerUnitMass = 0.4f;
+ ///
+ /// How many seconds to take to insert an entity per unit of its mass.
+ ///
+ [DataField, ViewVariables(VVAccess.ReadWrite)]
+ public float BaseInsertionDelay = 0.1f;
+
+ ///
+ /// How much to multiply biomass yield from botany produce.
+ ///
+ [DataField, ViewVariables(VVAccess.ReadWrite)]
+ public float ProduceYieldMultiplier = 0.25f;
+
///
/// The time it takes to process a mob, per mass.
///
@@ -58,7 +71,7 @@ public sealed partial class BiomassReclaimerComponent : Component
///
/// Will this refuse to gib a living mob?
///
- [ViewVariables(VVAccess.ReadWrite), DataField("safetyEnabled")]
+ [ViewVariables(VVAccess.ReadWrite), DataField]
public bool SafetyEnabled = true;
}
}
diff --git a/Content.Server/Medical/BiomassReclaimer/BiomassReclaimerSystem.cs b/Content.Server/Medical/BiomassReclaimer/BiomassReclaimerSystem.cs
index b126c74a10a..d07858aec5c 100644
--- a/Content.Server/Medical/BiomassReclaimer/BiomassReclaimerSystem.cs
+++ b/Content.Server/Medical/BiomassReclaimer/BiomassReclaimerSystem.cs
@@ -1,5 +1,6 @@
using System.Numerics;
using Content.Server.Body.Components;
+using Content.Server.Botany.Components;
using Content.Server.Fluids.EntitySystems;
using Content.Server.Materials;
using Content.Server.Power.Components;
@@ -17,6 +18,7 @@
using Content.Shared.Jittering;
using Content.Shared.Medical;
using Content.Shared.Mind;
+using Content.Shared.Materials;
using Content.Shared.Mobs.Components;
using Content.Shared.Mobs.Systems;
using Content.Shared.Nutrition.Components;
@@ -26,6 +28,7 @@
using Robust.Shared.Audio.Systems;
using Robust.Shared.Configuration;
using Robust.Shared.Physics.Components;
+using Robust.Shared.Prototypes;
using Robust.Shared.Random;
namespace Content.Server.Medical.BiomassReclaimer
@@ -47,6 +50,9 @@ public sealed class BiomassReclaimerSystem : EntitySystem
[Dependency] private readonly MaterialStorageSystem _material = default!;
[Dependency] private readonly SharedMindSystem _minds = default!;
+ [ValidatePrototypeId]
+ public const string BiomassPrototype = "Biomass";
+
public override void Update(float frameTime)
{
base.Update(frameTime);
@@ -79,7 +85,9 @@ public override void Update(float frameTime)
continue;
}
- _material.SpawnMultipleFromMaterial(reclaimer.CurrentExpectedYield, "Biomass", Transform(uid).Coordinates);
+ var actualYield = (int) (reclaimer.CurrentExpectedYield); // can only have integer biomass
+ reclaimer.CurrentExpectedYield = reclaimer.CurrentExpectedYield - actualYield; // store non-integer leftovers
+ _material.SpawnMultipleFromMaterial(actualYield, BiomassPrototype, Transform(uid).Coordinates);
reclaimer.BloodReagent = null;
reclaimer.SpawnedEntities.Clear();
@@ -148,10 +156,14 @@ private void OnAfterInteractUsing(Entity reclaimer, r
if (!args.CanReach || args.Target == null)
return;
- if (!HasComp(args.Used) || !CanGib(reclaimer, args.Used))
+ if (!CanGib(reclaimer, args.Used))
+ return;
+
+ if (!TryComp(args.Used, out var physics))
return;
- _doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, args.User, 7f, new ReclaimerDoAfterEvent(), reclaimer, target: args.Target, used: args.Used)
+ var delay = reclaimer.Comp.BaseInsertionDelay * physics.FixturesMass;
+ _doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, args.User, delay, new ReclaimerDoAfterEvent(), reclaimer, target: args.Target, used: args.Used)
{
BreakOnTargetMove = true,
BreakOnUserMove = true,
@@ -174,11 +186,14 @@ private void OnClimbedOn(Entity reclaimer, ref Climbe
private void OnDoAfter(Entity reclaimer, ref ReclaimerDoAfterEvent args)
{
- if (args.Handled || args.Cancelled || args.Args.Target == null || HasComp(args.Args.Target.Value))
+ if (args.Handled || args.Cancelled)
+ return;
+
+ if (args.Args.Used == null || args.Args.Target == null || !HasComp(args.Args.Target.Value))
return;
_adminLogger.Add(LogType.Action, LogImpact.Extreme, $"{ToPrettyString(args.Args.User):player} used a biomass reclaimer to gib {ToPrettyString(args.Args.Target.Value):target} in {ToPrettyString(reclaimer):reclaimer}");
- StartProcessing(args.Args.Target.Value, reclaimer);
+ StartProcessing(args.Args.Used.Value, reclaimer);
args.Handled = true;
}
@@ -200,8 +215,13 @@ private void StartProcessing(EntityUid toProcess, Entity(toProcess))
+ expectedYield *= component.ProduceYieldMultiplier;
+ component.CurrentExpectedYield += expectedYield;
+
component.ProcessingTimer = physics.FixturesMass * component.ProcessingTimePerUnitMass;
+
QueueDel(toProcess);
}
@@ -210,7 +230,8 @@ private bool CanGib(Entity reclaimer, EntityUid dragg
if (HasComp(reclaimer))
return false;
- if (!HasComp(dragged))
+ bool isPlant = HasComp(dragged);
+ if (!isPlant && !HasComp(dragged))
return false;
if (!Transform(reclaimer).Anchored)
@@ -219,7 +240,7 @@ private bool CanGib(Entity reclaimer, EntityUid dragg
if (TryComp(reclaimer, out var power) && !power.Powered)
return false;
- if (reclaimer.Comp.SafetyEnabled && !_mobState.IsDead(dragged))
+ if (!isPlant && reclaimer.Comp.SafetyEnabled && !_mobState.IsDead(dragged))
return false;
// Reject souled bodies in easy mode.