]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Rock and Meat anom rework (try 2) (#24449)
authorEd <96445749+TheShuEd@users.noreply.github.com>
Sat, 27 Jan 2024 02:52:07 +0000 (05:52 +0300)
committerGitHub <noreply@github.com>
Sat, 27 Jan 2024 02:52:07 +0000 (21:52 -0500)
* rework

* bruh

* all fixed

* balance

* bb

* Update TileAnomalySystem.cs

* Update EntityAnomalySystem.cs

* spawn on shutdown variant

* fix entites, fix DataRecord

* fix some review

* god forgive me

* oh fuck wrong brench

* Revert "oh fuck wrong brench"

This reverts commit c81f57f7830c8e55fd47982500c57281af40b0dc.

17 files changed:
Content.Server/Anomaly/Effects/EntityAnomalySystem.cs
Content.Server/Anomaly/Effects/TileAnomalySystem.cs
Content.Shared/Anomaly/Components/AnomalyComponent.cs
Content.Shared/Anomaly/Effects/Components/EntitySpawnAnomalyComponent.cs
Content.Shared/Anomaly/Effects/Components/TileSpawnAnomaly.cs [deleted file]
Content.Shared/Anomaly/Effects/Components/TileSpawnAnomalyComponent.cs [new file with mode: 0644]
Content.Shared/Anomaly/Effects/SharedEntityAnomalySystem.cs [new file with mode: 0644]
Content.Shared/Anomaly/Effects/SharedTileAnomalySystem.cs [new file with mode: 0644]
Content.Shared/Anomaly/SharedAnomalySystem.cs
Resources/Prototypes/Entities/Effects/wallspawn.yml
Resources/Prototypes/Entities/Markers/Spawners/Random/anomaly.yml
Resources/Prototypes/Entities/Markers/Spawners/Random/asteroidcrab.yml [deleted file]
Resources/Prototypes/Entities/Objects/Misc/ice_crust.yml
Resources/Prototypes/Entities/Structures/Specific/Anomaly/anomalies.yml
Resources/Prototypes/Entities/Structures/Walls/asteroid.yml
Resources/Textures/Structures/Specific/anomaly.rsi/anom6-pulse.png
Resources/Textures/Structures/Specific/anomaly.rsi/anom6.png

index ee4e2ac115f52a45a8a1f9131d29b999a0810663..9bfc48f4baa316bc5e2aa951316f9e81cc4e135f 100644 (file)
@@ -1,18 +1,16 @@
-using System.Linq;
-using System.Numerics;
+using Content.Shared.Anomaly;
 using Content.Shared.Anomaly.Components;
+using Content.Shared.Anomaly.Effects;
 using Content.Shared.Anomaly.Effects.Components;
-using Content.Shared.Physics;
 using Robust.Shared.Map;
-using Robust.Shared.Physics;
-using Robust.Shared.Physics.Components;
-using Robust.Shared.Prototypes;
+using Robust.Shared.Map.Components;
 using Robust.Shared.Random;
 
 namespace Content.Server.Anomaly.Effects;
 
-public sealed class EntityAnomalySystem : EntitySystem
+public sealed class EntityAnomalySystem : SharedEntityAnomalySystem
 {
+    [Dependency] private readonly SharedAnomalySystem _anomaly = default!;
     [Dependency] private readonly IMapManager _map = default!;
     [Dependency] private readonly IRobustRandom _random = default!;
 
@@ -22,84 +20,78 @@ public sealed class EntityAnomalySystem : EntitySystem
         SubscribeLocalEvent<EntitySpawnAnomalyComponent, AnomalyPulseEvent>(OnPulse);
         SubscribeLocalEvent<EntitySpawnAnomalyComponent, AnomalySupercriticalEvent>(OnSupercritical);
         SubscribeLocalEvent<EntitySpawnAnomalyComponent, AnomalyStabilityChangedEvent>(OnStabilityChanged);
+        SubscribeLocalEvent<EntitySpawnAnomalyComponent, AnomalySeverityChangedEvent>(OnSeverityChanged);
+        SubscribeLocalEvent<EntitySpawnAnomalyComponent, AnomalyShutdownEvent>(OnShutdown);
     }
 
-    private void OnPulse(EntityUid uid, EntitySpawnAnomalyComponent component, ref AnomalyPulseEvent args)
+    private void OnPulse(Entity<EntitySpawnAnomalyComponent> component, ref AnomalyPulseEvent args)
     {
-        if (!component.SpawnOnPulse)
-            return;
-
-        var range = component.SpawnRange * args.Stability;
-        var amount = (int) (component.MaxSpawnAmount * args.Severity + 0.5f);
+        foreach (var entry in component.Comp.Entries)
+        {
+            if (!entry.Settings.SpawnOnPulse)
+                continue;
 
-        var xform = Transform(uid);
-        SpawnEntitesOnOpenTiles(component, xform, amount, range, component.Spawns);
+            SpawnEntities(component, entry, args.Stability, args.Severity);
+        }
     }
 
-    private void OnSupercritical(EntityUid uid, EntitySpawnAnomalyComponent component, ref AnomalySupercriticalEvent args)
+    private void OnSupercritical(Entity<EntitySpawnAnomalyComponent> component, ref AnomalySupercriticalEvent args)
     {
-        if (!component.SpawnOnSuperCritical)
-            return;
+        foreach (var entry in component.Comp.Entries)
+        {
+            if (!entry.Settings.SpawnOnSuperCritical)
+                continue;
 
-        var xform = Transform(uid);
-        // A cluster of entities
-        SpawnEntitesOnOpenTiles(component, xform, component.MaxSpawnAmount, component.SpawnRange, component.Spawns);
-        // And so much meat (for the meat anomaly at least)
-        SpawnEntitesOnOpenTiles(component, xform, component.MaxSpawnAmount, component.SpawnRange, component.SuperCriticalSpawns);
+            SpawnEntities(component, entry, 1, 1);
+        }
     }
 
-    private void OnStabilityChanged(EntityUid uid, EntitySpawnAnomalyComponent component, ref AnomalyStabilityChangedEvent args)
+    private void OnShutdown(Entity<EntitySpawnAnomalyComponent> component, ref AnomalyShutdownEvent args)
     {
-        if (!component.SpawnOnStabilityChanged)
-            return;
+        foreach (var entry in component.Comp.Entries)
+        {
+            if (!entry.Settings.SpawnOnShutdown || args.Supercritical)
+                continue;
+
+            SpawnEntities(component, entry, 1, 1);
+        }
+    }
 
-        var range = component.SpawnRange * args.Stability;
-        var amount = (int) (component.MaxSpawnAmount * args.Stability + 0.5f);
+    private void OnStabilityChanged(Entity<EntitySpawnAnomalyComponent> component, ref AnomalyStabilityChangedEvent args)
+    {
+        foreach (var entry in component.Comp.Entries)
+        {
+            if (!entry.Settings.SpawnOnStabilityChanged)
+                continue;
 
-        var xform = Transform(uid);
-        SpawnEntitesOnOpenTiles(component, xform, amount, range, component.Spawns);
+            SpawnEntities(component, entry, args.Stability, args.Severity);
+        }
     }
 
-    private void SpawnEntitesOnOpenTiles(EntitySpawnAnomalyComponent component, TransformComponent xform, int amount, float radius, List<EntProtoId> spawns)
+    private void OnSeverityChanged(Entity<EntitySpawnAnomalyComponent> component, ref AnomalySeverityChangedEvent args)
     {
-        if (!component.Spawns.Any())
-            return;
+        foreach (var entry in component.Comp.Entries)
+        {
+            if (!entry.Settings.SpawnOnSeverityChanged)
+                continue;
 
-        if (!_map.TryGetGrid(xform.GridUid, out var grid))
-            return;
+            SpawnEntities(component, entry, args.Stability, args.Severity);
+        }
+    }
 
-        var localpos = xform.Coordinates.Position;
-        var tilerefs = grid.GetLocalTilesIntersecting(
-            new Box2(localpos + new Vector2(-radius, -radius), localpos + new Vector2(radius, radius))).ToArray();
+    private void SpawnEntities(Entity<EntitySpawnAnomalyComponent> anomaly, EntitySpawnSettingsEntry entry, float stability, float severity)
+    {
+        var xform = Transform(anomaly);
+        if (!TryComp<MapGridComponent>(xform.GridUid, out var grid))
+            return;
 
-        if (tilerefs.Length == 0)
+        var tiles = _anomaly.GetSpawningPoints(anomaly, stability, severity, entry.Settings);
+        if (tiles == null)
             return;
 
-        _random.Shuffle(tilerefs);
-        var physQuery = GetEntityQuery<PhysicsComponent>();
-        var amountCounter = 0;
-        foreach (var tileref in tilerefs)
+        foreach (var tileref in tiles)
         {
-            var valid = true;
-            foreach (var ent in grid.GetAnchoredEntities(tileref.GridIndices))
-            {
-                if (!physQuery.TryGetComponent(ent, out var body))
-                    continue;
-
-                if (body.BodyType != BodyType.Static ||
-                    !body.Hard ||
-                    (body.CollisionLayer & (int) CollisionGroup.Impassable) == 0)
-                    continue;
-
-                valid = false;
-                break;
-            }
-            if (!valid)
-                continue;
-            amountCounter++;
-            Spawn(_random.Pick(spawns), tileref.GridIndices.ToEntityCoordinates(xform.GridUid.Value, _map));
-            if (amountCounter >= amount)
-                return;
+            Spawn(_random.Pick(entry.Spawns), tileref.GridIndices.ToEntityCoordinates(xform.GridUid.Value, _map));
         }
     }
 }
