]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Task/food hud (#19312)
authorPrPleGoo <PrPleGoo@users.noreply.github.com>
Sat, 23 Sep 2023 13:14:06 +0000 (15:14 +0200)
committerGitHub <noreply@github.com>
Sat, 23 Sep 2023 13:14:06 +0000 (16:14 +0300)
* security HUD now shows a job icon on entities with a body

* thirst goggles

* set starting hud gear

* fix build

* remove from starting gear

* remove

* replace

* fix thirst and hunger icons

* update icons

* space

* space

* ]

* ]

* fix build

* fix comments

* fix

* spacing

* field

* move more namespaces

* use AutoGenerateComponentState

* comments

* fix build

* not all fields

* comments

* unpaused

* fix Dirty warning

---------

Co-authored-by: Slava0135 <super.novalskiy_0135@inbox.ru>
19 files changed:
Content.Client/Overlays/ShowHungerIconsSystem.cs [new file with mode: 0644]
Content.Client/Overlays/ShowThirstIconsSystem.cs [new file with mode: 0644]
Content.Server/Chemistry/ReagentEffects/SatiateThirst.cs
Content.Server/Medical/VomitSystem.cs
Content.Server/Nutrition/Components/ThirstComponent.cs [deleted file]
Content.Shared/Inventory/InventorySystem.Relay.cs
Content.Shared/Nutrition/Components/HungerComponent.cs
Content.Shared/Nutrition/Components/ThirstComponent.cs [new file with mode: 0644]
Content.Shared/Nutrition/EntitySystems/HungerSystem.cs
Content.Shared/Nutrition/EntitySystems/ThirstSystem.cs [moved from Content.Server/Nutrition/EntitySystems/ThirstSystem.cs with 84% similarity]
Content.Shared/Overlays/ShowHungerIconsComponent.cs [new file with mode: 0644]
Content.Shared/Overlays/ShowSecurityIconsComponent.cs
Content.Shared/Overlays/ShowThirstIconsComponent.cs [new file with mode: 0644]
Resources/Prototypes/Entities/Clothing/Eyes/hud.yml
Resources/Prototypes/StatusEffects/hunger.yml [new file with mode: 0644]
Resources/Textures/Interface/Misc/food_icons.rsi/parched.png
Resources/Textures/Interface/Misc/food_icons.rsi/peckish.png
Resources/Textures/Interface/Misc/food_icons.rsi/starving.png
Resources/Textures/Interface/Misc/food_icons.rsi/thirsty.png

