-using Content.Shared.Damage.Prototypes;
-using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
+using Content.Shared.Dataset;
+using Robust.Shared.Prototypes;
namespace Content.Server.Damage.Components;
/// <summary>
-/// This component shows entity damage severity when it is examined by player.
+/// This component shows entity damage severity when it is examined by player.
/// </summary>
[RegisterComponent]
public sealed partial class ExaminableDamageComponent : Component
{
- [DataField("messages", required: true, customTypeSerializer:typeof(PrototypeIdSerializer<ExaminableDamagePrototype>))]
- public string? MessagesProtoId;
-
- public ExaminableDamagePrototype? MessagesProto;
+ /// <summary>
+ /// ID of the <see cref="LocalizedDatasetPrototype"/> containing messages to display a different damage levels.
+ /// The first message will be used at 0 damage with the others equally distributed across the range from undamaged to fully damaged.
+ /// </summary>
+ [DataField]
+ public ProtoId<LocalizedDatasetPrototype>? Messages;
}
-using System.Linq;
-using Content.Server.Damage.Components;
+using Content.Server.Damage.Components;
using Content.Server.Destructible;
-using Content.Server.Destructible.Thresholds.Triggers;
using Content.Shared.Damage;
-using Content.Shared.Damage.Prototypes;
using Content.Shared.Examine;
using Content.Shared.Rounding;
using Robust.Shared.Prototypes;
public sealed class ExaminableDamageSystem : EntitySystem
{
+ [Dependency] private readonly DestructibleSystem _destructible = default!;
[Dependency] private readonly IPrototypeManager _prototype = default!;
public override void Initialize()
{
base.Initialize();
- SubscribeLocalEvent<ExaminableDamageComponent, ComponentInit>(OnInit);
SubscribeLocalEvent<ExaminableDamageComponent, ExaminedEvent>(OnExamine);
}
- private void OnInit(EntityUid uid, ExaminableDamageComponent component, ComponentInit args)
+ private void OnExamine(Entity<ExaminableDamageComponent> ent, ref ExaminedEvent args)
{
- if (component.MessagesProtoId == null)
- return;
- component.MessagesProto = _prototype.Index<ExaminableDamagePrototype>(component.MessagesProtoId);
- }
-
- private void OnExamine(EntityUid uid, ExaminableDamageComponent component, ExaminedEvent args)
- {
- if (component.MessagesProto == null)
- return;
-
- var messages = component.MessagesProto.Messages;
- if (messages.Length == 0)
+ if (!_prototype.TryIndex(ent.Comp.Messages, out var proto) || proto.Values.Count == 0)
return;
- var level = GetDamageLevel(uid, component);
- var msg = Loc.GetString(messages[level]);
- args.PushMarkup(msg,-99);
+ var percent = GetDamagePercent(ent);
+ var level = ContentHelpers.RoundToNearestLevels(percent, 1, proto.Values.Count - 1);
+ var msg = Loc.GetString(proto.Values[level]);
+ args.PushMarkup(msg, -99);
}
- private int GetDamageLevel(EntityUid uid, ExaminableDamageComponent? component = null,
- DamageableComponent? damageable = null, DestructibleComponent? destructible = null)
+ /// <summary>
+ /// Returns a value between 0 and 1 representing how damaged the entity is,
+ /// where 0 is undamaged and 1 is fully damaged.
+ /// </summary>
+ /// <returns>How damaged the entity is from 0 to 1</returns>
+ private float GetDamagePercent(Entity<ExaminableDamageComponent> ent)
{
- if (!Resolve(uid, ref component, ref damageable, ref destructible))
+ if (!TryComp<DamageableComponent>(ent, out var damageable))
return 0;
- if (component.MessagesProto == null)
- return 0;
-
- var maxLevels = component.MessagesProto.Messages.Length - 1;
- if (maxLevels <= 0)
- return 0;
+ var damage = damageable.TotalDamage;
+ var damageThreshold = _destructible.DestroyedAt(ent);
- var trigger = (DamageTrigger?) destructible.Thresholds
- .LastOrDefault(threshold => threshold.Trigger is DamageTrigger)?.Trigger;
- if (trigger == null)
+ if (damageThreshold == 0)
return 0;
- var damage = damageable.TotalDamage;
- var damageThreshold = trigger.Damage;
- var fraction = damageThreshold == 0 ? 0f : (float) damage / damageThreshold;
-
- var level = ContentHelpers.RoundToNearestLevels(fraction, 1, maxLevels);
- return level;
+ return (damage / damageThreshold).Float();
}
}