Make ore loot use walls as a mask (#16377)
This commit is contained in:
@@ -5,9 +5,9 @@ using Content.Shared.Decals;
|
||||
using Content.Shared.Parallax.Biomes;
|
||||
using Content.Shared.Parallax.Biomes.Layers;
|
||||
using Content.Shared.Parallax.Biomes.Markers;
|
||||
using Content.Shared.Parallax.Biomes.Points;
|
||||
using Robust.Server.Player;
|
||||
using Robust.Shared;
|
||||
using Robust.Shared.Collections;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.Map;
|
||||
@@ -326,6 +326,9 @@ public sealed partial class BiomeSystem : SharedBiomeSystem
|
||||
{
|
||||
var markers = _markerChunks[component];
|
||||
var loadedMarkers = component.LoadedMarkers;
|
||||
var spawnSet = new HashSet<Vector2i>();
|
||||
var spawns = new List<Vector2i>();
|
||||
var frontier = new Queue<Vector2i>();
|
||||
|
||||
foreach (var (layer, chunks) in markers)
|
||||
{
|
||||
@@ -334,45 +337,112 @@ public sealed partial class BiomeSystem : SharedBiomeSystem
|
||||
if (loadedMarkers.TryGetValue(layer, out var mobChunks) && mobChunks.Contains(chunk))
|
||||
continue;
|
||||
|
||||
spawns.Clear();
|
||||
spawnSet.Clear();
|
||||
var layerProto = _proto.Index<BiomeMarkerLayerPrototype>(layer);
|
||||
var buffer = layerProto.Radius / 2f;
|
||||
mobChunks ??= new HashSet<Vector2i>();
|
||||
mobChunks.Add(chunk);
|
||||
loadedMarkers[layer] = mobChunks;
|
||||
var rand = new Random(noise.GetSeed() + chunk.X * 8 + chunk.Y);
|
||||
var rand = new Random(noise.GetSeed() + chunk.X * 8 + chunk.Y + layerProto.GetHashCode());
|
||||
|
||||
// We treat a null entity mask as requiring nothing else on the tile
|
||||
var lower = (int) Math.Floor(buffer);
|
||||
var upper = (int) Math.Ceiling(layerProto.Size - buffer);
|
||||
|
||||
// TODO: Okay this is inefficient as FUCK
|
||||
// I think the ideal is pick a random tile then BFS outwards from it probably ig
|
||||
// It will bias edge tiles significantly more but will make the CPU cry less.
|
||||
for (var x = lower; x <= upper; x++)
|
||||
{
|
||||
for (var y = lower; y <= upper; y++)
|
||||
{
|
||||
var index = new Vector2i(x + chunk.X, y + chunk.Y);
|
||||
TryGetEntity(index, component.Layers, component.Noise, grid, out var proto);
|
||||
|
||||
if (proto != layerProto.EntityMask)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
spawns.Add(index);
|
||||
spawnSet.Add(index);
|
||||
}
|
||||
}
|
||||
|
||||
// Load NOW
|
||||
// TODO: Need poisson but crashes whenever I use moony's due to inputs or smth
|
||||
// TODO: Need poisson but crashes whenever I use moony's due to inputs or smth idk
|
||||
var count = (int) ((layerProto.Size - buffer) * (layerProto.Size - buffer) / (layerProto.Radius * layerProto.Radius));
|
||||
count = Math.Min(count, layerProto.MaxCount);
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
for (var j = 0; j < 5; j++)
|
||||
if (spawns.Count == 0)
|
||||
break;
|
||||
|
||||
var index = rand.Next(spawns.Count);
|
||||
var point = spawns[index];
|
||||
spawns.RemoveSwap(index);
|
||||
|
||||
// Point was potentially used in BFS search below but we hadn't updated the list yet.
|
||||
if (!spawnSet.Remove(point))
|
||||
{
|
||||
var point = new Vector2(
|
||||
chunk.X + buffer + rand.NextFloat() * (layerProto.Size - buffer),
|
||||
chunk.Y + buffer + rand.NextFloat() * (layerProto.Size - buffer));
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
|
||||
var coords = new EntityCoordinates(gridUid, point);
|
||||
var tile = grid.LocalToTile(coords);
|
||||
// BFS search
|
||||
frontier.Enqueue(point);
|
||||
var groupCount = layerProto.GroupCount;
|
||||
|
||||
// Blocked spawn, try again.
|
||||
if (grid.GetAnchoredEntitiesEnumerator(tile).MoveNext(out _))
|
||||
while (frontier.TryDequeue(out var node) && groupCount > 0)
|
||||
{
|
||||
var enumerator = grid.GetAnchoredEntitiesEnumerator(node);
|
||||
|
||||
if (enumerator.MoveNext(out _))
|
||||
continue;
|
||||
|
||||
for (var k = 0; k < layerProto.GroupCount; k++)
|
||||
// Need to ensure the tile under it has loaded for anchoring.
|
||||
if (TryGetBiomeTile(node, component.Layers, component.Noise, grid, out var tile))
|
||||
{
|
||||
grid.SetTile(node, tile.Value);
|
||||
}
|
||||
|
||||
// If it is a ghost role then purge it
|
||||
// TODO: This is *kind* of a bandaid but natural mobs spawns needs a lot more work.
|
||||
// Ideally we'd just have ghost role and non-ghost role variants for some stuff.
|
||||
var uid = EntityManager.CreateEntityUninitialized(layerProto.Prototype, new EntityCoordinates(gridUid, point));
|
||||
var uid = EntityManager.CreateEntityUninitialized(layerProto.Prototype, new EntityCoordinates(gridUid, node));
|
||||
RemComp<GhostTakeoverAvailableComponent>(uid);
|
||||
RemComp<GhostRoleComponent>(uid);
|
||||
EntityManager.InitializeAndStartEntity(uid);
|
||||
groupCount--;
|
||||
|
||||
for (var x = -1; x <= 1; x++)
|
||||
{
|
||||
for (var y = -1; y <= 1; y++)
|
||||
{
|
||||
if (x != 0 && y != 0)
|
||||
continue;
|
||||
|
||||
var neighbor = new Vector2i(x + node.X, y + node.Y);
|
||||
|
||||
if (!spawnSet.Contains(neighbor))
|
||||
continue;
|
||||
|
||||
frontier.Enqueue(neighbor);
|
||||
// Rather than doing some uggo remove check on the list we'll defer it until later
|
||||
spawnSet.Remove(neighbor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
// Add the unused nodes back in
|
||||
foreach (var node in frontier)
|
||||
{
|
||||
spawnSet.Add(node);
|
||||
}
|
||||
|
||||
frontier.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ using Content.Shared.Atmos;
|
||||
using Content.Shared.Dataset;
|
||||
using Content.Shared.Gravity;
|
||||
using Content.Shared.Parallax.Biomes;
|
||||
using Content.Shared.Parallax.Biomes.Markers;
|
||||
using Content.Shared.Procedural;
|
||||
using Content.Shared.Procedural.Loot;
|
||||
using Content.Shared.Random;
|
||||
@@ -220,11 +221,21 @@ public sealed class SpawnSalvageMissionJob : Job<bool>
|
||||
|
||||
switch (rule)
|
||||
{
|
||||
case BiomeMarkerLoot biomeLoot:
|
||||
{
|
||||
if (_entManager.TryGetComponent<BiomeComponent>(gridUid, out var biome))
|
||||
{
|
||||
_biome.AddMarkerLayer(biome, biomeLoot.Prototype);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BiomeTemplateLoot biomeLoot:
|
||||
{
|
||||
if (_entManager.TryGetComponent<BiomeComponent>(gridUid, out var biome))
|
||||
{
|
||||
_biome.AddTemplate(biome, "Loot", _prototypeManager.Index<BiomeTemplatePrototype>(biomeLoot.Prototype), i);
|
||||
}
|
||||
}
|
||||
break;
|
||||
// Spawns a cluster (like an ore vein) nearby.
|
||||
case DungeonClusterLoot clusterLoot:
|
||||
|
||||
@@ -1,20 +1,36 @@
|
||||
using Content.Shared.Parallax.Biomes.Points;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||
|
||||
namespace Content.Shared.Parallax.Biomes.Markers;
|
||||
|
||||
/// <summary>
|
||||
/// Spawns entities inside of the specified area with the minimum specified radius.
|
||||
/// </summary>
|
||||
[Prototype("biomeMarkerLayer")]
|
||||
public sealed class BiomeMarkerLayerPrototype : IBiomeMarkerLayer
|
||||
{
|
||||
[IdDataField] public string ID { get; } = default!;
|
||||
|
||||
[DataField("proto", required: true, customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
|
||||
public string Prototype = string.Empty;
|
||||
public string Prototype { get; } = string.Empty;
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>
|
||||
/// Checks for the relevant entity for the tile before spawning. Useful for substituting walls with ore veins for example.
|
||||
/// </summary>
|
||||
[DataField("entityMask", customTypeSerializer:typeof(PrototypeIdSerializer<EntityPrototype>))]
|
||||
public string? EntityMask { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Minimum radius between 2 points
|
||||
/// </summary>
|
||||
[DataField("radius")]
|
||||
public float Radius { get; } = 32f;
|
||||
public float Radius = 32f;
|
||||
|
||||
/// <summary>
|
||||
/// Maximum amount of group spawns
|
||||
/// </summary>
|
||||
[DataField("maxCount")]
|
||||
public int MaxCount = int.MaxValue;
|
||||
|
||||
/// <summary>
|
||||
/// How many mobs to spawn in one group.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared.Parallax.Biomes.Points;
|
||||
namespace Content.Shared.Parallax.Biomes.Markers;
|
||||
|
||||
/// <summary>
|
||||
/// Specifies one-off marker points to be used. This could be for dungeon markers, mob markers, etc.
|
||||
@@ -9,14 +9,14 @@ namespace Content.Shared.Parallax.Biomes.Points;
|
||||
public interface IBiomeMarkerLayer : IPrototype
|
||||
{
|
||||
/// <summary>
|
||||
/// Minimum radius between 2 points
|
||||
/// Biome template to use as a mask for this layer.
|
||||
/// </summary>
|
||||
[DataField("radius")]
|
||||
public float Radius { get; }
|
||||
public string? EntityMask { get; }
|
||||
|
||||
public string Prototype { get; }
|
||||
|
||||
/// <summary>
|
||||
/// How large the pre-generated points area is.
|
||||
/// </summary>
|
||||
[DataField("size")]
|
||||
public int Size { get; }
|
||||
}
|
||||
|
||||
13
Content.Shared/Procedural/Loot/BiomeMarkerLoot.cs
Normal file
13
Content.Shared/Procedural/Loot/BiomeMarkerLoot.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using Content.Shared.Parallax.Biomes.Markers;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||
|
||||
namespace Content.Shared.Procedural.Loot;
|
||||
|
||||
/// <summary>
|
||||
/// Adds a biome marker layer for dungeon loot.
|
||||
/// </summary>
|
||||
public sealed class BiomeMarkerLoot : IDungeonLoot
|
||||
{
|
||||
[DataField("proto", required: true, customTypeSerializer:typeof(PrototypeIdSerializer<BiomeMarkerLayerPrototype>))]
|
||||
public string Prototype = string.Empty;
|
||||
}
|
||||
@@ -3,12 +3,8 @@ using Content.Shared.Audio;
|
||||
using Content.Shared.Hands.Components;
|
||||
using Robust.Shared.GameStates;
|
||||
using Content.Shared.Weapons.Ranged.Events;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Robust.Shared.Physics.Components;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Projectiles;
|
||||
using Content.Shared.Weapons.Ranged.Events;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Physics.Systems;
|
||||
using Robust.Shared.Random;
|
||||
|
||||
|
||||
@@ -1,108 +1,54 @@
|
||||
# Allowed
|
||||
#allowedTiles:
|
||||
#- FloorPlanetGrass
|
||||
#- FloorPlanetDirt
|
||||
#- FloorSnow
|
||||
#- FloorBasalt
|
||||
#- FloorAsteroidSand
|
||||
|
||||
- type: biomeTemplate
|
||||
# Low value
|
||||
- type: biomeMarkerLayer
|
||||
id: OreTin
|
||||
layers:
|
||||
- !type:BiomeEntityLayer
|
||||
threshold: 0.90
|
||||
allowedTiles:
|
||||
- FloorPlanetGrass
|
||||
- FloorPlanetDirt
|
||||
- FloorSnow
|
||||
- FloorBasalt
|
||||
- FloorAsteroidSand
|
||||
noise:
|
||||
seed: 100
|
||||
noiseType: OpenSimplex2
|
||||
frequency: 0.04
|
||||
fractalType: None
|
||||
entities:
|
||||
- WallRockTin
|
||||
proto: WallRockTin
|
||||
entityMask: WallRock
|
||||
maxCount: 5
|
||||
groupCount: 10
|
||||
radius: 4
|
||||
|
||||
# Medium value
|
||||
# Gold
|
||||
- type: biomeTemplate
|
||||
- type: biomeMarkerLayer
|
||||
id: OreGold
|
||||
layers:
|
||||
- !type:BiomeEntityLayer
|
||||
threshold: 0.95
|
||||
allowedTiles:
|
||||
- FloorPlanetGrass
|
||||
- FloorPlanetDirt
|
||||
- FloorSnow
|
||||
- FloorBasalt
|
||||
- FloorAsteroidSand
|
||||
noise:
|
||||
seed: 100
|
||||
noiseType: OpenSimplex2
|
||||
frequency: 0.04
|
||||
fractalType: None
|
||||
entities:
|
||||
- WallRockGold
|
||||
proto: WallRockGold
|
||||
entityMask: WallRock
|
||||
maxCount: 5
|
||||
groupCount: 5
|
||||
radius: 4
|
||||
|
||||
# Silver
|
||||
- type: biomeTemplate
|
||||
- type: biomeMarkerLayer
|
||||
id: OreSilver
|
||||
layers:
|
||||
- !type:BiomeEntityLayer
|
||||
threshold: 0.95
|
||||
allowedTiles:
|
||||
- FloorPlanetGrass
|
||||
- FloorPlanetDirt
|
||||
- FloorSnow
|
||||
- FloorBasalt
|
||||
- FloorAsteroidSand
|
||||
noise:
|
||||
seed: 100
|
||||
noiseType: OpenSimplex2
|
||||
frequency: 0.05
|
||||
fractalType: None
|
||||
entities:
|
||||
- WallRockSilver
|
||||
proto: WallRockSilver
|
||||
entityMask: WallRock
|
||||
maxCount: 5
|
||||
groupCount: 5
|
||||
radius: 4
|
||||
|
||||
# High value
|
||||
# Plasma
|
||||
- type: biomeTemplate
|
||||
- type: biomeMarkerLayer
|
||||
id: OrePlasma
|
||||
layers:
|
||||
- !type:BiomeEntityLayer
|
||||
threshold: 0.99
|
||||
allowedTiles:
|
||||
- FloorPlanetGrass
|
||||
- FloorPlanetDirt
|
||||
- FloorSnow
|
||||
- FloorBasalt
|
||||
- FloorAsteroidSand
|
||||
noise:
|
||||
seed: 100
|
||||
noiseType: OpenSimplex2
|
||||
frequency: 0.04
|
||||
fractalType: None
|
||||
entities:
|
||||
- WallRockPlasma
|
||||
proto: WallRockPlasma
|
||||
entityMask: WallRock
|
||||
maxCount: 2
|
||||
groupCount: 5
|
||||
radius: 4
|
||||
|
||||
# Uranium
|
||||
- type: biomeTemplate
|
||||
- type: biomeMarkerLayer
|
||||
id: OreUranium
|
||||
layers:
|
||||
- !type:BiomeEntityLayer
|
||||
threshold: 0.99
|
||||
allowedTiles:
|
||||
- FloorPlanetGrass
|
||||
- FloorPlanetDirt
|
||||
- FloorSnow
|
||||
- FloorBasalt
|
||||
- FloorAsteroidSand
|
||||
noise:
|
||||
seed: 100
|
||||
noiseType: OpenSimplex2
|
||||
frequency: 0.04
|
||||
fractalType: None
|
||||
entities:
|
||||
- WallRockUranium
|
||||
proto: WallRockUranium
|
||||
entityMask: WallRock
|
||||
maxCount: 2
|
||||
groupCount: 5
|
||||
radius: 4
|
||||
|
||||
- type: biomeMarkerLayer
|
||||
id: OreBananium
|
||||
proto: WallRockBananium
|
||||
entityMask: WallRock
|
||||
maxCount: 2
|
||||
groupCount: 5
|
||||
radius: 4
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
id: OreTin
|
||||
desc: Veins of steel
|
||||
loots:
|
||||
- !type:BiomeTemplateLoot
|
||||
- !type:BiomeMarkerLoot
|
||||
proto: OreTin
|
||||
|
||||
# - Medium value
|
||||
@@ -64,14 +64,14 @@
|
||||
id: OreGold
|
||||
desc: Veins of gold ore
|
||||
loots:
|
||||
- !type:BiomeTemplateLoot
|
||||
- !type:BiomeMarkerLoot
|
||||
proto: OreGold
|
||||
|
||||
- type: salvageLoot
|
||||
id: OreSilver
|
||||
desc: Veins of silver ore
|
||||
loots:
|
||||
- !type:BiomeTemplateLoot
|
||||
- !type:BiomeMarkerLoot
|
||||
proto: OreSilver
|
||||
|
||||
# - High value
|
||||
@@ -79,12 +79,12 @@
|
||||
id: OrePlasma
|
||||
desc: Veins of plasma ore
|
||||
loots:
|
||||
- !type:BiomeTemplateLoot
|
||||
- !type:BiomeMarkerLoot
|
||||
proto: OrePlasma
|
||||
|
||||
- type: salvageLoot
|
||||
id: OreUranium
|
||||
desc: Veins of uranium ore
|
||||
loots:
|
||||
- !type:BiomeTemplateLoot
|
||||
- !type:BiomeMarkerLoot
|
||||
proto: OreUranium
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
id: OreBananium
|
||||
oreEntity: BananiumOre1
|
||||
minOreYield: 1
|
||||
maxOreYield: 2
|
||||
maxOreYield: 3
|
||||
|
||||
- type: weightedRandom
|
||||
id: RandomOreDistributionStandard
|
||||
|
||||
Reference in New Issue
Block a user