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>
|
/// </summary>
|
||||||
[DataField]
|
[DataField]
|
||||||
public float ForceFeedDelay = 3;
|
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)
|
public (bool Success, bool Handled) TryFeed(EntityUid user, EntityUid target, EntityUid food, FoodComponent foodComp)
|
||||||
{
|
{
|
||||||
//Suppresses eating yourself and alive mobs
|
//Suppresses eating yourself and alive mobs
|
||||||
if (food == user || _mobState.IsAlive(food))
|
if (food == user || (_mobState.IsAlive(food) && foodComp.RequireDead))
|
||||||
return (false, false);
|
return (false, false);
|
||||||
|
|
||||||
// Target can't be fed or they're already eating
|
// Target can't be fed or they're already eating
|
||||||
|
|
@ -303,33 +303,38 @@ public sealed class FoodSystem : EntitySystem
|
||||||
return;
|
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
|
var ev = new BeforeFullyEatenEvent
|
||||||
{
|
{
|
||||||
User = args.User
|
User = user
|
||||||
};
|
};
|
||||||
RaiseLocalEvent(uid, ev);
|
RaiseLocalEvent(food, ev);
|
||||||
if (ev.Cancelled)
|
if (ev.Cancelled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(component.Trash))
|
if (string.IsNullOrEmpty(component.Trash))
|
||||||
QueueDel(uid);
|
{
|
||||||
else
|
QueueDel(food);
|
||||||
DeleteAndSpawnTrash(component, uid, args.User);
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DeleteAndSpawnTrash(FoodComponent component, EntityUid food, EntityUid? user = null)
|
|
||||||
{
|
|
||||||
//We're empty. Become trash.
|
//We're empty. Become trash.
|
||||||
var position = Transform(food).MapPosition;
|
var position = Transform(food).MapPosition;
|
||||||
var finisher = Spawn(component.Trash, position);
|
var finisher = Spawn(component.Trash, position);
|
||||||
|
|
||||||
// If the user is holding the item
|
// 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);
|
Del(food);
|
||||||
|
|
||||||
// Put the trash in the user's hand
|
// Put the trash in the user's hand
|
||||||
_hands.TryPickup(user.Value, finisher, hand);
|
_hands.TryPickup(user, finisher, hand);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -346,7 +351,7 @@ public sealed class FoodSystem : EntitySystem
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// have to kill mouse before eating it
|
// have to kill mouse before eating it
|
||||||
if (_mobState.IsAlive(uid))
|
if (_mobState.IsAlive(uid) && component.RequireDead)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// only give moths eat verb for clothes since it would just fail otherwise
|
// only give moths eat verb for clothes since it would just fail otherwise
|
||||||
|
|
|
||||||
|
|
@ -576,6 +576,8 @@
|
||||||
- MobLayer
|
- MobLayer
|
||||||
- type: Tag
|
- type: Tag
|
||||||
tags:
|
tags:
|
||||||
|
# let moths eat wool directly
|
||||||
|
- ClothMade
|
||||||
- DoorBumpOpener
|
- DoorBumpOpener
|
||||||
- Goat
|
- Goat
|
||||||
- type: Reproductive
|
- type: Reproductive
|
||||||
|
|
@ -601,11 +603,19 @@
|
||||||
reagents:
|
reagents:
|
||||||
- ReagentId: MilkGoat
|
- ReagentId: MilkGoat
|
||||||
Quantity: 30
|
Quantity: 30
|
||||||
|
wool:
|
||||||
|
maxVol: 250
|
||||||
- type: Udder
|
- type: Udder
|
||||||
reagentId: MilkGoat
|
reagentId: MilkGoat
|
||||||
targetSolution: udder
|
targetSolution: udder
|
||||||
quantity: 25
|
quantity: 25
|
||||||
updateRate: 20
|
updateRate: 20
|
||||||
|
- type: Wooly
|
||||||
|
- type: Food
|
||||||
|
solution: wool
|
||||||
|
requiresSpecialDigestion: true
|
||||||
|
# Wooly prevents eating wool deleting the goat so its fine
|
||||||
|
requireDead: false
|
||||||
- type: Butcherable
|
- type: Butcherable
|
||||||
spawned:
|
spawned:
|
||||||
- id: FoodMeat
|
- id: FoodMeat
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue