Demiplan modifiers (#526)

* simple modifiers

* modifier tag filtering

* Update CP14DemiplanSystem.Generation.cs

* Update rocks.yml

* move loot to modifier

* move enemies to modificators

* fix filtering

* modifier rariry

* reward and difficulty limits

* rebalance and optimize calculation

* Update test.yml

* wizden PR copy

* move all alchemy reagents to modifiers
This commit is contained in:
Ed
2024-11-01 18:08:57 +03:00
committed by GitHub
parent 7124eb5335
commit 3b520ac69c
19 changed files with 564 additions and 235 deletions

View File

@@ -1,4 +1,5 @@
using System.Threading.Tasks;
using Content.Shared.Maps;
using Content.Shared.Procedural;
using Content.Shared.Procedural.Components;
using Content.Shared.Procedural.DungeonLayers;
@@ -20,44 +21,50 @@ public sealed partial class DungeonJob
{
// Doesn't use dungeon data because layers and we don't need top-down support at the moment.
var emptyTiles = false;
var replaceEntities = new Dictionary<Vector2i, EntityUid>();
var availableTiles = new List<Vector2i>();
var tiles = _maps.GetAllTilesEnumerator(_gridUid, _grid);
foreach (var node in dungeon.AllTiles)
while (tiles.MoveNext(out var tileRef))
{
// Empty tile, skip if relevant.
if (!emptyTiles && (!_maps.TryGetTile(_grid, node, out var tile) || tile.IsEmpty))
continue;
var tile = tileRef.Value.GridIndices;
// Check if it's a valid spawn, if so then use it.
var enumerator = _maps.GetAnchoredEntitiesEnumerator(_gridUid, _grid, node);
var found = false;
// We use existing entities as a mark to spawn in place
// OR
// We check for any existing entities to see if we can spawn there.
while (enumerator.MoveNext(out var uid))
//Tile mask filtering
if (gen.TileMask is not null)
{
// We can't replace so just stop here.
if (gen.Replacement == null)
break;
if (!gen.TileMask.Contains(((ContentTileDefinition) _tileDefManager[tileRef.Value.Tile.TypeId]).ID))
continue;
var prototype = _entManager.GetComponent<MetaDataComponent>(uid.Value).EntityPrototype;
if (prototype?.ID == gen.Replacement)
{
replaceEntities[node] = uid.Value;
found = true;
break;
}
//If entity mask null - we ignore the tiles that have anything on them.
if (gen.EntityMask is null && !_anchorable.TileFree(_grid, tile, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask))
continue;
}
if (!found)
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<MetaDataComponent>(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;
}
// Add it to valid nodes.
availableTiles.Add(node);
availableTiles.Add(tile);
await SuspendDungeon();
@@ -139,7 +146,7 @@ public sealed partial class DungeonJob
if (groupSize > 0)
{
_sawmill.Warning($"Found remaining group size for ore veins of {gen.Replacement ?? "null"}!");
_sawmill.Warning($"Found remaining group size for ore veins of {gen.Entity.Id ?? "null"}!");
}
}
}

View File

@@ -1,3 +1,4 @@
using System.Linq;
using System.Threading;
using Content.Server._CP14.Demiplane.Components;
using Content.Server._CP14.Demiplane.Jobs;
@@ -42,7 +43,7 @@ public sealed partial class CP14DemiplaneSystem
/// <summary>
/// Generates a new random demiplane based on the specified parameters
/// </summary>
public void SpawnRandomDemiplane(ProtoId<CP14DemiplaneLocationPrototype> location, out Entity<CP14DemiplaneComponent> demiplan, out MapId mapId)
public void SpawnRandomDemiplane(ProtoId<CP14DemiplaneLocationPrototype> location, List<ProtoId<CP14DemiplaneModifierPrototype>> modifiers, out Entity<CP14DemiplaneComponent> demiplan, out MapId mapId)
{
var mapUid = _mapSystem.CreateMap(out mapId, runMapInit: false);
var demiComp = EntityManager.EnsureComponent<CP14DemiplaneComponent>(mapUid);
@@ -61,6 +62,7 @@ public sealed partial class CP14DemiplaneSystem
mapUid,
mapId,
location,
modifiers,
_random.Next(-10000, 10000),
cancelToken.Token);
@@ -70,7 +72,7 @@ public sealed partial class CP14DemiplaneSystem
private void GeneratorUsedInHand(Entity<CP14DemiplaneGeneratorDataComponent> generator, ref UseInHandEvent args)
{
if (generator.Comp.LocationConfig is null)
if (generator.Comp.Location is null)
return;
//We cant open demiplan in another demiplan
@@ -80,7 +82,7 @@ public sealed partial class CP14DemiplaneSystem
return;
}
SpawnRandomDemiplane(generator.Comp.LocationConfig.Value, out var demiplane, out var mapId);
SpawnRandomDemiplane(generator.Comp.Location.Value, generator.Comp.Modifiers, out var demiplane, out var mapId);
//Admin log needed
//TEST
@@ -116,12 +118,93 @@ public sealed partial class CP14DemiplaneSystem
}
var selectedConfig = _random.Pick(suitableConfigs);
generator.Comp.LocationConfig = selectedConfig;
generator.Comp.Location = selectedConfig;
//Modifier generation
Dictionary<CP14DemiplaneModifierPrototype, float> suitableModifiersWeights = new();
foreach (var modifier in _proto.EnumeratePrototypes<CP14DemiplaneModifierPrototype>())
{
var passed = true;
//Tag blacklist filter
foreach (var configTag in selectedConfig.Tags)
{
if (modifier.BlacklistTags.Count != 0 && modifier.BlacklistTags.Contains(configTag))
{
passed = false;
break;
}
}
//Tag required filter
foreach (var reqTag in modifier.RequiredTags)
{
if (!selectedConfig.Tags.Contains(reqTag))
{
passed = false;
break;
}
}
if (passed)
{
suitableModifiersWeights.Add(modifier, modifier.GenerationWeight);
}
}
var difficulty = 0f;
var reward = 0f;
while (generator.Comp.Modifiers.Count < generator.Comp.MaxModifiers && suitableModifiersWeights.Count > 0)
{
var selectedModifier = ModifierPick(suitableModifiersWeights, _random);
if (difficulty + selectedModifier.Difficulty > generator.Comp.DifficultyLimit)
{
suitableModifiersWeights.Remove(selectedModifier);
continue;
}
if (reward + selectedModifier.Reward > generator.Comp.RewardLimit)
{
suitableModifiersWeights.Remove(selectedModifier);
continue;
}
generator.Comp.Modifiers.Add(selectedModifier);
reward += selectedModifier.Reward;
difficulty += selectedModifier.Difficulty;
if (selectedModifier.Unique)
suitableModifiersWeights.Remove(selectedModifier);
}
//Scenario generation
//ETC generation
}
/// <summary>
/// Optimization moment: avoid re-indexing for weight selection
/// </summary>
private static CP14DemiplaneModifierPrototype ModifierPick(Dictionary<CP14DemiplaneModifierPrototype, float> weights, IRobustRandom random)
{
var picks = weights;
var sum = picks.Values.Sum();
var accumulated = 0f;
var rand = random.NextFloat() * sum;
foreach (var (key, weight) in picks)
{
accumulated += weight;
if (accumulated >= rand)
{
return key;
}
}
// Shouldn't happen
throw new InvalidOperationException($"Invalid weighted pick in CP14DemiplanSystem.Generation!");
}
}

