]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Fix non-humanoid mobs being destroyed on devour (#38087)
authorSparlight <twiksparlight@gmail.com>
Wed, 9 Jul 2025 12:43:35 +0000 (06:43 -0600)
committerGitHub <noreply@github.com>
Wed, 9 Jul 2025 12:43:35 +0000 (14:43 +0200)
* Allow non-preference living things to be added to a devourer's stomach

* Fix ordering of devour logic

* Minor refactor for whitelist on storage and food preference

* Fix linter issue

* Coerce workflow to run again; also fix bad indenting error

* Code review changes

Content.Server/Devour/DevourSystem.cs
Content.Shared/Devour/Components/DevourerComponent.cs
Content.Shared/Devour/SharedDevourSystem.cs
Resources/Prototypes/Entities/Mobs/Player/dragon.yml

index 88edc3ec4c6d2dcbbbf465abb9f77f9c52d4986e..ede13fa8170c4d5f292deb5b55f8ac7f822aecc1 100644 (file)
@@ -3,13 +3,14 @@ using Content.Shared.Body.Events;
 using Content.Shared.Chemistry.Components;
 using Content.Shared.Devour;
 using Content.Shared.Devour.Components;
-using Content.Shared.Humanoid;
+using Content.Shared.Whitelist;
 
 namespace Content.Server.Devour;
 
 public sealed class DevourSystem : SharedDevourSystem
 {
     [Dependency] private readonly BloodstreamSystem _bloodstreamSystem = default!;
+    [Dependency] private readonly EntityWhitelistSystem _entityWhitelistSystem = default!;
 
     public override void Initialize()
     {
@@ -26,18 +27,20 @@ public sealed class DevourSystem : SharedDevourSystem
 
         var ichorInjection = new Solution(component.Chemical, component.HealRate);
 
-        if (component.FoodPreference == FoodPreference.All ||
-            (component.FoodPreference == FoodPreference.Humanoid && HasComp<HumanoidAppearanceComponent>(args.Args.Target)))
+        // Grant ichor if the devoured thing meets the dragon's food preference
+        if (args.Args.Target != null && _entityWhitelistSystem.IsWhitelistPassOrNull(component.FoodPreferenceWhitelist, (EntityUid)args.Args.Target))
         {
-            if (component.ShouldStoreDevoured && args.Args.Target is not null)
-            {
-                ContainerSystem.Insert(args.Args.Target.Value, component.Stomach);
-            }
             _bloodstreamSystem.TryAddToChemicals(uid, ichorInjection);
         }
 
+        // If the devoured thing meets the stomach whitelist criteria, add it to the stomach
+        if (args.Args.Target != null && _entityWhitelistSystem.IsWhitelistPass(component.StomachStorageWhitelist, (EntityUid)args.Args.Target))
+        {
+            ContainerSystem.Insert(args.Args.Target.Value, component.Stomach);
+        }
         //TODO: Figure out a better way of removing structures via devour that still entails standing still and waiting for a DoAfter. Somehow.
-        //If it's not human, it must be a structure
+        //If it's not alive, it must be a structure.
+        // Delete if the thing isn't in the stomach storage whitelist (or the stomach whitelist is null/empty)
         else if (args.Args.Target != null)
         {
             QueueDel(args.Args.Target.Value);
@@ -48,7 +51,7 @@ public sealed class DevourSystem : SharedDevourSystem
 
     private void OnGibContents(EntityUid uid, DevourerComponent component, ref BeingGibbedEvent args)
     {
-        if (!component.ShouldStoreDevoured)
+        if (component.StomachStorageWhitelist == null)
             return;
 
         // For some reason we have two different systems that should handle gibbing,
index fbeec28ca579f393ad938bf51fb2344f7ed6a1da..d1101759517196c0f891abd760dd3b1c6b276b7f 100644 (file)
@@ -12,19 +12,19 @@ namespace Content.Shared.Devour.Components;
 [Access(typeof(SharedDevourSystem))]
 public sealed partial class DevourerComponent : Component
 {
-    [DataField("devourAction", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
+    [DataField(customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
     public string? DevourAction = "ActionDevour";
 
-    [DataField("devourActionEntity")]
+    [DataField]
     public EntityUid? DevourActionEntity;
 
-    [ViewVariables(VVAccess.ReadWrite), DataField("soundDevour")]
+    [DataField]
     public SoundSpecifier? SoundDevour = new SoundPathSpecifier("/Audio/Effects/demon_consume.ogg")
     {
         Params = AudioParams.Default.WithVolume(-3f),
     };
 
-    [DataField("devourTime")]
+    [DataField]
     public float DevourTime = 3f;
 
     /// <summary>
@@ -33,10 +33,10 @@ public sealed partial class DevourerComponent : Component
     /// NOTE: original intended design was to increase this proportionally with damage thresholds, but those proved quite difficult to get consistently. right now it devours the structure at a fixed timer.
     /// </remarks>
     /// </summary>
-    [DataField("structureDevourTime")]
+    [DataField]
     public float StructureDevourTime = 10f;
 
-    [ViewVariables(VVAccess.ReadWrite), DataField("soundStructureDevour")]
+    [DataField]
     public SoundSpecifier? SoundStructureDevour = new SoundPathSpecifier("/Audio/Machines/airlock_creaking.ogg")
     {
         Params = AudioParams.Default.WithVolume(-3f),
@@ -47,10 +47,10 @@ public sealed partial class DevourerComponent : Component
     /// </summary>
     public Container Stomach = default!;
 
-    [ViewVariables(VVAccess.ReadWrite), DataField("shouldStoreDevoured")]
-    public bool ShouldStoreDevoured = true;
-
-    [ViewVariables(VVAccess.ReadWrite), DataField("whitelist")]
+    /// <summary>
+    /// Determines what things the devourer can consume.
+    /// </summary>
+    [DataField]
     public EntityWhitelist? Whitelist = new()
     {
         Components = new[]
@@ -59,22 +59,31 @@ public sealed partial class DevourerComponent : Component
         }
     };
 
+    /// <summary>
+    /// Determines what things end up in the dragon's stomach if they eat it.
+    /// If it isn't in the whitelist, it's deleted.
+    /// </summary>
+    [DataField]
+    public EntityWhitelist? StomachStorageWhitelist;
+
+    /// <summary>
+    /// Determine's the dragon's food preference.  If the eaten thing matches,
+    /// it is rewarded with the reward chemical.  If null, all food is fine.
+    /// </summary>
+    [DataField]
+    public EntityWhitelist? FoodPreferenceWhitelist;
+
     /// <summary>
     /// The chemical ID injected upon devouring
     /// </summary>
-    [DataField("chemical", customTypeSerializer: typeof(PrototypeIdSerializer<ReagentPrototype>))]
+    [DataField(customTypeSerializer: typeof(PrototypeIdSerializer<ReagentPrototype>))]
     public string Chemical = "Ichor";
 
     /// <summary>
     /// The amount of ichor injected per devour
     /// </summary>
-    [ViewVariables(VVAccess.ReadWrite), DataField("healRate")]
+    [DataField]
     public float HealRate = 15f;
 
-    /// <summary>
-    /// The favorite food not only feeds you, but also heals
-    /// </summary>
-    [DataField("foodPreference")]
-    public FoodPreference FoodPreference = FoodPreference.All;
 }
 
index 14047fba7dd2822920d79a9f57eedd1d46df225a..702884c984795e69f317e1b2f114ccb91461c899 100644 (file)
@@ -87,9 +87,3 @@ public sealed partial class DevourActionEvent : EntityTargetActionEvent { }
 [Serializable, NetSerializable]
 public sealed partial class DevourDoAfterEvent : SimpleDoAfterEvent { }
 
-[Serializable, NetSerializable]
-public enum FoodPreference : byte
-{
-    Humanoid = 0,
-    All = 1
-}
index fc2dddb23dd089683550404b7854833bd96db659..0d6489744fa7310cdcd9f3127573defe5458e4be 100644 (file)
         Piercing: 15
         Slash: 15
   - type: Devourer
-    foodPreference: Humanoid
-    shouldStoreDevoured: true
+    foodPreferenceWhitelist:
+      components:
+      - HumanoidAppearance
+    stomachStorageWhitelist:
+      components:
+      - MobState
     chemical: Ichor
     healRate: 7.5
     whitelist: