using Content.Shared.Actions; using Content.Shared.Cloning.Events; using Content.Shared.DoAfter; using Content.Shared.Nutrition.EntitySystems; using Robust.Shared.Serialization; using Content.Shared.Popups; using Robust.Shared.Network; using Content.Shared.Nutrition.Components; using Content.Shared.Stacks; namespace Content.Shared.Sericulture; /// /// Allows mobs to produce materials with . /// public abstract partial class SharedSericultureSystem : EntitySystem { // Managers [Dependency] private readonly INetManager _netManager = default!; // Systems [Dependency] private readonly SharedActionsSystem _actionsSystem = default!; [Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!; [Dependency] private readonly HungerSystem _hungerSystem = default!; [Dependency] private readonly SharedPopupSystem _popupSystem = default!; [Dependency] private readonly SharedStackSystem _stackSystem = default!; public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnMapInit); SubscribeLocalEvent(OnCompRemove); SubscribeLocalEvent(OnSericultureStart); SubscribeLocalEvent(OnSericultureDoAfter); SubscribeLocalEvent(OnClone); } private void OnClone(Entity ent, ref CloningEvent args) { if (!args.Settings.EventComponents.Contains(Factory.GetRegistration(ent.Comp.GetType()).Name)) return; var comp = EnsureComp(args.CloneUid); comp.PopupText = ent.Comp.PopupText; comp.ProductionLength = ent.Comp.ProductionLength; comp.HungerCost = ent.Comp.HungerCost; comp.EntityProduced = ent.Comp.EntityProduced; comp.MinHungerThreshold = ent.Comp.MinHungerThreshold; Dirty(args.CloneUid, comp); } /// /// Giveths the action to preform sericulture on the entity /// private void OnMapInit(EntityUid uid, SericultureComponent comp, MapInitEvent args) { _actionsSystem.AddAction(uid, ref comp.ActionEntity, comp.Action); } /// /// Takeths away the action to preform sericulture from the entity. /// private void OnCompRemove(EntityUid uid, SericultureComponent comp, ComponentShutdown args) { _actionsSystem.RemoveAction(uid, comp.ActionEntity); } private void OnSericultureStart(EntityUid uid, SericultureComponent comp, SericultureActionEvent args) { if (!TryComp(uid, out var hungerComp) || _hungerSystem.IsHungerBelowState(uid, comp.MinHungerThreshold, _hungerSystem.GetHunger(hungerComp) - comp.HungerCost, hungerComp)) { _popupSystem.PopupClient(Loc.GetString(comp.PopupText), uid, uid); return; } var doAfter = new DoAfterArgs(EntityManager, uid, comp.ProductionLength, new SericultureDoAfterEvent(), uid) { // I'm not sure if more things should be put here, but imo ideally it should probably be set in the component/YAML. Not sure if this is currently possible. BreakOnMove = true, BlockDuplicate = true, BreakOnDamage = true, CancelDuplicate = true, }; _doAfterSystem.TryStartDoAfter(doAfter); } private void OnSericultureDoAfter(EntityUid uid, SericultureComponent comp, SericultureDoAfterEvent args) { if (args.Cancelled || args.Handled || comp.Deleted) return; if (!TryComp(uid, out var hungerComp) // A check, just incase the doafter is somehow performed when the entity is not in the right hunger state. || _hungerSystem.IsHungerBelowState(uid, comp.MinHungerThreshold, _hungerSystem.GetHunger(hungerComp) - comp.HungerCost, hungerComp)) { _popupSystem.PopupClient(Loc.GetString(comp.PopupText), uid, uid); return; } _hungerSystem.ModifyHunger(uid, -comp.HungerCost, hungerComp); if (!_netManager.IsClient) // Have to do this because spawning stuff in shared is CBT. { var newEntity = Spawn(comp.EntityProduced, Transform(uid).Coordinates); _stackSystem.TryMergeToHands(newEntity, uid); } args.Repeat = true; } } /// /// Should be relayed upon using the action. /// public sealed partial class SericultureActionEvent : InstantActionEvent { } /// /// Is relayed at the end of the sericulturing doafter. /// [Serializable, NetSerializable] public sealed partial class SericultureDoAfterEvent : SimpleDoAfterEvent { }