View File

@@ -11,7 +11,17 @@ namespace Content.Server._CP14.Demiplane.Components;
public sealed partial class CP14DemiplaneGeneratorDataComponent : Component
{
[DataField]
public ProtoId<CP14DemiplaneLocationPrototype>? LocationConfig;
public ProtoId<CP14DemiplaneLocationPrototype>? Location;
//Generation settings
[DataField]
public List<ProtoId<CP14DemiplaneModifierPrototype>> Modifiers = new();
[DataField]
public float DifficultyLimit = 1;
[DataField]
public float RewardLimit = 1;
[DataField]
public int MaxModifiers = 6;
}

View File

@@ -24,6 +24,7 @@ public sealed class CP14SpawnRandomDemiplaneJob : Job<bool>
private readonly SharedMapSystem _map;
private readonly ProtoId<CP14DemiplaneLocationPrototype> _config;
private readonly List<ProtoId<CP14DemiplaneModifierPrototype>> _modifiers;
private readonly int _seed;
public readonly EntityUid DemiplaneMapUid;
@@ -43,6 +44,7 @@ public sealed class CP14SpawnRandomDemiplaneJob : Job<bool>
EntityUid demiplaneMapUid,
MapId demiplaneMapId,
ProtoId<CP14DemiplaneLocationPrototype> config,
List<ProtoId<CP14DemiplaneModifierPrototype>> modifiers,
int seed,
CancellationToken cancellation = default) : base(maxTime, cancellation)
{
@@ -55,6 +57,7 @@ public sealed class CP14SpawnRandomDemiplaneJob : Job<bool>
DemiplaneMapUid = demiplaneMapUid;
_demiplaneMapId = demiplaneMapId;
_config = config;
_modifiers = modifiers;
_seed = seed;
_sawmill = logManager.GetSawmill("cp14_expedition_job");
@@ -70,18 +73,33 @@ public sealed class CP14SpawnRandomDemiplaneJob : Job<bool>
_metaData.SetEntityName(DemiplaneMapUid, "TODO: MAP Expedition name generation");
_metaData.SetEntityName(grid, "TODO: GRID Expedition name generation");
//Spawn island config
//Setup demiplane config
var expeditionConfig = _prototypeManager.Index(_config);
var locationConfig = _prototypeManager.Index(expeditionConfig.LocationConfig);
_dungeon.GenerateDungeon(locationConfig,
var indexedLocation = _prototypeManager.Index(expeditionConfig.LocationConfig);
//Add map components
_entManager.AddComponents(DemiplaneMapUid, expeditionConfig.Components);
//Apply modifiers
foreach (var modifier in _modifiers)
{
if (!_prototypeManager.TryIndex(modifier, out var indexedModifier))
continue;
indexedLocation.Layers.AddRange(indexedModifier.Layers);
_entManager.AddComponents(DemiplaneMapUid, indexedModifier.Components);
}
_mapManager.DoMapInitialize(_demiplaneMapId);
_mapManager.SetMapPaused(_demiplaneMapId, false);
//Spawn modified config
_dungeon.GenerateDungeon(indexedLocation,
grid,
grid,
Vector2i.Zero,
_seed); //Not async, because dont work with biomespawner boilerplate
//Add map components
_entManager.AddComponents(DemiplaneMapUid, expeditionConfig.Components);
//Setup gravity
var gravity = _entManager.EnsureComponent<GravityComponent>(DemiplaneMapUid);
gravity.Enabled = true;
@@ -94,11 +112,6 @@ public sealed class CP14SpawnRandomDemiplaneJob : Job<bool>
var mixture = new GasMixture(moles, Atmospherics.T20C);
_entManager.System<AtmosphereSystem>().SetMapAtmosphere(DemiplaneMapUid, false, mixture);
_mapManager.DoMapInitialize(_demiplaneMapId);
_mapManager.SetMapPaused(_demiplaneMapId, false);
//Dungeon
return true;
}
}

