]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Liquid anomaly (#20626)
authorEd <96445749+TheShuEd@users.noreply.github.com>
Sat, 7 Oct 2023 00:26:34 +0000 (03:26 +0300)
committerGitHub <noreply@github.com>
Sat, 7 Oct 2023 00:26:34 +0000 (17:26 -0700)
Co-authored-by: Kara <lunarautomaton6@gmail.com>
17 files changed:
Content.Server/Anomaly/Components/InjectionAnomalyComponent.cs [new file with mode: 0644]
Content.Server/Anomaly/Components/PuddleCreateAnomalyComponent.cs [new file with mode: 0644]
Content.Server/Anomaly/Components/ReagentProducerAnomalyComponent.cs [new file with mode: 0644]
Content.Server/Anomaly/Effects/InjectionAnomalySystem.cs [new file with mode: 0644]
Content.Server/Anomaly/Effects/PuddleCreateAnomalySystem.cs [new file with mode: 0644]
Content.Server/Anomaly/Effects/ReagentProducerAnomalySystem.cs [new file with mode: 0644]
Resources/Audio/Effects/attributions.yml
Resources/Audio/Effects/waterswirl.ogg [new file with mode: 0644]
Resources/Prototypes/Entities/Markers/Spawners/Random/anomaly.yml
Resources/Prototypes/Entities/Mobs/NPCs/elemental.yml
Resources/Prototypes/Entities/Structures/Specific/anomalies.yml
Resources/Textures/Mobs/Aliens/elemental.rsi/alive.png [new file with mode: 0644]
Resources/Textures/Mobs/Aliens/elemental.rsi/dead.png [new file with mode: 0644]
Resources/Textures/Mobs/Aliens/elemental.rsi/meta.json [new file with mode: 0644]
Resources/Textures/Structures/Specific/Anomalies/liquid_anom.rsi/anom.png [new file with mode: 0644]
Resources/Textures/Structures/Specific/Anomalies/liquid_anom.rsi/meta.json [new file with mode: 0644]
Resources/Textures/Structures/Specific/Anomalies/liquid_anom.rsi/pulse.png [new file with mode: 0644]

diff --git a/Content.Server/Anomaly/Components/InjectionAnomalyComponent.cs b/Content.Server/Anomaly/Components/InjectionAnomalyComponent.cs
new file mode 100644 (file)
index 0000000..4a9b5b6
--- /dev/null
@@ -0,0 +1,47 @@
+using Content.Server.Anomaly.Effects;
+using Robust.Shared.Prototypes;
+
+namespace Content.Server.Anomaly.Components;
+
+/// <summary>
+/// This component allows the anomaly to inject liquid from the SolutionContainer
+/// into the surrounding entities with the InjectionSolution component
+/// </summary>
+
+[RegisterComponent, Access(typeof(InjectionAnomalySystem))]
+public sealed partial class InjectionAnomalyComponent : Component
+{
+    /// <summary>
+    /// the maximum amount of injection of a substance into an entity per pulsation
+    /// scales with Severity
+    /// </summary>
+    [DataField, ViewVariables(VVAccess.ReadWrite)]
+    public float MaxSolutionInjection = 15;
+    /// <summary>
+    /// the maximum amount of injection of a substance into an entity in the supercritical phase
+    /// </summary>
+    [DataField, ViewVariables(VVAccess.ReadWrite)]
+    public float SuperCriticalSolutionInjection = 50;
+
+    /// <summary>
+    /// The maximum radius in which the anomaly injects reagents into the surrounding containers.
+    /// </summary>
+    [DataField, ViewVariables(VVAccess.ReadWrite)]
+    public float InjectRadius = 3;
+    /// <summary>
+    /// The maximum radius in which the anomaly injects reagents into the surrounding containers.
+    /// </summary>
+    [DataField, ViewVariables(VVAccess.ReadWrite)]
+    public float SuperCriticalInjectRadius = 15;
+
+    /// <summary>
+    /// The name of the prototype of the special effect that appears above the entities into which the injection was carried out
+    /// </summary>
+    [DataField, ViewVariables(VVAccess.ReadOnly)]
+    public EntProtoId VisualEffectPrototype = "PuddleSparkle";
+    /// <summary>
+    /// Solution name that can be drained.
+    /// </summary>
+    [DataField, ViewVariables(VVAccess.ReadWrite)]
+    public string Solution { get; set; } = "default";
+}
diff --git a/Content.Server/Anomaly/Components/PuddleCreateAnomalyComponent.cs b/Content.Server/Anomaly/Components/PuddleCreateAnomalyComponent.cs
new file mode 100644 (file)
index 0000000..78c50b3
--- /dev/null
@@ -0,0 +1,29 @@
+using Content.Server.Anomaly.Effects;
+
+namespace Content.Server.Anomaly.Components;
+
+/// <summary>
+/// This component allows the anomaly to create puddles from the solutionContainer
+/// </summary>
+[RegisterComponent, Access(typeof(PuddleCreateAnomalySystem))]
+public sealed partial class PuddleCreateAnomalyComponent : Component
+{
+    /// <summary>
+    /// The maximum amount of solution that an anomaly can splash out of the storage on the floor during pulsation.
+    /// Scales with Severity.
+    /// </summary>
+    [DataField, ViewVariables(VVAccess.ReadWrite)]
+    public float MaxPuddleSize = 100;
+
+    /// <summary>
+    /// The maximum amount of solution that an anomaly can splash out of the storage on the floor during supercritical event
+    /// </summary>
+    [DataField, ViewVariables(VVAccess.ReadWrite)]
+    public float SuperCriticalPuddleSize = 1000;
+
+    /// <summary>
+    /// Solution name that can be drained.
+    /// </summary>
+    [DataField, ViewVariables(VVAccess.ReadWrite)]
+    public string Solution { get; set; } = "default";
+}
diff --git a/Content.Server/Anomaly/Components/ReagentProducerAnomalyComponent.cs b/Content.Server/Anomaly/Components/ReagentProducerAnomalyComponent.cs
new file mode 100644 (file)
index 0000000..aa860c1
--- /dev/null
@@ -0,0 +1,94 @@
+using Content.Server.Anomaly.Effects;
+using Content.Shared.Chemistry.Reagent;
+using Robust.Shared.Audio;
+using Robust.Shared.Prototypes;
+using System.Numerics;
+
+namespace Content.Server.Anomaly.Components;
+/// <summary>
+/// This component allows the anomaly to generate a random type of reagent in the specified SolutionContainer.
+/// With the increasing severity of the anomaly, the type of reagent produced may change.
+/// The higher the severity of the anomaly, the higher the chance of dangerous or useful reagents.
+/// </summary>
+[RegisterComponent, Access(typeof(ReagentProducerAnomalySystem))]
+public sealed partial class ReagentProducerAnomalyComponent : Component
+{
+    //the addition of the reagent will occur instantly when an anomaly appears,
+    //and there will not be the first three seconds of a white empty anomaly.
+    public float AccumulatedFrametime = 3.0f;
+    /// <summary>
+    ///     How frequently should this reagent generation update, in seconds?
+    /// </summary>
+    [DataField, ViewVariables(VVAccess.ReadWrite)]
+    public float UpdateInterval = 3.0f;
+
+    /// <summary>
+    /// The spread of the random weight of the choice of this category, depending on the severity.
+    /// </summary>
+    [DataField, ViewVariables(VVAccess.ReadWrite)]
+    public Vector2 WeightSpreadDangerous = new(5.0f, 9.0f);
+    /// <summary>
+    /// The spread of the random weight of the choice of this category, depending on the severity.
+    /// </summary>
+    [DataField, ViewVariables(VVAccess.ReadWrite)]
+    public Vector2 WeightSpreadFun = new(3.0f, 0.0f);
+    /// <summary>
+    /// The spread of the random weight of the choice of this category, depending on the severity.
+    /// </summary>
+    [DataField, ViewVariables(VVAccess.ReadWrite)]
+    public Vector2 WeightSpreadUseful = new(1.0f, 1.0f);
+
+    /// <summary>
+    /// Category of dangerous reagents for injection. Various toxins and poisons
+    /// </summary>
+    [DataField, ViewVariables(VVAccess.ReadWrite)]
+    public List<ProtoId<ReagentPrototype>> DangerousChemicals = new();
+    /// <summary>
+    /// Category of useful reagents for injection. Medicine and other things that players WANT to get
+    /// </summary>
+    [DataField, ViewVariables(VVAccess.ReadWrite)]
+    public List<ProtoId<ReagentPrototype>> UsefulChemicals = new();
+    /// <summary>
+    /// Category of fun reagents for injection. Glue, drugs, beer. Something that will bring fun.
+    /// </summary>
+    [DataField, ViewVariables(VVAccess.ReadWrite)]
+    public List<ProtoId<ReagentPrototype>> FunChemicals = new();
+
+    /// <summary>
+    /// Noise made when anomaly pulse.
+    /// </summary>
+    [DataField, ViewVariables(VVAccess.ReadWrite)]
+    public SoundSpecifier ChangeSound = new SoundPathSpecifier("/Audio/Effects/waterswirl.ogg");
+    /// <summary>
+    /// The component will repaint the sprites of the object to match the current color of the solution,
+    /// if the RandomSprite component is hung correctly.
+    /// Ideally, this should be put into a separate component, but I suffered for 4 hours,
+    /// and nothing worked out for me. So for now it will be like this.
+    /// </summary>
+    [DataField, ViewVariables(VVAccess.ReadOnly)]
+    public bool NeedRecolor = false;
+
+    /// <summary>
+    /// the maximum amount of reagent produced per second
+    /// </summary>
+    [DataField, ViewVariables(VVAccess.ReadWrite)]
+    public float MaxReagentProducing = 1.5f;
+
+    /// <summary>
+    /// how much does the reagent production increase before entering the supercritical state
+    /// </summary>
+    [DataField, ViewVariables(VVAccess.ReadWrite)]
+    public float SupercriticalReagentProducingModifier = 100f;
+
+    /// <summary>
+    /// The name of the reagent that the anomaly produces.
+    /// </summary>
+    [DataField, ViewVariables(VVAccess.ReadWrite)]
+    public ProtoId<ReagentPrototype> ProducingReagent = "Water";
+    /// <summary>
+    /// Solution name where the substance is generated
+    /// </summary>
+    [ViewVariables(VVAccess.ReadWrite)]
+    [DataField("solution")]
+    public string Solution = "default";
+}
diff --git a/Content.Server/Anomaly/Effects/InjectionAnomalySystem.cs b/Content.Server/Anomaly/Effects/InjectionAnomalySystem.cs
new file mode 100644 (file)
index 0000000..acc0e2f
--- /dev/null
@@ -0,0 +1,67 @@
+using System.Linq;
+using Content.Server.Anomaly.Components;
+using Content.Server.Chemistry.Components.SolutionManager;
+using Content.Server.Chemistry.EntitySystems;
+using Content.Shared.Anomaly.Components;
+
+namespace Content.Server.Anomaly.Effects;
+/// <summary>
+/// This component allows the anomaly to inject liquid from the SolutionContainer
+/// into the surrounding entities with the InjectionSolution component
+/// </summary>
+///
+
+/// <see cref="InjectionAnomalyComponent"/>
+public sealed class InjectionAnomalySystem : EntitySystem
+{
+    [Dependency] private readonly EntityLookupSystem _lookup = default!;
+    [Dependency] private readonly SolutionContainerSystem _solutionContainer = default!;
+
+    private EntityQuery<InjectableSolutionComponent> _injectableQuery;
+
+    public override void Initialize()
+    {
+        SubscribeLocalEvent<InjectionAnomalyComponent, AnomalyPulseEvent>(OnPulse);
+        SubscribeLocalEvent<InjectionAnomalyComponent, AnomalySupercriticalEvent>(OnSupercritical, before: new[] { typeof(SolutionContainerSystem) });
+
+        _injectableQuery = GetEntityQuery<InjectableSolutionComponent>();
+    }
+
+    private void OnPulse(EntityUid uid, InjectionAnomalyComponent component, ref AnomalyPulseEvent args)
+    {
+        PulseScalableEffect(uid, component, component.InjectRadius, component.MaxSolutionInjection * args.Severity);
+    }
+
+    private void OnSupercritical(EntityUid uid, InjectionAnomalyComponent component, ref AnomalySupercriticalEvent args)
+    {
+        PulseScalableEffect(uid, component, component.SuperCriticalInjectRadius, component.SuperCriticalSolutionInjection);
+    }
+
+    private void PulseScalableEffect(EntityUid uid, InjectionAnomalyComponent component, float injectRadius, float maxInject)
+    {
+        if (!_solutionContainer.TryGetSolution(uid, component.Solution, out var sol))
+            return;
+        //We get all the entity in the radius into which the reagent will be injected.
+        var xformQuery = GetEntityQuery<TransformComponent>();
+        var xform = xformQuery.GetComponent(uid);
+        var allEnts = _lookup.GetComponentsInRange<InjectableSolutionComponent>(xform.MapPosition, injectRadius)
+            .Select(x => x.Owner).ToList();
+
+        //for each matching entity found
+        foreach (var ent in allEnts)
+        {
+            if (!_solutionContainer.TryGetInjectableSolution(ent, out var injectable))
+                continue;
+
+            if (_injectableQuery.TryGetComponent(ent, out var injEnt))
+            {
+                var buffer = sol;
+                _solutionContainer.TryTransferSolution(ent, injectable, buffer, maxInject);
+                //Spawn Effect
+                var uidXform = Transform(ent);
+                Spawn(component.VisualEffectPrototype, uidXform.Coordinates);
+            }
+        }
+    }
+
+}
diff --git a/Content.Server/Anomaly/Effects/PuddleCreateAnomalySystem.cs b/Content.Server/Anomaly/Effects/PuddleCreateAnomalySystem.cs
new file mode 100644 (file)
index 0000000..deae38e
--- /dev/null
@@ -0,0 +1,39 @@
+using Content.Server.Anomaly.Components;
+using Content.Server.Chemistry.EntitySystems;
+using Content.Shared.Anomaly.Components;
+using Content.Server.Fluids.EntitySystems;
+
+namespace Content.Server.Anomaly.Effects;
+
+/// <summary>
+/// This component allows the anomaly to create puddles from SolutionContainer.
+/// </summary>
+public sealed class PuddleCreateAnomalySystem : EntitySystem
+{
+    [Dependency] private readonly PuddleSystem _puddle = default!;
+    [Dependency] private readonly SolutionContainerSystem _solutionContainer = default!;
+
+    public override void Initialize()
+    {
+        SubscribeLocalEvent<PuddleCreateAnomalyComponent, AnomalyPulseEvent>(OnPulse);
+        SubscribeLocalEvent<PuddleCreateAnomalyComponent, AnomalySupercriticalEvent>(OnSupercritical, before: new[] { typeof(InjectionAnomalySystem) });
+    }
+
+    private void OnPulse(EntityUid uid, PuddleCreateAnomalyComponent component, ref AnomalyPulseEvent args)
+    {
+        if (!_solutionContainer.TryGetSolution(uid, component.Solution, out var sol))
+            return;
+
+        var xform = Transform(uid);
+        var puddleSol = _solutionContainer.SplitSolution(uid, sol, component.MaxPuddleSize * args.Severity);
+        _puddle.TrySplashSpillAt(uid, xform.Coordinates, puddleSol, out _);
+    }
+    private void OnSupercritical(EntityUid uid, PuddleCreateAnomalyComponent component, ref AnomalySupercriticalEvent args)
+    {
+        if (!_solutionContainer.TryGetSolution(uid, component.Solution, out var sol))
+            return;
+        var buffer = sol;
+        var xform = Transform(uid);
+        _puddle.TrySpillAt(xform.Coordinates, buffer, out _);
+    }
+}
diff --git a/Content.Server/Anomaly/Effects/ReagentProducerAnomalySystem.cs b/Content.Server/Anomaly/Effects/ReagentProducerAnomalySystem.cs
new file mode 100644 (file)
index 0000000..fdfff42
--- /dev/null
@@ -0,0 +1,152 @@
+using Content.Server.Anomaly.Components;
+using Content.Server.Chemistry.EntitySystems;
+using Content.Shared.Anomaly.Components;
+using Robust.Shared.Random;
+using Content.Shared.Chemistry.Components;
+using Robust.Shared.Prototypes;
+using Content.Shared.Sprite;
+using Robust.Server.GameObjects;
+
+namespace Content.Server.Anomaly.Effects;
+
+/// <see cref="ReagentProducerAnomalyComponent"/>
+
+public sealed class ReagentProducerAnomalySystem : EntitySystem
+{
+    //The idea is to divide substances into several categories.
+    //The anomaly will choose one of the categories with a given chance based on severity.
+    //Then a random substance will be selected from the selected category.
+    //There are the following categories:
+
+    //Dangerous:
+    //selected most often. A list of substances that are extremely unpleasant for injection.
+
+    //Fun:
+    //Funny things have an increased chance of appearing in an anomaly.
+
+    //Useful:
+    //Those reagents that the players are hunting for. Very low percentage of loss.
+
+    [Dependency] private readonly SolutionContainerSystem _solutionContainer = default!;
+    [Dependency] private readonly IRobustRandom _random = default!;
+    [Dependency] private readonly PointLightSystem _light = default!;
+    [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
+    [Dependency] private readonly SharedAudioSystem _audio = default!;
+    
+    public const string FallbackReagent = "Water";
+
+    public override void Initialize()
+    {
+        SubscribeLocalEvent<ReagentProducerAnomalyComponent, AnomalyPulseEvent>(OnPulse);
+        SubscribeLocalEvent<ReagentProducerAnomalyComponent, MapInitEvent>(OnMapInit);
+    }
+
+    private void OnPulse(EntityUid uid, ReagentProducerAnomalyComponent component, ref AnomalyPulseEvent args)
+    {
+        if (_random.NextFloat(0.0f, 1.0f) > args.Stability)
+            ChangeReagent(uid, component, args.Severity);
+    }
+
+    private void ChangeReagent(EntityUid uid, ReagentProducerAnomalyComponent component, float severity)
+    {
+        var reagent = GetRandomReagentType(uid, component, severity);
+        component.ProducingReagent = reagent;
+        _audio.PlayPvs(component.ChangeSound, uid);
+    }
+
+    //reagent realtime generation
+    public override void Update(float frameTime)
+    {
+        base.Update(frameTime);
+
+        var query = EntityQueryEnumerator<ReagentProducerAnomalyComponent, AnomalyComponent>();
+        while (query.MoveNext(out var uid, out var component, out var anomaly))
+        {
+            component.AccumulatedFrametime += frameTime;
+
+            if (component.AccumulatedFrametime < component.UpdateInterval)
+                continue;
+
+            if (!_solutionContainer.TryGetSolution(uid, component.Solution, out var producerSol))
+                continue;
+
+            Solution newSol = new();
+            var reagentProducingAmount = anomaly.Stability * component.MaxReagentProducing * component.AccumulatedFrametime;
+            if (anomaly.Severity >= 0.97) reagentProducingAmount *= component.SupercriticalReagentProducingModifier;
+
+            newSol.AddReagent(component.ProducingReagent, reagentProducingAmount);
+            _solutionContainer.TryAddSolution(uid, producerSol, newSol); //TO DO - the container is not fully filled. 
+
+            component.AccumulatedFrametime = 0;
+
+            // The component will repaint the sprites of the object to match the current color of the solution,
+            // if the RandomSprite component is hung correctly.
+
+            // Ideally, this should be put into a separate component, but I suffered for 4 hours,
+            // and nothing worked out for me. So for now it will be like this.
+            if (component.NeedRecolor)
+            {
+                var color = producerSol.GetColor(_prototypeManager);
+                _light.SetColor(uid, color);
+                if (TryComp<RandomSpriteComponent>(uid, out var randomSprite))
+                {
+                    foreach (var ent in randomSprite.Selected)
+                    {
+                        var state = randomSprite.Selected[ent.Key];
+                        state.Color = color;
+                        randomSprite.Selected[ent.Key] = state;
+                    }
+                    Dirty(uid, randomSprite);
+                }
+            }
+        }
+    }
+
+    private void OnMapInit(EntityUid uid, ReagentProducerAnomalyComponent component, MapInitEvent args)
+    {
+        ChangeReagent(uid, component, 0.1f); //MapInit Reagent 100% change
+    }
+
+    // returns a random reagent based on a system of random weights.
+    // First, the category is selected: The category has a minimum and maximum weight,
+    // the current value depends on severity.
+    // Accordingly, with the strengthening of the anomaly,
+    // the chances of falling out of some categories grow, and some fall.
+    //
+    // After that, a random reagent in the selected category is selected.
+    //
+    // Such a system is made to control the danger and interest of the anomaly more.
+    private string GetRandomReagentType(EntityUid uid, ReagentProducerAnomalyComponent component, float severity)
+    {
+        //Category Weight Randomization
+        var currentWeightDangerous = MathHelper.Lerp(component.WeightSpreadDangerous.X, component.WeightSpreadDangerous.Y, severity);
+        var currentWeightFun = MathHelper.Lerp(component.WeightSpreadFun.X, component.WeightSpreadFun.Y, severity);
+        var currentWeightUseful = MathHelper.Lerp(component.WeightSpreadUseful.X, component.WeightSpreadUseful.Y, severity);
+
+        var sumWeight = currentWeightDangerous + currentWeightFun + currentWeightUseful;
+        var rnd = _random.NextFloat(0f, sumWeight);
+        //Dangerous
+        if (rnd <= currentWeightDangerous && component.DangerousChemicals.Count > 0)
+        {
+            var reagent = _random.Pick(component.DangerousChemicals);
+            return reagent;
+        }
+        else rnd -= currentWeightDangerous;
+        //Fun
+        if (rnd <= currentWeightFun && component.FunChemicals.Count > 0)
+        {
+            var reagent = _random.Pick(component.FunChemicals);
+            return reagent;
+        }
+        else rnd -= currentWeightFun;
+        //Useful
+        if (rnd <= currentWeightUseful && component.UsefulChemicals.Count > 0)
+        {
+            var reagent = _random.Pick(component.UsefulChemicals);
+            return reagent;
+        }
+        //We should never end up here.
+        //Maybe Log Error?
+        return FallbackReagent;
+    }
+}
index f9239f4dab977dae6633250cbf43f1f8e4fb8f14..71a2ae2b53c0a0a09f0238fd15e5a6d8fb5d0371 100644 (file)
@@ -56,4 +56,9 @@
 - files: ["break_stone.ogg"]
   license: "CC-BY-SA-3.0"
   copyright: "Taken from tgstation"
-  source: "https://github.com/tgstation/tgstation/blob/e3a835b96043fad1269ee7b0c3a6cb340a466f3a/sound/effects/break_stone.ogg"
\ No newline at end of file
+  source: "https://github.com/tgstation/tgstation/blob/e3a835b96043fad1269ee7b0c3a6cb340a466f3a/sound/effects/break_stone.ogg"
+  
+- files: ["waterswirl.ogg"]
+  license: "CC0-1.0"
+  copyright: "Taken from InspectorJ via freesound.org and mixed from stereo to mono."
+  source: "https://freesound.org/people/InspectorJ/sounds/398703/"
diff --git a/Resources/Audio/Effects/waterswirl.ogg b/Resources/Audio/Effects/waterswirl.ogg
new file mode 100644 (file)
index 0000000..d8c9755
Binary files /dev/null and b/Resources/Audio/Effects/waterswirl.ogg differ
index e1f1e56480e2fc40526019402f9f645300892488..043bf707b4db8a7e3de6176eebd4dfecb870767a 100644 (file)
@@ -17,4 +17,5 @@
     - AnomalyBluespace
     - AnomalyIce
     - AnomalyRock
+    - AnomalyLiquid
     chance: 1
index a49d0955359704aad30037a28ff72a0394aa763e..beed7db43ce2c7f7eefb65d2bff084072778ad1c 100644 (file)
     radius: 2
     energy: 3
     color: "#06DF24"
+
+- type: entity
+  name: Reagent slime
+  id: ReagentSlime
+  suffix: Water
+  parent: MobAdultSlimes
+  description: It consists of a liquid, and it wants to dissolve you in itself.
+  components:
+  - type: NpcFactionMember
+    factions:
+    - SimpleHostile 
+  - type: Sprite
+    drawdepth: Mobs
+    sprite: Mobs/Aliens/elemental.rsi
+    layers:
+      - map: [ "enum.DamageStateVisualLayers.Base" ]
+        state: alive
+        color: "#75b1f0"
+  - type: PointLight
+    radius: 2.0
+    energy: 3.5
+    color: "#75b1f0" # Edited through the LiquidAnomalySystem
+  - type: MobState
+    allowedStates:
+    - Alive
+    - Dead
+  - type: MobThresholds
+    thresholds:
+      0: Alive
+      150: Dead
+  - type: SlowOnDamage
+    speedModifierThresholds:
+      50: 0.4
+  - type: Bloodstream
+    bloodReagent: Water 
+    chemicalMaxVolume: 100
+  - type: StatusEffects
+    allowed:
+    - SlowedDown
+    - Electrocution
+  - type: MeleeWeapon
+    soundHit:
+      collection: AlienClaw
+    animation: WeaponArcBite
+    damage:
+      types:
+        Slash: 15
+  - type: MeleeChemicalInjector
+    solution: bloodstream
+    transferAmount: 5
+  - type: DamageStateVisuals
+    rotate: true
+    states:
+      Alive:
+        Base: alive
+      Dead:
+        Base: dead
+  - type: Tag
+    tags:
+      - FootstepSound
+      - CannotSuicide
+      - DoorBumpOpener
+  - type: NoSlip
+  - type: ZombieImmune
+  - type: ExaminableSolution
+    solution: bloodstream
+  - type: InjectableSolution
+    solution: bloodstream
+  - type: DrainableSolution
+    solution: bloodstream
+
+- type: entity
+  name: Reagent Slime Spawner
+  id: ReagentSlimeSpawner
+  parent: MarkerBase
+  components:
+    - type: Sprite
+      layers:
+        - state: red
+        - sprite: Mobs/Aliens/elemental.rsi
+          state: alive
+    - type: RandomSpawner
+      prototypes:
+        - ReagentSlime
+        - ReagentSlimeBeer
+        - ReagentSlimePax
+        - ReagentSlimeNocturine
+        - ReagentSlimeTHC
+        - ReagentSlimeBicaridine
+        - ReagentSlimeToxin
+        - ReagentSlimeNapalm
+        - ReagentSlimeOmnizine
+      chance: 1
+
+- type: entity
+  id: ReagentSlimeBeer
+  parent: ReagentSlime
+  suffix: Beer
+  components:
+  - type: Bloodstream
+    bloodReagent: Beer
+  - type: PointLight
+    color: "#cfa85f"
+  - type: Sprite
+    drawdepth: Mobs
+    sprite: Mobs/Aliens/elemental.rsi
+    layers:
+      - map: [ "enum.DamageStateVisualLayers.Base" ]
+        state: alive
+        color: "#cfa85f"
+
+- type: entity
+  id: ReagentSlimePax
+  parent: ReagentSlime
+  suffix: Pax
+  components:
+  - type: Bloodstream
+    bloodReagent: Pax
+  - type: PointLight
+    color: "#AAAAAA"
+  - type: Sprite
+    drawdepth: Mobs
+    sprite: Mobs/Aliens/elemental.rsi
+    layers:
+      - map: [ "enum.DamageStateVisualLayers.Base" ]
+        state: alive
+        color: "#AAAAAA"
+
+- type: entity
+  id: ReagentSlimeNocturine
+  parent: ReagentSlime
+  suffix: Nocturine
+  components:
+  - type: Bloodstream
+    bloodReagent: Nocturine
+  - type: PointLight
+    color: "#128e80"
+  - type: Sprite
+    drawdepth: Mobs
+    sprite: Mobs/Aliens/elemental.rsi
+    layers:
+      - map: [ "enum.DamageStateVisualLayers.Base" ]
+        state: alive
+        color: "#128e80"
+        
+- type: entity
+  id: ReagentSlimeTHC
+  parent: ReagentSlime
+  suffix: THC
+  components:
+  - type: Bloodstream
+    bloodReagent: THC
+  - type: PointLight
+    color: "#808080"
+  - type: Sprite
+    drawdepth: Mobs
+    sprite: Mobs/Aliens/elemental.rsi
+    layers:
+      - map: [ "enum.DamageStateVisualLayers.Base" ]
+        state: alive
+        color: "#808080"
+        
+- type: entity
+  id: ReagentSlimeBicaridine
+  parent: ReagentSlime
+  suffix: Bicaridine
+  components:
+  - type: Bloodstream
+    bloodReagent: Bicaridine
+  - type: PointLight
+    color: "#ffaa00"
+  - type: Sprite
+    drawdepth: Mobs
+    sprite: Mobs/Aliens/elemental.rsi
+    layers:
+      - map: [ "enum.DamageStateVisualLayers.Base" ]
+        state: alive
+        color: "#ffaa00"
+
+- type: entity
+  id: ReagentSlimeToxin
+  parent: ReagentSlime
+  suffix: Toxin
+  components:
+  - type: Bloodstream
+    bloodReagent: Toxin
+  - type: PointLight
+    color: "#cf3600"
+  - type: Sprite
+    drawdepth: Mobs
+    sprite: Mobs/Aliens/elemental.rsi
+    layers:
+      - map: [ "enum.DamageStateVisualLayers.Base" ]
+        state: alive
+        color: "#cf3600"
+
+- type: entity
+  id: ReagentSlimeNapalm
+  parent: ReagentSlime
+  suffix: Napalm
+  components:
+  - type: Bloodstream
+    bloodReagent: Napalm
+  - type: PointLight
+    color: "#FA00AF"
+  - type: Sprite
+    drawdepth: Mobs
+    sprite: Mobs/Aliens/elemental.rsi
+    layers:
+      - map: [ "enum.DamageStateVisualLayers.Base" ]
+        state: alive
+        color: "#FA00AF"
+     
+- type: entity
+  id: ReagentSlimeOmnizine
+  parent: ReagentSlime
+  suffix: Omnizine
+  components:
+  - type: Bloodstream
+    bloodReagent: Omnizine
+  - type: PointLight
+    color: "#fcf7f9"
+  - type: Sprite
+    drawdepth: Mobs
+    sprite: Mobs/Aliens/elemental.rsi
+    layers:
+      - map: [ "enum.DamageStateVisualLayers.Base" ]
+        state: alive
+        color: "#fcf7f9"
\ No newline at end of file
index 16d9365b9f42fc75848f283cf8e70d14ed05abc0..d227e57ff3b1cde0f4ec95d4dd2acbcd2b945d5b 100644 (file)
     superCriticalSpawns:
     - AsteroidRock
     - SpawnMobOreCrab
+
+- type: entity
+  id: AnomalyLiquid
+  parent: BaseAnomaly
+  suffix: Liquid
+  components:
+  - type: Sprite
+    sprite: Structures/Specific/Anomalies/liquid_anom.rsi
+    layers:
+    - state: anom
+      map: ["enum.AnomalyVisualLayers.Base"]
+    - state: pulse
+      map: ["enum.AnomalyVisualLayers.Animated"]
+      visible: false
+  - type: RandomSprite
+    selected: # Initialized layer values. Edited through the ReagentProducerAnomalySystem
+      enum.AnomalyVisualLayers.Base:
+        anom: "#ffffff"
+      enum.AnomalyVisualLayers.Animated:
+        pulse: "#ffffff"
+  - type: PointLight
+    radius: 4.0
+    energy: 3.5
+    color: "#bbbbbb"
+  - type: BadFood
+  - type: Anomaly
+    anomalyContactDamage:
+      types:
+        Slash: 1
+  - type: EntitySpawnAnomaly
+    superCriticalSpawns: 
+    - ReagentSlimeSpawner
+    spawns:
+      - PuddleSparkle
+  - type: SolutionContainerManager
+    solutions:
+      anomaly:
+        maxVol: 1500
+  - type: PuddleCreateAnomaly
+    solution: anomaly
+  - type: InjectionAnomaly
+    solution: anomaly
+  - type: ReagentProducerAnomaly
+    solution: anomaly
+    needRecolor: true
+    dangerousChemicals:
+    - UnstableMutagen
+    - Mold
+    - PolytrinicAcid
+    - FerrochromicAcid
+    - FluorosulfuricAcid
+    - SulfuricAcid
+    - HeartbreakerToxin
+    - VentCrud
+    - UncookedAnimalProteins
+    - Thermite
+    - Napalm
+    - Phlogiston
+    - ChlorineTrifluoride
+    - FoamingAgent
+    - BuzzochloricBees
+    - RobustHarvest
+    usefulChemicals:
+    - Cryptobiolin
+    - Dylovene
+    - Arithrazine
+    - Bicaridine
+    - Cryoxadone
+    - Dermaline
+    - Dexalin
+    - DexalinPlus
+    - Epinephrine
+    - Leporazine
+    - Ambuzol
+    - Tricordrazine
+    - Artifexium
+    - Ethylredoxrazine
+    funChemicals:
+    - Desoxyephedrine
+    - Ephedrine
+    - THC
+    - THCOil
+    - SpaceDrugs
+    - Nocturine
+    - MuteToxin
+    - NorepinephricAcid
+    - Pax
+    - Ipecac
+    - Cognizine
+    - Beer
+    - SpaceGlue
+    - CogChamp
+    - Honk
+    - Carpetium
+  - type: Drink
+    solution: anomaly
+  - type: DrainableSolution
+    solution: anomaly
+  - type: DrawableSolution
+    solution: anomaly
+  - type: ExaminableSolution
+    solution: anomaly
+  - type: RefillableSolution
+    solution: anomaly
+  - type: InjectableSolution
+    solution: beaker
diff --git a/Resources/Textures/Mobs/Aliens/elemental.rsi/alive.png b/Resources/Textures/Mobs/Aliens/elemental.rsi/alive.png
new file mode 100644 (file)
index 0000000..c0fbc02
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/elemental.rsi/alive.png differ
diff --git a/Resources/Textures/Mobs/Aliens/elemental.rsi/dead.png b/Resources/Textures/Mobs/Aliens/elemental.rsi/dead.png
new file mode 100644 (file)
index 0000000..1363188
Binary files /dev/null and b/Resources/Textures/Mobs/Aliens/elemental.rsi/dead.png differ
diff --git a/Resources/Textures/Mobs/Aliens/elemental.rsi/meta.json b/Resources/Textures/Mobs/Aliens/elemental.rsi/meta.json
new file mode 100644 (file)
index 0000000..3d3d7f7
--- /dev/null
@@ -0,0 +1,44 @@
+{
+  "version": 1,
+  "license": "CC0-1.0",
+  "copyright": "Created by TheShuEd (github) for Space Station 14.",
+  "size": {
+    "x": 32,
+    "y": 32
+  },
+  "states": [
+    {
+      "name": "dead"
+    },
+    {
+      "name": "alive",
+      "directions": 4,
+      "delays": [
+        [
+          0.2,
+          0.2,
+          0.2,
+          0.2
+        ],
+        [
+          0.2,
+          0.2,
+          0.2,
+          0.2
+        ],
+        [
+          0.2,
+          0.2,
+          0.2,
+          0.2
+        ],
+        [
+          0.2,
+          0.2,
+          0.2,
+          0.2
+        ]
+      ]
+    }
+  ]
+}
diff --git a/Resources/Textures/Structures/Specific/Anomalies/liquid_anom.rsi/anom.png b/Resources/Textures/Structures/Specific/Anomalies/liquid_anom.rsi/anom.png
new file mode 100644 (file)
index 0000000..f421984
Binary files /dev/null and b/Resources/Textures/Structures/Specific/Anomalies/liquid_anom.rsi/anom.png differ
diff --git a/Resources/Textures/Structures/Specific/Anomalies/liquid_anom.rsi/meta.json b/Resources/Textures/Structures/Specific/Anomalies/liquid_anom.rsi/meta.json
new file mode 100644 (file)
index 0000000..320816f
--- /dev/null
@@ -0,0 +1,33 @@
+{
+  "version": 1,
+  "license": "CC0-1.0",
+  "copyright": "Created by TheShuEd (github) for ss14",
+  "size": {
+    "x": 32,
+    "y": 32
+  },
+  "states": [
+    {
+      "name": "anom",
+      "delays": [
+        [
+          0.18625,
+          0.18625,
+          0.18625,
+          0.18625
+        ]
+      ]
+    },
+       {
+      "name": "pulse",
+      "delays": [
+        [
+          0.15625,
+          0.15625,
+          0.15625,
+          0.15625
+        ]
+      ]
+    }
+  ]
+}
diff --git a/Resources/Textures/Structures/Specific/Anomalies/liquid_anom.rsi/pulse.png b/Resources/Textures/Structures/Specific/Anomalies/liquid_anom.rsi/pulse.png
new file mode 100644 (file)
index 0000000..3447184
Binary files /dev/null and b/Resources/Textures/Structures/Specific/Anomalies/liquid_anom.rsi/pulse.png differ