]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Meteors now leave behind a bit of ore (#30419)
authorPlykiya <58439124+Plykiya@users.noreply.github.com>
Thu, 1 Aug 2024 02:55:02 +0000 (19:55 -0700)
committerGitHub <noreply@github.com>
Thu, 1 Aug 2024 02:55:02 +0000 (19:55 -0700)
* Meteors that leave behind asteroid ore

* bigger offset

* Bit more generic

* Better defaults

* hrm?

* I HATE CUSTOM SERIALIZERS

* More comments

* renamed a variable

---------

Co-authored-by: plykiya <plykiya@protonmail.com>
Content.Server/Destructible/Thresholds/Behaviors/WeightedSpawnEntityBehavior.cs [new file with mode: 0644]
Content.Server/Spawners/EntitySystems/SpawnOnDespawnSystem.cs
Resources/Prototypes/Entities/Markers/Spawners/temp.yml [new file with mode: 0644]
Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/meteors.yml
Resources/Prototypes/GameRules/meteorswarms.yml

diff --git a/Content.Server/Destructible/Thresholds/Behaviors/WeightedSpawnEntityBehavior.cs b/Content.Server/Destructible/Thresholds/Behaviors/WeightedSpawnEntityBehavior.cs
new file mode 100644 (file)
index 0000000..e02ed87
--- /dev/null
@@ -0,0 +1,89 @@
+using System.Numerics;
+using Content.Server.Spawners.Components;
+using Content.Server.Spawners.EntitySystems;
+using Content.Shared.Random;
+using Content.Shared.Random.Helpers;
+using Robust.Server.GameObjects;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
+using Robust.Shared.Spawners;
+
+namespace Content.Server.Destructible.Thresholds.Behaviors;
+
+/// <summary>
+/// Behavior that can be assigned to a trigger that that takes a <see cref="WeightedRandomEntityPrototype"/>
+/// and spawns a number of the same entity between a given min and max
+/// at a random offset from the final position of the entity.
+/// </summary>
+[Serializable]
+[DataDefinition]
+public sealed partial class WeightedSpawnEntityBehavior : IThresholdBehavior
+{
+    /// <summary>
+    /// A table of entities with assigned weights to randomly pick from
+    /// </summary>
+    [DataField(required: true)]
+    public ProtoId<WeightedRandomEntityPrototype> WeightedEntityTable;
+
+    /// <summary>
+    /// How far away to spawn the entity from the parent position
+    /// </summary>
+    [DataField]
+    public float SpawnOffset = 1;
+
+    /// <summary>
+    /// The mininum number of entities to spawn randomly
+    /// </summary>
+    [DataField]
+    public int MinSpawn = 1;
+
+    /// <summary>
+    /// The max number of entities to spawn randomly
+    /// </summary>
+    [DataField]
+    public int MaxSpawn = 1;
+
+    /// <summary>
+    /// Time in seconds to wait before spawning entities
+    /// </summary>
+    [DataField]
+    public float SpawnAfter;
+
+    public void Execute(EntityUid uid, DestructibleSystem system, EntityUid? cause = null)
+    {
+        // Get the position at which to start initially spawning entities
+        var transform = system.EntityManager.System<TransformSystem>();
+        var position = transform.GetMapCoordinates(uid);
+        // Helper function used to randomly get an offset to apply to the original position
+        Vector2 GetRandomVector() => new (system.Random.NextFloat(-SpawnOffset, SpawnOffset), system.Random.NextFloat(-SpawnOffset, SpawnOffset));
+        // Randomly pick the entity to spawn and randomly pick how many to spawn
+        var entity = system.PrototypeManager.Index(WeightedEntityTable).Pick(system.Random);
+        var amountToSpawn = system.Random.NextFloat(MinSpawn, MaxSpawn);
+
+        // Different behaviors for delayed spawning and immediate spawning
+        if (SpawnAfter != 0)
+        {
+            // if it fails to get the spawner, this won't ever work so just return
+            if (!system.PrototypeManager.TryIndex("TemporaryEntityForTimedDespawnSpawners", out var tempSpawnerProto))
+                return;
+
+            // spawn the spawner, assign it a lifetime, and assign the entity that it will spawn when despawned
+            for (var i = 0; i < amountToSpawn; i++)
+            {
+                var spawner = system.EntityManager.SpawnEntity(tempSpawnerProto.ID, position.Offset(GetRandomVector()));
+                system.EntityManager.EnsureComponent<TimedDespawnComponent>(spawner, out var timedDespawnComponent);
+                timedDespawnComponent.Lifetime = SpawnAfter;
+                system.EntityManager.EnsureComponent<SpawnOnDespawnComponent>(spawner, out var spawnOnDespawnComponent);
+                system.EntityManager.System<SpawnOnDespawnSystem>().SetPrototype((spawner, spawnOnDespawnComponent), entity);
+            }
+        }
+        else
+        {
+            // directly spawn the desired entities
+            for (var i = 0; i < amountToSpawn; i++)
+            {
+                system.EntityManager.SpawnEntity(entity, position.Offset(GetRandomVector()));
+            }
+        }
+    }
+}
index f5a34728dc86879db0356050fcbb727d46203493..2f850faab1366a172bc372be5332cd34381a70e6 100644 (file)
@@ -1,4 +1,5 @@
 using Content.Server.Spawners.Components;
+using Robust.Shared.Prototypes;
 using Robust.Shared.Spawners;
 
 namespace Content.Server.Spawners.EntitySystems;
@@ -19,4 +20,9 @@ public sealed class SpawnOnDespawnSystem : EntitySystem
 
         Spawn(comp.Prototype, xform.Coordinates);
     }
