[NEW STATUS SYSTEM] Drunkenness, Stuttering, Slurred Speech, and Bloodloss (#38678)

* The only commit that matters

* I had to stop playing with my cat to push this change

* Yaml removal

* Proper drunk status effect and remove shitcode

* Review changes

* whoops

* Whoops x2

* Update master fix merge conflicts

* Fix merge conflicts

* Dunk Component kill

* MORE RELAYS

* Holy fucking breaking changes

* Ough

* 46 file diff

* Fix bad commits

* Erm what the test fail?

* Fix those last two

* Merge conflicts

* Me when I fix the merge conflicts

---------

Co-authored-by: Princess Cheeseballs <66055347+Pronana@users.noreply.github.com>
This commit is contained in:
Princess Cheeseballs
2025-08-18 13:26:29 -07:00
committed by GitHub
parent d737e39a98
commit 6b73d320b9
27 changed files with 235 additions and 176 deletions

View File

@@ -1,5 +1,6 @@
using Content.Shared.Drunk; using Content.Shared.Drunk;
using Content.Shared.StatusEffect; using Content.Shared.StatusEffect;
using Content.Shared.StatusEffectNew;
using Robust.Client.Graphics; using Robust.Client.Graphics;
using Robust.Client.Player; using Robust.Client.Player;
using Robust.Shared.Enums; using Robust.Shared.Enums;
@@ -43,19 +44,21 @@ public sealed class DrunkOverlay : Overlay
if (playerEntity == null) if (playerEntity == null)
return; return;
if (!_entityManager.HasComponent<DrunkComponent>(playerEntity) var statusSys = _sysMan.GetEntitySystem<Shared.StatusEffectNew.StatusEffectsSystem>();
|| !_entityManager.TryGetComponent<StatusEffectsComponent>(playerEntity, out var status)) if (!statusSys.TryGetMaxTime<DrunkStatusEffectComponent>(playerEntity.Value, out var status))
return; return;
var statusSys = _sysMan.GetEntitySystem<StatusEffectsSystem>(); var time = status.Item2;
if (!statusSys.TryGetTime(playerEntity.Value, SharedDrunkSystem.DrunkKey, out var time, status))
return;
var power = SharedDrunkSystem.MagicNumber;
if (time != null)
{
var curTime = _timing.CurTime; var curTime = _timing.CurTime;
var timeLeft = (float) (time.Value.Item2 - curTime).TotalSeconds; power = (float) (time - curTime).Value.TotalSeconds;
}
CurrentBoozePower += 8f * (power * 0.5f - CurrentBoozePower) * args.DeltaSeconds / (power+1);
CurrentBoozePower += 8f * (0.5f*timeLeft - CurrentBoozePower) * args.DeltaSeconds / (timeLeft+1);
} }
protected override bool BeforeDraw(in OverlayDrawArgs args) protected override bool BeforeDraw(in OverlayDrawArgs args)

View File

