/// <summary>
/// The interval for <see cref="RandomMessTimer"/>.
/// </summary>
- [ViewVariables(VVAccess.ReadWrite), DataField("randomMessInterval")]
+ [ViewVariables(VVAccess.ReadWrite), DataField]
public TimeSpan RandomMessInterval = TimeSpan.FromSeconds(5);
/// <summary>
/// <summary>
/// Amount of biomass that the mob being processed will yield.
/// This is calculated from the YieldPerUnitMass.
+ /// Also stores non-integer leftovers.
/// </summary>
[ViewVariables]
- public int CurrentExpectedYield = default;
+ public float CurrentExpectedYield = 0f;
/// <summary>
/// The reagent that will be spilled while processing a mob.
[DataField, ViewVariables(VVAccess.ReadWrite)]
public float YieldPerUnitMass = 0.4f;
+ /// <summary>
+ /// How many seconds to take to insert an entity per unit of its mass.
+ /// </summary>
+ [DataField, ViewVariables(VVAccess.ReadWrite)]
+ public float BaseInsertionDelay = 0.1f;
+
+ /// <summary>
+ /// How much to multiply biomass yield from botany produce.
+ /// </summary>
+ [DataField, ViewVariables(VVAccess.ReadWrite)]
+ public float ProduceYieldMultiplier = 0.25f;
+
/// <summary>
/// The time it takes to process a mob, per mass.
/// </summary>
/// <summary>
/// Will this refuse to gib a living mob?
/// </summary>
- [ViewVariables(VVAccess.ReadWrite), DataField("safetyEnabled")]
+ [ViewVariables(VVAccess.ReadWrite), DataField]
public bool SafetyEnabled = true;
}
}
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;
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;
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
[Dependency] private readonly MaterialStorageSystem _material = default!;
[Dependency] private readonly SharedMindSystem _minds = default!;
+ [ValidatePrototypeId<MaterialPrototype>]
+ public const string BiomassPrototype = "Biomass";
+
public override void Update(float frameTime)
{
base.Update(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();
if (!args.CanReach || args.Target == null)
return;
- if (!HasComp<MobStateComponent>(args.Used) || !CanGib(reclaimer, args.Used))
+ if (!CanGib(reclaimer, args.Used))
+ return;
+
+ if (!TryComp<PhysicsComponent>(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,
private void OnDoAfter(Entity<BiomassReclaimerComponent> reclaimer, ref ReclaimerDoAfterEvent args)
{
- if (args.Handled || args.Cancelled || args.Args.Target == null || HasComp<BiomassReclaimerComponent>(args.Args.Target.Value))
+ if (args.Handled || args.Cancelled)
+ return;
+
+ if (args.Args.Used == null || args.Args.Target == null || !HasComp<BiomassReclaimerComponent>(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;
}
component.SpawnedEntities = butcherableComponent.SpawnedEntities;
}
- component.CurrentExpectedYield = (int) Math.Max(0, physics.FixturesMass * component.YieldPerUnitMass);
+ var expectedYield = physics.FixturesMass * component.YieldPerUnitMass;
+ if (HasComp<ProduceComponent>(toProcess))
+ expectedYield *= component.ProduceYieldMultiplier;
+ component.CurrentExpectedYield += expectedYield;
+
component.ProcessingTimer = physics.FixturesMass * component.ProcessingTimePerUnitMass;
+
QueueDel(toProcess);
}
if (HasComp<ActiveBiomassReclaimerComponent>(reclaimer))
return false;
- if (!HasComp<MobStateComponent>(dragged))
+ bool isPlant = HasComp<ProduceComponent>(dragged);
+ if (!isPlant && !HasComp<MobStateComponent>(dragged))
return false;
if (!Transform(reclaimer).Anchored)
if (TryComp<ApcPowerReceiverComponent>(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.