diff --git a/Content.Client/UserInterface/Systems/DamageOverlays/DamageOverlayUiController.cs b/Content.Client/UserInterface/Systems/DamageOverlays/DamageOverlayUiController.cs index c10c33a990..9d9dd30911 100644 --- a/Content.Client/UserInterface/Systems/DamageOverlays/DamageOverlayUiController.cs +++ b/Content.Client/UserInterface/Systems/DamageOverlays/DamageOverlayUiController.cs @@ -3,6 +3,7 @@ using Content.Shared.FixedPoint; 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; @@ -94,7 +95,11 @@ public sealed class DamageOverlayUiController : UIController { case MobState.Alive: { - if (damageable.DamagePerGroup.TryGetValue("Brute", out var bruteDamage)) + if (EntityManager.HasComponent(entity)) + { + _overlay.BruteLevel = 0; + } + else if (damageable.DamagePerGroup.TryGetValue("Brute", out var bruteDamage)) { _overlay.BruteLevel = FixedPoint2.Min(1f, bruteDamage / critThreshold).Float(); } diff --git a/Content.Server/Damage/ForceSay/DamageForceSaySystem.cs b/Content.Server/Damage/ForceSay/DamageForceSaySystem.cs index bc61c5d141..8dfe665541 100644 --- a/Content.Server/Damage/ForceSay/DamageForceSaySystem.cs +++ b/Content.Server/Damage/ForceSay/DamageForceSaySystem.cs @@ -1,5 +1,6 @@ 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; @@ -47,7 +48,7 @@ public sealed class DamageForceSaySystem : EntitySystem } } - 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(uid, out var actor)) return; @@ -57,7 +58,13 @@ public sealed class DamageForceSaySystem : EntitySystem _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; @@ -80,7 +87,7 @@ public sealed class DamageForceSaySystem : EntitySystem if (!args.FellAsleep) return; - TryForceSay(uid, component, true, "damage-force-say-sleep"); + TryForceSay(uid, component); AllowNextSpeech(uid); } diff --git a/Content.Shared/Bed/Sleep/SleepingComponent.cs b/Content.Shared/Bed/Sleep/SleepingComponent.cs index cbea0a0516..dbabb8bb9f 100644 --- a/Content.Shared/Bed/Sleep/SleepingComponent.cs +++ b/Content.Shared/Bed/Sleep/SleepingComponent.cs @@ -1,6 +1,8 @@ +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; @@ -39,4 +41,11 @@ public sealed partial class SleepingComponent : Component { Params = AudioParams.Default.WithVariation(0.05f) }; + + /// + /// The fluent string prefix to use when picking a random suffix + /// This is only active for those who have the sleeping component + /// + [DataField] + public ProtoId ForceSaySleepDataset = "ForceSaySleepDataset"; } diff --git a/Content.Shared/Bed/Sleep/SleepingSystem.cs b/Content.Shared/Bed/Sleep/SleepingSystem.cs index 90e1fd38e8..d0c6c753de 100644 --- a/Content.Shared/Bed/Sleep/SleepingSystem.cs +++ b/Content.Shared/Bed/Sleep/SleepingSystem.cs @@ -1,6 +1,7 @@ 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; @@ -18,6 +19,7 @@ using Content.Shared.Sound.Components; 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; @@ -63,6 +65,8 @@ public sealed partial class SleepingSystem : EntitySystem SubscribeLocalEvent(OnInit); SubscribeLocalEvent(OnUnbuckleAttempt); SubscribeLocalEvent(OnEmoteAttempt); + + SubscribeLocalEvent(OnChangeForceSay, after: new []{typeof(PainNumbnessSystem)}); } private void OnUnbuckleAttempt(Entity ent, ref UnbuckleAttemptEvent args) @@ -317,6 +321,11 @@ public sealed partial class SleepingSystem : EntitySystem { args.Cancel(); } + + private void OnChangeForceSay(Entity ent, ref BeforeForceSayEvent args) + { + args.Prefix = ent.Comp.ForceSaySleepDataset; + } } diff --git a/Content.Shared/Damage/Events/BeforeForceSayEvent.cs b/Content.Shared/Damage/Events/BeforeForceSayEvent.cs new file mode 100644 index 0000000000..9e35f6ce73 --- /dev/null +++ b/Content.Shared/Damage/Events/BeforeForceSayEvent.cs @@ -0,0 +1,14 @@ +using Content.Shared.Dataset; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization; + +namespace Content.Shared.Damage.Events; + +/// +/// Event for interrupting and changing the prefix for when an entity is being forced to say something +/// +[Serializable, NetSerializable] +public sealed class BeforeForceSayEvent(ProtoId prefixDataset) : EntityEventArgs +{ + public ProtoId Prefix = prefixDataset; +} diff --git a/Content.Shared/Damage/ForceSay/DamageForceSayComponent.cs b/Content.Shared/Damage/ForceSay/DamageForceSayComponent.cs index 163cc7cbf4..e184f4beb9 100644 --- a/Content.Shared/Damage/ForceSay/DamageForceSayComponent.cs +++ b/Content.Shared/Damage/ForceSay/DamageForceSayComponent.cs @@ -1,8 +1,8 @@ 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; @@ -30,14 +30,7 @@ public sealed partial class DamageForceSayComponent : Component /// The fluent string prefix to use when picking a random suffix /// [DataField] - public string ForceSayStringPrefix = "damage-force-say-"; - - /// - /// The number of suffixes that exist for use with . - /// i.e. (prefix)-1 through (prefix)-(count) - /// - [DataField] - public int ForceSayStringCount = 7; + public ProtoId ForceSayStringDataset = "ForceSayStringDataset"; /// /// The amount of total damage between that needs to be taken before diff --git a/Content.Shared/Mobs/Events/BeforeAlertSeverityCheckEvent.cs b/Content.Shared/Mobs/Events/BeforeAlertSeverityCheckEvent.cs new file mode 100644 index 0000000000..e729314d39 --- /dev/null +++ b/Content.Shared/Mobs/Events/BeforeAlertSeverityCheckEvent.cs @@ -0,0 +1,16 @@ +using Content.Shared.Alert; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization; + +namespace Content.Shared.Mobs.Events; + +/// +/// Event for allowing the interrupting and change of the mob threshold severity alert +/// +[Serializable, NetSerializable] +public sealed class BeforeAlertSeverityCheckEvent(ProtoId currentAlert, short severity) : EntityEventArgs +{ + public bool CancelUpdate = false; + public ProtoId CurrentAlert = currentAlert; + public short Severity = severity; +} diff --git a/Content.Shared/Mobs/Systems/MobThresholdSystem.cs b/Content.Shared/Mobs/Systems/MobThresholdSystem.cs index eeaecc24d8..a059c18dd8 100644 --- a/Content.Shared/Mobs/Systems/MobThresholdSystem.cs +++ b/Content.Shared/Mobs/Systems/MobThresholdSystem.cs @@ -4,6 +4,7 @@ using Content.Shared.Alert; 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; @@ -391,6 +392,16 @@ public sealed class MobThresholdSystem : EntitySystem 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)) { diff --git a/Content.Shared/Traits/Assorted/PainNumbnessComponent.cs b/Content.Shared/Traits/Assorted/PainNumbnessComponent.cs new file mode 100644 index 0000000000..9ae72c6286 --- /dev/null +++ b/Content.Shared/Traits/Assorted/PainNumbnessComponent.cs @@ -0,0 +1,16 @@ +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 +{ + /// + /// The fluent string prefix to use when picking a random suffix + /// This is only active for those who have the pain numbness component + /// + [DataField] + public ProtoId ForceSayNumbDataset = "ForceSayNumbDataset"; +} diff --git a/Content.Shared/Traits/Assorted/PainNumbnessSystem.cs b/Content.Shared/Traits/Assorted/PainNumbnessSystem.cs new file mode 100644 index 0000000000..3ded13300d --- /dev/null +++ b/Content.Shared/Traits/Assorted/PainNumbnessSystem.cs @@ -0,0 +1,46 @@ +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(OnComponentInit); + SubscribeLocalEvent(OnComponentRemove); + SubscribeLocalEvent(OnChangeForceSay); + SubscribeLocalEvent(OnAlertSeverityCheck); + } + + private void OnComponentRemove(EntityUid uid, PainNumbnessComponent component, ComponentRemove args) + { + if (!HasComp(uid)) + return; + + _mobThresholdSystem.VerifyThresholds(uid); + } + + private void OnComponentInit(EntityUid uid, PainNumbnessComponent component, ComponentInit args) + { + if (!HasComp(uid)) + return; + + _mobThresholdSystem.VerifyThresholds(uid); + } + + private void OnChangeForceSay(Entity ent, ref BeforeForceSayEvent args) + { + args.Prefix = ent.Comp.ForceSayNumbDataset; + } + + private void OnAlertSeverityCheck(Entity ent, ref BeforeAlertSeverityCheckEvent args) + { + if (args.CurrentAlert == "HumanHealth") + args.CancelUpdate = true; + } +} diff --git a/Resources/Locale/en-US/damage/damage-force-say.ftl b/Resources/Locale/en-US/damage/damage-force-say.ftl index a436035114..83934a181e 100644 --- a/Resources/Locale/en-US/damage/damage-force-say.ftl +++ b/Resources/Locale/en-US/damage/damage-force-say.ftl @@ -9,4 +9,10 @@ damage-force-say-5 = OW! 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- diff --git a/Resources/Locale/en-US/traits/traits.ftl b/Resources/Locale/en-US/traits/traits.ftl index 7f4dcfe2ec..f4e5736db5 100644 --- a/Resources/Locale/en-US/traits/traits.ftl +++ b/Resources/Locale/en-US/traits/traits.ftl @@ -59,3 +59,6 @@ trait-french-desc = Your accent seems to have a certain «je ne sais quoi». 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. diff --git a/Resources/Prototypes/Datasets/damage_force_say.yml b/Resources/Prototypes/Datasets/damage_force_say.yml new file mode 100644 index 0000000000..a3d2c28f56 --- /dev/null +++ b/Resources/Prototypes/Datasets/damage_force_say.yml @@ -0,0 +1,17 @@ +- 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 diff --git a/Resources/Prototypes/Traits/disabilities.yml b/Resources/Prototypes/Traits/disabilities.yml index c562c2fec0..b7b3ba1ddc 100644 --- a/Resources/Prototypes/Traits/disabilities.yml +++ b/Resources/Prototypes/Traits/disabilities.yml @@ -64,3 +64,11 @@ maxSoundDistance: 7 sounds: collection: Paracusia + +- type: trait + id: PainNumbness + name: trait-painnumbness-name + description: trait-painnumbness-desc + category: Disabilities + components: + - type: PainNumbness