Task/food hud (#19312)
* 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>
58
Content.Client/Overlays/ShowHungerIconsSystem.cs
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
58
Content.Client/Overlays/ShowThirstIconsSystem.cs
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using Content.Server.Nutrition.Components;
|
|
||||||
using Content.Shared.Chemistry.Reagent;
|
|
||||||
using Content.Server.Nutrition.EntitySystems;
|
using Content.Server.Nutrition.EntitySystems;
|
||||||
|
using Content.Shared.Chemistry.Reagent;
|
||||||
|
using Content.Shared.Nutrition.Components;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
namespace Content.Server.Chemistry.ReagentEffects
|
namespace Content.Server.Chemistry.ReagentEffects
|
||||||
|
|||||||
@@ -1,16 +1,12 @@
|
|||||||
using Content.Server.Body.Components;
|
using Content.Server.Body.Components;
|
||||||
using Content.Server.Body.Systems;
|
using Content.Server.Body.Systems;
|
||||||
using Content.Server.Chemistry.EntitySystems;
|
using Content.Server.Chemistry.EntitySystems;
|
||||||
using Content.Server.Fluids.Components;
|
|
||||||
using Content.Server.Fluids.EntitySystems;
|
using Content.Server.Fluids.EntitySystems;
|
||||||
using Content.Server.Forensics;
|
using Content.Server.Forensics;
|
||||||
using Content.Server.Nutrition.Components;
|
|
||||||
using Content.Server.Nutrition.EntitySystems;
|
using Content.Server.Nutrition.EntitySystems;
|
||||||
using Content.Server.Popups;
|
using Content.Server.Popups;
|
||||||
using Content.Server.Stunnable;
|
using Content.Server.Stunnable;
|
||||||
using Content.Shared.Audio;
|
|
||||||
using Content.Shared.Chemistry.Components;
|
using Content.Shared.Chemistry.Components;
|
||||||
using Content.Shared.Fluids.Components;
|
|
||||||
using Content.Shared.IdentityManagement;
|
using Content.Shared.IdentityManagement;
|
||||||
using Content.Shared.Nutrition.Components;
|
using Content.Shared.Nutrition.Components;
|
||||||
using Content.Shared.Nutrition.EntitySystems;
|
using Content.Shared.Nutrition.EntitySystems;
|
||||||
|
|||||||
@@ -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},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -38,6 +38,8 @@ public partial class InventorySystem
|
|||||||
|
|
||||||
// ComponentActivatedClientSystems
|
// ComponentActivatedClientSystems
|
||||||
SubscribeLocalEvent<InventoryComponent, RefreshEquipmentHudEvent<ShowSecurityIconsComponent>>(RelayInventoryEvent);
|
SubscribeLocalEvent<InventoryComponent, RefreshEquipmentHudEvent<ShowSecurityIconsComponent>>(RelayInventoryEvent);
|
||||||
|
SubscribeLocalEvent<InventoryComponent, RefreshEquipmentHudEvent<ShowHungerIconsComponent>>(RelayInventoryEvent);
|
||||||
|
SubscribeLocalEvent<InventoryComponent, RefreshEquipmentHudEvent<ShowThirstIconsComponent>>(RelayInventoryEvent);
|
||||||
|
|
||||||
SubscribeLocalEvent<InventoryComponent, GetVerbsEvent<EquipmentVerb>>(OnGetStrippingVerbs);
|
SubscribeLocalEvent<InventoryComponent, GetVerbsEvent<EquipmentVerb>>(OnGetStrippingVerbs);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,12 +9,14 @@ using Robust.Shared.Serialization.TypeSerializers.Implementations.Generic;
|
|||||||
namespace Content.Shared.Nutrition.Components;
|
namespace Content.Shared.Nutrition.Components;
|
||||||
|
|
||||||
[RegisterComponent, NetworkedComponent, Access(typeof(HungerSystem))]
|
[RegisterComponent, NetworkedComponent, Access(typeof(HungerSystem))]
|
||||||
|
[AutoGenerateComponentState]
|
||||||
public sealed partial class HungerComponent : Component
|
public sealed partial class HungerComponent : Component
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The current hunger amount of the entity
|
/// The current hunger amount of the entity
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("currentHunger"), ViewVariables(VVAccess.ReadWrite)]
|
[DataField("currentHunger"), ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
[AutoNetworkedField]
|
||||||
public float CurrentHunger;
|
public float CurrentHunger;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -28,6 +30,7 @@ public sealed partial class HungerComponent : Component
|
|||||||
/// Affected by <seealso cref="CurrentThreshold"/>
|
/// Affected by <seealso cref="CurrentThreshold"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("actualDecayRate"), ViewVariables(VVAccess.ReadWrite)]
|
[DataField("actualDecayRate"), ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
[AutoNetworkedField]
|
||||||
public float ActualDecayRate;
|
public float ActualDecayRate;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -35,18 +38,21 @@ public sealed partial class HungerComponent : Component
|
|||||||
/// Stored in order to prevent recalculating
|
/// Stored in order to prevent recalculating
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("lastThreshold"), ViewVariables(VVAccess.ReadWrite)]
|
[DataField("lastThreshold"), ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
[AutoNetworkedField]
|
||||||
public HungerThreshold LastThreshold;
|
public HungerThreshold LastThreshold;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The current hunger threshold the entity is at
|
/// The current hunger threshold the entity is at
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("currentThreshold"), ViewVariables(VVAccess.ReadWrite)]
|
[DataField("currentThreshold"), ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
[AutoNetworkedField]
|
||||||
public HungerThreshold CurrentThreshold;
|
public HungerThreshold CurrentThreshold;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A dictionary relating HungerThreshold to the amount of <see cref="CurrentHunger"/> needed for each one
|
/// A dictionary relating HungerThreshold to the amount of <see cref="CurrentHunger"/> needed for each one
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("thresholds", customTypeSerializer: typeof(DictionarySerializer<HungerThreshold, float>))]
|
[DataField("thresholds", customTypeSerializer: typeof(DictionarySerializer<HungerThreshold, float>))]
|
||||||
|
[AutoNetworkedField(cloneData: true)]
|
||||||
public Dictionary<HungerThreshold, float> Thresholds = new()
|
public Dictionary<HungerThreshold, float> Thresholds = new()
|
||||||
{
|
{
|
||||||
{ HungerThreshold.Overfed, 200.0f },
|
{ HungerThreshold.Overfed, 200.0f },
|
||||||
@@ -60,6 +66,7 @@ public sealed partial class HungerComponent : Component
|
|||||||
/// A dictionary relating hunger thresholds to corresponding alerts.
|
/// A dictionary relating hunger thresholds to corresponding alerts.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("hungerThresholdAlerts", customTypeSerializer: typeof(DictionarySerializer<HungerThreshold, AlertType>))]
|
[DataField("hungerThresholdAlerts", customTypeSerializer: typeof(DictionarySerializer<HungerThreshold, AlertType>))]
|
||||||
|
[AutoNetworkedField(cloneData: true)]
|
||||||
public Dictionary<HungerThreshold, AlertType> HungerThresholdAlerts = new()
|
public Dictionary<HungerThreshold, AlertType> HungerThresholdAlerts = new()
|
||||||
{
|
{
|
||||||
{ HungerThreshold.Peckish, AlertType.Peckish },
|
{ 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"/>.
|
/// A dictionary relating HungerThreshold to how much they modify <see cref="BaseDecayRate"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("hungerThresholdDecayModifiers", customTypeSerializer: typeof(DictionarySerializer<HungerThreshold, float>))]
|
[DataField("hungerThresholdDecayModifiers", customTypeSerializer: typeof(DictionarySerializer<HungerThreshold, float>))]
|
||||||
|
[AutoNetworkedField(cloneData: true)]
|
||||||
public Dictionary<HungerThreshold, float> HungerThresholdDecayModifiers = new()
|
public Dictionary<HungerThreshold, float> HungerThresholdDecayModifiers = new()
|
||||||
{
|
{
|
||||||
{ HungerThreshold.Overfed, 1.2f },
|
{ HungerThreshold.Overfed, 1.2f },
|
||||||
@@ -84,6 +92,7 @@ public sealed partial class HungerComponent : Component
|
|||||||
/// The amount of slowdown applied when an entity is starving
|
/// The amount of slowdown applied when an entity is starving
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("starvingSlowdownModifier"), ViewVariables(VVAccess.ReadWrite)]
|
[DataField("starvingSlowdownModifier"), ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
[AutoNetworkedField]
|
||||||
public float StarvingSlowdownModifier = 0.75f;
|
public float StarvingSlowdownModifier = 0.75f;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -96,50 +105,17 @@ public sealed partial class HungerComponent : Component
|
|||||||
/// The time when the hunger will update next.
|
/// The time when the hunger will update next.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("nextUpdateTime", customTypeSerializer: typeof(TimeOffsetSerializer)), ViewVariables(VVAccess.ReadWrite)]
|
[DataField("nextUpdateTime", customTypeSerializer: typeof(TimeOffsetSerializer)), ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
[AutoNetworkedField]
|
||||||
public TimeSpan NextUpdateTime;
|
public TimeSpan NextUpdateTime;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The time between each update.
|
/// The time between each update.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
[AutoNetworkedField]
|
||||||
public TimeSpan UpdateRate = TimeSpan.FromSeconds(1);
|
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]
|
[Serializable, NetSerializable]
|
||||||
public enum HungerThreshold : byte
|
public enum HungerThreshold : byte
|
||||||
{
|
{
|
||||||
|
|||||||
78
Content.Shared/Nutrition/Components/ThirstComponent.cs
Normal file
@@ -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,
|
||||||
|
}
|
||||||
@@ -1,10 +1,9 @@
|
|||||||
using Content.Shared.Alert;
|
using Content.Shared.Alert;
|
||||||
using Content.Shared.Damage;
|
using Content.Shared.Damage;
|
||||||
using Content.Shared.Mobs.Systems;
|
using Content.Shared.Mobs.Systems;
|
||||||
using Content.Shared.Movement.Systems;
|
using Content.Shared.Movement.Systems;
|
||||||
using Content.Shared.Nutrition.Components;
|
using Content.Shared.Nutrition.Components;
|
||||||
using Content.Shared.Rejuvenate;
|
using Content.Shared.Rejuvenate;
|
||||||
using Robust.Shared.GameStates;
|
|
||||||
using Robust.Shared.Random;
|
using Robust.Shared.Random;
|
||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
|
|
||||||
@@ -24,8 +23,6 @@ public sealed class HungerSystem : EntitySystem
|
|||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
SubscribeLocalEvent<HungerComponent, ComponentGetState>(OnGetState);
|
|
||||||
SubscribeLocalEvent<HungerComponent, ComponentHandleState>(OnHandleState);
|
|
||||||
SubscribeLocalEvent<HungerComponent, EntityUnpausedEvent>(OnUnpaused);
|
SubscribeLocalEvent<HungerComponent, EntityUnpausedEvent>(OnUnpaused);
|
||||||
SubscribeLocalEvent<HungerComponent, MapInitEvent>(OnMapInit);
|
SubscribeLocalEvent<HungerComponent, MapInitEvent>(OnMapInit);
|
||||||
SubscribeLocalEvent<HungerComponent, ComponentShutdown>(OnShutdown);
|
SubscribeLocalEvent<HungerComponent, ComponentShutdown>(OnShutdown);
|
||||||
@@ -33,30 +30,6 @@ public sealed class HungerSystem : EntitySystem
|
|||||||
SubscribeLocalEvent<HungerComponent, RejuvenateEvent>(OnRejuvenate);
|
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)
|
private void OnUnpaused(EntityUid uid, HungerComponent component, ref EntityUnpausedEvent args)
|
||||||
{
|
{
|
||||||
component.NextUpdateTime += args.PausedTime;
|
component.NextUpdateTime += args.PausedTime;
|
||||||
|
|||||||
@@ -1,23 +1,24 @@
|
|||||||
using Content.Server.Nutrition.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 JetBrains.Annotations;
|
||||||
using Robust.Shared.Random;
|
using Robust.Shared.Random;
|
||||||
using Content.Shared.Movement.Components;
|
using Robust.Shared.Timing;
|
||||||
using Content.Shared.Alert;
|
|
||||||
using Content.Shared.Movement.Systems;
|
|
||||||
using Content.Shared.Rejuvenate;
|
|
||||||
|
|
||||||
namespace Content.Server.Nutrition.EntitySystems;
|
namespace Content.Server.Nutrition.EntitySystems;
|
||||||
|
|
||||||
[UsedImplicitly]
|
[UsedImplicitly]
|
||||||
public sealed class ThirstSystem : EntitySystem
|
public sealed class ThirstSystem : EntitySystem
|
||||||
{
|
{
|
||||||
|
[Dependency] private readonly IGameTiming _timing = default!;
|
||||||
[Dependency] private readonly IRobustRandom _random = default!;
|
[Dependency] private readonly IRobustRandom _random = default!;
|
||||||
[Dependency] private readonly AlertsSystem _alerts = default!;
|
[Dependency] private readonly AlertsSystem _alerts = default!;
|
||||||
[Dependency] private readonly MovementSpeedModifierSystem _movement = default!;
|
[Dependency] private readonly MovementSpeedModifierSystem _movement = default!;
|
||||||
[Dependency] private readonly SharedJetpackSystem _jetpack = default!;
|
[Dependency] private readonly SharedJetpackSystem _jetpack = default!;
|
||||||
|
|
||||||
private ISawmill _sawmill = default!;
|
private ISawmill _sawmill = default!;
|
||||||
private float _accumulatedFrameTime;
|
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
@@ -28,6 +29,7 @@ public sealed class ThirstSystem : EntitySystem
|
|||||||
SubscribeLocalEvent<ThirstComponent, RefreshMovementSpeedModifiersEvent>(OnRefreshMovespeed);
|
SubscribeLocalEvent<ThirstComponent, RefreshMovementSpeedModifiersEvent>(OnRefreshMovespeed);
|
||||||
SubscribeLocalEvent<ThirstComponent, ComponentStartup>(OnComponentStartup);
|
SubscribeLocalEvent<ThirstComponent, ComponentStartup>(OnComponentStartup);
|
||||||
SubscribeLocalEvent<ThirstComponent, RejuvenateEvent>(OnRejuvenate);
|
SubscribeLocalEvent<ThirstComponent, RejuvenateEvent>(OnRejuvenate);
|
||||||
|
SubscribeLocalEvent<ThirstComponent, EntityUnpausedEvent>(OnUnpaused);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnComponentStartup(EntityUid uid, ThirstComponent component, ComponentStartup args)
|
private void OnComponentStartup(EntityUid uid, ThirstComponent component, ComponentStartup args)
|
||||||
@@ -154,22 +156,30 @@ public sealed class ThirstSystem : EntitySystem
|
|||||||
|
|
||||||
public override void Update(float frameTime)
|
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>();
|
if (_timing.CurTime < thirst.NextUpdateTime)
|
||||||
while (query.MoveNext(out var uid, out var comp))
|
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)
|
||||||
{
|
{
|
||||||
UpdateThirst(comp, - comp.ActualDecayRate);
|
component.NextUpdateTime += args.PausedTime;
|
||||||
var calculatedThirstThreshold = GetThirstThreshold(comp, comp.CurrentThirst);
|
|
||||||
if (calculatedThirstThreshold != comp.CurrentThirstThreshold)
|
|
||||||
{
|
|
||||||
comp.CurrentThirstThreshold = calculatedThirstThreshold;
|
|
||||||
UpdateEffects(uid, comp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_accumulatedFrameTime -= 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
9
Content.Shared/Overlays/ShowHungerIconsComponent.cs
Normal file
@@ -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 { }
|
||||||
@@ -1,10 +1,9 @@
|
|||||||
using Robust.Shared.GameStates;
|
using Robust.Shared.GameStates;
|
||||||
|
|
||||||
namespace Content.Shared.Overlays
|
namespace Content.Shared.Overlays;
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This component allows you to see job icons above mobs.
|
/// This component allows you to see job icons above mobs.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[RegisterComponent, NetworkedComponent]
|
[RegisterComponent, NetworkedComponent]
|
||||||
public sealed partial class ShowSecurityIconsComponent : Component { }
|
public sealed partial class ShowSecurityIconsComponent : Component { }
|
||||||
}
|
|
||||||
|
|||||||
9
Content.Shared/Overlays/ShowThirstIconsComponent.cs
Normal file
@@ -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 { }
|
||||||
@@ -42,6 +42,7 @@
|
|||||||
sprite: Clothing/Eyes/Hud/beergoggles.rsi
|
sprite: Clothing/Eyes/Hud/beergoggles.rsi
|
||||||
- type: Clothing
|
- type: Clothing
|
||||||
sprite: Clothing/Eyes/Hud/beergoggles.rsi
|
sprite: Clothing/Eyes/Hud/beergoggles.rsi
|
||||||
|
- type: ShowThirstIcons
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: ClothingEyesBase
|
parent: ClothingEyesBase
|
||||||
@@ -53,6 +54,19 @@
|
|||||||
sprite: Clothing/Eyes/Hud/friedonion.rsi
|
sprite: Clothing/Eyes/Hud/friedonion.rsi
|
||||||
- type: Clothing
|
- type: Clothing
|
||||||
sprite: Clothing/Eyes/Hud/friedonion.rsi
|
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
|
- type: entity
|
||||||
parent: ClothingEyesBase
|
parent: ClothingEyesBase
|
||||||
@@ -64,6 +78,8 @@
|
|||||||
sprite: Clothing/Eyes/Hud/onionbeer.rsi
|
sprite: Clothing/Eyes/Hud/onionbeer.rsi
|
||||||
- type: Clothing
|
- type: Clothing
|
||||||
sprite: Clothing/Eyes/Hud/onionbeer.rsi
|
sprite: Clothing/Eyes/Hud/onionbeer.rsi
|
||||||
|
- type: ShowHungerIcons
|
||||||
|
- type: ShowThirstIcons
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: ClothingEyesBase
|
parent: ClothingEyesBase
|
||||||
@@ -75,6 +91,7 @@
|
|||||||
sprite: Clothing/Eyes/Hud/medonion.rsi
|
sprite: Clothing/Eyes/Hud/medonion.rsi
|
||||||
- type: Clothing
|
- type: Clothing
|
||||||
sprite: Clothing/Eyes/Hud/medonion.rsi
|
sprite: Clothing/Eyes/Hud/medonion.rsi
|
||||||
|
- type: ShowHungerIcons
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: ClothingEyesBase
|
parent: ClothingEyesBase
|
||||||
@@ -86,6 +103,8 @@
|
|||||||
sprite: Clothing/Eyes/Hud/medonionbeer.rsi
|
sprite: Clothing/Eyes/Hud/medonionbeer.rsi
|
||||||
- type: Clothing
|
- type: Clothing
|
||||||
sprite: Clothing/Eyes/Hud/medonionbeer.rsi
|
sprite: Clothing/Eyes/Hud/medonionbeer.rsi
|
||||||
|
- type: ShowHungerIcons
|
||||||
|
- type: ShowThirstIcons
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: ClothingEyesBase
|
parent: ClothingEyesBase
|
||||||
@@ -122,3 +141,5 @@
|
|||||||
- type: Clothing
|
- type: Clothing
|
||||||
sprite: Clothing/Eyes/Hud/omni.rsi
|
sprite: Clothing/Eyes/Hud/omni.rsi
|
||||||
- type: ShowSecurityIcons
|
- type: ShowSecurityIcons
|
||||||
|
- type: ShowHungerIcons
|
||||||
|
- type: ShowThirstIcons
|
||||||
|
|||||||
49
Resources/Prototypes/StatusEffects/hunger.yml
Normal file
@@ -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
|
||||||
|
Before Width: | Height: | Size: 292 B After Width: | Height: | Size: 273 B |
|
Before Width: | Height: | Size: 283 B After Width: | Height: | Size: 234 B |
|
Before Width: | Height: | Size: 274 B After Width: | Height: | Size: 237 B |
|
Before Width: | Height: | Size: 296 B After Width: | Height: | Size: 273 B |