Fix dead mobs sneezing and coughing (#12919)
* Fix dead mobs sneezing and coughing * SneezeCough update * Streamlined Event code, moved dead-check * cleanup * I can has merge? * Shared event for SharedMobStateSystem
This commit is contained in:
@@ -9,6 +9,7 @@ using Content.Server.Popups;
|
|||||||
using Content.Shared.Clothing.Components;
|
using Content.Shared.Clothing.Components;
|
||||||
using Content.Shared.Disease;
|
using Content.Shared.Disease;
|
||||||
using Content.Shared.Disease.Components;
|
using Content.Shared.Disease.Components;
|
||||||
|
using Content.Shared.Disease.Events;
|
||||||
using Content.Shared.Examine;
|
using Content.Shared.Examine;
|
||||||
using Content.Shared.IdentityManagement;
|
using Content.Shared.IdentityManagement;
|
||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
@@ -17,6 +18,8 @@ using Content.Shared.Inventory;
|
|||||||
using Content.Shared.Inventory.Events;
|
using Content.Shared.Inventory.Events;
|
||||||
using Content.Shared.MobState.Components;
|
using Content.Shared.MobState.Components;
|
||||||
using Content.Shared.Rejuvenate;
|
using Content.Shared.Rejuvenate;
|
||||||
|
using Robust.Shared.Audio;
|
||||||
|
using Robust.Server.GameObjects;
|
||||||
using Robust.Shared.Player;
|
using Robust.Shared.Player;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
using Robust.Shared.Random;
|
using Robust.Shared.Random;
|
||||||
@@ -31,6 +34,7 @@ namespace Content.Server.Disease
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class DiseaseSystem : EntitySystem
|
public sealed class DiseaseSystem : EntitySystem
|
||||||
{
|
{
|
||||||
|
[Dependency] private readonly AudioSystem _audioSystem = default!;
|
||||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||||
[Dependency] private readonly ISerializationManager _serializationManager = default!;
|
[Dependency] private readonly ISerializationManager _serializationManager = default!;
|
||||||
[Dependency] private readonly IRobustRandom _random = default!;
|
[Dependency] private readonly IRobustRandom _random = default!;
|
||||||
@@ -264,7 +268,7 @@ namespace Content.Server.Disease
|
|||||||
{
|
{
|
||||||
if (TryComp<DiseaseCarrierComponent>(uid, out var carrier))
|
if (TryComp<DiseaseCarrierComponent>(uid, out var carrier))
|
||||||
{
|
{
|
||||||
SneezeCough(uid, _random.Pick(carrier.Diseases), string.Empty);
|
SneezeCough(uid, _random.Pick(carrier.Diseases), string.Empty, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -430,24 +434,34 @@ namespace Content.Server.Disease
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Plays a sneeze/cough popup if applicable
|
/// Raises an event for systems to cancel the snough if needed
|
||||||
|
/// Plays a sneeze/cough sound and popup if applicable
|
||||||
/// and then tries to infect anyone in range
|
/// and then tries to infect anyone in range
|
||||||
/// if the snougher is not wearing a mask.
|
/// if the snougher is not wearing a mask.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void SneezeCough(EntityUid uid, DiseasePrototype? disease, string snoughMessage, bool airTransmit = true, TransformComponent? xform = null)
|
public bool SneezeCough(EntityUid uid, DiseasePrototype? disease, string snoughMessage, SoundSpecifier? snoughSound, bool airTransmit = true, TransformComponent? xform = null)
|
||||||
{
|
{
|
||||||
if (!Resolve(uid, ref xform)) return;
|
if (!Resolve(uid, ref xform)) return false;
|
||||||
|
|
||||||
|
if (_mobStateSystem.IsDead(uid)) return false;
|
||||||
|
|
||||||
|
var attemptSneezeCoughEvent = new AttemptSneezeCoughEvent(uid, snoughMessage, snoughSound);
|
||||||
|
RaiseLocalEvent(uid, ref attemptSneezeCoughEvent);
|
||||||
|
if (attemptSneezeCoughEvent.Cancelled) return false;
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(snoughMessage))
|
if (!string.IsNullOrEmpty(snoughMessage))
|
||||||
_popupSystem.PopupEntity(Loc.GetString(snoughMessage, ("person", Identity.Entity(uid, EntityManager))), uid, Filter.Pvs(uid));
|
_popupSystem.PopupEntity(Loc.GetString(snoughMessage, ("person", Identity.Entity(uid, EntityManager))), uid, Filter.Pvs(uid));
|
||||||
|
|
||||||
|
if (snoughSound != null)
|
||||||
|
_audioSystem.PlayPvs(snoughSound, uid);
|
||||||
|
|
||||||
if (disease is not { Infectious: true } || !airTransmit)
|
if (disease is not { Infectious: true } || !airTransmit)
|
||||||
return;
|
return true;
|
||||||
|
|
||||||
if (_inventorySystem.TryGetSlotEntity(uid, "mask", out var maskUid) &&
|
if (_inventorySystem.TryGetSlotEntity(uid, "mask", out var maskUid) &&
|
||||||
EntityManager.TryGetComponent<IngestionBlockerComponent>(maskUid, out var blocker) &&
|
EntityManager.TryGetComponent<IngestionBlockerComponent>(maskUid, out var blocker) &&
|
||||||
blocker.Enabled)
|
blocker.Enabled)
|
||||||
return;
|
return true;
|
||||||
|
|
||||||
var carrierQuery = GetEntityQuery<DiseaseCarrierComponent>();
|
var carrierQuery = GetEntityQuery<DiseaseCarrierComponent>();
|
||||||
|
|
||||||
@@ -458,6 +472,7 @@ namespace Content.Server.Disease
|
|||||||
|
|
||||||
TryInfect(carrier, disease, 0.3f);
|
TryInfect(carrier, disease, 0.3f);
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
using Content.Shared.Disease;
|
using Content.Shared.Disease;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Content.Shared.Audio;
|
|
||||||
using Robust.Shared.Audio;
|
using Robust.Shared.Audio;
|
||||||
using Robust.Shared.Player;
|
|
||||||
|
|
||||||
namespace Content.Server.Disease
|
namespace Content.Server.Disease
|
||||||
{
|
{
|
||||||
@@ -13,6 +11,7 @@ namespace Content.Server.Disease
|
|||||||
[UsedImplicitly]
|
[UsedImplicitly]
|
||||||
public sealed class DiseaseSnough : DiseaseEffect
|
public sealed class DiseaseSnough : DiseaseEffect
|
||||||
{
|
{
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Message to play when snoughing
|
/// Message to play when snoughing
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -24,6 +23,7 @@ namespace Content.Server.Disease
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
[DataField("snoughSound")]
|
[DataField("snoughSound")]
|
||||||
public SoundSpecifier? SnoughSound;
|
public SoundSpecifier? SnoughSound;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether to spread the disease through the air
|
/// Whether to spread the disease through the air
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -32,9 +32,7 @@ namespace Content.Server.Disease
|
|||||||
|
|
||||||
public override void Effect(DiseaseEffectArgs args)
|
public override void Effect(DiseaseEffectArgs args)
|
||||||
{
|
{
|
||||||
if (SnoughSound != null)
|
EntitySystem.Get<DiseaseSystem>().SneezeCough(args.DiseasedEntity, args.Disease, SnoughMessage, SnoughSound, AirTransmit);
|
||||||
SoundSystem.Play(SnoughSound.GetSound(), Filter.Pvs(args.DiseasedEntity), args.DiseasedEntity, AudioHelpers.WithVariation(0.2f));
|
|
||||||
EntitySystem.Get<DiseaseSystem>().SneezeCough(args.DiseasedEntity, args.Disease, SnoughMessage, AirTransmit);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,4 @@
|
|||||||
using Content.Server.Disease;
|
using Content.Server.Disease;
|
||||||
using Content.Shared.Audio;
|
|
||||||
using Robust.Server.GameObjects;
|
|
||||||
using Robust.Shared.Audio;
|
|
||||||
using Robust.Shared.Player;
|
|
||||||
using Robust.Shared.Random;
|
using Robust.Shared.Random;
|
||||||
|
|
||||||
namespace Content.Server.Traits.Assorted;
|
namespace Content.Server.Traits.Assorted;
|
||||||
@@ -14,7 +10,6 @@ public sealed class UncontrollableSnoughSystem : EntitySystem
|
|||||||
{
|
{
|
||||||
[Dependency] private readonly IRobustRandom _random = default!;
|
[Dependency] private readonly IRobustRandom _random = default!;
|
||||||
[Dependency] private readonly DiseaseSystem _diseaseSystem = default!;
|
[Dependency] private readonly DiseaseSystem _diseaseSystem = default!;
|
||||||
[Dependency] private readonly AudioSystem _audioSystem = default!;
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
@@ -43,10 +38,7 @@ public sealed class UncontrollableSnoughSystem : EntitySystem
|
|||||||
snough.NextIncidentTime +=
|
snough.NextIncidentTime +=
|
||||||
_random.NextFloat(snough.TimeBetweenIncidents.X, snough.TimeBetweenIncidents.Y);
|
_random.NextFloat(snough.TimeBetweenIncidents.X, snough.TimeBetweenIncidents.Y);
|
||||||
|
|
||||||
if (snough.SnoughSound != null)
|
_diseaseSystem.SneezeCough(snough.Owner, null, snough.SnoughMessage, snough.SnoughSound, false);
|
||||||
_audioSystem.PlayPvs(snough.SnoughSound, snough.Owner);
|
|
||||||
|
|
||||||
_diseaseSystem.SneezeCough(snough.Owner, null, snough.SnoughMessage, false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,24 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Robust.Shared.Random;
|
|
||||||
using Content.Server.Body.Systems;
|
using Content.Server.Body.Systems;
|
||||||
|
using Content.Server.Chat.Systems;
|
||||||
|
using Content.Server.Disease;
|
||||||
using Content.Server.Disease.Components;
|
using Content.Server.Disease.Components;
|
||||||
using Content.Server.Drone.Components;
|
using Content.Server.Drone.Components;
|
||||||
using Content.Shared.Chemistry.Components;
|
|
||||||
using Content.Shared.MobState.Components;
|
|
||||||
using Content.Server.Disease;
|
|
||||||
using Content.Shared.Inventory;
|
|
||||||
using Content.Shared.MobState;
|
|
||||||
using Content.Server.Inventory;
|
using Content.Server.Inventory;
|
||||||
using Robust.Shared.Prototypes;
|
|
||||||
using Content.Server.Speech;
|
using Content.Server.Speech;
|
||||||
|
using Content.Shared.Bed.Sleep;
|
||||||
|
using Content.Shared.Chemistry.Components;
|
||||||
using Content.Server.Chat.Systems;
|
using Content.Server.Chat.Systems;
|
||||||
using Content.Shared.Bed.Sleep;
|
using Content.Shared.Bed.Sleep;
|
||||||
using Content.Shared.Damage;
|
using Content.Shared.Damage;
|
||||||
|
using Content.Shared.Disease.Events;
|
||||||
|
using Content.Shared.Inventory;
|
||||||
|
using Content.Shared.MobState;
|
||||||
|
using Content.Shared.MobState.Components;
|
||||||
using Content.Shared.Weapons.Melee.Events;
|
using Content.Shared.Weapons.Melee.Events;
|
||||||
using Content.Shared.Zombies;
|
using Content.Shared.Zombies;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
using Robust.Shared.Random;
|
||||||
|
|
||||||
namespace Content.Server.Zombies
|
namespace Content.Server.Zombies
|
||||||
{
|
{
|
||||||
@@ -37,6 +40,7 @@ namespace Content.Server.Zombies
|
|||||||
SubscribeLocalEvent<ZombieComponent, MeleeHitEvent>(OnMeleeHit);
|
SubscribeLocalEvent<ZombieComponent, MeleeHitEvent>(OnMeleeHit);
|
||||||
SubscribeLocalEvent<ZombieComponent, MobStateChangedEvent>(OnMobState);
|
SubscribeLocalEvent<ZombieComponent, MobStateChangedEvent>(OnMobState);
|
||||||
SubscribeLocalEvent<ActiveZombieComponent, DamageChangedEvent>(OnDamage);
|
SubscribeLocalEvent<ActiveZombieComponent, DamageChangedEvent>(OnDamage);
|
||||||
|
SubscribeLocalEvent<ActiveZombieComponent, AttemptSneezeCoughEvent>(OnSneeze);
|
||||||
SubscribeLocalEvent<ActiveZombieComponent, TryingToSleepEvent>(OnSleepAttempt);
|
SubscribeLocalEvent<ActiveZombieComponent, TryingToSleepEvent>(OnSleepAttempt);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -60,6 +64,11 @@ namespace Content.Server.Zombies
|
|||||||
DoGroan(uid, component);
|
DoGroan(uid, component);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnSneeze(EntityUid uid, ActiveZombieComponent component, ref AttemptSneezeCoughEvent args)
|
||||||
|
{
|
||||||
|
args.Cancelled = true;
|
||||||
|
}
|
||||||
|
|
||||||
private float GetZombieInfectionChance(EntityUid uid, ZombieComponent component)
|
private float GetZombieInfectionChance(EntityUid uid, ZombieComponent component)
|
||||||
{
|
{
|
||||||
var baseChance = component.MaxZombieInfectionChance;
|
var baseChance = component.MaxZombieInfectionChance;
|
||||||
|
|||||||
10
Content.Shared/Disease/Events/AttemptSneezeCoughEvent.cs
Normal file
10
Content.Shared/Disease/Events/AttemptSneezeCoughEvent.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
using Robust.Shared.Audio;
|
||||||
|
|
||||||
|
namespace Content.Shared.Disease.Events;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Raised by an entity about to sneeze/cough.
|
||||||
|
/// Set Cancelled to true on event handling to suppress the sneeze
|
||||||
|
/// </summary>
|
||||||
|
[ByRefEvent]
|
||||||
|
public record struct AttemptSneezeCoughEvent(EntityUid uid, string SnoughMessage, SoundSpecifier? SnoughSound, bool Cancelled = false);
|
||||||
@@ -5,6 +5,7 @@ using Content.Shared.Alert;
|
|||||||
using Content.Shared.Bed.Sleep;
|
using Content.Shared.Bed.Sleep;
|
||||||
using Content.Shared.Damage;
|
using Content.Shared.Damage;
|
||||||
using Content.Shared.Database;
|
using Content.Shared.Database;
|
||||||
|
using Content.Shared.Disease.Events;
|
||||||
using Content.Shared.DragDrop;
|
using Content.Shared.DragDrop;
|
||||||
using Content.Shared.Emoting;
|
using Content.Shared.Emoting;
|
||||||
using Content.Shared.FixedPoint;
|
using Content.Shared.FixedPoint;
|
||||||
@@ -58,6 +59,7 @@ namespace Content.Shared.MobState.EntitySystems
|
|||||||
SubscribeLocalEvent<MobStateComponent, UpdateCanMoveEvent>(OnMoveAttempt);
|
SubscribeLocalEvent<MobStateComponent, UpdateCanMoveEvent>(OnMoveAttempt);
|
||||||
SubscribeLocalEvent<MobStateComponent, StandAttemptEvent>(OnStandAttempt);
|
SubscribeLocalEvent<MobStateComponent, StandAttemptEvent>(OnStandAttempt);
|
||||||
SubscribeLocalEvent<MobStateComponent, TryingToSleepEvent>(OnSleepAttempt);
|
SubscribeLocalEvent<MobStateComponent, TryingToSleepEvent>(OnSleepAttempt);
|
||||||
|
SubscribeLocalEvent<MobStateComponent, AttemptSneezeCoughEvent>(OnSneezeAttempt);
|
||||||
SubscribeLocalEvent<MobStateChangedEvent>(OnStateChanged);
|
SubscribeLocalEvent<MobStateChangedEvent>(OnStateChanged);
|
||||||
// Note that there's no check for Down attempts because if a mob's in crit or dead, they can be downed...
|
// Note that there's no check for Down attempts because if a mob's in crit or dead, they can be downed...
|
||||||
}
|
}
|
||||||
@@ -68,6 +70,12 @@ namespace Content.Shared.MobState.EntitySystems
|
|||||||
args.Cancelled = true;
|
args.Cancelled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnSneezeAttempt(EntityUid uid, MobStateComponent component, ref AttemptSneezeCoughEvent args)
|
||||||
|
{
|
||||||
|
if(IsDead(uid, component))
|
||||||
|
args.Cancelled = true;
|
||||||
|
}
|
||||||
|
|
||||||
private void OnGettingStripped(EntityUid uid, MobStateComponent component, BeforeGettingStrippedEvent args)
|
private void OnGettingStripped(EntityUid uid, MobStateComponent component, BeforeGettingStrippedEvent args)
|
||||||
{
|
{
|
||||||
// Incapacitated or dead targets get stripped two or three times as fast. Makes stripping corpses less tedious.
|
// Incapacitated or dead targets get stripped two or three times as fast. Makes stripping corpses less tedious.
|
||||||
|
|||||||
Reference in New Issue
Block a user