Hunger and thirst HUDs (#18066)
* security HUD now shows a job icon on entities with a body * thirst goggles * set starting hud gear
115
Content.Client/Overlays/ComponentAddedOverlaySystemBase.cs
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
using Content.Shared.Clothing.Components;
|
||||||
|
using Content.Shared.GameTicking;
|
||||||
|
using Content.Shared.Inventory;
|
||||||
|
using Content.Shared.Inventory.Events;
|
||||||
|
using Robust.Client.GameObjects;
|
||||||
|
using Robust.Client.Player;
|
||||||
|
|
||||||
|
namespace Content.Client.Overlays
|
||||||
|
{
|
||||||
|
public abstract class ComponentAddedOverlaySystemBase<T> : EntitySystem where T : IComponent
|
||||||
|
{
|
||||||
|
[Dependency] private readonly IPlayerManager _player = default!;
|
||||||
|
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||||
|
private InventorySystem _invSystem = default!;
|
||||||
|
|
||||||
|
protected bool IsActive = false;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeLocalEvent<T, ComponentInit>(OnInit);
|
||||||
|
SubscribeLocalEvent<T, ComponentRemove>(OnRemove);
|
||||||
|
|
||||||
|
SubscribeLocalEvent<PlayerAttachedEvent>(OnPlayerAttached);
|
||||||
|
SubscribeLocalEvent<PlayerDetachedEvent>(OnPlayerDetached);
|
||||||
|
|
||||||
|
SubscribeLocalEvent<T, GotEquippedEvent>(OnCompEquip);
|
||||||
|
SubscribeLocalEvent<T, GotUnequippedEvent>(OnCompUnequip);
|
||||||
|
|
||||||
|
SubscribeLocalEvent<RoundRestartCleanupEvent>(OnRoundRestart);
|
||||||
|
|
||||||
|
_invSystem = _entityManager.System<InventorySystem>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ApplyOverlay(T component)
|
||||||
|
{
|
||||||
|
IsActive = true;
|
||||||
|
OnApplyOverlay(component);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveOverlay()
|
||||||
|
{
|
||||||
|
IsActive = false;
|
||||||
|
OnRemoveOverlay();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void OnApplyOverlay(T component) { }
|
||||||
|
|
||||||
|
protected virtual void OnRemoveOverlay() { }
|
||||||
|
|
||||||
|
private void OnInit(EntityUid uid, T component, ComponentInit args)
|
||||||
|
{
|
||||||
|
if (_player.LocalPlayer?.ControlledEntity == uid)
|
||||||
|
{
|
||||||
|
ApplyOverlay(component);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnRemove(EntityUid uid, T component, ComponentRemove args)
|
||||||
|
{
|
||||||
|
if (_player.LocalPlayer?.ControlledEntity == uid)
|
||||||
|
{
|
||||||
|
RemoveOverlay();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnPlayerAttached(PlayerAttachedEvent args)
|
||||||
|
{
|
||||||
|
if (TryComp<T>(args.Entity, out var component))
|
||||||
|
ApplyOverlay(component);
|
||||||
|
|
||||||
|
if (TryComp(args.Entity, out InventoryComponent? inventoryComponent)
|
||||||
|
&& _invSystem.TryGetSlots(args.Entity, out var slotDefinitions, inventoryComponent))
|
||||||
|
{
|
||||||
|
foreach (var slot in slotDefinitions)
|
||||||
|
{
|
||||||
|
if (_invSystem.TryGetSlotEntity(args.Entity, slot.Name, out var itemUid)
|
||||||
|
&& TryComp(itemUid.Value, out component))
|
||||||
|
{
|
||||||
|
OnCompEquip(itemUid.Value, component, new GotEquippedEvent(args.Entity, itemUid.Value, slot));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnPlayerDetached(PlayerDetachedEvent args)
|
||||||
|
{
|
||||||
|
RemoveOverlay();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnCompEquip(EntityUid uid, T component, GotEquippedEvent args)
|
||||||
|
{
|
||||||
|
if (!TryComp<ClothingComponent>(uid, out var clothing)) return;
|
||||||
|
|
||||||
|
if (args.Equipee != _player.LocalPlayer?.ControlledEntity) return;
|
||||||
|
|
||||||
|
if (!clothing.Slots.HasFlag(args.SlotFlags)) return;
|
||||||
|
|
||||||
|
ApplyOverlay(component);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnCompUnequip(EntityUid uid, T component, GotUnequippedEvent args)
|
||||||
|
{
|
||||||
|
if (args.Equipee != _player.LocalPlayer?.ControlledEntity) return;
|
||||||
|
|
||||||
|
RemoveOverlay();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnRoundRestart(RoundRestartCleanupEvent args)
|
||||||
|
{
|
||||||
|
RemoveOverlay();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
74
Content.Client/Overlays/ShowHungerIconsSystem.cs
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
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 : ComponentAddedOverlaySystemBase<ShowHungerIconsComponent>
|
||||||
|
{
|
||||||
|
[Dependency] private readonly IPrototypeManager _prototypeMan = default!;
|
||||||
|
[Dependency] private readonly IEntityManager _entManager = default!;
|
||||||
|
|
||||||
|
private StatusIconPrototype? _overfed;
|
||||||
|
private StatusIconPrototype? _peckish;
|
||||||
|
private StatusIconPrototype? _starving;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeLocalEvent<HungerComponent, GetStatusIconsEvent>(OnGetStatusIconsEvent);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnGetStatusIconsEvent(EntityUid uid, HungerComponent hungerComponent, ref GetStatusIconsEvent @event)
|
||||||
|
{
|
||||||
|
if (!IsActive)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var healthIcons = DecideHungerIcon(uid, hungerComponent);
|
||||||
|
|
||||||
|
@event.StatusIcons.AddRange(healthIcons);
|
||||||
|
}
|
||||||
|
|
||||||
|
private IReadOnlyList<StatusIconPrototype> DecideHungerIcon(EntityUid uid, HungerComponent hungerComponent)
|
||||||
|
{
|
||||||
|
var result = new List<StatusIconPrototype>();
|
||||||
|
|
||||||
|
if (_entManager.TryGetComponent<MetaDataComponent>(uid, out var metaDataComponent) &&
|
||||||
|
metaDataComponent.Flags.HasFlag(MetaDataFlags.InContainer))
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (hungerComponent.CurrentThreshold)
|
||||||
|
{
|
||||||
|
case HungerThreshold.Overfed:
|
||||||
|
if (_overfed != null ||
|
||||||
|
_prototypeMan.TryIndex("HungerIcon_Overfed", out _overfed))
|
||||||
|
{
|
||||||
|
result.Add(_overfed);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case HungerThreshold.Peckish:
|
||||||
|
if (_peckish != null ||
|
||||||
|
_prototypeMan.TryIndex("HungerIcon_Peckish", out _peckish))
|
||||||
|
{
|
||||||
|
result.Add(_peckish);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case HungerThreshold.Starving:
|
||||||
|
if (_starving != null ||
|
||||||
|
_prototypeMan.TryIndex("HungerIcon_Starving", out _starving))
|
||||||
|
{
|
||||||
|
result.Add(_starving);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
90
Content.Client/Overlays/ShowSecurityIconsSystem.cs
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
using Content.Shared.Access.Components;
|
||||||
|
using Content.Shared.Body.Components;
|
||||||
|
using Content.Shared.Inventory;
|
||||||
|
using Content.Shared.Overlays;
|
||||||
|
using Content.Shared.PDA;
|
||||||
|
using Content.Shared.StatusIcon;
|
||||||
|
using Content.Shared.StatusIcon.Components;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
|
namespace Content.Client.Overlays
|
||||||
|
{
|
||||||
|
public sealed class ShowSecurityIconsSystem : ComponentAddedOverlaySystemBase<ShowSecurityIconsComponent>
|
||||||
|
{
|
||||||
|
[Dependency] private readonly IPrototypeManager _prototypeMan = default!;
|
||||||
|
[Dependency] private readonly IEntityManager _entManager = default!;
|
||||||
|
[Dependency] private readonly InventorySystem _inventorySystem = default!;
|
||||||
|
|
||||||
|
private Dictionary<string, StatusIconPrototype> _jobIcons = new();
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeLocalEvent<BodyComponent, GetStatusIconsEvent>(OnGetStatusIconsEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnGetStatusIconsEvent(EntityUid uid, BodyComponent _, ref GetStatusIconsEvent @event)
|
||||||
|
{
|
||||||
|
if (!IsActive)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var healthIcons = DecideSecurityIcon(uid);
|
||||||
|
|
||||||
|
@event.StatusIcons.AddRange(healthIcons);
|
||||||
|
}
|
||||||
|
|
||||||
|
private IReadOnlyList<StatusIconPrototype> DecideSecurityIcon(EntityUid uid)
|
||||||
|
{
|
||||||
|
var result = new List<StatusIconPrototype>();
|
||||||
|
if (_entManager.TryGetComponent<MetaDataComponent>(uid, out var metaDataComponent) &&
|
||||||
|
metaDataComponent.Flags.HasFlag(MetaDataFlags.InContainer))
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
var iconToGet = "NoId";
|
||||||
|
if (_inventorySystem.TryGetSlotEntity(uid, "id", out var idUid))
|
||||||
|
{
|
||||||
|
// PDA
|
||||||
|
if (EntityManager.TryGetComponent(idUid, out PdaComponent? pda))
|
||||||
|
{
|
||||||
|
iconToGet = pda.ContainedId?.JobTitle ?? string.Empty;
|
||||||
|
}
|
||||||
|
// ID Card
|
||||||
|
else if (EntityManager.TryGetComponent(idUid, out IdCardComponent? id))
|
||||||
|
{
|
||||||
|
iconToGet = id.JobTitle ?? string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
iconToGet = iconToGet.Replace(" ", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
iconToGet = EnsureIcon(iconToGet, _jobIcons);
|
||||||
|
result.Add(_jobIcons[iconToGet]);
|
||||||
|
|
||||||
|
// Add arrest icons here, WYCI.
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string EnsureIcon(string iconKey, Dictionary<string, StatusIconPrototype> icons)
|
||||||
|
{
|
||||||
|
if (!icons.ContainsKey(iconKey))
|
||||||
|
{
|
||||||
|
if (_prototypeMan.TryIndex<StatusIconPrototype>($"JobIcon_{iconKey}", out var securityIcon))
|
||||||
|
{
|
||||||
|
icons.Add(iconKey, securityIcon);
|
||||||
|
return iconKey;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return iconKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
iconKey = "Unknown";
|
||||||
|
return EnsureIcon(iconKey, icons);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
73
Content.Client/Overlays/ShowThirstIconsSystem.cs
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
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 : ComponentAddedOverlaySystemBase<ShowThirstIconsComponent>
|
||||||
|
{
|
||||||
|
[Dependency] private readonly IPrototypeManager _prototypeMan = default!;
|
||||||
|
[Dependency] private readonly IEntityManager _entManager = default!;
|
||||||
|
|
||||||
|
private StatusIconPrototype? _overhydrated;
|
||||||
|
private StatusIconPrototype? _thirsty;
|
||||||
|
private StatusIconPrototype? _parched;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeLocalEvent<ThirstComponent, GetStatusIconsEvent>(OnGetStatusIconsEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnGetStatusIconsEvent(EntityUid uid, ThirstComponent thirstComponent, ref GetStatusIconsEvent @event)
|
||||||
|
{
|
||||||
|
if (!IsActive)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var healthIcons = DecideThirstIcon(uid, thirstComponent);
|
||||||
|
|
||||||
|
@event.StatusIcons.AddRange(healthIcons);
|
||||||
|
}
|
||||||
|
|
||||||
|
private IReadOnlyList<StatusIconPrototype> DecideThirstIcon(EntityUid uid, ThirstComponent thirstComponent)
|
||||||
|
{
|
||||||
|
var result = new List<StatusIconPrototype>();
|
||||||
|
|
||||||
|
if (_entManager.TryGetComponent<MetaDataComponent>(uid, out var metaDataComponent) &&
|
||||||
|
metaDataComponent.Flags.HasFlag(MetaDataFlags.InContainer))
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (thirstComponent.CurrentThirstThreshold)
|
||||||
|
{
|
||||||
|
case ThirstThreshold.OverHydrated:
|
||||||
|
if (_overhydrated != null ||
|
||||||
|
_prototypeMan.TryIndex("ThirstIcon_Overhydrated", out _overhydrated))
|
||||||
|
{
|
||||||
|
result.Add(_overhydrated);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ThirstThreshold.Thirsty:
|
||||||
|
if (_thirsty != null ||
|
||||||
|
_prototypeMan.TryIndex("ThirstIcon_Thirsty", out _thirsty))
|
||||||
|
{
|
||||||
|
result.Add(_thirsty);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ThirstThreshold.Parched:
|
||||||
|
if (_parched != null ||
|
||||||
|
_prototypeMan.TryIndex("ThirstIcon_Parched", out _parched))
|
||||||
|
{
|
||||||
|
result.Add(_parched);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
using System.Numerics;
|
using Content.Shared.StatusIcon;
|
||||||
using Content.Shared.StatusIcon.Components;
|
using Content.Shared.StatusIcon.Components;
|
||||||
using Robust.Client.GameObjects;
|
using Robust.Client.GameObjects;
|
||||||
using Robust.Client.Graphics;
|
using Robust.Client.Graphics;
|
||||||
using Robust.Shared.Enums;
|
using Robust.Shared.Enums;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace Content.Client.StatusIcon;
|
namespace Content.Client.StatusIcon;
|
||||||
|
|
||||||
@@ -57,7 +58,8 @@ public sealed class StatusIconOverlay : Overlay
|
|||||||
Matrix3.Multiply(rotationMatrix, scaledWorld, out var matty);
|
Matrix3.Multiply(rotationMatrix, scaledWorld, out var matty);
|
||||||
handle.SetTransform(matty);
|
handle.SetTransform(matty);
|
||||||
|
|
||||||
var count = 0;
|
var countL = 0;
|
||||||
|
var countR = 0;
|
||||||
var accOffsetL = 0;
|
var accOffsetL = 0;
|
||||||
var accOffsetR = 0;
|
var accOffsetR = 0;
|
||||||
icons.Sort();
|
icons.Sort();
|
||||||
@@ -71,13 +73,16 @@ public sealed class StatusIconOverlay : Overlay
|
|||||||
|
|
||||||
// the icons are ordered left to right, top to bottom.
|
// the icons are ordered left to right, top to bottom.
|
||||||
// extra icons that don't fit are just cut off.
|
// extra icons that don't fit are just cut off.
|
||||||
if (count % 2 == 0)
|
if (proto.LocationPreference == StatusIconLocationPreference.Left ||
|
||||||
|
proto.LocationPreference == StatusIconLocationPreference.None && countL <= countR)
|
||||||
{
|
{
|
||||||
if (accOffsetL + texture.Height > sprite.Bounds.Height * EyeManager.PixelsPerMeter)
|
if (accOffsetL + texture.Height > sprite.Bounds.Height * EyeManager.PixelsPerMeter)
|
||||||
break;
|
break;
|
||||||
accOffsetL += texture.Height;
|
accOffsetL += texture.Height;
|
||||||
yOffset = (bounds.Height + sprite.Offset.Y) / 2f - (float) accOffsetL / EyeManager.PixelsPerMeter;
|
yOffset = (bounds.Height + sprite.Offset.Y) / 2f - (float) accOffsetL / EyeManager.PixelsPerMeter;
|
||||||
xOffset = -(bounds.Width + sprite.Offset.X) / 2f;
|
xOffset = -(bounds.Width + sprite.Offset.X) / 2f;
|
||||||
|
|
||||||
|
countL++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -86,8 +91,9 @@ public sealed class StatusIconOverlay : Overlay
|
|||||||
accOffsetR += texture.Height;
|
accOffsetR += texture.Height;
|
||||||
yOffset = (bounds.Height + sprite.Offset.Y) / 2f - (float) accOffsetR / EyeManager.PixelsPerMeter;
|
yOffset = (bounds.Height + sprite.Offset.Y) / 2f - (float) accOffsetR / EyeManager.PixelsPerMeter;
|
||||||
xOffset = (bounds.Width + sprite.Offset.X) / 2f - (float) texture.Width / EyeManager.PixelsPerMeter;
|
xOffset = (bounds.Width + sprite.Offset.X) / 2f - (float) texture.Width / EyeManager.PixelsPerMeter;
|
||||||
|
|
||||||
|
countR++;
|
||||||
}
|
}
|
||||||
count++;
|
|
||||||
|
|
||||||
var position = new Vector2(xOffset, yOffset);
|
var position = new Vector2(xOffset, yOffset);
|
||||||
handle.DrawTexture(texture, position);
|
handle.DrawTexture(texture, position);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
using Content.Server.Nutrition.Components;
|
|
||||||
using Content.Shared.Chemistry.Reagent;
|
using Content.Shared.Chemistry.Reagent;
|
||||||
using Content.Server.Nutrition.EntitySystems;
|
using Content.Shared.Nutrition.Components;
|
||||||
|
using Content.Shared.Nutrition.EntitySystems;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
namespace Content.Server.Chemistry.ReagentEffects
|
namespace Content.Server.Chemistry.ReagentEffects
|
||||||
|
|||||||
@@ -1,16 +1,11 @@
|
|||||||
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.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 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; } = 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},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
101
Content.Shared/Nutrition/Components/ThirstComponent.cs
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
using Content.Shared.Alert;
|
||||||
|
using Content.Shared.Nutrition.EntitySystems;
|
||||||
|
using Robust.Shared.GameStates;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
|
||||||
|
|
||||||
|
namespace Content.Shared.Nutrition.Components
|
||||||
|
{
|
||||||
|
[RegisterComponent, NetworkedComponent, Access(typeof(ThirstSystem))]
|
||||||
|
public sealed 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;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The time when the hunger will update next.
|
||||||
|
/// </summary>
|
||||||
|
[DataField("nextUpdateTime", customTypeSerializer: typeof(TimeOffsetSerializer)), ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public TimeSpan NextUpdateTime;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The time between each update.
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public TimeSpan UpdateRate = TimeSpan.FromSeconds(1);
|
||||||
|
|
||||||
|
[DataField("thresholds")]
|
||||||
|
public Dictionary<ThirstThreshold, float> ThirstThresholds { get; } = 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},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public sealed class ThirstComponentState : ComponentState
|
||||||
|
{
|
||||||
|
public float BaseDecayRate;
|
||||||
|
|
||||||
|
public float ActualDecayRate;
|
||||||
|
|
||||||
|
public ThirstThreshold CurrentThirstThreshold;
|
||||||
|
|
||||||
|
public ThirstThreshold LastThirstThreshold;
|
||||||
|
|
||||||
|
public float CurrentThirst;
|
||||||
|
|
||||||
|
public TimeSpan NextUpdateTime;
|
||||||
|
|
||||||
|
public ThirstComponentState(float baseDecayRate,
|
||||||
|
float actualDecayRate,
|
||||||
|
ThirstThreshold currentThirstThreshold,
|
||||||
|
ThirstThreshold lastThirstThreshold,
|
||||||
|
float currentThirst,
|
||||||
|
TimeSpan nextUpdateTime)
|
||||||
|
{
|
||||||
|
BaseDecayRate = baseDecayRate;
|
||||||
|
ActualDecayRate = actualDecayRate;
|
||||||
|
CurrentThirstThreshold = currentThirstThreshold;
|
||||||
|
LastThirstThreshold = lastThirstThreshold;
|
||||||
|
CurrentThirst = currentThirst;
|
||||||
|
NextUpdateTime = nextUpdateTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
public enum ThirstThreshold : byte
|
||||||
|
{
|
||||||
|
// Hydrohomies
|
||||||
|
Dead = 0,
|
||||||
|
Parched = 1 << 0,
|
||||||
|
Thirsty = 1 << 1,
|
||||||
|
Okay = 1 << 2,
|
||||||
|
OverHydrated = 1 << 3,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,33 +1,71 @@
|
|||||||
using Content.Server.Nutrition.Components;
|
|
||||||
using JetBrains.Annotations;
|
|
||||||
using Robust.Shared.Random;
|
|
||||||
using Content.Shared.Movement.Components;
|
|
||||||
using Content.Shared.Alert;
|
using Content.Shared.Alert;
|
||||||
|
using Content.Shared.Movement.Components;
|
||||||
using Content.Shared.Movement.Systems;
|
using Content.Shared.Movement.Systems;
|
||||||
|
using Content.Shared.Nutrition.Components;
|
||||||
using Content.Shared.Rejuvenate;
|
using Content.Shared.Rejuvenate;
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
using Robust.Shared.GameStates;
|
||||||
|
using Robust.Shared.Random;
|
||||||
|
using Robust.Shared.Timing;
|
||||||
|
|
||||||
namespace Content.Server.Nutrition.EntitySystems
|
namespace Content.Shared.Nutrition.EntitySystems
|
||||||
{
|
{
|
||||||
[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()
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
_sawmill = Logger.GetSawmill("thirst");
|
_sawmill = Logger.GetSawmill("thirst");
|
||||||
|
SubscribeLocalEvent<ThirstComponent, ComponentGetState>(OnGetState);
|
||||||
|
SubscribeLocalEvent<ThirstComponent, ComponentHandleState>(OnHandleState);
|
||||||
|
SubscribeLocalEvent<ThirstComponent, EntityUnpausedEvent>(OnUnpaused);
|
||||||
SubscribeLocalEvent<ThirstComponent, RefreshMovementSpeedModifiersEvent>(OnRefreshMovespeed);
|
SubscribeLocalEvent<ThirstComponent, RefreshMovementSpeedModifiersEvent>(OnRefreshMovespeed);
|
||||||
|
SubscribeLocalEvent<ThirstComponent, ComponentShutdown>(OnShutdown);
|
||||||
SubscribeLocalEvent<ThirstComponent, ComponentStartup>(OnComponentStartup);
|
SubscribeLocalEvent<ThirstComponent, ComponentStartup>(OnComponentStartup);
|
||||||
SubscribeLocalEvent<ThirstComponent, RejuvenateEvent>(OnRejuvenate);
|
SubscribeLocalEvent<ThirstComponent, RejuvenateEvent>(OnRejuvenate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnGetState(EntityUid uid, ThirstComponent component, ref ComponentGetState args)
|
||||||
|
{
|
||||||
|
args.State = new ThirstComponentState(component.BaseDecayRate,
|
||||||
|
component.ActualDecayRate,
|
||||||
|
component.CurrentThirstThreshold,
|
||||||
|
component.LastThirstThreshold,
|
||||||
|
component.CurrentThirst,
|
||||||
|
component.NextUpdateTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnHandleState(EntityUid uid, ThirstComponent component, ref ComponentHandleState args)
|
||||||
|
{
|
||||||
|
if (args.Current is not ThirstComponentState state)
|
||||||
|
return;
|
||||||
|
component.BaseDecayRate = state.BaseDecayRate;
|
||||||
|
component.ActualDecayRate = state.ActualDecayRate;
|
||||||
|
component.CurrentThirstThreshold = state.CurrentThirstThreshold;
|
||||||
|
component.LastThirstThreshold = state.LastThirstThreshold;
|
||||||
|
component.CurrentThirst = state.CurrentThirst;
|
||||||
|
component.NextUpdateTime = state.NextUpdateTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnUnpaused(EntityUid uid, ThirstComponent component, ref EntityUnpausedEvent args)
|
||||||
|
{
|
||||||
|
component.NextUpdateTime += args.PausedTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnShutdown(EntityUid uid, ThirstComponent component, ComponentShutdown args)
|
||||||
|
{
|
||||||
|
_alerts.ClearAlertCategory(uid, AlertCategory.Thirst);
|
||||||
|
}
|
||||||
|
|
||||||
private void OnComponentStartup(EntityUid uid, ThirstComponent component, ComponentStartup args)
|
private void OnComponentStartup(EntityUid uid, ThirstComponent component, ComponentStartup args)
|
||||||
{
|
{
|
||||||
// Do not change behavior unless starting value is explicitly defined
|
// Do not change behavior unless starting value is explicitly defined
|
||||||
@@ -149,23 +187,26 @@ namespace Content.Server.Nutrition.EntitySystems
|
|||||||
throw new ArgumentOutOfRangeException($"No thirst threshold found for {component.CurrentThirstThreshold}");
|
throw new ArgumentOutOfRangeException($"No thirst threshold found for {component.CurrentThirstThreshold}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 thirst))
|
||||||
{
|
{
|
||||||
foreach (var component in EntityManager.EntityQuery<ThirstComponent>())
|
if (_timing.CurTime < thirst.NextUpdateTime)
|
||||||
|
continue;
|
||||||
|
thirst.NextUpdateTime = _timing.CurTime + thirst.UpdateRate;
|
||||||
|
|
||||||
|
UpdateThirst(thirst, -thirst.ActualDecayRate);
|
||||||
|
var calculatedThirstThreshold = GetThirstThreshold(thirst, thirst.CurrentThirst);
|
||||||
|
if (calculatedThirstThreshold != thirst.CurrentThirstThreshold)
|
||||||
{
|
{
|
||||||
UpdateThirst(component, - component.ActualDecayRate);
|
thirst.CurrentThirstThreshold = calculatedThirstThreshold;
|
||||||
var calculatedThirstThreshold = GetThirstThreshold(component, component.CurrentThirst);
|
UpdateEffects(thirst);
|
||||||
if (calculatedThirstThreshold != component.CurrentThirstThreshold)
|
|
||||||
{
|
|
||||||
component.CurrentThirstThreshold = calculatedThirstThreshold;
|
|
||||||
UpdateEffects(component);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
_accumulatedFrameTime -= 1;
|
Dirty(thirst);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
8
Content.Shared/Overlays/ShowHungerIconsComponent.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
namespace Content.Shared.Overlays
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// This component allows you to see the hungriness of mobs.
|
||||||
|
/// </summary>
|
||||||
|
[RegisterComponent]
|
||||||
|
public sealed class ShowHungerIconsComponent : Component { }
|
||||||
|
}
|
||||||
8
Content.Shared/Overlays/ShowSecurityIconsComponent.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
namespace Content.Shared.Overlays
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// This component allows you to see job icons above mobs.
|
||||||
|
/// </summary>
|
||||||
|
[RegisterComponent]
|
||||||
|
public sealed class ShowSecurityIconsComponent : Component { }
|
||||||
|
}
|
||||||
8
Content.Shared/Overlays/ShowThirstIconsComponent.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
namespace Content.Shared.Overlays
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// This component allows you to see the thirstiness of mobs.
|
||||||
|
/// </summary>
|
||||||
|
[RegisterComponent]
|
||||||
|
public sealed class ShowThirstIconsComponent : Component { }
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
namespace Content.Shared.StatusIcon;
|
namespace Content.Shared.StatusIcon;
|
||||||
@@ -22,6 +23,12 @@ public class StatusIconData : IComparable<StatusIconData>
|
|||||||
[DataField("priority")]
|
[DataField("priority")]
|
||||||
public int Priority = 10;
|
public int Priority = 10;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A preference for where the icon will be displayed. None | Left | Right
|
||||||
|
/// </summary>
|
||||||
|
[DataField("locationPreference")]
|
||||||
|
public StatusIconLocationPreference LocationPreference = StatusIconLocationPreference.None;
|
||||||
|
|
||||||
public int CompareTo(StatusIconData? other)
|
public int CompareTo(StatusIconData? other)
|
||||||
{
|
{
|
||||||
return Priority.CompareTo(other?.Priority ?? int.MaxValue);
|
return Priority.CompareTo(other?.Priority ?? int.MaxValue);
|
||||||
@@ -38,3 +45,11 @@ public sealed class StatusIconPrototype : StatusIconData, IPrototype
|
|||||||
[IdDataField]
|
[IdDataField]
|
||||||
public string ID { get; } = default!;
|
public string ID { get; } = default!;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public enum StatusIconLocationPreference : byte
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
Left,
|
||||||
|
Right,
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,14 +1,3 @@
|
|||||||
- type: entity
|
|
||||||
parent: ClothingEyesBase
|
|
||||||
id: ClothingEyesGlassesBeer
|
|
||||||
name: beer goggles
|
|
||||||
description: A pair of sunglasses outfitted with apparatus to scan reagents, as well as providing an innate understanding of liquid viscosity while in motion.
|
|
||||||
components:
|
|
||||||
- type: Sprite
|
|
||||||
sprite: Clothing/Eyes/Glasses/beergoggles.rsi
|
|
||||||
- type: Clothing
|
|
||||||
sprite: Clothing/Eyes/Glasses/beergoggles.rsi
|
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: ClothingEyesBase
|
parent: ClothingEyesBase
|
||||||
id: ClothingEyesGlassesGar
|
id: ClothingEyesGlassesGar
|
||||||
|
|||||||
@@ -30,3 +30,40 @@
|
|||||||
sprite: Clothing/Eyes/Hud/sec.rsi
|
sprite: Clothing/Eyes/Hud/sec.rsi
|
||||||
- type: Clothing
|
- type: Clothing
|
||||||
sprite: Clothing/Eyes/Hud/sec.rsi
|
sprite: Clothing/Eyes/Hud/sec.rsi
|
||||||
|
- type: ShowSecurityIcons
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
parent: ClothingEyesBase
|
||||||
|
id: ClothingEyesHudChef
|
||||||
|
name: onion goggles
|
||||||
|
description: Two onion rings that fused together while frying. They scan the humanoids in view and provide accurate data about their peckishness. Can be eaten as a little treat.
|
||||||
|
components:
|
||||||
|
- type: Sprite
|
||||||
|
sprite: Clothing/Eyes/Hud/friedoniongoggles.rsi
|
||||||
|
- type: Clothing
|
||||||
|
sprite: Clothing/Eyes/Hud/friedoniongoggles.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
|
||||||
|
id: ClothingEyesGlassesBeer
|
||||||
|
name: beer goggles
|
||||||
|
description: A pair of sunglasses outfitted with apparatus to scan reagents, as well as providing an innate understanding of liquid viscosity while in motion.
|
||||||
|
components:
|
||||||
|
- type: Sprite
|
||||||
|
sprite: Clothing/Eyes/Hud/beergoggles.rsi
|
||||||
|
- type: Clothing
|
||||||
|
sprite: Clothing/Eyes/Hud/beergoggles.rsi
|
||||||
|
- type: ShowThirstIcons
|
||||||
@@ -22,6 +22,7 @@
|
|||||||
id: BartenderGear
|
id: BartenderGear
|
||||||
equipment:
|
equipment:
|
||||||
head: ClothingHeadHatTophat
|
head: ClothingHeadHatTophat
|
||||||
|
eyes: ClothingEyesGlassesBeer
|
||||||
jumpsuit: ClothingUniformJumpsuitBartender
|
jumpsuit: ClothingUniformJumpsuitBartender
|
||||||
outerClothing: ClothingOuterVest
|
outerClothing: ClothingOuterVest
|
||||||
back: ClothingBackpackFilled
|
back: ClothingBackpackFilled
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
equipment:
|
equipment:
|
||||||
jumpsuit: ClothingUniformJumpsuitChef
|
jumpsuit: ClothingUniformJumpsuitChef
|
||||||
head: ClothingHeadHatChef
|
head: ClothingHeadHatChef
|
||||||
|
eyes: ClothingEyesHudChef
|
||||||
back: ClothingBackpackFilled
|
back: ClothingBackpackFilled
|
||||||
mask: ClothingMaskItalianMoustache
|
mask: ClothingMaskItalianMoustache
|
||||||
shoes: ClothingShoesColorBlack
|
shoes: ClothingShoesColorBlack
|
||||||
|
|||||||
49
Resources/Prototypes/StatusEffects/hunger.yml
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
#Hunger
|
||||||
|
- type: statusIcon
|
||||||
|
id: HungerIcon_Overfed
|
||||||
|
priority: 5
|
||||||
|
icon:
|
||||||
|
sprite: Interface/Misc/food_icons.rsi
|
||||||
|
state: overfed
|
||||||
|
locationPreference: Right
|
||||||
|
|
||||||
|
- type: statusIcon
|
||||||
|
id: HungerIcon_Peckish
|
||||||
|
priority: 5
|
||||||
|
icon:
|
||||||
|
sprite: Interface/Misc/food_icons.rsi
|
||||||
|
state: peckish
|
||||||
|
locationPreference: Right
|
||||||
|
|
||||||
|
- type: statusIcon
|
||||||
|
id: HungerIcon_Starving
|
||||||
|
priority: 5
|
||||||
|
icon:
|
||||||
|
sprite: Interface/Misc/food_icons.rsi
|
||||||
|
state: starving
|
||||||
|
locationPreference: Right
|
||||||
|
|
||||||
|
#Thirst
|
||||||
|
- type: statusIcon
|
||||||
|
id: ThirstIcon_Overhydrated
|
||||||
|
priority: 5
|
||||||
|
icon:
|
||||||
|
sprite: Interface/Misc/food_icons.rsi
|
||||||
|
state: overhydrated
|
||||||
|
locationPreference: Left
|
||||||
|
|
||||||
|
- type: statusIcon
|
||||||
|
id: ThirstIcon_Thirsty
|
||||||
|
priority: 5
|
||||||
|
icon:
|
||||||
|
sprite: Interface/Misc/food_icons.rsi
|
||||||
|
state: thirsty
|
||||||
|
locationPreference: Left
|
||||||
|
|
||||||
|
- type: statusIcon
|
||||||
|
id: ThirstIcon_Parched
|
||||||
|
priority: 5
|
||||||
|
icon:
|
||||||
|
sprite: Interface/Misc/food_icons.rsi
|
||||||
|
state: parched
|
||||||
|
locationPreference: Left
|
||||||
375
Resources/Prototypes/StatusEffects/job.yml
Normal file
@@ -0,0 +1,375 @@
|
|||||||
|
- type: statusIcon
|
||||||
|
id: JobIcon_Detective
|
||||||
|
priority: 1
|
||||||
|
icon:
|
||||||
|
sprite: Interface/Misc/job_icons.rsi
|
||||||
|
state: Detective
|
||||||
|
locationPreference: Left
|
||||||
|
|
||||||
|
- type: statusIcon
|
||||||
|
id: JobIcon_QuarterMaster
|
||||||
|
priority: 1
|
||||||
|
icon:
|
||||||
|
sprite: Interface/Misc/job_icons.rsi
|
||||||
|
state: QuarterMaster
|
||||||
|
locationPreference: Left
|
||||||
|
|
||||||
|
- type: statusIcon
|
||||||
|
id: JobIcon_Botanist
|
||||||
|
priority: 1
|
||||||
|
icon:
|
||||||
|
sprite: Interface/Misc/job_icons.rsi
|
||||||
|
state: Botanist
|
||||||
|
locationPreference: Left
|
||||||
|
|
||||||
|
- type: statusIcon
|
||||||
|
id: JobIcon_Boxer
|
||||||
|
priority: 1
|
||||||
|
icon:
|
||||||
|
sprite: Interface/Misc/job_icons.rsi
|
||||||
|
state: Boxer
|
||||||
|
locationPreference: Left
|
||||||
|
|
||||||
|
- type: statusIcon
|
||||||
|
id: JobIcon_AtmosphericTechnician
|
||||||
|
priority: 1
|
||||||
|
icon:
|
||||||
|
sprite: Interface/Misc/job_icons.rsi
|
||||||
|
state: AtmosphericTechnician
|
||||||
|
locationPreference: Left
|
||||||
|
|
||||||
|
- type: statusIcon
|
||||||
|
id: JobIcon_Nanotrasen
|
||||||
|
priority: 1
|
||||||
|
icon:
|
||||||
|
sprite: Interface/Misc/job_icons.rsi
|
||||||
|
state: Nanotrasen
|
||||||
|
locationPreference: Left
|
||||||
|
|
||||||
|
- type: statusIcon
|
||||||
|
id: JobIcon_Prisoner
|
||||||
|
priority: 1
|
||||||
|
icon:
|
||||||
|
sprite: Interface/Misc/job_icons.rsi
|
||||||
|
state: Prisoner
|
||||||
|
locationPreference: Left
|
||||||
|
|
||||||
|
- type: statusIcon
|
||||||
|
id: JobIcon_Janitor
|
||||||
|
priority: 1
|
||||||
|
icon:
|
||||||
|
sprite: Interface/Misc/job_icons.rsi
|
||||||
|
state: Janitor
|
||||||
|
locationPreference: Left
|
||||||
|
|
||||||
|
- type: statusIcon
|
||||||
|
id: JobIcon_Chemist
|
||||||
|
priority: 1
|
||||||
|
icon:
|
||||||
|
sprite: Interface/Misc/job_icons.rsi
|
||||||
|
state: Chemist
|
||||||
|
locationPreference: Left
|
||||||
|
|
||||||
|
- type: statusIcon
|
||||||
|
id: JobIcon_StationEngineer
|
||||||
|
priority: 1
|
||||||
|
icon:
|
||||||
|
sprite: Interface/Misc/job_icons.rsi
|
||||||
|
state: StationEngineer
|
||||||
|
locationPreference: Left
|
||||||
|
|
||||||
|
- type: statusIcon
|
||||||
|
id: JobIcon_SecurityOfficer
|
||||||
|
priority: 1
|
||||||
|
icon:
|
||||||
|
sprite: Interface/Misc/job_icons.rsi
|
||||||
|
state: SecurityOfficer
|
||||||
|
locationPreference: Left
|
||||||
|
|
||||||
|
- type: statusIcon
|
||||||
|
id: JobIcon_NoId
|
||||||
|
priority: 1
|
||||||
|
icon:
|
||||||
|
sprite: Interface/Misc/job_icons.rsi
|
||||||
|
state: NoId
|
||||||
|
locationPreference: Left
|
||||||
|
|
||||||
|
- type: statusIcon
|
||||||
|
id: JobIcon_ChiefMedicalOfficer
|
||||||
|
priority: 1
|
||||||
|
icon:
|
||||||
|
sprite: Interface/Misc/job_icons.rsi
|
||||||
|
state: ChiefMedicalOfficer
|
||||||
|
locationPreference: Left
|
||||||
|
|
||||||
|
- type: statusIcon
|
||||||
|
id: JobIcon_Roboticist
|
||||||
|
priority: 1
|
||||||
|
icon:
|
||||||
|
sprite: Interface/Misc/job_icons.rsi
|
||||||
|
state: Roboticist
|
||||||
|
locationPreference: Left
|
||||||
|
|
||||||
|
- type: statusIcon
|
||||||
|
id: JobIcon_Chaplain
|
||||||
|
priority: 1
|
||||||
|
icon:
|
||||||
|
sprite: Interface/Misc/job_icons.rsi
|
||||||
|
state: Chaplain
|
||||||
|
locationPreference: Left
|
||||||
|
|
||||||
|
- type: statusIcon
|
||||||
|
id: JobIcon_Lawyer
|
||||||
|
priority: 1
|
||||||
|
icon:
|
||||||
|
sprite: Interface/Misc/job_icons.rsi
|
||||||
|
state: Lawyer
|
||||||
|
locationPreference: Left
|
||||||
|
|
||||||
|
- type: statusIcon
|
||||||
|
id: JobIcon_Unknown
|
||||||
|
priority: 1
|
||||||
|
icon:
|
||||||
|
sprite: Interface/Misc/job_icons.rsi
|
||||||
|
state: Unknown
|
||||||
|
locationPreference: Left
|
||||||
|
|
||||||
|
- type: statusIcon
|
||||||
|
id: JobIcon_Librarian
|
||||||
|
priority: 1
|
||||||
|
icon:
|
||||||
|
sprite: Interface/Misc/job_icons.rsi
|
||||||
|
state: Librarian
|
||||||
|
locationPreference: Left
|
||||||
|
|
||||||
|
- type: statusIcon
|
||||||
|
id: JobIcon_CargoTechnician
|
||||||
|
priority: 1
|
||||||
|
icon:
|
||||||
|
sprite: Interface/Misc/job_icons.rsi
|
||||||
|
state: CargoTechnician
|
||||||
|
locationPreference: Left
|
||||||
|
|
||||||
|
- type: statusIcon
|
||||||
|
id: JobIcon_Scientist
|
||||||
|
priority: 1
|
||||||
|
icon:
|
||||||
|
sprite: Interface/Misc/job_icons.rsi
|
||||||
|
state: Scientist
|
||||||
|
locationPreference: Left
|
||||||
|
|
||||||
|
- type: statusIcon
|
||||||
|
id: JobIcon_ResearchAssistant
|
||||||
|
priority: 1
|
||||||
|
icon:
|
||||||
|
sprite: Interface/Misc/job_icons.rsi
|
||||||
|
state: ResearchAssistant
|
||||||
|
locationPreference: Left
|
||||||
|
|
||||||
|
- type: statusIcon
|
||||||
|
id: JobIcon_Geneticist
|
||||||
|
priority: 1
|
||||||
|
icon:
|
||||||
|
sprite: Interface/Misc/job_icons.rsi
|
||||||
|
state: Geneticist
|
||||||
|
locationPreference: Left
|
||||||
|
|
||||||
|
- type: statusIcon
|
||||||
|
id: JobIcon_Clown
|
||||||
|
priority: 1
|
||||||
|
icon:
|
||||||
|
sprite: Interface/Misc/job_icons.rsi
|
||||||
|
state: Clown
|
||||||
|
locationPreference: Left
|
||||||
|
|
||||||
|
- type: statusIcon
|
||||||
|
id: JobIcon_Captain
|
||||||
|
priority: 1
|
||||||
|
icon:
|
||||||
|
sprite: Interface/Misc/job_icons.rsi
|
||||||
|
state: Captain
|
||||||
|
locationPreference: Left
|
||||||
|
|
||||||
|
- type: statusIcon
|
||||||
|
id: JobIcon_HeadOfPersonnel
|
||||||
|
priority: 1
|
||||||
|
icon:
|
||||||
|
sprite: Interface/Misc/job_icons.rsi
|
||||||
|
state: HeadOfPersonnel
|
||||||
|
locationPreference: Left
|
||||||
|
|
||||||
|
- type: statusIcon
|
||||||
|
id: JobIcon_Virologist
|
||||||
|
priority: 1
|
||||||
|
icon:
|
||||||
|
sprite: Interface/Misc/job_icons.rsi
|
||||||
|
state: Virologist
|
||||||
|
locationPreference: Left
|
||||||
|
|
||||||
|
- type: statusIcon
|
||||||
|
id: JobIcon_ShaftMiner
|
||||||
|
priority: 1
|
||||||
|
icon:
|
||||||
|
sprite: Interface/Misc/job_icons.rsi
|
||||||
|
state: ShaftMiner
|
||||||
|
locationPreference: Left
|
||||||
|
|
||||||
|
- type: statusIcon
|
||||||
|
id: JobIcon_Passenger
|
||||||
|
priority: 1
|
||||||
|
icon:
|
||||||
|
sprite: Interface/Misc/job_icons.rsi
|
||||||
|
state: Passenger
|
||||||
|
locationPreference: Left
|
||||||
|
|
||||||
|
- type: statusIcon
|
||||||
|
id: JobIcon_ChiefEngineer
|
||||||
|
priority: 1
|
||||||
|
icon:
|
||||||
|
sprite: Interface/Misc/job_icons.rsi
|
||||||
|
state: ChiefEngineer
|
||||||
|
locationPreference: Left
|
||||||
|
|
||||||
|
- type: statusIcon
|
||||||
|
id: JobIcon_Bartender
|
||||||
|
priority: 1
|
||||||
|
icon:
|
||||||
|
sprite: Interface/Misc/job_icons.rsi
|
||||||
|
state: Bartender
|
||||||
|
locationPreference: Left
|
||||||
|
|
||||||
|
- type: statusIcon
|
||||||
|
id: JobIcon_HeadOfSecurity
|
||||||
|
priority: 1
|
||||||
|
icon:
|
||||||
|
sprite: Interface/Misc/job_icons.rsi
|
||||||
|
state: HeadOfSecurity
|
||||||
|
locationPreference: Left
|
||||||
|
|
||||||
|
- type: statusIcon
|
||||||
|
id: JobIcon_Brigmedic
|
||||||
|
priority: 1
|
||||||
|
icon:
|
||||||
|
sprite: Interface/Misc/job_icons.rsi
|
||||||
|
state: Brigmedic
|
||||||
|
locationPreference: Left
|
||||||
|
|
||||||
|
- type: statusIcon
|
||||||
|
id: JobIcon_MedicalDoctor
|
||||||
|
priority: 1
|
||||||
|
icon:
|
||||||
|
sprite: Interface/Misc/job_icons.rsi
|
||||||
|
state: MedicalDoctor
|
||||||
|
locationPreference: Left
|
||||||
|
|
||||||
|
- type: statusIcon
|
||||||
|
id: JobIcon_Paramedic
|
||||||
|
priority: 1
|
||||||
|
icon:
|
||||||
|
sprite: Interface/Misc/job_icons.rsi
|
||||||
|
state: Paramedic
|
||||||
|
locationPreference: Left
|
||||||
|
|
||||||
|
- type: statusIcon
|
||||||
|
id: JobIcon_Chef
|
||||||
|
priority: 1
|
||||||
|
icon:
|
||||||
|
sprite: Interface/Misc/job_icons.rsi
|
||||||
|
state: Chef
|
||||||
|
locationPreference: Left
|
||||||
|
|
||||||
|
- type: statusIcon
|
||||||
|
id: JobIcon_Warden
|
||||||
|
priority: 1
|
||||||
|
icon:
|
||||||
|
sprite: Interface/Misc/job_icons.rsi
|
||||||
|
state: Warden
|
||||||
|
locationPreference: Left
|
||||||
|
|
||||||
|
- type: statusIcon
|
||||||
|
id: JobIcon_ResearchDirector
|
||||||
|
priority: 1
|
||||||
|
icon:
|
||||||
|
sprite: Interface/Misc/job_icons.rsi
|
||||||
|
state: ResearchDirector
|
||||||
|
locationPreference: Left
|
||||||
|
|
||||||
|
- type: statusIcon
|
||||||
|
id: JobIcon_Mime
|
||||||
|
priority: 1
|
||||||
|
icon:
|
||||||
|
sprite: Interface/Misc/job_icons.rsi
|
||||||
|
state: Mime
|
||||||
|
locationPreference: Left
|
||||||
|
|
||||||
|
- type: statusIcon
|
||||||
|
id: JobIcon_Musician
|
||||||
|
priority: 1
|
||||||
|
icon:
|
||||||
|
sprite: Interface/Misc/job_icons.rsi
|
||||||
|
state: Musician
|
||||||
|
locationPreference: Left
|
||||||
|
|
||||||
|
- type: statusIcon
|
||||||
|
id: JobIcon_Reporter
|
||||||
|
priority: 1
|
||||||
|
icon:
|
||||||
|
sprite: Interface/Misc/job_icons.rsi
|
||||||
|
state: Reporter
|
||||||
|
locationPreference: Left
|
||||||
|
|
||||||
|
- type: statusIcon
|
||||||
|
id: JobIcon_Psychologist
|
||||||
|
priority: 1
|
||||||
|
icon:
|
||||||
|
sprite: Interface/Misc/job_icons.rsi
|
||||||
|
state: Psychologist
|
||||||
|
locationPreference: Left
|
||||||
|
|
||||||
|
- type: statusIcon
|
||||||
|
id: JobIcon_MedicalIntern
|
||||||
|
priority: 1
|
||||||
|
icon:
|
||||||
|
sprite: Interface/Misc/job_icons.rsi
|
||||||
|
state: MedicalIntern
|
||||||
|
locationPreference: Left
|
||||||
|
|
||||||
|
- type: statusIcon
|
||||||
|
id: JobIcon_TechnicalAssistant
|
||||||
|
priority: 1
|
||||||
|
icon:
|
||||||
|
sprite: Interface/Misc/job_icons.rsi
|
||||||
|
state: TechnicalAssistant
|
||||||
|
locationPreference: Left
|
||||||
|
|
||||||
|
- type: statusIcon
|
||||||
|
id: JobIcon_ServiceWorker
|
||||||
|
priority: 1
|
||||||
|
icon:
|
||||||
|
sprite: Interface/Misc/job_icons.rsi
|
||||||
|
state: ServiceWorker
|
||||||
|
locationPreference: Left
|
||||||
|
|
||||||
|
- type: statusIcon
|
||||||
|
id: JobIcon_SecurityCadet
|
||||||
|
priority: 1
|
||||||
|
icon:
|
||||||
|
sprite: Interface/Misc/job_icons.rsi
|
||||||
|
state: SecurityCadet
|
||||||
|
locationPreference: Left
|
||||||
|
|
||||||
|
- type: statusIcon
|
||||||
|
id: JobIcon_Zombie
|
||||||
|
priority: 1
|
||||||
|
icon:
|
||||||
|
sprite: Interface/Misc/job_icons.rsi
|
||||||
|
state: Zombie
|
||||||
|
locationPreference: Left
|
||||||
|
|
||||||
|
- type: statusIcon
|
||||||
|
id: JobIcon_Zookeeper
|
||||||
|
priority: 1
|
||||||
|
icon:
|
||||||
|
sprite: Interface/Misc/job_icons.rsi
|
||||||
|
state: Zookeeper
|
||||||
|
locationPreference: Left
|
||||||
|
Before Width: | Height: | Size: 187 B After Width: | Height: | Size: 187 B |
|
Before Width: | Height: | Size: 181 B After Width: | Height: | Size: 181 B |
|
Before Width: | Height: | Size: 523 B After Width: | Height: | Size: 523 B |
|
Before Width: | Height: | Size: 778 B After Width: | Height: | Size: 778 B |