index 08ec3a1c93801583949e656db800ad7b0a51fc86..c1487cfc8c64a46d6b4d6677dab27a10135ad154 100644 (file)
+using System.Linq;
 using System.Numerics;
+using Content.Shared.Anomaly;
 using Content.Shared.Anomaly.Components;
+using Content.Shared.Anomaly.Effects;
 using Content.Shared.Anomaly.Effects.Components;
 using Content.Shared.Maps;
 using Robust.Shared.Map;
+using Robust.Shared.Map.Components;
 using Robust.Shared.Random;
 
 namespace Content.Server.Anomaly.Effects;
 
-public sealed class TileAnomalySystem : EntitySystem
+public sealed class TileAnomalySystem : SharedTileAnomalySystem
 {
-    [Dependency] private readonly IMapManager _map = default!;
-    [Dependency] private readonly IRobustRandom _random = default!;
+    [Dependency] private readonly SharedAnomalySystem _anomaly = default!;
     [Dependency] private readonly ITileDefinitionManager _tiledef = default!;
     [Dependency] private readonly TileSystem _tile = default!;
 
     /// <inheritdoc/>
     public override void Initialize()
     {
-        SubscribeLocalEvent<TileSpawnAnomalyComponent, AnomalyStabilityChangedEvent>(OnSeverityChanged);
+        SubscribeLocalEvent<TileSpawnAnomalyComponent, AnomalyPulseEvent>(OnPulse);
+        SubscribeLocalEvent<TileSpawnAnomalyComponent, AnomalySupercriticalEvent>(OnSupercritical);
+        SubscribeLocalEvent<TileSpawnAnomalyComponent, AnomalyStabilityChangedEvent>(OnStabilityChanged);
+        SubscribeLocalEvent<TileSpawnAnomalyComponent, AnomalySeverityChangedEvent>(OnSeverityChanged);
+        SubscribeLocalEvent<TileSpawnAnomalyComponent, AnomalyShutdownEvent>(OnShutdown);
     }
 
-    private void OnSeverityChanged(EntityUid uid, TileSpawnAnomalyComponent component, ref AnomalyStabilityChangedEvent args)
+    private void OnPulse(Entity<TileSpawnAnomalyComponent> component, ref AnomalyPulseEvent args)
     {
-        var xform = Transform(uid);
-        if (!_map.TryGetGrid(xform.GridUid, out var grid))
-            return;
+        foreach (var entry in component.Comp.Entries)
+        {
+            if (!entry.Settings.SpawnOnPulse)
+                continue;
+
+            SpawnTiles(component, entry, args.Stability, args.Severity);
+        }
+    }
+
+    private void OnSupercritical(Entity<TileSpawnAnomalyComponent> component, ref AnomalySupercriticalEvent args)
+    {
+        foreach (var entry in component.Comp.Entries)
+        {
+            if (!entry.Settings.SpawnOnSuperCritical)
+                continue;
+
+            SpawnTiles(component, entry, 1, 1);
+        }
+    }
+
+    private void OnShutdown(Entity<TileSpawnAnomalyComponent> component, ref AnomalyShutdownEvent args)
+    {
+        foreach (var entry in component.Comp.Entries)
+        {
+            if (!entry.Settings.SpawnOnShutdown || args.Supercritical)
+                continue;
+
+            SpawnTiles(component, entry, 1, 1);
+        }
+    }
+
+    private void OnStabilityChanged(Entity<TileSpawnAnomalyComponent> component, ref AnomalyStabilityChangedEvent args)
+    {
+        foreach (var entry in component.Comp.Entries)
+        {
+            if (!entry.Settings.SpawnOnStabilityChanged)
+                continue;
 
-        var radius = component.SpawnRange * args.Stability;
-        var fleshTile = (ContentTileDefinition) _tiledef[component.FloorTileId];
-        var localpos = xform.Coordinates.Position;
-        var tilerefs = grid.GetLocalTilesIntersecting(
-            new Box2(localpos + new Vector2(-radius, -radius), localpos + new Vector2(radius, radius)));
-        foreach (var tileref in tilerefs)
+            SpawnTiles(component, entry, args.Stability, args.Severity);
+        }
+    }
+
+    private void OnSeverityChanged(Entity<TileSpawnAnomalyComponent> component, ref AnomalySeverityChangedEvent args)
+    {
+        foreach (var entry in component.Comp.Entries)
         {
-            if (!_random.Prob(component.SpawnChance))
+            if (!entry.Settings.SpawnOnSeverityChanged)
                 continue;
-            _tile.ReplaceTile(tileref, fleshTile);
+
+            SpawnTiles(component, entry, args.Stability, args.Severity);
+        }
+    }
+
+    private void SpawnTiles(Entity<TileSpawnAnomalyComponent> anomaly, TileSpawnSettingsEntry entry, float stability, float severity)
+    {
+        var xform = Transform(anomaly);
+        if (!TryComp<MapGridComponent>(xform.GridUid, out var grid))
+            return;
+
+        var tiles = _anomaly.GetSpawningPoints(anomaly, stability, severity, entry.Settings);
+        if (tiles == null)
+            return;
+
+        foreach (var tileref in tiles)
+        {
+            var tile = (ContentTileDefinition) _tiledef[entry.Floor];
+            _tile.ReplaceTile(tileref, tile);
         }
     }
 }
