WeightedSpawnEntityBehavior.cs 3.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. using System.Numerics;
  2. using Content.Server.Spawners.Components;
  3. using Content.Server.Spawners.EntitySystems;
  4. using Content.Shared.Random;
  5. using Content.Shared.Random.Helpers;
  6. using Robust.Server.GameObjects;
  7. using Robust.Shared.Prototypes;
  8. using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
  9. using Robust.Shared.Spawners;
  10. namespace Content.Server.Destructible.Thresholds.Behaviors;
  11. /// <summary>
  12. /// Behavior that can be assigned to a trigger that that takes a <see cref="WeightedRandomEntityPrototype"/>
  13. /// and spawns a number of the same entity between a given min and max
  14. /// at a random offset from the final position of the entity.
  15. /// </summary>
  16. [Serializable]
  17. [DataDefinition]
  18. public sealed partial class WeightedSpawnEntityBehavior : IThresholdBehavior
  19. {
  20. /// <summary>
  21. /// A table of entities with assigned weights to randomly pick from
  22. /// </summary>
  23. [DataField(required: true)]
  24. public ProtoId<WeightedRandomEntityPrototype> WeightedEntityTable;
  25. /// <summary>
  26. /// How far away to spawn the entity from the parent position
  27. /// </summary>
  28. [DataField]
  29. public float SpawnOffset = 1;
  30. /// <summary>
  31. /// The mininum number of entities to spawn randomly
  32. /// </summary>
  33. [DataField]
  34. public int MinSpawn = 1;
  35. /// <summary>
  36. /// The max number of entities to spawn randomly
  37. /// </summary>
  38. [DataField]
  39. public int MaxSpawn = 1;
  40. /// <summary>
  41. /// Time in seconds to wait before spawning entities
  42. /// </summary>
  43. [DataField]
  44. public float SpawnAfter;
  45. public void Execute(EntityUid uid, DestructibleSystem system, EntityUid? cause = null)
  46. {
  47. // Get the position at which to start initially spawning entities
  48. var transform = system.EntityManager.System<TransformSystem>();
  49. var position = transform.GetMapCoordinates(uid);
  50. // Helper function used to randomly get an offset to apply to the original position
  51. Vector2 GetRandomVector() => new (system.Random.NextFloat(-SpawnOffset, SpawnOffset), system.Random.NextFloat(-SpawnOffset, SpawnOffset));
  52. // Randomly pick the entity to spawn and randomly pick how many to spawn
  53. var entity = system.PrototypeManager.Index(WeightedEntityTable).Pick(system.Random);
  54. var amountToSpawn = system.Random.NextFloat(MinSpawn, MaxSpawn);
  55. // Different behaviors for delayed spawning and immediate spawning
  56. if (SpawnAfter != 0)
  57. {
  58. // if it fails to get the spawner, this won't ever work so just return
  59. if (!system.PrototypeManager.TryIndex("TemporaryEntityForTimedDespawnSpawners", out var tempSpawnerProto))
  60. return;
  61. // spawn the spawner, assign it a lifetime, and assign the entity that it will spawn when despawned
  62. for (var i = 0; i < amountToSpawn; i++)
  63. {
  64. var spawner = system.EntityManager.SpawnEntity(tempSpawnerProto.ID, position.Offset(GetRandomVector()));
  65. system.EntityManager.EnsureComponent<TimedDespawnComponent>(spawner, out var timedDespawnComponent);
  66. timedDespawnComponent.Lifetime = SpawnAfter;
  67. system.EntityManager.EnsureComponent<SpawnOnDespawnComponent>(spawner, out var spawnOnDespawnComponent);
  68. system.EntityManager.System<SpawnOnDespawnSystem>().SetPrototype((spawner, spawnOnDespawnComponent), entity);
  69. }
  70. }
  71. else
  72. {
  73. // directly spawn the desired entities
  74. for (var i = 0; i < amountToSpawn; i++)
  75. {
  76. system.EntityManager.SpawnEntity(entity, position.Offset(GetRandomVector()));
  77. }
  78. }
  79. }
  80. }