From: deltanedas <39013340+deltanedas@users.noreply.github.com>
Date: Fri, 17 Nov 2023 08:51:51 +0000 (+0000)
Subject: moths can eat goat wool (#21704)
X-Git-Url: https://git.smokeofanarchy.ru/gitweb.cgi?a=commitdiff_plain;h=1ba6cad88084ca3ff368c5fd42985dccf30058ad;p=space-station-14.git
moths can eat goat wool (#21704)
* add Wooly system
* add RequireDead to Food
* minor fix+cleanup and fix repeating
* minor fix+cleanup and fix repeating
* make goat wooly
---------
Co-authored-by: deltanedas <@deltanedas:kde.org>
---
diff --git a/Content.Server/Animals/Components/WoolyComponent.cs b/Content.Server/Animals/Components/WoolyComponent.cs
new file mode 100644
index 0000000000..8db44973e5
--- /dev/null
+++ b/Content.Server/Animals/Components/WoolyComponent.cs
@@ -0,0 +1,42 @@
+using Content.Server.Animals.Systems;
+using Content.Shared.Chemistry.Reagent;
+using Content.Shared.FixedPoint;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
+
+///
+/// Lets an animal grow a wool solution when not hungry.
+///
+[RegisterComponent, Access(typeof(WoolySystem))]
+public sealed partial class WoolyComponent : Component
+{
+ ///
+ /// What reagent to grow.
+ ///
+ [DataField, ViewVariables(VVAccess.ReadWrite)]
+ public ProtoId ReagentId = "Fiber";
+
+ ///
+ /// How much wool to grow at every growth cycle.
+ ///
+ [DataField, ViewVariables(VVAccess.ReadWrite)]
+ public FixedPoint2 Quantity = 25;
+
+ ///
+ /// What solution to add the wool reagent to.
+ ///
+ [DataField, ViewVariables(VVAccess.ReadWrite)]
+ public string Solution = "wool";
+
+ ///
+ /// How long to wait before growing wool.
+ ///
+ [DataField, ViewVariables(VVAccess.ReadWrite)]
+ public TimeSpan GrowthDelay = TimeSpan.FromMinutes(1);
+
+ ///
+ /// When to next try growing wool.
+ ///
+ [DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), ViewVariables(VVAccess.ReadWrite)]
+ public TimeSpan NextGrowth = TimeSpan.FromSeconds(0);
+}
diff --git a/Content.Server/Animals/Systems/WoolySystem.cs b/Content.Server/Animals/Systems/WoolySystem.cs
new file mode 100644
index 0000000000..e63718c395
--- /dev/null
+++ b/Content.Server/Animals/Systems/WoolySystem.cs
@@ -0,0 +1,56 @@
+using Content.Server.Animals.Components;
+using Content.Server.Nutrition;
+using Content.Shared.Chemistry.EntitySystems;
+using Content.Shared.Nutrition.Components;
+using Content.Shared.Nutrition.EntitySystems;
+using Robust.Shared.Timing;
+
+namespace Content.Server.Animals.Systems;
+
+///
+/// Handles regeneration of an animal's wool solution when not hungry.
+/// Shearing is not currently possible so the only use is for moths to eat.
+///
+public sealed class WoolySystem : EntitySystem
+{
+ [Dependency] private readonly HungerSystem _hunger = default!;
+ [Dependency] private readonly IGameTiming _timing = default!;
+ [Dependency] private readonly SolutionContainerSystem _solutionContainer = default!;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnBeforeFullyEaten);
+ }
+
+ public override void Update(float frameTime)
+ {
+ base.Update(frameTime);
+
+ var query = EntityQueryEnumerator();
+ var now = _timing.CurTime;
+ while (query.MoveNext(out var uid, out var comp, out var hunger))
+ {
+ if (now < comp.NextGrowth)
+ continue;
+
+ comp.NextGrowth = now + comp.GrowthDelay;
+
+ // Is there enough nutrition to produce reagent?
+ if (_hunger.GetHungerThreshold(hunger) < HungerThreshold.Peckish)
+ continue;
+
+ if (!_solutionContainer.TryGetSolution(uid, comp.Solution, out var solution))
+ continue;
+
+ _solutionContainer.TryAddReagent(uid, solution, comp.ReagentId, comp.Quantity, out _);
+ }
+ }
+
+ private void OnBeforeFullyEaten(Entity ent, ref BeforeFullyEatenEvent args)
+ {
+ // don't want moths to delete goats after eating them
+ args.Cancel();
+ }
+}
diff --git a/Content.Server/Nutrition/Components/FoodComponent.cs b/Content.Server/Nutrition/Components/FoodComponent.cs
index af74352132..c7f90ccff1 100644
--- a/Content.Server/Nutrition/Components/FoodComponent.cs
+++ b/Content.Server/Nutrition/Components/FoodComponent.cs
@@ -67,4 +67,10 @@ public sealed partial class FoodComponent : Component
///
[DataField]
public float ForceFeedDelay = 3;
+
+ ///
+ /// For mobs that are food, requires killing them before eating.
+ ///
+ [DataField, ViewVariables(VVAccess.ReadWrite)]
+ public bool RequireDead = true;
}
diff --git a/Content.Server/Nutrition/EntitySystems/FoodSystem.cs b/Content.Server/Nutrition/EntitySystems/FoodSystem.cs
index 758d42356e..51f75a2e19 100644
--- a/Content.Server/Nutrition/EntitySystems/FoodSystem.cs
+++ b/Content.Server/Nutrition/EntitySystems/FoodSystem.cs
@@ -96,7 +96,7 @@ public sealed class FoodSystem : EntitySystem
public (bool Success, bool Handled) TryFeed(EntityUid user, EntityUid target, EntityUid food, FoodComponent foodComp)
{
//Suppresses eating yourself and alive mobs
- if (food == user || _mobState.IsAlive(food))
+ if (food == user || (_mobState.IsAlive(food) && foodComp.RequireDead))
return (false, false);
// Target can't be fed or they're already eating
@@ -304,33 +304,38 @@ public sealed class FoodSystem : EntitySystem
return;
}
+ // don't try to repeat if its being deleted
+ args.Repeat = false;
+ DeleteAndSpawnTrash(component, uid, args.User);
+ }
+
+ public void DeleteAndSpawnTrash(FoodComponent component, EntityUid food, EntityUid user)
+ {
var ev = new BeforeFullyEatenEvent
{
- User = args.User
+ User = user
};
- RaiseLocalEvent(uid, ev);
+ RaiseLocalEvent(food, ev);
if (ev.Cancelled)
return;
if (string.IsNullOrEmpty(component.Trash))
- QueueDel(uid);
- else
- DeleteAndSpawnTrash(component, uid, args.User);
- }
+ {
+ QueueDel(food);
+ return;
+ }
- public void DeleteAndSpawnTrash(FoodComponent component, EntityUid food, EntityUid? user = null)
- {
//We're empty. Become trash.
var position = Transform(food).MapPosition;
var finisher = Spawn(component.Trash, position);
// If the user is holding the item
- if (user != null && _hands.IsHolding(user.Value, food, out var hand))
+ if (_hands.IsHolding(user, food, out var hand))
{
Del(food);
// Put the trash in the user's hand
- _hands.TryPickup(user.Value, finisher, hand);
+ _hands.TryPickup(user, finisher, hand);
return;
}
@@ -347,7 +352,7 @@ public sealed class FoodSystem : EntitySystem
return;
// have to kill mouse before eating it
- if (_mobState.IsAlive(uid))
+ if (_mobState.IsAlive(uid) && component.RequireDead)
return;
// only give moths eat verb for clothes since it would just fail otherwise
diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml
index 26e7a62018..5e24f0d30f 100644
--- a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml
+++ b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml
@@ -763,6 +763,8 @@
- MobLayer
- type: Tag
tags:
+ # let moths eat wool directly
+ - ClothMade
- DoorBumpOpener
- Goat
- type: Reproductive
@@ -788,11 +790,19 @@
reagents:
- ReagentId: MilkGoat
Quantity: 30
+ wool:
+ maxVol: 250
- type: Udder
reagentId: MilkGoat
targetSolution: udder
quantity: 25
updateRate: 20
+ - type: Wooly
+ - type: Food
+ solution: wool
+ requiresSpecialDigestion: true
+ # Wooly prevents eating wool deleting the goat so its fine
+ requireDead: false
- type: Butcherable
spawned:
- id: FoodMeat