View File

@@ -1,3 +1,4 @@
using Content.Shared.Maps;
using Robust.Shared.Prototypes;
namespace Content.Shared.Procedural.DungeonLayers;
@@ -12,10 +13,16 @@ namespace Content.Shared.Procedural.DungeonLayers;
public partial class OreDunGen : IDunGenLayer
{
/// <summary>
/// If the vein generation should occur on top of existing entities what are we replacing.
/// This vein can only be generated by replacing the specified entities.
/// </summary>
[DataField]
public EntProtoId? Replacement;
public HashSet<EntProtoId>? EntityMask;
/// <summary>
/// This vein can only be generated on the specified tiles
/// </summary>
[DataField]
public HashSet<ProtoId<ContentTileDefinition>>? TileMask;
/// <summary>
/// Entity to spawn.

View File

@@ -1,4 +1,5 @@
using Content.Shared.Procedural;
using Content.Shared.Tag;
using Robust.Shared.Prototypes;
namespace Content.Shared._CP14.Demiplane.Prototypes;
@@ -14,12 +15,15 @@ public sealed partial class CP14DemiplaneLocationPrototype : IPrototype
[DataField(required: true)]
public ProtoId<DungeonConfigPrototype> LocationConfig;
/// <summary>
/// Components that will be automatically added to the demiplane when it is generated
/// </summary>
[DataField]
public ComponentRegistry Components = new();
//Player faced description
//Tier restriction
//Some abstract restriction?
/// <summary>
/// Tags allow modifiers to filter which ones can apply to the current location and which ones cannot.
/// </summary>
[DataField]
public List<ProtoId<TagPrototype>> Tags = new();
}