diff --git a/Content.Client/Overlays/ShowHungerIconsSystem.cs b/Content.Client/Overlays/ShowHungerIconsSystem.cs
new file mode 100644 (file)
index 0000000..0182a08
--- /dev/null
@@ -0,0 +1,58 @@
+using Content.Shared.Nutrition.Components;
+using Content.Shared.Overlays;
+using Content.Shared.StatusIcon;
+using Content.Shared.StatusIcon.Components;
+using Robust.Shared.Prototypes;
+
+namespace Content.Client.Overlays;
+
+public sealed class ShowHungerIconsSystem : EquipmentHudSystem<ShowHungerIconsComponent>
+{
+    [Dependency] private readonly IPrototypeManager _prototypeMan = default!;
+
+    public override void Initialize()
+    {
+        base.Initialize();
+
+        SubscribeLocalEvent<HungerComponent, GetStatusIconsEvent>(OnGetStatusIconsEvent);
+    }
+
+    private void OnGetStatusIconsEvent(EntityUid uid, HungerComponent hungerComponent, ref GetStatusIconsEvent args)
+    {
+        if (!IsActive || args.InContainer)
+            return;
+
+        var healthIcons = DecideHungerIcon(uid, hungerComponent);
+
+        args.StatusIcons.AddRange(healthIcons);
+    }
+
+    private IReadOnlyList<StatusIconPrototype> DecideHungerIcon(EntityUid uid, HungerComponent hungerComponent)
+    {
+        var result = new List<StatusIconPrototype>();
+
+        switch (hungerComponent.CurrentThreshold)
+        {
+            case HungerThreshold.Overfed:
+                if (_prototypeMan.TryIndex<StatusIconPrototype>("HungerIconOverfed", out var overfed))
+                {
+                    result.Add(overfed);
+                }
+                break;
+            case HungerThreshold.Peckish:
+                if (_prototypeMan.TryIndex<StatusIconPrototype>("HungerIconPeckish", out var peckish))
+                {
+                    result.Add(peckish);
+                }
+                break;
+            case HungerThreshold.Starving:
+                if (_prototypeMan.TryIndex<StatusIconPrototype>("HungerIconStarving", out var starving))
+                {
+                    result.Add(starving);
+                }
+                break;
+        }
+
+        return result;
+    }
+}
diff --git a/Content.Client/Overlays/ShowThirstIconsSystem.cs b/Content.Client/Overlays/ShowThirstIconsSystem.cs
new file mode 100644 (file)
index 0000000..89bc502
--- /dev/null
@@ -0,0 +1,58 @@
+using Content.Shared.Nutrition.Components;
+using Content.Shared.Overlays;
+using Content.Shared.StatusIcon;
+using Content.Shared.StatusIcon.Components;
+using Robust.Shared.Prototypes;
+
+namespace Content.Client.Overlays;
+
+public sealed class ShowThirstIconsSystem : EquipmentHudSystem<ShowThirstIconsComponent>
+{
+    [Dependency] private readonly IPrototypeManager _prototypeMan = default!;
+
+    public override void Initialize()
+    {
+        base.Initialize();
+
+        SubscribeLocalEvent<ThirstComponent, GetStatusIconsEvent>(OnGetStatusIconsEvent);
+    }
+
+    private void OnGetStatusIconsEvent(EntityUid uid, ThirstComponent thirstComponent, ref GetStatusIconsEvent args)
+    {
+        if (!IsActive || args.InContainer)
+            return;
+
+        var healthIcons = DecideThirstIcon(uid, thirstComponent);
+
+        args.StatusIcons.AddRange(healthIcons);
+    }
+
+    private IReadOnlyList<StatusIconPrototype> DecideThirstIcon(EntityUid uid, ThirstComponent thirstComponent)
+    {
+        var result = new List<StatusIconPrototype>();
+
+        switch (thirstComponent.CurrentThirstThreshold)
+        {
+            case ThirstThreshold.OverHydrated:
+                if (_prototypeMan.TryIndex<StatusIconPrototype>("ThirstIconOverhydrated", out var overhydrated))
+                {
+                    result.Add(overhydrated);
+                }
+                break;
+            case ThirstThreshold.Thirsty:
+                if (_prototypeMan.TryIndex<StatusIconPrototype>("ThirstIconThirsty", out var thirsty))
+                {
+                    result.Add(thirsty);
+                }
+                break;
+            case ThirstThreshold.Parched:
+                if (_prototypeMan.TryIndex<StatusIconPrototype>("ThirstIconParched", out var parched))
+                {
+                    result.Add(parched);
+                }
+                break;
+        }
+
+        return result;
+    }
+}
index 551e4923bc9d605c4520280c50fe7a39456eafe9..529aa8adf179099ec83ea14763f3cf46145699c8 100644 (file)
@@ -1,6 +1,6 @@
-using Content.Server.Nutrition.Components;
-using Content.Shared.Chemistry.Reagent;
 using Content.Server.Nutrition.EntitySystems;
+using Content.Shared.Chemistry.Reagent;
+using Content.Shared.Nutrition.Components;
 using Robust.Shared.Prototypes;
 
 namespace Content.Server.Chemistry.ReagentEffects
index ed62176973880f3e61e1ac3972c4cfc744780be4..a764cd2b19cfed5e19cbd55b2d000fa79622bca7 100644 (file)
@@ -1,16 +1,12 @@
 using Content.Server.Body.Components;
 using Content.Server.Body.Systems;
 using Content.Server.Chemistry.EntitySystems;
-using Content.Server.Fluids.Components;
 using Content.Server.Fluids.EntitySystems;
 using Content.Server.Forensics;
-using Content.Server.Nutrition.Components;
 using Content.Server.Nutrition.EntitySystems;
 using Content.Server.Popups;
 using Content.Server.Stunnable;
-using Content.Shared.Audio;
 using Content.Shared.Chemistry.Components;
