Files
tbd-station-14/Content.Server/Animals/Systems/EggLayerSystem.cs
Baa 1f42413416 Fix udder wooly reagent creation V2 (#32905)
* Changed comments to be more clear and uniform.
EggLayer uses NextGrowth instead of frame accumulation.
Egglayer uses much less energy to make eggs, and lay time is randomized for player and AI chicken.

* UdderComponent ReagentId can be changed now
UdderSystem and WoolySystem use SharedSolutionContainerSystem now

* Entities with udders can be examined to see a rough hunger level
udders and wooly stop reagent generation/extra nutrient usage once the solution container is full

* Moved stuff to Shared
AutoPausedField now

* Cleanup moving stuff to Shared

* Oops. Make UdderSystem sealed instead of abstract.

* Switch PopupEntity for PopupClient

* Didn't mean to delete Access

* new() instead of default! prototype
revert egglayer balance change
NextGrowth += timespan   in egglayer

* forgot [Datafield] for NextGrowth

* forgot NetworkedComponent again...

* Renaming Shared Animal to Shared Animals to match Server
Hopefully also resolve merge conflicts.

* Fix incorrect filename

* Update with requested changes
Put UdderSystem dependencies in alphabetical order.
Initialise NextGrowth for Udder and Wooly components on MapInitEvent.
Clean-up EggLayerSystem a little.
Re-write OnExamine function for UdderSystem, improving clarity.
Add full stops to end of udder examine locales.
And more :)

* Add some additional descriptions for cow hunger levels.

* Add Udder and Wooly quantity to AutoNetworkedField

* Account for less than starving threshold.

---------

Co-authored-by: sirionaut <sirionaut@gmail.com>
Co-authored-by: Sirionaut <148076704+Sirionaut@users.noreply.github.com>
Co-authored-by: Tayrtahn <tayrtahn@gmail.com>
2024-12-16 13:53:21 +01:00

109 lines
3.8 KiB
C#

using Content.Server.Actions;
using Content.Server.Animals.Components;
using Content.Server.Popups;
using Content.Shared.Actions.Events;
using Content.Shared.Mobs.Systems;
using Content.Shared.Nutrition.Components;
using Content.Shared.Nutrition.EntitySystems;
using Content.Shared.Storage;
using Robust.Server.Audio;
using Robust.Shared.Player;
using Robust.Shared.Random;
using Robust.Shared.Timing;
namespace Content.Server.Animals.Systems;
/// <summary>
/// Gives the ability to lay eggs/other things;
/// produces endlessly if the owner does not have a HungerComponent.
/// </summary>
public sealed class EggLayerSystem : EntitySystem
{
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly ActionsSystem _actions = default!;
[Dependency] private readonly AudioSystem _audio = default!;
[Dependency] private readonly HungerSystem _hunger = default!;
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly PopupSystem _popup = default!;
[Dependency] private readonly MobStateSystem _mobState = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<EggLayerComponent, MapInitEvent>(OnMapInit);
SubscribeLocalEvent<EggLayerComponent, EggLayInstantActionEvent>(OnEggLayAction);
}
public override void Update(float frameTime)
{
base.Update(frameTime);
var query = EntityQueryEnumerator<EggLayerComponent>();
while (query.MoveNext(out var uid, out var eggLayer))
{
// Players should be using the action.
if (HasComp<ActorComponent>(uid))
continue;
if (_timing.CurTime < eggLayer.NextGrowth)
continue;
// Randomize next growth time for more organic egglaying.
eggLayer.NextGrowth += TimeSpan.FromSeconds(_random.NextFloat(eggLayer.EggLayCooldownMin, eggLayer.EggLayCooldownMax));
if (_mobState.IsDead(uid))
continue;
// Hungerlevel check/modification is done in TryLayEgg()
// so it's used for player controlled chickens as well.
TryLayEgg(uid, eggLayer);
}
}
private void OnMapInit(EntityUid uid, EggLayerComponent component, MapInitEvent args)
{
_actions.AddAction(uid, ref component.Action, component.EggLayAction);
component.NextGrowth = _timing.CurTime + TimeSpan.FromSeconds(_random.NextFloat(component.EggLayCooldownMin, component.EggLayCooldownMax));
}
private void OnEggLayAction(EntityUid uid, EggLayerComponent egglayer, EggLayInstantActionEvent args)
{
// Cooldown is handeled by ActionAnimalLayEgg in types.yml.
args.Handled = TryLayEgg(uid, egglayer);
}
public bool TryLayEgg(EntityUid uid, EggLayerComponent? egglayer)
{
if (!Resolve(uid, ref egglayer))
return false;
if (_mobState.IsDead(uid))
return false;
// Allow infinitely laying eggs if they can't get hungry.
if (TryComp<HungerComponent>(uid, out var hunger))
{
if (hunger.CurrentHunger < egglayer.HungerUsage)
{
_popup.PopupEntity(Loc.GetString("action-popup-lay-egg-too-hungry"), uid, uid);
return false;
}
_hunger.ModifyHunger(uid, -egglayer.HungerUsage, hunger);
}
foreach (var ent in EntitySpawnCollection.GetSpawns(egglayer.EggSpawn, _random))
{
Spawn(ent, Transform(uid).Coordinates);
}
// Sound + popups
_audio.PlayPvs(egglayer.EggLaySound, 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);
return true;
}
}