View File

@@ -0,0 +1,62 @@
using Content.Shared.Procedural;
using Content.Shared.Tag;
using Robust.Shared.Prototypes;
namespace Content.Shared._CP14.Demiplane.Prototypes;
/// <summary>
/// Demiplane modifier prototype. The answer to the question “Which” in terms of the combinatorics of demiplane generation is
/// </summary>
[Prototype("cp14DemiplaneModifier")]
public sealed partial class CP14DemiplaneModifierPrototype : IPrototype
{
[IdDataField] public string ID { get; } = default!;
/// <summary>
/// Abstract danger of this modifier. The demiplane has a threat limit, which it gains from modifiers until it reaches the limit.
/// </summary>
[DataField]
public float Difficulty = 0;
/// <summary>
/// The abstract value of this modifier. The demiplane has a limit of rewards it gains from modifiers until it reaches the limit.
/// </summary>
[DataField]
public float Reward = 0;
/// <summary>
/// How often can this modifier be generated? Determined by weight from all modifiers available for the location
/// </summary>
[DataField]
public float GenerationWeight = 1;
/// <summary>
/// Can this modifier be generated multiple times within a single demiplane?
/// </summary>
[DataField]
public bool Unique = true;
/// <summary>
/// Generation layers that will be added to the location generation after the main layers.
/// </summary>
[DataField]
public List<IDunGenLayer> Layers = new();
/// <summary>
/// Components that will be added to the map
/// </summary>
[DataField]
public ComponentRegistry Components = new();
/// <summary>
/// Modifier cannot be applied to locations with the following tags. Leave empty for disable
/// </summary>
[DataField]
public List<ProtoId<TagPrototype>> BlacklistTags = new();
/// <summary>
/// Modifier can only be applied to locations that have all of the following tags. Leave empty for disable
/// </summary>
[DataField]
public List<ProtoId<TagPrototype>> RequiredTags = new();
}

View File

@@ -14,7 +14,8 @@
- type: oreDunGen
id: OreIron
replacement: AsteroidRock
entityMask:
- AsteroidRock
entity: AsteroidRockTin
count: 5
minGroupSize: 5
@@ -22,7 +23,8 @@
- type: oreDunGen
id: OreQuartz
replacement: AsteroidRock
entityMask:
- AsteroidRock
entity: AsteroidRockQuartz
count: 5
minGroupSize: 5
@@ -30,7 +32,8 @@
- type: oreDunGen
id: OreCoal
replacement: AsteroidRock
entityMask:
- AsteroidRock
entity: AsteroidRockCoal
count: 3
minGroupSize: 5
@@ -38,7 +41,8 @@
- type: oreDunGen
id: OreSalt
replacement: AsteroidRock
entityMask:
- AsteroidRock
entity: AsteroidRockSalt
count: 3
minGroupSize: 5
@@ -46,7 +50,8 @@
- type: oreDunGen
id: OreGold
replacement: AsteroidRock
entityMask:
- AsteroidRock
entity: AsteroidRockGold
count: 4
minGroupSize: 5
@@ -54,7 +59,8 @@
- type: oreDunGen
id: OreSilver
replacement: AsteroidRock
entityMask:
- AsteroidRock
entity: AsteroidRockSilver
count: 4
minGroupSize: 5
@@ -62,7 +68,8 @@
- type: oreDunGen
id: OrePlasma
replacement: AsteroidRock
entityMask:
- AsteroidRock
entity: AsteroidRockPlasma
count: 4
minGroupSize: 5
@@ -70,7 +77,8 @@
- type: oreDunGen
id: OreUranium
replacement: AsteroidRock
entityMask:
- AsteroidRock
entity: AsteroidRockUranium
count: 4
minGroupSize: 5
@@ -78,7 +86,8 @@
- type: oreDunGen
id: OreBananium
replacement: AsteroidRock
entityMask:
- AsteroidRock
entity: AsteroidRockBananium
count: 6
minGroupSize: 3
@@ -86,10 +95,10 @@
- type: oreDunGen
id: OreArtifactFragment
replacement: AsteroidRock
entityMask:
- AsteroidRock
entity: AsteroidRockArtifactFragment
count: 5
minGroupSize: 1
maxGroupSize: 2

