Meteors now leave behind a bit of ore (#30419)

* 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>
This commit is contained in:
Plykiya
2024-07-31 19:55:02 -07:00
committed by GitHub
parent 1ef4f26a44
commit 1d2b7131ab
5 changed files with 138 additions and 1 deletions

View File

@@ -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()));
}
}
}
}

View File

@@ -1,4 +1,5 @@
using Content.Server.Spawners.Components; using Content.Server.Spawners.Components;
using Robust.Shared.Prototypes;
using Robust.Shared.Spawners; using Robust.Shared.Spawners;
namespace Content.Server.Spawners.EntitySystems; namespace Content.Server.Spawners.EntitySystems;
@@ -19,4 +20,9 @@ public sealed class SpawnOnDespawnSystem : EntitySystem
Spawn(comp.Prototype, xform.Coordinates); Spawn(comp.Prototype, xform.Coordinates);
} }
public void SetPrototype(Entity<SpawnOnDespawnComponent> entity, EntProtoId prototype)
{
entity.Comp.Prototype = prototype;
}
} }

View File

@@ -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

View File

@@ -112,6 +112,11 @@
sound: sound:
collection: MetalBreak collection: MetalBreak
- !type:ExplodeBehavior - !type:ExplodeBehavior
- !type:WeightedSpawnEntityBehavior
weightedEntityTable: "MeteorSpawnAsteroidWallTable"
minSpawn: 2
maxSpawn: 4
spawnAfter: 0.5
- type: entity - type: entity
parent: BaseMeteor parent: BaseMeteor
@@ -147,6 +152,12 @@
sound: sound:
collection: MetalBreak collection: MetalBreak
- !type:ExplodeBehavior - !type:ExplodeBehavior
- !type:WeightedSpawnEntityBehavior
weightedEntityTable: "MeteorSpawnAsteroidWallTable"
spawnOffset: 2
minSpawn: 3
maxSpawn: 6
spawnAfter: 0.5
- type: entity - type: entity
parent: BaseMeteor parent: BaseMeteor
@@ -169,6 +180,12 @@
sound: sound:
collection: MetalBreak collection: MetalBreak
- !type:ExplodeBehavior - !type:ExplodeBehavior
- !type:WeightedSpawnEntityBehavior
weightedEntityTable: "MeteorSpawnAsteroidWallTable"
spawnOffset: 3
minSpawn: 5
maxSpawn: 8
spawnAfter: 0.5
- type: entity - type: entity
parent: BaseMeteor parent: BaseMeteor

View File

@@ -17,6 +17,20 @@
GameRuleMeteorSwarmLarge: 5 GameRuleMeteorSwarmLarge: 5
GameRuleUristSwarm: 0.05 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 - type: entity
parent: BaseGameRule parent: BaseGameRule
id: GameRuleMeteorSwarm id: GameRuleMeteorSwarm