]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Move entity effects definitions to shared (#35614)
authorpathetic meowmeow <uhhadd@gmail.com>
Fri, 23 May 2025 16:32:22 +0000 (12:32 -0400)
committerGitHub <noreply@github.com>
Fri, 23 May 2025 16:32:22 +0000 (12:32 -0400)
* Move entity effects to shared

* relocate spawning to server

* Generic version of EntityEffect for just raising event.

* genericise everything

* oops forgot to push you

* some condensation

* finish rebas

* unwhite the space

* oops forgot nuke

* bad rebase fix

* useless annotations begone

---------

Co-authored-by: EmoGarbage404 <retron404@gmail.com>
132 files changed:
Content.Server/Body/Systems/BloodstreamSystem.cs
Content.Server/Body/Systems/RespiratorSystem.cs
Content.Server/Botany/SeedPrototype.cs
Content.Server/EntityEffects/EffectConditions/BreathingCondition.cs [deleted file]
Content.Server/EntityEffects/EffectConditions/OrganType.cs [deleted file]
Content.Server/EntityEffects/Effects/AdjustTemperature.cs [deleted file]
Content.Server/EntityEffects/Effects/AreaReactionEffect.cs [deleted file]
Content.Server/EntityEffects/Effects/CauseZombieInfection.cs [deleted file]
Content.Server/EntityEffects/Effects/ChemCleanBloodstream.cs [deleted file]
Content.Server/EntityEffects/Effects/ChemVomit.cs [deleted file]
Content.Server/EntityEffects/Effects/CreateEntityReactionEffect.cs [deleted file]
Content.Server/EntityEffects/Effects/CreateGas.cs [deleted file]
Content.Server/EntityEffects/Effects/CureZombieInfection.cs [deleted file]
Content.Server/EntityEffects/Effects/EmpReactionEffect.cs [deleted file]
Content.Server/EntityEffects/Effects/FlammableReaction.cs [deleted file]
Content.Server/EntityEffects/Effects/FlashReactionEffect.cs [deleted file]
Content.Server/EntityEffects/Effects/Ignite.cs [deleted file]
Content.Server/EntityEffects/Effects/MakeSentient.cs [deleted file]
Content.Server/EntityEffects/Effects/ModifyBleedAmount.cs [deleted file]
Content.Server/EntityEffects/Effects/ModifyBloodLevel.cs [deleted file]
Content.Server/EntityEffects/Effects/ModifyLungGas.cs [deleted file]
Content.Server/EntityEffects/Effects/Oxygenate.cs [deleted file]
Content.Server/EntityEffects/Effects/PlantChangeStat.cs [deleted file]
Content.Server/EntityEffects/Effects/PlantMetabolism/PlantAdjustHealth.cs [deleted file]
Content.Server/EntityEffects/Effects/PlantMetabolism/PlantAdjustMutationLevel.cs [deleted file]
Content.Server/EntityEffects/Effects/PlantMetabolism/PlantAdjustMutationMod.cs [deleted file]
Content.Server/EntityEffects/Effects/PlantMetabolism/PlantAdjustNutrition.cs [deleted file]
Content.Server/EntityEffects/Effects/PlantMetabolism/PlantAdjustPests.cs [deleted file]
Content.Server/EntityEffects/Effects/PlantMetabolism/PlantAdjustPotency.cs [deleted file]
Content.Server/EntityEffects/Effects/PlantMetabolism/PlantAdjustToxins.cs [deleted file]
Content.Server/EntityEffects/Effects/PlantMetabolism/PlantAdjustWater.cs [deleted file]
Content.Server/EntityEffects/Effects/PlantMetabolism/PlantAdjustWeeds.cs [deleted file]
Content.Server/EntityEffects/Effects/PlantMetabolism/PlantAffectGrowth.cs [deleted file]
Content.Server/EntityEffects/Effects/PlantMetabolism/PlantCryoxadone.cs [deleted file]
Content.Server/EntityEffects/Effects/PlantMetabolism/PlantDestroySeeds.cs [deleted file]
Content.Server/EntityEffects/Effects/PlantMetabolism/PlantDiethylamine.cs [deleted file]
Content.Server/EntityEffects/Effects/PlantMetabolism/PlantPhalanximine.cs [deleted file]
Content.Server/EntityEffects/Effects/PlantMetabolism/PlantRestoreSeeds.cs [deleted file]
Content.Server/EntityEffects/Effects/PlantMetabolism/RobustHarvest.cs [deleted file]
Content.Server/EntityEffects/Effects/PlantMutateChemicals.cs [deleted file]
Content.Server/EntityEffects/Effects/PlantMutateGases.cs [deleted file]
Content.Server/EntityEffects/Effects/PlantMutateHarvest.cs [deleted file]
Content.Server/EntityEffects/Effects/PlantSpeciesChange.cs [deleted file]
Content.Server/EntityEffects/Effects/ReduceRotting.cs [deleted file]
Content.Server/EntityEffects/Effects/ResetNarcolepsy.cs [deleted file]
Content.Server/EntityEffects/Effects/SatiateHunger.cs [deleted file]
Content.Server/EntityEffects/EntityEffectSystem.cs [new file with mode: 0644]
Content.Server/Fluids/EntitySystems/SmokeSystem.cs
Content.Server/Nutrition/EntitySystems/DrinkSystem.cs
Content.Shared/Chemistry/Reaction/ReactionPrototype.cs
Content.Shared/Chemistry/Reagent/ReagentPrototype.cs
Content.Shared/EntityEffects/EffectConditions/BodyTemperature.cs [moved from Content.Server/EntityEffects/EffectConditions/BodyTemperature.cs with 52% similarity]
Content.Shared/EntityEffects/EffectConditions/BreathingCondition.cs [new file with mode: 0644]
Content.Shared/EntityEffects/EffectConditions/HasTagCondition.cs [moved from Content.Server/EntityEffects/EffectConditions/HasTagCondition.cs with 86% similarity]
Content.Shared/EntityEffects/EffectConditions/InternalsCondition.cs [moved from Content.Server/EntityEffects/EffectConditions/InternalsCondition.cs with 100% similarity]
Content.Shared/EntityEffects/EffectConditions/JobCondition.cs [moved from Content.Server/EntityEffects/EffectConditions/JobCondition.cs with 95% similarity]
Content.Shared/EntityEffects/EffectConditions/MobStateCondition.cs [moved from Content.Server/EntityEffects/EffectConditions/MobStateCondition.cs with 88% similarity]
Content.Shared/EntityEffects/EffectConditions/OrganType.cs [new file with mode: 0644]
Content.Shared/EntityEffects/EffectConditions/ReagentThreshold.cs [moved from Content.Server/EntityEffects/EffectConditions/ReagentThreshold.cs with 95% similarity]
Content.Shared/EntityEffects/EffectConditions/SolutionTemperature.cs [moved from Content.Server/EntityEffects/EffectConditions/SolutionTemperature.cs with 92% similarity]
Content.Shared/EntityEffects/EffectConditions/TotalDamage.cs [moved from Content.Server/EntityEffects/EffectConditions/TotalDamage.cs with 94% similarity]
Content.Shared/EntityEffects/EffectConditions/TotalHunger.cs [moved from Content.Server/EntityEffects/EffectConditions/TotalHunger.cs with 94% similarity]
Content.Shared/EntityEffects/Effects/AddToSolutionReaction.cs [moved from Content.Server/EntityEffects/Effects/AddToSolutionReaction.cs with 91% similarity]
Content.Shared/EntityEffects/Effects/AdjustAlert.cs [moved from Content.Server/EntityEffects/Effects/AdjustAlert.cs with 95% similarity]
Content.Shared/EntityEffects/Effects/AdjustReagent.cs [moved from Content.Server/EntityEffects/Effects/AdjustReagent.cs with 96% similarity]
Content.Shared/EntityEffects/Effects/AdjustTemperature.cs [new file with mode: 0644]
Content.Shared/EntityEffects/Effects/AreaReactionEffect.cs [new file with mode: 0644]
Content.Shared/EntityEffects/Effects/ArtifactUnlock.cs [moved from Content.Server/EntityEffects/Effects/ArtifactUnlock.cs with 84% similarity]
Content.Shared/EntityEffects/Effects/CauseZombieInfection.cs [new file with mode: 0644]
Content.Shared/EntityEffects/Effects/ChemCleanBloodstream.cs [new file with mode: 0644]
Content.Shared/EntityEffects/Effects/ChemHealEyeDamage.cs [moved from Content.Server/EntityEffects/Effects/ChemHealEyeDamage.cs with 87% similarity]
Content.Shared/EntityEffects/Effects/ChemVomit.cs [new file with mode: 0644]
Content.Shared/EntityEffects/Effects/CreateEntityReactionEffect.cs [new file with mode: 0644]
Content.Shared/EntityEffects/Effects/CreateGas.cs [new file with mode: 0644]
Content.Shared/EntityEffects/Effects/CureZombieInfection.cs [new file with mode: 0644]
Content.Shared/EntityEffects/Effects/Drunk.cs [moved from Content.Server/EntityEffects/Effects/Drunk.cs with 91% similarity]
Content.Shared/EntityEffects/Effects/Electrocute.cs [moved from Content.Server/EntityEffects/Effects/Electrocute.cs with 78% similarity]
Content.Shared/EntityEffects/Effects/Emote.cs [moved from Content.Server/EntityEffects/Effects/Emote.cs with 70% similarity]
Content.Shared/EntityEffects/Effects/EmpReactionEffect.cs [new file with mode: 0644]
Content.Shared/EntityEffects/Effects/EvenHealthChange.cs [moved from Content.Server/EntityEffects/Effects/EvenHealthChange.cs with 98% similarity]
Content.Shared/EntityEffects/Effects/ExplosionReactionEffect.cs [moved from Content.Server/EntityEffects/Effects/ExplosionReactionEffect.cs with 74% similarity]
Content.Shared/EntityEffects/Effects/ExtinguishReaction.cs [moved from Content.Server/EntityEffects/Effects/ExtinguishReaction.cs with 88% similarity]
Content.Shared/EntityEffects/Effects/FlammableReaction.cs [new file with mode: 0644]
Content.Shared/EntityEffects/Effects/FlashReactionEffect.cs [new file with mode: 0644]
Content.Shared/EntityEffects/Effects/Glow.cs [moved from Content.Server/EntityEffects/Effects/Glow.cs with 96% similarity]
Content.Shared/EntityEffects/Effects/HealthChange.cs [moved from Content.Server/EntityEffects/Effects/HealthChange.cs with 98% similarity]
Content.Shared/EntityEffects/Effects/Ignite.cs [new file with mode: 0644]
Content.Shared/EntityEffects/Effects/MakeSentient.cs [new file with mode: 0644]
Content.Shared/EntityEffects/Effects/ModifyBleedAmount.cs [new file with mode: 0644]
Content.Shared/EntityEffects/Effects/ModifyBloodLevel.cs [new file with mode: 0644]
Content.Shared/EntityEffects/Effects/ModifyLungGas.cs [new file with mode: 0644]
Content.Shared/EntityEffects/Effects/MovespeedModifier.cs [moved from Content.Server/EntityEffects/Effects/MovespeedModifier.cs with 97% similarity]
Content.Shared/EntityEffects/Effects/Oxygenate.cs [new file with mode: 0644]
Content.Shared/EntityEffects/Effects/Paralyze.cs [moved from Content.Server/EntityEffects/Effects/Paralyze.cs with 79% similarity]
Content.Shared/EntityEffects/Effects/PlantMetabolism/PlantAdjustAttribute.cs [moved from Content.Server/EntityEffects/Effects/PlantMetabolism/PlantAdjustAttribute.cs with 51% similarity]
Content.Shared/EntityEffects/Effects/PlantMetabolism/PlantAdjustHealth.cs [new file with mode: 0644]
Content.Shared/EntityEffects/Effects/PlantMetabolism/PlantAdjustMutationLevel.cs [new file with mode: 0644]
Content.Shared/EntityEffects/Effects/PlantMetabolism/PlantAdjustMutationMod.cs [new file with mode: 0644]
Content.Shared/EntityEffects/Effects/PlantMetabolism/PlantAdjustNutrition.cs [new file with mode: 0644]
Content.Shared/EntityEffects/Effects/PlantMetabolism/PlantAdjustPests.cs [new file with mode: 0644]
Content.Shared/EntityEffects/Effects/PlantMetabolism/PlantAdjustPotency.cs [new file with mode: 0644]
Content.Shared/EntityEffects/Effects/PlantMetabolism/PlantAdjustToxins.cs [new file with mode: 0644]
Content.Shared/EntityEffects/Effects/PlantMetabolism/PlantAdjustWater.cs [new file with mode: 0644]
Content.Shared/EntityEffects/Effects/PlantMetabolism/PlantAdjustWeeds.cs [new file with mode: 0644]
Content.Shared/EntityEffects/Effects/PlantMetabolism/PlantAffectGrowth.cs [new file with mode: 0644]
Content.Shared/EntityEffects/Effects/PlantMetabolism/PlantChangeStat.cs [new file with mode: 0644]
Content.Shared/EntityEffects/Effects/PlantMetabolism/PlantCryoxadone.cs [new file with mode: 0644]
Content.Shared/EntityEffects/Effects/PlantMetabolism/PlantDestroySeeds.cs [new file with mode: 0644]
Content.Shared/EntityEffects/Effects/PlantMetabolism/PlantDiethylamine.cs [new file with mode: 0644]
Content.Shared/EntityEffects/Effects/PlantMetabolism/PlantPhalanximine.cs [new file with mode: 0644]
Content.Shared/EntityEffects/Effects/PlantMetabolism/PlantRestoreSeeds.cs [new file with mode: 0644]
Content.Shared/EntityEffects/Effects/PlantMetabolism/RobustHarvest.cs [new file with mode: 0644]
Content.Shared/EntityEffects/Effects/PlantMutateChemicals.cs [new file with mode: 0644]
Content.Shared/EntityEffects/Effects/PlantMutateGases.cs [new file with mode: 0644]
Content.Shared/EntityEffects/Effects/PlantMutateHarvest.cs [new file with mode: 0644]
Content.Shared/EntityEffects/Effects/PlantSpeciesChange.cs [new file with mode: 0644]
Content.Shared/EntityEffects/Effects/Polymorph.cs [moved from Content.Server/EntityEffects/Effects/Polymorph.cs with 55% similarity]
Content.Shared/EntityEffects/Effects/PopupMessage.cs [moved from Content.Server/EntityEffects/Effects/PopupMessage.cs with 95% similarity]
Content.Shared/EntityEffects/Effects/ReduceRotting.cs [new file with mode: 0644]
Content.Shared/EntityEffects/Effects/ResetNarcolepsy.cs [new file with mode: 0644]
Content.Shared/EntityEffects/Effects/SatiateHunger.cs [new file with mode: 0644]
Content.Shared/EntityEffects/Effects/SatiateThirst.cs [moved from Content.Server/EntityEffects/Effects/SatiateThirst.cs with 93% similarity]
Content.Shared/EntityEffects/Effects/Slipify.cs [moved from Content.Server/EntityEffects/Effects/Slipify.cs with 95% similarity]
Content.Shared/EntityEffects/Effects/SolutionTemperatureEffects.cs [moved from Content.Server/EntityEffects/Effects/SolutionTemperatureEffects.cs with 98% similarity]
Content.Shared/EntityEffects/Effects/StatusEffects/GenericStatusEffect.cs [moved from Content.Server/EntityEffects/Effects/StatusEffects/GenericStatusEffect.cs with 94% similarity]
Content.Shared/EntityEffects/Effects/StatusEffects/Jitter.cs [moved from Content.Server/EntityEffects/Effects/StatusEffects/Jitter.cs with 92% similarity]
Content.Shared/EntityEffects/Effects/WashCreamPieReaction.cs [moved from Content.Server/EntityEffects/Effects/WashCreamPieReaction.cs with 67% similarity]
Content.Shared/EntityEffects/Effects/WearableReaction.cs [moved from Content.Server/EntityEffects/Effects/WearableReaction.cs with 94% similarity]
Content.Shared/EntityEffects/EntityEffect.cs
Content.Shared/EntityEffects/EntityEffectCondition.cs
Content.Shared/EntityEffects/EventEntityEffect.cs [new file with mode: 0644]
Content.Shared/EntityEffects/EventEntityEffectCondition.cs [new file with mode: 0644]

index 6dc03fed744c4c050d76db582f83e33ff8647ab9..107299715137a0ab343f3a111584b1906aa030c4 100644 (file)
@@ -1,5 +1,5 @@
 using Content.Server.Body.Components;
-using Content.Server.EntityEffects.Effects;
+using Content.Shared.EntityEffects.Effects;
 using Content.Server.Fluids.EntitySystems;
 using Content.Server.Popups;
 using Content.Shared.Alert;
index bebf92f977611687b5c4bd7a2ddf6c0bab118c38..e068aa9c7a24cbfc70122f8fe6ea8f396023805b 100644 (file)
@@ -2,8 +2,9 @@ using Content.Server.Administration.Logs;
 using Content.Server.Atmos.EntitySystems;
 using Content.Server.Body.Components;
 using Content.Server.Chat.Systems;
-using Content.Server.EntityEffects.EffectConditions;
-using Content.Server.EntityEffects.Effects;
+using Content.Server.EntityEffects;
+using Content.Shared.EntityEffects.EffectConditions;
+using Content.Shared.EntityEffects.Effects;
 using Content.Shared.Chemistry.EntitySystems;
 using Content.Shared.Alert;
 using Content.Shared.Atmos;
@@ -35,6 +36,7 @@ public sealed class RespiratorSystem : EntitySystem
     [Dependency] private readonly IPrototypeManager _protoMan = default!;
     [Dependency] private readonly SharedSolutionContainerSystem _solutionContainerSystem = default!;
     [Dependency] private readonly ChatSystem _chat = default!;
+    [Dependency] private readonly EntityEffectSystem _entityEffect = default!;
 
     private static readonly ProtoId<MetabolismGroupPrototype> GasId = new("Gas");
 
@@ -283,7 +285,7 @@ public sealed class RespiratorSystem : EntitySystem
 
             foreach (var cond in effect.Conditions)
             {
-                if (cond is OrganType organ && !organ.Condition(lung, EntityManager))
+                if (cond is OrganType organ && !_entityEffect.OrganCondition(organ, lung))
                     return false;
             }
 
index 22021f1fabca8f7c397dfc3252190c0e2f53adf7..ae182cbe7e8862357c940132d0de09ad8fcd151b 100644 (file)
@@ -10,6 +10,8 @@ using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototy
 using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
 using Robust.Shared.Utility;
 
+using Content.Server.EntityEffects;
+
 namespace Content.Server.Botany;
 
 [Prototype]
@@ -82,7 +84,7 @@ public partial struct SeedChemQuantity
 
 // TODO reduce the number of friends to a reasonable level. Requires ECS-ing things like plant holder component.
 [Virtual, DataDefinition]
-[Access(typeof(BotanySystem), typeof(PlantHolderSystem), typeof(SeedExtractorSystem), typeof(PlantHolderComponent), typeof(EntityEffect), typeof(MutationSystem))]
+[Access(typeof(BotanySystem), typeof(PlantHolderSystem), typeof(SeedExtractorSystem), typeof(PlantHolderComponent), typeof(EntityEffectSystem), typeof(MutationSystem))]
 public partial class SeedData
 {
     #region Tracking
diff --git a/Content.Server/EntityEffects/EffectConditions/BreathingCondition.cs b/Content.Server/EntityEffects/EffectConditions/BreathingCondition.cs
deleted file mode 100644 (file)
index d87e686..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-using Content.Server.Body.Components;
-using Content.Server.Body.Systems;
-using Content.Shared.EntityEffects;
-using Robust.Shared.Prototypes;
-
-namespace Content.Server.EntityEffects.EffectConditions;
-
-/// <summary>
-///     Condition for if the entity is successfully breathing.
-/// </summary>
-public sealed partial class Breathing : EntityEffectCondition
-{
-    /// <summary>
-    ///     If true, the entity must not have trouble breathing to pass.
-    /// </summary>
-    [DataField]
-    public bool IsBreathing = true;
-
-    public override bool Condition(EntityEffectBaseArgs args)
-    {
-        if (!args.EntityManager.TryGetComponent(args.TargetEntity, out RespiratorComponent? respiratorComp))
-            return !IsBreathing; // They do not breathe.
-
-        var breathingState = args.EntityManager.System<RespiratorSystem>().IsBreathing((args.TargetEntity, respiratorComp));
-        return IsBreathing == breathingState;
-    }
-
-    public override string GuidebookExplanation(IPrototypeManager prototype)
-    {
-        return Loc.GetString("reagent-effect-condition-guidebook-breathing",
-                            ("isBreathing", IsBreathing));
-    }
-}
diff --git a/Content.Server/EntityEffects/EffectConditions/OrganType.cs b/Content.Server/EntityEffects/EffectConditions/OrganType.cs
deleted file mode 100644 (file)
index fc52608..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-using Content.Server.Body.Components;
-using Content.Shared.Body.Prototypes;
-using Content.Shared.EntityEffects;
-using Robust.Shared.Prototypes;
-using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
-
-namespace Content.Server.EntityEffects.EffectConditions;
-
-/// <summary>
-///     Requires that the metabolizing organ is or is not tagged with a certain MetabolizerType
-/// </summary>
-public sealed partial class OrganType : EntityEffectCondition
-{
-    [DataField(required: true, customTypeSerializer: typeof(PrototypeIdSerializer<MetabolizerTypePrototype>))]
-    public string Type = default!;
-
-    /// <summary>
-    ///     Does this condition pass when the organ has the type, or when it doesn't have the type?
-    /// </summary>
-    [DataField]
-    public bool ShouldHave = true;
-
-    public override bool Condition(EntityEffectBaseArgs args)
-    {
-        if (args is EntityEffectReagentArgs reagentArgs)
-        {
-            if (reagentArgs.OrganEntity == null)
-                return false;
-
-            return Condition(reagentArgs.OrganEntity.Value, reagentArgs.EntityManager);
-        }
-
-        // TODO: Someone needs to figure out how to do this for non-reagent effects.
-        throw new NotImplementedException();
-    }
-
-    public bool Condition(Entity<MetabolizerComponent?> metabolizer, IEntityManager entMan)
-    {
-        metabolizer.Comp ??= entMan.GetComponentOrNull<MetabolizerComponent>(metabolizer.Owner);
-        if (metabolizer.Comp != null
-            && metabolizer.Comp.MetabolizerTypes != null
-            && metabolizer.Comp.MetabolizerTypes.Contains(Type))
-            return ShouldHave;
-        return !ShouldHave;
-    }
-
-    public override string GuidebookExplanation(IPrototypeManager prototype)
-    {
-        return Loc.GetString("reagent-effect-condition-guidebook-organ-type",
-            ("name", prototype.Index<MetabolizerTypePrototype>(Type).LocalizedName),
-            ("shouldhave", ShouldHave));
-    }
-}
diff --git a/Content.Server/EntityEffects/Effects/AdjustTemperature.cs b/Content.Server/EntityEffects/Effects/AdjustTemperature.cs
deleted file mode 100644 (file)
index 3c5c77c..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-using Content.Server.Temperature.Components;
-using Content.Server.Temperature.Systems;
-using Content.Shared.EntityEffects;
-using Robust.Shared.Prototypes;
-
-namespace Content.Server.EntityEffects.Effects
-{
-    public sealed partial class AdjustTemperature : EntityEffect
-    {
-        [DataField]
-        public float Amount;
-
-        protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
-            => Loc.GetString("reagent-effect-guidebook-adjust-temperature",
-                ("chance", Probability),
-                ("deltasign", MathF.Sign(Amount)),
-                ("amount", MathF.Abs(Amount)));
-
-        public override void Effect(EntityEffectBaseArgs args)
-        {
-            if (args.EntityManager.TryGetComponent(args.TargetEntity, out TemperatureComponent? temp))
-            {
-                var sys = args.EntityManager.EntitySysManager.GetEntitySystem<TemperatureSystem>();
-                var amount = Amount;
-
-                if (args is EntityEffectReagentArgs reagentArgs)
-                {
-                    amount *= reagentArgs.Scale.Float();
-                }
-
-                sys.ChangeHeat(args.TargetEntity, amount, true, temp);
-            }
-        }
-    }
-}
diff --git a/Content.Server/EntityEffects/Effects/AreaReactionEffect.cs b/Content.Server/EntityEffects/Effects/AreaReactionEffect.cs
deleted file mode 100644 (file)
index ce06705..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-using Content.Server.Fluids.EntitySystems;
-using Content.Server.Spreader;
-using Content.Shared.Audio;
-using Content.Shared.Coordinates.Helpers;
-using Content.Shared.Database;
-using Content.Shared.EntityEffects;
-using Content.Shared.FixedPoint;
-using Content.Shared.Maps;
-using JetBrains.Annotations;
-using Robust.Server.GameObjects;
-using Robust.Shared.Audio;
-using Robust.Shared.Audio.Systems;
-using Robust.Shared.Map;
-using Robust.Shared.Prototypes;
-using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
-
-namespace Content.Server.EntityEffects.Effects;
-
-/// <summary>
-/// Basically smoke and foam reactions.
-/// </summary>
-[UsedImplicitly]
-[DataDefinition]
-public sealed partial class AreaReactionEffect : EntityEffect
-{
-    /// <summary>
-    /// How many seconds will the effect stay, counting after fully spreading.
-    /// </summary>
-    [DataField("duration")] private float _duration = 10;
-
-    /// <summary>
-    /// How many units of reaction for 1 smoke entity.
-    /// </summary>
-    [DataField] public FixedPoint2 OverflowThreshold = FixedPoint2.New(2.5);
-
-    /// <summary>
-    /// The entity prototype that will be spawned as the effect.
-    /// </summary>
-    [DataField("prototypeId", required: true, customTypeSerializer:typeof(PrototypeIdSerializer<EntityPrototype>))]
-    private string _prototypeId = default!;
-
-    /// <summary>
-    /// Sound that will get played when this reaction effect occurs.
-    /// </summary>
-    [DataField("sound", required: true)] private SoundSpecifier _sound = default!;
-
-    public override bool ShouldLog => true;
-
-    protected override string ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
-            => Loc.GetString("reagent-effect-guidebook-area-reaction",
-                    ("duration", _duration)
-                );
-
-    public override LogImpact LogImpact => LogImpact.High;
-
-    public override void Effect(EntityEffectBaseArgs args)
-    {
-        if (args is EntityEffectReagentArgs reagentArgs)
-        {
-            if (reagentArgs.Source == null)
-                return;
-
-            var spreadAmount = (int) Math.Max(0, Math.Ceiling((reagentArgs.Quantity / OverflowThreshold).Float()));
-            var splitSolution = reagentArgs.Source.SplitSolution(reagentArgs.Source.Volume);
-            var transform = reagentArgs.EntityManager.GetComponent<TransformComponent>(reagentArgs.TargetEntity);
-            var mapManager = IoCManager.Resolve<IMapManager>();
-            var mapSys = reagentArgs.EntityManager.System<MapSystem>();
-            var spreaderSys = args.EntityManager.System<SpreaderSystem>();
-            var sys = args.EntityManager.System<TransformSystem>();
-            var mapCoords = sys.GetMapCoordinates(reagentArgs.TargetEntity, xform: transform);
-
-            if (!mapManager.TryFindGridAt(mapCoords, out var gridUid, out var grid) ||
-                !mapSys.TryGetTileRef(gridUid, grid, transform.Coordinates, out var tileRef))
-            {
-                return;
-            }
-
-            if (spreaderSys.RequiresFloorToSpread(_prototypeId) && tileRef.Tile.IsSpace())
-                return;
-
-            var coords = mapSys.MapToGrid(gridUid, mapCoords);
-            var ent = reagentArgs.EntityManager.SpawnEntity(_prototypeId, coords.SnapToGrid());
-
-            var smoke = reagentArgs.EntityManager.System<SmokeSystem>();
-            smoke.StartSmoke(ent, splitSolution, _duration, spreadAmount);
-
-            var audio = reagentArgs.EntityManager.System<SharedAudioSystem>();
-            audio.PlayPvs(_sound, reagentArgs.TargetEntity, AudioParams.Default.WithVariation(0.25f));
-            return;
-        }
-
-        // TODO: Someone needs to figure out how to do this for non-reagent effects.
-        throw new NotImplementedException();
-    }
-}
diff --git a/Content.Server/EntityEffects/Effects/CauseZombieInfection.cs b/Content.Server/EntityEffects/Effects/CauseZombieInfection.cs
deleted file mode 100644 (file)
index b71e6a3..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-using Content.Server.Zombies;
-using Content.Shared.EntityEffects;
-using Robust.Shared.Prototypes;
-using Content.Shared.Zombies;
-
-namespace Content.Server.EntityEffects.Effects;
-
-public sealed partial class CauseZombieInfection : EntityEffect
-{
-    protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
-        => Loc.GetString("reagent-effect-guidebook-cause-zombie-infection", ("chance", Probability));
-
-    // Adds the Zombie Infection Components
-    public override void Effect(EntityEffectBaseArgs args)
-    {
-        var entityManager = args.EntityManager;
-        entityManager.EnsureComponent<ZombifyOnDeathComponent>(args.TargetEntity);
-        entityManager.EnsureComponent<PendingZombieComponent>(args.TargetEntity);
-    }
-}
-
diff --git a/Content.Server/EntityEffects/Effects/ChemCleanBloodstream.cs b/Content.Server/EntityEffects/Effects/ChemCleanBloodstream.cs
deleted file mode 100644 (file)
index b7f6f0d..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-using Content.Server.Body.Systems;
-using Content.Shared.EntityEffects;
-using JetBrains.Annotations;
-using Robust.Shared.Prototypes;
-
-namespace Content.Server.EntityEffects.Effects;
-
-/// <summary>
-/// Basically smoke and foam reactions.
-/// </summary>
-[UsedImplicitly]
-public sealed partial class ChemCleanBloodstream : EntityEffect
-{
-    [DataField]
-    public float CleanseRate = 3.0f;
-
-    protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
-        => Loc.GetString("reagent-effect-guidebook-chem-clean-bloodstream", ("chance", Probability));
-
-    public override void Effect(EntityEffectBaseArgs args)
-    {
-        
-        var cleanseRate = CleanseRate;
-
-        var bloodstreamSys = args.EntityManager.System<BloodstreamSystem>();
-
-        if (args is EntityEffectReagentArgs reagentArgs)
-        {
-            if (reagentArgs.Source == null || reagentArgs.Reagent == null)
-                return;
-
-            cleanseRate *= reagentArgs.Scale.Float();
-            bloodstreamSys.FlushChemicals(args.TargetEntity, reagentArgs.Reagent.ID, cleanseRate);
-        }
-        else
-        {
-            bloodstreamSys.FlushChemicals(args.TargetEntity, "", cleanseRate);
-        }
-    }
-}
diff --git a/Content.Server/EntityEffects/Effects/ChemVomit.cs b/Content.Server/EntityEffects/Effects/ChemVomit.cs
deleted file mode 100644 (file)
index 0d1bac8..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-using Content.Server.Medical;
-using Content.Shared.EntityEffects;
-using JetBrains.Annotations;
-using Robust.Shared.Prototypes;
-
-namespace Content.Server.EntityEffects.Effects
-{
-    /// <summary>
-    /// Forces you to vomit.
-    /// </summary>
-    [UsedImplicitly]
-    public sealed partial class ChemVomit : EntityEffect
-    {
-        /// How many units of thirst to add each time we vomit
-        [DataField]
-        public float ThirstAmount = -8f;
-        /// How many units of hunger to add each time we vomit
-        [DataField]
-        public float HungerAmount = -8f;
-
-        protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
-            => Loc.GetString("reagent-effect-guidebook-chem-vomit", ("chance", Probability));
-
-        public override void Effect(EntityEffectBaseArgs args)
-        {
-            if (args is EntityEffectReagentArgs reagentArgs)
-                if (reagentArgs.Scale != 1f)
-                    return;
-
-            var vomitSys = args.EntityManager.EntitySysManager.GetEntitySystem<VomitSystem>();
-
-            vomitSys.Vomit(args.TargetEntity, ThirstAmount, HungerAmount);
-        }
-    }
-}
diff --git a/Content.Server/EntityEffects/Effects/CreateEntityReactionEffect.cs b/Content.Server/EntityEffects/Effects/CreateEntityReactionEffect.cs
deleted file mode 100644 (file)
index 5288cb5..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-using Content.Shared.EntityEffects;
-using Robust.Shared.Prototypes;
-using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
-
-namespace Content.Server.EntityEffects.Effects;
-
-[DataDefinition]
-public sealed partial class CreateEntityReactionEffect : EntityEffect
-{
-    /// <summary>
-    ///     What entity to create.
-    /// </summary>
-    [DataField(required: true, customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
-    public string Entity = default!;
-
-    /// <summary>
-    ///     How many entities to create per unit reaction.
-    /// </summary>
-    [DataField]
-    public uint Number = 1;
-
-    protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
-        => Loc.GetString("reagent-effect-guidebook-create-entity-reaction-effect",
-            ("chance", Probability),
-            ("entname", IoCManager.Resolve<IPrototypeManager>().Index<EntityPrototype>(Entity).Name),
-            ("amount", Number));
-
-    public override void Effect(EntityEffectBaseArgs args)
-    {
-        var transform = args.EntityManager.GetComponent<TransformComponent>(args.TargetEntity);
-        var transformSystem = args.EntityManager.System<SharedTransformSystem>();
-        var quantity = (int)Number;
-        if (args is EntityEffectReagentArgs reagentArgs)
-            quantity *= reagentArgs.Quantity.Int();
-
-        for (var i = 0; i < quantity; i++)
-        {
-            var uid = args.EntityManager.SpawnEntity(Entity, transformSystem.GetMapCoordinates(args.TargetEntity, xform: transform));
-            transformSystem.AttachToGridOrMap(uid);
-
-            // TODO figure out how to properly spawn inside of containers
-            // e.g. cheese:
-            // if the user is holding a bowl milk & enzyme, should drop to floor, not attached to the user.
-            // if reaction happens in a backpack, should insert cheese into backpack.
-            // --> if it doesn't fit, iterate through parent storage until it attaches to the grid (again, DON'T attach to players).
-            // if the reaction happens INSIDE a stomach? the bloodstream? I have no idea how to handle that.
-            // presumably having cheese materialize inside of your blood would have "disadvantages".
-        }
-    }
-}
diff --git a/Content.Server/EntityEffects/Effects/CreateGas.cs b/Content.Server/EntityEffects/Effects/CreateGas.cs
deleted file mode 100644 (file)
index fb57a43..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-using Content.Server.Atmos.EntitySystems;
-using Content.Shared.Atmos;
-using Content.Shared.Database;
-using Content.Shared.EntityEffects;
-using Robust.Shared.Prototypes;
-
-namespace Content.Server.EntityEffects.Effects;
-
-public sealed partial class CreateGas : EntityEffect
-{
-    [DataField(required: true)]
-    public Gas Gas = default!;
-
-    /// <summary>
-    ///     For each unit consumed, how many moles of gas should be created?
-    /// </summary>
-    [DataField]
-    public float Multiplier = 3f;
-
-    public override bool ShouldLog => true;
-    protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
-    {
-        var atmos = entSys.GetEntitySystem<AtmosphereSystem>();
-        var gasProto = atmos.GetGas(Gas);
-
-        return Loc.GetString("reagent-effect-guidebook-create-gas",
-            ("chance", Probability),
-            ("moles", Multiplier),
-            ("gas", gasProto.Name));
-    }
-
-    public override LogImpact LogImpact => LogImpact.High;
-
-    public override void Effect(EntityEffectBaseArgs args)
-    {
-        var atmosSys = args.EntityManager.EntitySysManager.GetEntitySystem<AtmosphereSystem>();
-
-        var tileMix = atmosSys.GetContainingMixture(args.TargetEntity, false, true);
-
-        if (tileMix != null)
-        {
-            if (args is EntityEffectReagentArgs reagentArgs)
-            {
-                tileMix.AdjustMoles(Gas, reagentArgs.Quantity.Float() * Multiplier);
-            }
-            else
-            {
-                tileMix.AdjustMoles(Gas, Multiplier);
-            }
-        }
-    }
-}
diff --git a/Content.Server/EntityEffects/Effects/CureZombieInfection.cs b/Content.Server/EntityEffects/Effects/CureZombieInfection.cs
deleted file mode 100644 (file)
index 8dfc2de..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-using Content.Server.Zombies;
-using Content.Shared.EntityEffects;
-using Robust.Shared.Prototypes;
-using Content.Shared.Zombies;
-
-namespace Content.Server.EntityEffects.Effects;
-
-public sealed partial class CureZombieInfection : EntityEffect
-{
-    [DataField]
-    public bool Innoculate;
-
-    protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
-    {
-        if(Innoculate)
-            return Loc.GetString("reagent-effect-guidebook-innoculate-zombie-infection", ("chance", Probability));
-
-        return Loc.GetString("reagent-effect-guidebook-cure-zombie-infection", ("chance", Probability));
-    }
-
-    // Removes the Zombie Infection Components
-    public override void Effect(EntityEffectBaseArgs args)
-    {
-        var entityManager = args.EntityManager;
-        if (entityManager.HasComponent<IncurableZombieComponent>(args.TargetEntity))
-            return;
-
-        entityManager.RemoveComponent<ZombifyOnDeathComponent>(args.TargetEntity);
-        entityManager.RemoveComponent<PendingZombieComponent>(args.TargetEntity);
-
-        if (Innoculate)
-        {
-            entityManager.EnsureComponent<ZombieImmuneComponent>(args.TargetEntity);
-        }
-    }
-}
-
diff --git a/Content.Server/EntityEffects/Effects/EmpReactionEffect.cs b/Content.Server/EntityEffects/Effects/EmpReactionEffect.cs
deleted file mode 100644 (file)
index ec7801f..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-using Content.Server.Emp;
-using Content.Shared.EntityEffects;
-using Content.Shared.Chemistry.Reagent;
-using Robust.Server.GameObjects;
-using Robust.Shared.Prototypes;
-
-namespace Content.Server.EntityEffects.Effects;
-
-
-[DataDefinition]
-public sealed partial class EmpReactionEffect : EntityEffect
-{
-    /// <summary>
-    ///     Impulse range per unit of quantity
-    /// </summary>
-    [DataField("rangePerUnit")]
-    public float EmpRangePerUnit = 0.5f;
-
-    /// <summary>
-    ///     Maximum impulse range
-    /// </summary>
-    [DataField("maxRange")]
-    public float EmpMaxRange = 10;
-
-    /// <summary>
-    ///     How much energy will be drain from sources
-    /// </summary>
-    [DataField]
-    public float EnergyConsumption = 12500;
-
-    /// <summary>
-    ///     Amount of time entities will be disabled
-    /// </summary>
-    [DataField("duration")]
-    public float DisableDuration = 15;
-
-    protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
-            => Loc.GetString("reagent-effect-guidebook-emp-reaction-effect", ("chance", Probability));
-
-    public override void Effect(EntityEffectBaseArgs args)
-    {
-        var tSys = args.EntityManager.System<TransformSystem>();
-        var transform = args.EntityManager.GetComponent<TransformComponent>(args.TargetEntity);
-
-        var range = EmpRangePerUnit;
-
-        if (args is EntityEffectReagentArgs reagentArgs)
-        {
-            range = MathF.Min((float) (reagentArgs.Quantity * EmpRangePerUnit), EmpMaxRange);
-        }
-
-        args.EntityManager.System<EmpSystem>()
-            .EmpPulse(tSys.GetMapCoordinates(args.TargetEntity, xform: transform),
-            range,
-            EnergyConsumption,
-            DisableDuration);
-    }
-}
diff --git a/Content.Server/EntityEffects/Effects/FlammableReaction.cs b/Content.Server/EntityEffects/Effects/FlammableReaction.cs
deleted file mode 100644 (file)
index 8e1f6d8..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-using Content.Server.Atmos.Components;
-using Content.Server.Atmos.EntitySystems;
-using Content.Shared.Database;
-using Content.Shared.EntityEffects;
-using JetBrains.Annotations;
-using Robust.Shared.Prototypes;
-
-namespace Content.Server.EntityEffects.Effects
-{
-    [UsedImplicitly]
-    public sealed partial class FlammableReaction : EntityEffect
-    {
-        [DataField]
-        public float Multiplier = 0.05f;
-
-        // The fire stack multiplier if fire stacks already exist on target, only works if 0 or greater
-        [DataField]
-        public float MultiplierOnExisting = -1f;
-
-        public override bool ShouldLog => true;
-
-        protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
-            => Loc.GetString("reagent-effect-guidebook-flammable-reaction", ("chance", Probability));
-
-        public override LogImpact LogImpact => LogImpact.Medium;
-
-        public override void Effect(EntityEffectBaseArgs args)
-        {
-            if (!args.EntityManager.TryGetComponent(args.TargetEntity, out FlammableComponent? flammable))
-                return;
-
-            // Sets the multiplier for FireStacks to MultiplierOnExisting is 0 or greater and target already has FireStacks
-            var multiplier = flammable.FireStacks != 0f && MultiplierOnExisting >= 0 ? MultiplierOnExisting : Multiplier;
-            var quantity = 1f;
-            if (args is EntityEffectReagentArgs reagentArgs)
-            {
-                quantity = reagentArgs.Quantity.Float();
-                reagentArgs.EntityManager.System<FlammableSystem>().AdjustFireStacks(args.TargetEntity, quantity * multiplier, flammable);
-                if (reagentArgs.Reagent != null)
-                    reagentArgs.Source?.RemoveReagent(reagentArgs.Reagent.ID, reagentArgs.Quantity);
-            }
-            else
-            {
-                args.EntityManager.System<FlammableSystem>().AdjustFireStacks(args.TargetEntity, multiplier, flammable);
-            }
-        }
-    }
-}
diff --git a/Content.Server/EntityEffects/Effects/FlashReactionEffect.cs b/Content.Server/EntityEffects/Effects/FlashReactionEffect.cs
deleted file mode 100644 (file)
index fbf99e9..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-using Content.Shared.EntityEffects;
-using Content.Server.Flash;
-using Robust.Server.GameObjects;
-using Robust.Shared.Audio;
-using Robust.Shared.Prototypes;
-
-namespace Content.Server.EntityEffects.Effects;
-
-[DataDefinition]
-public sealed partial class FlashReactionEffect : EntityEffect
-{
-    /// <summary>
-    ///     Flash range per unit of reagent.
-    /// </summary>
-    [DataField]
-    public float RangePerUnit = 0.2f;
-
-    /// <summary>
-    ///     Maximum flash range.
-    /// </summary>
-    [DataField]
-    public float MaxRange = 10f;
-
-    /// <summary>
-    ///     How much to entities are slowed down.
-    /// </summary>
-    [DataField]
-    public float SlowTo = 0.5f;
-
-    /// <summary>
-    ///     The time entities will be flashed in seconds.
-    ///     The default is chosen to be better than the hand flash so it is worth using it for grenades etc.
-    /// </summary>
-    [DataField]
-    public float Duration = 4f;
-
-    /// <summary>
-    ///     The prototype ID used for the visual effect.
-    /// </summary>
-    [DataField]
-    public EntProtoId? FlashEffectPrototype = "ReactionFlash";
-
-    /// <summary>
-    ///     The sound the flash creates.
-    /// </summary>
-    [DataField]
-    public SoundSpecifier? Sound = new SoundPathSpecifier("/Audio/Weapons/flash.ogg");
-
-    protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
-        => Loc.GetString("reagent-effect-guidebook-flash-reaction-effect", ("chance", Probability));
-
-    public override void Effect(EntityEffectBaseArgs args)
-    {
-        var transform = args.EntityManager.GetComponent<TransformComponent>(args.TargetEntity);
-        var transformSystem = args.EntityManager.System<SharedTransformSystem>();
-
-        var range = 1f;
-
-        if (args is EntityEffectReagentArgs reagentArgs)
-            range = MathF.Min((float)(reagentArgs.Quantity * RangePerUnit), MaxRange);
-
-        args.EntityManager.System<FlashSystem>().FlashArea(
-            args.TargetEntity,
-            null,
-            range,
-            Duration * 1000,
-            slowTo: SlowTo,
-            sound: Sound);
-
-        if (FlashEffectPrototype == null)
-            return;
-
-        var uid = args.EntityManager.SpawnEntity(FlashEffectPrototype, transformSystem.GetMapCoordinates(transform));
-        transformSystem.AttachToGridOrMap(uid);
-
-        if (!args.EntityManager.TryGetComponent<PointLightComponent>(uid, out var pointLightComp))
-            return;
-        var pointLightSystem = args.EntityManager.System<SharedPointLightSystem>();
-        // PointLights with a radius lower than 1.1 are too small to be visible, so this is hardcoded
-        pointLightSystem.SetRadius(uid, MathF.Max(1.1f, range), pointLightComp);
-    }
-}
diff --git a/Content.Server/EntityEffects/Effects/Ignite.cs b/Content.Server/EntityEffects/Effects/Ignite.cs
deleted file mode 100644 (file)
index 85d7f09..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-using Content.Server.Atmos.Components;
-using Content.Server.Atmos.EntitySystems;
-using Content.Shared.Database;
-using Content.Shared.EntityEffects;
-using Robust.Shared.Prototypes;
-
-namespace Content.Server.EntityEffects.Effects;
-
-/// <summary>
-///     Ignites a mob.
-/// </summary>
-public sealed partial class Ignite : EntityEffect
-{
-    public override bool ShouldLog => true;
-
-    protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
-        => Loc.GetString("reagent-effect-guidebook-ignite", ("chance", Probability));
-
-    public override LogImpact LogImpact => LogImpact.Medium;
-
-    public override void Effect(EntityEffectBaseArgs args)
-    {
-        if (!args.EntityManager.TryGetComponent(args.TargetEntity, out FlammableComponent? flammable))
-            return;
-
-        var flamSys = args.EntityManager.System<FlammableSystem>();
-        if (args is EntityEffectReagentArgs reagentArgs)
-        {
-            flamSys.Ignite(reagentArgs.TargetEntity, reagentArgs.OrganEntity ?? reagentArgs.TargetEntity, flammable: flammable);
-        }
-        else
-        {
-            flamSys.Ignite(args.TargetEntity, args.TargetEntity, flammable: flammable);
-        }
-    }
-}
diff --git a/Content.Server/EntityEffects/Effects/MakeSentient.cs b/Content.Server/EntityEffects/Effects/MakeSentient.cs
deleted file mode 100644 (file)
index c487043..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-using Content.Server.Ghost.Roles.Components;
-using Content.Server.Speech.Components;
-using Content.Shared.EntityEffects;
-using Content.Shared.Mind.Components;
-using Robust.Shared.Prototypes;
-
-namespace Content.Server.EntityEffects.Effects;
-
-public sealed partial class MakeSentient : EntityEffect
-{
-    protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
-        => Loc.GetString("reagent-effect-guidebook-make-sentient", ("chance", Probability));
-
-    public override void Effect(EntityEffectBaseArgs args)
-    {
-        var entityManager = args.EntityManager;
-        var uid = args.TargetEntity;
-
-        // Let affected entities speak normally to make this effect different from, say, the "random sentience" event
-        // This also works on entities that already have a mind
-        // We call this before the mind check to allow things like player-controlled mice to be able to benefit from the effect
-        entityManager.RemoveComponent<ReplacementAccentComponent>(uid);
-        entityManager.RemoveComponent<MonkeyAccentComponent>(uid);
-
-        // Stops from adding a ghost role to things like people who already have a mind
-        if (entityManager.TryGetComponent<MindContainerComponent>(uid, out var mindContainer) && mindContainer.HasMind)
-        {
-            return;
-        }
-
-        // Don't add a ghost role to things that already have ghost roles
-        if (entityManager.TryGetComponent(uid, out GhostRoleComponent? ghostRole))
-        {
-            return;
-        }
-
-        ghostRole = entityManager.AddComponent<GhostRoleComponent>(uid);
-        entityManager.EnsureComponent<GhostTakeoverAvailableComponent>(uid);
-
-        var entityData = entityManager.GetComponent<MetaDataComponent>(uid);
-        ghostRole.RoleName = entityData.EntityName;
-        ghostRole.RoleDescription = Loc.GetString("ghost-role-information-cognizine-description");
-    }
-}
diff --git a/Content.Server/EntityEffects/Effects/ModifyBleedAmount.cs b/Content.Server/EntityEffects/Effects/ModifyBleedAmount.cs
deleted file mode 100644 (file)
index 58bc304..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-using Content.Server.Body.Components;
-using Content.Server.Body.Systems;
-using Content.Shared.EntityEffects;
-using Robust.Shared.Prototypes;
-
-namespace Content.Server.EntityEffects.Effects;
-
-public sealed partial class ModifyBleedAmount : EntityEffect
-{
-    [DataField]
-    public bool Scaled = false;
-
-    [DataField]
-    public float Amount = -1.0f;
-
-    protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
-        => Loc.GetString("reagent-effect-guidebook-modify-bleed-amount", ("chance", Probability),
-            ("deltasign", MathF.Sign(Amount)));
-
-    public override void Effect(EntityEffectBaseArgs args)
-    {
-        if (args.EntityManager.TryGetComponent<BloodstreamComponent>(args.TargetEntity, out var blood))
-        {
-            var sys = args.EntityManager.System<BloodstreamSystem>();
-            var amt = Amount;
-            if (args is EntityEffectReagentArgs reagentArgs) {
-                if (Scaled)
-                    amt *= reagentArgs.Quantity.Float();
-                amt *= reagentArgs.Scale.Float();
-            }
-
-            sys.TryModifyBleedAmount(args.TargetEntity, amt, blood);
-        }
-    }
-}
diff --git a/Content.Server/EntityEffects/Effects/ModifyBloodLevel.cs b/Content.Server/EntityEffects/Effects/ModifyBloodLevel.cs
deleted file mode 100644 (file)
index d8aca7d..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-using Content.Server.Body.Components;
-using Content.Server.Body.Systems;
-using Content.Shared.EntityEffects;
-using Content.Shared.FixedPoint;
-using Robust.Shared.Prototypes;
-
-namespace Content.Server.EntityEffects.Effects;
-
-public sealed partial class ModifyBloodLevel : EntityEffect
-{
-    [DataField]
-    public bool Scaled = false;
-
-    [DataField]
-    public FixedPoint2 Amount = 1.0f;
-
-    protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
-        => Loc.GetString("reagent-effect-guidebook-modify-blood-level", ("chance", Probability),
-            ("deltasign", MathF.Sign(Amount.Float())));
-
-    public override void Effect(EntityEffectBaseArgs args)
-    {
-        if (args.EntityManager.TryGetComponent<BloodstreamComponent>(args.TargetEntity, out var blood))
-        {
-            var sys = args.EntityManager.System<BloodstreamSystem>();
-            var amt = Amount;
-            if (args is EntityEffectReagentArgs reagentArgs)
-            {
-                if (Scaled)
-                    amt *= reagentArgs.Quantity;
-                amt *= reagentArgs.Scale;
-            }
-
-            sys.TryModifyBloodLevel(args.TargetEntity, amt, blood);
-        }
-    }
-}
diff --git a/Content.Server/EntityEffects/Effects/ModifyLungGas.cs b/Content.Server/EntityEffects/Effects/ModifyLungGas.cs
deleted file mode 100644 (file)
index b752cd9..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-using Content.Server.Body.Components;
-using Content.Shared.Atmos;
-using Content.Shared.EntityEffects;
-using Robust.Shared.Prototypes;
-
-namespace Content.Server.EntityEffects.Effects;
-
-public sealed partial class ModifyLungGas : EntityEffect
-{
-    [DataField("ratios", required: true)]
-    private Dictionary<Gas, float> _ratios = default!;
-
-    // JUSTIFICATION: This is internal magic that players never directly interact with.
-    protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
-        => null;
-
-    public override void Effect(EntityEffectBaseArgs args)
-    {
-
-        LungComponent? lung;
-        float amount = 1f;
-
-        if (args is EntityEffectReagentArgs reagentArgs)
-        {
-            if (!args.EntityManager.TryGetComponent<LungComponent>(reagentArgs.OrganEntity, out var organLung))
-                return;
-            lung = organLung;
-            amount = reagentArgs.Quantity.Float();
-        }
-        else
-        {
-            if (!args.EntityManager.TryGetComponent<LungComponent>(args.TargetEntity, out var organLung)) //Likely needs to be modified to ensure it works correctly
-                return;
-            lung = organLung;
-        }
-
-        if (lung != null)
-        {
-            foreach (var (gas, ratio) in _ratios)
-            {
-                var quantity = ratio * amount / Atmospherics.BreathMolesToReagentMultiplier;
-                if (quantity < 0)
-                    quantity = Math.Max(quantity, -lung.Air[(int) gas]);
-                lung.Air.AdjustMoles(gas, quantity);
-            }
-        }
-    }
-}
diff --git a/Content.Server/EntityEffects/Effects/Oxygenate.cs b/Content.Server/EntityEffects/Effects/Oxygenate.cs
deleted file mode 100644 (file)
index 6038318..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-using Content.Server.Body.Components;
-using Content.Server.Body.Systems;
-using Content.Shared.EntityEffects;
-using Robust.Shared.Prototypes;
-
-namespace Content.Server.EntityEffects.Effects;
-
-public sealed partial class Oxygenate : EntityEffect
-{
-    [DataField]
-    public float Factor = 1f;
-
-    // JUSTIFICATION: This is internal magic that players never directly interact with.
-    protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
-        => null;
-
-    public override void Effect(EntityEffectBaseArgs args)
-    {
-
-        var multiplier = 1f;
-        if (args is EntityEffectReagentArgs reagentArgs)
-        {
-            multiplier = reagentArgs.Quantity.Float();
-        }
-
-        if (args.EntityManager.TryGetComponent<RespiratorComponent>(args.TargetEntity, out var resp))
-        {
-            var respSys = args.EntityManager.System<RespiratorSystem>();
-            respSys.UpdateSaturation(args.TargetEntity, multiplier * Factor, resp);
-        }
-    }
-}
diff --git a/Content.Server/EntityEffects/Effects/PlantChangeStat.cs b/Content.Server/EntityEffects/Effects/PlantChangeStat.cs
deleted file mode 100644 (file)
index 9592ff7..0000000
+++ /dev/null
@@ -1,142 +0,0 @@
-using Content.Server.Botany;
-using Content.Server.Botany.Components;
-using Content.Shared.EntityEffects;
-using JetBrains.Annotations;
-using Robust.Shared.Prototypes;
-using Robust.Shared.Random;
-
-namespace Content.Server.EntityEffects.Effects.PlantMetabolism;
-
-[UsedImplicitly]
-public sealed partial class PlantChangeStat : EntityEffect
-{
-    [DataField]
-    public string TargetValue;
-
-    [DataField]
-    public float MinValue;
-
-    [DataField]
-    public float MaxValue;
-
-    [DataField]
-    public int Steps;
-
-    public override void Effect(EntityEffectBaseArgs args)
-    {
-        var plantHolder = args.EntityManager.GetComponent<PlantHolderComponent>(args.TargetEntity);
-        if (plantHolder == null || plantHolder.Seed == null)
-            return;
-
-        var member = plantHolder.Seed.GetType().GetField(TargetValue);
-        var mutationSys = args.EntityManager.System<MutationSystem>();
-
-        if (member == null)
-        {
-            mutationSys.Log.Error(this.GetType().Name + " Error: Member " + TargetValue + " not found on " + plantHolder.GetType().Name + ". Did you misspell it?");
-            return;
-        }
-
-        var currentValObj = member.GetValue(plantHolder.Seed);
-        if (currentValObj == null)
-            return;
-
-        if (member.FieldType == typeof(float))
-        {
-            var floatVal = (float)currentValObj;
-            MutateFloat(ref floatVal, MinValue, MaxValue, Steps);
-            member.SetValue(plantHolder.Seed, floatVal);
-        }
-        else if (member.FieldType == typeof(int))
-        {
-            var intVal = (int)currentValObj;
-            MutateInt(ref intVal, (int)MinValue, (int)MaxValue, Steps);
-            member.SetValue(plantHolder.Seed, intVal);
-        }
-        else if (member.FieldType == typeof(bool))
-        {
-            var boolVal = (bool)currentValObj;
-            boolVal = !boolVal;
-            member.SetValue(plantHolder.Seed, boolVal);
-        }
-    }
-
-    // Mutate reference 'val' between 'min' and 'max' by pretending the value
-    // is representable by a thermometer code with 'bits' number of bits and
-    // randomly flipping some of them.
-    private void MutateFloat(ref float val, float min, float max, int bits)
-    {
-        if (min == max)
-        {
-            val = min;
-            return;
-        }
-
-        // Starting number of bits that are high, between 0 and bits.
-        // In other words, it's val mapped linearly from range [min, max] to range [0, bits], and then rounded.
-        int valInt = (int)MathF.Round((val - min) / (max - min) * bits);
-        // val may be outside the range of min/max due to starting prototype values, so clamp.
-        valInt = Math.Clamp(valInt, 0, bits);
-
-        // Probability that the bit flip increases n.
-        // The higher the current value is, the lower the probability of increasing value is, and the higher the probability of decreasive it it.
-        // In other words, it tends to go to the middle.
-        float probIncrease = 1 - (float)valInt / bits;
-        int valIntMutated;
-        if (Random(probIncrease))
-        {
-            valIntMutated = valInt + 1;
-        }
-        else
-        {
-            valIntMutated = valInt - 1;
-        }
-
-        // Set value based on mutated thermometer code.
-        float valMutated = Math.Clamp((float)valIntMutated / bits * (max - min) + min, min, max);
-        val = valMutated;
-    }
-
-    private void MutateInt(ref int val, int min, int max, int bits)
-    {
-        if (min == max)
-        {
-            val = min;
-            return;
-        }
-
-        // Starting number of bits that are high, between 0 and bits.
-        // In other words, it's val mapped linearly from range [min, max] to range [0, bits], and then rounded.
-        int valInt = (int)MathF.Round((val - min) / (max - min) * bits);
-        // val may be outside the range of min/max due to starting prototype values, so clamp.
-        valInt = Math.Clamp(valInt, 0, bits);
-
-        // Probability that the bit flip increases n.
-        // The higher the current value is, the lower the probability of increasing value is, and the higher the probability of decreasing it.
-        // In other words, it tends to go to the middle.
-        float probIncrease = 1 - (float)valInt / bits;
-        int valMutated;
-        if (Random(probIncrease))
-        {
-            valMutated = val + 1;
-        }
-        else
-        {
-            valMutated = val - 1;
-        }
-
-        valMutated = Math.Clamp(valMutated, min, max);
-        val = valMutated;
-    }
-
-    private bool Random(float odds)
-    {
-        var random = IoCManager.Resolve<IRobustRandom>();
-        return random.Prob(odds);
-    }
-
-    protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
-    {
-        throw new NotImplementedException();
-    }
-}
diff --git a/Content.Server/EntityEffects/Effects/PlantMetabolism/PlantAdjustHealth.cs b/Content.Server/EntityEffects/Effects/PlantMetabolism/PlantAdjustHealth.cs
deleted file mode 100644 (file)
index 774f6ec..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-using Content.Server.Botany.Systems;
-using Content.Shared.EntityEffects;
-
-namespace Content.Server.EntityEffects.Effects.PlantMetabolism;
-
-public sealed partial class PlantAdjustHealth : PlantAdjustAttribute
-{
-    public override string GuidebookAttributeName { get; set; } = "plant-attribute-health";
-    
-    public override void Effect(EntityEffectBaseArgs args)
-    {
-        if (!CanMetabolize(args.TargetEntity, out var plantHolderComp, args.EntityManager))
-            return;
-
-        var plantHolder = args.EntityManager.System<PlantHolderSystem>();
-
-        plantHolderComp.Health += Amount;
-        plantHolder.CheckHealth(args.TargetEntity, plantHolderComp);
-    }
-}
-
diff --git a/Content.Server/EntityEffects/Effects/PlantMetabolism/PlantAdjustMutationLevel.cs b/Content.Server/EntityEffects/Effects/PlantMetabolism/PlantAdjustMutationLevel.cs
deleted file mode 100644 (file)
index bf41a21..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-using Content.Shared.EntityEffects;
-
-namespace Content.Server.EntityEffects.Effects.PlantMetabolism;
-
-public sealed partial class PlantAdjustMutationLevel : PlantAdjustAttribute
-{
-    public override string GuidebookAttributeName { get; set; } = "plant-attribute-mutation-level";
-
-    public override void Effect(EntityEffectBaseArgs args)
-    {
-        if (!CanMetabolize(args.TargetEntity, out var plantHolderComp, args.EntityManager))
-            return;
-
-        plantHolderComp.MutationLevel += Amount * plantHolderComp.MutationMod;
-    }
-}
diff --git a/Content.Server/EntityEffects/Effects/PlantMetabolism/PlantAdjustMutationMod.cs b/Content.Server/EntityEffects/Effects/PlantMetabolism/PlantAdjustMutationMod.cs
deleted file mode 100644 (file)
index 6ed793e..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-using Content.Shared.EntityEffects;
-using JetBrains.Annotations;
-
-namespace Content.Server.EntityEffects.Effects.PlantMetabolism;
-
-[UsedImplicitly]
-public sealed partial class PlantAdjustMutationMod : PlantAdjustAttribute
-{
-    public override string GuidebookAttributeName { get; set; } = "plant-attribute-mutation-mod";
-
-    public override void Effect(EntityEffectBaseArgs args)
-    {
-        if (!CanMetabolize(args.TargetEntity, out var plantHolderComp, args.EntityManager))
-            return;
-
-        plantHolderComp.MutationMod += Amount;
-    }
-}
-
diff --git a/Content.Server/EntityEffects/Effects/PlantMetabolism/PlantAdjustNutrition.cs b/Content.Server/EntityEffects/Effects/PlantMetabolism/PlantAdjustNutrition.cs
deleted file mode 100644 (file)
index b9389af..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-using Content.Server.Botany.Systems;
-using Content.Shared.EntityEffects;
-using JetBrains.Annotations;
-
-namespace Content.Server.EntityEffects.Effects.PlantMetabolism;
-
-[UsedImplicitly]
-public sealed partial class PlantAdjustNutrition : PlantAdjustAttribute
-{
-    public override string GuidebookAttributeName { get; set; } = "plant-attribute-nutrition";
-
-    public override void Effect(EntityEffectBaseArgs args)
-    {
-        if (!CanMetabolize(args.TargetEntity, out var plantHolderComp, args.EntityManager, mustHaveAlivePlant: false))
-            return;
-
-        var plantHolder = args.EntityManager.System<PlantHolderSystem>();
-
-        plantHolder.AdjustNutrient(args.TargetEntity, Amount, plantHolderComp);
-    }
-}
diff --git a/Content.Server/EntityEffects/Effects/PlantMetabolism/PlantAdjustPests.cs b/Content.Server/EntityEffects/Effects/PlantMetabolism/PlantAdjustPests.cs
deleted file mode 100644 (file)
index 219529b..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-using Content.Shared.EntityEffects;
-using JetBrains.Annotations;
-
-namespace Content.Server.EntityEffects.Effects.PlantMetabolism;
-
-[UsedImplicitly]
-public sealed partial class PlantAdjustPests : PlantAdjustAttribute
-{
-    public override string GuidebookAttributeName { get; set; } = "plant-attribute-pests";
-    public override bool GuidebookIsAttributePositive { get; protected set; } = false;
-
-    public override void Effect(EntityEffectBaseArgs args)
-    {
-        if (!CanMetabolize(args.TargetEntity, out var plantHolderComp, args.EntityManager))
-            return;
-
-        plantHolderComp.PestLevel += Amount;
-    }
-}
-
diff --git a/Content.Server/EntityEffects/Effects/PlantMetabolism/PlantAdjustPotency.cs b/Content.Server/EntityEffects/Effects/PlantMetabolism/PlantAdjustPotency.cs
deleted file mode 100644 (file)
index 5776463..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-using Content.Server.Botany.Systems;
-using Content.Shared.EntityEffects;
-
-namespace Content.Server.EntityEffects.Effects.PlantMetabolism;
-
-/// <summary>
-///     Handles increase or decrease of plant potency.
-/// </summary>
-
-public sealed partial class PlantAdjustPotency : PlantAdjustAttribute
-{
-    public override string GuidebookAttributeName { get; set; } = "plant-attribute-potency";
-
-    public override void Effect(EntityEffectBaseArgs args)
-    {
-        if (!CanMetabolize(args.TargetEntity, out var plantHolderComp, args.EntityManager))
-            return;
-
-        if (plantHolderComp.Seed == null)
-            return;
-
-        var plantHolder = args.EntityManager.System<PlantHolderSystem>();
-
-        plantHolder.EnsureUniqueSeed(args.TargetEntity, plantHolderComp);
-
-        plantHolderComp.Seed.Potency = Math.Max(plantHolderComp.Seed.Potency + Amount, 1);
-    }
-}
diff --git a/Content.Server/EntityEffects/Effects/PlantMetabolism/PlantAdjustToxins.cs b/Content.Server/EntityEffects/Effects/PlantMetabolism/PlantAdjustToxins.cs
deleted file mode 100644 (file)
index ab1baa4..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-using Content.Shared.EntityEffects;
-using JetBrains.Annotations;
-
-namespace Content.Server.EntityEffects.Effects.PlantMetabolism;
-
-[UsedImplicitly]
-public sealed partial class PlantAdjustToxins : PlantAdjustAttribute
-{
-    public override string GuidebookAttributeName { get; set; } = "plant-attribute-toxins";
-    public override bool GuidebookIsAttributePositive { get; protected set; } = false;
-
-    public override void Effect(EntityEffectBaseArgs args)
-    {
-        if (!CanMetabolize(args.TargetEntity, out var plantHolderComp, args.EntityManager))
-            return;
-
-        plantHolderComp.Toxins += Amount;
-    }
-}
-
diff --git a/Content.Server/EntityEffects/Effects/PlantMetabolism/PlantAdjustWater.cs b/Content.Server/EntityEffects/Effects/PlantMetabolism/PlantAdjustWater.cs
deleted file mode 100644 (file)
index 4177497..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-using Content.Server.Botany.Systems;
-using Content.Shared.EntityEffects;
-using JetBrains.Annotations;
-
-namespace Content.Server.EntityEffects.Effects.PlantMetabolism;
-
-[UsedImplicitly]
-public sealed partial class PlantAdjustWater : PlantAdjustAttribute
-{
-    public override string GuidebookAttributeName { get; set; } = "plant-attribute-water";
-
-    public override void Effect(EntityEffectBaseArgs args)
-    {
-        if (!CanMetabolize(args.TargetEntity, out var plantHolderComp, args.EntityManager, mustHaveAlivePlant: false))
-            return;
-
-        var plantHolder = args.EntityManager.System<PlantHolderSystem>();
-
-        plantHolder.AdjustWater(args.TargetEntity, Amount, plantHolderComp);
-    }
-}
-
diff --git a/Content.Server/EntityEffects/Effects/PlantMetabolism/PlantAdjustWeeds.cs b/Content.Server/EntityEffects/Effects/PlantMetabolism/PlantAdjustWeeds.cs
deleted file mode 100644 (file)
index 421e319..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-using Content.Shared.EntityEffects;
-using JetBrains.Annotations;
-
-namespace Content.Server.EntityEffects.Effects.PlantMetabolism;
-
-[UsedImplicitly]
-public sealed partial class PlantAdjustWeeds : PlantAdjustAttribute
-{
-    public override string GuidebookAttributeName { get; set; } = "plant-attribute-weeds";
-    public override bool GuidebookIsAttributePositive { get; protected set; } = false;
-
-    public override void Effect(EntityEffectBaseArgs args)
-    {
-        if (!CanMetabolize(args.TargetEntity, out var plantHolderComp, args.EntityManager))
-            return;
-
-        plantHolderComp.WeedLevel += Amount;
-    }
-}
diff --git a/Content.Server/EntityEffects/Effects/PlantMetabolism/PlantAffectGrowth.cs b/Content.Server/EntityEffects/Effects/PlantMetabolism/PlantAffectGrowth.cs
deleted file mode 100644 (file)
index 397eace..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-using Content.Server.Botany.Systems;
-using Content.Shared.EntityEffects;
-using JetBrains.Annotations;
-
-namespace Content.Server.EntityEffects.Effects.PlantMetabolism;
-
-[UsedImplicitly]
-public sealed partial class PlantAffectGrowth : PlantAdjustAttribute
-{
-    public override string GuidebookAttributeName { get; set; } = "plant-attribute-growth";
-
-    public override void Effect(EntityEffectBaseArgs args)
-    {
-        if (!CanMetabolize(args.TargetEntity, out var plantHolderComp, args.EntityManager))
-            return;
-
-        var plantHolder = args.EntityManager.System<PlantHolderSystem>();
-
-        plantHolder.AffectGrowth(args.TargetEntity, (int) Amount, plantHolderComp);
-    }
-}
-
diff --git a/Content.Server/EntityEffects/Effects/PlantMetabolism/PlantCryoxadone.cs b/Content.Server/EntityEffects/Effects/PlantMetabolism/PlantCryoxadone.cs
deleted file mode 100644 (file)
index 8a143ea..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-using Content.Server.Botany.Components;
-using Content.Shared.EntityEffects;
-using JetBrains.Annotations;
-using Robust.Shared.Prototypes;
-using Robust.Shared.Random;
-
-namespace Content.Server.EntityEffects.Effects.PlantMetabolism;
-
-[UsedImplicitly]
-[DataDefinition]
-public sealed partial class PlantCryoxadone : EntityEffect
-{
-    public override void Effect(EntityEffectBaseArgs args)
-    {
-        if (!args.EntityManager.TryGetComponent(args.TargetEntity, out PlantHolderComponent? plantHolderComp)
-        || plantHolderComp.Seed == null || plantHolderComp.Dead)
-            return;
-
-        var deviation = 0;
-        var seed = plantHolderComp.Seed;
-        var random = IoCManager.Resolve<IRobustRandom>();
-        if (plantHolderComp.Age > seed.Maturation)
-            deviation = (int) Math.Max(seed.Maturation - 1, plantHolderComp.Age - random.Next(7, 10));
-        else
-            deviation = (int) (seed.Maturation / seed.GrowthStages);
-        plantHolderComp.Age -= deviation;
-        plantHolderComp.LastProduce = plantHolderComp.Age;
-        plantHolderComp.SkipAging++;
-        plantHolderComp.ForceUpdate = true;
-    }
-
-    protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) => Loc.GetString("reagent-effect-guidebook-plant-cryoxadone", ("chance", Probability));
-}
diff --git a/Content.Server/EntityEffects/Effects/PlantMetabolism/PlantDestroySeeds.cs b/Content.Server/EntityEffects/Effects/PlantMetabolism/PlantDestroySeeds.cs
deleted file mode 100644 (file)
index 2929bb6..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-using Content.Server.Botany.Components;
-using Content.Server.Botany.Systems;
-using Content.Shared.EntityEffects;
-using Content.Shared.Popups;
-using Robust.Shared.Prototypes;
-
-namespace Content.Server.EntityEffects.Effects.PlantMetabolism;
-
-/// <summary>
-///     Handles removal of seeds on a plant.
-/// </summary>
-
-public sealed partial class PlantDestroySeeds : EntityEffect
-{
-    public override void Effect(EntityEffectBaseArgs args)
-    {
-        if (
-            !args.EntityManager.TryGetComponent(args.TargetEntity, out PlantHolderComponent? plantHolderComp)
-            || plantHolderComp.Seed == null
-            || plantHolderComp.Dead
-            || plantHolderComp.Seed.Immutable
-        )
-            return;
-
-        var plantHolder = args.EntityManager.System<PlantHolderSystem>();
-        var popupSystem = args.EntityManager.System<SharedPopupSystem>();
-
-        if (plantHolderComp.Seed.Seedless == false)
-        {
-            plantHolder.EnsureUniqueSeed(args.TargetEntity, plantHolderComp);
-            popupSystem.PopupEntity(
-                Loc.GetString("botany-plant-seedsdestroyed"),
-                args.TargetEntity,
-                PopupType.SmallCaution
-            );
-            plantHolderComp.Seed.Seedless = true;
-        }
-    }
-
-    protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) =>
-        Loc.GetString("reagent-effect-guidebook-plant-seeds-remove", ("chance", Probability));
-}
diff --git a/Content.Server/EntityEffects/Effects/PlantMetabolism/PlantDiethylamine.cs b/Content.Server/EntityEffects/Effects/PlantMetabolism/PlantDiethylamine.cs
deleted file mode 100644 (file)
index 36b6a83..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-using Content.Server.Botany.Components;
-using Content.Server.Botany.Systems;
-using Content.Shared.EntityEffects;
-using JetBrains.Annotations;
-using Robust.Shared.Prototypes;
-using Robust.Shared.Random;
-
-namespace Content.Server.EntityEffects.Effects.PlantMetabolism;
-
-[UsedImplicitly]
-[DataDefinition]
-public sealed partial class PlantDiethylamine : EntityEffect
-{
-    public override void Effect(EntityEffectBaseArgs args)
-    {
-        if (!args.EntityManager.TryGetComponent(args.TargetEntity, out PlantHolderComponent? plantHolderComp)
-                                || plantHolderComp.Seed == null || plantHolderComp.Dead ||
-                                plantHolderComp.Seed.Immutable)
-            return;
-
-
-        var plantHolder = args.EntityManager.System<PlantHolderSystem>();
-
-        var random = IoCManager.Resolve<IRobustRandom>();
-
-        if (random.Prob(0.1f))
-        {
-            plantHolder.EnsureUniqueSeed(args.TargetEntity, plantHolderComp);
-            plantHolderComp.Seed.Lifespan++;
-        }
-
-        if (random.Prob(0.1f))
-        {
-            plantHolder.EnsureUniqueSeed(args.TargetEntity, plantHolderComp);
-            plantHolderComp.Seed.Endurance++;
-        }
-    }
-
-    protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) => Loc.GetString("reagent-effect-guidebook-plant-diethylamine", ("chance", Probability));
-}
-
diff --git a/Content.Server/EntityEffects/Effects/PlantMetabolism/PlantPhalanximine.cs b/Content.Server/EntityEffects/Effects/PlantMetabolism/PlantPhalanximine.cs
deleted file mode 100644 (file)
index 96d98bf..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-using Content.Server.Botany.Components;
-using Content.Shared.EntityEffects;
-using JetBrains.Annotations;
-using Robust.Shared.Prototypes;
-
-namespace Content.Server.EntityEffects.Effects.PlantMetabolism;
-
-[UsedImplicitly]
-[DataDefinition]
-public sealed partial class PlantPhalanximine : EntityEffect
-{
-    public override void Effect(EntityEffectBaseArgs args)
-    {
-        if (!args.EntityManager.TryGetComponent(args.TargetEntity, out PlantHolderComponent? plantHolderComp)
-                                || plantHolderComp.Seed == null || plantHolderComp.Dead ||
-                                plantHolderComp.Seed.Immutable)
-            return;
-
-        plantHolderComp.Seed.Viable = true;
-    }
-
-    protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) => Loc.GetString("reagent-effect-guidebook-plant-phalanximine", ("chance", Probability));
-}
diff --git a/Content.Server/EntityEffects/Effects/PlantMetabolism/PlantRestoreSeeds.cs b/Content.Server/EntityEffects/Effects/PlantMetabolism/PlantRestoreSeeds.cs
deleted file mode 100644 (file)
index 11af8d5..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-using Content.Server.Botany.Components;
-using Content.Server.Botany.Systems;
-using Content.Shared.EntityEffects;
-using Content.Shared.Popups;
-using Robust.Shared.Prototypes;
-
-namespace Content.Server.EntityEffects.Effects.PlantMetabolism;
-
-/// <summary>
-///     Handles restoral of seeds on a plant.
-/// </summary>
-
-public sealed partial class PlantRestoreSeeds : EntityEffect
-{
-    public override void Effect(EntityEffectBaseArgs args)
-    {
-        if (
-            !args.EntityManager.TryGetComponent(args.TargetEntity, out PlantHolderComponent? plantHolderComp)
-            || plantHolderComp.Seed == null
-            || plantHolderComp.Dead
-            || plantHolderComp.Seed.Immutable
-        )
-            return;
-
-        var plantHolder = args.EntityManager.System<PlantHolderSystem>();
-        var popupSystem = args.EntityManager.System<SharedPopupSystem>();
-
-        if (plantHolderComp.Seed.Seedless)
-        {
-            plantHolder.EnsureUniqueSeed(args.TargetEntity, plantHolderComp);
-            popupSystem.PopupEntity(Loc.GetString("botany-plant-seedsrestored"), args.TargetEntity);
-            plantHolderComp.Seed.Seedless = false;
-        }
-    }
-
-    protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) =>
-        Loc.GetString("reagent-effect-guidebook-plant-seeds-add", ("chance", Probability));
-}
diff --git a/Content.Server/EntityEffects/Effects/PlantMetabolism/RobustHarvest.cs b/Content.Server/EntityEffects/Effects/PlantMetabolism/RobustHarvest.cs
deleted file mode 100644 (file)
index 695cb96..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-using Content.Server.Botany.Components;
-using Content.Server.Botany.Systems;
-using Content.Shared.EntityEffects;
-using JetBrains.Annotations;
-using Robust.Shared.Prototypes;
-using Robust.Shared.Random;
-
-namespace Content.Server.EntityEffects.Effects.PlantMetabolism;
-
-[UsedImplicitly]
-[DataDefinition]
-public sealed partial class RobustHarvest : EntityEffect
-{
-    [DataField]
-    public int PotencyLimit = 50;
-
-    [DataField]
-    public int PotencyIncrease = 3;
-
-    [DataField]
-    public int PotencySeedlessThreshold = 30;
-
-    public override void Effect(EntityEffectBaseArgs args)
-    {
-        if (!args.EntityManager.TryGetComponent(args.TargetEntity, out PlantHolderComponent? plantHolderComp)
-                                || plantHolderComp.Seed == null || plantHolderComp.Dead ||
-                                plantHolderComp.Seed.Immutable)
-            return;
-
-
-        var plantHolder = args.EntityManager.System<PlantHolderSystem>();
-        var random = IoCManager.Resolve<IRobustRandom>();
-
-        if (plantHolderComp.Seed.Potency < PotencyLimit)
-        {
-            plantHolder.EnsureUniqueSeed(args.TargetEntity, plantHolderComp);
-            plantHolderComp.Seed.Potency = Math.Min(plantHolderComp.Seed.Potency + PotencyIncrease, PotencyLimit);
-
-            if (plantHolderComp.Seed.Potency > PotencySeedlessThreshold)
-            {
-                plantHolderComp.Seed.Seedless = true;
-            }
-        }
-        else if (plantHolderComp.Seed.Yield > 1 && random.Prob(0.1f))
-        {
-            // Too much of a good thing reduces yield
-            plantHolder.EnsureUniqueSeed(args.TargetEntity, plantHolderComp);
-            plantHolderComp.Seed.Yield--;
-        }
-    }
-
-    protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) => Loc.GetString("reagent-effect-guidebook-plant-robust-harvest", ("seedlesstreshold", PotencySeedlessThreshold), ("limit", PotencyLimit), ("increase", PotencyIncrease), ("chance", Probability));
-}
diff --git a/Content.Server/EntityEffects/Effects/PlantMutateChemicals.cs b/Content.Server/EntityEffects/Effects/PlantMutateChemicals.cs
deleted file mode 100644 (file)
index 7ee6cd1..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-using Content.Server.Botany;
-using Content.Server.Botany.Components;
-using Content.Shared.EntityEffects;
-using Content.Shared.Random;
-using Robust.Shared.Prototypes;
-using Robust.Shared.Random;
-
-namespace Content.Server.EntityEffects.Effects;
-
-/// <summary>
-///     changes the chemicals available in a plant's produce
-/// </summary>
-public sealed partial class PlantMutateChemicals : EntityEffect
-{
-    public override void Effect(EntityEffectBaseArgs args)
-    {
-        var plantholder = args.EntityManager.GetComponent<PlantHolderComponent>(args.TargetEntity);
-
-        if (plantholder.Seed == null)
-            return;
-
-        var random = IoCManager.Resolve<IRobustRandom>();
-        var prototypeManager = IoCManager.Resolve<IPrototypeManager>();
-        var chemicals = plantholder.Seed.Chemicals;
-        var randomChems = prototypeManager.Index<WeightedRandomFillSolutionPrototype>("RandomPickBotanyReagent").Fills;
-
-        // Add a random amount of a random chemical to this set of chemicals
-        if (randomChems != null)
-        {
-            var pick = random.Pick<RandomFillSolution>(randomChems);
-            var chemicalId = random.Pick(pick.Reagents);
-            var amount = random.Next(1, (int)pick.Quantity);
-            var seedChemQuantity = new SeedChemQuantity();
-            if (chemicals.ContainsKey(chemicalId))
-            {
-                seedChemQuantity.Min = chemicals[chemicalId].Min;
-                seedChemQuantity.Max = chemicals[chemicalId].Max + amount;
-            }
-            else
-            {
-                seedChemQuantity.Min = 1;
-                seedChemQuantity.Max = 1 + amount;
-                seedChemQuantity.Inherent = false;
-            }
-            var potencyDivisor = (int)Math.Ceiling(100.0f / seedChemQuantity.Max);
-            seedChemQuantity.PotencyDivisor = potencyDivisor;
-            chemicals[chemicalId] = seedChemQuantity;
-        }
-    }
-
-    protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
-    {
-        return "TODO";
-    }
-}
diff --git a/Content.Server/EntityEffects/Effects/PlantMutateGases.cs b/Content.Server/EntityEffects/Effects/PlantMutateGases.cs
deleted file mode 100644 (file)
index 52b9da3..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-using Content.Server.Botany.Components;
-using Content.Shared.Atmos;
-using Content.Shared.EntityEffects;
-using Robust.Shared.Prototypes;
-using Robust.Shared.Random;
-using System.Linq;
-
-namespace Content.Server.EntityEffects.Effects;
-
-/// <summary>
-///     changes the gases that a plant or produce create.
-/// </summary>
-public sealed partial class PlantMutateExudeGasses : EntityEffect
-{
-    [DataField]
-    public float MinValue = 0.01f;
-
-    [DataField]
-    public float MaxValue = 0.5f;
-
-    public override void Effect(EntityEffectBaseArgs args)
-    {
-        var plantholder = args.EntityManager.GetComponent<PlantHolderComponent>(args.TargetEntity);
-
-        if (plantholder.Seed == null)
-            return;
-
-        var random = IoCManager.Resolve<IRobustRandom>();
-        var gasses = plantholder.Seed.ExudeGasses;
-
-        // Add a random amount of a random gas to this gas dictionary
-        float amount = random.NextFloat(MinValue, MaxValue);
-        Gas gas = random.Pick(Enum.GetValues(typeof(Gas)).Cast<Gas>().ToList());
-        if (gasses.ContainsKey(gas))
-        {
-            gasses[gas] += amount;
-        }
-        else
-        {
-            gasses.Add(gas, amount);
-        }
-    }
-
-    protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
-    {
-        return "TODO";
-    }
-}
-
-/// <summary>
-///     changes the gases that a plant or produce consumes.
-/// </summary>
-public sealed partial class PlantMutateConsumeGasses : EntityEffect
-{
-    [DataField]
-    public float MinValue = 0.01f;
-
-    [DataField]
-    public float MaxValue = 0.5f;
-    public override void Effect(EntityEffectBaseArgs args)
-    {
-        var plantholder = args.EntityManager.GetComponent<PlantHolderComponent>(args.TargetEntity);
-
-        if (plantholder.Seed == null)
-            return;
-
-        var random = IoCManager.Resolve<IRobustRandom>();
-        var gasses = plantholder.Seed.ConsumeGasses;
-
-        // Add a random amount of a random gas to this gas dictionary
-        float amount = random.NextFloat(MinValue, MaxValue);
-        Gas gas = random.Pick(Enum.GetValues(typeof(Gas)).Cast<Gas>().ToList());
-        if (gasses.ContainsKey(gas))
-        {
-            gasses[gas] += amount;
-        }
-        else
-        {
-            gasses.Add(gas, amount);
-        }
-    }
-
-    protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
-    {
-        return "TODO";
-    }
-}
diff --git a/Content.Server/EntityEffects/Effects/PlantMutateHarvest.cs b/Content.Server/EntityEffects/Effects/PlantMutateHarvest.cs
deleted file mode 100644 (file)
index e67176e..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-using Content.Server.Botany;
-using Content.Server.Botany.Components;
-using Content.Shared.EntityEffects;
-using Robust.Shared.Prototypes;
-
-namespace Content.Server.EntityEffects.Effects;
-
-/// <summary>
-///     Upgrades a plant's harvest type.
-/// </summary>
-public sealed partial class PlantMutateHarvest : EntityEffect
-{
-    public override void Effect(EntityEffectBaseArgs args)
-    {
-        var plantholder = args.EntityManager.GetComponent<PlantHolderComponent>(args.TargetEntity);
-
-        if (plantholder.Seed == null)
-            return;
-
-        if (plantholder.Seed.HarvestRepeat == HarvestType.NoRepeat)
-            plantholder.Seed.HarvestRepeat = HarvestType.Repeat;
-        else if (plantholder.Seed.HarvestRepeat == HarvestType.Repeat)
-            plantholder.Seed.HarvestRepeat = HarvestType.SelfHarvest;
-    }
-
-    protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
-    {
-        return "TODO";
-    }
-}
diff --git a/Content.Server/EntityEffects/Effects/PlantSpeciesChange.cs b/Content.Server/EntityEffects/Effects/PlantSpeciesChange.cs
deleted file mode 100644 (file)
index 65bd59d..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-using Content.Server.Botany;
-using Content.Server.Botany.Components;
-using Content.Shared.EntityEffects;
-using Robust.Shared.Prototypes;
-using Robust.Shared.Random;
-using Serilog;
-
-namespace Content.Server.EntityEffects.Effects;
-
-/// <summary>
-///     Changes a plant into one of the species its able to mutate into.
-/// </summary>
-public sealed partial class PlantSpeciesChange : EntityEffect
-{
-    public override void Effect(EntityEffectBaseArgs args)
-    {
-        var prototypeManager = IoCManager.Resolve<IPrototypeManager>();
-        var plantholder = args.EntityManager.GetComponent<PlantHolderComponent>(args.TargetEntity);
-
-        if (plantholder.Seed == null)
-            return;
-
-        if (plantholder.Seed.MutationPrototypes.Count == 0)
-            return;
-
-        var random = IoCManager.Resolve<IRobustRandom>();
-        var targetProto = random.Pick(plantholder.Seed.MutationPrototypes);
-        prototypeManager.TryIndex(targetProto, out SeedPrototype? protoSeed);
-
-        if (protoSeed == null)
-        {
-            Log.Error($"Seed prototype could not be found: {targetProto}!");
-            return;
-        }
-
-        plantholder.Seed = plantholder.Seed.SpeciesChange(protoSeed);
-    }
-
-    protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
-    {
-        return "TODO";
-    }
-}
diff --git a/Content.Server/EntityEffects/Effects/ReduceRotting.cs b/Content.Server/EntityEffects/Effects/ReduceRotting.cs
deleted file mode 100644 (file)
index 5c00492..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-using Content.Shared.Chemistry.Reagent;
-using Content.Shared.EntityEffects;
-using JetBrains.Annotations;
-using Robust.Shared.Prototypes;
-using Content.Server.Atmos.Rotting;
-
-namespace Content.Server.EntityEffects.Effects
-{
-    /// <summary>
-    /// Reduces the rotting accumulator on the patient, making them revivable.
-    /// </summary>
-    [UsedImplicitly]
-    public sealed partial class ReduceRotting : EntityEffect
-    {
-        [DataField("seconds")]
-        public double RottingAmount = 10;
-
-        protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
-            => Loc.GetString("reagent-effect-guidebook-reduce-rotting",
-                ("chance", Probability),
-                ("time", RottingAmount));
-        public override void Effect(EntityEffectBaseArgs args)
-        {
-            if (args is EntityEffectReagentArgs reagentArgs)
-            {
-                if (reagentArgs.Scale != 1f)
-                    return;
-            }
-
-            var rottingSys = args.EntityManager.EntitySysManager.GetEntitySystem<RottingSystem>();
-
-            rottingSys.ReduceAccumulator(args.TargetEntity, TimeSpan.FromSeconds(RottingAmount));
-        }
-    }
-}
diff --git a/Content.Server/EntityEffects/Effects/ResetNarcolepsy.cs b/Content.Server/EntityEffects/Effects/ResetNarcolepsy.cs
deleted file mode 100644 (file)
index f956471..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-using Content.Server.Traits.Assorted;
-using Content.Shared.Chemistry.Reagent;
-using Content.Shared.EntityEffects;
-using JetBrains.Annotations;
-using Robust.Shared.Prototypes;
-
-namespace Content.Server.EntityEffects.Effects;
-
-/// <summary>
-/// Reset narcolepsy timer
-/// </summary>
-[UsedImplicitly]
-public sealed partial class ResetNarcolepsy : EntityEffect
-{
-    /// <summary>
-    /// The # of seconds the effect resets the narcolepsy timer to
-    /// </summary>
-    [DataField("TimerReset")]
-    public int TimerReset = 600;
-
-    protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
-        => Loc.GetString("reagent-effect-guidebook-reset-narcolepsy", ("chance", Probability));
-
-    public override void Effect(EntityEffectBaseArgs args)
-    {
-        if (args is EntityEffectReagentArgs reagentArgs)
-            if (reagentArgs.Scale != 1f)
-                return;
-
-        args.EntityManager.EntitySysManager.GetEntitySystem<NarcolepsySystem>().AdjustNarcolepsyTimer(args.TargetEntity, TimerReset);
-    }
-}
diff --git a/Content.Server/EntityEffects/Effects/SatiateHunger.cs b/Content.Server/EntityEffects/Effects/SatiateHunger.cs
deleted file mode 100644 (file)
index dd58654..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-using Content.Server.Nutrition.Components;
-using Content.Shared.Chemistry.Reagent;
-using Content.Shared.EntityEffects;
-using Content.Shared.Nutrition.Components;
-using Content.Shared.Nutrition.EntitySystems;
-using Robust.Shared.Prototypes;
-
-namespace Content.Server.EntityEffects.Effects
-{
-    /// <summary>
-    /// Attempts to find a HungerComponent on the target,
-    /// and to update it's hunger values.
-    /// </summary>
-    public sealed partial class SatiateHunger : EntityEffect
-    {
-        private const float DefaultNutritionFactor = 3.0f;
-
-        /// <summary>
-        ///     How much hunger is satiated.
-        ///     Is multiplied by quantity if used with EntityEffectReagentArgs.
-        /// </summary>
-        [DataField("factor")] public float NutritionFactor { get; set; } = DefaultNutritionFactor;
-
-        //Remove reagent at set rate, satiate hunger if a HungerComponent can be found
-        public override void Effect(EntityEffectBaseArgs args)
-        {
-            var entman = args.EntityManager;
-            if (!entman.TryGetComponent(args.TargetEntity, out HungerComponent? hunger))
-                return;
-            if (args is EntityEffectReagentArgs reagentArgs)
-            {
-                entman.System<HungerSystem>().ModifyHunger(reagentArgs.TargetEntity, NutritionFactor * (float) reagentArgs.Quantity, hunger);
-            }
-            else
-            {
-                entman.System<HungerSystem>().ModifyHunger(args.TargetEntity, NutritionFactor, hunger);
-            }
-        }
-
-        protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
-            => Loc.GetString("reagent-effect-guidebook-satiate-hunger", ("chance", Probability), ("relative", NutritionFactor / DefaultNutritionFactor));
-    }
-}
diff --git a/Content.Server/EntityEffects/EntityEffectSystem.cs b/Content.Server/EntityEffects/EntityEffectSystem.cs
new file mode 100644 (file)
index 0000000..5d5e81a
--- /dev/null
@@ -0,0 +1,975 @@
+using System.Diagnostics.CodeAnalysis;
+using System.Linq;
+using Content.Server.Atmos.Components;
+using Content.Server.Atmos.EntitySystems;
+using Content.Server.Body.Components;
+using Content.Server.Body.Systems;
+using Content.Server.Botany.Components;
+using Content.Server.Botany.Systems;
+using Content.Server.Botany;
+using Content.Server.Chat.Systems;
+using Content.Server.Emp;
+using Content.Server.Explosion.EntitySystems;
+using Content.Server.Flash;
+using Content.Server.Fluids.EntitySystems;
+using Content.Server.Ghost.Roles.Components;
+using Content.Server.Medical;
+using Content.Server.Polymorph.Components;
+using Content.Server.Polymorph.Systems;
+using Content.Server.Speech.Components;
+using Content.Server.Spreader;
+using Content.Server.Temperature.Components;
+using Content.Server.Temperature.Systems;
+using Content.Server.Traits.Assorted;
+using Content.Server.Zombies;
+using Content.Shared.Atmos;
+using Content.Shared.Audio;
+using Content.Shared.Coordinates.Helpers;
+using Content.Shared.EntityEffects.EffectConditions;
+using Content.Shared.EntityEffects.Effects.PlantMetabolism;
+using Content.Shared.EntityEffects.Effects.StatusEffects;
+using Content.Shared.EntityEffects.Effects;
+using Content.Shared.EntityEffects;
+using Content.Shared.Maps;
+using Content.Shared.Mind.Components;
+using Content.Shared.Popups;
+using Content.Shared.Random;
+using Content.Shared.Zombies;
+using Robust.Server.GameObjects;
+using Robust.Shared.Audio;
+using Robust.Shared.Audio.Systems;
+using Robust.Shared.GameObjects;
+using Robust.Shared.Map;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Random;
+
+using TemperatureCondition = Content.Shared.EntityEffects.EffectConditions.Temperature; // disambiguate the namespace
+using PolymorphEffect = Content.Shared.EntityEffects.Effects.Polymorph;
+
+namespace Content.Server.EntityEffects;
+
+public sealed class EntityEffectSystem : EntitySystem
+{
+    [Dependency] private readonly AtmosphereSystem _atmosphere = default!;
+    [Dependency] private readonly BloodstreamSystem _bloodstream = default!;
+    [Dependency] private readonly ChatSystem _chat = default!;
+    [Dependency] private readonly EmpSystem _emp = default!;
+    [Dependency] private readonly ExplosionSystem _explosion = default!;
+    [Dependency] private readonly FlammableSystem _flammable = default!;
+    [Dependency] private readonly FlashSystem _flash = default!;
+    [Dependency] private readonly IMapManager _mapManager = default!;
+    [Dependency] private readonly IPrototypeManager _protoManager = default!;
+    [Dependency] private readonly IRobustRandom _random = default!;
+    [Dependency] private readonly SharedMapSystem _map = default!;
+    [Dependency] private readonly MutationSystem _mutation = default!;
+    [Dependency] private readonly NarcolepsySystem _narcolepsy = default!;
+    [Dependency] private readonly PlantHolderSystem _plantHolder = default!;
+    [Dependency] private readonly PolymorphSystem _polymorph = default!;
+    [Dependency] private readonly RespiratorSystem _respirator = default!;
+    [Dependency] private readonly SharedAudioSystem _audio = default!;
+    [Dependency] private readonly SharedPointLightSystem _pointLight = default!;
+    [Dependency] private readonly SharedPopupSystem _popup = default!;
+    [Dependency] private readonly SmokeSystem _smoke = default!;
+    [Dependency] private readonly SpreaderSystem _spreader = default!;
+    [Dependency] private readonly TemperatureSystem _temperature = default!;
+    [Dependency] private readonly SharedTransformSystem _xform = default!;
+    [Dependency] private readonly VomitSystem _vomit = default!;
+
+    public override void Initialize()
+    {
+        base.Initialize();
+
+        SubscribeLocalEvent<CheckEntityEffectConditionEvent<TemperatureCondition>>(OnCheckTemperature);
+        SubscribeLocalEvent<CheckEntityEffectConditionEvent<Breathing>>(OnCheckBreathing);
+        SubscribeLocalEvent<CheckEntityEffectConditionEvent<OrganType>>(OnCheckOrganType);
+        SubscribeLocalEvent<ExecuteEntityEffectEvent<PlantAdjustHealth>>(OnExecutePlantAdjustHealth);
+        SubscribeLocalEvent<ExecuteEntityEffectEvent<PlantAdjustMutationLevel>>(OnExecutePlantAdjustMutationLevel);
+        SubscribeLocalEvent<ExecuteEntityEffectEvent<PlantAdjustMutationMod>>(OnExecutePlantAdjustMutationMod);
+        SubscribeLocalEvent<ExecuteEntityEffectEvent<PlantAdjustPests>>(OnExecutePlantAdjustPests);
+        SubscribeLocalEvent<ExecuteEntityEffectEvent<PlantAdjustPotency>>(OnExecutePlantAdjustPotency);
+        SubscribeLocalEvent<ExecuteEntityEffectEvent<PlantAdjustToxins>>(OnExecutePlantAdjustToxins);
+        SubscribeLocalEvent<ExecuteEntityEffectEvent<PlantAdjustWater>>(OnExecutePlantAdjustWater);
+        SubscribeLocalEvent<ExecuteEntityEffectEvent<PlantAdjustWeeds>>(OnExecutePlantAdjustWeeds);
+        SubscribeLocalEvent<ExecuteEntityEffectEvent<PlantAffectGrowth>>(OnExecutePlantAffectGrowth);
+        SubscribeLocalEvent<ExecuteEntityEffectEvent<PlantChangeStat>>(OnExecutePlantChangeStat);
+        SubscribeLocalEvent<ExecuteEntityEffectEvent<PlantCryoxadone>>(OnExecutePlantCryoxadone);
+        SubscribeLocalEvent<ExecuteEntityEffectEvent<PlantDestroySeeds>>(OnExecutePlantDestroySeeds);
+        SubscribeLocalEvent<ExecuteEntityEffectEvent<PlantDiethylamine>>(OnExecutePlantDiethylamine);
+        SubscribeLocalEvent<ExecuteEntityEffectEvent<PlantPhalanximine>>(OnExecutePlantPhalanximine);
+        SubscribeLocalEvent<ExecuteEntityEffectEvent<PlantRestoreSeeds>>(OnExecutePlantRestoreSeeds);
+        SubscribeLocalEvent<ExecuteEntityEffectEvent<AdjustTemperature>>(OnExecuteAdjustTemperature);
+        SubscribeLocalEvent<ExecuteEntityEffectEvent<AreaReactionEffect>>(OnExecuteAreaReactionEffect);
+        SubscribeLocalEvent<ExecuteEntityEffectEvent<CauseZombieInfection>>(OnExecuteCauseZombieInfection);
+        SubscribeLocalEvent<ExecuteEntityEffectEvent<ChemCleanBloodstream>>(OnExecuteChemCleanBloodstream);
+        SubscribeLocalEvent<ExecuteEntityEffectEvent<ChemVomit>>(OnExecuteChemVomit);
+        SubscribeLocalEvent<ExecuteEntityEffectEvent<CreateEntityReactionEffect>>(OnExecuteCreateEntityReactionEffect);
+        SubscribeLocalEvent<ExecuteEntityEffectEvent<CreateGas>>(OnExecuteCreateGas);
+        SubscribeLocalEvent<ExecuteEntityEffectEvent<CureZombieInfection>>(OnExecuteCureZombieInfection);
+        SubscribeLocalEvent<ExecuteEntityEffectEvent<Emote>>(OnExecuteEmote);
+        SubscribeLocalEvent<ExecuteEntityEffectEvent<EmpReactionEffect>>(OnExecuteEmpReactionEffect);
+        SubscribeLocalEvent<ExecuteEntityEffectEvent<ExplosionReactionEffect>>(OnExecuteExplosionReactionEffect);
+        SubscribeLocalEvent<ExecuteEntityEffectEvent<FlammableReaction>>(OnExecuteFlammableReaction);
+        SubscribeLocalEvent<ExecuteEntityEffectEvent<FlashReactionEffect>>(OnExecuteFlashReactionEffect);
+        SubscribeLocalEvent<ExecuteEntityEffectEvent<Ignite>>(OnExecuteIgnite);
+        SubscribeLocalEvent<ExecuteEntityEffectEvent<MakeSentient>>(OnExecuteMakeSentient);
+        SubscribeLocalEvent<ExecuteEntityEffectEvent<ModifyBleedAmount>>(OnExecuteModifyBleedAmount);
+        SubscribeLocalEvent<ExecuteEntityEffectEvent<ModifyBloodLevel>>(OnExecuteModifyBloodLevel);
+        SubscribeLocalEvent<ExecuteEntityEffectEvent<ModifyLungGas>>(OnExecuteModifyLungGas);
+        SubscribeLocalEvent<ExecuteEntityEffectEvent<Oxygenate>>(OnExecuteOxygenate);
+        SubscribeLocalEvent<ExecuteEntityEffectEvent<PlantMutateChemicals>>(OnExecutePlantMutateChemicals);
+        SubscribeLocalEvent<ExecuteEntityEffectEvent<PlantMutateConsumeGasses>>(OnExecutePlantMutateConsumeGasses);
+        SubscribeLocalEvent<ExecuteEntityEffectEvent<PlantMutateExudeGasses>>(OnExecutePlantMutateExudeGasses);
+        SubscribeLocalEvent<ExecuteEntityEffectEvent<PlantMutateHarvest>>(OnExecutePlantMutateHarvest);
+        SubscribeLocalEvent<ExecuteEntityEffectEvent<PlantSpeciesChange>>(OnExecutePlantSpeciesChange);
+        SubscribeLocalEvent<ExecuteEntityEffectEvent<PolymorphEffect>>(OnExecutePolymorph);
+        SubscribeLocalEvent<ExecuteEntityEffectEvent<ResetNarcolepsy>>(OnExecuteResetNarcolepsy);
+    }
+
+    private void OnCheckTemperature(ref CheckEntityEffectConditionEvent<TemperatureCondition> args)
+    {
+        args.Result = false;
+        if (TryComp(args.Args.TargetEntity, out TemperatureComponent? temp))
+        {
+            if (temp.CurrentTemperature > args.Condition.Min && temp.CurrentTemperature < args.Condition.Max)
+                args.Result = true;
+        }
+    }
+
+    private void OnCheckBreathing(ref CheckEntityEffectConditionEvent<Breathing> args)
+    {
+        if (!TryComp(args.Args.TargetEntity, out RespiratorComponent? respiratorComp))
+        {
+            args.Result = !args.Condition.IsBreathing;
+            return;
+        }
+
+        var breathingState = _respirator.IsBreathing((args.Args.TargetEntity, respiratorComp));
+        args.Result = args.Condition.IsBreathing == breathingState;
+    }
+
+    private void OnCheckOrganType(ref CheckEntityEffectConditionEvent<OrganType> args)
+    {
+        if (args.Args is EntityEffectReagentArgs reagentArgs)
+        {
+            if (reagentArgs.OrganEntity == null)
+            {
+                args.Result = false;
+                return;
+            }
+
+            args.Result = OrganCondition(args.Condition, reagentArgs.OrganEntity.Value);
+            return;
+        }
+
+        // TODO: Someone needs to figure out how to do this for non-reagent effects.
+        throw new NotImplementedException();
+    }
+
+    public bool OrganCondition(OrganType condition, Entity<MetabolizerComponent?> metabolizer)
+    {
+        metabolizer.Comp ??= EntityManager.GetComponentOrNull<MetabolizerComponent>(metabolizer.Owner);
+        if (metabolizer.Comp != null
+            && metabolizer.Comp.MetabolizerTypes != null
+            && metabolizer.Comp.MetabolizerTypes.Contains(condition.Type))
+            return condition.ShouldHave;
+        return !condition.ShouldHave;
+    }
+
+    /// <summary>
+    ///     Checks if the plant holder can metabolize the reagent or not. Checks if it has an alive plant by default.
+    /// </summary>
+    /// <param name="plantHolder">The entity holding the plant</param>
+    /// <param name="plantHolderComponent">The plant holder component</param>
+    /// <param name="entityManager">The entity manager</param>
+    /// <param name="mustHaveAlivePlant">Whether to check if it has an alive plant or not</param>
+    /// <returns></returns>
+    private bool CanMetabolizePlant(EntityUid plantHolder, [NotNullWhen(true)] out PlantHolderComponent? plantHolderComponent,
+        bool mustHaveAlivePlant = true, bool mustHaveMutableSeed = false)
+    {
+        plantHolderComponent = null;
+
+        if (!TryComp(plantHolder, out plantHolderComponent))
+            return false;
+
+        if (mustHaveAlivePlant && (plantHolderComponent.Seed == null || plantHolderComponent.Dead))
+            return false;
+
+        if (mustHaveMutableSeed && (plantHolderComponent.Seed == null || plantHolderComponent.Seed.Immutable))
+            return false;
+
+        return true;
+    }
+
+    private void OnExecutePlantAdjustHealth(ref ExecuteEntityEffectEvent<PlantAdjustHealth> args)
+    {
+        if (!CanMetabolizePlant(args.Args.TargetEntity, out var plantHolderComp))
+            return;
+
+        plantHolderComp.Health += args.Effect.Amount;
+        _plantHolder.CheckHealth(args.Args.TargetEntity, plantHolderComp);
+    }
+
+    private void OnExecutePlantAdjustMutationLevel(ref ExecuteEntityEffectEvent<PlantAdjustMutationLevel> args)
+    {
+        if (!CanMetabolizePlant(args.Args.TargetEntity, out var plantHolderComp))
+            return;
+
+        plantHolderComp.MutationLevel += args.Effect.Amount * plantHolderComp.MutationMod;
+    }
+
+    private void OnExecutePlantAdjustMutationMod(ref ExecuteEntityEffectEvent<PlantAdjustMutationMod> args)
+    {
+        if (!CanMetabolizePlant(args.Args.TargetEntity, out var plantHolderComp))
+            return;
+
+        plantHolderComp.MutationMod += args.Effect.Amount;
+    }
+
+    private void OnExecutePlantAdjustNutrition(ref ExecuteEntityEffectEvent<PlantAdjustNutrition> args)
+    {
+        if (!CanMetabolizePlant(args.Args.TargetEntity, out var plantHolderComp, mustHaveAlivePlant: false))
+            return;
+
+        _plantHolder.AdjustNutrient(args.Args.TargetEntity, args.Effect.Amount, plantHolderComp);
+    }
+
+    private void OnExecutePlantAdjustPests(ref ExecuteEntityEffectEvent<PlantAdjustPests> args)
+    {
+        if (!CanMetabolizePlant(args.Args.TargetEntity, out var plantHolderComp))
+            return;
+
+        plantHolderComp.PestLevel += args.Effect.Amount;
+    }
+
+    private void OnExecutePlantAdjustPotency(ref ExecuteEntityEffectEvent<PlantAdjustPotency> args)
+    {
+        if (!CanMetabolizePlant(args.Args.TargetEntity, out var plantHolderComp))
+            return;
+
+        if (plantHolderComp.Seed == null)
+            return;
+
+        _plantHolder.EnsureUniqueSeed(args.Args.TargetEntity, plantHolderComp);
+        plantHolderComp.Seed.Potency = Math.Max(plantHolderComp.Seed.Potency + args.Effect.Amount, 1);
+    }
+
+    private void OnExecutePlantAdjustToxins(ref ExecuteEntityEffectEvent<PlantAdjustToxins> args)
+    {
+        if (!CanMetabolizePlant(args.Args.TargetEntity, out var plantHolderComp))
+            return;
+
+        plantHolderComp.Toxins += args.Effect.Amount;
+    }
+
+    private void OnExecutePlantAdjustWater(ref ExecuteEntityEffectEvent<PlantAdjustWater> args)
+    {
+        if (!CanMetabolizePlant(args.Args.TargetEntity, out var plantHolderComp, mustHaveAlivePlant: false))
+            return;
+
+        _plantHolder.AdjustWater(args.Args.TargetEntity, args.Effect.Amount, plantHolderComp);
+    }
+
+    private void OnExecutePlantAdjustWeeds(ref ExecuteEntityEffectEvent<PlantAdjustWeeds> args)
+    {
+        if (!CanMetabolizePlant(args.Args.TargetEntity, out var plantHolderComp))
+            return;
+
+        plantHolderComp.WeedLevel += args.Effect.Amount;
+    }
+
+    private void OnExecutePlantAffectGrowth(ref ExecuteEntityEffectEvent<PlantAffectGrowth> args)
+    {
+        if (!CanMetabolizePlant(args.Args.TargetEntity, out var plantHolderComp))
+            return;
+
+        _plantHolder.AffectGrowth(args.Args.TargetEntity, (int) args.Effect.Amount, plantHolderComp);
+    }
+
+    // Mutate reference 'val' between 'min' and 'max' by pretending the value
+    // is representable by a thermometer code with 'bits' number of bits and
+    // randomly flipping some of them.
+    private void MutateFloat(ref float val, float min, float max, int bits)
+    {
+        if (min == max)
+        {
+            val = min;
+            return;
+        }
+
+        // Starting number of bits that are high, between 0 and bits.
+        // In other words, it's val mapped linearly from range [min, max] to range [0, bits], and then rounded.
+        int valInt = (int)MathF.Round((val - min) / (max - min) * bits);
+        // val may be outside the range of min/max due to starting prototype values, so clamp.
+        valInt = Math.Clamp(valInt, 0, bits);
+
+        // Probability that the bit flip increases n.
+        // The higher the current value is, the lower the probability of increasing value is, and the higher the probability of decreasive it it.
+        // In other words, it tends to go to the middle.
+        float probIncrease = 1 - (float)valInt / bits;
+        int valIntMutated;
+        if (_random.Prob(probIncrease))
+        {
+            valIntMutated = valInt + 1;
+        }
+        else
+        {
+            valIntMutated = valInt - 1;
+        }
+
+        // Set value based on mutated thermometer code.
+        float valMutated = Math.Clamp((float)valIntMutated / bits * (max - min) + min, min, max);
+        val = valMutated;
+    }
+
+    private void MutateInt(ref int val, int min, int max, int bits)
+    {
+        if (min == max)
+        {
+            val = min;
+            return;
+        }
+
+        // Starting number of bits that are high, between 0 and bits.
+        // In other words, it's val mapped linearly from range [min, max] to range [0, bits], and then rounded.
+        int valInt = (int)MathF.Round((val - min) / (max - min) * bits);
+        // val may be outside the range of min/max due to starting prototype values, so clamp.
+        valInt = Math.Clamp(valInt, 0, bits);
+
+        // Probability that the bit flip increases n.
+        // The higher the current value is, the lower the probability of increasing value is, and the higher the probability of decreasing it.
+        // In other words, it tends to go to the middle.
+        float probIncrease = 1 - (float)valInt / bits;
+        int valMutated;
+        if (_random.Prob(probIncrease))
+        {
+            valMutated = val + 1;
+        }
+        else
+        {
+            valMutated = val - 1;
+        }
+
+        valMutated = Math.Clamp(valMutated, min, max);
+        val = valMutated;
+    }
+
+    private void OnExecutePlantChangeStat(ref ExecuteEntityEffectEvent<PlantChangeStat> args)
+    {
+        if (!CanMetabolizePlant(args.Args.TargetEntity, out var plantHolderComp))
+            return;
+
+        if (plantHolderComp.Seed == null)
+            return;
+
+        var member = plantHolderComp.Seed.GetType().GetField(args.Effect.TargetValue);
+
+        if (member == null)
+        {
+            _mutation.Log.Error(args.Effect.GetType().Name + " Error: Member " + args.Effect.TargetValue + " not found on " + plantHolderComp.Seed.GetType().Name + ". Did you misspell it?");
+            return;
+        }
+
+        var currentValObj = member.GetValue(plantHolderComp.Seed);
+        if (currentValObj == null)
+            return;
+
+        if (member.FieldType == typeof(float))
+        {
+            var floatVal = (float)currentValObj;
+            MutateFloat(ref floatVal, args.Effect.MinValue, args.Effect.MaxValue, args.Effect.Steps);
+            member.SetValue(plantHolderComp.Seed, floatVal);
+        }
+        else if (member.FieldType == typeof(int))
+        {
+            var intVal = (int)currentValObj;
+            MutateInt(ref intVal, (int)args.Effect.MinValue, (int)args.Effect.MaxValue, args.Effect.Steps);
+            member.SetValue(plantHolderComp.Seed, intVal);
+        }
+        else if (member.FieldType == typeof(bool))
+        {
+            var boolVal = (bool)currentValObj;
+            boolVal = !boolVal;
+            member.SetValue(plantHolderComp.Seed, boolVal);
+        }
+    }
+
+    private void OnExecutePlantCryoxadone(ref ExecuteEntityEffectEvent<PlantCryoxadone> args)
+    {
+        if (!CanMetabolizePlant(args.Args.TargetEntity, out var plantHolderComp))
+            return;
+
+        var deviation = 0;
+        var seed = plantHolderComp.Seed;
+        if (seed == null)
+            return;
+        if (plantHolderComp.Age > seed.Maturation)
+            deviation = (int) Math.Max(seed.Maturation - 1, plantHolderComp.Age - _random.Next(7, 10));
+        else
+            deviation = (int) (seed.Maturation / seed.GrowthStages);
+        plantHolderComp.Age -= deviation;
+        plantHolderComp.LastProduce = plantHolderComp.Age;
+        plantHolderComp.SkipAging++;
+        plantHolderComp.ForceUpdate = true;
+    }
+
+    private void OnExecutePlantDestroySeeds(ref ExecuteEntityEffectEvent<PlantDestroySeeds> args)
+    {
+        if (!CanMetabolizePlant(args.Args.TargetEntity, out var plantHolderComp, mustHaveMutableSeed: true))
+            return;
+
+        if (plantHolderComp.Seed!.Seedless == false)
+        {
+            _plantHolder.EnsureUniqueSeed(args.Args.TargetEntity, plantHolderComp);
+            _popup.PopupEntity(
+                Loc.GetString("botany-plant-seedsdestroyed"),
+                args.Args.TargetEntity,
+                PopupType.SmallCaution
+            );
+            plantHolderComp.Seed.Seedless = true;
+        }
+    }
+
+    private void OnExecutePlantDiethylamine(ref ExecuteEntityEffectEvent<PlantDiethylamine> args)
+    {
+        if (!CanMetabolizePlant(args.Args.TargetEntity, out var plantHolderComp, mustHaveMutableSeed: true))
+            return;
+
+        if (_random.Prob(0.1f))
+        {
+            _plantHolder.EnsureUniqueSeed(args.Args.TargetEntity, plantHolderComp);
+            plantHolderComp.Seed!.Lifespan++;
+        }
+
+        if (_random.Prob(0.1f))
+        {
+            _plantHolder.EnsureUniqueSeed(args.Args.TargetEntity, plantHolderComp);
+            plantHolderComp.Seed!.Endurance++;
+        }
+    }
+
+    private void OnExecutePlantPhalanximine(ref ExecuteEntityEffectEvent<PlantPhalanximine> args)
+    {
+        if (!CanMetabolizePlant(args.Args.TargetEntity, out var plantHolderComp, mustHaveMutableSeed: true))
+            return;
+
+        plantHolderComp.Seed!.Viable = true;
+    }
+
+    private void OnExecutePlantRestoreSeeds(ref ExecuteEntityEffectEvent<PlantRestoreSeeds> args)
+    {
+        if (!CanMetabolizePlant(args.Args.TargetEntity, out var plantHolderComp, mustHaveMutableSeed: true))
+            return;
+
+        if (plantHolderComp.Seed!.Seedless)
+        {
+            _plantHolder.EnsureUniqueSeed(args.Args.TargetEntity, plantHolderComp);
+            _popup.PopupEntity(Loc.GetString("botany-plant-seedsrestored"), args.Args.TargetEntity);
+            plantHolderComp.Seed.Seedless = false;
+        }
+    }
+
+    private void OnExecuteRobustHarvest(ref ExecuteEntityEffectEvent<RobustHarvest> args)
+    {
+        if (!CanMetabolizePlant(args.Args.TargetEntity, out var plantHolderComp))
+            return;
+
+        if (plantHolderComp.Seed == null)
+            return;
+
+        if (plantHolderComp.Seed.Potency < args.Effect.PotencyLimit)
+        {
+            _plantHolder.EnsureUniqueSeed(args.Args.TargetEntity, plantHolderComp);
+            plantHolderComp.Seed.Potency = Math.Min(plantHolderComp.Seed.Potency + args.Effect.PotencyIncrease, args.Effect.PotencyLimit);
+
+            if (plantHolderComp.Seed.Potency > args.Effect.PotencySeedlessThreshold)
+            {
+                plantHolderComp.Seed.Seedless = true;
+            }
+        }
+        else if (plantHolderComp.Seed.Yield > 1 && _random.Prob(0.1f))
+        {
+            // Too much of a good thing reduces yield
+            _plantHolder.EnsureUniqueSeed(args.Args.TargetEntity, plantHolderComp);
+            plantHolderComp.Seed.Yield--;
+        }
+    }
+
+    private void OnExecuteAdjustTemperature(ref ExecuteEntityEffectEvent<AdjustTemperature> args)
+    {
+        if (TryComp(args.Args.TargetEntity, out TemperatureComponent? temp))
+        {
+            var amount = args.Effect.Amount;
+
+            if (args.Args is EntityEffectReagentArgs reagentArgs)
+            {
+                amount *= reagentArgs.Scale.Float();
+            }
+
+            _temperature.ChangeHeat(args.Args.TargetEntity, amount, true, temp);
+        }
+    }
+
+    private void OnExecuteAreaReactionEffect(ref ExecuteEntityEffectEvent<AreaReactionEffect> args)
+    {
+        if (args.Args is EntityEffectReagentArgs reagentArgs)
+        {
+            if (reagentArgs.Source == null)
+                return;
+
+            var spreadAmount = (int) Math.Max(0, Math.Ceiling((reagentArgs.Quantity / args.Effect.OverflowThreshold).Float()));
+            var splitSolution = reagentArgs.Source.SplitSolution(reagentArgs.Source.Volume);
+            var transform = EntityManager.GetComponent<TransformComponent>(reagentArgs.TargetEntity);
+            var mapCoords = _xform.GetMapCoordinates(reagentArgs.TargetEntity, xform: transform);
+
+            if (!_mapManager.TryFindGridAt(mapCoords, out var gridUid, out var grid) ||
+                !_map.TryGetTileRef(gridUid, grid, transform.Coordinates, out var tileRef))
+            {
+                return;
+            }
+
+            if (_spreader.RequiresFloorToSpread(args.Effect.PrototypeId) && tileRef.Tile.IsSpace())
+                return;
+
+            var coords = _map.MapToGrid(gridUid, mapCoords);
+            var ent = EntityManager.SpawnEntity(args.Effect.PrototypeId, coords.SnapToGrid());
+
+            _smoke.StartSmoke(ent, splitSolution, args.Effect.Duration, spreadAmount);
+
+            _audio.PlayPvs(args.Effect.Sound, reagentArgs.TargetEntity, AudioParams.Default.WithVariation(0.25f));
+            return;
+        }
+
+        // TODO: Someone needs to figure out how to do this for non-reagent effects.
+        throw new NotImplementedException();
+    }
+
+    private void OnExecuteCauseZombieInfection(ref ExecuteEntityEffectEvent<CauseZombieInfection> args)
+    {
+        EnsureComp<ZombifyOnDeathComponent>(args.Args.TargetEntity);
+        EnsureComp<PendingZombieComponent>(args.Args.TargetEntity);
+    }
+
+    private void OnExecuteChemCleanBloodstream(ref ExecuteEntityEffectEvent<ChemCleanBloodstream> args)
+    {
+        var cleanseRate = args.Effect.CleanseRate;
+        if (args.Args is EntityEffectReagentArgs reagentArgs)
+        {
+            if (reagentArgs.Source == null || reagentArgs.Reagent == null)
+                return;
+
+            cleanseRate *= reagentArgs.Scale.Float();
+            _bloodstream.FlushChemicals(args.Args.TargetEntity, reagentArgs.Reagent.ID, cleanseRate);
+        }
+        else
+        {
+            _bloodstream.FlushChemicals(args.Args.TargetEntity, "", cleanseRate);
+        }
+    }
+
+    private void OnExecuteChemVomit(ref ExecuteEntityEffectEvent<ChemVomit> args)
+    {
+        if (args.Args is EntityEffectReagentArgs reagentArgs)
+            if (reagentArgs.Scale != 1f)
+                return;
+
+        _vomit.Vomit(args.Args.TargetEntity, args.Effect.ThirstAmount, args.Effect.HungerAmount);
+    }
+
+    private void OnExecuteCreateEntityReactionEffect(ref ExecuteEntityEffectEvent<CreateEntityReactionEffect> args)
+    {
+        var transform = Comp<TransformComponent>(args.Args.TargetEntity);
+        var quantity = (int)args.Effect.Number;
+        if (args.Args is EntityEffectReagentArgs reagentArgs)
+            quantity *= reagentArgs.Quantity.Int();
+
+        for (var i = 0; i < quantity; i++)
+        {
+            var uid = Spawn(args.Effect.Entity, _xform.GetMapCoordinates(args.Args.TargetEntity, xform: transform));
+            _xform.AttachToGridOrMap(uid);
+
+            // TODO figure out how to properly spawn inside of containers
+            // e.g. cheese:
+            // if the user is holding a bowl milk & enzyme, should drop to floor, not attached to the user.
+            // if reaction happens in a backpack, should insert cheese into backpack.
+            // --> if it doesn't fit, iterate through parent storage until it attaches to the grid (again, DON'T attach to players).
+            // if the reaction happens INSIDE a stomach? the bloodstream? I have no idea how to handle that.
+            // presumably having cheese materialize inside of your blood would have "disadvantages".
+        }
+    }
+
+    private void OnExecuteCreateGas(ref ExecuteEntityEffectEvent<CreateGas> args)
+    {
+        var tileMix = _atmosphere.GetContainingMixture(args.Args.TargetEntity, false, true);
+
+        if (tileMix != null)
+        {
+            if (args.Args is EntityEffectReagentArgs reagentArgs)
+            {
+                tileMix.AdjustMoles(args.Effect.Gas, reagentArgs.Quantity.Float() * args.Effect.Multiplier);
+            }
+            else
+            {
+                tileMix.AdjustMoles(args.Effect.Gas, args.Effect.Multiplier);
+            }
+        }
+    }
+
+    private void OnExecuteCureZombieInfection(ref ExecuteEntityEffectEvent<CureZombieInfection> args)
+    {
+        if (HasComp<IncurableZombieComponent>(args.Args.TargetEntity))
+            return;
+
+        RemComp<ZombifyOnDeathComponent>(args.Args.TargetEntity);
+        RemComp<PendingZombieComponent>(args.Args.TargetEntity);
+
+        if (args.Effect.Innoculate)
+        {
+            EnsureComp<ZombieImmuneComponent>(args.Args.TargetEntity);
+        }
+    }
+
+    private void OnExecuteEmote(ref ExecuteEntityEffectEvent<Emote> args)
+    {
+        if (args.Effect.EmoteId == null)
+            return;
+
+        if (args.Effect.ShowInChat)
+            _chat.TryEmoteWithChat(args.Args.TargetEntity, args.Effect.EmoteId, ChatTransmitRange.GhostRangeLimit, forceEmote: args.Effect.Force);
+        else
+            _chat.TryEmoteWithoutChat(args.Args.TargetEntity, args.Effect.EmoteId);
+    }
+
+    private void OnExecuteEmpReactionEffect(ref ExecuteEntityEffectEvent<EmpReactionEffect> args)
+    {
+        var transform = EntityManager.GetComponent<TransformComponent>(args.Args.TargetEntity);
+
+        var range = args.Effect.EmpRangePerUnit;
+
+        if (args.Args is EntityEffectReagentArgs reagentArgs)
+        {
+            range = MathF.Min((float) (reagentArgs.Quantity * args.Effect.EmpRangePerUnit), args.Effect.EmpMaxRange);
+        }
+
+        _emp.EmpPulse(_xform.GetMapCoordinates(args.Args.TargetEntity, xform: transform),
+            range,
+            args.Effect.EnergyConsumption,
+            args.Effect.DisableDuration);
+    }
+
+    private void OnExecuteExplosionReactionEffect(ref ExecuteEntityEffectEvent<ExplosionReactionEffect> args)
+    {
+        var intensity = args.Effect.IntensityPerUnit;
+
+        if (args.Args is EntityEffectReagentArgs reagentArgs)
+        {
+            intensity = MathF.Min((float) reagentArgs.Quantity * args.Effect.IntensityPerUnit, args.Effect.MaxTotalIntensity);
+        }
+
+        _explosion.QueueExplosion(
+            args.Args.TargetEntity,
+            args.Effect.ExplosionType,
+            intensity,
+            args.Effect.IntensitySlope,
+            args.Effect.MaxIntensity,
+            args.Effect.TileBreakScale);
+    }
+
+    private void OnExecuteFlammableReaction(ref ExecuteEntityEffectEvent<FlammableReaction> args)
+    {
+        if (!TryComp(args.Args.TargetEntity, out FlammableComponent? flammable))
+            return;
+
+        // Sets the multiplier for FireStacks to MultiplierOnExisting is 0 or greater and target already has FireStacks
+        var multiplier = flammable.FireStacks != 0f && args.Effect.MultiplierOnExisting >= 0 ? args.Effect.MultiplierOnExisting : args.Effect.Multiplier;
+        var quantity = 1f;
+        if (args.Args is EntityEffectReagentArgs reagentArgs)
+        {
+            quantity = reagentArgs.Quantity.Float();
+            _flammable.AdjustFireStacks(args.Args.TargetEntity, quantity * multiplier, flammable);
+            if (reagentArgs.Reagent != null)
+                reagentArgs.Source?.RemoveReagent(reagentArgs.Reagent.ID, reagentArgs.Quantity);
+        }
+        else
+        {
+            _flammable.AdjustFireStacks(args.Args.TargetEntity, multiplier, flammable);
+        }
+    }
+
+    private void OnExecuteFlashReactionEffect(ref ExecuteEntityEffectEvent<FlashReactionEffect> args)
+    {
+        var transform = EntityManager.GetComponent<TransformComponent>(args.Args.TargetEntity);
+
+        var range = 1f;
+
+        if (args.Args is EntityEffectReagentArgs reagentArgs)
+            range = MathF.Min((float)(reagentArgs.Quantity * args.Effect.RangePerUnit), args.Effect.MaxRange);
+
+        _flash.FlashArea(
+            args.Args.TargetEntity,
+            null,
+            range,
+            args.Effect.Duration * 1000,
+            slowTo: args.Effect.SlowTo,
+            sound: args.Effect.Sound);
+
+        if (args.Effect.FlashEffectPrototype == null)
+            return;
+
+        var uid = EntityManager.SpawnEntity(args.Effect.FlashEffectPrototype, _xform.GetMapCoordinates(transform));
+        _xform.AttachToGridOrMap(uid);
+
+        if (!TryComp<PointLightComponent>(uid, out var pointLightComp))
+            return;
+
+        _pointLight.SetRadius(uid, MathF.Max(1.1f, range), pointLightComp);
+    }
+
+    private void OnExecuteIgnite(ref ExecuteEntityEffectEvent<Ignite> args)
+    {
+        if (!TryComp(args.Args.TargetEntity, out FlammableComponent? flammable))
+            return;
+
+        if (args.Args is EntityEffectReagentArgs reagentArgs)
+        {
+            _flammable.Ignite(reagentArgs.TargetEntity, reagentArgs.OrganEntity ?? reagentArgs.TargetEntity, flammable: flammable);
+        }
+        else
+        {
+            _flammable.Ignite(args.Args.TargetEntity, args.Args.TargetEntity, flammable: flammable);
+        }
+    }
+
+    private void OnExecuteMakeSentient(ref ExecuteEntityEffectEvent<MakeSentient> args)
+    {
+        var uid = args.Args.TargetEntity;
+
+        // Let affected entities speak normally to make this effect different from, say, the "random sentience" event
+        // This also works on entities that already have a mind
+        // We call this before the mind check to allow things like player-controlled mice to be able to benefit from the effect
+        RemComp<ReplacementAccentComponent>(uid);
+        RemComp<MonkeyAccentComponent>(uid);
+
+        // Stops from adding a ghost role to things like people who already have a mind
+        if (TryComp<MindContainerComponent>(uid, out var mindContainer) && mindContainer.HasMind)
+        {
+            return;
+        }
+
+        // Don't add a ghost role to things that already have ghost roles
+        if (TryComp(uid, out GhostRoleComponent? ghostRole))
+        {
+            return;
+        }
+
+        ghostRole = AddComp<GhostRoleComponent>(uid);
+        EnsureComp<GhostTakeoverAvailableComponent>(uid);
+
+        var entityData = EntityManager.GetComponent<MetaDataComponent>(uid);
+        ghostRole.RoleName = entityData.EntityName;
+        ghostRole.RoleDescription = Loc.GetString("ghost-role-information-cognizine-description");
+    }
+
+    private void OnExecuteModifyBleedAmount(ref ExecuteEntityEffectEvent<ModifyBleedAmount> args)
+    {
+        if (TryComp<BloodstreamComponent>(args.Args.TargetEntity, out var blood))
+        {
+            var amt = args.Effect.Amount;
+            if (args.Args is EntityEffectReagentArgs reagentArgs) {
+                if (args.Effect.Scaled)
+                    amt *= reagentArgs.Quantity.Float();
+                amt *= reagentArgs.Scale.Float();
+            }
+
+            _bloodstream.TryModifyBleedAmount(args.Args.TargetEntity, amt, blood);
+        }
+    }
+
+    private void OnExecuteModifyBloodLevel(ref ExecuteEntityEffectEvent<ModifyBloodLevel> args)
+    {
+        if (TryComp<BloodstreamComponent>(args.Args.TargetEntity, out var blood))
+        {
+            var amt = args.Effect.Amount;
+            if (args.Args is EntityEffectReagentArgs reagentArgs)
+            {
+                if (args.Effect.Scaled)
+                    amt *= reagentArgs.Quantity;
+                amt *= reagentArgs.Scale;
+            }
+
+            _bloodstream.TryModifyBloodLevel(args.Args.TargetEntity, amt, blood);
+        }
+    }
+
+    private void OnExecuteModifyLungGas(ref ExecuteEntityEffectEvent<ModifyLungGas> args)
+    {
+        LungComponent? lung;
+        float amount = 1f;
+
+        if (args.Args is EntityEffectReagentArgs reagentArgs)
+        {
+            if (!TryComp<LungComponent>(reagentArgs.OrganEntity, out var organLung))
+                return;
+            lung = organLung;
+            amount = reagentArgs.Quantity.Float();
+        }
+        else
+        {
+            if (!TryComp<LungComponent>(args.Args.TargetEntity, out var organLung)) //Likely needs to be modified to ensure it works correctly
+                return;
+            lung = organLung;
+        }
+
+        if (lung != null)
+        {
+            foreach (var (gas, ratio) in args.Effect.Ratios)
+            {
+                var quantity = ratio * amount / Atmospherics.BreathMolesToReagentMultiplier;
+                if (quantity < 0)
+                    quantity = Math.Max(quantity, -lung.Air[(int) gas]);
+                lung.Air.AdjustMoles(gas, quantity);
+            }
+        }
+    }
+
+    private void OnExecuteOxygenate(ref ExecuteEntityEffectEvent<Oxygenate> args)
+    {
+        var multiplier = 1f;
+        if (args.Args is EntityEffectReagentArgs reagentArgs)
+        {
+            multiplier = reagentArgs.Quantity.Float();
+        }
+
+        if (TryComp<RespiratorComponent>(args.Args.TargetEntity, out var resp))
+        {
+            _respirator.UpdateSaturation(args.Args.TargetEntity, multiplier * args.Effect.Factor, resp);
+        }
+    }
+
+    private void OnExecutePlantMutateChemicals(ref ExecuteEntityEffectEvent<PlantMutateChemicals> args)
+    {
+        var plantholder = EntityManager.GetComponent<PlantHolderComponent>(args.Args.TargetEntity);
+
+        if (plantholder.Seed == null)
+            return;
+
+        var chemicals = plantholder.Seed.Chemicals;
+        var randomChems = _protoManager.Index<WeightedRandomFillSolutionPrototype>("RandomPickBotanyReagent").Fills;
+
+        // Add a random amount of a random chemical to this set of chemicals
+        if (randomChems != null)
+        {
+            var pick = _random.Pick<RandomFillSolution>(randomChems);
+            var chemicalId = _random.Pick(pick.Reagents);
+            var amount = _random.Next(1, (int)pick.Quantity);
+            var seedChemQuantity = new SeedChemQuantity();
+            if (chemicals.ContainsKey(chemicalId))
+            {
+                seedChemQuantity.Min = chemicals[chemicalId].Min;
+                seedChemQuantity.Max = chemicals[chemicalId].Max + amount;
+            }
+            else
+            {
+                seedChemQuantity.Min = 1;
+                seedChemQuantity.Max = 1 + amount;
+                seedChemQuantity.Inherent = false;
+            }
+            var potencyDivisor = (int)Math.Ceiling(100.0f / seedChemQuantity.Max);
+            seedChemQuantity.PotencyDivisor = potencyDivisor;
+            chemicals[chemicalId] = seedChemQuantity;
+        }
+    }
+
+    private void OnExecutePlantMutateConsumeGasses(ref ExecuteEntityEffectEvent<PlantMutateConsumeGasses> args)
+    {
+        var plantholder = EntityManager.GetComponent<PlantHolderComponent>(args.Args.TargetEntity);
+
+        if (plantholder.Seed == null)
+            return;
+
+        var gasses = plantholder.Seed.ExudeGasses;
+
+        // Add a random amount of a random gas to this gas dictionary
+        float amount = _random.NextFloat(args.Effect.MinValue, args.Effect.MaxValue);
+        Gas gas = _random.Pick(Enum.GetValues(typeof(Gas)).Cast<Gas>().ToList());
+        if (gasses.ContainsKey(gas))
+        {
+            gasses[gas] += amount;
+        }
+        else
+        {
+            gasses.Add(gas, amount);
+        }
+    }
+
+    private void OnExecutePlantMutateExudeGasses(ref ExecuteEntityEffectEvent<PlantMutateExudeGasses> args)
+    {
+        var plantholder = EntityManager.GetComponent<PlantHolderComponent>(args.Args.TargetEntity);
+
+        if (plantholder.Seed == null)
+            return;
+
+        var gasses = plantholder.Seed.ConsumeGasses;
+
+        // Add a random amount of a random gas to this gas dictionary
+        float amount = _random.NextFloat(args.Effect.MinValue, args.Effect.MaxValue);
+        Gas gas = _random.Pick(Enum.GetValues(typeof(Gas)).Cast<Gas>().ToList());
+        if (gasses.ContainsKey(gas))
+        {
+            gasses[gas] += amount;
+        }
+        else
+        {
+            gasses.Add(gas, amount);
+        }
+    }
+
+    private void OnExecutePlantMutateHarvest(ref ExecuteEntityEffectEvent<PlantMutateHarvest> args)
+    {
+        var plantholder = EntityManager.GetComponent<PlantHolderComponent>(args.Args.TargetEntity);
+
+        if (plantholder.Seed == null)
+            return;
+
+        if (plantholder.Seed.HarvestRepeat == HarvestType.NoRepeat)
+            plantholder.Seed.HarvestRepeat = HarvestType.Repeat;
+        else if (plantholder.Seed.HarvestRepeat == HarvestType.Repeat)
+            plantholder.Seed.HarvestRepeat = HarvestType.SelfHarvest;
+    }
+
+    private void OnExecutePlantSpeciesChange(ref ExecuteEntityEffectEvent<PlantSpeciesChange> args)
+    {
+        var plantholder = EntityManager.GetComponent<PlantHolderComponent>(args.Args.TargetEntity);
+        if (plantholder.Seed == null)
+            return;
+
+        if (plantholder.Seed.MutationPrototypes.Count == 0)
+            return;
+
+        var targetProto = _random.Pick(plantholder.Seed.MutationPrototypes);
+        _protoManager.TryIndex(targetProto, out SeedPrototype? protoSeed);
+
+        if (protoSeed == null)
+        {
+            Log.Error($"Seed prototype could not be found: {targetProto}!");
+            return;
+        }
+
+        plantholder.Seed = plantholder.Seed.SpeciesChange(protoSeed);
+    }
+
+    private void OnExecutePolymorph(ref ExecuteEntityEffectEvent<PolymorphEffect> args)
+    {
+        // Make it into a prototype
+        EnsureComp<PolymorphableComponent>(args.Args.TargetEntity);
+        _polymorph.PolymorphEntity(args.Args.TargetEntity, args.Effect.PolymorphPrototype);
+    }
+
+    private void OnExecuteResetNarcolepsy(ref ExecuteEntityEffectEvent<ResetNarcolepsy> args)
+    {
+        if (args.Args is EntityEffectReagentArgs reagentArgs)
+            if (reagentArgs.Scale != 1f)
+                return;
+
+        _narcolepsy.AdjustNarcolepsyTimer(args.Args.TargetEntity, args.Effect.TimerReset);
+    }
+}
index bdbc2651640e70119651cea43b2b2f3c7cfc4b0d..dfbad1bbe9bc6c73305fee746fa6b6054157f1a9 100644 (file)
@@ -1,7 +1,7 @@
 using Content.Server.Administration.Logs;
 using Content.Server.Body.Components;
 using Content.Server.Body.Systems;