View File

@@ -28,65 +28,111 @@
proto: VGRoidFill
# Ores
- !type:OreDunGen
replacement: IronRock
entityMask:
- IronRock
entity: IronRockIron
count: 50
minGroupSize: 10
maxGroupSize: 15
- !type:OreDunGen
replacement: IronRock
entityMask:
- IronRock
entity: IronRockCoal
count: 50
minGroupSize: 8
maxGroupSize: 12
- !type:OreDunGen
replacement: IronRock
entityMask:
- IronRock
entity: IronRockQuartz
count: 50
minGroupSize: 10
maxGroupSize: 15
- !type:OreDunGen
replacement: IronRock
entityMask:
- IronRock
entity: IronRockSalt
count: 50
minGroupSize: 8
maxGroupSize: 12
- !type:OreDunGen
replacement: IronRock
entityMask:
- IronRock
entity: IronRockGold
count: 40
minGroupSize: 8
maxGroupSize: 12
- !type:OreDunGen
replacement: IronRock
entityMask:
- IronRock
entity: IronRockSilver
count: 40
minGroupSize: 8
maxGroupSize: 12
- !type:OreDunGen
replacement: IronRock
entityMask:
- IronRock
entity: IronRockPlasma
count: 35
minGroupSize: 4
maxGroupSize: 8
- !type:OreDunGen
replacement: IronRock
entityMask:
- IronRock
entity: IronRockUranium
count: 35
minGroupSize: 4
maxGroupSize: 8
- !type:OreDunGen
replacement: IronRock
entityMask:
- IronRock
entity: IronRockArtifactFragment
count: 25
minGroupSize: 1
maxGroupSize: 3
- !type:OreDunGen
replacement: IronRock
entityMask:
- IronRock
entity: IronRockDiamond
count: 15
minGroupSize: 1
maxGroupSize: 2
# Decoration
- !type:OreDunGen
tileMask:
- FloorAsteroidSand
entity: CrystalGreen
count: 10
minGroupSize: 3
maxGroupSize: 5
- !type:OreDunGen
tileMask:
- FloorAsteroidSand
entity: CrystalPink
count: 10
minGroupSize: 3
maxGroupSize: 5
- !type:OreDunGen
tileMask:
- FloorAsteroidSand
entity: CrystalOrange
count: 10
minGroupSize: 3
maxGroupSize: 5
- !type:OreDunGen
tileMask:
- FloorAsteroidSand
entity: CrystalBlue
count: 10
minGroupSize: 3
maxGroupSize: 5
- !type:OreDunGen
tileMask:
- FloorAsteroidSand
entity: CrystalCyan
count: 10
minGroupSize: 3
maxGroupSize: 5
# Configs
- type: dungeonConfig
@@ -225,4 +271,4 @@
layers:
- !type:FillGridDunGen
allowedTiles:
- FloorAsteroidSand
- FloorAsteroidSand

View File

@@ -3,7 +3,6 @@
parent: MobXeno
categories: [ ForkFiltered ]
components:
- type: CP14OutPVSDespawn
- type: NpcFactionMember
factions:
- CP14HostileEveryone
@@ -13,7 +12,6 @@
parent: MobXenoDrone
categories: [ ForkFiltered ]
components:
- type: CP14OutPVSDespawn
- type: NpcFactionMember
factions:
- CP14HostileEveryone
@@ -24,7 +22,6 @@
parent: MobCobraSpace
categories: [ ForkFiltered ]
components:
- type: CP14OutPVSDespawn
- type: NpcFactionMember
factions:
- CP14HostileEveryone
@@ -34,7 +31,6 @@
parent: MobPurpleSnake
categories: [ ForkFiltered ]
components:
- type: CP14OutPVSDespawn
- type: NpcFactionMember
factions:
- CP14HostileEveryone
@@ -44,7 +40,6 @@
parent: MobSmallPurpleSnake
categories: [ ForkFiltered ]
components:
- type: CP14OutPVSDespawn
- type: NpcFactionMember
factions:
- CP14HostileEveryone
@@ -54,7 +49,6 @@
parent: MobWatcherMagmawing
categories: [ ForkFiltered ]
components:
- type: CP14OutPVSDespawn
- type: NpcFactionMember
factions:
- CP14HostileEveryone

