Health alert tweaks (#20557)
@@ -5,7 +5,6 @@ using Content.Shared.Damage;
|
|||||||
using Content.Shared.FixedPoint;
|
using Content.Shared.FixedPoint;
|
||||||
using Content.Shared.Mobs.Components;
|
using Content.Shared.Mobs.Components;
|
||||||
using Robust.Shared.GameStates;
|
using Robust.Shared.GameStates;
|
||||||
using Robust.Shared.Utility;
|
|
||||||
|
|
||||||
namespace Content.Shared.Mobs.Systems;
|
namespace Content.Shared.Mobs.Systems;
|
||||||
|
|
||||||
@@ -52,6 +51,38 @@ public sealed class MobThresholdSystem : EntitySystem
|
|||||||
|
|
||||||
#region Public API
|
#region Public API
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the next available state for a mob.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="target">Target entity</param>
|
||||||
|
/// <param name="mobState">Supplied MobState</param>
|
||||||
|
/// <param name="nextState">The following MobState. Can be null if there isn't one.</param>
|
||||||
|
/// <param name="thresholdsComponent">Threshold Component Owned by the target</param>
|
||||||
|
/// <returns>True if the next mob state exists</returns>
|
||||||
|
public bool TryGetNextState(
|
||||||
|
EntityUid target,
|
||||||
|
MobState mobState,
|
||||||
|
[NotNullWhen(true)] out MobState? nextState,
|
||||||
|
MobThresholdsComponent? thresholdsComponent = null)
|
||||||
|
{
|
||||||
|
nextState = null;
|
||||||
|
if (!Resolve(target, ref thresholdsComponent))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
MobState? min = null;
|
||||||
|
foreach (var state in thresholdsComponent.Thresholds.Values)
|
||||||
|
{
|
||||||
|
if (state <= mobState)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (min == null || state < min)
|
||||||
|
min = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
nextState = min;
|
||||||
|
return nextState != null;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get the Damage Threshold for the appropriate state if it exists
|
/// Get the Damage Threshold for the appropriate state if it exists
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -261,7 +292,7 @@ public sealed class MobThresholdSystem : EntitySystem
|
|||||||
threshold.Thresholds.Remove(damageThreshold);
|
threshold.Thresholds.Remove(damageThreshold);
|
||||||
}
|
}
|
||||||
threshold.Thresholds[damage] = mobState;
|
threshold.Thresholds[damage] = mobState;
|
||||||
Dirty(threshold);
|
Dirty(target, threshold);
|
||||||
VerifyThresholds(target, threshold);
|
VerifyThresholds(target, threshold);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -291,7 +322,7 @@ public sealed class MobThresholdSystem : EntitySystem
|
|||||||
if (!Resolve(uid, ref component, false))
|
if (!Resolve(uid, ref component, false))
|
||||||
return;
|
return;
|
||||||
component.AllowRevives = val;
|
component.AllowRevives = val;
|
||||||
Dirty(component);
|
Dirty(uid, component);
|
||||||
VerifyThresholds(uid, component);
|
VerifyThresholds(uid, component);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -344,42 +375,37 @@ public sealed class MobThresholdSystem : EntitySystem
|
|||||||
if (!threshold.TriggersAlerts)
|
if (!threshold.TriggersAlerts)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var dict = threshold.StateAlertDict;
|
if (!threshold.StateAlertDict.TryGetValue(currentMobState, out var currentAlert))
|
||||||
var healthAlert = AlertType.HumanHealth;
|
{
|
||||||
var critAlert = AlertType.HumanCrit;
|
Log.Error($"No alert alert for mob state {currentMobState} for entity {ToPrettyString(target)}");
|
||||||
var deadAlert = AlertType.HumanDead;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
dict.TryGetValue(MobState.Alive, out healthAlert);
|
if (!_alerts.TryGet(currentAlert, out var alertPrototype))
|
||||||
dict.TryGetValue(MobState.Critical, out critAlert);
|
{
|
||||||
dict.TryGetValue(MobState.Dead, out deadAlert);
|
Log.Error($"Invalid alert type {currentAlert}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch (currentMobState)
|
if (alertPrototype.SupportsSeverity)
|
||||||
{
|
{
|
||||||
case MobState.Alive:
|
var severity = _alerts.GetMinSeverity(currentAlert);
|
||||||
|
if (TryGetNextState(target, currentMobState, out var nextState, threshold) &&
|
||||||
|
TryGetPercentageForState(target, nextState.Value, damageable.TotalDamage, out var percentage))
|
||||||
{
|
{
|
||||||
var severity = _alerts.GetMinSeverity(healthAlert);
|
percentage = FixedPoint2.Clamp(percentage.Value, 0, 1);
|
||||||
if (TryGetIncapPercentage(target, damageable.TotalDamage, out var percentage))
|
|
||||||
{
|
severity = (short) MathF.Round(
|
||||||
severity = (short) MathF.Floor(percentage.Value.Float() *
|
MathHelper.Lerp(
|
||||||
_alerts.GetSeverityRange(healthAlert));
|
_alerts.GetMinSeverity(currentAlert),
|
||||||
severity += _alerts.GetMinSeverity(healthAlert);
|
_alerts.GetMaxSeverity(currentAlert),
|
||||||
|
percentage.Value.Float()));
|
||||||
}
|
}
|
||||||
_alerts.ShowAlert(target, healthAlert, severity);
|
_alerts.ShowAlert(target, currentAlert, severity);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
case MobState.Critical:
|
else
|
||||||
{
|
{
|
||||||
_alerts.ShowAlert(target, critAlert);
|
_alerts.ShowAlert(target, currentAlert);
|
||||||
break;
|
|
||||||
}
|
|
||||||
case MobState.Dead:
|
|
||||||
{
|
|
||||||
_alerts.ShowAlert(target, deadAlert);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case MobState.Invalid:
|
|
||||||
default:
|
|
||||||
throw new ArgumentOutOfRangeException(nameof(currentMobState), currentMobState, null);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.3 KiB |