index 0e83861863310ead16c9b0c5216ecb97018feef0..89afbb0122eb92107c848b87193dd905d9068a8a 100644 (file)
@@ -268,13 +268,13 @@ public readonly record struct AnomalyShutdownEvent(EntityUid Anomaly, bool Super
 /// </summary>
 /// <param name="Anomaly">The anomaly being changed</param>
 [ByRefEvent]
-public readonly record struct AnomalySeverityChangedEvent(EntityUid Anomaly, float Severity);
+public readonly record struct AnomalySeverityChangedEvent(EntityUid Anomaly, float Stability, float Severity);
 
 /// <summary>
 /// Event broadcast when an anomaly's stability is changed.
 /// </summary>
 [ByRefEvent]
-public readonly record struct AnomalyStabilityChangedEvent(EntityUid Anomaly, float Stability);
+public readonly record struct AnomalyStabilityChangedEvent(EntityUid Anomaly, float Stability, float Severity);
 
 /// <summary>
 /// Event broadcast when an anomaly's health is changed.
index 7a816e43123f7341bc9fa1636a7c75876f33283e..07cd5c6825474462e7531689076f44ecb01408fe 100644 (file)
@@ -1,53 +1,25 @@
+using Robust.Shared.GameStates;
 using Robust.Shared.Prototypes;
 
 namespace Content.Shared.Anomaly.Effects.Components;
 
-[RegisterComponent]
+[RegisterComponent, NetworkedComponent, Access(typeof(SharedEntityAnomalySystem))]
 public sealed partial class EntitySpawnAnomalyComponent : Component
 {
     /// <summary>
-    /// A list of entities that are random picked to be spawned on each pulse
-    /// </summary>
-    [DataField]
-    public List<EntProtoId> Spawns = new();
-
-    /// <summary>
-    /// A list of entities that are random picked to be spawned when supercritical;
+    /// All types of entity spawns with their settings
     /// </summary>
     [DataField]
-    public List<EntProtoId> SuperCriticalSpawns = new();
-
-    /// <summary>
-    /// The maximum number of entities that spawn per pulse
-    /// scales with severity.
-    /// </summary>
-    [DataField("maxSpawnAmount"), ViewVariables(VVAccess.ReadWrite)]
-    public int MaxSpawnAmount = 7;
-
-    /// <summary>
-    /// The maximum radius the entities will spawn in.
-    /// Also governs the maximum reach of flesh tiles
-    /// scales with stability
-    /// </summary>
-    [DataField("spawnRange"), ViewVariables(VVAccess.ReadWrite)]
-    public float SpawnRange = 5f;
-
-    /// <summary>
-    /// Whether or not anomaly spawns entities on Pulse
-    /// </summary>
-    [DataField, ViewVariables(VVAccess.ReadWrite)]
-    public bool SpawnOnPulse = true;
+    public List<EntitySpawnSettingsEntry> Entries = new();
+}
 
+[DataRecord]
+public partial record struct EntitySpawnSettingsEntry()
+{
     /// <summary>
-    /// Whether or not anomaly spawns entities on SuperCritical
+    /// A list of entities that are random picked to be spawned on each pulse
     /// </summary>
-    [DataField, ViewVariables(VVAccess.ReadWrite)]
-    public bool SpawnOnSuperCritical = true;
+    public List<EntProtoId> Spawns { get; set; } = new();
 
-    /// <summary>
-    /// Whether or not anomaly spawns entities on StabilityChanged
-    /// The idea was to spawn entities either on Pulse/Supercritical OR StabilityChanged
-    /// </summary>
-    [DataField, ViewVariables(VVAccess.ReadWrite)]
-    public bool SpawnOnStabilityChanged = false;
+    public AnomalySpawnSettings Settings { get; set; } = new();
 }
diff --git a/Content.Shared/Anomaly/Effects/Components/TileSpawnAnomaly.cs b/Content.Shared/Anomaly/Effects/Components/TileSpawnAnomaly.cs
deleted file mode 100644 (file)
index 7e3125b..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-using Content.Shared.Maps;
-using Robust.Shared.Prototypes;
-
-namespace Content.Shared.Anomaly.Effects.Components;
-
-[RegisterComponent]
-public sealed partial class TileSpawnAnomalyComponent : Component
-{
-    /// <summary>
-    /// The maximum radius of tiles scales with stability
-    /// </summary>
-    [DataField, ViewVariables(VVAccess.ReadWrite)]
-    public float SpawnRange = 5f;
-
-    /// <summary>
-    /// The probability a tile will spawn.
-    /// </summary>
-    [DataField, ViewVariables(VVAccess.ReadWrite)]
-    public float SpawnChance = 0.33f;
-
-    /// <summary>
-    /// The tile that is spawned by the anomaly's effect
-    /// </summary>
-    [DataField, ViewVariables(VVAccess.ReadWrite)]
-    public ProtoId<ContentTileDefinition> FloorTileId = "FloorFlesh";
-}
diff --git a/Content.Shared/Anomaly/Effects/Components/TileSpawnAnomalyComponent.cs b/Content.Shared/Anomaly/Effects/Components/TileSpawnAnomalyComponent.cs
new file mode 100644 (file)
index 0000000..1105589
--- /dev/null
@@ -0,0 +1,26 @@
+using Content.Shared.Maps;
+using Robust.Shared.GameStates;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.Anomaly.Effects.Components;
+
+[RegisterComponent, NetworkedComponent, Access(typeof(SharedTileAnomalySystem))]
+public sealed partial class TileSpawnAnomalyComponent : Component
+{
+    /// <summary>
+    /// All types of floors spawns with their settings
+    /// </summary>
+    [DataField]
+    public List<TileSpawnSettingsEntry> Entries = new();
+}
+
+[DataRecord]
+public partial record struct TileSpawnSettingsEntry()
+{
+    /// <summary>
+    /// The tile that is spawned by the anomaly's effect
+    /// </summary>
+    public ProtoId<ContentTileDefinition> Floor { get; set; } = default!;
+
+    public AnomalySpawnSettings Settings { get; set; } = new();
+}
diff --git a/Content.Shared/Anomaly/Effects/SharedEntityAnomalySystem.cs b/Content.Shared/Anomaly/Effects/SharedEntityAnomalySystem.cs
new file mode 100644 (file)
index 0000000..28732f4
--- /dev/null
@@ -0,0 +1,6 @@
+
+namespace Content.Shared.Anomaly.Effects;
+
+public abstract class SharedEntityAnomalySystem : EntitySystem
+{
+}
diff --git a/Content.Shared/Anomaly/Effects/SharedTileAnomalySystem.cs b/Content.Shared/Anomaly/Effects/SharedTileAnomalySystem.cs
new file mode 100644 (file)
index 0000000..199c6b6
--- /dev/null
@@ -0,0 +1,6 @@
+
+namespace Content.Shared.Anomaly.Effects;
+
+public abstract class SharedTileAnomalySystem : EntitySystem
+{
+}
index c014ff90e1159662b063056ea232b50f6b82570d..dcf7cae2159bc5ea82bb5ca377c0aa0aa116bde5 100644 (file)
@@ -3,10 +3,13 @@ using Content.Shared.Anomaly.Components;
 using Content.Shared.Damage;
 using Content.Shared.Database;
 using Content.Shared.Interaction;
+using Content.Shared.Physics;
 using Content.Shared.Popups;
 using Content.Shared.Weapons.Melee.Components;
 using Content.Shared.Weapons.Melee.Events;
 using Robust.Shared.Audio.Systems;
+using Robust.Shared.Map;
+using Robust.Shared.Map.Components;
 using Robust.Shared.Network;
 using Robust.Shared.Physics;
 using Robust.Shared.Physics.Components;
@@ -14,6 +17,8 @@ using Robust.Shared.Physics.Systems;
 using Robust.Shared.Random;
 using Robust.Shared.Timing;
 using Robust.Shared.Utility;
+using System.Linq;
+using System.Numerics;
 
 namespace Content.Shared.Anomaly;
 
@@ -28,6 +33,7 @@ public abstract class SharedAnomalySystem : EntitySystem
     [Dependency] protected readonly SharedAppearanceSystem Appearance = default!;
     [Dependency] private readonly SharedPhysicsSystem _physics = default!;
     [Dependency] protected readonly SharedPopupSystem Popup = default!;
+    [Dependency] private readonly IRobustRandom _random = default!;
 
     private ISawmill _sawmill = default!;
 
@@ -227,7 +233,7 @@ public abstract class SharedAnomalySystem : EntitySystem
         component.Stability = Math.Clamp(newVal, 0, 1);
         Dirty(component);
 
-        var ev = new AnomalyStabilityChangedEvent(uid, component.Stability);
+        var ev = new AnomalyStabilityChangedEvent(uid, component.Stability, component.Severity);
         RaiseLocalEvent(uid, ref ev, true);
     }
 