+
+    public void SetPrototype(Entity<SpawnOnDespawnComponent> entity, EntProtoId prototype)
+    {
+        entity.Comp.Prototype = prototype;
+    }
 }
diff --git a/Resources/Prototypes/Entities/Markers/Spawners/temp.yml b/Resources/Prototypes/Entities/Markers/Spawners/temp.yml
new file mode 100644 (file)
index 0000000..aa76bb5
--- /dev/null
@@ -0,0 +1,11 @@
+- type: entity
+  id: TemporaryEntityForTimedDespawnSpawners
+  categories: [ HideSpawnMenu, Spawner ]
+  components:
+  - type: Transform
+    anchored: True
+  - type: Physics
+    bodyType: Static
+    canCollide: false
+  - type: TimedDespawn
+    # we can't declare the SpawnOnDespawnComponent because the entity is required on yml
index 3468cade76b564c897caa3f6c04a5be736ad7c78..235010acc96cb13b6beba01a5cd2b74b90af034a 100644 (file)
         sound:
           collection: MetalBreak
       - !type:ExplodeBehavior
+      - !type:WeightedSpawnEntityBehavior
+        weightedEntityTable: "MeteorSpawnAsteroidWallTable"
+        minSpawn: 2
+        maxSpawn: 4
+        spawnAfter: 0.5
 
 - type: entity
   parent: BaseMeteor
         sound:
           collection: MetalBreak
       - !type:ExplodeBehavior
+      - !type:WeightedSpawnEntityBehavior
+        weightedEntityTable: "MeteorSpawnAsteroidWallTable"
+        spawnOffset: 2
+        minSpawn: 3
+        maxSpawn: 6
+        spawnAfter: 0.5
 
 - type: entity
   parent: BaseMeteor
         sound:
           collection: MetalBreak
       - !type:ExplodeBehavior
+      - !type:WeightedSpawnEntityBehavior
+        weightedEntityTable: "MeteorSpawnAsteroidWallTable"
+        spawnOffset: 3
+        minSpawn: 5
+        maxSpawn: 8
+        spawnAfter: 0.5
 
 - type: entity
   parent: BaseMeteor
             volume: 10
       - !type:SpillBehavior
         solution: blood
-      - !type:ExplodeBehavior
+      - !type:ExplodeBehavior
\ No newline at end of file
index b85032f0564c52c96d1020bb1ebf0afa2793e15f..2f1cb4eba5ed90c766faadcc553eae945365cd96 100644 (file)
     GameRuleMeteorSwarmLarge: 5
     GameRuleUristSwarm: 0.05
 
+- type: weightedRandomEntity
+  id: MeteorSpawnAsteroidWallTable
+  weights:
+    AsteroidRock: 10
+    AsteroidRockCoal: 5
+    AsteroidRockQuartz: 5
+    AsteroidRockTin: 5
+    AsteroidRockSilver: 2
+    AsteroidRockGold: 2
+    AsteroidRockPlasma: 2
+    AsteroidRockDiamond: 2
+    AsteroidRockUranium: 0.5
+    AsteroidRockBananium: 0.5      
+
 - type: entity
   parent: BaseGameRule
   id: GameRuleMeteorSwarm