-using Content.Server.EntityEffects.Effects;
+using Content.Shared.EntityEffects.Effects;
 using Content.Server.Spreader;
 using Content.Shared.Chemistry;
 using Content.Shared.Chemistry.Components;
index f11a2c9041a3e30395fa9b2f20cf8f2a6777d17c..7ac5c20a7da9af79c6b8c72873acbeb83e1bfd5c 100644 (file)
@@ -1,6 +1,6 @@
 using Content.Server.Body.Components;
 using Content.Server.Body.Systems;
-using Content.Server.EntityEffects.Effects;
+using Content.Shared.EntityEffects.Effects;
 using Content.Server.Fluids.EntitySystems;
 using Content.Server.Forensics;
 using Content.Server.Inventory;
index 92559e48740f1bb0eed186279f18ee050bb9507a..4bbb972572372677280fb3ee79fff3b8357be587 100644 (file)
@@ -60,7 +60,7 @@ namespace Content.Shared.Chemistry.Reaction
         /// <summary>
         /// Effects to be triggered when the reaction occurs.
         /// </summary>
-        [DataField("effects", serverOnly: true)] public List<EntityEffect> Effects = new();
+        [DataField("effects")] public List<EntityEffect> Effects = new();
 
         /// <summary>
         /// How dangerous is this effect? Stuff like bicaridine should be low, while things like methamphetamine