@@ -250,7 +256,7 @@ public abstract class SharedAnomalySystem : EntitySystem
         component.Severity = Math.Clamp(newVal, 0, 1);
         Dirty(component);
 
-        var ev = new AnomalySeverityChangedEvent(uid, component.Severity);
+        var ev = new AnomalySeverityChangedEvent(uid, component.Stability, component.Severity);
         RaiseLocalEvent(uid, ref ev, true);
     }
 
@@ -349,4 +355,122 @@ public abstract class SharedAnomalySystem : EntitySystem
             RemComp(ent, super);
         }
     }
+
+    /// <summary>
+    /// Gets random points around the anomaly based on the given parameters.
+    /// </summary>
+    public List<TileRef>? GetSpawningPoints(EntityUid uid, float stability, float severity, AnomalySpawnSettings settings)
+    {
+        var xform = Transform(uid);
+
+        if (!TryComp<MapGridComponent>(xform.GridUid, out var grid))
+            return null;
+
+        var amount = (int) (MathHelper.Lerp(settings.MinAmount, settings.MaxAmount, severity * stability) + 0.5f);
+
+        var localpos = xform.Coordinates.Position;
+        var tilerefs = grid.GetLocalTilesIntersecting(
+            new Box2(localpos + new Vector2(-settings.MaxRange, -settings.MaxRange), localpos + new Vector2(settings.MaxRange, settings.MaxRange))).ToList();
+
+        if (tilerefs.Count == 0)
+            return null;
+
+        var physQuery = GetEntityQuery<PhysicsComponent>();
+        var resultList = new List<TileRef>();
+        while (resultList.Count() < amount)
+        {
+            if (tilerefs.Count() == 0)
+                break;
+
+            var tileref = _random.Pick(tilerefs);
+            var distance = MathF.Sqrt(MathF.Pow(tileref.X - xform.LocalPosition.X, 2) + MathF.Pow(tileref.Y - xform.LocalPosition.Y, 2));
+
+            //cut outer & inner circle
+            if (distance > settings.MaxRange || distance < settings.MinRange)
+            {
+                tilerefs.Remove(tileref);
+                continue;
+            }
+
+            if (!settings.CanSpawnOnEntities)
+            {
+                var valid = true;
+                foreach (var ent in grid.GetAnchoredEntities(tileref.GridIndices))
+                {
+                    if (!physQuery.TryGetComponent(ent, out var body))
+                        continue;
+
+                    if (body.BodyType != BodyType.Static ||
+                        !body.Hard ||
+                        (body.CollisionLayer & (int) CollisionGroup.Impassable) == 0)
+                        continue;
+
+                    valid = false;
+                    break;
+                }
+                if (!valid)
+                {
+                    tilerefs.Remove(tileref);
+                    continue;
+                }
+            }
+            resultList.Add(tileref);
+        }
+        return resultList;
+    }
+}
+
+[DataRecord]
+public partial record struct AnomalySpawnSettings()
+{
+    /// <summary>
+    /// should entities block spawning?
+    /// </summary>
+    public bool CanSpawnOnEntities { get; set; } = true;
+
+    /// <summary>
+    /// The minimum number of entities that spawn per pulse
+    /// </summary>
+    public int MinAmount { get; set; } = 0;
+
+    /// <summary>
+    /// The maximum number of entities that spawn per pulse
+    /// scales with severity.
+    /// </summary>
+    public int MaxAmount { get; set; } = 1;
+
+    /// <summary>
+    /// The distance from the anomaly in which the entities will not appear
+    /// </summary>
+    public float MinRange { get; set; } = 0f;
+
+    /// <summary>
+    /// The maximum radius the entities will spawn in.
+    /// </summary>
+    public float MaxRange { get; set; } = 1f;
+
+    /// <summary>
+    /// Whether or not anomaly spawns entities on Pulse
+    /// </summary>
+    public bool SpawnOnPulse { get; set; } = false;
+
+    /// <summary>
+    /// Whether or not anomaly spawns entities on SuperCritical
+    /// </summary>
+    public bool SpawnOnSuperCritical { get; set; } = false;
+
+    /// <summary>
+    /// Whether or not anomaly spawns entities when destroyed
+    /// </summary>
+    public bool SpawnOnShutdown { get; set; } = false;
+
+    /// <summary>
+    /// Whether or not anomaly spawns entities on StabilityChanged
+    /// </summary>
+    public bool SpawnOnStabilityChanged { get; set; } = false;
+
+    /// <summary>
+    /// Whether or not anomaly spawns entities on SeverityChanged
+    /// </summary>
+    public bool SpawnOnSeverityChanged { get; set; } = false;
 }
