Make it possible to hide full health bars below a total damage threshold (#28127)
* Make it possible to hide full health bars below a total damage threshold * Fix not setting state
This commit is contained in:
@@ -1,15 +1,14 @@
|
||||
using System.Numerics;
|
||||
using Content.Client.UserInterface.Systems;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Content.Shared.Mobs;
|
||||
using Content.Shared.Mobs.Components;
|
||||
using Content.Shared.Mobs.Systems;
|
||||
using Content.Shared.StatusIcon.Components;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Shared.Enums;
|
||||
using System.Numerics;
|
||||
using Content.Shared.StatusIcon.Components;
|
||||
using Content.Client.UserInterface.Systems;
|
||||
using Robust.Shared.Prototypes;
|
||||
using static Robust.Shared.Maths.Color;
|
||||
|
||||
namespace Content.Client.Overlays;
|
||||
@@ -79,6 +78,10 @@ public sealed class EntityHealthBarOverlay : Overlay
|
||||
continue;
|
||||
}
|
||||
|
||||
// we are all progressing towards death every day
|
||||
if (CalcProgress(uid, mobStateComponent, damageableComponent, mobThresholdsComponent) is not { } deathProgress)
|
||||
continue;
|
||||
|
||||
var worldPosition = _transform.GetWorldPosition(xform);
|
||||
var worldMatrix = Matrix3.CreateTranslation(worldPosition);
|
||||
|
||||
@@ -91,10 +94,6 @@ public sealed class EntityHealthBarOverlay : Overlay
|
||||
var widthOfMob = 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.
|
||||
@@ -122,10 +121,13 @@ public sealed class EntityHealthBarOverlay : Overlay
|
||||
/// <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)
|
||||
private (float ratio, bool inCrit)? CalcProgress(EntityUid uid, MobStateComponent component, DamageableComponent dmg, MobThresholdsComponent thresholds)
|
||||
{
|
||||
if (_mobStateSystem.IsAlive(uid, component))
|
||||
{
|
||||
if (dmg.HealthBarThreshold != null && dmg.TotalDamage < dmg.HealthBarThreshold)
|
||||
return null;
|
||||
|
||||
if (!_mobThresholdSystem.TryGetThresholdForState(uid, MobState.Critical, out var threshold, thresholds) &&
|
||||
!_mobThresholdSystem.TryGetThresholdForState(uid, MobState.Dead, out threshold, thresholds))
|
||||
return (1, false);
|
||||
|
||||
@@ -5,8 +5,6 @@ using Content.Shared.StatusIcon;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
|
||||
|
||||
namespace Content.Shared.Damage
|
||||
{
|
||||
@@ -18,7 +16,7 @@ namespace Content.Shared.Damage
|
||||
/// may also have resistances to certain damage types, defined via a <see cref="DamageModifierSetPrototype"/>.
|
||||
/// </remarks>
|
||||
[RegisterComponent]
|
||||
[NetworkedComponent()]
|
||||
[NetworkedComponent]
|
||||
[Access(typeof(DamageableSystem), Other = AccessPermissions.ReadExecute)]
|
||||
public sealed partial class DamageableComponent : Component
|
||||
{
|
||||
@@ -26,8 +24,8 @@ namespace Content.Shared.Damage
|
||||
/// This <see cref="DamageContainerPrototype"/> specifies what damage types are supported by this component.
|
||||
/// If null, all damage types will be supported.
|
||||
/// </summary>
|
||||
[DataField("damageContainer", customTypeSerializer: typeof(PrototypeIdSerializer<DamageContainerPrototype>))]
|
||||
public string? DamageContainerID;
|
||||
[DataField("damageContainer")]
|
||||
public ProtoId<DamageContainerPrototype>? DamageContainerID;
|
||||
|
||||
/// <summary>
|
||||
/// This <see cref="DamageModifierSetPrototype"/> will be applied to any damage that is dealt to this container,
|
||||
@@ -37,8 +35,8 @@ namespace Content.Shared.Damage
|
||||
/// Though DamageModifierSets can be deserialized directly, we only want to use the prototype version here
|
||||
/// to reduce duplication.
|
||||
/// </remarks>
|
||||
[DataField("damageModifierSet", customTypeSerializer: typeof(PrototypeIdSerializer<DamageModifierSetPrototype>))]
|
||||
public string? DamageModifierSetId;
|
||||
[DataField("damageModifierSet")]
|
||||
public ProtoId<DamageModifierSetPrototype>? DamageModifierSetId;
|
||||
|
||||
/// <summary>
|
||||
/// All the damage information is stored in this <see cref="DamageSpecifier"/>.
|
||||
@@ -46,7 +44,7 @@ namespace Content.Shared.Damage
|
||||
/// <remarks>
|
||||
/// If this data-field is specified, this allows damageable components to be initialized with non-zero damage.
|
||||
/// </remarks>
|
||||
[DataField("damage", readOnly: true)] //todo remove this readonly when implementing writing to damagespecifier
|
||||
[DataField(readOnly: true)] //todo remove this readonly when implementing writing to damagespecifier
|
||||
public DamageSpecifier Damage = new();
|
||||
|
||||
/// <summary>
|
||||
@@ -64,8 +62,8 @@ namespace Content.Shared.Damage
|
||||
[ViewVariables]
|
||||
public FixedPoint2 TotalDamage;
|
||||
|
||||
[DataField("radiationDamageTypes", customTypeSerializer: typeof(PrototypeIdListSerializer<DamageTypePrototype>))]
|
||||
public List<string> RadiationDamageTypeIDs = new() { "Radiation" };
|
||||
[DataField("radiationDamageTypes")]
|
||||
public List<ProtoId<DamageTypePrototype>> RadiationDamageTypeIDs = new() { "Radiation" };
|
||||
|
||||
[DataField]
|
||||
public Dictionary<MobState, ProtoId<StatusIconPrototype>> HealthIcons = new()
|
||||
@@ -77,6 +75,9 @@ namespace Content.Shared.Damage
|
||||
|
||||
[DataField]
|
||||
public ProtoId<StatusIconPrototype> RottingIcon = "HealthIconRotting";
|
||||
|
||||
[DataField]
|
||||
public FixedPoint2? HealthBarThreshold;
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
@@ -84,13 +85,16 @@ namespace Content.Shared.Damage
|
||||
{
|
||||
public readonly Dictionary<string, FixedPoint2> DamageDict;
|
||||
public readonly string? ModifierSetId;
|
||||
public readonly FixedPoint2? HealthBarThreshold;
|
||||
|
||||
public DamageableComponentState(
|
||||
Dictionary<string, FixedPoint2> damageDict,
|
||||
string? modifierSetId)
|
||||
string? modifierSetId,
|
||||
FixedPoint2? healthBarThreshold)
|
||||
{
|
||||
DamageDict = damageDict;
|
||||
ModifierSetId = modifierSetId;
|
||||
HealthBarThreshold = healthBarThreshold;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System.Linq;
|
||||
using Content.Shared.Administration.Logs;
|
||||
using Content.Shared.Damage.Prototypes;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Content.Shared.Inventory;
|
||||
@@ -229,12 +228,12 @@ namespace Content.Shared.Damage
|
||||
{
|
||||
if (_netMan.IsServer)
|
||||
{
|
||||
args.State = new DamageableComponentState(component.Damage.DamageDict, component.DamageModifierSetId);
|
||||
args.State = new DamageableComponentState(component.Damage.DamageDict, component.DamageModifierSetId, component.HealthBarThreshold);
|
||||
}
|
||||
else
|
||||
{
|
||||
// avoid mispredicting damage on newly spawned entities.
|
||||
args.State = new DamageableComponentState(component.Damage.DamageDict.ShallowClone(), component.DamageModifierSetId);
|
||||
args.State = new DamageableComponentState(component.Damage.DamageDict.ShallowClone(), component.DamageModifierSetId, component.HealthBarThreshold);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -268,6 +267,7 @@ namespace Content.Shared.Damage
|
||||
}
|
||||
|
||||
component.DamageModifierSetId = state.ModifierSetId;
|
||||
component.HealthBarThreshold = state.HealthBarThreshold;
|
||||
|
||||
// Has the damage actually changed?
|
||||
DamageSpecifier newDamage = new() { DamageDict = new(state.DamageDict) };
|
||||
|
||||
Reference in New Issue
Block a user