diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.cs index f2bd5a4394..bbc390b95a 100644 --- a/Content.Server/Procedural/DungeonJob/DungeonJob.cs +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.cs @@ -213,6 +213,11 @@ public sealed partial class DungeonJob : Job> switch (layer) { + //CP14 zone + case CP14OreDunGen cp14OreDunGen: + await PostGen(cp14OreDunGen, dungeons, reservedTiles, random); + break; + //CP14 zone end case AutoCablingDunGen cabling: await PostGen(cabling, dungeons[^1], reservedTiles, random); break; diff --git a/Content.Server/_CP14/Procedural/DungeonJob/DungeonJob.CP14Ore.cs b/Content.Server/_CP14/Procedural/DungeonJob/DungeonJob.CP14Ore.cs new file mode 100644 index 0000000000..7bc77534e4 --- /dev/null +++ b/Content.Server/_CP14/Procedural/DungeonJob/DungeonJob.CP14Ore.cs @@ -0,0 +1,159 @@ +using System.Threading.Tasks; +using Content.Shared.Maps; +using Content.Shared.Procedural; +using Content.Shared.Procedural.Components; +using Content.Shared.Procedural.DungeonLayers; +using Robust.Shared.Collections; +using Robust.Shared.Prototypes; +using Robust.Shared.Random; + +namespace Content.Server.Procedural.DungeonJob; + +public sealed partial class DungeonJob +{ + /// + /// + /// + private async Task PostGen( + CP14OreDunGen gen, + List dungeons, + HashSet reservedTiles, + Random random) + { + // Doesn't use dungeon data because layers and we don't need top-down support at the moment. + + var replaceEntities = new Dictionary(); + var availableTiles = new List(); + var tiles = _maps.GetAllTilesEnumerator(_gridUid, _grid); + + // WARNING: + // This DunGen handles not only the tiles of the passed dungeon, but ALL the tiles of the current grid + // So don't run it anywhere + while (tiles.MoveNext(out var tileRef)) + { + var tile = tileRef.Value.GridIndices; + + //Tile mask filtering + if (gen.TileMask is not null) + { + if (!gen.TileMask.Contains(((ContentTileDefinition) _tileDefManager[tileRef.Value.Tile.TypeId]).ID)) + continue; + } + + //Entity mask filtering + if (gen.EntityMask is not null) + { + var found = false; + var enumerator2 = _maps.GetAnchoredEntitiesEnumerator(_gridUid, _grid, tile); + while (enumerator2.MoveNext(out var uid)) + { + var prototype = _entManager.GetComponent(uid.Value).EntityPrototype; + + if (prototype?.ID is null) + continue; + + if (!gen.EntityMask.Contains(prototype.ID)) + continue; + + replaceEntities[tile] = uid.Value; + found = true; + } + + if (!found) + continue; + } + else + { + //If entity mask null - we ignore the tiles that have anything on them. + if (!_anchorable.TileFree(_grid, tile, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask)) + continue; + } + + // Add it to valid nodes. + availableTiles.Add(tile); + + await SuspendDungeon(); + + if (!ValidateResume()) + return; + } + + var remapping = new Dictionary(); + + // TODO: Move this to engine + if (_prototype.TryIndex(gen.Entity, out var proto) && + proto.Components.TryGetComponent("EntityRemap", out var comps)) + { + var remappingComp = (EntityRemapComponent) comps; + remapping = remappingComp.Mask; + } + + var frontier = new ValueList(32); + + // Iterate the group counts and pathfind out each group. + for (var i = 0; i < gen.Count; i++) + { + await SuspendDungeon(); + + if (!ValidateResume()) + return; + + var groupSize = random.Next(gen.MinGroupSize, gen.MaxGroupSize + 1); + + // While we have remaining tiles keep iterating + while (groupSize > 0 && availableTiles.Count > 0) + { + var startNode = random.PickAndTake(availableTiles); + frontier.Clear(); + frontier.Add(startNode); + + // This essentially may lead to a vein being split in multiple areas but the count matters more than position. + while (frontier.Count > 0 && groupSize > 0) + { + // Need to pick a random index so we don't just get straight lines of ores. + var frontierIndex = random.Next(frontier.Count); + var node = frontier[frontierIndex]; + frontier.RemoveSwap(frontierIndex); + availableTiles.Remove(node); + + // Add neighbors if they're valid, worst case we add no more and pick another random seed tile. + for (var x = -1; x <= 1; x++) + { + for (var y = -1; y <= 1; y++) + { + var neighbor = new Vector2i(node.X + x, node.Y + y); + + if (frontier.Contains(neighbor) || !availableTiles.Contains(neighbor)) + continue; + + frontier.Add(neighbor); + } + } + + var prototype = gen.Entity; + + if (replaceEntities.TryGetValue(node, out var existingEnt)) + { + var existingProto = _entManager.GetComponent(existingEnt).EntityPrototype; + _entManager.DeleteEntity(existingEnt); + + if (existingProto != null && remapping.TryGetValue(existingProto.ID, out var remapped)) + { + prototype = remapped; + } + } + + // Tile valid salad so add it. + _entManager.SpawnAtPosition(prototype, _maps.GridTileToLocal(_gridUid, _grid, node)); + + groupSize--; + } + } + + if (groupSize > 0) + { + _sawmill.Warning($"Found remaining group size for ore veins of {gen.Entity.Id ?? "null"}!"); + } + } + } +} diff --git a/Content.Shared/Procedural/DungeonLayers/OreDunGen.cs b/Content.Shared/Procedural/DungeonLayers/OreDunGen.cs index 3c2c4db441..308e44b4cc 100644 --- a/Content.Shared/Procedural/DungeonLayers/OreDunGen.cs +++ b/Content.Shared/Procedural/DungeonLayers/OreDunGen.cs @@ -1,4 +1,3 @@ -using Content.Shared.Maps; using Robust.Shared.Prototypes; namespace Content.Shared.Procedural.DungeonLayers; @@ -13,16 +12,10 @@ namespace Content.Shared.Procedural.DungeonLayers; public partial class OreDunGen : IDunGenLayer { /// - /// This vein can only be generated by replacing the specified entities. + /// If the vein generation should occur on top of existing entities what are we replacing. /// [DataField] - public HashSet? EntityMask; - - /// - /// This vein can only be generated on the specified tiles - /// - [DataField] - public HashSet>? TileMask; + public EntProtoId? Replacement; /// /// Entity to spawn. diff --git a/Content.Shared/_CP14/Procedural/DungeonLayers/CP14OreDunGen.cs b/Content.Shared/_CP14/Procedural/DungeonLayers/CP14OreDunGen.cs new file mode 100644 index 0000000000..6dd6cf3d47 --- /dev/null +++ b/Content.Shared/_CP14/Procedural/DungeonLayers/CP14OreDunGen.cs @@ -0,0 +1,50 @@ +using Content.Shared.Maps; +using Robust.Shared.Prototypes; + +namespace Content.Shared.Procedural.DungeonLayers; + +/// +/// Generates veins inside of the specified dungeon. +/// +/// +/// Generates on top of existing entities for sanity reasons moreso than performance. +/// +[Virtual] +public partial class CP14OreDunGen : IDunGenLayer +{ + /// + /// This vein can only be generated by replacing the specified entities. + /// + [DataField] + public HashSet? EntityMask; + + /// + /// This vein can only be generated on the specified tiles + /// + [DataField] + public HashSet>? TileMask; + + /// + /// Entity to spawn. + /// + [DataField(required: true)] + public EntProtoId Entity; + + /// + /// Maximum amount of group spawns + /// + [DataField] + public int Count = 10; + + /// + /// Minimum entities to spawn in one group. + /// + [DataField] + public int MinGroupSize = 1; + + /// + /// Maximum entities to spawn in one group. + /// + [DataField] + public int MaxGroupSize = 1; +} diff --git a/Resources/Prototypes/_CP14/Procedural/Demiplane/Modifiers/Danger/misc.yml b/Resources/Prototypes/_CP14/Procedural/Demiplane/Modifiers/Danger/misc.yml index cd4a73253b..6eb4844f83 100644 --- a/Resources/Prototypes/_CP14/Procedural/Demiplane/Modifiers/Danger/misc.yml +++ b/Resources/Prototypes/_CP14/Procedural/Demiplane/Modifiers/Danger/misc.yml @@ -10,7 +10,7 @@ categories: Danger: 0.25 layers: - - !type:OreDunGen + - !type:CP14OreDunGen entity: CP14Chasm tileMask: - CP14FloorBase @@ -33,7 +33,7 @@ - CP14DemiplaneCold - CP14DemiplaneHerbals layers: - - !type:OreDunGen + - !type:CP14OreDunGen entity: CP14FloorLava tileMask: - CP14FloorBase @@ -53,7 +53,7 @@ categories: Danger: 0.2 layers: - - !type:OreDunGen + - !type:CP14OreDunGen entity: LandMineExplosive count: 20 minGroupSize: 1 @@ -68,7 +68,7 @@ categories: Danger: 0.25 layers: - - !type:OreDunGen + - !type:CP14OreDunGen entity: CP14AstralHaze count: 10 minGroupSize: 1 diff --git a/Resources/Prototypes/_CP14/Procedural/Demiplane/Modifiers/Danger/mobs.yml b/Resources/Prototypes/_CP14/Procedural/Demiplane/Modifiers/Danger/mobs.yml index 796c7b1a4e..48826941ea 100644 --- a/Resources/Prototypes/_CP14/Procedural/Demiplane/Modifiers/Danger/mobs.yml +++ b/Resources/Prototypes/_CP14/Procedural/Demiplane/Modifiers/Danger/mobs.yml @@ -12,7 +12,7 @@ blacklistTags: - CP14DemiplaneHot layers: - - !type:OreDunGen + - !type:CP14OreDunGen entity: CP14SpawnMobUndeadZombieRandom count: 4 minGroupSize: 3 @@ -30,7 +30,7 @@ - CP14DemiplaneOpenSky - CP14DemiplaneHerbals layers: - - !type:OreDunGen + - !type:CP14OreDunGen entity: CP14SpawnMobDinoYumkaraptor count: 5 minGroupSize: 1 @@ -49,7 +49,7 @@ blacklistTags: - CP14DemiplaneHot layers: - - !type:OreDunGen + - !type:CP14OreDunGen entity: CP14SpawnMobMonsterMosquito count: 4 minGroupSize: 2 @@ -66,7 +66,7 @@ requiredTags: - CP14DemiplaneHerbals layers: - - !type:OreDunGen + - !type:CP14OreDunGen entity: CP14MobDinoSmallHydra count: 4 minGroupSize: 2 @@ -85,7 +85,7 @@ requiredTags: - CP14DemiplaneUnderground layers: - - !type:OreDunGen + - !type:CP14OreDunGen entity: CP14MobMonsterMole count: 6 minGroupSize: 1 @@ -104,7 +104,7 @@ blacklistTags: - CP14DemiplaneHot layers: - - !type:OreDunGen + - !type:CP14OreDunGen entity: CP14MobIceSpectre count: 6 minGroupSize: 1 @@ -121,7 +121,7 @@ # requiredTags: # - CP14DemiplaneUnderground # layers: -# - !type:OreDunGen +# - !type:CP14OreDunGen # entity: CP14MobMonsterInvisibleWhistler # count: 2 # minGroupSize: 1 @@ -136,7 +136,7 @@ categories: Danger: 0.35 layers: - - !type:OreDunGen + - !type:CP14OreDunGen entity: CP14MobSlimeElectric count: 6 minGroupSize: 1 @@ -153,7 +153,7 @@ requiredTags: - CP14DemiplaneHot layers: - - !type:OreDunGen + - !type:CP14OreDunGen entity: CP14MobSlimeFire count: 6 minGroupSize: 1 @@ -170,7 +170,7 @@ requiredTags: - CP14DemiplaneCold layers: - - !type:OreDunGen + - !type:CP14OreDunGen entity: CP14MobSlimeIce count: 6 minGroupSize: 1 @@ -184,7 +184,7 @@ categories: Danger: 0.25 layers: - - !type:OreDunGen + - !type:CP14OreDunGen entity: CP14MobSlimeBase count: 6 minGroupSize: 1 @@ -203,7 +203,7 @@ blacklistTags: - CP14DemiplaneHot layers: - - !type:OreDunGen + - !type:CP14OreDunGen entity: CP14MobWatcherIce count: 8 minGroupSize: 2 @@ -222,7 +222,7 @@ blacklistTags: - CP14DemiplaneCold layers: - - !type:OreDunGen + - !type:CP14OreDunGen entity: CP14MobWatcherMagma count: 8 minGroupSize: 2 diff --git a/Resources/Prototypes/_CP14/Procedural/Demiplane/Modifiers/Fun/lol.yml b/Resources/Prototypes/_CP14/Procedural/Demiplane/Modifiers/Fun/lol.yml index 70d1ca53f2..c4f80a28fa 100644 --- a/Resources/Prototypes/_CP14/Procedural/Demiplane/Modifiers/Fun/lol.yml +++ b/Resources/Prototypes/_CP14/Procedural/Demiplane/Modifiers/Fun/lol.yml @@ -11,7 +11,7 @@ - CP14DemiplaneHerbals - CP14DemiplaneOpenSky layers: - - !type:OreDunGen + - !type:CP14OreDunGen tileMask: - CP14FloorGrass - CP14FloorGrassLight @@ -34,7 +34,7 @@ - CP14DemiplaneHerbals - CP14DemiplaneOpenSky layers: - - !type:OreDunGen + - !type:CP14OreDunGen tileMask: - CP14FloorGrass - CP14FloorGrassLight @@ -56,12 +56,12 @@ requiredTags: - CP14DemiplaneOpenSky layers: - - !type:OreDunGen + - !type:CP14OreDunGen entity: CP14StatueStoneHeadHigh count: 1 minGroupSize: 1 maxGroupSize: 1 - - !type:OreDunGen + - !type:CP14OreDunGen entity: CP14StatueStoneHeadLow count: 1 minGroupSize: 1 diff --git a/Resources/Prototypes/_CP14/Procedural/Demiplane/Modifiers/GhostRoleDanger/misc.yml b/Resources/Prototypes/_CP14/Procedural/Demiplane/Modifiers/GhostRoleDanger/misc.yml index b3ae56d7f6..72b806e317 100644 --- a/Resources/Prototypes/_CP14/Procedural/Demiplane/Modifiers/GhostRoleDanger/misc.yml +++ b/Resources/Prototypes/_CP14/Procedural/Demiplane/Modifiers/GhostRoleDanger/misc.yml @@ -9,7 +9,7 @@ categories: GhostRoleDanger: 1 layers: - - !type:OreDunGen + - !type:CP14OreDunGen entity: CP14SpawnPointGhostDemiplaneSkeletonT1 count: 1 minGroupSize: 1 @@ -25,7 +25,7 @@ categories: GhostRoleDanger: 1 layers: - - !type:OreDunGen + - !type:CP14OreDunGen entity: CP14SpawnPointGhostDemiplaneSkeletonT2 count: 1 minGroupSize: 2 @@ -41,7 +41,7 @@ categories: GhostRoleDanger: 1 layers: - - !type:OreDunGen + - !type:CP14OreDunGen entity: SpawnPointGhostDemiplaneLurker count: 1 minGroupSize: 1 diff --git a/Resources/Prototypes/_CP14/Procedural/Demiplane/Modifiers/Ore/ores.yml b/Resources/Prototypes/_CP14/Procedural/Demiplane/Modifiers/Ore/ores.yml index 21c0d12464..27cc1a0fd6 100644 --- a/Resources/Prototypes/_CP14/Procedural/Demiplane/Modifiers/Ore/ores.yml +++ b/Resources/Prototypes/_CP14/Procedural/Demiplane/Modifiers/Ore/ores.yml @@ -13,7 +13,7 @@ - CP14DemiplaneOres - CP14DemiplaneOpenSky layers: - - !type:OreDunGen + - !type:CP14OreDunGen entityMask: - CP14WallStone entity: CP14WallStoneIronOre @@ -34,7 +34,7 @@ - CP14DemiplaneOres - CP14DemiplaneUnderground layers: - - !type:OreDunGen + - !type:CP14OreDunGen entityMask: - CP14WallStone entity: CP14WallStoneIronOre @@ -55,7 +55,7 @@ - CP14DemiplaneOres - CP14DemiplaneOpenSky layers: - - !type:OreDunGen + - !type:CP14OreDunGen entityMask: - CP14WallStone entity: CP14WallStoneCopperOre @@ -76,7 +76,7 @@ - CP14DemiplaneOres - CP14DemiplaneUnderground layers: - - !type:OreDunGen + - !type:CP14OreDunGen entityMask: - CP14WallStone entity: CP14WallStoneCopperOre @@ -99,7 +99,7 @@ - CP14DemiplaneOres - CP14DemiplaneOpenSky layers: - - !type:OreDunGen + - !type:CP14OreDunGen entityMask: - CP14WallStone entity: CP14WallStoneGoldOre @@ -120,7 +120,7 @@ - CP14DemiplaneOres - CP14DemiplaneUnderground layers: - - !type:OreDunGen + - !type:CP14OreDunGen entityMask: - CP14WallStone entity: CP14WallStoneGoldOre @@ -141,7 +141,7 @@ - CP14DemiplaneOres - CP14DemiplaneOpenSky layers: - - !type:OreDunGen + - !type:CP14OreDunGen entityMask: - CP14WallStone entity: CP14WallStoneMithrilOre @@ -162,7 +162,7 @@ - CP14DemiplaneOres - CP14DemiplaneUnderground layers: - - !type:OreDunGen + - !type:CP14OreDunGen entityMask: - CP14WallStone entity: CP14WallStoneMithrilOre diff --git a/Resources/Prototypes/_CP14/Procedural/Demiplane/Modifiers/Reward/crystals.yml b/Resources/Prototypes/_CP14/Procedural/Demiplane/Modifiers/Reward/crystals.yml index c36cdaee0c..b4ef5f0c30 100644 --- a/Resources/Prototypes/_CP14/Procedural/Demiplane/Modifiers/Reward/crystals.yml +++ b/Resources/Prototypes/_CP14/Procedural/Demiplane/Modifiers/Reward/crystals.yml @@ -6,7 +6,7 @@ categories: Reward: 0.15 layers: - - !type:OreDunGen + - !type:CP14OreDunGen tileMask: - CP14FloorBase - CP14FloorIce diff --git a/Resources/Prototypes/_CP14/Procedural/Demiplane/Modifiers/Reward/herbals.yml b/Resources/Prototypes/_CP14/Procedural/Demiplane/Modifiers/Reward/herbals.yml index 0d98423bc4..be9d40c31f 100644 --- a/Resources/Prototypes/_CP14/Procedural/Demiplane/Modifiers/Reward/herbals.yml +++ b/Resources/Prototypes/_CP14/Procedural/Demiplane/Modifiers/Reward/herbals.yml @@ -12,7 +12,7 @@ - CP14DemiplaneHerbals - CP14DemiplaneOpenSky layers: - - !type:OreDunGen + - !type:CP14OreDunGen tileMask: - CP14FloorGrass - CP14FloorGrassLight @@ -33,7 +33,7 @@ requiredTags: - CP14DemiplaneHerbals layers: - - !type:OreDunGen + - !type:CP14OreDunGen tileMask: - CP14FloorBase - CP14FloorGrass @@ -55,7 +55,7 @@ requiredTags: - CP14DemiplaneHerbals layers: - - !type:OreDunGen + - !type:CP14OreDunGen tileMask: - CP14FloorGrass - CP14FloorGrassLight @@ -76,7 +76,7 @@ requiredTags: - CP14DemiplaneHerbals layers: - - !type:OreDunGen + - !type:CP14OreDunGen tileMask: - CP14FloorGrass - CP14FloorGrassLight @@ -98,7 +98,7 @@ - CP14DemiplaneHerbals - CP14DemiplaneOpenSky layers: - - !type:OreDunGen + - !type:CP14OreDunGen tileMask: - CP14FloorGrass - CP14FloorGrassLight @@ -120,7 +120,7 @@ - CP14DemiplaneHerbals - CP14DemiplaneWater layers: - - !type:OreDunGen + - !type:CP14OreDunGen entityMask: - CP14FloorWater - CP14FloorWaterLilies @@ -142,7 +142,7 @@ requiredTags: - CP14DemiplaneUnderground layers: - - !type:OreDunGen + - !type:CP14OreDunGen tileMask: - CP14FloorGrass - CP14FloorGrassLight diff --git a/Resources/Prototypes/_CP14/Procedural/Demiplane/Modifiers/Reward/misc.yml b/Resources/Prototypes/_CP14/Procedural/Demiplane/Modifiers/Reward/misc.yml index 93d254a823..d0d971ffb4 100644 --- a/Resources/Prototypes/_CP14/Procedural/Demiplane/Modifiers/Reward/misc.yml +++ b/Resources/Prototypes/_CP14/Procedural/Demiplane/Modifiers/Reward/misc.yml @@ -9,7 +9,7 @@ categories: Reward: 0.15 layers: - - !type:OreDunGen + - !type:CP14OreDunGen entity: CP14SpawnerDemiplaneLootT1 count: 20 minGroupSize: 2 @@ -27,7 +27,7 @@ requiredTags: - CP14DemiplanePeacefulAnimals layers: - - !type:OreDunGen + - !type:CP14OreDunGen entity: CP14MobRabbit count: 3 minGroupSize: 2 @@ -45,7 +45,7 @@ requiredTags: - CP14DemiplanePeacefulAnimals layers: - - !type:OreDunGen + - !type:CP14OreDunGen entity: CP14MobBoar count: 3 minGroupSize: 2 @@ -62,7 +62,7 @@ requiredTags: - CP14DemiplaneAnimalsSwamp layers: - - !type:OreDunGen + - !type:CP14OreDunGen tileMask: - CP14FloorGrass - CP14FloorGrassLight @@ -84,7 +84,7 @@ requiredTags: - CP14DemiplanePeacefulAnimals layers: - - !type:OreDunGen + - !type:CP14OreDunGen entity: CP14MobSheep count: 1 minGroupSize: 4 @@ -100,7 +100,7 @@ Reward: 0.2 generationProb: 0.8 layers: - - !type:OreDunGen + - !type:CP14OreDunGen entity: CP14DemiplaneRuinsRoomSpawner count: 8 minGroupSize: 1 @@ -117,7 +117,7 @@ categories: Reward: 0.15 layers: - - !type:OreDunGen + - !type:CP14OreDunGen entity: CP14SpawnerDemiplaneLootT2 count: 20 minGroupSize: 2 diff --git a/Resources/Prototypes/_CP14/Procedural/Demiplane/Modifiers/Reward/rooms.yml b/Resources/Prototypes/_CP14/Procedural/Demiplane/Modifiers/Reward/rooms.yml index 690f774b8e..cebe60a181 100644 --- a/Resources/Prototypes/_CP14/Procedural/Demiplane/Modifiers/Reward/rooms.yml +++ b/Resources/Prototypes/_CP14/Procedural/Demiplane/Modifiers/Reward/rooms.yml @@ -7,7 +7,7 @@ categories: Reward: 0.15 layers: - - !type:OreDunGen + - !type:CP14OreDunGen entity: CP14DemiplaneArtifactRoomSpawner count: 1 minGroupSize: 1