index 2010b8e73ef328699877600196817d5c16f2517a..f1bd236a8abc7191fc82f9922ed89e8ce55d3b98 100644 (file)
     prototype: AsteroidRock
 
 - type: entity
-  id: WallSpawnAsteroidCrab
+  id: WallSpawnAsteroidUraniumCrab
   parent: WallSpawnAsteroid
   components:
   - type: SpawnOnDespawn
-    prototype: AsteroidRockCrab
+    prototype: AsteroidRockUraniumCrab
 
 - type: entity
-  id: WallSpawnAsteroidCrab1
+  id: WallSpawnAsteroidUranium
   parent: WallSpawnAsteroid
   components:
   - type: SpawnOnDespawn
-    prototype: AsteroidRockCrab1
+    prototype: AsteroidRockUranium
+
+- type: entity
+  id: WallSpawnAsteroidQuartzCrab
+  parent: WallSpawnAsteroid
+  components:
+  - type: SpawnOnDespawn
+    prototype: AsteroidRockQuartzCrab
+
+- type: entity
+  id: WallSpawnAsteroidQuartz
+  parent: WallSpawnAsteroid
+  components:
+  - type: SpawnOnDespawn
+    prototype: AsteroidRockQuartz
+
+- type: entity
+  id: WallSpawnAsteroidSilverCrab
+  parent: WallSpawnAsteroid
+  components:
+  - type: SpawnOnDespawn
+    prototype: AsteroidRockSilverCrab
+
+- type: entity
+  id: WallSpawnAsteroidSilver
+  parent: WallSpawnAsteroid
+  components:
+  - type: SpawnOnDespawn
+    prototype: AsteroidRockSilver
+
+- type: entity
+  id: WallSpawnAsteroidIronCrab
+  parent: WallSpawnAsteroid
+  components:
+  - type: SpawnOnDespawn
+    prototype: AsteroidRockTinCrab
+
+- type: entity
+  id: WallSpawnAsteroidIron
+  parent: WallSpawnAsteroid
+  components:
+  - type: SpawnOnDespawn
+    prototype: AsteroidRockTin
\ No newline at end of file
index 6d2149965f7598a8bb7e69284da0d2592630d9dd..c81c840fb003338ba45d3df71f9c3f2d0fac88c1 100644 (file)
     - AnomalyFlesh
     - AnomalyBluespace
     - AnomalyIce