@@ -1,4 +1,5 @@
using Content.Shared.Drunk; using Content.Shared.Drunk;
using Content.Shared.StatusEffectNew;
using Robust.Client.Graphics; using Robust.Client.Graphics;
using Robust.Client.Player; using Robust.Client.Player;
using Robust.Shared.Player; using Robust.Shared.Player;
@@ -16,38 +17,41 @@ public sealed class DrunkSystem : SharedDrunkSystem
{ {
base.Initialize(); base.Initialize();
SubscribeLocalEvent<DrunkComponent, ComponentInit>(OnDrunkInit); SubscribeLocalEvent<DrunkStatusEffectComponent, StatusEffectAppliedEvent>(OnStatusApplied);
SubscribeLocalEvent<DrunkComponent, ComponentShutdown>(OnDrunkShutdown); SubscribeLocalEvent<DrunkStatusEffectComponent, StatusEffectRemovedEvent>(OnStatusRemoved);
SubscribeLocalEvent<DrunkComponent, LocalPlayerAttachedEvent>(OnPlayerAttached); SubscribeLocalEvent<DrunkStatusEffectComponent, StatusEffectRelayedEvent<LocalPlayerAttachedEvent>>(OnPlayerAttached);
SubscribeLocalEvent<DrunkComponent, LocalPlayerDetachedEvent>(OnPlayerDetached); SubscribeLocalEvent<DrunkStatusEffectComponent, StatusEffectRelayedEvent<LocalPlayerDetachedEvent>>(OnPlayerDetached);
_overlay = new(); _overlay = new();
} }
private void OnPlayerAttached(EntityUid uid, DrunkComponent component, LocalPlayerAttachedEvent args) private void OnStatusApplied(Entity<DrunkStatusEffectComponent> entity, ref StatusEffectAppliedEvent args)
{ {
if (!_overlayMan.HasOverlay<DrunkOverlay>())
_overlayMan.AddOverlay(_overlay); _overlayMan.AddOverlay(_overlay);
} }
private void OnPlayerDetached(EntityUid uid, DrunkComponent component, LocalPlayerDetachedEvent args) private void OnStatusRemoved(Entity<DrunkStatusEffectComponent> entity, ref StatusEffectRemovedEvent args)
{ {
if (Status.HasEffectComp<DrunkStatusEffectComponent>(args.Target))
return;
if (_player.LocalEntity != args.Target)
return;
_overlay.CurrentBoozePower = 0; _overlay.CurrentBoozePower = 0;
_overlayMan.RemoveOverlay(_overlay); _overlayMan.RemoveOverlay(_overlay);
} }
private void OnDrunkInit(EntityUid uid, DrunkComponent component, ComponentInit args) private void OnPlayerAttached(Entity<DrunkStatusEffectComponent> entity, ref StatusEffectRelayedEvent<LocalPlayerAttachedEvent> args)
{ {
if (_player.LocalEntity == uid)
_overlayMan.AddOverlay(_overlay); _overlayMan.AddOverlay(_overlay);
} }
private void OnDrunkShutdown(EntityUid uid, DrunkComponent component, ComponentShutdown args) private void OnPlayerDetached(Entity<DrunkStatusEffectComponent> entity, ref StatusEffectRelayedEvent<LocalPlayerDetachedEvent> args)
{
if (_player.LocalEntity == uid)
{ {
_overlay.CurrentBoozePower = 0; _overlay.CurrentBoozePower = 0;
_overlayMan.RemoveOverlay(_overlay); _overlayMan.RemoveOverlay(_overlay);
} }
} }
}

View File

@@ -418,7 +418,7 @@ public sealed class ElectrocutionSystem : SharedElectrocutionSystem
} }
} }
_stuttering.DoStutter(uid, time * StutteringTimeMultiplier, refresh, statusEffects); _stuttering.DoStutter(uid, time * StutteringTimeMultiplier, refresh);
_jittering.DoJitter(uid, time * JitterTimeMultiplier, refresh, JitterAmplitude, JitterFrequency, true, statusEffects); _jittering.DoJitter(uid, time * JitterTimeMultiplier, refresh, JitterAmplitude, JitterFrequency, true, statusEffects);
_popup.PopupEntity(Loc.GetString("electrocuted-component-mob-shocked-popup-player"), uid, uid); _popup.PopupEntity(Loc.GetString("electrocuted-component-mob-shocked-popup-player"), uid, uid);

View File

@@ -6,29 +6,25 @@ namespace Content.Server.Speech.Components
/// <summary> /// <summary>
/// Percentage chance that a stutter will occur if it matches. /// Percentage chance that a stutter will occur if it matches.
/// </summary> /// </summary>
[DataField("matchRandomProb")] [DataField]
[ViewVariables(VVAccess.ReadWrite)]
public float MatchRandomProb = 0.8f; public float MatchRandomProb = 0.8f;
/// <summary> /// <summary>
/// Percentage chance that a stutter occurs f-f-f-f-four times. /// Percentage chance that a stutter occurs f-f-f-f-four times.
/// </summary> /// </summary>
[DataField("fourRandomProb")] [DataField]
[ViewVariables(VVAccess.ReadWrite)]
public float FourRandomProb = 0.1f; public float FourRandomProb = 0.1f;
/// <summary> /// <summary>
/// Percentage chance that a stutter occurs t-t-t-three times. /// Percentage chance that a stutter occurs t-t-t-three times.
/// </summary> /// </summary>
[DataField("threeRandomProb")] [DataField]
[ViewVariables(VVAccess.ReadWrite)]
public float ThreeRandomProb = 0.2f; public float ThreeRandomProb = 0.2f;
/// <summary> /// <summary>
/// Percentage chance that a stutter cut off. /// Percentage chance that a stutter cut off.
/// </summary> /// </summary>
[DataField("cutRandomProb")] [DataField]
[ViewVariables(VVAccess.ReadWrite)]
public float CutRandomProb = 0.05f; public float CutRandomProb = 0.05f;
} }
} }

View File