View File

@@ -7,6 +7,8 @@
placement:
mode: SnapgridCenter
components:
- type: Transform
anchored: True
- type: Clickable
- type: Sprite
drawdepth: Mobs

View File

@@ -7,7 +7,6 @@
description: The core that connects the real world to the demiplane. Use it to open a temporary passage to the other world.
components:
- type: Sprite
drawdepth: Effects
sprite: /Textures/_CP14/Structures/Dungeon/demiplan_rift_core.rsi
layers:
- state: core
@@ -18,9 +17,9 @@
parent: CP14BaseSubdimensionalKey
components:
- type: CP14DemiplaneGeneratorData
rewardLimit: 1.25
difficultyLimit: 0.75
- type: CP14DemiplaneRift
- type: Sprite
state: key1
- type: entity
id: CP14DemiplanRiftCore

View File

@@ -1,6 +1,9 @@
- type: cp14DemiplaneLocation
id: T1Caves
locationConfig: CP14ExpeditionCaves
tags:
- CP14DemiplanOre
- CP14DemiplanUnderground
components:
- type: CP14WeatherController
entries:
@@ -25,32 +28,6 @@
proto: CP14ExpeditionCavesFillAir
- !type:PrototypeDunGen
proto: CP14ExpeditionCavesFillCave
# Ore and resources
- !type:OreDunGen
replacement: CP14WallStone
entity: CP14WallStoneGoldOre
count: 10
minGroupSize: 10
maxGroupSize: 15
- !type:OreDunGen
replacement: CP14WallStone
entity: CP14WallStoneIronOre
count: 10
minGroupSize: 10
maxGroupSize: 15
- !type:OreDunGen
replacement: CP14WallStone
entity: CP14WallStoneCopperOre
count: 10
minGroupSize: 10
maxGroupSize: 15
# Mobs
- !type:MobsDunGen
minCount: 5
maxCount: 10
groups:
- id: CP14SpawnMobUndeadZombie
amount: 1
# Enter and Exit
- !type:MobsDunGen
minCount: 1
@@ -64,12 +41,6 @@
groups:
- id: CP14DemiplanePassway
amount: 1
# Loot
- !type:EntityTableDunGen
minCount: 10
maxCount: 25
table: !type:NestedSelector
tableId: CP14TableExpeditionLootCommon
- type: dungeonConfig
id: CP14ExpeditionCavesFloorMaskAir

View File

@@ -1,6 +1,10 @@
- type: cp14DemiplaneLocation
id: T1GrasslandIsland
locationConfig: CP14ExpeditionGrasslandIsland
tags:
- CP14DemiplanOre
- CP14DemiplanOpenSky
- CP14DemiplanGrass
components:
- type: MapLight
ambientLightColor: "#BFEEFFFF"
@@ -57,32 +61,6 @@
proto: CP14ExpeditionGrasslandIslandFillGrassland
- !type:PrototypeDunGen
proto: CP14ExpeditionGrasslandIslandFillCave
# Ore and resources
- !type:OreDunGen
replacement: CP14WallStone
entity: CP14WallStoneGoldOre
count: 10
minGroupSize: 10
maxGroupSize: 15
- !type:OreDunGen
replacement: CP14WallStone
entity: CP14WallStoneIronOre
count: 10
minGroupSize: 10
maxGroupSize: 15
- !type:OreDunGen
replacement: CP14WallStone
entity: CP14WallStoneCopperOre
count: 10
minGroupSize: 10
maxGroupSize: 15
# Mobs
- !type:MobsDunGen
minCount: 3
maxCount: 6
groups:
- id: CP14SpawnMobDinoYumkaraptor
amount: 1
# Enter and Exit
- !type:MobsDunGen
minCount: 1
@@ -96,12 +74,6 @@
groups:
- id: CP14DemiplanePassway
amount: 1
# Loot
- !type:EntityTableDunGen
minCount: 5
maxCount: 20
table: !type:NestedSelector
tableId: CP14TableExpeditionLootCommon
- type: dungeonConfig
id: CP14ExpeditionGrasslandIslandFloorMaskStone

View File