-    - AnomalyRock
+    - RandomRockAnomalySpawner
     - AnomalyLiquid
     - AnomalyFlora
     chance: 1
     offset: 0.15 # not to put it higher. The anomaly sychnronizer looks for anomalies within this radius, and if the radius is higher, the anomaly can be attracted from a neighboring tile.
+
+- type: entity
+  id: RandomRockAnomalySpawner
+  parent: MarkerBase
+  components:
+  - type: Sprite
+    layers:
+    - state: red
+    - sprite: Structures/Specific/anomaly.rsi
+      state: anom6
+  - type: RandomSpawner
+    prototypes:
+    - AnomalyRockIron
+    - AnomalyRockSilver
+    - AnomalyRockQuartz
+    - AnomalyRockUranium
+    chance: 1
+    offset: 0.15
\ No newline at end of file
diff --git a/Resources/Prototypes/Entities/Markers/Spawners/Random/asteroidcrab.yml b/Resources/Prototypes/Entities/Markers/Spawners/Random/asteroidcrab.yml
deleted file mode 100644 (file)
index 4c4b969..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-- type: entity
-  name: Asteroid Crab Spawner
-  id: AsteroidCrabSpawner
-  parent: MarkerBase
-  components:
-    - type: Sprite
-      layers:
-        - state: red
-        - sprite: Structures/Walls/rock.rsi
-          state: rock_asteroid_ore
-    - type: RandomSpawner
-      prototypes:
-        - AsteroidRockCrab
-        - AsteroidRockCrab1
-      chance: 1
-
-- type: entity
-  name: Rock Anom Crab Spawner
-  id: RockAnomCrabSpawner
-  parent: MarkerBase
-  components:
-    - type: Sprite
-      layers:
-        - state: red
-        - sprite: Structures/Walls/rock.rsi
-          state: rock_asteroid_ore
-    - type: RandomSpawner
-      prototypes:
-        - WallSpawnAsteroidCrab
-        - WallSpawnAsteroidCrab1
-      chance: 1
\ No newline at end of file
index ad1f8766751c1aea3eb8984bc30094815ccef8f3..bc3488aaf432345d616136060578e29357e8b8b7 100644 (file)
@@ -10,8 +10,7 @@
     - type: MeleeSound
       soundGroups:
         Brute:
-          path:
-            "/Audio/Weapons/slash.ogg"
+          collection: GlassBreak
     - type: Sprite
       sprite: Objects/Misc/ice_crust.rsi
       layers:
index aecef8c637b28072fe70a77496753e330b9e3cc6..56c970929cbff7e36bb97d9f8e73b5a4ff6608f8 100644 (file)
     color: "#cb5b7e"
     castShadows: false
   - type: TileSpawnAnomaly
-    floorTileId: FloorFlesh
+    entries:
+    - settings:
+        spawnOnPulse: true
+        spawnOnStabilityChanged: true
+        minAmount: 3
+        maxAmount: 7
+        maxRange: 4
+      floor: FloorFlesh
+    - settings:
+        spawnOnSuperCritical: true
+        minAmount: 10
+        maxAmount: 30
+        maxRange: 10
+      floor: FloorFlesh
   - type: EntitySpawnAnomaly
-    superCriticalSpawns:
-    - FleshKudzu
-    spawns:
-    - MobFleshJared
-    - MobFleshGolem
-    - MobFleshClamp
-    - MobFleshLover
-    - FleshBlocker
+    entries:
+    - settings:
+        spawnOnPulse: true
+        minAmount: 1
+        maxAmount: 4
+        minRange: 1.5
+        maxRange: 2.5
+      spawns:
+      - FleshBlocker
+    - settings:
+        spawnOnPulse: true
+        maxAmount: 3
+        minRange: 3
+        maxRange: 4.5
+      spawns:
+      - MobFleshJared
+      - MobFleshGolem
+      - MobFleshClamp
+      - MobFleshLover
+    - settings:
+        spawnOnSuperCritical: true
+        minAmount: 10
+        maxAmount: 15
+        minRange: 5
+        maxRange: 15
+      spawns:
+      - FleshBlocker
+    - settings:
+        spawnOnSuperCritical: true
+        minAmount: 5
+        maxAmount: 10
+        maxRange: 8
+      spawns:
+      - MobFleshJared
+      - MobFleshGolem
+      - MobFleshClamp
+      - MobFleshLover
+    - settings:
+        spawnOnSuperCritical: true
+        minAmount: 5
+        maxAmount: 8
+        maxRange: 10
+      spawns:
+      - FleshKudzu
+    - settings:
+        spawnOnShutdown: true
+        maxAmount: 2
+        maxRange: 1
+      spawns:
+      - MobFleshJared
+      - MobFleshGolem
+      - MobFleshClamp
+      - MobFleshLover
+      - FleshKudzu
 
 - type: entity
   id: AnomalyBluespace
     projectilePrototype: ProjectileIcicle
     targetNonSentientChance: 0.1
   - type: EntitySpawnAnomaly
-    spawns:
-    - IceCrust
-    maxSpawnAmount: 17
-    spawnOnPulse: false
-    spawnOnSuperCritical: false
-    spawnOnStabilityChanged: true
+    entries:
+    - settings:
+        spawnOnStabilityChanged: true
+        minAmount: 5
+        maxAmount: 15
+        maxRange: 4
+      spawns:
+      - IceCrust
   - type: TempAffectingAnomaly
     tempChangePerSecond: -25
     hotspotExposeTemperature: -1000
     spawnRadius: 0
 
 - type: entity
-  id: AnomalyRock
+  id: AnomalyRockBase
   parent: BaseAnomaly
+  abstract: true
   suffix: Rock
   components:
   - type: Anomaly
     color: "#5ca8cb"
     castShadows: false
   - type: TileSpawnAnomaly
