* Add Crash to Windlands survival gamemode and map Introduces the CP14CrashToWindlandsRule and its component for a new survival gamemode where a ship crashes into wildlands. Adds the 'nautilus_ship' map, updates English and Russian locale files with new gamemode titles and descriptions, and modifies relevant prototype and map pool files to support the new mode. * fix FTL map * firebombing is real * fix biome dungen all grid overriding * Update PostMapInitTest.cs * Update DungeonJob.CP14Biome.cs * Refactor demiplane generation and crash rules Replaces the old demiplane job system with a new procedural location generation system (CP14LocationGenerationSystem and CP14SpawnProceduralLocationJob). Splits the crash-to-windlands rule into CP14CrashingShipRule (handles explosions) and CP14ExpeditionToWindlandsRule (handles map generation and FTL), with corresponding new components. Updates roundstart game rule prototype and moves/renames several files for clarity and modularity. * Refactor location generation to support optional seed and position Updated the GenerateLocation method to accept an optional seed and position, defaulting to a random seed if none is provided. Adjusted all call sites and the procedural job to support these changes, improving flexibility and consistency in procedural location generation. * procedural integration into game map * Demiplanes deletion * clear demiplane content * remapping procedural + frigid coast deletion * clear demiplane guidebook * dungeons generations * Refactor procedural location configs and add ComossIsland Consolidated and renamed procedural location and dungeonConfig prototypes for demiplane locations, replacing T1-prefixed and legacy IDs with new, consistent names. Updated map YAMLs to reference new location IDs and configs. Added a new ComossIsland location and dungeonConfig. Refactored code to support passing custom dungeon layers and removed unused ExamineProb field from CP14ProceduralLocationPrototype. * Enhance procedural world gen and location configs Improved procedural world generation by adding location generation probability, adjusting level ranges, and refining modifier uniqueness. Updated CP14ProceduralLocationPrototype and CP14ProceduralModifierPrototype, refactored node data generation logic, and made related test and map changes. Added new venicialis_fort station map and updated several procedural location and modifier YAMLs for consistency. * fix * connections room spawners * track finishing global world generation * real connection * Update PostMapInitTest.cs * Update venicialis.yml * Update venicialis.yml * fix raids, decrease city island sizes * Update migration.yml * Update migration.yml * fix shutdowning * Update CP14SpawnProceduralLocationJob.cs
157 lines
5.5 KiB
C#
157 lines
5.5 KiB
C#
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
|
|
{
|
|
/// <summary>
|
|
/// <see cref="OreDunGen"/>
|
|
/// </summary>
|
|
private async Task PostGen(
|
|
CP14OreDunGen gen,
|
|
List<Dungeon> dungeons,
|
|
HashSet<Vector2i> reservedTiles,
|
|
Random random)
|
|
{
|
|
var replaceEntities = new Dictionary<Vector2i, EntityUid>();
|
|
var availableTiles = new List<Vector2i>();
|
|
|
|
foreach (var dun in dungeons)
|
|
{
|
|
foreach (var tile in dun.AllTiles)
|
|
{
|
|
var tileRef = _maps.GetTileRef(_gridUid, _grid, tile);
|
|
|
|
//Tile mask filtering
|
|
if (gen.TileMask is not null)
|
|
{
|
|
if (!gen.TileMask.Contains(((ContentTileDefinition) _tileDefManager[tileRef.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<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;
|
|
}
|
|
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<EntProtoId, EntProtoId>();
|
|
|
|
// 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<Vector2i>(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) && _entManager.TryGetComponent<MetaDataComponent>(existingEnt, out var metaData))
|
|
{
|
|
var existingProto = metaData.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"}!");
|
|
}
|
|
}
|
|
}
|
|
}
|