index 2250347a47c3d75104e1ef296f55049faaf69ec0..1a3d17c340b1a4d28ba9c60024322cbe89dbb365 100644 (file)
@@ -145,16 +145,16 @@ namespace Content.Shared.Chemistry.Reagent
         [DataField]
         public bool WorksOnTheDead;
 
-        [DataField(serverOnly: true)]
+        [DataField]
         public FrozenDictionary<ProtoId<MetabolismGroupPrototype>, ReagentEffectsEntry>? Metabolisms;
 
-        [DataField(serverOnly: true)]
+        [DataField]
         public Dictionary<ProtoId<ReactiveGroupPrototype>, ReactiveReagentEffectEntry>? ReactiveEffects;
 
         [DataField(serverOnly: true)]
         public List<ITileReaction> TileReactions = new(0);
 
-        [DataField("plantMetabolism", serverOnly: true)]
+        [DataField("plantMetabolism")]
         public List<EntityEffect> PlantMetabolisms = new(0);
 
         [DataField]
similarity index 52%
rename from Content.Server/EntityEffects/EffectConditions/BodyTemperature.cs
rename to Content.Shared/EntityEffects/EffectConditions/BodyTemperature.cs
index 9f68bec91828a47bace9efffd466037777b7e41b..351e4ee12c505a65b72112dffab07a7f2cfdcc18 100644 (file)
@@ -1,30 +1,18 @@
-using Content.Server.Temperature.Components;
-using Content.Shared.EntityEffects;
 using Robust.Shared.Prototypes;
 