-    floorTileId: FloorAsteroidTile
-    spawnChance: 0.8
+    entries:
+    - settings:
+        spawnOnPulse: true
+        minAmount: 15
+        maxAmount: 20
+        maxRange: 7.5
+      floor: FloorAsteroidTile
+    - settings:
+        spawnOnSuperCritical: true
+        minAmount: 30
+        maxAmount: 50
+        maxRange: 12
+      floor: FloorAsteroidTile
+
+- type: entity
+  id: AnomalyRockUranium
+  parent: AnomalyRockBase
+  suffix: Rock, Uranium
+  components:
+  - type: Sprite
+    color: "#52ff39"
+  - type: PointLight
+    radius: 2.0
+    energy: 7.5
+    color: "#52ff39"
+  - type: EntitySpawnAnomaly
+    entries:
+    - settings:
+        spawnOnPulse: true
+        minAmount: 8
+        maxAmount: 15
+        minRange: 4.5
+        maxRange: 7.5
+      spawns:
+      - WallSpawnAsteroid
+      - WallSpawnAsteroid
+      - WallSpawnAsteroidUranium
+      - WallSpawnAsteroidUraniumCrab
+    - settings:
+        spawnOnPulse: true
+        maxAmount: 3
+        minRange: 2.5
+        maxRange: 4.5
+      spawns:
+      - CrystalGreen
+    - settings:
+        spawnOnSuperCritical: true
+        minAmount: 30
+        maxAmount: 40
+        minRange: 5
+        maxRange: 15
+      spawns:
+      - CrystalGreen
+      - WallSpawnAsteroid
+      - WallSpawnAsteroid
+      - WallSpawnAsteroidUraniumCrab
+    - settings:
+        spawnOnSuperCritical: true
+        minAmount: 6
+        maxAmount: 10
+        maxRange: 5
+      spawns:
+      - MobSpawnCrabUranium
+
+- type: entity
+  id: AnomalyRockQuartz
+  parent: AnomalyRockBase
+  suffix: Rock, Quartz
+  components:
+  - type: Sprite
+    color: "#fb4747"
+  - type: PointLight
+    radius: 2.0
+    energy: 7.5
+    color: "#fb4747"
+  - type: EntitySpawnAnomaly
+    entries:
+    - settings:  
+        spawnOnPulse: true
+        minAmount: 8
+        maxAmount: 15
+        minRange: 4.5
+        maxRange: 7.5
+      spawns:
+      - WallSpawnAsteroid
+      - WallSpawnAsteroid
+      - WallSpawnAsteroidQuartz
+      - WallSpawnAsteroidQuartzCrab
+    - settings:
+        spawnOnPulse: true
+        maxAmount: 3
+        minRange: 2.5
+        maxRange: 4.5
+      spawns:
+      - CrystalGrey
+    - settings:
+        spawnOnSuperCritical: true
+        minAmount: 30
+        maxAmount: 40
+        minRange: 5
+        maxRange: 15
+      spawns:
+      - CrystalGrey
+      - WallSpawnAsteroid
+      - WallSpawnAsteroid
+      - WallSpawnAsteroidQuartzCrab
+    - settings:
+        spawnOnSuperCritical: true
+        minAmount: 6
+        maxAmount: 10
+        maxRange: 5
+      spawns:
+      - MobSpawnCrabQuartz
+
+- type: entity
+  id: AnomalyRockSilver
+  parent: AnomalyRockBase
+  suffix: Rock, Silver
+  components:
+  - type: Sprite
+    color: "#47f8ff"
+  - type: PointLight
+    radius: 2.0
+    energy: 7.5
+    color: "#47f8ff"
+  - type: EntitySpawnAnomaly
+    entries:
+    - settings:
+        spawnOnPulse: true
+        minAmount: 8
+        maxAmount: 15
+        minRange: 4.5
+        maxRange: 7.5
+      spawns:
+      - WallSpawnAsteroid
+      - WallSpawnAsteroid
+      - WallSpawnAsteroidSilver
+      - WallSpawnAsteroidSilverCrab
+    - settings:
+        spawnOnPulse: true
+        maxAmount: 3
+        minRange: 2.5
+        maxRange: 4.5
+      spawns:
+      - CrystalCyan
+    - settings:
+        spawnOnSuperCritical: true
+        minAmount: 30
+        maxAmount: 40
+        minRange: 5
+        maxRange: 15
+      spawns:
+      - CrystalCyan
+      - WallSpawnAsteroid
+      - WallSpawnAsteroid
+      - WallSpawnAsteroidSilverCrab
+    - settings:
+        spawnOnSuperCritical: true
+        minAmount: 6
+        maxAmount: 10
+        maxRange: 5
+      spawns:
+      - MobSpawnCrabSilver
+
+- type: entity
+  id: AnomalyRockIron
+  parent: AnomalyRockBase
+  suffix: Rock, Iron
+  components:
+  - type: Sprite
+    color: "#ff8227"
+  - type: PointLight
+    radius: 2.0
+    energy: 7.5
+    color: "#ff8227"
   - type: EntitySpawnAnomaly
-    maxSpawnAmount: 50
-    spawnRange: 10
-    spawns:
-    - WallSpawnAsteroid
-    - RockAnomCrabSpawner
-    - CrystalSpawner
-    superCriticalSpawns:
-    - WallSpawnAsteroid
-    - SpawnMobOreCrab
+    entries:
+    - settings:
+        spawnOnPulse: true
+        minAmount: 8
+        maxAmount: 15
+        minRange: 4.5
+        maxRange: 7.5
+      spawns:
+      - WallSpawnAsteroid
+      - WallSpawnAsteroid
+      - WallSpawnAsteroidIron
+      - WallSpawnAsteroidIronCrab
+    - settings:
+        spawnOnPulse: true
+        maxAmount: 3
+        minRange: 2.5
+        maxRange: 4.5
+      spawns:
+      - CrystalOrange
+    - settings: 
+        spawnOnSuperCritical: true
+        minAmount: 30
+        maxAmount: 40
+        minRange: 5
+        maxRange: 15
+      spawns:
+      - CrystalOrange
+      - WallSpawnAsteroid
+      - WallSpawnAsteroid
+      - WallSpawnAsteroidIronCrab
+    - settings:
+        spawnOnSuperCritical: true
+        minAmount: 6
+        maxAmount: 10
+        maxRange: 5
+      spawns:
+      - MobSpawnCrabIron
 
 - type: entity
   id: AnomalyFlora
       types:
         Slash: 0
   - type: TileSpawnAnomaly
