Animals obey conservation of matter unless they are undead (#21922)
This commit is contained in:
@@ -1,7 +1,6 @@
|
|||||||
using Content.Shared.Storage;
|
using Content.Shared.Storage;
|
||||||
using Robust.Shared.Audio;
|
using Robust.Shared.Audio;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
|
||||||
|
|
||||||
namespace Content.Server.Animals.Components;
|
namespace Content.Server.Animals.Components;
|
||||||
|
|
||||||
@@ -9,28 +8,29 @@ namespace Content.Server.Animals.Components;
|
|||||||
/// This component handles animals which lay eggs (or some other item) on a timer, using up hunger to do so.
|
/// This component handles animals which lay eggs (or some other item) on a timer, using up hunger to do so.
|
||||||
/// It also grants an action to players who are controlling these entities, allowing them to do it manually.
|
/// It also grants an action to players who are controlling these entities, allowing them to do it manually.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
||||||
[RegisterComponent]
|
[RegisterComponent]
|
||||||
public sealed partial class EggLayerComponent : Component
|
public sealed partial class EggLayerComponent : Component
|
||||||
{
|
{
|
||||||
[DataField("eggLayAction", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
|
[DataField]
|
||||||
public string EggLayAction = "ActionAnimalLayEgg";
|
public EntProtoId EggLayAction = "ActionAnimalLayEgg";
|
||||||
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
/// <summary>
|
||||||
[DataField("hungerUsage")]
|
/// The amount of nutrient consumed on update.
|
||||||
|
/// </summary>
|
||||||
|
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
||||||
public float HungerUsage = 60f;
|
public float HungerUsage = 60f;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Minimum cooldown used for the automatic egg laying.
|
/// Minimum cooldown used for the automatic egg laying.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
||||||
[DataField("eggLayCooldownMin")]
|
|
||||||
public float EggLayCooldownMin = 60f;
|
public float EggLayCooldownMin = 60f;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Maximum cooldown used for the automatic egg laying.
|
/// Maximum cooldown used for the automatic egg laying.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
||||||
[DataField("eggLayCooldownMax")]
|
|
||||||
public float EggLayCooldownMax = 120f;
|
public float EggLayCooldownMax = 120f;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -39,14 +39,13 @@ public sealed partial class EggLayerComponent : Component
|
|||||||
[ViewVariables(VVAccess.ReadWrite)]
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
public float CurrentEggLayCooldown;
|
public float CurrentEggLayCooldown;
|
||||||
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
[DataField(required: true), ViewVariables(VVAccess.ReadWrite)]
|
||||||
[DataField("eggSpawn", required: true)]
|
|
||||||
public List<EntitySpawnEntry> EggSpawn = default!;
|
public List<EntitySpawnEntry> EggSpawn = default!;
|
||||||
|
|
||||||
[DataField("eggLaySound")]
|
[DataField]
|
||||||
public SoundSpecifier EggLaySound = new SoundPathSpecifier("/Audio/Effects/pop.ogg");
|
public SoundSpecifier EggLaySound = new SoundPathSpecifier("/Audio/Effects/pop.ogg");
|
||||||
|
|
||||||
[DataField("accumulatedFrametime")]
|
[DataField]
|
||||||
public float AccumulatedFrametime;
|
public float AccumulatedFrametime;
|
||||||
|
|
||||||
[DataField] public EntityUid? Action;
|
[DataField] public EntityUid? Action;
|
||||||
|
|||||||
@@ -1,9 +1,15 @@
|
|||||||
using Content.Server.Animals.Systems;
|
using Content.Server.Animals.Systems;
|
||||||
using Content.Shared.Chemistry.Reagent;
|
using Content.Shared.Chemistry.Reagent;
|
||||||
using Content.Shared.FixedPoint;
|
using Content.Shared.FixedPoint;
|
||||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
using Robust.Shared.Prototypes;
|
||||||
|
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
|
||||||
|
|
||||||
|
|
||||||
namespace Content.Server.Animals.Components
|
namespace Content.Server.Animals.Components
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Lets an entity produce milk. Uses hunger if present.
|
||||||
|
/// </summary>
|
||||||
{
|
{
|
||||||
[RegisterComponent, Access(typeof(UdderSystem))]
|
[RegisterComponent, Access(typeof(UdderSystem))]
|
||||||
internal sealed partial class UdderComponent : Component
|
internal sealed partial class UdderComponent : Component
|
||||||
@@ -11,31 +17,37 @@ namespace Content.Server.Animals.Components
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The reagent to produce.
|
/// The reagent to produce.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ViewVariables(VVAccess.ReadOnly)]
|
[DataField, ViewVariables(VVAccess.ReadOnly)]
|
||||||
[DataField("reagentId", customTypeSerializer:typeof(PrototypeIdSerializer<ReagentPrototype>))]
|
public ProtoId<ReagentPrototype> ReagentId = "Milk";
|
||||||
public string ReagentId = "Milk";
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The solution to add reagent to.
|
/// The solution to add reagent to.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ViewVariables(VVAccess.ReadOnly)]
|
[DataField, ViewVariables(VVAccess.ReadOnly)]
|
||||||
[DataField("targetSolution")]
|
public string Solution = "udder";
|
||||||
public string TargetSolutionName = "udder";
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The amount of reagent to be generated on update.
|
/// The amount of reagent to be generated on update.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ViewVariables(VVAccess.ReadOnly)]
|
[DataField, ViewVariables(VVAccess.ReadOnly)]
|
||||||
[DataField("quantity")]
|
public FixedPoint2 QuantityPerUpdate = 25;
|
||||||
public FixedPoint2 QuantityPerUpdate = 1;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The time between updates (in seconds).
|
/// The amount of nutrient consumed on update.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ViewVariables(VVAccess.ReadOnly)]
|
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
||||||
[DataField("updateRate")]
|
public float HungerUsage = 10f;
|
||||||
public float UpdateRate = 5;
|
|
||||||
|
|
||||||
public float AccumulatedFrameTime;
|
/// <summary>
|
||||||
|
/// How long to wait before producing.
|
||||||
|
/// </summary>
|
||||||
|
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public TimeSpan GrowthDelay = TimeSpan.FromMinutes(1);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// When to next try to produce.
|
||||||
|
/// </summary>
|
||||||
|
[DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public TimeSpan NextGrowth = TimeSpan.FromSeconds(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,29 +4,38 @@ using Content.Shared.FixedPoint;
|
|||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
|
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
|
||||||
|
|
||||||
|
namespace Content.Server.Animals.Components;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Lets an animal grow a wool solution when not hungry.
|
/// Lets an entity produce wool fibers. Uses hunger if present.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
||||||
[RegisterComponent, Access(typeof(WoolySystem))]
|
[RegisterComponent, Access(typeof(WoolySystem))]
|
||||||
public sealed partial class WoolyComponent : Component
|
public sealed partial class WoolyComponent : Component
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// What reagent to grow.
|
/// The reagent to grow.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
[DataField, ViewVariables(VVAccess.ReadOnly)]
|
||||||
public ProtoId<ReagentPrototype> ReagentId = "Fiber";
|
public ProtoId<ReagentPrototype> ReagentId = "Fiber";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// How much wool to grow at every growth cycle.
|
/// The solution to add reagent to.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
[DataField, ViewVariables(VVAccess.ReadOnly)]
|
||||||
|
public string Solution = "wool";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The amount of reagent to be generated on update.
|
||||||
|
/// </summary>
|
||||||
|
[DataField, ViewVariables(VVAccess.ReadOnly)]
|
||||||
public FixedPoint2 Quantity = 25;
|
public FixedPoint2 Quantity = 25;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// What solution to add the wool reagent to.
|
/// The amount of nutrient consumed on update.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
||||||
public string Solution = "wool";
|
public float HungerUsage = 10f;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// How long to wait before growing wool.
|
/// How long to wait before growing wool.
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ using Content.Server.Actions;
|
|||||||
using Content.Server.Animals.Components;
|
using Content.Server.Animals.Components;
|
||||||
using Content.Server.Popups;
|
using Content.Server.Popups;
|
||||||
using Content.Shared.Actions.Events;
|
using Content.Shared.Actions.Events;
|
||||||
|
using Content.Shared.Mobs.Systems;
|
||||||
using Content.Shared.Nutrition.Components;
|
using Content.Shared.Nutrition.Components;
|
||||||
using Content.Shared.Nutrition.EntitySystems;
|
using Content.Shared.Nutrition.EntitySystems;
|
||||||
using Content.Shared.Storage;
|
using Content.Shared.Storage;
|
||||||
@@ -12,6 +13,10 @@ using Robust.Shared.Random;
|
|||||||
|
|
||||||
namespace Content.Server.Animals.Systems;
|
namespace Content.Server.Animals.Systems;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gives ability to produce eggs, produces endless if the
|
||||||
|
/// owner has no HungerComponent
|
||||||
|
/// </summary>
|
||||||
public sealed class EggLayerSystem : EntitySystem
|
public sealed class EggLayerSystem : EntitySystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IRobustRandom _random = default!;
|
[Dependency] private readonly IRobustRandom _random = default!;
|
||||||
@@ -19,6 +24,7 @@ public sealed class EggLayerSystem : EntitySystem
|
|||||||
[Dependency] private readonly AudioSystem _audio = default!;
|
[Dependency] private readonly AudioSystem _audio = default!;
|
||||||
[Dependency] private readonly HungerSystem _hunger = default!;
|
[Dependency] private readonly HungerSystem _hunger = default!;
|
||||||
[Dependency] private readonly PopupSystem _popup = default!;
|
[Dependency] private readonly PopupSystem _popup = default!;
|
||||||
|
[Dependency] private readonly MobStateSystem _mobState = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
@@ -57,35 +63,38 @@ public sealed class EggLayerSystem : EntitySystem
|
|||||||
component.CurrentEggLayCooldown = _random.NextFloat(component.EggLayCooldownMin, component.EggLayCooldownMax);
|
component.CurrentEggLayCooldown = _random.NextFloat(component.EggLayCooldownMin, component.EggLayCooldownMax);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnEggLayAction(EntityUid uid, EggLayerComponent component, EggLayInstantActionEvent args)
|
private void OnEggLayAction(EntityUid uid, EggLayerComponent egglayer, EggLayInstantActionEvent args)
|
||||||
{
|
{
|
||||||
args.Handled = TryLayEgg(uid, component);
|
args.Handled = TryLayEgg(uid, egglayer);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryLayEgg(EntityUid uid, EggLayerComponent? component)
|
public bool TryLayEgg(EntityUid uid, EggLayerComponent? egglayer)
|
||||||
{
|
{
|
||||||
if (!Resolve(uid, ref component))
|
if (!Resolve(uid, ref egglayer))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (_mobState.IsDead(uid))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Allow infinitely laying eggs if they can't get hungry
|
// Allow infinitely laying eggs if they can't get hungry
|
||||||
if (TryComp<HungerComponent>(uid, out var hunger))
|
if (TryComp<HungerComponent>(uid, out var hunger))
|
||||||
{
|
{
|
||||||
if (hunger.CurrentHunger < component.HungerUsage)
|
if (hunger.CurrentHunger < egglayer.HungerUsage)
|
||||||
{
|
{
|
||||||
_popup.PopupEntity(Loc.GetString("action-popup-lay-egg-too-hungry"), uid, uid);
|
_popup.PopupEntity(Loc.GetString("action-popup-lay-egg-too-hungry"), uid, uid);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
_hunger.ModifyHunger(uid, -component.HungerUsage, hunger);
|
_hunger.ModifyHunger(uid, -egglayer.HungerUsage, hunger);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var ent in EntitySpawnCollection.GetSpawns(component.EggSpawn, _random))
|
foreach (var ent in EntitySpawnCollection.GetSpawns(egglayer.EggSpawn, _random))
|
||||||
{
|
{
|
||||||
Spawn(ent, Transform(uid).Coordinates);
|
Spawn(ent, Transform(uid).Coordinates);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sound + popups
|
// Sound + popups
|
||||||
_audio.PlayPvs(component.EggLaySound, uid);
|
_audio.PlayPvs(egglayer.EggLaySound, uid);
|
||||||
_popup.PopupEntity(Loc.GetString("action-popup-lay-egg-user"), uid, uid);
|
_popup.PopupEntity(Loc.GetString("action-popup-lay-egg-user"), uid, uid);
|
||||||
_popup.PopupEntity(Loc.GetString("action-popup-lay-egg-others", ("entity", uid)), uid, Filter.PvsExcept(uid), true);
|
_popup.PopupEntity(Loc.GetString("action-popup-lay-egg-others", ("entity", uid)), uid, Filter.PvsExcept(uid), true);
|
||||||
|
|
||||||
|
|||||||
@@ -4,23 +4,28 @@ using Content.Shared.Chemistry.Components;
|
|||||||
using Content.Shared.Chemistry.EntitySystems;
|
using Content.Shared.Chemistry.EntitySystems;
|
||||||
using Content.Shared.DoAfter;
|
using Content.Shared.DoAfter;
|
||||||
using Content.Shared.IdentityManagement;
|
using Content.Shared.IdentityManagement;
|
||||||
|
using Content.Shared.Mobs.Systems;
|
||||||
using Content.Shared.Nutrition.Components;
|
using Content.Shared.Nutrition.Components;
|
||||||
using Content.Shared.Nutrition.EntitySystems;
|
using Content.Shared.Nutrition.EntitySystems;
|
||||||
using Content.Shared.Popups;
|
using Content.Shared.Popups;
|
||||||
using Content.Shared.Udder;
|
using Content.Shared.Udder;
|
||||||
using Content.Shared.Verbs;
|
using Content.Shared.Verbs;
|
||||||
|
using Robust.Shared.Timing;
|
||||||
|
|
||||||
|
namespace Content.Server.Animals.Systems;
|
||||||
|
|
||||||
namespace Content.Server.Animals.Systems
|
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gives ability to living beings with acceptable hunger level to produce milkable reagents.
|
/// Gives ability to produce milkable reagents, produces endless if the
|
||||||
|
/// owner has no HungerComponent
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal sealed class UdderSystem : EntitySystem
|
internal sealed class UdderSystem : EntitySystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!;
|
|
||||||
[Dependency] private readonly HungerSystem _hunger = default!;
|
[Dependency] private readonly HungerSystem _hunger = default!;
|
||||||
[Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!;
|
[Dependency] private readonly IGameTiming _timing = default!;
|
||||||
|
[Dependency] private readonly MobStateSystem _mobState = default!;
|
||||||
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
||||||
|
[Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!;
|
||||||
|
[Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
@@ -32,40 +37,44 @@ namespace Content.Server.Animals.Systems
|
|||||||
|
|
||||||
public override void Update(float frameTime)
|
public override void Update(float frameTime)
|
||||||
{
|
{
|
||||||
|
base.Update(frameTime);
|
||||||
|
|
||||||
var query = EntityQueryEnumerator<UdderComponent>();
|
var query = EntityQueryEnumerator<UdderComponent>();
|
||||||
|
var now = _timing.CurTime;
|
||||||
while (query.MoveNext(out var uid, out var udder))
|
while (query.MoveNext(out var uid, out var udder))
|
||||||
{
|
{
|
||||||
udder.AccumulatedFrameTime += frameTime;
|
if (now < udder.NextGrowth)
|
||||||
|
continue;
|
||||||
|
|
||||||
while (udder.AccumulatedFrameTime > udder.UpdateRate)
|
udder.NextGrowth = now + udder.GrowthDelay;
|
||||||
{
|
|
||||||
udder.AccumulatedFrameTime -= udder.UpdateRate;
|
if (_mobState.IsDead(uid))
|
||||||
|
continue;
|
||||||
|
|
||||||
// Actually there is food digestion so no problem with instant reagent generation "OnFeed"
|
// Actually there is food digestion so no problem with instant reagent generation "OnFeed"
|
||||||
if (EntityManager.TryGetComponent(uid, out HungerComponent? hunger))
|
if (EntityManager.TryGetComponent(uid, out HungerComponent? hunger))
|
||||||
{
|
{
|
||||||
// Is there enough nutrition to produce reagent?
|
// Is there enough nutrition to produce reagent?
|
||||||
if (_hunger.GetHungerThreshold(hunger) < HungerThreshold.Peckish)
|
if (_hunger.GetHungerThreshold(hunger) < HungerThreshold.Okay)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
_hunger.ModifyHunger(uid, -udder.HungerUsage, hunger);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_solutionContainerSystem.TryGetSolution(uid, udder.TargetSolutionName,
|
if (!_solutionContainerSystem.TryGetSolution(uid, udder.Solution, out var solution))
|
||||||
out var solution))
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
//TODO: toxins from bloodstream !?
|
//TODO: toxins from bloodstream !?
|
||||||
_solutionContainerSystem.TryAddReagent(uid, solution, udder.ReagentId,
|
_solutionContainerSystem.TryAddReagent(uid, solution, udder.ReagentId, udder.QuantityPerUpdate, out _);
|
||||||
udder.QuantityPerUpdate, out var accepted);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AttemptMilk(EntityUid uid, EntityUid userUid, EntityUid containerUid, UdderComponent? udder = null)
|
private void AttemptMilk(Entity<UdderComponent?> udder, EntityUid userUid, EntityUid containerUid)
|
||||||
{
|
{
|
||||||
if (!Resolve(uid, ref udder))
|
if (!Resolve(udder, ref udder.Comp))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var doargs = new DoAfterArgs(EntityManager, userUid, 5, new MilkingDoAfterEvent(), uid, uid, used: containerUid)
|
var doargs = new DoAfterArgs(EntityManager, userUid, 5, new MilkingDoAfterEvent(), udder, udder, used: containerUid)
|
||||||
{
|
{
|
||||||
BreakOnUserMove = true,
|
BreakOnUserMove = true,
|
||||||
BreakOnDamage = true,
|
BreakOnDamage = true,
|
||||||
@@ -81,7 +90,7 @@ namespace Content.Server.Animals.Systems
|
|||||||
if (args.Cancelled || args.Handled || args.Args.Used == null)
|
if (args.Cancelled || args.Handled || args.Args.Used == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!_solutionContainerSystem.TryGetSolution(uid, component.TargetSolutionName, out var solution))
|
if (!_solutionContainerSystem.TryGetSolution(uid, component.Solution, out var solution))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!_solutionContainerSystem.TryGetRefillableSolution(args.Args.Used.Value, out var targetSolution))
|
if (!_solutionContainerSystem.TryGetRefillableSolution(args.Args.Used.Value, out var targetSolution))
|
||||||
@@ -116,7 +125,7 @@ namespace Content.Server.Animals.Systems
|
|||||||
{
|
{
|
||||||
Act = () =>
|
Act = () =>
|
||||||
{
|
{
|
||||||
AttemptMilk(uid, args.User, args.Using.Value, component);
|
AttemptMilk(uid, args.User, args.Using.Value);
|
||||||
},
|
},
|
||||||
Text = Loc.GetString("udder-system-verb-milk"),
|
Text = Loc.GetString("udder-system-verb-milk"),
|
||||||
Priority = 2
|
Priority = 2
|
||||||
@@ -124,4 +133,3 @@ namespace Content.Server.Animals.Systems
|
|||||||
args.Verbs.Add(verb);
|
args.Verbs.Add(verb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using Content.Server.Animals.Components;
|
using Content.Server.Animals.Components;
|
||||||
using Content.Server.Nutrition;
|
using Content.Server.Nutrition;
|
||||||
using Content.Shared.Chemistry.EntitySystems;
|
using Content.Shared.Chemistry.EntitySystems;
|
||||||
|
using Content.Shared.Mobs.Systems;
|
||||||
using Content.Shared.Nutrition.Components;
|
using Content.Shared.Nutrition.Components;
|
||||||
using Content.Shared.Nutrition.EntitySystems;
|
using Content.Shared.Nutrition.EntitySystems;
|
||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
@@ -8,13 +9,14 @@ using Robust.Shared.Timing;
|
|||||||
namespace Content.Server.Animals.Systems;
|
namespace Content.Server.Animals.Systems;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles regeneration of an animal's wool solution when not hungry.
|
/// Gives ability to produce fiber reagents, produces endless if the
|
||||||
/// Shearing is not currently possible so the only use is for moths to eat.
|
/// owner has no HungerComponent
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class WoolySystem : EntitySystem
|
public sealed class WoolySystem : EntitySystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly HungerSystem _hunger = default!;
|
[Dependency] private readonly HungerSystem _hunger = default!;
|
||||||
[Dependency] private readonly IGameTiming _timing = default!;
|
[Dependency] private readonly IGameTiming _timing = default!;
|
||||||
|
[Dependency] private readonly MobStateSystem _mobState = default!;
|
||||||
[Dependency] private readonly SolutionContainerSystem _solutionContainer = default!;
|
[Dependency] private readonly SolutionContainerSystem _solutionContainer = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
@@ -28,23 +30,32 @@ public sealed class WoolySystem : EntitySystem
|
|||||||
{
|
{
|
||||||
base.Update(frameTime);
|
base.Update(frameTime);
|
||||||
|
|
||||||
var query = EntityQueryEnumerator<WoolyComponent, HungerComponent>();
|
var query = EntityQueryEnumerator<WoolyComponent>();
|
||||||
var now = _timing.CurTime;
|
var now = _timing.CurTime;
|
||||||
while (query.MoveNext(out var uid, out var comp, out var hunger))
|
while (query.MoveNext(out var uid, out var wooly))
|
||||||
{
|
{
|
||||||
if (now < comp.NextGrowth)
|
if (now < wooly.NextGrowth)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
comp.NextGrowth = now + comp.GrowthDelay;
|
wooly.NextGrowth = now + wooly.GrowthDelay;
|
||||||
|
|
||||||
|
if (_mobState.IsDead(uid))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Actually there is food digestion so no problem with instant reagent generation "OnFeed"
|
||||||
|
if (EntityManager.TryGetComponent(uid, out HungerComponent? hunger))
|
||||||
|
{
|
||||||
// Is there enough nutrition to produce reagent?
|
// Is there enough nutrition to produce reagent?
|
||||||
if (_hunger.GetHungerThreshold(hunger) < HungerThreshold.Peckish)
|
if (_hunger.GetHungerThreshold(hunger) < HungerThreshold.Okay)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!_solutionContainer.TryGetSolution(uid, comp.Solution, out var solution))
|
_hunger.ModifyHunger(uid, -wooly.HungerUsage, hunger);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_solutionContainer.TryGetSolution(uid, wooly.Solution, out var solution))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
_solutionContainer.TryAddReagent(uid, solution, comp.ReagentId, comp.Quantity, out _);
|
_solutionContainer.TryAddReagent(uid, solution, wooly.ReagentId, wooly.Quantity, out _);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ using Content.Shared.Mobs;
|
|||||||
using Content.Shared.Mobs.Components;
|
using Content.Shared.Mobs.Components;
|
||||||
using Content.Shared.Mobs.Systems;
|
using Content.Shared.Mobs.Systems;
|
||||||
using Content.Shared.Movement.Systems;
|
using Content.Shared.Movement.Systems;
|
||||||
|
using Content.Shared.Nutrition.AnimalHusbandry;
|
||||||
using Content.Shared.Nutrition.Components;
|
using Content.Shared.Nutrition.Components;
|
||||||
using Content.Shared.Popups;
|
using Content.Shared.Popups;
|
||||||
using Content.Shared.Roles;
|
using Content.Shared.Roles;
|
||||||
@@ -96,11 +97,13 @@ namespace Content.Server.Zombies
|
|||||||
var zombiecomp = AddComp<ZombieComponent>(target);
|
var zombiecomp = AddComp<ZombieComponent>(target);
|
||||||
|
|
||||||
//we need to basically remove all of these because zombies shouldn't
|
//we need to basically remove all of these because zombies shouldn't
|
||||||
//get diseases, breath, be thirst, be hungry, or die in space
|
//get diseases, breath, be thirst, be hungry, die in space or have offspring
|
||||||
RemComp<RespiratorComponent>(target);
|
RemComp<RespiratorComponent>(target);
|
||||||
RemComp<BarotraumaComponent>(target);
|
RemComp<BarotraumaComponent>(target);
|
||||||
RemComp<HungerComponent>(target);
|
RemComp<HungerComponent>(target);
|
||||||
RemComp<ThirstComponent>(target);
|
RemComp<ThirstComponent>(target);
|
||||||
|
RemComp<ReproductiveComponent>(target);
|
||||||
|
RemComp<ReproductivePartnerComponent>(target);
|
||||||
|
|
||||||
//funny voice
|
//funny voice
|
||||||
var accentType = "zombie";
|
var accentType = "zombie";
|
||||||
|
|||||||
Reference in New Issue
Block a user