@@ -0,0 +1,227 @@
- type: cp14DemiplaneModifier
id: GoldOre
unique: false
reward: 0.5
requiredTags:
- CP14DemiplanOre
layers:
- !type:OreDunGen
entityMask:
- CP14WallStone
entity: CP14WallStoneGoldOre
count: 10
minGroupSize: 10
maxGroupSize: 15
- type: cp14DemiplaneModifier
id: IronOre
unique: false
reward: 0.4
requiredTags:
- CP14DemiplanOre
layers:
- !type:OreDunGen
entityMask:
- CP14WallStone
entity: CP14WallStoneIronOre
count: 10
minGroupSize: 10
maxGroupSize: 15
- type: cp14DemiplaneModifier
id: QuartzCrystal
reward: 0.2
requiredTags:
- CP14DemiplanOre
layers:
- !type:OreDunGen
tileMask:
- CP14FloorBase
entity: CP14QuartzCrystal
count: 10
minGroupSize: 3
maxGroupSize: 5
- type: cp14DemiplaneModifier
id: Dayflin
reward: 0.2
requiredTags:
- CP14DemiplanGrass
- CP14DemiplanOpenSky
layers:
- !type:OreDunGen
tileMask:
- CP14FloorGrass
- CP14FloorGrassLight
- CP14FloorGrassTall
entity: CP14GatherableDayflin
count: 10
minGroupSize: 3
maxGroupSize: 5
- type: cp14DemiplaneModifier
id: BlueAmanita
reward: 0.2
requiredTags:
- CP14DemiplanGrass
layers:
- !type:OreDunGen
tileMask:
- CP14FloorGrass
- CP14FloorGrassLight
- CP14FloorGrassTall
entity: CP14GatherableBlueAmanita
count: 10
minGroupSize: 3
maxGroupSize: 5
- type: cp14DemiplaneModifier
id: BloodFlower
reward: 0.2
requiredTags:
- CP14DemiplanGrass
layers:
- !type:OreDunGen
tileMask:
- CP14FloorGrass
- CP14FloorGrassLight
- CP14FloorGrassTall
entity: CP14GatherableBloodFlower
count: 10
minGroupSize: 3
maxGroupSize: 5
- type: cp14DemiplaneModifier
id: WildSage
reward: 0.2
requiredTags:
- CP14DemiplanGrass
- CP14DemiplanOpenSky
layers:
- !type:OreDunGen
tileMask:
- CP14FloorGrass
- CP14FloorGrassLight
- CP14FloorGrassTall
entity: CP14GatherableWildSage
count: 10
minGroupSize: 3
maxGroupSize: 5
- type: cp14DemiplaneModifier
id: LumiShroom
reward: 0.2
requiredTags:
- CP14DemiplanUnderground
layers:
- !type:OreDunGen
tileMask:
- CP14FloorGrass
- CP14FloorGrassLight
- CP14FloorGrassTall
- CP14FloorBase
entity: CP14GatherableLumiMushroom
count: 10
minGroupSize: 3
maxGroupSize: 5
- type: cp14DemiplaneModifier
id: CopperOre
unique: false
reward: 0.3
requiredTags:
- CP14DemiplanOre
layers:
- !type:OreDunGen
entityMask:
- CP14WallStone
entity: CP14WallStoneCopperOre
count: 10
minGroupSize: 10
maxGroupSize: 15
- type: cp14DemiplaneModifier
id: Explosive
difficulty: 0.4
generationWeight: 0.25
layers:
- !type:MobsDunGen
minCount: 25
maxCount: 50
groups:
- id: LandMineExplosive
amount: 1
- type: cp14DemiplaneModifier
id: CommonLoot
reward: 0.25
generationWeight: 2
layers:
- !type:EntityTableDunGen
minCount: 15
maxCount: 30
table: !type:NestedSelector
tableId: CP14TableExpeditionLootCommon
- type: cp14DemiplaneModifier
id: EnemyXeno
difficulty: 0.5
requiredTags:
- CP14DemiplanUnderground
layers:
- !type:EntityTableDunGen
minCount: 5
maxCount: 10
table: !type:GroupSelector
children:
- id: CP14MobXenoDrone
- id: CP14MobXeno
- type: cp14DemiplaneModifier
id: EnemyZombie
difficulty: 0.4
layers:
- !type:EntityTableDunGen
minCount: 5
maxCount: 10
table: !type:GroupSelector
children:
- id: CP14SpawnMobUndeadZombie
- type: cp14DemiplaneModifier
id: EnemyDyno
difficulty: 0.5
requiredTags:
- CP14DemiplanOpenSky
layers:
- !type:MobsDunGen
minCount: 3
maxCount: 6
groups:
- id: CP14SpawnMobDinoYumkaraptor
amount: 1
- type: cp14DemiplaneModifier
id: EnemySnakes
difficulty: 0.7
layers:
- !type:EntityTableDunGen
minCount: 5
maxCount: 10
table: !type:GroupSelector
children:
- id: CP14MobPurpleSnake
- id: CP14MobSmallPurpleSnake
- id: CP14MobSpaceCobra
- type: cp14DemiplaneModifier
id: EnemyMagmawind
difficulty: 0.3
generationWeight: 0.4
layers:
- !type:MobsDunGen
minCount: 3
maxCount: 5
groups:
- id: CP14MobWatcherMagmawing
amount: 1