-using Content.Shared.Fluids.Components;
 using Content.Shared.IdentityManagement;
 using Content.Shared.Nutrition.Components;
 using Content.Shared.Nutrition.EntitySystems;
diff --git a/Content.Server/Nutrition/Components/ThirstComponent.cs b/Content.Server/Nutrition/Components/ThirstComponent.cs
deleted file mode 100644 (file)
index 1b2d904..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-using Content.Shared.Alert;
-
-namespace Content.Server.Nutrition.Components
-{
-    [Flags]
-    public enum ThirstThreshold : byte
-    {
-        // Hydrohomies
-        Dead = 0,
-        Parched = 1 << 0,
-        Thirsty = 1 << 1,
-        Okay = 1 << 2,
-        OverHydrated = 1 << 3,
-    }
-
-    [RegisterComponent]
-    public sealed partial class ThirstComponent : Component
-    {
-        // Base stuff
-        [ViewVariables(VVAccess.ReadWrite)]
-        [DataField("baseDecayRate")]
-        public float BaseDecayRate = 0.1f;
-
-        [ViewVariables(VVAccess.ReadWrite)]
-        public float ActualDecayRate;
-
-        // Thirst
-        [ViewVariables(VVAccess.ReadOnly)]
-        public ThirstThreshold CurrentThirstThreshold;
-
-        public ThirstThreshold LastThirstThreshold;
-
-        [ViewVariables(VVAccess.ReadWrite)]
-        [DataField("startingThirst")]
-        public float CurrentThirst = -1f;
-
-        [DataField("thresholds")]
-        public Dictionary<ThirstThreshold, float> ThirstThresholds { get; private set; } = new()
-        {
-            {ThirstThreshold.OverHydrated, 600.0f},
-            {ThirstThreshold.Okay, 450.0f},
-            {ThirstThreshold.Thirsty, 300.0f},
-            {ThirstThreshold.Parched, 150.0f},
-            {ThirstThreshold.Dead, 0.0f},
-        };
-
-        public static readonly Dictionary<ThirstThreshold, AlertType> ThirstThresholdAlertTypes = new()
-        {
-            {ThirstThreshold.Thirsty, AlertType.Thirsty},
-            {ThirstThreshold.Parched, AlertType.Parched},
-            {ThirstThreshold.Dead, AlertType.Parched},
-        };
-    }
-}
index 1731d5c64e947180f25f245b563c3c8ea41e2b06..83b47542e2929ca9adff1085074678ebff8af27a 100644 (file)
@@ -38,6 +38,8 @@ public partial class InventorySystem
 
         // ComponentActivatedClientSystems
         SubscribeLocalEvent<InventoryComponent, RefreshEquipmentHudEvent<ShowSecurityIconsComponent>>(RelayInventoryEvent);
+        SubscribeLocalEvent<InventoryComponent, RefreshEquipmentHudEvent<ShowHungerIconsComponent>>(RelayInventoryEvent);
+        SubscribeLocalEvent<InventoryComponent, RefreshEquipmentHudEvent<ShowThirstIconsComponent>>(RelayInventoryEvent);
 
         SubscribeLocalEvent<InventoryComponent, GetVerbsEvent<EquipmentVerb>>(OnGetStrippingVerbs);
     }
index 25d1e5e0a2efd40c76c1f84faa9f7540c3fcbbb7..037c069cf4dc76d9a9d486985e6fc53149ca9d99 100644 (file)
@@ -9,12 +9,14 @@ using Robust.Shared.Serialization.TypeSerializers.Implementations.Generic;
 namespace Content.Shared.Nutrition.Components;
 
 [RegisterComponent, NetworkedComponent, Access(typeof(HungerSystem))]
