--- /dev/null
+using Content.Shared.Sericulture;
+
+namespace Content.Client.Sericulture;
+
+/// <summary>
+/// <inheritdoc/>
+/// </summary>
+public sealed partial class SericultureSystem : SharedSericultureSystem { }
+++ /dev/null
-using Robust.Shared.Prototypes;
-using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
-
-namespace Content.Server.Sericulture;
-
-[RegisterComponent]
-public sealed partial class SericultureComponent : Component
-{
- [DataField("popupText")]
- public string PopupText = "sericulture-failure-hunger";
-
- /// <summary>
- /// What will be produced at the end of the action.
- /// </summary>
- [DataField("entityProduced", required: true)]
- public string EntityProduced = "";
-
- [DataField("action", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
- public string Action = "ActionSericulture";
-
- [DataField("actionEntity")] public EntityUid? ActionEntity;
-
- /// <summary>
- /// How long will it take to make.
- /// </summary>
- [DataField("productionLength", required: true), ViewVariables(VVAccess.ReadWrite)]
- public float ProductionLength = 0;
-
- [DataField("hungerCost"), ViewVariables(VVAccess.ReadWrite)]
- public float HungerCost = 0f;
-}
-using Content.Server.Actions;
-using Content.Server.DoAfter;
-using Content.Server.Popups;
-using Content.Server.Stack;
-using Content.Shared.DoAfter;
-using Content.Shared.Nutrition.Components;
-using Content.Shared.Nutrition.EntitySystems;
using Content.Shared.Sericulture;
namespace Content.Server.Sericulture;
-public sealed partial class SericultureSystem : EntitySystem
+public sealed partial class SericultureSystem : SharedSericultureSystem
{
- [Dependency] private readonly ActionsSystem _actionsSystem = default!;
- [Dependency] private readonly DoAfterSystem _doAfterSystem = default!;
- [Dependency] private readonly HungerSystem _hungerSystem = default!;
- [Dependency] private readonly PopupSystem _popupSystem = default!;
- [Dependency] private readonly StackSystem _stackSystem = default!;
-
- public override void Initialize()
- {
- base.Initialize();
-
- SubscribeLocalEvent<SericultureComponent, MapInitEvent>(OnCompMapInit);
- SubscribeLocalEvent<SericultureComponent, ComponentShutdown>(OnCompRemove);
- SubscribeLocalEvent<SericultureComponent, SericultureActionEvent>(OnSericultureStart);
- SubscribeLocalEvent<SericultureComponent, SericultureDoAfterEvent>(OnSericultureDoAfter);
- }
-
- private void OnCompMapInit(EntityUid uid, SericultureComponent comp, MapInitEvent args)
- {
- _actionsSystem.AddAction(uid, ref comp.ActionEntity, comp.Action, uid);
- }
-
- private void OnCompRemove(EntityUid uid, SericultureComponent comp, ComponentShutdown args)
- {
- _actionsSystem.RemoveAction(uid, comp.ActionEntity);
- }
-
- private void OnSericultureStart(EntityUid uid, SericultureComponent comp, SericultureActionEvent args)
- {
- if (IsHungry(uid))
- {
- _popupSystem.PopupEntity(Loc.GetString(comp.PopupText), uid, uid);
- return;
- }
-
- var doAfter = new DoAfterArgs(EntityManager, uid, comp.ProductionLength, new SericultureDoAfterEvent(), uid)
- {
- BreakOnUserMove = 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 (IsHungry(uid))
- {
- _popupSystem.PopupEntity(Loc.GetString(comp.PopupText), uid, uid);
- return;
- }
-
- _hungerSystem.ModifyHunger(uid, -comp.HungerCost);
-
- var newEntity = Spawn(comp.EntityProduced, Transform(uid).Coordinates);
-
- _stackSystem.TryMergeToHands(newEntity, uid);
-
- args.Repeat = true;
- }
-
- private bool IsHungry(EntityUid uid, HungerComponent? comp = null)
- {
- if (!Resolve(uid, ref comp))
- return false;
-
- if (_hungerSystem.GetHungerThreshold(comp) <= HungerThreshold.Peckish)
- return true;
-
- return false;
- }
}
return result;
}
+ /// <summary>
+ /// A check that returns if the entity is below a hunger threshold.
+ /// </summary>
+ public bool IsHungerBelowState(EntityUid uid, HungerThreshold threshold, float? food = null, HungerComponent? comp = null)
+ {
+ if (!Resolve(uid, ref comp))
+ return false; // It's never going to go hungry, so it's probably fine to assume that it's not... you know, hungry.
+
+ return GetHungerThreshold(comp, food) < threshold;
+ }
+
private bool GetMovementThreshold(HungerThreshold threshold)
{
switch (threshold)
--- /dev/null
+using Content.Shared.Nutrition.Components;
+using Robust.Shared.GameStates;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
+
+namespace Content.Shared.Sericulture;
+
+/// <summary>
+/// Should be applied to any mob that you want to be able to produce any material with an action and the cost of hunger.
+/// TODO: Probably adjust this to utilize organs?
+/// </summary>
+[RegisterComponent, NetworkedComponent, Access(typeof(SharedSericultureSystem))]
+public sealed partial class SericultureComponent : Component
+{
+ /// <summary>
+ /// The text that pops up whenever sericulture fails for not having enough hunger.
+ /// </summary>
+ [DataField("popupText")]
+ [ViewVariables(VVAccess.ReadWrite)]
+ [AutoNetworkedField]
+ public string PopupText = "sericulture-failure-hunger";
+
+ /// <summary>
+ /// What will be produced at the end of the action.
+ /// </summary>
+ [DataField("entityProduced", required: true, customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
+ [ViewVariables(VVAccess.ReadWrite)]
+ [AutoNetworkedField]
+ public string EntityProduced = string.Empty;
+
+ /// <summary>
+ /// The entity needed to actually preform sericulture. This will be granted (and removed) upon the entity's creation.
+ /// </summary>
+ [DataField("action", required: true, customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
+ [ViewVariables(VVAccess.ReadWrite)]
+ [AutoNetworkedField]
+ public string Action = string.Empty;
+
+ [AutoNetworkedField]
+ [DataField("actionEntity")]
+ public EntityUid? ActionEntity;
+
+ /// <summary>
+ /// How long will it take to make.
+ /// </summary>
+ [DataField("productionLength")]
+ [ViewVariables(VVAccess.ReadWrite)]
+ [AutoNetworkedField]
+ public float ProductionLength = 3f;
+
+ /// <summary>
+ /// This will subtract (not add, don't get this mixed up) from the current hunger of the mob doing sericulture.
+ /// </summary>
+ [DataField("hungerCost")]
+ [ViewVariables(VVAccess.ReadWrite)]
+ [AutoNetworkedField]
+ public float HungerCost = 5f;
+
+ /// <summary>
+ /// The lowest hunger threshold that this mob can be in before it's allowed to spin silk.
+ /// </summary>
+ [DataField("minHungerThreshold")]
+ [ViewVariables(VVAccess.ReadWrite)]
+ [AutoNetworkedField]
+ public HungerThreshold MinHungerThreshold = HungerThreshold.Okay;
+}
+++ /dev/null
-using Content.Shared.Actions;
-using Content.Shared.DoAfter;
-using Robust.Shared.Serialization;
-
-namespace Content.Shared.Sericulture;
-
-[Serializable, NetSerializable]
-public sealed partial class SericultureDoAfterEvent : SimpleDoAfterEvent { }
-
-public sealed partial class SericultureActionEvent : InstantActionEvent { }
--- /dev/null
+using Content.Shared.Actions;
+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;
+
+/// <summary>
+/// Allows mobs to produce materials with <see cref="SericultureComponent"/>.
+/// </summary>
+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<SericultureComponent, MapInitEvent>(OnMapInit);
+ SubscribeLocalEvent<SericultureComponent, ComponentShutdown>(OnCompRemove);
+ SubscribeLocalEvent<SericultureComponent, SericultureActionEvent>(OnSericultureStart);
+ SubscribeLocalEvent<SericultureComponent, SericultureDoAfterEvent>(OnSericultureDoAfter);
+ }
+
+ /// <summary>
+ /// Giveths the action to preform sericulture on the entity
+ /// </summary>
+ private void OnMapInit(EntityUid uid, SericultureComponent comp, MapInitEvent args)
+ {
+ _actionsSystem.AddAction(uid, ref comp.ActionEntity, comp.Action);
+ }
+
+ /// <summary>
+ /// Takeths away the action to preform sericulture from the entity.
+ /// </summary>
+ 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<HungerComponent>(uid, out var hungerComp)
+ && _hungerSystem.IsHungerBelowState(uid, comp.MinHungerThreshold, hungerComp.CurrentHunger - 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.
+ BreakOnUserMove = 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<HungerComponent>(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, hungerComp.CurrentHunger - comp.HungerCost, hungerComp))
+ {
+ _popupSystem.PopupClient(Loc.GetString(comp.PopupText), uid, uid);
+ return;
+ }
+
+ _hungerSystem.ModifyHunger(uid, -comp.HungerCost);
+
+ 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;
+ }
+}
+
+/// <summary>
+/// Should be relayed upon using the action.
+/// </summary>
+public sealed partial class SericultureActionEvent : InstantActionEvent { }
+
+/// <summary>
+/// Is relayed at the end of the sericulturing doafter.
+/// </summary>
+[Serializable, NetSerializable]
+public sealed partial class SericultureDoAfterEvent : SimpleDoAfterEvent { }
+