Add health bar overlays for eye equipment (#21980)
* PR 1 * fix an error with health bar overlay (#1292) * Revert "Revert "Replace `ResourcePath` with `ResPath` (#15308)" (#155… (#15566) * [1612] change ShowHealthBarsComponent's DamageContainer field to a list (#1662) * fix build * no crit entities from not updating * cleanup * namespace * undu irrelevant changes * undo icon change * make health bar 1 px taller and icon 1 px shorter * fix medibot * fix comment * don't show health bar ratio when in crit * fix build * put the crit bar back * don't render healthbars for mobs that are in containers * draw more boxes without the background sprite * fine status icon for all bio mobs * add wacky mandatory things * attempt 2 * whoops wrong file * cool, this works too * move null check to top * only 1 init * security huds * remove shader * fix build after cleanup * slight cleanup * little more cleanup * Remove clothing grant component system * security HUD now shows a job icon on entities with a body * remove sec stuff and do similar changes to split off PR + remove unused comp * process comments * don't return * update to ComponentAddedOverlaySystemBase * no cache * colors and not rendering out of sight * touch ups * fix build & cleanup * undo * remove shader from icons * process comments * documentation * fix licence * validate prototype id * just use args * rename method and append in method * type * just fucken delete the command * space * undo * remove * don't use LocalPlayer * re-add showhealthbars command, but working * rename icon lists and conform health icon code to the others * space * undo * update command * oops --------- Co-authored-by: Rane <60792108+Elijahrane@users.noreply.github.com> Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
This commit is contained in:
54
Content.Client/Commands/ShowHealthBarsCommand.cs
Normal file
54
Content.Client/Commands/ShowHealthBarsCommand.cs
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
using Content.Shared.Overlays;
|
||||||
|
using Robust.Client.Player;
|
||||||
|
using Robust.Shared.Console;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Content.Client.Commands;
|
||||||
|
|
||||||
|
public sealed class ShowHealthBarsCommand : LocalizedCommands
|
||||||
|
{
|
||||||
|
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||||
|
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||||
|
|
||||||
|
public override string Command => "showhealthbars";
|
||||||
|
|
||||||
|
public override string Help => LocalizationManager.GetString($"cmd-{Command}-help", ("command", Command));
|
||||||
|
|
||||||
|
public override void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||||
|
{
|
||||||
|
var player = _playerManager.LocalSession;
|
||||||
|
if (player == null)
|
||||||
|
{
|
||||||
|
shell.WriteError(LocalizationManager.GetString($"cmd-{Command}-error-not-player"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var playerEntity = player?.AttachedEntity;
|
||||||
|
if (!playerEntity.HasValue)
|
||||||
|
{
|
||||||
|
shell.WriteError(LocalizationManager.GetString($"cmd-{Command}-error-no-entity"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_entityManager.HasComponent<ShowHealthBarsComponent>(playerEntity))
|
||||||
|
{
|
||||||
|
var showHealthBarsComponent = new ShowHealthBarsComponent
|
||||||
|
{
|
||||||
|
DamageContainers = args.ToList(),
|
||||||
|
NetSyncEnabled = false
|
||||||
|
};
|
||||||
|
|
||||||
|
_entityManager.AddComponent(playerEntity.Value, showHealthBarsComponent, true);
|
||||||
|
|
||||||
|
shell.WriteLine(LocalizationManager.GetString($"cmd-{Command}-notify-enabled", ("args", string.Join(", ", args))));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_entityManager.RemoveComponentDeferred<ShowHealthBarsComponent>(playerEntity.Value);
|
||||||
|
shell.WriteLine(LocalizationManager.GetString($"cmd-{Command}-notify-disabled"));
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
using Content.Client.HealthOverlay;
|
|
||||||
using Robust.Shared.Console;
|
|
||||||
|
|
||||||
namespace Content.Client.Commands;
|
|
||||||
|
|
||||||
public sealed class ToggleHealthOverlayCommand : LocalizedCommands
|
|
||||||
{
|
|
||||||
[Dependency] private readonly IEntitySystemManager _entitySystemManager = default!;
|
|
||||||
|
|
||||||
public override string Command => "togglehealthoverlay";
|
|
||||||
|
|
||||||
public override string Help => LocalizationManager.GetString($"cmd-{Command}-help", ("command", Command));
|
|
||||||
|
|
||||||
public override void Execute(IConsoleShell shell, string argStr, string[] args)
|
|
||||||
{
|
|
||||||
var system = _entitySystemManager.GetEntitySystem<HealthOverlaySystem>();
|
|
||||||
system.Enabled = !system.Enabled;
|
|
||||||
|
|
||||||
shell.WriteLine(LocalizationManager.GetString($"cmd-{Command}-notify", ("state", system.Enabled ? "enabled" : "disabled")));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
using Content.Client.HealthOverlay.UI;
|
|
||||||
using Content.Shared.Damage;
|
|
||||||
using Content.Shared.GameTicking;
|
|
||||||
using Content.Shared.Mobs.Components;
|
|
||||||
using JetBrains.Annotations;
|
|
||||||
using Robust.Client.Graphics;
|
|
||||||
using Robust.Client.Player;
|
|
||||||
|
|
||||||
namespace Content.Client.HealthOverlay
|
|
||||||
{
|
|
||||||
[UsedImplicitly]
|
|
||||||
public sealed class HealthOverlaySystem : EntitySystem
|
|
||||||
{
|
|
||||||
[Dependency] private readonly IEyeManager _eyeManager = default!;
|
|
||||||
[Dependency] private readonly IEntityManager _entities = default!;
|
|
||||||
[Dependency] private readonly IPlayerManager _player = default!;
|
|
||||||
|
|
||||||
private readonly Dictionary<EntityUid, HealthOverlayGui> _guis = new();
|
|
||||||
private bool _enabled;
|
|
||||||
|
|
||||||
public bool Enabled
|
|
||||||
{
|
|
||||||
get => _enabled;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (_enabled == value)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_enabled = value;
|
|
||||||
|
|
||||||
foreach (var gui in _guis.Values)
|
|
||||||
{
|
|
||||||
gui.SetVisibility(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Initialize()
|
|
||||||
{
|
|
||||||
base.Initialize();
|
|
||||||
|
|
||||||
SubscribeNetworkEvent<RoundRestartCleanupEvent>(Reset);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Reset(RoundRestartCleanupEvent ev)
|
|
||||||
{
|
|
||||||
foreach (var gui in _guis.Values)
|
|
||||||
{
|
|
||||||
gui.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
_guis.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void FrameUpdate(float frameTime)
|
|
||||||
{
|
|
||||||
base.Update(frameTime);
|
|
||||||
|
|
||||||
if (!_enabled)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_player.LocalEntity is not {} ent || Deleted(ent))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var viewBox = _eyeManager.GetWorldViewport().Enlarged(2.0f);
|
|
||||||
|
|
||||||
var query = EntityQueryEnumerator<MobStateComponent, DamageableComponent>();
|
|
||||||
while (query.MoveNext(out var entity, out var mobState, out _))
|
|
||||||
{
|
|
||||||
if (_entities.GetComponent<TransformComponent>(ent).MapID != _entities.GetComponent<TransformComponent>(entity).MapID ||
|
|
||||||
!viewBox.Contains(_entities.GetComponent<TransformComponent>(entity).WorldPosition))
|
|
||||||
{
|
|
||||||
if (_guis.TryGetValue(entity, out var oldGui))
|
|
||||||
{
|
|
||||||
_guis.Remove(entity);
|
|
||||||
oldGui.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_guis.ContainsKey(entity))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var gui = new HealthOverlayGui(entity);
|
|
||||||
_guis.Add(entity, gui);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
using Robust.Client.Graphics;
|
|
||||||
using Robust.Client.UserInterface;
|
|
||||||
using Robust.Shared.IoC;
|
|
||||||
using Robust.Shared.Maths;
|
|
||||||
using Robust.Shared.Prototypes;
|
|
||||||
|
|
||||||
namespace Content.Client.HealthOverlay.UI
|
|
||||||
{
|
|
||||||
public sealed class HealthOverlayBar : Control
|
|
||||||
{
|
|
||||||
public const byte HealthBarScale = 2;
|
|
||||||
|
|
||||||
private const int XPixelDiff = 20 * HealthBarScale;
|
|
||||||
|
|
||||||
public HealthOverlayBar()
|
|
||||||
{
|
|
||||||
IoCManager.InjectDependencies(this);
|
|
||||||
Shader = IoCManager.Resolve<IPrototypeManager>().Index<ShaderPrototype>("unshaded").Instance();
|
|
||||||
}
|
|
||||||
|
|
||||||
private ShaderInstance Shader { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// From -1 (dead) to 0 (crit) and 1 (alive)
|
|
||||||
/// </summary>
|
|
||||||
public float Ratio { get; set; }
|
|
||||||
|
|
||||||
public Color Color { get; set; }
|
|
||||||
|
|
||||||
protected override void Draw(DrawingHandleScreen handle)
|
|
||||||
{
|
|
||||||
base.Draw(handle);
|
|
||||||
|
|
||||||
handle.UseShader(Shader);
|
|
||||||
|
|
||||||
var leftOffset = 2 * HealthBarScale;
|
|
||||||
var box = new UIBox2i(
|
|
||||||
leftOffset,
|
|
||||||
-2 + 2 * HealthBarScale,
|
|
||||||
leftOffset + (int) (XPixelDiff * Ratio * UIScale),
|
|
||||||
-2);
|
|
||||||
|
|
||||||
handle.DrawRect(box, Color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,164 +0,0 @@
|
|||||||
using System.Numerics;
|
|
||||||
using Content.Client.IoC;
|
|
||||||
using Content.Client.Resources;
|
|
||||||
using Content.Shared.Damage;
|
|
||||||
using Content.Shared.FixedPoint;
|
|
||||||
using Content.Shared.Mobs;
|
|
||||||
using Content.Shared.Mobs.Components;
|
|
||||||
using Content.Shared.Mobs.Systems;
|
|
||||||
using Robust.Client.Graphics;
|
|
||||||
using Robust.Client.UserInterface.Controls;
|
|
||||||
using Robust.Shared.Timing;
|
|
||||||
|
|
||||||
namespace Content.Client.HealthOverlay.UI
|
|
||||||
{
|
|
||||||
public sealed class HealthOverlayGui : BoxContainer
|
|
||||||
{
|
|
||||||
[Dependency] private readonly IEyeManager _eyeManager = default!;
|
|
||||||
[Dependency] private readonly IEntityManager _entities = default!;
|
|
||||||
|
|
||||||
public HealthOverlayGui(EntityUid entity)
|
|
||||||
{
|
|
||||||
IoCManager.InjectDependencies(this);
|
|
||||||
UserInterfaceManager.WindowRoot.AddChild(this);
|
|
||||||
SeparationOverride = 0;
|
|
||||||
Orientation = LayoutOrientation.Vertical;
|
|
||||||
|
|
||||||
CritBar = new HealthOverlayBar
|
|
||||||
{
|
|
||||||
Visible = false,
|
|
||||||
VerticalAlignment = VAlignment.Center,
|
|
||||||
Color = Color.Red
|
|
||||||
};
|
|
||||||
|
|
||||||
HealthBar = new HealthOverlayBar
|
|
||||||
{
|
|
||||||
Visible = false,
|
|
||||||
VerticalAlignment = VAlignment.Center,
|
|
||||||
Color = Color.LimeGreen
|
|
||||||
};
|
|
||||||
|
|
||||||
AddChild(Panel = new PanelContainer
|
|
||||||
{
|
|
||||||
Children =
|
|
||||||
{
|
|
||||||
new TextureRect
|
|
||||||
{
|
|
||||||
Texture = StaticIoC.ResC.GetTexture("/Textures/Interface/Misc/health_bar.rsi/icon.png"),
|
|
||||||
TextureScale = Vector2.One * HealthOverlayBar.HealthBarScale,
|
|
||||||
VerticalAlignment = VAlignment.Center,
|
|
||||||
},
|
|
||||||
CritBar,
|
|
||||||
HealthBar
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Entity = entity;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PanelContainer Panel { get; }
|
|
||||||
|
|
||||||
public HealthOverlayBar HealthBar { get; }
|
|
||||||
|
|
||||||
public HealthOverlayBar CritBar { get; }
|
|
||||||
|
|
||||||
public EntityUid Entity { get; }
|
|
||||||
|
|
||||||
public void SetVisibility(bool val)
|
|
||||||
{
|
|
||||||
Visible = val;
|
|
||||||
Panel.Visible = val;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void MoreFrameUpdate()
|
|
||||||
{
|
|
||||||
if (_entities.Deleted(Entity))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_entities.TryGetComponent(Entity, out MobStateComponent? mobState) ||
|
|
||||||
!_entities.TryGetComponent(Entity, out DamageableComponent? damageable))
|
|
||||||
{
|
|
||||||
CritBar.Visible = false;
|
|
||||||
HealthBar.Visible = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var mobStateSystem = _entities.EntitySysManager.GetEntitySystem<MobStateSystem>();
|
|
||||||
var mobThresholdSystem = _entities.EntitySysManager.GetEntitySystem<MobThresholdSystem>();
|
|
||||||
if (mobStateSystem.IsAlive(Entity, mobState))
|
|
||||||
{
|
|
||||||
if (!mobThresholdSystem.TryGetThresholdForState(Entity,MobState.Critical, out var threshold))
|
|
||||||
{
|
|
||||||
CritBar.Visible = false;
|
|
||||||
HealthBar.Visible = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
CritBar.Ratio = 1;
|
|
||||||
CritBar.Visible = true;
|
|
||||||
HealthBar.Ratio = 1 - ((FixedPoint2)(damageable.TotalDamage / threshold)).Float();
|
|
||||||
HealthBar.Visible = true;
|
|
||||||
}
|
|
||||||
else if (mobStateSystem.IsCritical(Entity, mobState))
|
|
||||||
{
|
|
||||||
HealthBar.Ratio = 0;
|
|
||||||
HealthBar.Visible = false;
|
|
||||||
|
|
||||||
if (!mobThresholdSystem.TryGetThresholdForState(Entity, MobState.Critical, out var critThreshold) ||
|
|
||||||
!mobThresholdSystem.TryGetThresholdForState(Entity, MobState.Dead, out var deadThreshold))
|
|
||||||
{
|
|
||||||
CritBar.Visible = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
CritBar.Visible = true;
|
|
||||||
CritBar.Ratio = 1 -
|
|
||||||
((damageable.TotalDamage - critThreshold) /
|
|
||||||
(deadThreshold - critThreshold)).Value.Float();
|
|
||||||
}
|
|
||||||
else if (mobStateSystem.IsDead(Entity, mobState))
|
|
||||||
{
|
|
||||||
CritBar.Ratio = 0;
|
|
||||||
CritBar.Visible = false;
|
|
||||||
HealthBar.Ratio = 0;
|
|
||||||
HealthBar.Visible = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
CritBar.Visible = false;
|
|
||||||
HealthBar.Visible = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void FrameUpdate(FrameEventArgs args)
|
|
||||||
{
|
|
||||||
base.FrameUpdate(args);
|
|
||||||
|
|
||||||
MoreFrameUpdate();
|
|
||||||
|
|
||||||
if (_entities.Deleted(Entity) || _eyeManager.CurrentMap != _entities.GetComponent<TransformComponent>(Entity).MapID)
|
|
||||||
{
|
|
||||||
Visible = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Visible = true;
|
|
||||||
|
|
||||||
var screenCoordinates = _eyeManager.CoordinatesToScreen(_entities.GetComponent<TransformComponent>(Entity).Coordinates);
|
|
||||||
var playerPosition = UserInterfaceManager.ScreenToUIPosition(screenCoordinates);
|
|
||||||
LayoutContainer.SetPosition(this, new Vector2(playerPosition.X - Width / 2, playerPosition.Y - Height - 30.0f));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
|
||||||
{
|
|
||||||
base.Dispose(disposing);
|
|
||||||
|
|
||||||
if (!disposing)
|
|
||||||
return;
|
|
||||||
|
|
||||||
HealthBar.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
170
Content.Client/Overlays/EntityHealthBarOverlay.cs
Normal file
170
Content.Client/Overlays/EntityHealthBarOverlay.cs
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
using Content.Shared.Damage;
|
||||||
|
using Content.Shared.FixedPoint;
|
||||||
|
using Content.Shared.Mobs;
|
||||||
|
using Content.Shared.Mobs.Components;
|
||||||
|
using Content.Shared.Mobs.Systems;
|
||||||
|
using Robust.Client.GameObjects;
|
||||||
|
using Robust.Client.Graphics;
|
||||||
|
using Robust.Shared.Enums;
|
||||||
|
using System.Numerics;
|
||||||
|
using static Robust.Shared.Maths.Color;
|
||||||
|
|
||||||
|
namespace Content.Client.Overlays;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Overlay that shows a health bar on mobs.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class EntityHealthBarOverlay : Overlay
|
||||||
|
{
|
||||||
|
private readonly IEntityManager _entManager;
|
||||||
|
private readonly SharedTransformSystem _transform;
|
||||||
|
private readonly MobStateSystem _mobStateSystem;
|
||||||
|
private readonly MobThresholdSystem _mobThresholdSystem;
|
||||||
|
public override OverlaySpace Space => OverlaySpace.WorldSpaceBelowFOV;
|
||||||
|
public HashSet<string> DamageContainers = new();
|
||||||
|
|
||||||
|
public EntityHealthBarOverlay(IEntityManager entManager)
|
||||||
|
{
|
||||||
|
_entManager = entManager;
|
||||||
|
_transform = _entManager.EntitySysManager.GetEntitySystem<SharedTransformSystem>();
|
||||||
|
_mobStateSystem = _entManager.EntitySysManager.GetEntitySystem<MobStateSystem>();
|
||||||
|
_mobThresholdSystem = _entManager.EntitySysManager.GetEntitySystem<MobThresholdSystem>();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Draw(in OverlayDrawArgs args)
|
||||||
|
{
|
||||||
|
var handle = args.WorldHandle;
|
||||||
|
var rotation = args.Viewport.Eye?.Rotation ?? Angle.Zero;
|
||||||
|
var xformQuery = _entManager.GetEntityQuery<TransformComponent>();
|
||||||
|
|
||||||
|
const float scale = 1f;
|
||||||
|
var scaleMatrix = Matrix3.CreateScale(new Vector2(scale, scale));
|
||||||
|
var rotationMatrix = Matrix3.CreateRotation(-rotation);
|
||||||
|
|
||||||
|
var query = _entManager.AllEntityQueryEnumerator<MobThresholdsComponent, MobStateComponent, DamageableComponent, SpriteComponent>();
|
||||||
|
while (query.MoveNext(out var uid,
|
||||||
|
out var mobThresholdsComponent,
|
||||||
|
out var mobStateComponent,
|
||||||
|
out var damageableComponent,
|
||||||
|
out var spriteComponent))
|
||||||
|
{
|
||||||
|
if (_entManager.TryGetComponent<MetaDataComponent>(uid, out var metaDataComponent) &&
|
||||||
|
metaDataComponent.Flags.HasFlag(MetaDataFlags.InContainer))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!xformQuery.TryGetComponent(uid, out var xform) ||
|
||||||
|
xform.MapID != args.MapId)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (damageableComponent.DamageContainerID == null || !DamageContainers.Contains(damageableComponent.DamageContainerID))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var bounds = spriteComponent.Bounds;
|
||||||
|
var worldPos = _transform.GetWorldPosition(xform, xformQuery);
|
||||||
|
|
||||||
|
if (!bounds.Translated(worldPos).Intersects(args.WorldAABB))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var worldPosition = _transform.GetWorldPosition(xform);
|
||||||
|
var worldMatrix = Matrix3.CreateTranslation(worldPosition);
|
||||||
|
|
||||||
|
Matrix3.Multiply(scaleMatrix, worldMatrix, out var scaledWorld);
|
||||||
|
Matrix3.Multiply(rotationMatrix, scaledWorld, out var matty);
|
||||||
|
|
||||||
|
handle.SetTransform(matty);
|
||||||
|
|
||||||
|
var yOffset = spriteComponent.Bounds.Height * EyeManager.PixelsPerMeter / 2 - 3f;
|
||||||
|
var widthOfMob = spriteComponent.Bounds.Width * EyeManager.PixelsPerMeter;
|
||||||
|
|
||||||
|
var position = new Vector2(-widthOfMob / EyeManager.PixelsPerMeter / 2, yOffset / EyeManager.PixelsPerMeter);
|
||||||
|
|
||||||
|
// we are all progressing towards death every day
|
||||||
|
(float ratio, bool inCrit) deathProgress = CalcProgress(uid, mobStateComponent, damageableComponent, mobThresholdsComponent);
|
||||||
|
|
||||||
|
var color = GetProgressColor(deathProgress.ratio, deathProgress.inCrit);
|
||||||
|
|
||||||
|
// Hardcoded width of the progress bar because it doesn't match the texture.
|
||||||
|
const float startX = 8f;
|
||||||
|
var endX = widthOfMob - 8f;
|
||||||
|
|
||||||
|
var xProgress = (endX - startX) * deathProgress.ratio + startX;
|
||||||
|
|
||||||
|
var boxBackground = new Box2(new Vector2(startX, 0f) / EyeManager.PixelsPerMeter, new Vector2(endX, 3f) / EyeManager.PixelsPerMeter);
|
||||||
|
boxBackground = boxBackground.Translated(position);
|
||||||
|
handle.DrawRect(boxBackground, Black.WithAlpha(192));
|
||||||
|
|
||||||
|
var boxMain = new Box2(new Vector2(startX, 0f) / EyeManager.PixelsPerMeter, new Vector2(xProgress, 3f) / EyeManager.PixelsPerMeter);
|
||||||
|
boxMain = boxMain.Translated(position);
|
||||||
|
handle.DrawRect(boxMain, color);
|
||||||
|
|
||||||
|
var pixelDarken = new Box2(new Vector2(startX, 2f) / EyeManager.PixelsPerMeter, new Vector2(xProgress, 3f) / EyeManager.PixelsPerMeter);
|
||||||
|
pixelDarken = pixelDarken.Translated(position);
|
||||||
|
handle.DrawRect(pixelDarken, Black.WithAlpha(128));
|
||||||
|
}
|
||||||
|
|
||||||
|
handle.UseShader(null);
|
||||||
|
handle.SetTransform(Matrix3.Identity);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a ratio between 0 and 1, and whether the entity is in crit.
|
||||||
|
/// </summary>
|
||||||
|
private (float, bool) CalcProgress(EntityUid uid, MobStateComponent component, DamageableComponent dmg, MobThresholdsComponent thresholds)
|
||||||
|
{
|
||||||
|
if (_mobStateSystem.IsAlive(uid, component))
|
||||||
|
{
|
||||||
|
if (!_mobThresholdSystem.TryGetThresholdForState(uid, MobState.Critical, out var threshold, thresholds) &&
|
||||||
|
!_mobThresholdSystem.TryGetThresholdForState(uid, MobState.Dead, out threshold, thresholds))
|
||||||
|
return (1, false);
|
||||||
|
|
||||||
|
var ratio = 1 - ((FixedPoint2) (dmg.TotalDamage / threshold)).Float();
|
||||||
|
return (ratio, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_mobStateSystem.IsCritical(uid, component))
|
||||||
|
{
|
||||||
|
if (!_mobThresholdSystem.TryGetThresholdForState(uid, MobState.Critical, out var critThreshold, thresholds) ||
|
||||||
|
!_mobThresholdSystem.TryGetThresholdForState(uid, MobState.Dead, out var deadThreshold, thresholds))
|
||||||
|
{
|
||||||
|
return (1, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
var ratio = 1 - ((dmg.TotalDamage - critThreshold) / (deadThreshold - critThreshold)).Value.Float();
|
||||||
|
|
||||||
|
return (ratio, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (0, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Color GetProgressColor(float progress, bool crit)
|
||||||
|
{
|
||||||
|
if (progress >= 1.0f)
|
||||||
|
{
|
||||||
|
return SeaBlue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!crit)
|
||||||
|
{
|
||||||
|
switch (progress)
|
||||||
|
{
|
||||||
|
case > 0.90F:
|
||||||
|
return SeaBlue;
|
||||||
|
case > 0.50F:
|
||||||
|
return Violet;
|
||||||
|
case > 0.15F:
|
||||||
|
return Ruber;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return VividGamboge;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -72,7 +72,7 @@ public abstract class EquipmentHudSystem<T> : EntitySystem where T : IComponent
|
|||||||
|
|
||||||
private void OnPlayerDetached(LocalPlayerDetachedEvent args)
|
private void OnPlayerDetached(LocalPlayerDetachedEvent args)
|
||||||
{
|
{
|
||||||
if (_player.LocalPlayer?.ControlledEntity == null)
|
if (_player.LocalSession?.AttachedEntity == null)
|
||||||
Deactivate();
|
Deactivate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,17 +93,18 @@ public abstract class EquipmentHudSystem<T> : EntitySystem where T : IComponent
|
|||||||
|
|
||||||
protected virtual void OnRefreshEquipmentHud(EntityUid uid, T component, InventoryRelayedEvent<RefreshEquipmentHudEvent<T>> args)
|
protected virtual void OnRefreshEquipmentHud(EntityUid uid, T component, InventoryRelayedEvent<RefreshEquipmentHudEvent<T>> args)
|
||||||
{
|
{
|
||||||
args.Args.Active = true;
|
OnRefreshComponentHud(uid, component, args.Args);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void OnRefreshComponentHud(EntityUid uid, T component, RefreshEquipmentHudEvent<T> args)
|
protected virtual void OnRefreshComponentHud(EntityUid uid, T component, RefreshEquipmentHudEvent<T> args)
|
||||||
{
|
{
|
||||||
args.Active = true;
|
args.Active = true;
|
||||||
|
args.Components.Add(component);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RefreshOverlay(EntityUid uid)
|
private void RefreshOverlay(EntityUid uid)
|
||||||
{
|
{
|
||||||
if (uid != _player.LocalPlayer?.ControlledEntity)
|
if (uid != _player.LocalSession?.AttachedEntity)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var ev = new RefreshEquipmentHudEvent<T>(TargetSlots);
|
var ev = new RefreshEquipmentHudEvent<T>(TargetSlots);
|
||||||
|
|||||||
46
Content.Client/Overlays/ShowHealthBarsSystem.cs
Normal file
46
Content.Client/Overlays/ShowHealthBarsSystem.cs
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
using Content.Shared.Inventory.Events;
|
||||||
|
using Content.Shared.Overlays;
|
||||||
|
using Robust.Client.Graphics;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Content.Client.Overlays;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a health bar overlay.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class ShowHealthBarsSystem : EquipmentHudSystem<ShowHealthBarsComponent>
|
||||||
|
{
|
||||||
|
[Dependency] private readonly IOverlayManager _overlayMan = default!;
|
||||||
|
|
||||||
|
private EntityHealthBarOverlay _overlay = default!;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
_overlay = new(EntityManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void UpdateInternal(RefreshEquipmentHudEvent<ShowHealthBarsComponent> component)
|
||||||
|
{
|
||||||
|
base.UpdateInternal(component);
|
||||||
|
|
||||||
|
foreach (var damageContainerId in component.Components.SelectMany(x => x.DamageContainers))
|
||||||
|
{
|
||||||
|
_overlay.DamageContainers.Add(damageContainerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_overlayMan.HasOverlay<EntityHealthBarOverlay>())
|
||||||
|
{
|
||||||
|
_overlayMan.AddOverlay(_overlay);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void DeactivateInternal()
|
||||||
|
{
|
||||||
|
base.DeactivateInternal();
|
||||||
|
|
||||||
|
_overlay.DamageContainers.Clear();
|
||||||
|
_overlayMan.RemoveOverlay(_overlay);
|
||||||
|
}
|
||||||
|
}
|
||||||
77
Content.Client/Overlays/ShowHealthIconsSystem.cs
Normal file
77
Content.Client/Overlays/ShowHealthIconsSystem.cs
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
using Content.Shared.Damage;
|
||||||
|
using Content.Shared.Inventory.Events;
|
||||||
|
using Content.Shared.Overlays;
|
||||||
|
using Content.Shared.StatusIcon;
|
||||||
|
using Content.Shared.StatusIcon.Components;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Content.Client.Overlays;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Shows a healthy icon on mobs.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class ShowHealthIconsSystem : EquipmentHudSystem<ShowHealthIconsComponent>
|
||||||
|
{
|
||||||
|
[Dependency] private readonly IPrototypeManager _prototypeMan = default!;
|
||||||
|
|
||||||
|
public HashSet<string> DamageContainers = new();
|
||||||
|
|
||||||
|
[ValidatePrototypeId<StatusIconPrototype>]
|
||||||
|
private const string HealthIconFine = "HealthIconFine";
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeLocalEvent<DamageableComponent, GetStatusIconsEvent>(OnGetStatusIconsEvent);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void UpdateInternal(RefreshEquipmentHudEvent<ShowHealthIconsComponent> component)
|
||||||
|
{
|
||||||
|
base.UpdateInternal(component);
|
||||||
|
|
||||||
|
foreach (var damageContainerId in component.Components.SelectMany(x => x.DamageContainers))
|
||||||
|
{
|
||||||
|
DamageContainers.Add(damageContainerId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void DeactivateInternal()
|
||||||
|
{
|
||||||
|
base.DeactivateInternal();
|
||||||
|
|
||||||
|
DamageContainers.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnGetStatusIconsEvent(EntityUid uid, DamageableComponent damageableComponent, ref GetStatusIconsEvent args)
|
||||||
|
{
|
||||||
|
if (!IsActive || args.InContainer)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var healthIcons = DecideHealthIcons(damageableComponent);
|
||||||
|
|
||||||
|
args.StatusIcons.AddRange(healthIcons);
|
||||||
|
}
|
||||||
|
|
||||||
|
private IReadOnlyList<StatusIconPrototype> DecideHealthIcons(DamageableComponent damageableComponent)
|
||||||
|
{
|
||||||
|
if (damageableComponent.DamageContainerID == null ||
|
||||||
|
!DamageContainers.Contains(damageableComponent.DamageContainerID))
|
||||||
|
{
|
||||||
|
return Array.Empty<StatusIconPrototype>();
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = new List<StatusIconPrototype>();
|
||||||
|
|
||||||
|
// Here you could check health status, diseases, mind status, etc. and pick a good icon, or multiple depending on whatever.
|
||||||
|
if (damageableComponent?.DamageContainerID == "Biological" &&
|
||||||
|
_prototypeMan.TryIndex<StatusIconPrototype>(HealthIconFine, out var healthyIcon))
|
||||||
|
{
|
||||||
|
result.Add(healthyIcon);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -22,9 +22,9 @@ public sealed class ShowHungerIconsSystem : EquipmentHudSystem<ShowHungerIconsCo
|
|||||||
if (!IsActive || args.InContainer)
|
if (!IsActive || args.InContainer)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var healthIcons = DecideHungerIcon(uid, hungerComponent);
|
var hungerIcons = DecideHungerIcon(uid, hungerComponent);
|
||||||
|
|
||||||
args.StatusIcons.AddRange(healthIcons);
|
args.StatusIcons.AddRange(hungerIcons);
|
||||||
}
|
}
|
||||||
|
|
||||||
private IReadOnlyList<StatusIconPrototype> DecideHungerIcon(EntityUid uid, HungerComponent hungerComponent)
|
private IReadOnlyList<StatusIconPrototype> DecideHungerIcon(EntityUid uid, HungerComponent hungerComponent)
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ using Content.Shared.StatusIcon.Components;
|
|||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
namespace Content.Client.Overlays;
|
namespace Content.Client.Overlays;
|
||||||
|
|
||||||
public sealed class ShowSecurityIconsSystem : EquipmentHudSystem<ShowSecurityIconsComponent>
|
public sealed class ShowSecurityIconsSystem : EquipmentHudSystem<ShowSecurityIconsComponent>
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IPrototypeManager _prototypeMan = default!;
|
[Dependency] private readonly IPrototypeManager _prototypeMan = default!;
|
||||||
@@ -30,9 +31,9 @@ public sealed class ShowSecurityIconsSystem : EquipmentHudSystem<ShowSecurityIco
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var healthIcons = DecideSecurityIcon(uid);
|
var securityIcons = DecideSecurityIcon(uid);
|
||||||
|
|
||||||
@event.StatusIcons.AddRange(healthIcons);
|
@event.StatusIcons.AddRange(securityIcons);
|
||||||
}
|
}
|
||||||
|
|
||||||
private IReadOnlyList<StatusIconPrototype> DecideSecurityIcon(EntityUid uid)
|
private IReadOnlyList<StatusIconPrototype> DecideSecurityIcon(EntityUid uid)
|
||||||
|
|||||||
@@ -23,9 +23,9 @@ public sealed class ShowSyndicateIconsSystem : EquipmentHudSystem<ShowSyndicateI
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var healthIcons = SyndicateIcon(uid, nukeOperativeComponent);
|
var syndicateIcons = SyndicateIcon(uid, nukeOperativeComponent);
|
||||||
|
|
||||||
args.StatusIcons.AddRange(healthIcons);
|
args.StatusIcons.AddRange(syndicateIcons);
|
||||||
}
|
}
|
||||||
|
|
||||||
private IReadOnlyList<StatusIconPrototype> SyndicateIcon(EntityUid uid, NukeOperativeComponent nukeOperativeComponent)
|
private IReadOnlyList<StatusIconPrototype> SyndicateIcon(EntityUid uid, NukeOperativeComponent nukeOperativeComponent)
|
||||||
|
|||||||
@@ -22,9 +22,9 @@ public sealed class ShowThirstIconsSystem : EquipmentHudSystem<ShowThirstIconsCo
|
|||||||
if (!IsActive || args.InContainer)
|
if (!IsActive || args.InContainer)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var healthIcons = DecideThirstIcon(uid, thirstComponent);
|
var thirstIcons = DecideThirstIcon(uid, thirstComponent);
|
||||||
|
|
||||||
args.StatusIcons.AddRange(healthIcons);
|
args.StatusIcons.AddRange(thirstIcons);
|
||||||
}
|
}
|
||||||
|
|
||||||
private IReadOnlyList<StatusIconPrototype> DecideThirstIcon(EntityUid uid, ThirstComponent thirstComponent)
|
private IReadOnlyList<StatusIconPrototype> DecideThirstIcon(EntityUid uid, ThirstComponent thirstComponent)
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ public sealed class StatusIconOverlay : Overlay
|
|||||||
private readonly SpriteSystem _sprite;
|
private readonly SpriteSystem _sprite;
|
||||||
private readonly TransformSystem _transform;
|
private readonly TransformSystem _transform;
|
||||||
private readonly StatusIconSystem _statusIcon;
|
private readonly StatusIconSystem _statusIcon;
|
||||||
|
|
||||||
private readonly ShaderInstance _shader;
|
private readonly ShaderInstance _shader;
|
||||||
|
|
||||||
public override OverlaySpace Space => OverlaySpace.WorldSpaceBelowFOV;
|
public override OverlaySpace Space => OverlaySpace.WorldSpaceBelowFOV;
|
||||||
@@ -28,7 +27,6 @@ public sealed class StatusIconOverlay : Overlay
|
|||||||
_sprite = _entity.System<SpriteSystem>();
|
_sprite = _entity.System<SpriteSystem>();
|
||||||
_transform = _entity.System<TransformSystem>();
|
_transform = _entity.System<TransformSystem>();
|
||||||
_statusIcon = _entity.System<StatusIconSystem>();
|
_statusIcon = _entity.System<StatusIconSystem>();
|
||||||
|
|
||||||
_shader = _prototype.Index<ShaderPrototype>("unshaded").Instance();
|
_shader = _prototype.Index<ShaderPrototype>("unshaded").Instance();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ public sealed class RefreshEquipmentHudEvent<T> : EntityEventArgs, IInventoryRel
|
|||||||
{
|
{
|
||||||
public SlotFlags TargetSlots { get; init; }
|
public SlotFlags TargetSlots { get; init; }
|
||||||
public bool Active = false;
|
public bool Active = false;
|
||||||
public object? ExtraData;
|
public List<T> Components = new();
|
||||||
|
|
||||||
public RefreshEquipmentHudEvent(SlotFlags targetSlots)
|
public RefreshEquipmentHudEvent(SlotFlags targetSlots)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -39,6 +39,8 @@ public partial class InventorySystem
|
|||||||
|
|
||||||
// ComponentActivatedClientSystems
|
// ComponentActivatedClientSystems
|
||||||
SubscribeLocalEvent<InventoryComponent, RefreshEquipmentHudEvent<ShowSecurityIconsComponent>>(RelayInventoryEvent);
|
SubscribeLocalEvent<InventoryComponent, RefreshEquipmentHudEvent<ShowSecurityIconsComponent>>(RelayInventoryEvent);
|
||||||
|
SubscribeLocalEvent<InventoryComponent, RefreshEquipmentHudEvent<ShowHealthBarsComponent>>(RelayInventoryEvent);
|
||||||
|
SubscribeLocalEvent<InventoryComponent, RefreshEquipmentHudEvent<ShowHealthIconsComponent>>(RelayInventoryEvent);
|
||||||
SubscribeLocalEvent<InventoryComponent, RefreshEquipmentHudEvent<ShowHungerIconsComponent>>(RelayInventoryEvent);
|
SubscribeLocalEvent<InventoryComponent, RefreshEquipmentHudEvent<ShowHungerIconsComponent>>(RelayInventoryEvent);
|
||||||
SubscribeLocalEvent<InventoryComponent, RefreshEquipmentHudEvent<ShowThirstIconsComponent>>(RelayInventoryEvent);
|
SubscribeLocalEvent<InventoryComponent, RefreshEquipmentHudEvent<ShowThirstIconsComponent>>(RelayInventoryEvent);
|
||||||
SubscribeLocalEvent<InventoryComponent, RefreshEquipmentHudEvent<ShowSyndicateIconsComponent>>(RelayInventoryEvent);
|
SubscribeLocalEvent<InventoryComponent, RefreshEquipmentHudEvent<ShowSyndicateIconsComponent>>(RelayInventoryEvent);
|
||||||
|
|||||||
18
Content.Shared/Overlays/ShowHealthBarsComponent.cs
Normal file
18
Content.Shared/Overlays/ShowHealthBarsComponent.cs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
using Content.Shared.Damage.Prototypes;
|
||||||
|
using Robust.Shared.GameStates;
|
||||||
|
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
|
||||||
|
|
||||||
|
namespace Content.Shared.Overlays;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This component allows you to see health bars above damageable mobs.
|
||||||
|
/// </summary>
|
||||||
|
[RegisterComponent, NetworkedComponent]
|
||||||
|
public sealed partial class ShowHealthBarsComponent : Component
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Displays health bars of the damage containers.
|
||||||
|
/// </summary>
|
||||||
|
[DataField("damageContainers", customTypeSerializer: typeof(PrototypeIdListSerializer<DamageContainerPrototype>))]
|
||||||
|
public List<string> DamageContainers = new();
|
||||||
|
}
|
||||||
18
Content.Shared/Overlays/ShowHealthIconsComponent.cs
Normal file
18
Content.Shared/Overlays/ShowHealthIconsComponent.cs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
using Content.Shared.Damage.Prototypes;
|
||||||
|
using Robust.Shared.GameStates;
|
||||||
|
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
|
||||||
|
|
||||||
|
namespace Content.Shared.Overlays;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This component allows you to see health status icons above damageable mobs.
|
||||||
|
/// </summary>
|
||||||
|
[RegisterComponent, NetworkedComponent]
|
||||||
|
public sealed partial class ShowHealthIconsComponent : Component
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Displays health status icons of the damage containers.
|
||||||
|
/// </summary>
|
||||||
|
[DataField("damageContainers", customTypeSerializer: typeof(PrototypeIdListSerializer<DamageContainerPrototype>))]
|
||||||
|
public List<string> DamageContainers = new();
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
cmd-showhealthbars-desc = Toggles health bars above mobs.
|
||||||
|
cmd-showhealthbars-help = Usage: {$command} [<DamageContainerId>]
|
||||||
|
cmd-showhealthbars-error-not-player = You aren't a player.
|
||||||
|
cmd-showhealthbars-error-no-entity = You do not have an attached entity.
|
||||||
|
cmd-showhealthbars-notify-enabled = Enabled health overlay for DamageContainers: {$args}.
|
||||||
|
cmd-showhealthbars-notify-disabled = Disabled health overlay.
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
cmd-togglehealthoverlay-desc = Toggles a health bar above mobs.
|
|
||||||
cmd-togglehealthoverlay-help = Usage: {$command}
|
|
||||||
cmd-togglehealthoverlay-notify = Health overlay system {$state}.
|
|
||||||
@@ -8,6 +8,9 @@
|
|||||||
sprite: Clothing/Eyes/Hud/diag.rsi
|
sprite: Clothing/Eyes/Hud/diag.rsi
|
||||||
- type: Clothing
|
- type: Clothing
|
||||||
sprite: Clothing/Eyes/Hud/diag.rsi
|
sprite: Clothing/Eyes/Hud/diag.rsi
|
||||||
|
- type: ShowHealthBars
|
||||||
|
damageContainers:
|
||||||
|
- Inorganic
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: ClothingEyesBase
|
parent: ClothingEyesBase
|
||||||
@@ -19,6 +22,12 @@
|
|||||||
sprite: Clothing/Eyes/Hud/med.rsi
|
sprite: Clothing/Eyes/Hud/med.rsi
|
||||||
- type: Clothing
|
- type: Clothing
|
||||||
sprite: Clothing/Eyes/Hud/med.rsi
|
sprite: Clothing/Eyes/Hud/med.rsi
|
||||||
|
- type: ShowHealthBars
|
||||||
|
damageContainers:
|
||||||
|
- Biological
|
||||||
|
- type: ShowHealthIcons
|
||||||
|
damageContainers:
|
||||||
|
- Biological
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: ClothingEyesBase
|
parent: ClothingEyesBase
|
||||||
@@ -94,6 +103,12 @@
|
|||||||
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: ShowHealthBars
|
||||||
|
damageContainers:
|
||||||
|
- Biological
|
||||||
|
- type: ShowHealthIcons
|
||||||
|
damageContainers:
|
||||||
|
- Biological
|
||||||
- type: ShowHungerIcons
|
- type: ShowHungerIcons
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
@@ -106,6 +121,12 @@
|
|||||||
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: ShowHealthBars
|
||||||
|
damageContainers:
|
||||||
|
- Biological
|
||||||
|
- type: ShowHealthIcons
|
||||||
|
damageContainers:
|
||||||
|
- Biological
|
||||||
- type: ShowHungerIcons
|
- type: ShowHungerIcons
|
||||||
- type: ShowThirstIcons
|
- type: ShowThirstIcons
|
||||||
|
|
||||||
@@ -132,6 +153,13 @@
|
|||||||
- type: Clothing
|
- type: Clothing
|
||||||
sprite: Clothing/Eyes/Hud/medsecengi.rsi
|
sprite: Clothing/Eyes/Hud/medsecengi.rsi
|
||||||
- type: ShowSecurityIcons
|
- type: ShowSecurityIcons
|
||||||
|
- type: ShowHealthBars
|
||||||
|
damageContainers:
|
||||||
|
- Biological
|
||||||
|
- Inorganic
|
||||||
|
- type: ShowHealthIcons
|
||||||
|
damageContainers:
|
||||||
|
- Biological
|
||||||
- type: ShowSyndicateIcons
|
- type: ShowSyndicateIcons
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
@@ -145,6 +173,13 @@
|
|||||||
- type: Clothing
|
- type: Clothing
|
||||||
sprite: Clothing/Eyes/Hud/omni.rsi
|
sprite: Clothing/Eyes/Hud/omni.rsi
|
||||||
- type: ShowSecurityIcons
|
- type: ShowSecurityIcons
|
||||||
|
- type: ShowHealthBars
|
||||||
|
damageContainers:
|
||||||
|
- Biological
|
||||||
|
- Inorganic
|
||||||
|
- type: ShowHealthIcons
|
||||||
|
damageContainers:
|
||||||
|
- Biological
|
||||||
- type: ShowHungerIcons
|
- type: ShowHungerIcons
|
||||||
- type: ShowThirstIcons
|
- type: ShowThirstIcons
|
||||||
- type: ShowSyndicateIcons
|
- type: ShowSyndicateIcons
|
||||||
|
|||||||
@@ -349,6 +349,12 @@
|
|||||||
interactFailureString: petting-failure-medibot
|
interactFailureString: petting-failure-medibot
|
||||||
interactSuccessSound:
|
interactSuccessSound:
|
||||||
path: /Audio/Ambience/Objects/periodic_beep.ogg
|
path: /Audio/Ambience/Objects/periodic_beep.ogg
|
||||||
|
- type: ShowHealthBars
|
||||||
|
damageContainers:
|
||||||
|
- Biological
|
||||||
|
- type: ShowHealthIcons
|
||||||
|
damageContainers:
|
||||||
|
- Biological
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: MobSiliconBase
|
parent: MobSiliconBase
|
||||||
|
|||||||
7
Resources/Prototypes/StatusEffects/health.yml
Normal file
7
Resources/Prototypes/StatusEffects/health.yml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
- type: statusIcon
|
||||||
|
id: HealthIconFine
|
||||||
|
priority: 1
|
||||||
|
icon:
|
||||||
|
sprite: Interface/Misc/health_icons.rsi
|
||||||
|
state: Fine
|
||||||
|
locationPreference: Right
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 2.1 KiB |
@@ -1,14 +0,0 @@
|
|||||||
{
|
|
||||||
"version": 1,
|
|
||||||
"size": {
|
|
||||||
"y": 7,
|
|
||||||
"x": 24
|
|
||||||
},
|
|
||||||
"license": "CC-BY-SA-3.0",
|
|
||||||
"copyright": "https://github.com/tgstation/tgstation/blob/886ca0f8dddf83ecaf10c92ff106172722352192/icons/effects/progessbar.dmi",
|
|
||||||
"states": [
|
|
||||||
{
|
|
||||||
"name": "icon"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
BIN
Resources/Textures/Interface/Misc/health_icons.rsi/Fine.png
Normal file
BIN
Resources/Textures/Interface/Misc/health_icons.rsi/Fine.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
14
Resources/Textures/Interface/Misc/health_icons.rsi/meta.json
Normal file
14
Resources/Textures/Interface/Misc/health_icons.rsi/meta.json
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"version": 1,
|
||||||
|
"size": {
|
||||||
|
"x": 8,
|
||||||
|
"y": 8
|
||||||
|
},
|
||||||
|
"license": "CC-BY-SA-3.0",
|
||||||
|
"copyright": "https://github.com/tgstation/tgstation/blob/master/icons/mob/huds/hud.dmi",
|
||||||
|
"states": [
|
||||||
|
{
|
||||||
|
"name": "Fine"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user