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:
Errant
2022-12-16 17:33:34 +00:00
committed by GitHub
parent 23ee8ecaaa
commit 656ce251e4
6 changed files with 59 additions and 27 deletions

View File

@@ -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>

View File

@@ -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);
} }
} }
} }

View File

@@ -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);
} }
} }
} }

View File

@@ -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;

View 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);

View File

@@ -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.