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:
parent
764581d497
commit
9183b2b5b7
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue