mirror of
https://github.com/space-syndicate/space-station-14.git
synced 2026-02-14 23:14:45 +01:00
Add status effect support to Traits, change PainNumbness to be a status effect (#41646)
* Initial commit * Review comments * Jobify * Prototype(effect)
This commit is contained in:
@@ -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.StatusEffectNew;
|
||||
using Content.Shared.Traits.Assorted;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.Graphics;
|
||||
@@ -20,6 +21,7 @@ public sealed class DamageOverlayUiController : UIController
|
||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||
|
||||
[UISystemDependency] private readonly MobThresholdSystem _mobThresholdSystem = default!;
|
||||
[UISystemDependency] private readonly StatusEffectsSystem _statusEffects = default!;
|
||||
private Overlays.DamageOverlay _overlay = default!;
|
||||
|
||||
public override void Initialize()
|
||||
@@ -98,7 +100,7 @@ public sealed class DamageOverlayUiController : UIController
|
||||
FixedPoint2 painLevel = 0;
|
||||
_overlay.PainLevel = 0;
|
||||
|
||||
if (!EntityManager.HasComponent<PainNumbnessComponent>(entity))
|
||||
if (!_statusEffects.TryEffectsWithComp<PainNumbnessStatusEffectComponent>(entity, out _))
|
||||
{
|
||||
foreach (var painDamageType in damageable.PainDamageGroups)
|
||||
{
|
||||
|
||||
@@ -9,6 +9,7 @@ using Content.Shared.Implants;
|
||||
using Content.Shared.Implants.Components;
|
||||
using Content.Shared.NameModifier.EntitySystems;
|
||||
using Content.Shared.StatusEffect;
|
||||
using Content.Shared.StatusEffectNew.Components;
|
||||
using Content.Shared.Storage;
|
||||
using Content.Shared.Storage.EntitySystems;
|
||||
using Content.Shared.Whitelist;
|
||||
@@ -36,6 +37,7 @@ public sealed partial class CloningSystem : SharedCloningSystem
|
||||
[Dependency] private readonly SharedStorageSystem _storage = default!;
|
||||
[Dependency] private readonly SharedSubdermalImplantSystem _subdermalImplant = default!;
|
||||
[Dependency] private readonly NameModifierSystem _nameMod = default!;
|
||||
[Dependency] private readonly Shared.StatusEffectNew.StatusEffectsSystem _statusEffects = default!; //TODO: This system has to support both the old and new status effect systems, until the old is able to be fully removed.
|
||||
|
||||
/// <summary>
|
||||
/// Spawns a clone of the given humanoid mob at the specified location or in nullspace.
|
||||
@@ -75,6 +77,10 @@ public sealed partial class CloningSystem : SharedCloningSystem
|
||||
if (settings.CopyImplants)
|
||||
CopyImplants(original, clone.Value, settings.CopyInternalStorage, settings.Whitelist, settings.Blacklist);
|
||||
|
||||
// Copy permanent status effects
|
||||
if (settings.CopyStatusEffects)
|
||||
CopyStatusEffects(original, clone.Value);
|
||||
|
||||
var originalName = _nameMod.GetBaseName(original);
|
||||
|
||||
// Set the clone's name. The raised events will also adjust their PDA and ID card names.
|
||||
@@ -267,4 +273,33 @@ public sealed partial class CloningSystem : SharedCloningSystem
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scans all permanent status effects applied to the original entity and transfers them to the clone.
|
||||
/// </summary>
|
||||
public void CopyStatusEffects(Entity<StatusEffectContainerComponent?> original, Entity<StatusEffectContainerComponent?> target)
|
||||
{
|
||||
if (!Resolve(original, ref original.Comp, false))
|
||||
return;
|
||||
|
||||
if (original.Comp.ActiveStatusEffects is null)
|
||||
return;
|
||||
|
||||
foreach (var effect in original.Comp.ActiveStatusEffects.ContainedEntities)
|
||||
{
|
||||
if (!TryComp<StatusEffectComponent>(effect, out var effectComp))
|
||||
continue;
|
||||
|
||||
//We are not interested in temporary effects, only permanent ones.
|
||||
if (effectComp.EndEffectTime is not null)
|
||||
continue;
|
||||
|
||||
var effectProto = Prototype(effect);
|
||||
|
||||
if (effectProto is null)
|
||||
continue;
|
||||
|
||||
_statusEffects.TrySetStatusEffectDuration(target, effectProto);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
27
Content.Server/Jobs/ApplyStatusEffectSpecial.cs
Normal file
27
Content.Server/Jobs/ApplyStatusEffectSpecial.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using Content.Shared.Roles;
|
||||
using Content.Shared.StatusEffectNew;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.Jobs;
|
||||
|
||||
/// <summary>
|
||||
/// Adds permanent status effects to the entity.
|
||||
/// TODO: Move this, and other JobSpecials, from Server to Shared.
|
||||
/// </summary>
|
||||
[UsedImplicitly]
|
||||
public sealed partial class ApplyStatusEffectSpecial : JobSpecial
|
||||
{
|
||||
[DataField(required: true)]
|
||||
public HashSet<EntProtoId> StatusEffects { get; private set; } = new();
|
||||
|
||||
public override void AfterEquip(EntityUid mob)
|
||||
{
|
||||
var entMan = IoCManager.Resolve<IEntityManager>();
|
||||
var statusSystem = entMan.System<StatusEffectsSystem>();
|
||||
foreach (var effect in StatusEffects)
|
||||
{
|
||||
statusSystem.TrySetStatusEffectDuration(mob, effect);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ using Content.Shared.GameTicking;
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.Roles;
|
||||
using Content.Shared.StatusEffectNew;
|
||||
using Content.Shared.Traits;
|
||||
using Content.Shared.Whitelist;
|
||||
using Robust.Shared.Prototypes;
|
||||
@@ -13,6 +14,7 @@ public sealed class TraitSystem : EntitySystem
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
[Dependency] private readonly SharedHandsSystem _sharedHandsSystem = default!;
|
||||
[Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!;
|
||||
[Dependency] private readonly StatusEffectsSystem _statusEffects = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -45,7 +47,14 @@ public sealed class TraitSystem : EntitySystem
|
||||
continue;
|
||||
|
||||
// Add all components required by the prototype
|
||||
EntityManager.AddComponents(args.Mob, traitPrototype.Components, false);
|
||||
if (traitPrototype.Components.Count > 0)
|
||||
EntityManager.AddComponents(args.Mob, traitPrototype.Components, false);
|
||||
|
||||
// Add all JobSpecials required by the prototype
|
||||
foreach (var special in traitPrototype.Specials)
|
||||
{
|
||||
special.AfterEquip(args.Mob);
|
||||
}
|
||||
|
||||
// Add item required by the trait
|
||||
if (traitPrototype.TraitGear == null)
|
||||
|
||||
@@ -50,6 +50,12 @@ public sealed partial class CloningSettingsPrototype : IPrototype, IInheritingPr
|
||||
[DataField]
|
||||
public bool CopyImplants = true;
|
||||
|
||||
/// <summary>
|
||||
/// Should infinite status effects applied to an entity be copied or not?
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public bool CopyStatusEffects = true;
|
||||
|
||||
/// <summary>
|
||||
/// Whitelist for the equipment allowed to be copied.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
namespace Content.Shared.Roles
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides special hooks for when jobs get spawned in/equipped.
|
||||
/// Provides special hooks for when jobs get spawned in/equipped.
|
||||
/// TODO: This is being/should be utilized by more than jobs, and is really just a way to assign components/implants/status effects upon spawning. Rename this class and its derivatives in the future!
|
||||
/// TODO: Move derivatives from Server to Shared, probably.
|
||||
/// </summary>
|
||||
[ImplicitDataDefinitionForInheritors]
|
||||
public abstract partial class JobSpecial
|
||||
|
||||
@@ -353,6 +353,7 @@ public sealed partial class StatusEffectsSystem
|
||||
/// <summary>
|
||||
/// Returns all status effects that have the specified component.
|
||||
/// </summary>
|
||||
/// <returns>Returns true if any entity with the specified component is found.</returns>
|
||||
public bool TryEffectsWithComp<T>(EntityUid? target, [NotNullWhen(true)] out HashSet<Entity<T, StatusEffectComponent>>? effects) where T : IComponent
|
||||
{
|
||||
effects = null;
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
using Content.Shared.Damage.Events;
|
||||
using Content.Shared.Mobs.Events;
|
||||
using Content.Shared.Movement.Events;
|
||||
using Content.Shared.Movement.Systems;
|
||||
using Content.Shared.Rejuvenate;
|
||||
@@ -25,6 +27,9 @@ public sealed partial class StatusEffectsSystem
|
||||
SubscribeLocalEvent<StatusEffectContainerComponent, StandUpAttemptEvent>(RefRelayStatusEffectEvent);
|
||||
SubscribeLocalEvent<StatusEffectContainerComponent, StunEndAttemptEvent>(RefRelayStatusEffectEvent);
|
||||
|
||||
SubscribeLocalEvent<StatusEffectContainerComponent, BeforeForceSayEvent>(RelayStatusEffectEvent);
|
||||
SubscribeLocalEvent<StatusEffectContainerComponent, BeforeAlertSeverityCheckEvent>(RelayStatusEffectEvent);
|
||||
|
||||
SubscribeLocalEvent<StatusEffectContainerComponent, AccentGetEvent>(RelayStatusEffectEvent);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
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";
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using Content.Shared.Dataset;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared.Traits.Assorted;
|
||||
|
||||
/// <summary>
|
||||
/// Hides the damage overlay and displays the health alert for the client controlling the entity as full.
|
||||
/// Has to be applied as a status effect.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class PainNumbnessStatusEffectComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// The fluent string prefix to use when picking a random suffix upon taking damage.
|
||||
/// This is only active for those who have the pain numbness status effect. Set to null to prevent changing.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public ProtoId<LocalizedDatasetPrototype>? ForceSayNumbDataset = "ForceSayNumbDataset";
|
||||
}
|
||||
@@ -2,6 +2,7 @@ using Content.Shared.Damage.Events;
|
||||
using Content.Shared.Mobs.Components;
|
||||
using Content.Shared.Mobs.Events;
|
||||
using Content.Shared.Mobs.Systems;
|
||||
using Content.Shared.StatusEffectNew;
|
||||
|
||||
namespace Content.Shared.Traits.Assorted;
|
||||
|
||||
@@ -11,36 +12,37 @@ public sealed class PainNumbnessSystem : EntitySystem
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
SubscribeLocalEvent<PainNumbnessComponent, ComponentInit>(OnComponentInit);
|
||||
SubscribeLocalEvent<PainNumbnessComponent, ComponentRemove>(OnComponentRemove);
|
||||
SubscribeLocalEvent<PainNumbnessComponent, BeforeForceSayEvent>(OnChangeForceSay);
|
||||
SubscribeLocalEvent<PainNumbnessComponent, BeforeAlertSeverityCheckEvent>(OnAlertSeverityCheck);
|
||||
SubscribeLocalEvent<PainNumbnessStatusEffectComponent, StatusEffectAppliedEvent>(OnEffectApplied);
|
||||
SubscribeLocalEvent<PainNumbnessStatusEffectComponent, StatusEffectRemovedEvent>(OnEffectRemoved);
|
||||
SubscribeLocalEvent<PainNumbnessStatusEffectComponent, StatusEffectRelayedEvent<BeforeForceSayEvent>>(OnChangeForceSay);
|
||||
SubscribeLocalEvent<PainNumbnessStatusEffectComponent, StatusEffectRelayedEvent<BeforeAlertSeverityCheckEvent>>(OnAlertSeverityCheck);
|
||||
}
|
||||
|
||||
private void OnComponentRemove(EntityUid uid, PainNumbnessComponent component, ComponentRemove args)
|
||||
private void OnEffectApplied(Entity<PainNumbnessStatusEffectComponent> ent, ref StatusEffectAppliedEvent args)
|
||||
{
|
||||
if (!HasComp<MobThresholdsComponent>(uid))
|
||||
if (!HasComp<MobThresholdsComponent>(args.Target))
|
||||
return;
|
||||
|
||||
_mobThresholdSystem.VerifyThresholds(uid);
|
||||
_mobThresholdSystem.VerifyThresholds(args.Target);
|
||||
}
|
||||
|
||||
private void OnComponentInit(EntityUid uid, PainNumbnessComponent component, ComponentInit args)
|
||||
private void OnEffectRemoved(Entity<PainNumbnessStatusEffectComponent> ent, ref StatusEffectRemovedEvent args)
|
||||
{
|
||||
if (!HasComp<MobThresholdsComponent>(uid))
|
||||
if (!HasComp<MobThresholdsComponent>(args.Target))
|
||||
return;
|
||||
|
||||
_mobThresholdSystem.VerifyThresholds(uid);
|
||||
_mobThresholdSystem.VerifyThresholds(args.Target);
|
||||
}
|
||||
|
||||
private void OnChangeForceSay(Entity<PainNumbnessComponent> ent, ref BeforeForceSayEvent args)
|
||||
private void OnChangeForceSay(Entity<PainNumbnessStatusEffectComponent> ent, ref StatusEffectRelayedEvent<BeforeForceSayEvent> args)
|
||||
{
|
||||
args.Prefix = ent.Comp.ForceSayNumbDataset;
|
||||
if (ent.Comp.ForceSayNumbDataset != null)
|
||||
args.Args.Prefix = ent.Comp.ForceSayNumbDataset.Value;
|
||||
}
|
||||
|
||||
private void OnAlertSeverityCheck(Entity<PainNumbnessComponent> ent, ref BeforeAlertSeverityCheckEvent args)
|
||||
private void OnAlertSeverityCheck(Entity<PainNumbnessStatusEffectComponent> ent, ref StatusEffectRelayedEvent<BeforeAlertSeverityCheckEvent> args)
|
||||
{
|
||||
if (args.CurrentAlert == "HumanHealth")
|
||||
args.CancelUpdate = true;
|
||||
if (args.Args.CurrentAlert == "HumanHealth")
|
||||
args.Args.CancelUpdate = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Content.Shared.Roles;
|
||||
using Content.Shared.Whitelist;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
@@ -39,9 +40,17 @@ public sealed partial class TraitPrototype : IPrototype
|
||||
|
||||
/// <summary>
|
||||
/// The components that get added to the player, when they pick this trait.
|
||||
/// NOTE: When implementing a new trait, it's preferable to add it as a status effect instead if possible.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public ComponentRegistry Components { get; private set; } = default!;
|
||||
[Obsolete("Use JobSpecial instead.")]
|
||||
public ComponentRegistry Components { get; private set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Special effects applied to the player who takes this Trait.
|
||||
/// </summary>
|
||||
[DataField(serverOnly: true)]
|
||||
public List<JobSpecial> Specials { get; private set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Gear that is given to the player, when they pick this trait.
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
- Muted
|
||||
- Narcolepsy
|
||||
- Pacified
|
||||
- PainNumbness
|
||||
- Paracusia
|
||||
- PermanentBlindness
|
||||
- Snoring
|
||||
|
||||
@@ -3,16 +3,27 @@
|
||||
id: BloodstreamStatusEffectBase
|
||||
abstract: true
|
||||
components:
|
||||
- type: StatusEffect
|
||||
whitelist:
|
||||
components:
|
||||
- Bloodstream
|
||||
- type: StatusEffect
|
||||
whitelist:
|
||||
components:
|
||||
- Bloodstream
|
||||
|
||||
- type: entity
|
||||
parent: [ BloodstreamStatusEffectBase ]
|
||||
id: StatusEffectBloodloss
|
||||
name: bloodloss
|
||||
components:
|
||||
- type: StutteringAccent
|
||||
- type: DrunkStatusEffect
|
||||
- type: RejuvenateRemovedStatusEffect
|
||||
- type: StutteringAccent
|
||||
- type: DrunkStatusEffect
|
||||
- type: RejuvenateRemovedStatusEffect
|
||||
|
||||
- type: entity
|
||||
parent: MobStatusEffectBase
|
||||
id: PainNumbnessTraitStatusEffect
|
||||
components:
|
||||
- type: StatusEffect
|
||||
whitelist:
|
||||
components:
|
||||
- MobState
|
||||
- MobThresholds
|
||||
- type: PainNumbnessStatusEffect
|
||||
|
||||
@@ -83,8 +83,10 @@
|
||||
name: trait-painnumbness-name
|
||||
description: trait-painnumbness-desc
|
||||
category: Disabilities
|
||||
components:
|
||||
- type: PainNumbness
|
||||
specials:
|
||||
- !type:ApplyStatusEffectSpecial
|
||||
statusEffects:
|
||||
- PainNumbnessTraitStatusEffect
|
||||
|
||||
- type: trait
|
||||
id: Hemophilia
|
||||
|
||||
Reference in New Issue
Block a user