-    floorTileId: FloorAstroGrass
-    spawnRange: 6
+    entries:
+    - settings:
+        spawnOnPulse: true
+        minAmount: 3
+        maxAmount: 7
+        maxRange: 5
+      floor: FloorAstroGrass
+    - settings:
+        spawnOnSuperCritical: true
+        minAmount: 10
+        maxAmount: 30
+        maxRange: 15
+      floor: FloorAstroGrass
   - type: EntitySpawnAnomaly
-    maxSpawnAmount: 15
-    spawnRange: 6
-    superCriticalSpawns:
-    - KudzuFlowerAngry
-    spawns:
-    - KudzuFlowerFriendly
+    entries:
+    - settings:
+        spawnOnPulse: true
+        minAmount: 2
+        maxAmount: 5
+        maxRange: 2
+      spawns: 
+      - KudzuFlowerFriendly
+    - settings:
+        spawnOnSuperCritical: true
+        minAmount: 5
+        maxAmount: 10
+        maxRange: 6
+      spawns: 
+      - KudzuFlowerAngry
 
 - type: entity
   id: AnomalyFloraBulb
       types:
         Slash: 1
   - type: EntitySpawnAnomaly
-    superCriticalSpawns:
-    - ReagentSlimeSpawner
-    spawns:
-      - PuddleSparkle
+    entries:
+    - settings:
+        spawnOnSuperCritical: true
+        minAmount: 3
+        maxAmount: 8
+        maxRange: 2
+      spawns:
+      - ReagentSlimeSpawner
   - type: SolutionContainerManager
     solutions:
       anomaly:
index d5c542a0a173e520dccc4580e846eba2e48d6911..aa5f1421c737946fd4a64faef02883137b111916 100644 (file)
           state: rock_asteroid_west
         - state: rock_quartz
 
+- type: entity
+  id: AsteroidRockQuartzCrab
+  parent: AsteroidRock
+  description: An ore vein rich with quartz.
+  suffix: Quartz Crab
+  components:
+    - type: OreVein
+      oreChance: 1.0
+      currentOre: OreQuartzCrab
+    - type: Sprite
+      layers:
+        - state: rock_asteroid
+        - map: [ "enum.EdgeLayer.South" ]
+          state: rock_asteroid_south
+        - map: [ "enum.EdgeLayer.East" ]
+          state: rock_asteroid_east
+        - map: [ "enum.EdgeLayer.North" ]
+          state: rock_asteroid_north
+        - map: [ "enum.EdgeLayer.West" ]
+          state: rock_asteroid_west
+        - state: rock_quartz
+
 - type: entity
   id: AsteroidRockSilver
   parent: AsteroidRock
         - map: [ "enum.EdgeLayer.West" ]
           state: rock_asteroid_west
         - state: rock_silver
+        
+- type: entity
+  id: AsteroidRockSilverCrab
+  parent: AsteroidRockSilver
+  suffix: Silver Crab
+  components:
+    - type: OreVein
+      oreChance: 1.0
+      currentOre: OreSilverCrab
 
 # Yes I know it drops steel but we may get smelting at some point
 - type: entity
         - map: [ "enum.EdgeLayer.West" ]
           state: rock_asteroid_west
         - state: rock_tin
+        
+- type: entity
+  id: AsteroidRockTinCrab
+  parent: AsteroidRockTin
+  suffix: Iron
+  components:
+    - type: OreVein
+      oreChance: 1.0
+      currentOre: OreIronCrab
 
 - type: entity
   id: AsteroidRockUranium
           state: rock_asteroid_west
         - state: rock_uranium
 
+- type: entity
+  id: AsteroidRockUraniumCrab
+  parent: AsteroidRockUranium
+  suffix: Uranium Crab
+  components:
+    - type: OreVein
+      oreChance: 1.0
+      currentOre: OreUraniumCrab
 
 - type: entity
   id: AsteroidRockBananium
     oreChance: 0.33
     oreRarityPrototypeId: RandomOreDistributionStandard
 
-- type: entity
-  id: AsteroidRockCrab
-  parent: AsteroidRock
-  name: asteroid rock
-  suffix: orecrab
-  description: An asteroid.
-  components:
-  - type: Sprite
-    sprite: Structures/Walls/rock.rsi
-    layers:
-      - state: rock_asteroid_ore
-      - map: [ "enum.EdgeLayer.South" ]
-        state: rock_asteroid_south
-      - map: [ "enum.EdgeLayer.East" ]
-        state: rock_asteroid_east
-      - map: [ "enum.EdgeLayer.North" ]
-        state: rock_asteroid_north
-      - map: [ "enum.EdgeLayer.West" ]
-        state: rock_asteroid_west
-  - type: OreVein
-    oreChance: 0.33
-    oreRarityPrototypeId: OreCrab
-
-- type: entity
-  id: AsteroidRockCrab1
-  parent: AsteroidRockCrab
-  components:
-  - type: Sprite
-    sprite: Structures/Walls/rock.rsi
-    layers:
-      - state: rock_asteroid_ore1
-      - map: [ "enum.EdgeLayer.South" ]
-        state: rock_asteroid_south
-      - map: [ "enum.EdgeLayer.East" ]
-        state: rock_asteroid_east
-      - map: [ "enum.EdgeLayer.North" ]
-        state: rock_asteroid_north
-      - map: [ "enum.EdgeLayer.West" ]
-        state: rock_asteroid_west
-
 - type: entity
   id: IronRock
   parent: AsteroidRock
index f92a77a95ed07e8d75d6211cbf7841b4f44ce5e0..cfeabdaa8131470a8d54c12755fe3a83f06bdb93 100644 (file)
Binary files a/Resources/Textures/Structures/Specific/anomaly.rsi/anom6-pulse.png and b/Resources/Textures/Structures/Specific/anomaly.rsi/anom6-pulse.png differ
index 04c772bca1787588e9b44b43109fbc5d815fe3e6..14fc7d80c00005711861c259c827ecd110abd3ec 100644 (file)
Binary files a/Resources/Textures/Structures/Specific/anomaly.rsi/anom6.png and b/Resources/Textures/Structures/Specific/anomaly.rsi/anom6.png differ