+[AutoGenerateComponentState]
 public sealed partial class HungerComponent : Component
 {
     /// <summary>
     /// The current hunger amount of the entity
     /// </summary>
     [DataField("currentHunger"), ViewVariables(VVAccess.ReadWrite)]
+    [AutoNetworkedField]
     public float CurrentHunger;
 
     /// <summary>
@@ -28,6 +30,7 @@ public sealed partial class HungerComponent : Component
     /// Affected by <seealso cref="CurrentThreshold"/>
     /// </summary>
     [DataField("actualDecayRate"), ViewVariables(VVAccess.ReadWrite)]
+    [AutoNetworkedField]
     public float ActualDecayRate;
 
     /// <summary>
@@ -35,18 +38,21 @@ public sealed partial class HungerComponent : Component
     /// Stored in order to prevent recalculating
     /// </summary>
     [DataField("lastThreshold"), ViewVariables(VVAccess.ReadWrite)]
+    [AutoNetworkedField]
     public HungerThreshold LastThreshold;
 
     /// <summary>
     /// The current hunger threshold the entity is at
     /// </summary>
     [DataField("currentThreshold"), ViewVariables(VVAccess.ReadWrite)]
+    [AutoNetworkedField]
     public HungerThreshold CurrentThreshold;
 
     /// <summary>
     /// A dictionary relating HungerThreshold to the amount of <see cref="CurrentHunger"/> needed for each one
     /// </summary>
     [DataField("thresholds", customTypeSerializer: typeof(DictionarySerializer<HungerThreshold, float>))]
+    [AutoNetworkedField(cloneData: true)]
     public Dictionary<HungerThreshold, float> Thresholds = new()
     {
         { HungerThreshold.Overfed, 200.0f },
@@ -60,6 +66,7 @@ public sealed partial class HungerComponent : Component
     /// A dictionary relating hunger thresholds to corresponding alerts.
     /// </summary>
     [DataField("hungerThresholdAlerts", customTypeSerializer: typeof(DictionarySerializer<HungerThreshold, AlertType>))]
+    [AutoNetworkedField(cloneData: true)]
     public Dictionary<HungerThreshold, AlertType> HungerThresholdAlerts = new()
     {
         { HungerThreshold.Peckish, AlertType.Peckish },
@@ -71,6 +78,7 @@ public sealed partial class HungerComponent : Component
     /// A dictionary relating HungerThreshold to how much they modify <see cref="BaseDecayRate"/>.
     /// </summary>
     [DataField("hungerThresholdDecayModifiers", customTypeSerializer: typeof(DictionarySerializer<HungerThreshold, float>))]
+    [AutoNetworkedField(cloneData: true)]
     public Dictionary<HungerThreshold, float> HungerThresholdDecayModifiers = new()
     {
         { HungerThreshold.Overfed, 1.2f },
@@ -84,6 +92,7 @@ public sealed partial class HungerComponent : Component
     /// The amount of slowdown applied when an entity is starving
     /// </summary>
     [DataField("starvingSlowdownModifier"), ViewVariables(VVAccess.ReadWrite)]
+    [AutoNetworkedField]
     public float StarvingSlowdownModifier = 0.75f;
 
     /// <summary>
@@ -96,50 +105,17 @@ public sealed partial class HungerComponent : Component
     /// The time when the hunger will update next.
     /// </summary>
     [DataField("nextUpdateTime", customTypeSerializer: typeof(TimeOffsetSerializer)), ViewVariables(VVAccess.ReadWrite)]
+    [AutoNetworkedField]
     public TimeSpan NextUpdateTime;
 
     /// <summary>
     /// The time between each update.
     /// </summary>
     [ViewVariables(VVAccess.ReadWrite)]
+    [AutoNetworkedField]
     public TimeSpan UpdateRate = TimeSpan.FromSeconds(1);
 }
 
-[Serializable, NetSerializable]
-public sealed class HungerComponentState : ComponentState
-{
-    public float CurrentHunger;
-
-    public float BaseDecayRate;
-
-    public float ActualDecayRate;
-
-    public HungerThreshold LastHungerThreshold;
-
-    public HungerThreshold CurrentThreshold;
-
-    public float StarvingSlowdownModifier;
-
-    public TimeSpan NextUpdateTime;
-
-    public HungerComponentState(float currentHunger,
-        float baseDecayRate,
-        float actualDecayRate,
-        HungerThreshold lastHungerThreshold,
-        HungerThreshold currentThreshold,
-        float starvingSlowdownModifier,
-        TimeSpan nextUpdateTime)
-    {
-        CurrentHunger = currentHunger;
-        BaseDecayRate = baseDecayRate;
-        ActualDecayRate = actualDecayRate;
-        LastHungerThreshold = lastHungerThreshold;
-        CurrentThreshold = currentThreshold;
-        StarvingSlowdownModifier = starvingSlowdownModifier;
-        NextUpdateTime = nextUpdateTime;
-    }
-}
-
 [Serializable, NetSerializable]
 public enum HungerThreshold : byte
 {
diff --git a/Content.Shared/Nutrition/Components/ThirstComponent.cs b/Content.Shared/Nutrition/Components/ThirstComponent.cs
new file mode 100644 (file)
index 0000000..da75a8e
--- /dev/null
@@ -0,0 +1,78 @@
+using Content.Server.Nutrition.EntitySystems;
+using Content.Shared.Alert;
+using Robust.Shared.GameStates;
+using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
+
+namespace Content.Shared.Nutrition.Components;
+
+[RegisterComponent, NetworkedComponent, Access(typeof(ThirstSystem))]
+[AutoGenerateComponentState]
+public sealed partial class ThirstComponent : Component
+{
+    // Base stuff
+    [ViewVariables(VVAccess.ReadWrite)]
+    [DataField("baseDecayRate")]
+    [AutoNetworkedField]
+    public float BaseDecayRate = 0.1f;
+
+    [ViewVariables(VVAccess.ReadWrite)]
+    [AutoNetworkedField]
+    public float ActualDecayRate;
+
+    // Thirst
+    [ViewVariables(VVAccess.ReadOnly)]
+    [AutoNetworkedField]
+    public ThirstThreshold CurrentThirstThreshold;
+
+    [ViewVariables(VVAccess.ReadOnly)]
+    [AutoNetworkedField]
+    public ThirstThreshold LastThirstThreshold;
+
+    [ViewVariables(VVAccess.ReadWrite)]
+    [DataField("startingThirst")]
+    [AutoNetworkedField]
+    public float CurrentThirst = -1f;
+
+    /// <summary>
+    /// The time when the hunger will update next.
+    /// </summary>
+    [DataField("nextUpdateTime", customTypeSerializer: typeof(TimeOffsetSerializer)), ViewVariables(VVAccess.ReadWrite)]
+    [AutoNetworkedField]
+    public TimeSpan NextUpdateTime;
+
+    /// <summary>
+    /// The time between each update.
+    /// </summary>
+    [ViewVariables(VVAccess.ReadWrite)]
+    [AutoNetworkedField]
+    public TimeSpan UpdateRate = TimeSpan.FromSeconds(1);
+
+    [DataField("thresholds")]
+    [AutoNetworkedField(cloneData: true)]
+    public Dictionary<ThirstThreshold, float> ThirstThresholds = new()
+    {
+        {ThirstThreshold.OverHydrated, 600.0f},
+        {ThirstThreshold.Okay, 450.0f},
+        {ThirstThreshold.Thirsty, 300.0f},
+        {ThirstThreshold.Parched, 150.0f},
+        {ThirstThreshold.Dead, 0.0f},
+    };
+
+    public static readonly Dictionary<ThirstThreshold, AlertType> ThirstThresholdAlertTypes = new()
+    {
+        {ThirstThreshold.Thirsty, AlertType.Thirsty},
+        {ThirstThreshold.Parched, AlertType.Parched},
+        {ThirstThreshold.Dead, AlertType.Parched},
+    };
+}
+
+[Flags]
+public enum ThirstThreshold : byte
+{
+    // Hydrohomies
+    Dead = 0,
+    Parched = 1 << 0,
+    Thirsty = 1 << 1,
+    Okay = 1 << 2,
+    OverHydrated = 1 << 3,
+}
index d5f8860081ea705b3ea0d23307d1f4f271ca9a43..8baee3e379947990f0ad4ac63d6482b49a6b6789 100644 (file)
@@ -1,10 +1,9 @@
-using Content.Shared.Alert;
+using Content.Shared.Alert;
 using Content.Shared.Damage;
 using Content.Shared.Mobs.Systems;
 using Content.Shared.Movement.Systems;
 using Content.Shared.Nutrition.Components;
 using Content.Shared.Rejuvenate;
-using Robust.Shared.GameStates;
 using Robust.Shared.Random;
 using Robust.Shared.Timing;
 
@@ -24,8 +23,6 @@ public sealed class HungerSystem : EntitySystem
     {
         base.Initialize();
 
-        SubscribeLocalEvent<HungerComponent, ComponentGetState>(OnGetState);
-        SubscribeLocalEvent<HungerComponent, ComponentHandleState>(OnHandleState);
         SubscribeLocalEvent<HungerComponent, EntityUnpausedEvent>(OnUnpaused);
         SubscribeLocalEvent<HungerComponent, MapInitEvent>(OnMapInit);
         SubscribeLocalEvent<HungerComponent, ComponentShutdown>(OnShutdown);
@@ -33,30 +30,6 @@ public sealed class HungerSystem : EntitySystem
         SubscribeLocalEvent<HungerComponent, RejuvenateEvent>(OnRejuvenate);
     }
 
-    private void OnGetState(EntityUid uid, HungerComponent component, ref ComponentGetState args)
-    {
-        args.State = new HungerComponentState(component.CurrentHunger,
-            component.BaseDecayRate,
-            component.ActualDecayRate,
-            component.LastThreshold,
-            component.CurrentThreshold,
-            component.StarvingSlowdownModifier,
-            component.NextUpdateTime);
-    }
-
-    private void OnHandleState(EntityUid uid, HungerComponent component, ref ComponentHandleState args)
-    {
-        if (args.Current is not HungerComponentState state)
-            return;
-        component.CurrentHunger = state.CurrentHunger;
-        component.BaseDecayRate = state.BaseDecayRate;
-        component.ActualDecayRate = state.ActualDecayRate;
-        component.LastThreshold = state.LastHungerThreshold;
-        component.CurrentThreshold = state.CurrentThreshold;
-        component.StarvingSlowdownModifier = state.StarvingSlowdownModifier;
-        component.NextUpdateTime = state.NextUpdateTime;
-    }
-
     private void OnUnpaused(EntityUid uid, HungerComponent component, ref EntityUnpausedEvent args)
     {
         component.NextUpdateTime += args.PausedTime;
similarity index 84%
rename from Content.Server/Nutrition/EntitySystems/ThirstSystem.cs
rename to Content.Shared/Nutrition/EntitySystems/ThirstSystem.cs
index 2e9c1134a29f9b3770ce7fa5db006a3b6d505991..4fa7c417aa45b915f7d7c2918b2d5ff18185c4ea 100644 (file)
@@ -1,23 +1,24 @@
-using Content.Server.Nutrition.Components;
-using JetBrains.Annotations;
-using Robust.Shared.Random;
-using Content.Shared.Movement.Components;
 using Content.Shared.Alert;
+using Content.Shared.Movement.Components;
 using Content.Shared.Movement.Systems;
+using Content.Shared.Nutrition.Components;
 using Content.Shared.Rejuvenate;
+using JetBrains.Annotations;
+using Robust.Shared.Random;
+using Robust.Shared.Timing;
 
 namespace Content.Server.Nutrition.EntitySystems;
 
 [UsedImplicitly]
 public sealed class ThirstSystem : EntitySystem
 {
+    [Dependency] private readonly IGameTiming _timing = default!;
     [Dependency] private readonly IRobustRandom _random = default!;
     [Dependency] private readonly AlertsSystem _alerts = default!;
     [Dependency] private readonly MovementSpeedModifierSystem _movement = default!;
     [Dependency] private readonly SharedJetpackSystem _jetpack = default!;
 
     private ISawmill _sawmill = default!;
-    private float _accumulatedFrameTime;
 
     public override void Initialize()
     {
@@ -28,6 +29,7 @@ public sealed class ThirstSystem : EntitySystem
         SubscribeLocalEvent<ThirstComponent, RefreshMovementSpeedModifiersEvent>(OnRefreshMovespeed);
         SubscribeLocalEvent<ThirstComponent, ComponentStartup>(OnComponentStartup);
         SubscribeLocalEvent<ThirstComponent, RejuvenateEvent>(OnRejuvenate);
+        SubscribeLocalEvent<ThirstComponent, EntityUnpausedEvent>(OnUnpaused);
     }
 
     private void OnComponentStartup(EntityUid uid, ThirstComponent component, ComponentStartup args)
@@ -154,22 +156,30 @@ public sealed class ThirstSystem : EntitySystem
 
     public override void Update(float frameTime)
     {
-        _accumulatedFrameTime += frameTime;
+        base.Update(frameTime);
 
-        if (_accumulatedFrameTime > 1)
+        var query = EntityQueryEnumerator<ThirstComponent>();
+        while (query.MoveNext(out var uid, out var thirst))
         {
-            var query = EntityManager.EntityQueryEnumerator<ThirstComponent>();
-            while (query.MoveNext(out var uid, out var comp))
-            {
-                UpdateThirst(comp, - comp.ActualDecayRate);
-                var calculatedThirstThreshold = GetThirstThreshold(comp, comp.CurrentThirst);
-                if (calculatedThirstThreshold != comp.CurrentThirstThreshold)
-                {
-                    comp.CurrentThirstThreshold = calculatedThirstThreshold;
-                    UpdateEffects(uid, comp);
-                }
-            }
-            _accumulatedFrameTime -= 1;
+            if (_timing.CurTime < thirst.NextUpdateTime)
+                continue;
+
+            thirst.NextUpdateTime += thirst.UpdateRate;
+
+            UpdateThirst(thirst, -thirst.ActualDecayRate);
+            var calculatedThirstThreshold = GetThirstThreshold(thirst, thirst.CurrentThirst);
+
+            if (calculatedThirstThreshold == thirst.CurrentThirstThreshold)
+                continue;
+
+            thirst.CurrentThirstThreshold = calculatedThirstThreshold;
+            UpdateEffects(uid, thirst);
+            Dirty(uid, thirst);
         }
     }
+
+    private void OnUnpaused(EntityUid uid, ThirstComponent component, ref EntityUnpausedEvent args)
+    {
+        component.NextUpdateTime += args.PausedTime;
+    }
 }
diff --git a/Content.Shared/Overlays/ShowHungerIconsComponent.cs b/Content.Shared/Overlays/ShowHungerIconsComponent.cs
new file mode 100644 (file)
index 0000000..bf1fb2d
--- /dev/null
@@ -0,0 +1,9 @@
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Overlays;
+
+/// <summary>
+/// This component allows you to see the hungriness of mobs.
+/// </summary>
+[RegisterComponent, NetworkedComponent]
+public sealed partial class ShowHungerIconsComponent : Component { }
index 2127408afbdbea153281c1e0b8df2fec4e5a0f58..ec268174d18f92dd6dbf3020180f297c31aeae01 100644 (file)
@@ -1,10 +1,9 @@
 using Robust.Shared.GameStates;
 
-namespace Content.Shared.Overlays
-{
-    /// <summary>
-    /// This component allows you to see job icons above mobs.
-    /// </summary>
-    [RegisterComponent, NetworkedComponent]
-    public sealed partial class ShowSecurityIconsComponent : Component { }
-}
+namespace Content.Shared.Overlays;
+
+/// <summary>
+/// This component allows you to see job icons above mobs.
+/// </summary>
+[RegisterComponent, NetworkedComponent]
+public sealed partial class ShowSecurityIconsComponent : Component { }
diff --git a/Content.Shared/Overlays/ShowThirstIconsComponent.cs b/Content.Shared/Overlays/ShowThirstIconsComponent.cs
new file mode 100644 (file)
index 0000000..905ab07
--- /dev/null
@@ -0,0 +1,9 @@
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Overlays;
+
+/// <summary>
+/// This component allows you to see the thirstiness of mobs.
+/// </summary>
+[RegisterComponent, NetworkedComponent]
+public sealed partial class ShowThirstIconsComponent : Component { }
index 9b505654c993c64e3a6b556bbece4b7d32caee12..80317fbaec031a60483a3e491ad5d4855f4a5c69 100644 (file)
@@ -42,6 +42,7 @@
     sprite: Clothing/Eyes/Hud/beergoggles.rsi
   - type: Clothing
     sprite: Clothing/Eyes/Hud/beergoggles.rsi
+  - type: ShowThirstIcons
 
 - type: entity
   parent: ClothingEyesBase
     sprite: Clothing/Eyes/Hud/friedonion.rsi
   - type: Clothing
     sprite: Clothing/Eyes/Hud/friedonion.rsi
+  - type: ShowHungerIcons
+  - type: Food
+  - type: SolutionContainerManager
+    solutions:
+      food:
+        maxVol: 3
+        reagents:
+        - ReagentId: Nutriment
+          Quantity: 3
+  - type: FlavorProfile
+    flavors:
+      - onion
+      - greasey
 
 - type: entity
   parent: ClothingEyesBase
@@ -64,6 +78,8 @@
     sprite: Clothing/Eyes/Hud/onionbeer.rsi
   - type: Clothing
     sprite: Clothing/Eyes/Hud/onionbeer.rsi
+  - type: ShowHungerIcons
+  - type: ShowThirstIcons
 
 - type: entity
   parent: ClothingEyesBase
@@ -75,6 +91,7 @@
     sprite: Clothing/Eyes/Hud/medonion.rsi
   - type: Clothing
     sprite: Clothing/Eyes/Hud/medonion.rsi
+  - type: ShowHungerIcons
 
 - type: entity
   parent: ClothingEyesBase
     sprite: Clothing/Eyes/Hud/medonionbeer.rsi
   - type: Clothing
     sprite: Clothing/Eyes/Hud/medonionbeer.rsi
+  - type: ShowHungerIcons
+  - type: ShowThirstIcons
 
 - type: entity
   parent: ClothingEyesBase
   - type: Clothing
     sprite: Clothing/Eyes/Hud/omni.rsi
   - type: ShowSecurityIcons
+  - type: ShowHungerIcons
+  - type: ShowThirstIcons
diff --git a/Resources/Prototypes/StatusEffects/hunger.yml b/Resources/Prototypes/StatusEffects/hunger.yml
new file mode 100644 (file)
index 0000000..294a765
--- /dev/null
@@ -0,0 +1,49 @@
+#Hunger
+- type: statusIcon
+  id: HungerIconOverfed
+  priority: 5
+  icon:
+    sprite: Interface/Misc/food_icons.rsi
+    state: overfed
+  locationPreference: Right
+
+- type: statusIcon
+  id: HungerIconPeckish
+  priority: 5
+  icon:
+    sprite: Interface/Misc/food_icons.rsi
+    state: peckish
+  locationPreference: Right
+
+- type: statusIcon
+  id: HungerIconStarving
+  priority: 5
+  icon:
+    sprite: Interface/Misc/food_icons.rsi
+    state: starving
+  locationPreference: Right
+
+#Thirst
+- type: statusIcon
+  id: ThirstIconOverhydrated
+  priority: 5
+  icon:
+    sprite: Interface/Misc/food_icons.rsi
+    state: overhydrated
+  locationPreference: Left
+
+- type: statusIcon
+  id: ThirstIconThirsty
+  priority: 5
+  icon:
+    sprite: Interface/Misc/food_icons.rsi
+    state: thirsty
+  locationPreference: Left
+
+- type: statusIcon
+  id: ThirstIconParched
+  priority: 5
+  icon:
+    sprite: Interface/Misc/food_icons.rsi
+    state: parched
+  locationPreference: Left
index eb0a16390b7b4ac53375416a05a5138b2d469a4b..461d5f17299dfcc6b71b191d8df232a827c0bf0d 100644 (file)
Binary files a/Resources/Textures/Interface/Misc/food_icons.rsi/parched.png and b/Resources/Textures/Interface/Misc/food_icons.rsi/parched.png differ
index 0f93a4c2e71a1363e33e9c7bc3b9aa21430729ca..760019c7800dae39476c0af454c94efd00a5011d 100644 (file)
Binary files a/Resources/Textures/Interface/Misc/food_icons.rsi/peckish.png and b/Resources/Textures/Interface/Misc/food_icons.rsi/peckish.png differ
index be1d0abaaa76015e3b20e0cf8402a64889342091..bbf27f1b2f9f42eadafa70e8519404cf97b63c39 100644 (file)
Binary files a/Resources/Textures/Interface/Misc/food_icons.rsi/starving.png and b/Resources/Textures/Interface/Misc/food_icons.rsi/starving.png differ
index 89bc4240c1cf00f5b61b6aa169374d1acb2a8581..318b166abcadcba3578b2ba9cc258a6967707e45 100644 (file)
Binary files a/Resources/Textures/Interface/Misc/food_icons.rsi/thirsty.png and b/Resources/Textures/Interface/Misc/food_icons.rsi/thirsty.png differ