View File

@@ -0,0 +1,11 @@
- type: Tag
id: CP14DemiplanOre
- type: Tag
id: CP14DemiplanGrass
- type: Tag
id: CP14DemiplanOpenSky
- type: Tag
id: CP14DemiplanUnderground

View File

@@ -22,24 +22,6 @@
- CP14FloorBase
entities:
- CP14RockSmall
- CP14RockSmall
- CP14QuartzCrystal
- !type:BiomeEntityLayer # lumishroom sage
threshold: 0.8
noise:
seed: 8
noiseType: OpenSimplex2
fractalType: Ridged
frequency: 0.045
octaves: 3
lacunarity: 1.8
gain: 0.7
domainWarpType: OpenSimplex2
domainWarpAmp: 120
allowedTiles:
- CP14FloorBase
entities:
- CP14GatherableLumiMushroom
- type: biomeTemplate
id: CP14CavesGeneric

View File

@@ -98,42 +98,6 @@
- CP14GrassBushes7
- CP14GrassBushes8
- CP14GrassBushes9
- !type:BiomeEntityLayer # flowers
threshold: 0.7
noise:
seed: 34
noiseType: OpenSimplex2
fractalType: Ridged
frequency: 0.035
octaves: 3
lacunarity: 1.8
gain: 0.7
domainWarpType: OpenSimplex2
domainWarpAmp: 120
allowedTiles:
- CP14FloorGrass
- CP14FloorGrassLight
- CP14FloorGrassTall
entities:
- CP14GatherableDayflin
- !type:BiomeEntityLayer # BLue amanita
threshold: 0.7
noise:
seed: 67
noiseType: OpenSimplex2
fractalType: Ridged
frequency: 0.038
octaves: 3
lacunarity: 1.8
gain: 0.7
domainWarpType: OpenSimplex2
domainWarpAmp: 120
allowedTiles:
- CP14FloorGrass
- CP14FloorGrassLight
- CP14FloorGrassTall
entities:
- CP14GatherableBlueAmanita
- !type:BiomeEntityLayer # Tall grass!
threshold: 0.3
noise:
@@ -174,40 +138,6 @@
- CP14FloraTreeLarge04
- CP14FloraTreeLarge05
- CP14FloraTreeLarge06
- !type:BiomeEntityLayer # Rare Bloodflower
threshold: 0.7
noise:
seed: 3
noiseType: OpenSimplex2
fractalType: Ridged
frequency: 0.015
octaves: 3
lacunarity: 1.8
gain: 0.7
domainWarpType: OpenSimplex2
domainWarpAmp: 120
allowedTiles:
- CP14FloorGrass
- CP14FloorGrassLight
- CP14FloorGrassTall
entities:
- CP14GatherableBloodFlower
- !type:BiomeEntityLayer # Rare Wild sage
threshold: 0.6
noise:
seed: 8
noiseType: OpenSimplex2
fractalType: Ridged
frequency: 0.015
octaves: 3
lacunarity: 1.8
gain: 0.7
domainWarpType: OpenSimplex2
domainWarpAmp: 120
allowedTiles:
- CP14FloorGrass
entities:
- CP14GatherableWildSage
- !type:BiomeEntityLayer # More Rocks
threshold: 0.7
noise: