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>
This commit is contained in:
deltanedas 2023-11-17 08:51:51 +00:00 committed by Debug
parent 764581d497
commit 9183b2b5b7
5 changed files with 131 additions and 12 deletions

View File

@ -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;
/// <summary>
/// Lets an animal grow a wool solution when not hungry.
/// </summary>
[RegisterComponent, Access(typeof(WoolySystem))]
public sealed partial class WoolyComponent : Component
{
/// <summary>
/// What reagent to grow.
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
public ProtoId<ReagentPrototype> ReagentId = "Fiber";
/// <summary>
/// How much wool to grow at every growth cycle.
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
public FixedPoint2 Quantity = 25;
/// <summary>
/// What solution to add the wool reagent to.
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
public string Solution = "wool";
/// <summary>
/// How long to wait before growing wool.
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
public TimeSpan GrowthDelay = TimeSpan.FromMinutes(1);
/// <summary>
/// When to next try growing wool.
/// </summary>
[DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), ViewVariables(VVAccess.ReadWrite)]
public TimeSpan NextGrowth = TimeSpan.FromSeconds(0);
}

View File

@ -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;
/// <summary>
/// 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.
/// </summary>
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<WoolyComponent, BeforeFullyEatenEvent>(OnBeforeFullyEaten);
}
public override void Update(float frameTime)
{
base.Update(frameTime);
var query = EntityQueryEnumerator<WoolyComponent, HungerComponent>();
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<WoolyComponent> ent, ref BeforeFullyEatenEvent args)
{
// don't want moths to delete goats after eating them
args.Cancel();
}
}

View File

@ -67,4 +67,10 @@ public sealed partial class FoodComponent : Component
/// </summary>
[DataField]
public float ForceFeedDelay = 3;
/// <summary>
/// For mobs that are food, requires killing them before eating.
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
public bool RequireDead = true;
}

View File

@ -95,7 +95,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
@ -303,33 +303,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;
}
@ -346,7 +351,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

View File

@ -576,6 +576,8 @@
- MobLayer
- type: Tag
tags:
# let moths eat wool directly
- ClothMade
- DoorBumpOpener
- Goat
- type: Reproductive
@ -601,11 +603,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