-namespace Content.Server.EntityEffects.EffectConditions;
+namespace Content.Shared.EntityEffects.EffectConditions;
 
 /// <summary>
 ///     Requires the target entity to be above or below a certain temperature.
 ///     Used for things like cryoxadone and pyroxadone.
 /// </summary>
-public sealed partial class Temperature : EntityEffectCondition
+public sealed partial class Temperature : EventEntityEffectCondition<Temperature>
 {
     [DataField]
     public float Min = 0;
 
     [DataField]
     public float Max = float.PositiveInfinity;
-    public override bool Condition(EntityEffectBaseArgs args)
-    {
-        if (args.EntityManager.TryGetComponent(args.TargetEntity, out TemperatureComponent? temp))
-        {
-            if (temp.CurrentTemperature > Min && temp.CurrentTemperature < Max)
-                return true;
-        }
-
-        return false;
-    }
 
     public override string GuidebookExplanation(IPrototypeManager prototype)
     {
diff --git a/Content.Shared/EntityEffects/EffectConditions/BreathingCondition.cs b/Content.Shared/EntityEffects/EffectConditions/BreathingCondition.cs
new file mode 100644 (file)
index 0000000..9de1bfd
--- /dev/null
@@ -0,0 +1,21 @@
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.EffectConditions;
+
+/// <summary>
+///     Condition for if the entity is successfully breathing.
+/// </summary>
+public sealed partial class Breathing : EventEntityEffectCondition<Breathing>
+{
+    /// <summary>
+    ///     If true, the entity must not have trouble breathing to pass.
+    /// </summary>
+    [DataField]
+    public bool IsBreathing = true;
+
+    public override string GuidebookExplanation(IPrototypeManager prototype)
+    {
+        return Loc.GetString("reagent-effect-condition-guidebook-breathing",
+                            ("isBreathing", IsBreathing));
+    }
+}
similarity index 86%
rename from Content.Server/EntityEffects/EffectConditions/HasTagCondition.cs
rename to Content.Shared/EntityEffects/EffectConditions/HasTagCondition.cs
index b0428b41bfc23257e274beb5a6ffc55c5e290770..379a24802712c68bf850938484a2ef7cba1a1543 100644 (file)
@@ -1,12 +1,9 @@
-using Content.Shared.EntityEffects;
 using Content.Shared.Tag;
-using JetBrains.Annotations;
 using Robust.Shared.Prototypes;
 using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
 
-namespace Content.Server.EntityEffects.EffectConditions;
+namespace Content.Shared.EntityEffects.EffectConditions;
 
-[UsedImplicitly]
 public sealed partial class HasTag : EntityEffectCondition
 {
     [DataField(customTypeSerializer: typeof(PrototypeIdSerializer<TagPrototype>))]
similarity index 95%
rename from Content.Server/EntityEffects/EffectConditions/JobCondition.cs
rename to Content.Shared/EntityEffects/EffectConditions/JobCondition.cs
index 9621d6945f6147e6635627e9dfb37664603938ba..7fec087d6b90e8951b3398dde2b4b75471015713 100644 (file)
@@ -1,5 +1,4 @@
 using System.Linq;
-using Content.Shared.EntityEffects;
 using Content.Shared.Localizations;
 using Content.Shared.Mind;
 using Content.Shared.Mind.Components;
@@ -7,7 +6,7 @@ using Content.Shared.Roles;
 using Content.Shared.Roles.Jobs;
 using Robust.Shared.Prototypes;
 
-namespace Content.Server.EntityEffects.EffectConditions;
+namespace Content.Shared.EntityEffects.EffectConditions;
 
 public sealed partial class JobCondition : EntityEffectCondition
 {
similarity index 88%
rename from Content.Server/EntityEffects/EffectConditions/MobStateCondition.cs
rename to Content.Shared/EntityEffects/EffectConditions/MobStateCondition.cs
index d676b29bf9ee1eac8dd83e103ec2684d2fed51c6..efe7246b2ac31f8e9535e4241de066ea7ebf3961 100644 (file)
@@ -1,9 +1,8 @@
-using Content.Shared.EntityEffects;
 using Content.Shared.Mobs;
 using Content.Shared.Mobs.Components;
 using Robust.Shared.Prototypes;
 
-namespace Content.Server.EntityEffects.EffectConditions;
+namespace Content.Shared.EntityEffects.EffectConditions;
 
 public sealed partial class MobStateCondition : EntityEffectCondition
 {
diff --git a/Content.Shared/EntityEffects/EffectConditions/OrganType.cs b/Content.Shared/EntityEffects/EffectConditions/OrganType.cs
new file mode 100644 (file)
index 0000000..f99eb5c
--- /dev/null
@@ -0,0 +1,28 @@
+// using Content.Server.Body.Components;
+using Content.Shared.Body.Prototypes;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
+
+namespace Content.Shared.EntityEffects.EffectConditions;
+
+/// <summary>
+///     Requires that the metabolizing organ is or is not tagged with a certain MetabolizerType
+/// </summary>
+public sealed partial class OrganType : EventEntityEffectCondition<OrganType>
+{
+    [DataField(required: true, customTypeSerializer: typeof(PrototypeIdSerializer<MetabolizerTypePrototype>))]
+    public string Type = default!;
+
+    /// <summary>
+    ///     Does this condition pass when the organ has the type, or when it doesn't have the type?
+    /// </summary>
+    [DataField]
+    public bool ShouldHave = true;
+
+    public override string GuidebookExplanation(IPrototypeManager prototype)
+    {
+        return Loc.GetString("reagent-effect-condition-guidebook-organ-type",
+            ("name", prototype.Index<MetabolizerTypePrototype>(Type).LocalizedName),
+            ("shouldhave", ShouldHave));
+    }
+}
similarity index 95%
rename from Content.Server/EntityEffects/EffectConditions/ReagentThreshold.cs
rename to Content.Shared/EntityEffects/EffectConditions/ReagentThreshold.cs
index 6cbd7b4ea578c2d41fce5d086c4075fcde6ee348..af71f20c8ec23c494bbf1a77486f773f043a6d72 100644 (file)
@@ -1,9 +1,8 @@
 using Content.Shared.Chemistry.Reagent;
-using Content.Shared.EntityEffects;
 using Content.Shared.FixedPoint;
 using Robust.Shared.Prototypes;
 
-namespace Content.Server.EntityEffects.EffectConditions;
+namespace Content.Shared.EntityEffects.EffectConditions;
 
 /// <summary>
 ///     Used for implementing reagent effects that require a certain amount of reagent before it should be applied.
similarity index 92%
rename from Content.Server/EntityEffects/EffectConditions/SolutionTemperature.cs
rename to Content.Shared/EntityEffects/EffectConditions/SolutionTemperature.cs
index b964435db52e1e74529dcbfac29eb52890bb161f..a9629401a0579baa3759a378c24c50df2da5ce73 100644 (file)
@@ -1,7 +1,6 @@
-using Content.Shared.EntityEffects;
 using Robust.Shared.Prototypes;
 
-namespace Content.Server.EntityEffects.EffectConditions;
+namespace Content.Shared.EntityEffects.EffectConditions;
 
 /// <summary>
 ///     Requires the solution to be above or below a certain temperature.
similarity index 94%
rename from Content.Server/EntityEffects/EffectConditions/TotalDamage.cs
rename to Content.Shared/EntityEffects/EffectConditions/TotalDamage.cs
index 2d039a1ac8f523f7ce1febe57013af9fe05db433..62b3e037e1c959531bf48e04d469db9998f64377 100644 (file)
@@ -3,7 +3,7 @@ using Content.Shared.Damage;
 using Content.Shared.FixedPoint;
 using Robust.Shared.Prototypes;
 
-namespace Content.Server.EntityEffects.EffectConditions;
+namespace Content.Shared.EntityEffects.EffectConditions;
 
 public sealed partial class TotalDamage : EntityEffectCondition
 {
similarity index 94%
rename from Content.Server/EntityEffects/EffectConditions/TotalHunger.cs
rename to Content.Shared/EntityEffects/EffectConditions/TotalHunger.cs
index c4f69b60de67c7cd1a6c1406ce07a88b2141a183..b4f1a1af898502b17ad7a9c5caf0ea537b2f8c4c 100644 (file)
@@ -3,7 +3,7 @@ using Content.Shared.Nutrition.Components;
 using Content.Shared.Nutrition.EntitySystems;
 using Robust.Shared.Prototypes;
 
-namespace Content.Server.EntityEffects.EffectConditions;
+namespace Content.Shared.EntityEffects.EffectConditions;
 
 public sealed partial class Hunger : EntityEffectCondition
 {
similarity index 91%
rename from Content.Server/EntityEffects/Effects/AddToSolutionReaction.cs
rename to Content.Shared/EntityEffects/Effects/AddToSolutionReaction.cs
index b5bb2a22fb2e3ecc293482f5354a6ce045eca8bb..0f2d35d369ffecd796c6edec7ee361533dcddf5b 100644 (file)
@@ -1,11 +1,8 @@
 using Content.Shared.Chemistry.EntitySystems;
-using Content.Shared.EntityEffects;
-using JetBrains.Annotations;
 using Robust.Shared.Prototypes;
 
-namespace Content.Server.EntityEffects.Effects
+namespace Content.Shared.EntityEffects.Effects
 {
-    [UsedImplicitly]
     public sealed partial class AddToSolutionReaction : EntityEffect
     {
         [DataField("solution")]
similarity index 95%
rename from Content.Server/EntityEffects/Effects/AdjustAlert.cs
rename to Content.Shared/EntityEffects/Effects/AdjustAlert.cs
index 3bf57b309d1ee9cc9d37b9d1c40820d21aaf168b..282de0a06c22e71a1b95549928a0eb66617d5493 100644 (file)
@@ -1,9 +1,8 @@
 using Content.Shared.Alert;
-using Content.Shared.EntityEffects;
 using Robust.Shared.Prototypes;
 using Robust.Shared.Timing;
 
-namespace Content.Server.EntityEffects.Effects;
+namespace Content.Shared.EntityEffects.Effects;
 
 public sealed partial class AdjustAlert : EntityEffect
 {
similarity index 96%
rename from Content.Server/EntityEffects/Effects/AdjustReagent.cs
rename to Content.Shared/EntityEffects/Effects/AdjustReagent.cs
index 71117d6ec5377a1579f197959702c984a82ed0e7..bb655b46bce5d7d3ebec9865fa99490b6f1e4f9d 100644 (file)
@@ -1,14 +1,11 @@
 using Content.Shared.Body.Prototypes;
 using Content.Shared.Chemistry.Reagent;
-using Content.Shared.EntityEffects;
 using Content.Shared.FixedPoint;
-using JetBrains.Annotations;
 using Robust.Shared.Prototypes;
 using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
 
-namespace Content.Server.EntityEffects.Effects
+namespace Content.Shared.EntityEffects.Effects
 {
-    [UsedImplicitly]
     public sealed partial class AdjustReagent : EntityEffect
     {
         /// <summary>
@@ -90,3 +87,4 @@ namespace Content.Server.EntityEffects.Effects
         }
     }
 }
+
diff --git a/Content.Shared/EntityEffects/Effects/AdjustTemperature.cs b/Content.Shared/EntityEffects/Effects/AdjustTemperature.cs
new file mode 100644 (file)
index 0000000..03dc226
--- /dev/null
@@ -0,0 +1,15 @@
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects;
+
+public sealed partial class AdjustTemperature : EventEntityEffect<AdjustTemperature>
+{
+    [DataField]
+    public float Amount;
+
+    protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
+        => Loc.GetString("reagent-effect-guidebook-adjust-temperature",
+            ("chance", Probability),
+            ("deltasign", MathF.Sign(Amount)),
+            ("amount", MathF.Abs(Amount)));
+}
diff --git a/Content.Shared/EntityEffects/Effects/AreaReactionEffect.cs b/Content.Shared/EntityEffects/Effects/AreaReactionEffect.cs
new file mode 100644 (file)
index 0000000..45ed261
--- /dev/null
@@ -0,0 +1,43 @@
+using Content.Shared.Database;
+using Content.Shared.FixedPoint;
+using Robust.Shared.Audio;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
+
+namespace Content.Shared.EntityEffects.Effects;
+
+/// <summary>
+/// Basically smoke and foam reactions.
+/// </summary>
+public sealed partial class AreaReactionEffect : EventEntityEffect<AreaReactionEffect>
+{
+    /// <summary>
+    /// How many seconds will the effect stay, counting after fully spreading.
+    /// </summary>
+    [DataField("duration")] public float Duration = 10;
+
+    /// <summary>
+    /// How many units of reaction for 1 smoke entity.
+    /// </summary>
+    [DataField] public FixedPoint2 OverflowThreshold = FixedPoint2.New(2.5);
+
+    /// <summary>
+    /// The entity prototype that will be spawned as the effect.
+    /// </summary>
+    [DataField("prototypeId", required: true, customTypeSerializer:typeof(PrototypeIdSerializer<EntityPrototype>))]
+    public string PrototypeId = default!;
+
+    /// <summary>
+    /// Sound that will get played when this reaction effect occurs.
+    /// </summary>
+    [DataField("sound", required: true)] public SoundSpecifier Sound = default!;
+
+    public override bool ShouldLog => true;
+
+    protected override string ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
+            => Loc.GetString("reagent-effect-guidebook-area-reaction",
+                    ("duration", Duration)
+                );
+
+    public override LogImpact LogImpact => LogImpact.High;
+}
similarity index 84%
rename from Content.Server/EntityEffects/Effects/ArtifactUnlock.cs
rename to Content.Shared/EntityEffects/Effects/ArtifactUnlock.cs
index 21454ff7a79df97fec24fe0d9809335cb496df93..077e1ebfd208d5fa7f15cf539d5f231b84eb49b3 100644 (file)
@@ -1,25 +1,22 @@
-using Content.Server.Popups;
-using Content.Server.Xenoarchaeology.Artifact;
+using Content.Shared.Xenoarchaeology.Artifact;
 using Content.Shared.EntityEffects;
 using Content.Shared.Popups;
 using Content.Shared.Xenoarchaeology.Artifact.Components;
-using JetBrains.Annotations;
 using Robust.Shared.Prototypes;
 
-namespace Content.Server.EntityEffects.Effects;
+namespace Content.Shared.EntityEffects.Effects;
 
 /// <summary>
 /// Sets an artifact into the unlocking state and marks the artifexium effect as true.
 /// This is a very specific behavior intended for a specific chem.
 /// </summary>
-[UsedImplicitly]
 public sealed partial class ArtifactUnlock : EntityEffect
 {
     public override void Effect(EntityEffectBaseArgs args)
     {
         var entMan = args.EntityManager;
-        var xenoArtifactSys = entMan.System<XenoArtifactSystem>();
-        var popupSys = entMan.System<PopupSystem>();
+        var xenoArtifactSys = entMan.System<SharedXenoArtifactSystem>();
+        var popupSys = entMan.System<SharedPopupSystem>();
 
         if (!entMan.TryGetComponent<XenoArtifactComponent>(args.TargetEntity, out var xenoArtifact))
             return;
diff --git a/Content.Shared/EntityEffects/Effects/CauseZombieInfection.cs b/Content.Shared/EntityEffects/Effects/CauseZombieInfection.cs
new file mode 100644 (file)
index 0000000..3f8c58b
--- /dev/null
@@ -0,0 +1,9 @@
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects;
+
+public sealed partial class CauseZombieInfection : EventEntityEffect<CauseZombieInfection>
+{
+    protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
+        => Loc.GetString("reagent-effect-guidebook-cause-zombie-infection", ("chance", Probability));
+}
diff --git a/Content.Shared/EntityEffects/Effects/ChemCleanBloodstream.cs b/Content.Shared/EntityEffects/Effects/ChemCleanBloodstream.cs
new file mode 100644 (file)
index 0000000..98181b8
--- /dev/null
@@ -0,0 +1,15 @@
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects;
+
+/// <summary>
+/// Basically smoke and foam reactions.
+/// </summary>
+public sealed partial class ChemCleanBloodstream : EventEntityEffect<ChemCleanBloodstream>
+{
+    [DataField]
+    public float CleanseRate = 3.0f;
+
+    protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
+        => Loc.GetString("reagent-effect-guidebook-chem-clean-bloodstream", ("chance", Probability));
+}
similarity index 87%
rename from Content.Server/EntityEffects/Effects/ChemHealEyeDamage.cs
rename to Content.Shared/EntityEffects/Effects/ChemHealEyeDamage.cs
index 42fc9ffa9fbcedd9deb5efae128eb21c7158d875..83b2aa96e5fe78a99c3df519a0d7814c21b38f06 100644 (file)
@@ -1,14 +1,11 @@
-using Content.Shared.EntityEffects;
 using Content.Shared.Eye.Blinding.Systems;
-using JetBrains.Annotations;
 using Robust.Shared.Prototypes;
 
-namespace Content.Server.EntityEffects.Effects;
+namespace Content.Shared.EntityEffects.Effects;
 
 /// <summary>
 /// Heal or apply eye damage
 /// </summary>
-[UsedImplicitly]
 public sealed partial class ChemHealEyeDamage : EntityEffect
 {
     /// <summary>
diff --git a/Content.Shared/EntityEffects/Effects/ChemVomit.cs b/Content.Shared/EntityEffects/Effects/ChemVomit.cs
new file mode 100644 (file)
index 0000000..1cd6b25
--- /dev/null
@@ -0,0 +1,19 @@
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects;
+
+/// <summary>
+/// Forces you to vomit.
+/// </summary>
+public sealed partial class ChemVomit : EventEntityEffect<ChemVomit>
+{
+    /// How many units of thirst to add each time we vomit
+    [DataField]
+    public float ThirstAmount = -8f;
+    /// How many units of hunger to add each time we vomit
+    [DataField]
+    public float HungerAmount = -8f;
+
+    protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
+        => Loc.GetString("reagent-effect-guidebook-chem-vomit", ("chance", Probability));
+}
diff --git a/Content.Shared/EntityEffects/Effects/CreateEntityReactionEffect.cs b/Content.Shared/EntityEffects/Effects/CreateEntityReactionEffect.cs
new file mode 100644 (file)
index 0000000..33173b1
--- /dev/null
@@ -0,0 +1,26 @@
+using Robust.Shared.Prototypes;
+using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
+
+namespace Content.Shared.EntityEffects.Effects;
+
+[DataDefinition]
+public sealed partial class CreateEntityReactionEffect : EventEntityEffect<CreateEntityReactionEffect>
+{
+    /// <summary>
+    ///     What entity to create.
+    /// </summary>
+    [DataField(required: true, customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
+    public string Entity = default!;
+
+    /// <summary>
+    ///     How many entities to create per unit reaction.
+    /// </summary>
+    [DataField]
+    public uint Number = 1;
+
+    protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
+        => Loc.GetString("reagent-effect-guidebook-create-entity-reaction-effect",
+            ("chance", Probability),
+            ("entname", IoCManager.Resolve<IPrototypeManager>().Index<EntityPrototype>(Entity).Name),
+            ("amount", Number));
+}
diff --git a/Content.Shared/EntityEffects/Effects/CreateGas.cs b/Content.Shared/EntityEffects/Effects/CreateGas.cs
new file mode 100644 (file)
index 0000000..75d554c
--- /dev/null
@@ -0,0 +1,32 @@
+using Content.Shared.Atmos;
+using Content.Shared.Atmos.EntitySystems;
+using Content.Shared.Database;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects;
+
+public sealed partial class CreateGas : EventEntityEffect<CreateGas>
+{
+    [DataField(required: true)]
+    public Gas Gas = default!;
+
+    /// <summary>
+    ///     For each unit consumed, how many moles of gas should be created?
+    /// </summary>
+    [DataField]
+    public float Multiplier = 3f;
+
+    public override bool ShouldLog => true;
+    protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
+    {
+        var atmos = entSys.GetEntitySystem<SharedAtmosphereSystem>();
+        var gasProto = atmos.GetGas(Gas);
+
+        return Loc.GetString("reagent-effect-guidebook-create-gas",
+            ("chance", Probability),
+            ("moles", Multiplier),
+            ("gas", gasProto.Name));
+    }
+
+    public override LogImpact LogImpact => LogImpact.High;
+}
diff --git a/Content.Shared/EntityEffects/Effects/CureZombieInfection.cs b/Content.Shared/EntityEffects/Effects/CureZombieInfection.cs
new file mode 100644 (file)
index 0000000..dd2d218
--- /dev/null
@@ -0,0 +1,18 @@
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects;
+
+public sealed partial class CureZombieInfection : EventEntityEffect<CureZombieInfection>
+{
+    [DataField]
+    public bool Innoculate;
+
+    protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
+    {
+        if(Innoculate)
+            return Loc.GetString("reagent-effect-guidebook-innoculate-zombie-infection", ("chance", Probability));
+
+        return Loc.GetString("reagent-effect-guidebook-cure-zombie-infection", ("chance", Probability));
+    }
+}
+
similarity index 91%
rename from Content.Server/EntityEffects/Effects/Drunk.cs
rename to Content.Shared/EntityEffects/Effects/Drunk.cs
index 493560e5b98a619064e66e35b922592b61f648f4..5f7f29c342be5690b0eec0b2c9d8efbcbc2eb97e 100644 (file)
@@ -1,8 +1,7 @@
 using Content.Shared.Drunk;
-using Content.Shared.EntityEffects;
 using Robust.Shared.Prototypes;
 
-namespace Content.Server.EntityEffects.Effects;
+namespace Content.Shared.EntityEffects.Effects;
 
 public sealed partial class Drunk : EntityEffect
 {
@@ -28,7 +27,7 @@ public sealed partial class Drunk : EntityEffect
         if (args is EntityEffectReagentArgs reagentArgs) {
             boozePower *= reagentArgs.Scale.Float();
         }
-        
+
         var drunkSys = args.EntityManager.EntitySysManager.GetEntitySystem<SharedDrunkSystem>();
         drunkSys.TryApplyDrunkenness(args.TargetEntity, boozePower, SlurSpeech);
     }
similarity index 78%
rename from Content.Server/EntityEffects/Effects/Electrocute.cs
rename to Content.Shared/EntityEffects/Effects/Electrocute.cs
index f6a5f1a2da7130056874a5693abfa0b0931fd7a6..32e0ff1172fb8990780df27e959a762ad751fdc2 100644 (file)
@@ -1,8 +1,7 @@
-using Content.Server.Electrocution;
-using Content.Shared.EntityEffects;
+using Content.Shared.Electrocution;
 using Robust.Shared.Prototypes;
 
-namespace Content.Server.EntityEffects.Effects;
+namespace Content.Shared.EntityEffects.Effects;
 
 public sealed partial class Electrocute : EntityEffect
 {
@@ -24,14 +23,14 @@ public sealed partial class Electrocute : EntityEffect
     {
         if (args is EntityEffectReagentArgs reagentArgs)
         {
-            reagentArgs.EntityManager.System<ElectrocutionSystem>().TryDoElectrocution(reagentArgs.TargetEntity, null,
+            reagentArgs.EntityManager.System<SharedElectrocutionSystem>().TryDoElectrocution(reagentArgs.TargetEntity, null,
                 Math.Max((reagentArgs.Quantity * ElectrocuteDamageScale).Int(), 1), TimeSpan.FromSeconds(ElectrocuteTime), Refresh, ignoreInsulation: true);
 
             if (reagentArgs.Reagent != null)
                 reagentArgs.Source?.RemoveReagent(reagentArgs.Reagent.ID, reagentArgs.Quantity);
         } else
         {
-            args.EntityManager.System<ElectrocutionSystem>().TryDoElectrocution(args.TargetEntity, null,
+            args.EntityManager.System<SharedElectrocutionSystem>().TryDoElectrocution(args.TargetEntity, null,
                 Math.Max(ElectrocuteDamageScale, 1), TimeSpan.FromSeconds(ElectrocuteTime), Refresh, ignoreInsulation: true);
         }
     }
similarity index 70%
rename from Content.Server/EntityEffects/Effects/Emote.cs
rename to Content.Shared/EntityEffects/Effects/Emote.cs
index 227e60a175ff31c9142b1d77e1fa2ad0c3996bda..08cf58c39ade62a008b9e89147e2babac3aa5171 100644 (file)
@@ -1,17 +1,13 @@
-using Content.Server.Chat.Systems;
 using Content.Shared.Chat.Prototypes;
-using Content.Shared.EntityEffects;
-using JetBrains.Annotations;
 using Robust.Shared.Prototypes;
 using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
 
-namespace Content.Server.EntityEffects.Effects;
+namespace Content.Shared.EntityEffects.Effects;
 
 /// <summary>
 ///     Tries to force someone to emote (scream, laugh, etc). Still respects whitelists/blacklists and other limits unless specially forced.
 /// </summary>
-[UsedImplicitly]
-public sealed partial class Emote : EntityEffect
+public sealed partial class Emote : EventEntityEffect<Emote>
 {
     /// <summary>
     ///     The emote the entity will preform.
@@ -44,13 +40,4 @@ public sealed partial class Emote : EntityEffect
 
         return Loc.GetString("reagent-effect-guidebook-emote", ("chance", Probability), ("emote", EmoteId));
     }
-
-    public override void Effect(EntityEffectBaseArgs args)
-    {
-        var chatSys = args.EntityManager.System<ChatSystem>();
-        if (ShowInChat)
-            chatSys.TryEmoteWithChat(args.TargetEntity, EmoteId, ChatTransmitRange.GhostRangeLimit, forceEmote: Force);
-        else
-            chatSys.TryEmoteWithoutChat(args.TargetEntity, EmoteId);
-    }
 }
diff --git a/Content.Shared/EntityEffects/Effects/EmpReactionEffect.cs b/Content.Shared/EntityEffects/Effects/EmpReactionEffect.cs
new file mode 100644 (file)
index 0000000..eee0aeb
--- /dev/null
@@ -0,0 +1,34 @@
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects;
+
+[DataDefinition]
+public sealed partial class EmpReactionEffect : EventEntityEffect<EmpReactionEffect>
+{
+    /// <summary>
+    ///     Impulse range per unit of quantity
+    /// </summary>
+    [DataField("rangePerUnit")]
+    public float EmpRangePerUnit = 0.5f;
+
+    /// <summary>
+    ///     Maximum impulse range
+    /// </summary>
+    [DataField("maxRange")]
+    public float EmpMaxRange = 10;
+
+    /// <summary>
+    ///     How much energy will be drain from sources
+    /// </summary>
+    [DataField]
+    public float EnergyConsumption = 12500;
+
+    /// <summary>
+    ///     Amount of time entities will be disabled
+    /// </summary>
+    [DataField("duration")]
+    public float DisableDuration = 15;
+
+    protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
+            => Loc.GetString("reagent-effect-guidebook-emp-reaction-effect", ("chance", Probability));
+}
similarity index 98%
rename from Content.Server/EntityEffects/Effects/EvenHealthChange.cs
rename to Content.Shared/EntityEffects/Effects/EvenHealthChange.cs
index acf2bfafab948851728aac1ff8a219645d4c8803..968d559939f915bd8b53dcb24fb7b82f84d2c3bb 100644 (file)
@@ -3,16 +3,14 @@ using Content.Shared.Damage.Prototypes;
 using Content.Shared.EntityEffects;
 using Content.Shared.FixedPoint;
 using Content.Shared.Localizations;
-using JetBrains.Annotations;
 using Robust.Shared.Prototypes;
 using Robust.Shared.Utility;
 
-namespace Content.Server.EntityEffects.Effects;
+namespace Content.Shared.EntityEffects.Effects;
 
 /// <summary>
 /// Version of <see cref="HealthChange"/> that distributes the healing to groups
 /// </summary>
-[UsedImplicitly]
 public sealed partial class EvenHealthChange : EntityEffect
 {
     /// <summary>
similarity index 74%
rename from Content.Server/EntityEffects/Effects/ExplosionReactionEffect.cs
rename to Content.Shared/EntityEffects/Effects/ExplosionReactionEffect.cs
index 24c58898c6521cdbf2efdee51de3a82e8ed12461..bc9af1509255bce7e79aa5773538b7a41df5be80 100644 (file)
@@ -1,15 +1,13 @@
-using Content.Server.Explosion.EntitySystems;
 using Content.Shared.Database;
-using Content.Shared.EntityEffects;
 using Content.Shared.Explosion;
 using Robust.Shared.Prototypes;
 using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
 using System.Text.Json.Serialization;
 
-namespace Content.Server.EntityEffects.Effects;
+namespace Content.Shared.EntityEffects.Effects;
 
 [DataDefinition]
-public sealed partial class ExplosionReactionEffect : EntityEffect
+public sealed partial class ExplosionReactionEffect : EventEntityEffect<ExplosionReactionEffect>
 {
     /// <summary>
     ///     The type of explosion. Determines damage types and tile break chance scaling.
@@ -45,7 +43,7 @@ public sealed partial class ExplosionReactionEffect : EntityEffect
     /// </summary>
     [DataField]
     public float IntensityPerUnit = 1;
-       
+
     /// <summary>
     ///     Factor used to scale the explosion intensity when calculating tile break chances. Allows for stronger
     ///     explosives that don't space tiles, without having to create a new explosion-type prototype.
@@ -58,23 +56,4 @@ public sealed partial class ExplosionReactionEffect : EntityEffect
     protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
         => Loc.GetString("reagent-effect-guidebook-explosion-reaction-effect", ("chance", Probability));
     public override LogImpact LogImpact => LogImpact.High;
-
-    public override void Effect(EntityEffectBaseArgs args)
-    {
-        var intensity = IntensityPerUnit;
-
-        if (args is EntityEffectReagentArgs reagentArgs)
-        {
-            intensity = MathF.Min((float) reagentArgs.Quantity * IntensityPerUnit, MaxTotalIntensity);
-        }
-
-        args.EntityManager.System<ExplosionSystem>()
-            .QueueExplosion(
-            args.TargetEntity,
-            ExplosionType,
-            intensity,
-            IntensitySlope,
-            MaxIntensity,
-                       TileBreakScale);
-    }
 }
similarity index 88%
rename from Content.Server/EntityEffects/Effects/ExtinguishReaction.cs
rename to Content.Shared/EntityEffects/Effects/ExtinguishReaction.cs
index d36ac9a576faf5c00de4711a2b488e0770764daf..11e776ac908a1bc082ac048f03903f4443040606 100644 (file)
@@ -1,11 +1,8 @@
 using Content.Shared.Atmos;
-using Content.Shared.EntityEffects;
-using JetBrains.Annotations;
 using Robust.Shared.Prototypes;
 
-namespace Content.Server.EntityEffects.Effects
+namespace Content.Shared.EntityEffects.Effects
 {
-    [UsedImplicitly]
     public sealed partial class ExtinguishReaction : EntityEffect
     {
         /// <summary>
diff --git a/Content.Shared/EntityEffects/Effects/FlammableReaction.cs b/Content.Shared/EntityEffects/Effects/FlammableReaction.cs
new file mode 100644 (file)
index 0000000..9f7d504
--- /dev/null
@@ -0,0 +1,21 @@
+using Content.Shared.Database;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects;
+
+public sealed partial class FlammableReaction : EventEntityEffect<FlammableReaction>
+{
+    [DataField]
+    public float Multiplier = 0.05f;
+
+    // The fire stack multiplier if fire stacks already exist on target, only works if 0 or greater
+    [DataField]
+    public float MultiplierOnExisting = -1f;
+
+    public override bool ShouldLog => true;
+
+    protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
+        => Loc.GetString("reagent-effect-guidebook-flammable-reaction", ("chance", Probability));
+
+    public override LogImpact LogImpact => LogImpact.Medium;
+}
diff --git a/Content.Shared/EntityEffects/Effects/FlashReactionEffect.cs b/Content.Shared/EntityEffects/Effects/FlashReactionEffect.cs
new file mode 100644 (file)
index 0000000..5cd7f06
--- /dev/null
@@ -0,0 +1,48 @@
+using Robust.Shared.Audio;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects;
+
+[DataDefinition]
+public sealed partial class FlashReactionEffect : EventEntityEffect<FlashReactionEffect>
+{
+    /// <summary>
+    ///     Flash range per unit of reagent.
+    /// </summary>
+    [DataField]
+    public float RangePerUnit = 0.2f;
+
+    /// <summary>
+    ///     Maximum flash range.
+    /// </summary>
+    [DataField]
+    public float MaxRange = 10f;
+
+    /// <summary>
+    ///     How much to entities are slowed down.
+    /// </summary>
+    [DataField]
+    public float SlowTo = 0.5f;
+
+    /// <summary>
+    ///     The time entities will be flashed in seconds.
+    ///     The default is chosen to be better than the hand flash so it is worth using it for grenades etc.
+    /// </summary>
+    [DataField]
+    public float Duration = 4f;
+
+    /// <summary>
+    ///     The prototype ID used for the visual effect.
+    /// </summary>
+    [DataField]
+    public EntProtoId? FlashEffectPrototype = "ReactionFlash";
+
+    /// <summary>
+    ///     The sound the flash creates.
+    /// </summary>
+    [DataField]
+    public SoundSpecifier? Sound = new SoundPathSpecifier("/Audio/Weapons/flash.ogg");
+
+    protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
+        => Loc.GetString("reagent-effect-guidebook-flash-reaction-effect", ("chance", Probability));
+}
similarity index 96%
rename from Content.Server/EntityEffects/Effects/Glow.cs
rename to Content.Shared/EntityEffects/Effects/Glow.cs
index 9f0347672975d7785ed3e25cd2bd2f9d9e2869c2..394d406700c3f45f4490b39b3749d9ed5043bfbf 100644 (file)
@@ -2,7 +2,7 @@ using Content.Shared.EntityEffects;
 using Robust.Shared.Prototypes;
 using Robust.Shared.Random;
 
-namespace Content.Server.EntityEffects.Effects;
+namespace Content.Shared.EntityEffects.Effects;
 
 /// <summary>
 ///     Makes a mob glow.
similarity index 98%
rename from Content.Server/EntityEffects/Effects/HealthChange.cs
rename to Content.Shared/EntityEffects/Effects/HealthChange.cs
index dd398da5b2e69f7595a76092d7d33469c8f68ec3..17c24f6b5afa438f33a18c82f5de4a3f674a9467 100644 (file)
@@ -3,17 +3,15 @@ using Content.Shared.Damage.Prototypes;
 using Content.Shared.EntityEffects;
 using Content.Shared.FixedPoint;
 using Content.Shared.Localizations;
-using JetBrains.Annotations;
 using Robust.Shared.Prototypes;
 using System.Linq;
 using System.Text.Json.Serialization;
 
-namespace Content.Server.EntityEffects.Effects
+namespace Content.Shared.EntityEffects.Effects
 {
     /// <summary>
     /// Default metabolism used for medicine reagents.
     /// </summary>
-    [UsedImplicitly]
     public sealed partial class HealthChange : EntityEffect
     {
         /// <summary>
diff --git a/Content.Shared/EntityEffects/Effects/Ignite.cs b/Content.Shared/EntityEffects/Effects/Ignite.cs
new file mode 100644 (file)
index 0000000..707ecc3
--- /dev/null
@@ -0,0 +1,18 @@
+using Content.Shared.Database;
+using Content.Shared.EntityEffects;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects;
+
+/// <summary>
+///     Ignites a mob.
+/// </summary>
+public sealed partial class Ignite : EventEntityEffect<Ignite>
+{
+    public override bool ShouldLog => true;
+
+    protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
+        => Loc.GetString("reagent-effect-guidebook-ignite", ("chance", Probability));
+
+    public override LogImpact LogImpact => LogImpact.Medium;
+}
diff --git a/Content.Shared/EntityEffects/Effects/MakeSentient.cs b/Content.Shared/EntityEffects/Effects/MakeSentient.cs
new file mode 100644 (file)
index 0000000..9c70eb4
--- /dev/null
@@ -0,0 +1,10 @@
+using Content.Shared.Mind.Components;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects;
+
+public sealed partial class MakeSentient : EventEntityEffect<MakeSentient>
+{
+    protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
+        => Loc.GetString("reagent-effect-guidebook-make-sentient", ("chance", Probability));
+}
diff --git a/Content.Shared/EntityEffects/Effects/ModifyBleedAmount.cs b/Content.Shared/EntityEffects/Effects/ModifyBleedAmount.cs
new file mode 100644 (file)
index 0000000..9f15652
--- /dev/null
@@ -0,0 +1,16 @@
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects;
+
+public sealed partial class ModifyBleedAmount : EventEntityEffect<ModifyBleedAmount>
+{
+    [DataField]
+    public bool Scaled = false;
+
+    [DataField]
+    public float Amount = -1.0f;
+
+    protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
+        => Loc.GetString("reagent-effect-guidebook-modify-bleed-amount", ("chance", Probability),
+            ("deltasign", MathF.Sign(Amount)));
+}
diff --git a/Content.Shared/EntityEffects/Effects/ModifyBloodLevel.cs b/Content.Shared/EntityEffects/Effects/ModifyBloodLevel.cs
new file mode 100644 (file)
index 0000000..06c026f
--- /dev/null
@@ -0,0 +1,17 @@
+using Content.Shared.FixedPoint;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects;
+
+public sealed partial class ModifyBloodLevel : EventEntityEffect<ModifyBloodLevel>
+{
+    [DataField]
+    public bool Scaled = false;
+
+    [DataField]
+    public FixedPoint2 Amount = 1.0f;
+
+    protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
+        => Loc.GetString("reagent-effect-guidebook-modify-blood-level", ("chance", Probability),
+            ("deltasign", MathF.Sign(Amount.Float())));
+}
diff --git a/Content.Shared/EntityEffects/Effects/ModifyLungGas.cs b/Content.Shared/EntityEffects/Effects/ModifyLungGas.cs
new file mode 100644 (file)
index 0000000..45dc8c8
--- /dev/null
@@ -0,0 +1,14 @@
+using Content.Shared.Atmos;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects;
+
+public sealed partial class ModifyLungGas : EventEntityEffect<ModifyLungGas>
+{
+    [DataField("ratios", required: true)]
+    public Dictionary<Gas, float> Ratios = default!;
+
+    // JUSTIFICATION: This is internal magic that players never directly interact with.
+    protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
+        => null;
+}
similarity index 97%
rename from Content.Server/EntityEffects/Effects/MovespeedModifier.cs
rename to Content.Shared/EntityEffects/Effects/MovespeedModifier.cs
index 74f4489c75feba695b3b96f4a42627426af7c2af..5e72746e3276ceecb27d42898fd3eb9dcf3170f9 100644 (file)
@@ -1,10 +1,9 @@
 using Content.Shared.Chemistry.Components;
-using Content.Shared.EntityEffects;
 using Content.Shared.Movement.Systems;
 using Robust.Shared.Prototypes;
 using Robust.Shared.Timing;
 
-namespace Content.Server.EntityEffects.Effects;
+namespace Content.Shared.EntityEffects.Effects;
 
 /// <summary>
 /// Default metabolism for stimulants and tranqs. Attempts to find a MovementSpeedModifier on the target,
diff --git a/Content.Shared/EntityEffects/Effects/Oxygenate.cs b/Content.Shared/EntityEffects/Effects/Oxygenate.cs
new file mode 100644 (file)
index 0000000..e990a3f
--- /dev/null
@@ -0,0 +1,13 @@
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects;
+
+public sealed partial class Oxygenate : EventEntityEffect<Oxygenate>
+{
+    [DataField]
+    public float Factor = 1f;
+
+    // JUSTIFICATION: This is internal magic that players never directly interact with.
+    protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
+        => null;
+}
similarity index 79%
rename from Content.Server/EntityEffects/Effects/Paralyze.cs
rename to Content.Shared/EntityEffects/Effects/Paralyze.cs
index ba020dd39b7accfdf6d71e6ceb9028888ec215a9..2da6a6a0794c1808fa906018c1db186438fea656 100644 (file)
@@ -1,8 +1,8 @@
-using Content.Server.Stunnable;
 using Content.Shared.EntityEffects;
+using Content.Shared.Stunnable;
 using Robust.Shared.Prototypes;
 
-namespace Content.Server.EntityEffects.Effects;
+namespace Content.Shared.EntityEffects.Effects;
 
 public sealed partial class Paralyze : EntityEffect
 {
@@ -27,7 +27,7 @@ public sealed partial class Paralyze : EntityEffect
             paralyzeTime *= (double)reagentArgs.Scale;
         }
 
-        args.EntityManager.System<StunSystem>().TryParalyze(args.TargetEntity, TimeSpan.FromSeconds(paralyzeTime), Refresh);
+        args.EntityManager.System<SharedStunSystem>().TryParalyze(args.TargetEntity, TimeSpan.FromSeconds(paralyzeTime), Refresh);
     }
 }
 
similarity index 51%
rename from Content.Server/EntityEffects/Effects/PlantMetabolism/PlantAdjustAttribute.cs
rename to Content.Shared/EntityEffects/Effects/PlantMetabolism/PlantAdjustAttribute.cs
index 5133fe502ffc8f2087fb9d6530360c5f948b09cb..2c8046452b0e8f9841937df47436145bef31c837 100644 (file)
@@ -1,13 +1,12 @@
-using Content.Server.Botany.Components;
 using Content.Shared.EntityEffects;
 using Robust.Shared.Prototypes;
 using Robust.Shared.Random;
 using System.Diagnostics.CodeAnalysis;
 
-namespace Content.Server.EntityEffects.Effects.PlantMetabolism;
+namespace Content.Shared.EntityEffects.Effects.PlantMetabolism;
 
 [ImplicitDataDefinitionForInheritors]
-public abstract partial class PlantAdjustAttribute : EntityEffect
+public abstract partial class PlantAdjustAttribute<T> : EventEntityEffect<T> where T : PlantAdjustAttribute<T>
 {
     [DataField]
     public float Amount { get; protected set; } = 1;
@@ -24,27 +23,6 @@ public abstract partial class PlantAdjustAttribute : EntityEffect
     [DataField]
     public virtual bool GuidebookIsAttributePositive { get; protected set; } = true;
 
-    /// <summary>
-    ///     Checks if the plant holder can metabolize the reagent or not. Checks if it has an alive plant by default.
-    /// </summary>
-    /// <param name="plantHolder">The entity holding the plant</param>
-    /// <param name="plantHolderComponent">The plant holder component</param>
-    /// <param name="entityManager">The entity manager</param>
-    /// <param name="mustHaveAlivePlant">Whether to check if it has an alive plant or not</param>
-    /// <returns></returns>
-    public bool CanMetabolize(EntityUid plantHolder, [NotNullWhen(true)] out PlantHolderComponent? plantHolderComponent,
-        IEntityManager entityManager,
-        bool mustHaveAlivePlant = true)
-    {
-        plantHolderComponent = null;
-
-        if (!entityManager.TryGetComponent(plantHolder, out plantHolderComponent)
-                                || mustHaveAlivePlant && (plantHolderComponent.Seed == null || plantHolderComponent.Dead))
-            return false;
-
-        return true;
-    }
-
     protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
     {
         string color;
diff --git a/Content.Shared/EntityEffects/Effects/PlantMetabolism/PlantAdjustHealth.cs b/Content.Shared/EntityEffects/Effects/PlantMetabolism/PlantAdjustHealth.cs
new file mode 100644 (file)
index 0000000..c1e7189
--- /dev/null
@@ -0,0 +1,7 @@
+namespace Content.Shared.EntityEffects.Effects.PlantMetabolism;
+
+public sealed partial class PlantAdjustHealth : PlantAdjustAttribute<PlantAdjustHealth>
+{
+    public override string GuidebookAttributeName { get; set; } = "plant-attribute-health";
+}
+
diff --git a/Content.Shared/EntityEffects/Effects/PlantMetabolism/PlantAdjustMutationLevel.cs b/Content.Shared/EntityEffects/Effects/PlantMetabolism/PlantAdjustMutationLevel.cs
new file mode 100644 (file)
index 0000000..6610adf
--- /dev/null
@@ -0,0 +1,6 @@
+namespace Content.Shared.EntityEffects.Effects.PlantMetabolism;
+
+public sealed partial class PlantAdjustMutationLevel : PlantAdjustAttribute<PlantAdjustMutationLevel>
+{
+    public override string GuidebookAttributeName { get; set; } = "plant-attribute-mutation-level";
+}
diff --git a/Content.Shared/EntityEffects/Effects/PlantMetabolism/PlantAdjustMutationMod.cs b/Content.Shared/EntityEffects/Effects/PlantMetabolism/PlantAdjustMutationMod.cs
new file mode 100644 (file)
index 0000000..91be222
--- /dev/null
@@ -0,0 +1,6 @@
+namespace Content.Shared.EntityEffects.Effects.PlantMetabolism;
+
+public sealed partial class PlantAdjustMutationMod : PlantAdjustAttribute<PlantAdjustMutationMod>
+{
+    public override string GuidebookAttributeName { get; set; } = "plant-attribute-mutation-mod";
+}
diff --git a/Content.Shared/EntityEffects/Effects/PlantMetabolism/PlantAdjustNutrition.cs b/Content.Shared/EntityEffects/Effects/PlantMetabolism/PlantAdjustNutrition.cs
new file mode 100644 (file)
index 0000000..db01d5d
--- /dev/null
@@ -0,0 +1,6 @@
+namespace Content.Shared.EntityEffects.Effects.PlantMetabolism;
+
+public sealed partial class PlantAdjustNutrition : PlantAdjustAttribute<PlantAdjustNutrition>
+{
+    public override string GuidebookAttributeName { get; set; } = "plant-attribute-nutrition";
+}
diff --git a/Content.Shared/EntityEffects/Effects/PlantMetabolism/PlantAdjustPests.cs b/Content.Shared/EntityEffects/Effects/PlantMetabolism/PlantAdjustPests.cs
new file mode 100644 (file)
index 0000000..18c0055
--- /dev/null
@@ -0,0 +1,7 @@
+namespace Content.Shared.EntityEffects.Effects.PlantMetabolism;
+
+public sealed partial class PlantAdjustPests : PlantAdjustAttribute<PlantAdjustPests>
+{
+    public override string GuidebookAttributeName { get; set; } = "plant-attribute-pests";
+    public override bool GuidebookIsAttributePositive { get; protected set; } = false;
+}
diff --git a/Content.Shared/EntityEffects/Effects/PlantMetabolism/PlantAdjustPotency.cs b/Content.Shared/EntityEffects/Effects/PlantMetabolism/PlantAdjustPotency.cs
new file mode 100644 (file)
index 0000000..971f05f
--- /dev/null
@@ -0,0 +1,12 @@
+// using Content.Server.Botany.Systems;
+
+namespace Content.Shared.EntityEffects.Effects.PlantMetabolism;
+
+/// <summary>
+///     Handles increase or decrease of plant potency.
+/// </summary>
+
+public sealed partial class PlantAdjustPotency : PlantAdjustAttribute<PlantAdjustPotency>
+{
+    public override string GuidebookAttributeName { get; set; } = "plant-attribute-potency";
+}
diff --git a/Content.Shared/EntityEffects/Effects/PlantMetabolism/PlantAdjustToxins.cs b/Content.Shared/EntityEffects/Effects/PlantMetabolism/PlantAdjustToxins.cs
new file mode 100644 (file)
index 0000000..9123b58
--- /dev/null
@@ -0,0 +1,8 @@
+namespace Content.Shared.EntityEffects.Effects.PlantMetabolism;
+
+public sealed partial class PlantAdjustToxins : PlantAdjustAttribute<PlantAdjustToxins>
+{
+    public override string GuidebookAttributeName { get; set; } = "plant-attribute-toxins";
+    public override bool GuidebookIsAttributePositive { get; protected set; } = false;
+}
+
diff --git a/Content.Shared/EntityEffects/Effects/PlantMetabolism/PlantAdjustWater.cs b/Content.Shared/EntityEffects/Effects/PlantMetabolism/PlantAdjustWater.cs
new file mode 100644 (file)
index 0000000..610d022
--- /dev/null
@@ -0,0 +1,7 @@
+namespace Content.Shared.EntityEffects.Effects.PlantMetabolism;
+
+public sealed partial class PlantAdjustWater : PlantAdjustAttribute<PlantAdjustWater>
+{
+    public override string GuidebookAttributeName { get; set; } = "plant-attribute-water";
+}
+
diff --git a/Content.Shared/EntityEffects/Effects/PlantMetabolism/PlantAdjustWeeds.cs b/Content.Shared/EntityEffects/Effects/PlantMetabolism/PlantAdjustWeeds.cs
new file mode 100644 (file)
index 0000000..70ff074
--- /dev/null
@@ -0,0 +1,7 @@
+namespace Content.Shared.EntityEffects.Effects.PlantMetabolism;
+
+public sealed partial class PlantAdjustWeeds : PlantAdjustAttribute<PlantAdjustWeeds>
+{
+    public override string GuidebookAttributeName { get; set; } = "plant-attribute-weeds";
+    public override bool GuidebookIsAttributePositive { get; protected set; } = false;
+}
diff --git a/Content.Shared/EntityEffects/Effects/PlantMetabolism/PlantAffectGrowth.cs b/Content.Shared/EntityEffects/Effects/PlantMetabolism/PlantAffectGrowth.cs
new file mode 100644 (file)
index 0000000..36b8f57
--- /dev/null
@@ -0,0 +1,7 @@
+namespace Content.Shared.EntityEffects.Effects.PlantMetabolism;
+
+public sealed partial class PlantAffectGrowth : PlantAdjustAttribute<PlantAffectGrowth>
+{
+    public override string GuidebookAttributeName { get; set; } = "plant-attribute-growth";
+}
+
diff --git a/Content.Shared/EntityEffects/Effects/PlantMetabolism/PlantChangeStat.cs b/Content.Shared/EntityEffects/Effects/PlantMetabolism/PlantChangeStat.cs
new file mode 100644 (file)
index 0000000..66cfb66
--- /dev/null
@@ -0,0 +1,24 @@
+using Robust.Shared.Prototypes;
+using Robust.Shared.Random;
+
+namespace Content.Shared.EntityEffects.Effects.PlantMetabolism;
+
+public sealed partial class PlantChangeStat : EventEntityEffect<PlantChangeStat>
+{
+    [DataField]
+    public string TargetValue;
+
+    [DataField]
+    public float MinValue;
+
+    [DataField]
+    public float MaxValue;
+
+    [DataField]
+    public int Steps;
+
+    protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
+    {
+        throw new NotImplementedException();
+    }
+}
diff --git a/Content.Shared/EntityEffects/Effects/PlantMetabolism/PlantCryoxadone.cs b/Content.Shared/EntityEffects/Effects/PlantMetabolism/PlantCryoxadone.cs
new file mode 100644 (file)
index 0000000..0dabf1f
--- /dev/null
@@ -0,0 +1,8 @@
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects.PlantMetabolism;
+
+public sealed partial class PlantCryoxadone : EventEntityEffect<PlantCryoxadone>
+{
+    protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) => Loc.GetString("reagent-effect-guidebook-plant-cryoxadone", ("chance", Probability));
+}
diff --git a/Content.Shared/EntityEffects/Effects/PlantMetabolism/PlantDestroySeeds.cs b/Content.Shared/EntityEffects/Effects/PlantMetabolism/PlantDestroySeeds.cs
new file mode 100644 (file)
index 0000000..9f16c35
--- /dev/null
@@ -0,0 +1,13 @@
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects.PlantMetabolism;
+
+/// <summary>
+///     Handles removal of seeds on a plant.
+/// </summary>
+
+public sealed partial class PlantDestroySeeds : EventEntityEffect<PlantDestroySeeds>
+{
+    protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) =>
+        Loc.GetString("reagent-effect-guidebook-plant-seeds-remove", ("chance", Probability));
+}
diff --git a/Content.Shared/EntityEffects/Effects/PlantMetabolism/PlantDiethylamine.cs b/Content.Shared/EntityEffects/Effects/PlantMetabolism/PlantDiethylamine.cs
new file mode 100644 (file)
index 0000000..9feccbf
--- /dev/null
@@ -0,0 +1,9 @@
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects.PlantMetabolism;
+
+public sealed partial class PlantDiethylamine : EventEntityEffect<PlantDiethylamine>
+{
+    protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) => Loc.GetString("reagent-effect-guidebook-plant-diethylamine", ("chance", Probability));
+}
+
diff --git a/Content.Shared/EntityEffects/Effects/PlantMetabolism/PlantPhalanximine.cs b/Content.Shared/EntityEffects/Effects/PlantMetabolism/PlantPhalanximine.cs
new file mode 100644 (file)
index 0000000..9dc5140
--- /dev/null
@@ -0,0 +1,8 @@
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects.PlantMetabolism;
+
+public sealed partial class PlantPhalanximine : EventEntityEffect<PlantPhalanximine>
+{
+    protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) => Loc.GetString("reagent-effect-guidebook-plant-phalanximine", ("chance", Probability));
+}
diff --git a/Content.Shared/EntityEffects/Effects/PlantMetabolism/PlantRestoreSeeds.cs b/Content.Shared/EntityEffects/Effects/PlantMetabolism/PlantRestoreSeeds.cs
new file mode 100644 (file)
index 0000000..51ce353
--- /dev/null
@@ -0,0 +1,12 @@
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects.PlantMetabolism;
+
+/// <summary>
+///     Handles restoral of seeds on a plant.
+/// </summary>
+public sealed partial class PlantRestoreSeeds : EventEntityEffect<PlantRestoreSeeds>
+{
+    protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) =>
+        Loc.GetString("reagent-effect-guidebook-plant-seeds-add", ("chance", Probability));
+}
diff --git a/Content.Shared/EntityEffects/Effects/PlantMetabolism/RobustHarvest.cs b/Content.Shared/EntityEffects/Effects/PlantMetabolism/RobustHarvest.cs
new file mode 100644 (file)
index 0000000..6ba37c9
--- /dev/null
@@ -0,0 +1,18 @@
+using Robust.Shared.Prototypes;
+using Robust.Shared.Random;
+
+namespace Content.Shared.EntityEffects.Effects.PlantMetabolism;
+
+public sealed partial class RobustHarvest : EventEntityEffect<RobustHarvest>
+{
+    [DataField]
+    public int PotencyLimit = 50;
+
+    [DataField]
+    public int PotencyIncrease = 3;
+
+    [DataField]
+    public int PotencySeedlessThreshold = 30;
+
+    protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) => Loc.GetString("reagent-effect-guidebook-plant-robust-harvest", ("seedlesstreshold", PotencySeedlessThreshold), ("limit", PotencyLimit), ("increase", PotencyIncrease), ("chance", Probability));
+}
diff --git a/Content.Shared/EntityEffects/Effects/PlantMutateChemicals.cs b/Content.Shared/EntityEffects/Effects/PlantMutateChemicals.cs
new file mode 100644 (file)
index 0000000..9a3408b
--- /dev/null
@@ -0,0 +1,16 @@
+using Content.Shared.Random;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Random;
+
+namespace Content.Shared.EntityEffects.Effects;
+
+/// <summary>
+///     changes the chemicals available in a plant's produce
+/// </summary>
+public sealed partial class PlantMutateChemicals : EventEntityEffect<PlantMutateChemicals>
+{
+    protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
+    {
+        return "TODO";
+    }
+}
diff --git a/Content.Shared/EntityEffects/Effects/PlantMutateGases.cs b/Content.Shared/EntityEffects/Effects/PlantMutateGases.cs
new file mode 100644 (file)
index 0000000..5eb5b1d
--- /dev/null
@@ -0,0 +1,39 @@
+using Robust.Shared.Prototypes;
+using Robust.Shared.Random;
+using System.Linq;
+
+namespace Content.Shared.EntityEffects.Effects;
+
+/// <summary>
+///     changes the gases that a plant or produce create.
+/// </summary>
+public sealed partial class PlantMutateExudeGasses : EventEntityEffect<PlantMutateExudeGasses>
+{
+    [DataField]
+    public float MinValue = 0.01f;
+
+    [DataField]
+    public float MaxValue = 0.5f;
+
+    protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
+    {
+        return "TODO";
+    }
+}
+
+/// <summary>
+///     changes the gases that a plant or produce consumes.
+/// </summary>
+public sealed partial class PlantMutateConsumeGasses : EventEntityEffect<PlantMutateConsumeGasses>
+{
+    [DataField]
+    public float MinValue = 0.01f;
+
+    [DataField]
+    public float MaxValue = 0.5f;
+
+    protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
+    {
+        return "TODO";
+    }
+}
diff --git a/Content.Shared/EntityEffects/Effects/PlantMutateHarvest.cs b/Content.Shared/EntityEffects/Effects/PlantMutateHarvest.cs
new file mode 100644 (file)
index 0000000..84d6293
--- /dev/null
@@ -0,0 +1,14 @@
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects;
+
+/// <summary>
+///     Upgrades a plant's harvest type.
+/// </summary>
+public sealed partial class PlantMutateHarvest : EventEntityEffect<PlantMutateHarvest>
+{
+    protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
+    {
+        return "TODO";
+    }
+}
diff --git a/Content.Shared/EntityEffects/Effects/PlantSpeciesChange.cs b/Content.Shared/EntityEffects/Effects/PlantSpeciesChange.cs
new file mode 100644 (file)
index 0000000..e2acc4c
--- /dev/null
@@ -0,0 +1,14 @@
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects;
+
+/// <summary>
+///     Changes a plant into one of the species its able to mutate into.
+/// </summary>
+public sealed partial class PlantSpeciesChange : EventEntityEffect<PlantSpeciesChange>
+{
+    protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
+    {
+        return "TODO";
+    }
+}
similarity index 55%
rename from Content.Server/EntityEffects/Effects/Polymorph.cs
rename to Content.Shared/EntityEffects/Effects/Polymorph.cs
index 2ee533a4d70013524b1e4984c186236b7f0fa491..65711ff99a9d9829e06e2b567557775752261b51 100644 (file)
@@ -1,13 +1,10 @@
-using Content.Server.Polymorph.Components;
-using Content.Server.Polymorph.Systems;
-using Content.Shared.EntityEffects;
 using Content.Shared.Polymorph;
 using Robust.Shared.Prototypes;
 using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
 
-namespace Content.Server.EntityEffects.Effects;
+namespace Content.Shared.EntityEffects.Effects;
 
-public sealed partial class Polymorph : EntityEffect
+public sealed partial class Polymorph : EventEntityEffect<Polymorph>
 {
     /// <summary>
     ///     What polymorph prototype is used on effect
@@ -19,15 +16,4 @@ public sealed partial class Polymorph : EntityEffect
     => Loc.GetString("reagent-effect-guidebook-make-polymorph",
             ("chance", Probability), ("entityname",
                 prototype.Index<EntityPrototype>(prototype.Index<PolymorphPrototype>(PolymorphPrototype).Configuration.Entity).Name));
-
-    public override void Effect(EntityEffectBaseArgs args)
-    {
-        var entityManager = args.EntityManager;
-        var uid = args.TargetEntity;
-        var polySystem = entityManager.System<PolymorphSystem>();
-
-        // Make it into a prototype
-        entityManager.EnsureComponent<PolymorphableComponent>(uid);
-        polySystem.PolymorphEntity(uid, PolymorphPrototype);
-    }
 }
similarity index 95%
rename from Content.Server/EntityEffects/Effects/PopupMessage.cs
rename to Content.Shared/EntityEffects/Effects/PopupMessage.cs
index ac22b13051b5f5efc6de7113c6946e44602f6e62..a837f816e46c172de1a0fe02e62345eddafeece0 100644 (file)
@@ -1,9 +1,8 @@
-using Content.Shared.EntityEffects;
 using Content.Shared.Popups;
 using Robust.Shared.Prototypes;
 using Robust.Shared.Random;
 
-namespace Content.Server.EntityEffects.Effects
+namespace Content.Shared.EntityEffects.Effects
 {
     public sealed partial class PopupMessage : EntityEffect
     {
diff --git a/Content.Shared/EntityEffects/Effects/ReduceRotting.cs b/Content.Shared/EntityEffects/Effects/ReduceRotting.cs
new file mode 100644 (file)
index 0000000..b5f2a7a
--- /dev/null
@@ -0,0 +1,32 @@
+using Content.Shared.Chemistry.Reagent;
+using Robust.Shared.Prototypes;
+using Content.Shared.Atmos.Rotting;
+
+namespace Content.Shared.EntityEffects.Effects;
+
+/// <summary>
+/// Reduces the rotting accumulator on the patient, making them revivable.
+/// </summary>
+public sealed partial class ReduceRotting : EntityEffect
+{
+    [DataField("seconds")]
+    public double RottingAmount = 10;
+
+    protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
+        => Loc.GetString("reagent-effect-guidebook-reduce-rotting",
+            ("chance", Probability),
+            ("time", RottingAmount));
+
+    public override void Effect(EntityEffectBaseArgs args)
+    {
+        if (args is EntityEffectReagentArgs reagentArgs)
+        {
+            if (reagentArgs.Scale != 1f)
+                return;
+        }
+
+        var rottingSys = args.EntityManager.EntitySysManager.GetEntitySystem<SharedRottingSystem>();
+
+        rottingSys.ReduceAccumulator(args.TargetEntity, TimeSpan.FromSeconds(RottingAmount));
+    }
+}
diff --git a/Content.Shared/EntityEffects/Effects/ResetNarcolepsy.cs b/Content.Shared/EntityEffects/Effects/ResetNarcolepsy.cs
new file mode 100644 (file)
index 0000000..71d228a
--- /dev/null
@@ -0,0 +1,19 @@
+using Content.Shared.Chemistry.Reagent;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects;
+
+/// <summary>
+/// Reset narcolepsy timer
+/// </summary>
+public sealed partial class ResetNarcolepsy : EventEntityEffect<ResetNarcolepsy>
+{
+    /// <summary>
+    /// The # of seconds the effect resets the narcolepsy timer to
+    /// </summary>
+    [DataField("TimerReset")]
+    public int TimerReset = 600;
+
+    protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
+        => Loc.GetString("reagent-effect-guidebook-reset-narcolepsy", ("chance", Probability));
+}
diff --git a/Content.Shared/EntityEffects/Effects/SatiateHunger.cs b/Content.Shared/EntityEffects/Effects/SatiateHunger.cs
new file mode 100644 (file)
index 0000000..3e7af88
--- /dev/null
@@ -0,0 +1,40 @@
+using Content.Shared.Chemistry.Reagent;
+using Content.Shared.Nutrition.Components;
+using Content.Shared.Nutrition.EntitySystems;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.EntityEffects.Effects;
+
+/// <summary>
+/// Attempts to find a HungerComponent on the target,
+/// and to update it's hunger values.
+/// </summary>
+public sealed partial class SatiateHunger : EntityEffect
+{
+    private const float DefaultNutritionFactor = 3.0f;
+
+    /// <summary>
+    ///     How much hunger is satiated.
+    ///     Is multiplied by quantity if used with EntityEffectReagentArgs.
+    /// </summary>
+    [DataField("factor")] public float NutritionFactor { get; set; } = DefaultNutritionFactor;
+
+    //Remove reagent at set rate, satiate hunger if a HungerComponent can be found
+    public override void Effect(EntityEffectBaseArgs args)
+    {
+        var entman = args.EntityManager;
+        if (!entman.TryGetComponent(args.TargetEntity, out HungerComponent? hunger))
+            return;
+        if (args is EntityEffectReagentArgs reagentArgs)
+        {
+            entman.System<HungerSystem>().ModifyHunger(reagentArgs.TargetEntity, NutritionFactor * (float) reagentArgs.Quantity, hunger);
+        }
+        else
+        {
+            entman.System<HungerSystem>().ModifyHunger(args.TargetEntity, NutritionFactor, hunger);
+        }
+    }
+
+    protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
+        => Loc.GetString("reagent-effect-guidebook-satiate-hunger", ("chance", Probability), ("relative", NutritionFactor / DefaultNutritionFactor));
+}
similarity index 93%
rename from Content.Server/EntityEffects/Effects/SatiateThirst.cs
rename to Content.Shared/EntityEffects/Effects/SatiateThirst.cs
index d0dbe4371b9564c3dad158849576df817fe5b55b..21a055b528cec1f50a5744373bcf683eaec056c7 100644 (file)
@@ -1,10 +1,9 @@
 using Content.Shared.Chemistry.Reagent;
-using Content.Shared.EntityEffects;
 using Content.Shared.Nutrition.Components;
 using Content.Shared.Nutrition.EntitySystems;
 using Robust.Shared.Prototypes;
 
-namespace Content.Server.EntityEffects.Effects;
+namespace Content.Shared.EntityEffects.Effects;
 
 /// <summary>
 /// Default metabolism for drink reagents. Attempts to find a ThirstComponent on the target,
similarity index 95%
rename from Content.Server/EntityEffects/Effects/Slipify.cs
rename to Content.Shared/EntityEffects/Effects/Slipify.cs
index bc1cc062a387d823c54b8dc59cf47ce5f084cfa1..c152b8b0100720b87efbb3f82910ffb26c91a3eb 100644 (file)
@@ -1,4 +1,3 @@
-using Content.Shared.EntityEffects;
 using Content.Shared.Physics;
 using Content.Shared.Slippery;
 using Content.Shared.StepTrigger.Components;
@@ -7,7 +6,7 @@ using Robust.Shared.Physics.Components;
 using Robust.Shared.Physics.Systems;
 using Robust.Shared.Prototypes;
 
-namespace Content.Server.EntityEffects.Effects;
+namespace Content.Shared.EntityEffects.Effects;
 
 /// <summary>
 ///     Makes a mob slippery.
similarity index 98%
rename from Content.Server/EntityEffects/Effects/SolutionTemperatureEffects.cs
rename to Content.Shared/EntityEffects/Effects/SolutionTemperatureEffects.cs
index 85c20dbcd11dc6ab89a0483a705c1a404ef2ce04..30ac6c3d77d2724f90fe4fd39aefca59eced9a4a 100644 (file)
@@ -1,8 +1,7 @@
 using Content.Shared.Chemistry.Reagent;
-using Content.Shared.EntityEffects;
 using Robust.Shared.Prototypes;
 
-namespace Content.Server.EntityEffects.Effects;
+namespace Content.Shared.EntityEffects.Effects;
 
 /// <summary>
 ///     Sets the temperature of the solution involved with the reaction to a new value.
similarity index 94%
rename from Content.Server/EntityEffects/Effects/StatusEffects/GenericStatusEffect.cs
rename to Content.Shared/EntityEffects/Effects/StatusEffects/GenericStatusEffect.cs
index bb9bbf344699ec44e54987098d44e6c3d1d8f7c5..c6b162a82f89ff256556c0db4e4b027d37a3565a 100644 (file)
@@ -1,10 +1,8 @@
 using Content.Shared.Chemistry.Reagent;
-using Content.Shared.EntityEffects;
 using Content.Shared.StatusEffect;
-using JetBrains.Annotations;
 using Robust.Shared.Prototypes;
 
-namespace Content.Server.EntityEffects.Effects.StatusEffects;
+namespace Content.Shared.EntityEffects.Effects.StatusEffects;
 
 /// <summary>
 ///     Adds a generic status effect to the entity,
@@ -15,7 +13,6 @@ namespace Content.Server.EntityEffects.Effects.StatusEffects;
 /// <remarks>
 ///     Can be used for things like adding accents or something. I don't know. Go wild.
 /// </remarks>
-[UsedImplicitly]
 public sealed partial class GenericStatusEffect : EntityEffect
 {
     [DataField(required: true)]
similarity index 92%
rename from Content.Server/EntityEffects/Effects/StatusEffects/Jitter.cs
rename to Content.Shared/EntityEffects/Effects/StatusEffects/Jitter.cs
index dbca4fad5882f89f3c77be9202d7118018e9fdc5..891c791b07bd7041dbe9648d52fd7f9c4a1387fd 100644 (file)
@@ -1,9 +1,8 @@
 using Content.Shared.Chemistry.Reagent;
-using Content.Shared.EntityEffects;
 using Content.Shared.Jittering;
 using Robust.Shared.Prototypes;
 
-namespace Content.Server.EntityEffects.Effects.StatusEffects;
+namespace Content.Shared.EntityEffects.Effects.StatusEffects;
 
 /// <summary>
 ///     Adds the jitter status effect to a mob.
similarity index 67%
rename from Content.Server/EntityEffects/Effects/WashCreamPieReaction.cs
rename to Content.Shared/EntityEffects/Effects/WashCreamPieReaction.cs
index 67bfac6335d462a8e8132901c37dd586ed3d38f8..e6992a3ec83c395d28baf3fdb6fa87bb0b21baf7 100644 (file)
@@ -1,13 +1,10 @@
-using Content.Server.Nutrition.EntitySystems;
 using Content.Shared.Chemistry.Reagent;
-using Content.Shared.EntityEffects;
 using Content.Shared.Nutrition.Components;
-using JetBrains.Annotations;
+using Content.Shared.Nutrition.EntitySystems;
 using Robust.Shared.Prototypes;
 
-namespace Content.Server.EntityEffects.Effects;
+namespace Content.Shared.EntityEffects.Effects;
 
-[UsedImplicitly]
 public sealed partial class WashCreamPieReaction : EntityEffect
 {
     protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
@@ -17,6 +14,6 @@ public sealed partial class WashCreamPieReaction : EntityEffect
     {
         if (!args.EntityManager.TryGetComponent(args.TargetEntity, out CreamPiedComponent? creamPied)) return;
 
-        args.EntityManager.System<CreamPieSystem>().SetCreamPied(args.TargetEntity, creamPied, false);
+        args.EntityManager.System<SharedCreamPieSystem>().SetCreamPied(args.TargetEntity, creamPied, false);
     }
 }
similarity index 94%
rename from Content.Server/EntityEffects/Effects/WearableReaction.cs
rename to Content.Shared/EntityEffects/Effects/WearableReaction.cs
index 9655bbc073f099d88abd0d57b81d0ed963b6ae2c..08c28f9821ca920f551c9f02f302193e1664ea36 100644 (file)
@@ -1,9 +1,8 @@
 using Content.Shared.Inventory;
 using Content.Shared.Chemistry.Reagent;
-using Content.Shared.EntityEffects;
 using Robust.Shared.Prototypes;
 
-namespace Content.Server.EntityEffects.Effects.Effects;
+namespace Content.Shared.EntityEffects.Effects;
 
 /// <summary>
 /// A reaction effect that spawns a PrototypeID in the entity's Slot, and attempts to consume the reagent if EntityEffectReagentArgs.
index 21e79f224de7021cca1e5625a86eb2cde2c46c49..998759006f956e07c74aff2164c8915e442a5e63 100644 (file)
@@ -89,6 +89,19 @@ public static class EntityEffectExt
     }
 }
 
+[ByRefEvent]
+public struct ExecuteEntityEffectEvent<T> where T : EntityEffect
+{
+    public T Effect;
+    public EntityEffectBaseArgs Args;
+
+    public ExecuteEntityEffectEvent(T effect, EntityEffectBaseArgs args)
+    {
+        Effect = effect;
+        Args = args;
+    }
+}
+
 /// <summary>
 ///     EntityEffectBaseArgs only contains the target of an effect.
 ///     If a trigger wants to include more info (e.g. the quantity of the chemical triggering the effect), it can be extended (see EntityEffectReagentArgs).
index d6028b9f2c4d92590885579f0eaf20144d364abc..4c27b1e6edcbd38b3f16c845ee0fdabe24d2e73e 100644 (file)
@@ -20,3 +20,10 @@ public abstract partial class EntityEffectCondition
     public abstract string GuidebookExplanation(IPrototypeManager prototype);
 }
 
+[ByRefEvent]
+public struct CheckEntityEffectConditionEvent<T> where T : EntityEffectCondition
+{
+    public T Condition;
+    public EntityEffectBaseArgs Args;
+    public bool Result;
+}
diff --git a/Content.Shared/EntityEffects/EventEntityEffect.cs b/Content.Shared/EntityEffects/EventEntityEffect.cs
new file mode 100644 (file)
index 0000000..22cd035
--- /dev/null
@@ -0,0 +1,12 @@
+namespace Content.Shared.EntityEffects;
+
+public abstract partial class EventEntityEffect<T> : EntityEffect where T : EntityEffect
+{
+    public override void Effect(EntityEffectBaseArgs args)
+    {
+        if (this is not T type)
+            return;
+        var ev = new ExecuteEntityEffectEvent<T>(type, args);
+        args.EntityManager.EventBus.RaiseEvent(EventSource.Local, ref ev);
+    }
+}
diff --git a/Content.Shared/EntityEffects/EventEntityEffectCondition.cs b/Content.Shared/EntityEffects/EventEntityEffectCondition.cs
new file mode 100644 (file)
index 0000000..f36b177
--- /dev/null
@@ -0,0 +1,14 @@
+namespace Content.Shared.EntityEffects;
+
+public abstract partial class EventEntityEffectCondition<T> : EntityEffectCondition where T : EventEntityEffectCondition<T>
+{
+    public override bool Condition(EntityEffectBaseArgs args)
+    {
+        if (this is not T type)
+            return false;
+
+        var evt = new CheckEntityEffectConditionEvent<T> { Condition = type, Args = args };
+        args.EntityManager.EventBus.RaiseEvent(EventSource.Local, ref evt);
+        return evt.Result;
+    }
+}