@@ -3,8 +3,7 @@ using Content.Server.Speech.Components;
using Content.Shared.Drunk; using Content.Shared.Drunk;
using Content.Shared.Speech; using Content.Shared.Speech;
using Content.Shared.Speech.EntitySystems; using Content.Shared.Speech.EntitySystems;
using Content.Shared.StatusEffect; using Content.Shared.StatusEffectNew;
using Robust.Shared.Prototypes;
using Robust.Shared.Random; using Robust.Shared.Random;
using Robust.Shared.Timing; using Robust.Shared.Timing;
@@ -12,26 +11,15 @@ namespace Content.Server.Speech.EntitySystems;
public sealed class SlurredSystem : SharedSlurredSystem public sealed class SlurredSystem : SharedSlurredSystem
{ {
[Dependency] private readonly StatusEffectsSystem _statusEffectsSystem = default!; [Dependency] private readonly StatusEffectsSystem _status = default!;
[Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly IGameTiming _timing = default!; [Dependency] private readonly IGameTiming _timing = default!;
private static readonly ProtoId<StatusEffectPrototype> SlurKey = "SlurredSpeech";
public override void Initialize() public override void Initialize()
{ {
SubscribeLocalEvent<SlurredAccentComponent, AccentGetEvent>(OnAccent); SubscribeLocalEvent<SlurredAccentComponent, AccentGetEvent>(OnAccent);
}
public override void DoSlur(EntityUid uid, TimeSpan time, StatusEffectsComponent? status = null) SubscribeLocalEvent<SlurredAccentComponent, StatusEffectRelayedEvent<AccentGetEvent>>(OnAccentRelayed);
{
if (!Resolve(uid, ref status, false))
return;
if (!_statusEffectsSystem.HasStatusEffect(uid, SlurKey, status))
_statusEffectsSystem.TryAddStatusEffect<SlurredAccentComponent>(uid, SlurKey, time, true, status);
else
_statusEffectsSystem.TryAddTime(uid, SlurKey, time, status);
} }
/// <summary> /// <summary>
@@ -39,15 +27,33 @@ public sealed class SlurredSystem : SharedSlurredSystem
/// </summary> /// </summary>
private float GetProbabilityScale(EntityUid uid) private float GetProbabilityScale(EntityUid uid)
{ {
if (!_statusEffectsSystem.TryGetTime(uid, SharedDrunkSystem.DrunkKey, out var time)) if (!_status.TryGetMaxTime<DrunkStatusEffectComponent>(uid, out var time))
return 0; return 0;
// This is a magic number. Why this value? No clue it was made 3 years before I refactored this.
var magic = SharedDrunkSystem.MagicNumber;
if (time.Item2 != null)
{
var curTime = _timing.CurTime; var curTime = _timing.CurTime;
var timeLeft = (float) (time.Value.Item2 - curTime).TotalSeconds; magic = (float) (time.Item2 - curTime).Value.TotalSeconds - 80f;
return Math.Clamp((timeLeft - 80) / 1100, 0f, 1f);
} }
private void OnAccent(EntityUid uid, SlurredAccentComponent component, AccentGetEvent args) return Math.Clamp(magic / SharedDrunkSystem.MagicNumber, 0f, 1f);
}
private void OnAccent(Entity<SlurredAccentComponent> entity, ref AccentGetEvent args)
{
GetAccent(entity, ref args);
}
private void OnAccentRelayed(Entity<SlurredAccentComponent> entity, ref StatusEffectRelayedEvent<AccentGetEvent> args)
{
var ev = args.Args;
GetAccent(args.Args.Entity, ref ev);
}
private void GetAccent(EntityUid uid, ref AccentGetEvent args)
{ {
var scale = GetProbabilityScale(uid); var scale = GetProbabilityScale(uid);
args.Message = Accentuate(args.Message, scale); args.Message = Accentuate(args.Message, scale);

View File

@@ -3,14 +3,13 @@ using System.Text.RegularExpressions;
using Content.Server.Speech.Components; using Content.Server.Speech.Components;
using Content.Shared.Speech; using Content.Shared.Speech;
using Content.Shared.Speech.EntitySystems; using Content.Shared.Speech.EntitySystems;
using Content.Shared.StatusEffect; using Content.Shared.StatusEffectNew;
using Robust.Shared.Random; using Robust.Shared.Random;
namespace Content.Server.Speech.EntitySystems namespace Content.Server.Speech.EntitySystems
{ {
public sealed class StutteringSystem : SharedStutteringSystem public sealed class StutteringSystem : SharedStutteringSystem
{ {
[Dependency] private readonly StatusEffectsSystem _statusEffectsSystem = default!;
[Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly IRobustRandom _random = default!;
// Regex of characters to stutter. // Regex of characters to stutter.
@@ -20,19 +19,36 @@ namespace Content.Server.Speech.EntitySystems
public override void Initialize() public override void Initialize()
{ {
SubscribeLocalEvent<StutteringAccentComponent, AccentGetEvent>(OnAccent); SubscribeLocalEvent<StutteringAccentComponent, AccentGetEvent>(OnAccent);
SubscribeLocalEvent<StutteringAccentComponent, StatusEffectRelayedEvent<AccentGetEvent>>(OnAccent);
} }
public override void DoStutter(EntityUid uid, TimeSpan time, bool refresh, StatusEffectsComponent? status = null) public override void DoStutter(EntityUid uid, TimeSpan time, bool refresh)
{ {
if (!Resolve(uid, ref status, false)) if (refresh)
return; Status.TryUpdateStatusEffectDuration(uid, Stuttering, time);
else
_statusEffectsSystem.TryAddStatusEffect<StutteringAccentComponent>(uid, StutterKey, time, refresh, status); Status.TryAddStatusEffectDuration(uid, Stuttering, time);
} }
private void OnAccent(EntityUid uid, StutteringAccentComponent component, AccentGetEvent args) public override void DoRemoveStutterTime(EntityUid uid, TimeSpan timeRemoved)
{ {
args.Message = Accentuate(args.Message, component); Status.TryAddTime(uid, Stuttering, -timeRemoved);
}
public override void DoRemoveStutter(EntityUid uid)
{
Status.TryRemoveStatusEffect(uid, Stuttering);
}
private void OnAccent(Entity<StutteringAccentComponent> entity, ref AccentGetEvent args)
{
args.Message = Accentuate(args.Message, entity.Comp);
}
private void OnAccent(Entity<StutteringAccentComponent> entity, ref StatusEffectRelayedEvent<AccentGetEvent> args)
{
args.Args.Message = Accentuate(args.Args.Message, entity.Comp);
} }
public string Accentuate(string message, StutteringAccentComponent component) public string Accentuate(string message, StutteringAccentComponent component)

View File

@@ -198,12 +198,6 @@ public sealed partial class BloodstreamComponent : Component
[ViewVariables] [ViewVariables]
public Entity<SolutionComponent>? TemporarySolution; public Entity<SolutionComponent>? TemporarySolution;
/// <summary>
/// Variable that stores the amount of status time added by having a low blood level.
/// </summary>
[DataField, AutoNetworkedField]
public TimeSpan StatusTime;
/// <summary> /// <summary>
/// Alert to show when bleeding. /// Alert to show when bleeding.
/// </summary> /// </summary>

View File

@@ -6,7 +6,6 @@ using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Chemistry.Reaction; using Content.Shared.Chemistry.Reaction;
using Content.Shared.Chemistry.Reagent; using Content.Shared.Chemistry.Reagent;
using Content.Shared.Damage; using Content.Shared.Damage;
using Content.Shared.Drunk;
using Content.Shared.EntityEffects.Effects; using Content.Shared.EntityEffects.Effects;
using Content.Shared.FixedPoint; using Content.Shared.FixedPoint;
using Content.Shared.Fluids; using Content.Shared.Fluids;
@@ -16,7 +15,7 @@ using Content.Shared.Mobs.Systems;
using Content.Shared.Popups; using Content.Shared.Popups;
using Content.Shared.Random.Helpers; using Content.Shared.Random.Helpers;
using Content.Shared.Rejuvenate; using Content.Shared.Rejuvenate;
using Content.Shared.Speech.EntitySystems; using Content.Shared.StatusEffectNew;
using Robust.Shared.Audio.Systems; using Robust.Shared.Audio.Systems;
using Robust.Shared.Containers; using Robust.Shared.Containers;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
@@ -27,17 +26,18 @@ namespace Content.Shared.Body.Systems;
public abstract class SharedBloodstreamSystem : EntitySystem public abstract class SharedBloodstreamSystem : EntitySystem
{ {
public static readonly EntProtoId Bloodloss = "StatusEffectBloodloss";
[Dependency] protected readonly SharedSolutionContainerSystem SolutionContainer = default!; [Dependency] protected readonly SharedSolutionContainerSystem SolutionContainer = default!;
[Dependency] private readonly IGameTiming _timing = default!; [Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!; [Dependency] private readonly SharedPopupSystem _popup = default!;
[Dependency] private readonly SharedPuddleSystem _puddle = default!; [Dependency] private readonly SharedPuddleSystem _puddle = default!;
[Dependency] private readonly StatusEffectsSystem _status = default!;
[Dependency] private readonly AlertsSystem _alertsSystem = default!; [Dependency] private readonly AlertsSystem _alertsSystem = default!;
[Dependency] private readonly MobStateSystem _mobStateSystem = default!; [Dependency] private readonly MobStateSystem _mobStateSystem = default!;
[Dependency] private readonly DamageableSystem _damageableSystem = default!; [Dependency] private readonly DamageableSystem _damageableSystem = default!;
[Dependency] private readonly SharedDrunkSystem _drunkSystem = default!;
[Dependency] private readonly SharedStutteringSystem _stutteringSystem = default!;
public override void Initialize() public override void Initialize()
{ {
@@ -100,15 +100,7 @@ public abstract class SharedBloodstreamSystem : EntitySystem
// Apply dizziness as a symptom of bloodloss. // Apply dizziness as a symptom of bloodloss.
// The effect is applied in a way that it will never be cleared without being healthy. // The effect is applied in a way that it will never be cleared without being healthy.
// Multiplying by 2 is arbitrary but works for this case, it just prevents the time from running out // Multiplying by 2 is arbitrary but works for this case, it just prevents the time from running out
_drunkSystem.TryApplyDrunkenness( _status.TrySetStatusEffectDuration(uid, Bloodloss);
uid,
(float)bloodstream.AdjustedUpdateInterval.TotalSeconds * 2,
applySlur: false);
_stutteringSystem.DoStutter(uid, bloodstream.AdjustedUpdateInterval * 2, refresh: false);
// storing the drunk and stutter time so we can remove it independently from other effects additions
bloodstream.StatusTime += bloodstream.AdjustedUpdateInterval * 2;
DirtyField(uid, bloodstream, nameof(BloodstreamComponent.StatusTime));
} }
else if (!_mobStateSystem.IsDead(uid)) else if (!_mobStateSystem.IsDead(uid))
{ {
@@ -118,12 +110,7 @@ public abstract class SharedBloodstreamSystem : EntitySystem
bloodstream.BloodlossHealDamage * bloodPercentage, bloodstream.BloodlossHealDamage * bloodPercentage,
ignoreResistances: true, interruptsDoAfters: false); ignoreResistances: true, interruptsDoAfters: false);
// Remove the drunk effect when healthy. Should only remove the amount of drunk and stutter added by low blood level _status.TryRemoveStatusEffect(uid, Bloodloss);
_drunkSystem.TryRemoveDrunkenessTime(uid, bloodstream.StatusTime.TotalSeconds);
_stutteringSystem.DoRemoveStutterTime(uid, bloodstream.StatusTime.TotalSeconds);
// Reset the drunk and stutter time to zero
bloodstream.StatusTime = TimeSpan.Zero;
DirtyField(uid, bloodstream, nameof(BloodstreamComponent.StatusTime));
} }
} }
} }

View File

@@ -1,6 +0,0 @@
using Robust.Shared.GameStates;
namespace Content.Shared.Drunk;
[RegisterComponent, NetworkedComponent]
public sealed partial class DrunkComponent : Component { }

View File

@@ -0,0 +1,11 @@
using Robust.Shared.GameStates;
namespace Content.Shared.Drunk;
/// <summary>
/// This is used by a status effect entity to apply the <see cref="DrunkComponent"/> to an entity.
/// </summary>
[RegisterComponent, NetworkedComponent]
public sealed partial class DrunkStatusEffectComponent : Component
{
}

View File

@@ -1,48 +0,0 @@
using Content.Shared.Speech.EntitySystems;
using Content.Shared.StatusEffect;
using Content.Shared.Traits.Assorted;
using Robust.Shared.Prototypes;
namespace Content.Shared.Drunk;
public abstract class SharedDrunkSystem : EntitySystem
{
public static readonly ProtoId<StatusEffectPrototype> DrunkKey = "Drunk";
[Dependency] private readonly StatusEffectsSystem _statusEffectsSystem = default!;
[Dependency] private readonly SharedSlurredSystem _slurredSystem = default!;
public void TryApplyDrunkenness(EntityUid uid, float boozePower, bool applySlur = true,
StatusEffectsComponent? status = null)
{
if (!Resolve(uid, ref status, false))
return;
if (TryComp<LightweightDrunkComponent>(uid, out var trait))
boozePower *= trait.BoozeStrengthMultiplier;
if (applySlur)
{
_slurredSystem.DoSlur(uid, TimeSpan.FromSeconds(boozePower), status);
}
if (!_statusEffectsSystem.HasStatusEffect(uid, DrunkKey, status))
{
_statusEffectsSystem.TryAddStatusEffect<DrunkComponent>(uid, DrunkKey, TimeSpan.FromSeconds(boozePower), true, status);
}
else
{
_statusEffectsSystem.TryAddTime(uid, DrunkKey, TimeSpan.FromSeconds(boozePower), status);
}
}
public void TryRemoveDrunkenness(EntityUid uid)
{
_statusEffectsSystem.TryRemoveStatusEffect(uid, DrunkKey);
}
public void TryRemoveDrunkenessTime(EntityUid uid, double timeRemoved)
{
_statusEffectsSystem.TryRemoveTime(uid, DrunkKey, TimeSpan.FromSeconds(timeRemoved));
}
}

View File

@@ -0,0 +1,50 @@
using Content.Shared.Speech.EntitySystems;
using Content.Shared.StatusEffectNew;
using Content.Shared.Traits.Assorted;
using Robust.Shared.Prototypes;
namespace Content.Shared.Drunk;
public abstract class SharedDrunkSystem : EntitySystem
{
public static EntProtoId Drunk = "StatusEffectDrunk";
public static EntProtoId Woozy = "StatusEffectWoozy";
/* I have no clue why this magic number was chosen, I copied it from slur system and needed it for the overlay
If you have a more intelligent magic number be my guest to completely explode this value.
There were no comments as to why this value was chosen three years ago. */
public static float MagicNumber = 1100f;
[Dependency] protected readonly StatusEffectsSystem Status = default!;
public override void Initialize()
{
SubscribeLocalEvent<LightweightDrunkComponent, DrunkEvent>(OnLightweightDrinking);
}
public void TryApplyDrunkenness(EntityUid uid, TimeSpan boozePower)
{
var ev = new DrunkEvent(boozePower);
RaiseLocalEvent(uid, ref ev);
Status.TryAddStatusEffectDuration(uid, Drunk, ev.Duration);
}
public void TryRemoveDrunkenness(EntityUid uid)
{
Status.TryRemoveStatusEffect(uid, Drunk);
}
public void TryRemoveDrunkennessTime(EntityUid uid, TimeSpan boozePower)
{
Status.TryAddTime(uid, Drunk, - boozePower);
}
private void OnLightweightDrinking(Entity<LightweightDrunkComponent> entity, ref DrunkEvent args)
{
args.Duration *= entity.Comp.BoozeStrengthMultiplier;
}
[ByRefEvent]
public record struct DrunkEvent(TimeSpan Duration);
}

View File

@@ -9,13 +9,7 @@ public sealed partial class Drunk : EntityEffect
/// BoozePower is how long each metabolism cycle will make the drunk effect last for. /// BoozePower is how long each metabolism cycle will make the drunk effect last for.
/// </summary> /// </summary>
[DataField] [DataField]
public float BoozePower = 3f; public TimeSpan BoozePower = TimeSpan.FromSeconds(3f);
/// <summary>
/// Whether speech should be slurred.
/// </summary>
[DataField]
public bool SlurSpeech = true;
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
=> Loc.GetString("reagent-effect-guidebook-drunk", ("chance", Probability)); => Loc.GetString("reagent-effect-guidebook-drunk", ("chance", Probability));
@@ -24,11 +18,10 @@ public sealed partial class Drunk : EntityEffect
{ {
var boozePower = BoozePower; var boozePower = BoozePower;
if (args is EntityEffectReagentArgs reagentArgs) { if (args is EntityEffectReagentArgs reagentArgs)
boozePower *= reagentArgs.Scale.Float(); boozePower *= reagentArgs.Scale.Float();
}
var drunkSys = args.EntityManager.EntitySysManager.GetEntitySystem<SharedDrunkSystem>(); var drunkSys = args.EntityManager.EntitySysManager.GetEntitySystem<SharedDrunkSystem>();
drunkSys.TryApplyDrunkenness(args.TargetEntity, boozePower, SlurSpeech); drunkSys.TryApplyDrunkenness(args.TargetEntity, boozePower);
} }
} }

View File

@@ -1,8 +1,11 @@
using Content.Shared.StatusEffect; using Content.Shared.StatusEffect;
using Robust.Shared.Prototypes;
namespace Content.Shared.Speech.EntitySystems; namespace Content.Shared.Speech.EntitySystems;
public abstract class SharedSlurredSystem : EntitySystem public abstract class SharedSlurredSystem : EntitySystem
{ {
public static readonly EntProtoId Stutter = "StatusEffectSlurred";
public virtual void DoSlur(EntityUid uid, TimeSpan time, StatusEffectsComponent? status = null) { } public virtual void DoSlur(EntityUid uid, TimeSpan time, StatusEffectsComponent? status = null) { }
} }

View File

@@ -1,26 +1,24 @@
using Content.Shared.StatusEffect; using Content.Shared.StatusEffectNew;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
namespace Content.Shared.Speech.EntitySystems; namespace Content.Shared.Speech.EntitySystems;
public abstract class SharedStutteringSystem : EntitySystem public abstract class SharedStutteringSystem : EntitySystem
{ {
public static readonly ProtoId<StatusEffectPrototype> StutterKey = "Stutter"; public static readonly EntProtoId Stuttering = "StatusEffectStutter";
[Dependency] private readonly StatusEffectsSystem _statusEffectsSystem = default!; [Dependency] protected readonly StatusEffectsSystem Status = default!;
// For code in shared... I imagine we ain't getting accent prediction anytime soon so let's not bother. // For code in shared... I imagine we ain't getting accent prediction anytime soon so let's not bother.
public virtual void DoStutter(EntityUid uid, TimeSpan time, bool refresh, StatusEffectsComponent? status = null) public virtual void DoStutter(EntityUid uid, TimeSpan time, bool refresh)
{ {
} }
public virtual void DoRemoveStutterTime(EntityUid uid, double timeRemoved) public virtual void DoRemoveStutterTime(EntityUid uid, TimeSpan timeRemoved)
{ {
_statusEffectsSystem.TryRemoveTime(uid, StutterKey, TimeSpan.FromSeconds(timeRemoved));
} }
public void DoRemoveStutter(EntityUid uid, double timeRemoved) public virtual void DoRemoveStutter(EntityUid uid)
{ {
_statusEffectsSystem.TryRemoveStatusEffect(uid, StutterKey);
} }
} }

View File

@@ -1,4 +1,3 @@
using Content.Shared.Alert;
using Content.Shared.Whitelist; using Content.Shared.Whitelist;
using Robust.Shared.GameStates; using Robust.Shared.GameStates;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;

View File

@@ -1,6 +1,7 @@
using Content.Shared.Movement.Events; using Content.Shared.Movement.Events;
using Content.Shared.Movement.Systems; using Content.Shared.Movement.Systems;
using Content.Shared.Rejuvenate; using Content.Shared.Rejuvenate;
using Content.Shared.Speech;
using Content.Shared.StatusEffectNew.Components; using Content.Shared.StatusEffectNew.Components;
using Content.Shared.Stunnable; using Content.Shared.Stunnable;
using Robust.Shared.Player; using Robust.Shared.Player;
@@ -23,6 +24,8 @@ public sealed partial class StatusEffectsSystem
SubscribeLocalEvent<StatusEffectContainerComponent, StandUpAttemptEvent>(RefRelayStatusEffectEvent); SubscribeLocalEvent<StatusEffectContainerComponent, StandUpAttemptEvent>(RefRelayStatusEffectEvent);
SubscribeLocalEvent<StatusEffectContainerComponent, StunEndAttemptEvent>(RefRelayStatusEffectEvent); SubscribeLocalEvent<StatusEffectContainerComponent, StunEndAttemptEvent>(RefRelayStatusEffectEvent);
SubscribeLocalEvent<StatusEffectContainerComponent, AccentGetEvent>(RelayStatusEffectEvent);
} }
private void RefRelayStatusEffectEvent<T>(EntityUid uid, StatusEffectContainerComponent component, ref T args) where T : struct private void RefRelayStatusEffectEvent<T>(EntityUid uid, StatusEffectContainerComponent component, ref T args) where T : struct

View File

@@ -19,7 +19,6 @@
group: GenericNumber group: GenericNumber
- type: StatusEffects - type: StatusEffects
allowed: allowed:
- Stutter
- Electrocution - Electrocution
- TemporaryBlindness - TemporaryBlindness
- RadiationProtection - RadiationProtection

View File

@@ -35,7 +35,6 @@
bodyType: KinematicController # Same for all inheritors bodyType: KinematicController # Same for all inheritors
- type: StatusEffects - type: StatusEffects
allowed: allowed:
- Stutter
- Electrocution - Electrocution
- type: Pullable - type: Pullable
- type: Tag - type: Tag

View File

@@ -15,7 +15,6 @@
bodyType: KinematicController # Same for all inheritors bodyType: KinematicController # Same for all inheritors
- type: StatusEffects - type: StatusEffects
allowed: allowed:
- Stutter
- Electrocution - Electrocution
- type: Repairable - type: Repairable
doAfterDelay: 8 doAfterDelay: 8

View File

@@ -19,7 +19,6 @@
baseSprintSpeed : 4 baseSprintSpeed : 4
- type: StatusEffects - type: StatusEffects
allowed: allowed:
- Stutter
- Electrocution - Electrocution
- TemporaryBlindness - TemporaryBlindness
- Pacified - Pacified
@@ -93,7 +92,6 @@
baseDecayRate: 0.04 baseDecayRate: 0.04
- type: StatusEffects - type: StatusEffects
allowed: allowed:
- Stutter
- Electrocution - Electrocution
- TemporaryBlindness - TemporaryBlindness
- Pacified - Pacified

View File

@@ -100,7 +100,6 @@
types: {} types: {}
- type: StatusEffects # Overwriting basesimplemob to remove flash, getting flashed as dragon just feelsbad - type: StatusEffects # Overwriting basesimplemob to remove flash, getting flashed as dragon just feelsbad
allowed: allowed:
- Stutter
- Electrocution - Electrocution
- TemporaryBlindness - TemporaryBlindness
- Pacified - Pacified

View File

@@ -120,10 +120,7 @@
- !type:WashCreamPieReaction - !type:WashCreamPieReaction
- type: StatusEffects - type: StatusEffects
allowed: allowed:
- Stutter
- Electrocution - Electrocution
- Drunk
- SlurredSpeech
- RatvarianLanguage - RatvarianLanguage
- PressureImmunity - PressureImmunity
- Muted - Muted

View File

@@ -0,0 +1,18 @@
- type: entity
parent: MobStatusEffectBase
id: BloodstreamStatusEffectBase
abstract: true
components:
- type: StatusEffect
whitelist:
components:
- Bloodstream
- type: entity
parent: [ BloodstreamStatusEffectBase ]
id: StatusEffectBloodloss
name: bloodloss
components:
- type: StutteringAccent
- type: DrunkStatusEffect
- type: RejuvenateRemovedStatusEffect

View File

@@ -78,3 +78,17 @@
name: hallucinations name: hallucinations
components: components:
- type: SeeingRainbowsStatusEffect - type: SeeingRainbowsStatusEffect
# Causes your vision to become blurry and gives me a headache.
- type: entity
parent: MobStatusEffectDebuff
id: StatusEffectWoozy
name: woozy
components:
- type: DrunkStatusEffect
# Causes you to get drunk
- type: entity
parent: [ StatusEffectWoozy, StatusEffectSlurred ]
id: StatusEffectDrunk
name: drunk

View File

@@ -0,0 +1,27 @@
- type: entity
parent: MobStatusEffectDebuff
id: SpeechStatusEffectBase
abstract: true
components:
- type: StatusEffect
whitelist:
components:
- MobState
- Speech
requireAll: true
# Causes you to st-t-u-t-t-t-er randomly when talking.
- type: entity
parent: SpeechStatusEffectBase
id: StatusEffectStutter
name: stutter
components:
- type: StutteringAccent
# Causes you to schlur your words schwhen talking.
- type: entity
parent: SpeechStatusEffectBase
id: StatusEffectSlurred
name: slurred
components:
- type: SlurredAccent

View File

@@ -12,9 +12,9 @@
- !type:GenericStatusEffect - !type:GenericStatusEffect
key: Stutter key: Stutter
component: ScrambledAccent component: ScrambledAccent
- !type:Drunk - !type:ModifyStatusEffect
slurSpeech: false effectProto: StatusEffectSlurred
boozePower: 20 time: 20.0
- type: reagent - type: reagent
id: Dylovene id: Dylovene
@@ -104,8 +104,8 @@
metabolisms: metabolisms:
Medicine: Medicine:
effects: effects:
- !type:GenericStatusEffect - !type:ModifyStatusEffect
key: Drunk effectProto: StatusEffectDrunk
time: 6.0 time: 6.0
type: Remove type: Remove
- !type:HealthChange - !type:HealthChange
@@ -1353,8 +1353,8 @@
key: Jitter key: Jitter
time: 2.0 time: 2.0
type: Remove type: Remove
- !type:GenericStatusEffect - !type:ModifyStatusEffect
key: Drunk effectProto: StatusEffectDrunk
time: 6.0 time: 6.0
type: Remove type: Remove
- !type:PopupMessage # we dont have sanity/mood so this will have to do - !type:PopupMessage # we dont have sanity/mood so this will have to do