using Content.Shared.Mobs;
using Content.Shared.Mobs.Components;
using Content.Shared.Mobs.Systems;
+using Content.Shared.Traits.Assorted;
using JetBrains.Annotations;
using Robust.Client.Graphics;
using Robust.Client.Player;
{
case MobState.Alive:
{
- if (damageable.DamagePerGroup.TryGetValue("Brute", out var bruteDamage))
+ if (EntityManager.HasComponent<PainNumbnessComponent>(entity))
+ {
+ _overlay.BruteLevel = 0;
+ }
+ else if (damageable.DamagePerGroup.TryGetValue("Brute", out var bruteDamage))
{
_overlay.BruteLevel = FixedPoint2.Min(1f, bruteDamage / critThreshold).Float();
}
using Content.Shared.Bed.Sleep;
using Content.Shared.Damage;
+using Content.Shared.Damage.Events;
using Content.Shared.Damage.ForceSay;
using Content.Shared.FixedPoint;
using Content.Shared.Mobs;
}
}
- private void TryForceSay(EntityUid uid, DamageForceSayComponent component, bool useSuffix=true, string? suffixOverride = null)
+ private void TryForceSay(EntityUid uid, DamageForceSayComponent component, bool useSuffix=true)
{
if (!TryComp<ActorComponent>(uid, out var actor))
return;
_timing.CurTime < component.NextAllowedTime)
return;
- var suffix = Loc.GetString(suffixOverride ?? component.ForceSayStringPrefix + _random.Next(1, component.ForceSayStringCount));
+ var ev = new BeforeForceSayEvent(component.ForceSayStringDataset);
+ RaiseLocalEvent(uid, ev);
+
+ if (!_prototype.TryIndex(ev.Prefix, out var prefixList))
+ return;
+
+ var suffix = Loc.GetString(_random.Pick(prefixList.Values));
// set cooldown & raise event
component.NextAllowedTime = _timing.CurTime + component.Cooldown;
if (!args.FellAsleep)
return;
- TryForceSay(uid, component, true, "damage-force-say-sleep");
+ TryForceSay(uid, component);
AllowNextSpeech(uid);
}
+using Content.Shared.Dataset;
using Content.Shared.FixedPoint;
using Robust.Shared.Audio;
using Robust.Shared.GameStates;
+using Robust.Shared.Prototypes;
namespace Content.Shared.Bed.Sleep;
{
Params = AudioParams.Default.WithVariation(0.05f)
};
+
+ /// <summary>
+ /// The fluent string prefix to use when picking a random suffix
+ /// This is only active for those who have the sleeping component
+ /// </summary>
+ [DataField]
+ public ProtoId<LocalizedDatasetPrototype> ForceSaySleepDataset = "ForceSaySleepDataset";
}
using Content.Shared.Actions;
using Content.Shared.Buckle.Components;
using Content.Shared.Damage;
+using Content.Shared.Damage.Events;
using Content.Shared.Damage.ForceSay;
using Content.Shared.Emoting;
using Content.Shared.Examine;
using Content.Shared.Speech;
using Content.Shared.StatusEffect;
using Content.Shared.Stunnable;
+using Content.Shared.Traits.Assorted;
using Content.Shared.Verbs;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Prototypes;
SubscribeLocalEvent<ForcedSleepingComponent, ComponentInit>(OnInit);
SubscribeLocalEvent<SleepingComponent, UnbuckleAttemptEvent>(OnUnbuckleAttempt);
SubscribeLocalEvent<SleepingComponent, EmoteAttemptEvent>(OnEmoteAttempt);
+
+ SubscribeLocalEvent<SleepingComponent, BeforeForceSayEvent>(OnChangeForceSay, after: new []{typeof(PainNumbnessSystem)});
}
private void OnUnbuckleAttempt(Entity<SleepingComponent> ent, ref UnbuckleAttemptEvent args)
{
args.Cancel();
}
+
+ private void OnChangeForceSay(Entity<SleepingComponent> ent, ref BeforeForceSayEvent args)
+ {
+ args.Prefix = ent.Comp.ForceSaySleepDataset;
+ }
}
--- /dev/null
+using Content.Shared.Dataset;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Serialization;
+
+namespace Content.Shared.Damage.Events;
+
+/// <summary>
+/// Event for interrupting and changing the prefix for when an entity is being forced to say something
+/// </summary>
+[Serializable, NetSerializable]
+public sealed class BeforeForceSayEvent(ProtoId<LocalizedDatasetPrototype> prefixDataset) : EntityEventArgs
+{
+ public ProtoId<LocalizedDatasetPrototype> Prefix = prefixDataset;
+}
using Content.Shared.Damage.Prototypes;
+using Content.Shared.Dataset;
using Content.Shared.FixedPoint;
using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;
-using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Set;
namespace Content.Shared.Damage.ForceSay;
/// The fluent string prefix to use when picking a random suffix
/// </summary>
[DataField]
- public string ForceSayStringPrefix = "damage-force-say-";
-
- /// <summary>
- /// The number of suffixes that exist for use with <see cref="ForceSayStringPrefix"/>.
- /// i.e. (prefix)-1 through (prefix)-(count)
- /// </summary>
- [DataField]
- public int ForceSayStringCount = 7;
+ public ProtoId<LocalizedDatasetPrototype> ForceSayStringDataset = "ForceSayStringDataset";
/// <summary>
/// The amount of total damage between <see cref="ValidDamageGroups"/> that needs to be taken before
--- /dev/null
+using Content.Shared.Alert;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Serialization;
+
+namespace Content.Shared.Mobs.Events;
+
+/// <summary>
+/// Event for allowing the interrupting and change of the mob threshold severity alert
+/// </summary>
+[Serializable, NetSerializable]
+public sealed class BeforeAlertSeverityCheckEvent(ProtoId<AlertPrototype> currentAlert, short severity) : EntityEventArgs
+{
+ public bool CancelUpdate = false;
+ public ProtoId<AlertPrototype> CurrentAlert = currentAlert;
+ public short Severity = severity;
+}
using Content.Shared.Damage;
using Content.Shared.FixedPoint;
using Content.Shared.Mobs.Components;
+using Content.Shared.Mobs.Events;
using Robust.Shared.GameStates;
namespace Content.Shared.Mobs.Systems;
if (alertPrototype.SupportsSeverity)
{
var severity = _alerts.GetMinSeverity(currentAlert);
+
+ var ev = new BeforeAlertSeverityCheckEvent(currentAlert, severity);
+ RaiseLocalEvent(target, ev);
+
+ if (ev.CancelUpdate)
+ {
+ _alerts.ShowAlert(target, ev.CurrentAlert, ev.Severity);
+ return;
+ }
+
if (TryGetNextState(target, currentMobState, out var nextState, threshold) &&
TryGetPercentageForState(target, nextState.Value, damageable.TotalDamage, out var percentage))
{
--- /dev/null
+using Content.Shared.Dataset;
+using Robust.Shared.GameStates;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.Traits.Assorted;
+
+[RegisterComponent, NetworkedComponent]
+public sealed partial class PainNumbnessComponent : Component
+{
+ /// <summary>
+ /// The fluent string prefix to use when picking a random suffix
+ /// This is only active for those who have the pain numbness component
+ /// </summary>
+ [DataField]
+ public ProtoId<LocalizedDatasetPrototype> ForceSayNumbDataset = "ForceSayNumbDataset";
+}
--- /dev/null
+using Content.Shared.Damage.Events;
+using Content.Shared.Mobs.Components;
+using Content.Shared.Mobs.Events;
+using Content.Shared.Mobs.Systems;
+
+namespace Content.Shared.Traits.Assorted;
+
+public sealed class PainNumbnessSystem : EntitySystem
+{
+ [Dependency] private readonly MobThresholdSystem _mobThresholdSystem = default!;
+
+ public override void Initialize()
+ {
+ SubscribeLocalEvent<PainNumbnessComponent, ComponentInit>(OnComponentInit);
+ SubscribeLocalEvent<PainNumbnessComponent, ComponentRemove>(OnComponentRemove);
+ SubscribeLocalEvent<PainNumbnessComponent, BeforeForceSayEvent>(OnChangeForceSay);
+ SubscribeLocalEvent<PainNumbnessComponent, BeforeAlertSeverityCheckEvent>(OnAlertSeverityCheck);
+ }
+
+ private void OnComponentRemove(EntityUid uid, PainNumbnessComponent component, ComponentRemove args)
+ {
+ if (!HasComp<MobThresholdsComponent>(uid))
+ return;
+
+ _mobThresholdSystem.VerifyThresholds(uid);
+ }
+
+ private void OnComponentInit(EntityUid uid, PainNumbnessComponent component, ComponentInit args)
+ {
+ if (!HasComp<MobThresholdsComponent>(uid))
+ return;
+
+ _mobThresholdSystem.VerifyThresholds(uid);
+ }
+
+ private void OnChangeForceSay(Entity<PainNumbnessComponent> ent, ref BeforeForceSayEvent args)
+ {
+ args.Prefix = ent.Comp.ForceSayNumbDataset;
+ }
+
+ private void OnAlertSeverityCheck(Entity<PainNumbnessComponent> ent, ref BeforeAlertSeverityCheckEvent args)
+ {
+ if (args.CurrentAlert == "HumanHealth")
+ args.CancelUpdate = true;
+ }
+}
damage-force-say-6 = URGH!
damage-force-say-7 = HRNK!
-damage-force-say-sleep = zzz...
+damage-force-say-sleep-1 = zzz...
+
+damage-force-say-numb-1 = oh-
+damage-force-say-numb-2 = ow-
+damage-force-say-numb-3 = oof-
+damage-force-say-numb-4 = ah-
+damage-force-say-numb-5 = ugh-
trait-spanish-name = Spanish accent
trait-spanish-desc = Hola señor, donde esta la biblioteca.
+
+trait-painnumbness-name = Numb
+trait-painnumbness-desc = You lack any sense of feeling pain, being unaware of how hurt you may be.
--- /dev/null
+- type: localizedDataset
+ id: ForceSayStringDataset
+ values:
+ prefix: damage-force-say-
+ count: 7
+
+- type: localizedDataset
+ id: ForceSaySleepDataset
+ values:
+ prefix: damage-force-say-sleep-
+ count: 1
+
+- type: localizedDataset
+ id: ForceSayNumbDataset
+ values:
+ prefix: damage-force-say-numb-
+ count: 5
maxSoundDistance: 7
sounds:
collection: Paracusia
+
+- type: trait
+ id: PainNumbness
+ name: trait-painnumbness-name
+ description: trait-painnumbness-desc
+ category: Disabilities
+ components:
+ - type: PainNumbness