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.Nutrition.Prototypes; using Content.Shared.Stacks; using Robust.Shared.Prototypes; namespace Content.Shared.Sericulture; /// /// Allows mobs to produce materials with . /// public abstract partial class SharedSericultureSystem : EntitySystem { // Managers [Dependency] private INetManager _netManager = default!; // Systems [Dependency] private SharedActionsSystem _actionsSystem = default!; [Dependency] private SharedDoAfterSystem _doAfterSystem = default!; [Dependency] private SatiationSystem _satiation = default!; [Dependency] private SharedPopupSystem _popupSystem = default!; [Dependency] private 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; // Make sure to set the datafields before adding the component so that the correct action gets spawned on map init. var cloneComp = Factory.GetComponent(); cloneComp.PopupText = ent.Comp.PopupText; cloneComp.EntityProduced = ent.Comp.EntityProduced; cloneComp.Action = ent.Comp.Action; cloneComp.ProductionLength = ent.Comp.ProductionLength; cloneComp.HungerCost = ent.Comp.HungerCost; cloneComp.MinHungerThreshold = ent.Comp.MinHungerThreshold; AddComp(args.CloneUid, cloneComp, true); } /// /// 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 satiationComponent) || !_satiation.IsValueInRange((uid, satiationComponent), SatiationSystem.Hunger, above: comp.MinHungerThreshold, hypotheticalValueDelta: -comp.HungerCost)) { _popupSystem.PopupEntity(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; // A check, just incase the doafter is somehow performed when the entity is not in the right hunger state. if (!TryComp(uid, out var satiationComponent) || !_satiation.IsValueInRange((uid, satiationComponent), SatiationSystem.Hunger, above: comp.MinHungerThreshold, hypotheticalValueDelta: -comp.HungerCost)) { _popupSystem.PopupEntity(Loc.GetString(comp.PopupText), uid, uid); return; } _satiation.ModifyValue((uid, satiationComponent), SatiationSystem.Hunger, -comp.HungerCost); if (!_netManager.IsClient) // Have to do this because spawning stuff in shared is CBT. { var newEntity = SpawnNextToOrDrop(comp.EntityProduced, uid); _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;