diff --git a/Subsurface/Barotrauma.csproj b/Subsurface/Barotrauma.csproj
index 6d0b466df..a6d01c714 100644
--- a/Subsurface/Barotrauma.csproj
+++ b/Subsurface/Barotrauma.csproj
@@ -136,6 +136,7 @@
+
@@ -768,6 +769,10 @@
PreserveNewest
+
+ PreserveNewest
+ Designer
+
PreserveNewest
diff --git a/Subsurface/Content/Map/LevelGenerationParameters.xml b/Subsurface/Content/Map/LevelGenerationParameters.xml
new file mode 100644
index 000000000..f593fbfc1
--- /dev/null
+++ b/Subsurface/Content/Map/LevelGenerationParameters.xml
@@ -0,0 +1,72 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Subsurface/Source/ContentPackage.cs b/Subsurface/Source/ContentPackage.cs
index 52a3397de..1e6b65557 100644
--- a/Subsurface/Source/ContentPackage.cs
+++ b/Subsurface/Source/ContentPackage.cs
@@ -10,7 +10,17 @@ namespace Barotrauma
{
public enum ContentType
{
- None, Jobs, Item, Character, Structure, Executable, LocationTypes, RandomEvents, Missions, BackgroundCreaturePrefabs, BackgroundSpritePrefabs
+ None,
+ Jobs,
+ Item,
+ Character,
+ Structure,
+ Executable,
+ LocationTypes,
+ LevelGenerationPresets,
+ RandomEvents,
+ Missions,
+ BackgroundCreaturePrefabs, BackgroundSpritePrefabs
}
public class ContentPackage
diff --git a/Subsurface/Source/DebugConsole.cs b/Subsurface/Source/DebugConsole.cs
index 3d33e997b..cbd52d02f 100644
--- a/Subsurface/Source/DebugConsole.cs
+++ b/Subsurface/Source/DebugConsole.cs
@@ -493,10 +493,6 @@ namespace Barotrauma
case "fire":
if (GameMain.Client == null) Hull.EditFire = !Hull.EditFire;
- break;
- case "generatelevel":
- GameMain.Level = new Level("asdf", 50.0f, 500,500, 50);
- GameMain.Level.Generate();
break;
case "fixitems":
foreach (Item it in Item.ItemList)
diff --git a/Subsurface/Source/GameMain.cs b/Subsurface/Source/GameMain.cs
index 795cf1dbf..7de66445f 100644
--- a/Subsurface/Source/GameMain.cs
+++ b/Subsurface/Source/GameMain.cs
@@ -206,6 +206,7 @@ namespace Barotrauma
Mission.Init();
MapEntityPrefab.Init();
+ LevelGenerationParams.LoadPresets();
TitleScreen.LoadState = 10.0f;
yield return CoroutineStatus.Running;
diff --git a/Subsurface/Source/Map/Levels/CaveGenerator.cs b/Subsurface/Source/Map/Levels/CaveGenerator.cs
index 0602aa5e6..e1836f09d 100644
--- a/Subsurface/Source/Map/Levels/CaveGenerator.cs
+++ b/Subsurface/Source/Map/Levels/CaveGenerator.cs
@@ -189,16 +189,18 @@ namespace Barotrauma
{
Site site = (i == 0) ? ge.site1 : ge.site2;
- VoronoiCell cell = cellGrid[
- (int)Math.Floor((site.coord.x-borders.X) / gridCellSize),
- (int)Math.Floor((site.coord.y-borders.Y) / gridCellSize)].Find(c => c.site == site);
+ int x = (int)(Math.Floor((site.coord.x-borders.X) / gridCellSize));
+ int y = (int)(Math.Floor((site.coord.y-borders.Y) / gridCellSize));
+
+ x = MathHelper.Clamp(x, 0, cellGrid.GetLength(0)-1);
+ y = MathHelper.Clamp(y, 0, cellGrid.GetLength(1)-1);
+
+ VoronoiCell cell = cellGrid[x,y].Find(c => c.site == site);
if (cell == null)
{
cell = new VoronoiCell(site);
- cellGrid[
- (int)Math.Floor((cell.Center.X-borders.X) / gridCellSize),
- (int)Math.Floor((cell.Center.Y - borders.Y) / gridCellSize)].Add(cell);
+ cellGrid[x, y].Add(cell);
cells.Add(cell);
}
diff --git a/Subsurface/Source/Map/Levels/Level.cs b/Subsurface/Source/Map/Levels/Level.cs
index d60196be0..fb13abd02 100644
--- a/Subsurface/Source/Map/Levels/Level.cs
+++ b/Subsurface/Source/Map/Levels/Level.cs
@@ -50,9 +50,7 @@ namespace Barotrauma
public const float ExitDistance = 6000.0f;
private string seed;
-
- private int siteInterval;
-
+
public const int GridCellSize = 2000;
private List[,] cellGrid;
@@ -77,6 +75,8 @@ namespace Barotrauma
private Color backgroundColor;
+ private LevelGenerationParams generationParams;
+
public Vector2 StartPosition
{
get { return startPosition; }
@@ -124,24 +124,22 @@ namespace Barotrauma
get { return backgroundColor; }
}
- public Level(string seed, float difficulty, int width, int height, int siteInterval)
+ public Level(string seed, float difficulty, LevelGenerationParams generationParams)
{
this.seed = seed;
-
- this.siteInterval = siteInterval;
-
+
this.Difficulty = difficulty;
- borders = new Rectangle(0, 0, width, height);
+ this.generationParams = generationParams;
+
+ borders = new Rectangle(0, 0, (int)generationParams.Width, (int)generationParams.Height);
}
public static Level CreateRandom(LocationConnection locationConnection)
{
string seed = locationConnection.Locations[0].Name + locationConnection.Locations[1].Name;
-
- Rand.SetSyncedSeed(ToolBox.StringToInt(seed));
-
- return new Level(seed, locationConnection.Difficulty, Rand.Range(80000, 120000, false), Rand.Range(40000, 60000, false), 2000);
+
+ return new Level(seed, locationConnection.Difficulty, LevelGenerationParams.GetRandom(seed));
}
public static Level CreateRandom(string seed = "")
@@ -153,10 +151,10 @@ namespace Barotrauma
Rand.SetSyncedSeed(ToolBox.StringToInt(seed));
- return new Level(seed, Rand.Range(30.0f, 80.0f, false), Rand.Range(80000, 120000, false), Rand.Range(40000, 60000, false), 2000);
+ return new Level(seed, Rand.Range(30.0f, 80.0f, false), LevelGenerationParams.GetRandom(seed));
}
- public void Generate(bool mirror=false)
+ public void Generate(bool mirror = false)
{
Stopwatch sw = new Stopwatch();
sw.Start();
@@ -175,47 +173,51 @@ namespace Barotrauma
bodies = new List();
Rand.SetSyncedSeed(ToolBox.StringToInt(seed));
-
- float brightness = Rand.Range(1.0f, 1.3f, false);
- backgroundColor = Color.Lerp(new Color(11, 18, 26), new Color(50, 46, 20), Rand.Range(0.0f, 1.0f, false)) * brightness;
- backgroundColor = new Color(backgroundColor, 1.0f);
-
+
+ backgroundColor = generationParams.BackgroundColor;
float avgValue = (backgroundColor.R + backgroundColor.G + backgroundColor.G) / 3;
GameMain.LightManager.AmbientLight = new Color(backgroundColor * (60.0f / avgValue), 1.0f);
float minWidth = Submarine.MainSub == null ? 0.0f : Math.Max(Submarine.MainSub.Borders.Width, Submarine.MainSub.Borders.Height);
minWidth = Math.Max(minWidth, 6500.0f);
- startPosition = new Vector2(minWidth * 2, Rand.Range(minWidth * 2, borders.Height - minWidth * 2, false));
- endPosition = new Vector2(borders.Width - minWidth * 2, Rand.Range(minWidth * 2, borders.Height - minWidth * 2, false));
+ startPosition = new Vector2(
+ Rand.Range(minWidth * 2, minWidth * 4, false),
+ Rand.Range(minWidth * 2, borders.Height - minWidth * 2, false));
+
+ endPosition = new Vector2(
+ borders.Width - Rand.Range(minWidth * 2, minWidth * 4, false),
+ Rand.Range(minWidth * 2, borders.Height - minWidth * 2, false));
List pathNodes = new List();
Rectangle pathBorders = borders;// new Rectangle((int)minWidth, (int)minWidth, borders.Width - (int)minWidth * 2, borders.Height - (int)minWidth);
pathBorders.Inflate(-minWidth*2, -minWidth*2);
-
pathNodes.Add(new Vector2(startPosition.X, borders.Height));
pathNodes.Add(startPosition);
- for (float x = startPosition.X; x < endPosition.X; x += Rand.Range(5000.0f, 10000.0f, false))
+ for (float x = startPosition.X;
+ x < endPosition.X;
+ x += Rand.Range(generationParams.MainPathNodeIntervalRange.X, generationParams.MainPathNodeIntervalRange.Y, false))
{
pathNodes.Add(new Vector2(x, Rand.Range(pathBorders.Y, pathBorders.Bottom, false)));
}
pathNodes.Add(endPosition);
pathNodes.Add(new Vector2(endPosition.X, borders.Height));
-
- int smallTunnelCount = 5;
-
+
List> smallTunnels = new List>();
- for (int i = 0; i < smallTunnelCount; i++)
+ for (int i = 0; i < generationParams.SmallTunnelCount; i++)
{
var tunnelStartPos = pathNodes[Rand.Range(2, pathNodes.Count - 2, false)];
tunnelStartPos.X = MathHelper.Clamp(tunnelStartPos.X, pathBorders.X, pathBorders.Right);
- float tunnelLength = Rand.Range(5000.0f, 10000.0f, false);
+ float tunnelLength = Rand.Range(
+ generationParams.SmallTunnelLengthRange.X,
+ generationParams.SmallTunnelLengthRange.Y,
+ false);
var tunnelNodes = MathUtils.GenerateJaggedLine(
tunnelStartPos,
@@ -231,21 +233,23 @@ namespace Barotrauma
if (tunnel.Any()) smallTunnels.Add(tunnel);
}
-
-
-
- float siteVariance = siteInterval * 0.4f;
- for (int x = siteInterval / 2; x < borders.Width; x += siteInterval)
+
+ Vector2 siteInterval = generationParams.VoronoiSiteInterval;
+ Vector2 siteVariance = generationParams.VoronoiSiteVariance;
+ for (float x = siteInterval.X / 2; x < borders.Width; x += siteInterval.X)
{
- for (int y = siteInterval / 2; y < borders.Height; y += siteInterval)
+ for (float y = siteInterval.Y / 2; y < borders.Height; y += siteInterval.Y)
{
- Vector2 site = new Vector2(x, y) + Rand.Vector(siteVariance, false);
+ Vector2 site = new Vector2(
+ x + Rand.Range(-siteVariance.X, siteVariance.X, false),
+ y + Rand.Range(-siteVariance.Y, siteVariance.Y, false));
- if (smallTunnels.Any(t => t.Any(node => Vector2.Distance(node, site) < siteInterval)))
+ if (smallTunnels.Any(t => t.Any(node => Vector2.Distance(node, site) < siteInterval.Length())))
{
- if (x < borders.Width - siteInterval) sites.Add(new Vector2(x, y) + Vector2.UnitX * siteInterval * 0.5f);
- if (y < borders.Height - siteInterval) sites.Add(new Vector2(x, y) + Vector2.UnitY * siteInterval * 0.5f);
- if (x < borders.Width - siteInterval && y < borders.Height - siteInterval) sites.Add(new Vector2(x, y) + Vector2.One * siteInterval * 0.5f);
+ //add some more sites around the small tunnels to generate more small voronoi cells
+ if (x < borders.Width - siteInterval.X) sites.Add(new Vector2(x, y) + Vector2.UnitX * siteInterval * 0.5f);
+ if (y < borders.Height - siteInterval.Y) sites.Add(new Vector2(x, y) + Vector2.UnitY * siteInterval * 0.5f);
+ if (x < borders.Width - siteInterval.X && y < borders.Height - siteInterval.Y) sites.Add(new Vector2(x, y) + Vector2.One * siteInterval * 0.5f);
}
if (mirror) site.X = borders.Width - site.X;
@@ -259,7 +263,6 @@ namespace Barotrauma
List graphEdges = voronoi.MakeVoronoiGraph(sites, borders.Width, borders.Height);
-
Debug.WriteLine("MakeVoronoiGraph: " + sw2.ElapsedMilliseconds + " ms");
sw2.Restart();
@@ -272,7 +275,6 @@ namespace Barotrauma
List mainPath = CaveGenerator.GeneratePath(pathNodes, cells, cellGrid, GridCellSize,
new Rectangle(pathBorders.X, pathBorders.Y, pathBorders.Width, borders.Height), 0.3f, mirror);
-
for (int i = 2; i < mainPath.Count; i += 3)
{
positionsOfInterest.Add(new InterestingPosition(mainPath[i].Center, PositionType.MainPath));
@@ -315,9 +317,9 @@ namespace Barotrauma
cells = CleanCells(pathCells);
- pathCells.AddRange(CreateBottomHoles(Rand.Range(0.1f,0.8f, false), new Rectangle(
+ pathCells.AddRange(CreateBottomHoles(generationParams.BottomHoleProbability, new Rectangle(
(int)(borders.Width * 0.2f), 0,
- (int)(borders.Width * 0.6f), (int)(borders.Height * 0.3f))));
+ (int)(borders.Width * 0.6f), (int)(borders.Height * 0.8f))));
foreach (VoronoiCell cell in pathCells)
{
@@ -408,92 +410,33 @@ namespace Barotrauma
cellGrid[x, y].Add(cell);
}
-
- Vector2 ruinSize = new Vector2(Rand.Range(5000.0f, 8000.0f, false), Rand.Range(5000.0f, 8000.0f, false));
- float ruinRadius = Math.Max(ruinSize.X, ruinSize.Y) * 0.5f;
-
- Vector2 ruinPos = cells[Rand.Int(cells.Count, false)].Center;
-
- int iter = 0;
-
- while (mainPath.Any(p => Vector2.Distance(ruinPos, p.Center) < ruinRadius*2.0f))
+ for (int i = 0; i 10000.0f) continue;
-
- Vector2 moveAmount = Vector2.Normalize(ruinPos - pathCell.Center) * 100000.0f / dist;
-
- //if (weighedPathPos.Y + moveAmount.Y > borders.Bottom - ruinSize.X)
- //{
- // moveAmount.X = (Math.Abs(moveAmount.Y) + Math.Abs(moveAmount.X))*Math.Sign(moveAmount.X);
- // moveAmount.Y = 0.0f;
- //}
-
- weighedPathPos += moveAmount;
- }
-
- ruinPos = weighedPathPos;
-
- if (iter > 10000) break;
- }
-
- VoronoiCell closestPathCell = null;
- float closestDist = 0.0f;
- foreach (VoronoiCell pathCell in mainPath)
- {
- float dist = Vector2.Distance(pathCell.Center, ruinPos);
- if (closestPathCell == null || dist < closestDist)
- {
- closestPathCell = pathCell;
- closestDist = dist;
- }
- }
-
- var ruin = new Ruin(closestPathCell, cells, new Rectangle((ruinPos - ruinSize * 0.5f).ToPoint(), ruinSize.ToPoint()));
-
- ruins = new List();
- ruins.Add(ruin);
-
- ruin.RuinShapes.Sort((shape1, shape2) => shape2.DistanceFromEntrance.CompareTo(shape1.DistanceFromEntrance));
- for (int i = 0; i < 4; i++ )
- {
- positionsOfInterest.Add(new InterestingPosition(ruin.RuinShapes[i].Rect.Center.ToVector2(), PositionType.Ruin));
+ GenerateRuin(mainPath);
}
startPosition.Y = borders.Height;
endPosition.Y = borders.Height;
List cellsWithBody = new List(cells);
- foreach (RuinShape ruinShape in ruin.RuinShapes)
- {
- var tooClose = GetTooCloseCells(ruinShape.Rect.Center.ToVector2(), Math.Max(ruinShape.Rect.Width, ruinShape.Rect.Height));
-
- tooClose.ForEach(c =>
- {
- if (c.edges.Any(e => ruinShape.Rect.Contains(e.point1) || ruinShape.Rect.Contains(e.point2))) c.CellType = CellType.Empty;
- });
- }
-
+
List bodyVertices;
bodies = CaveGenerator.GeneratePolygons(cellsWithBody, out bodyVertices);
renderer.SetBodyVertices(bodyVertices.ToArray());
renderer.SetWallVertices(CaveGenerator.GenerateWallShapes(cells));
- renderer.PlaceSprites(1000);
+ renderer.PlaceSprites(generationParams.BackgroundSpriteAmount);
wrappingWalls = new WrappingWall[2, 2];
+ Rectangle ignoredArea = new Rectangle((int)startPosition.X, 0, (int)(endPosition.X - startPosition.X), borders.Height);
+
for (int side = 0; side < 2; side++)
{
for (int i = 0; i < 2; i++)
{
- wrappingWalls[side, i] = new WrappingWall(pathCells, cells, borders.Height * 0.5f,
+ wrappingWalls[side, i] = new WrappingWall(pathCells, cells, ignoredArea,
(side == 0 ? -1 : 1) * (i + 1));
List wrappingWallVertices;
@@ -532,27 +475,18 @@ namespace Barotrauma
edge.site1 = null;
edge.site2 = null;
}
-
}
Debug.WriteLine("Generatelevel: " + sw2.ElapsedMilliseconds + " ms");
sw2.Restart();
-
- //vertexBuffer = new VertexBuffer(GameMain.CurrGraphicsDevice, VertexPositionTexture.VertexDeclaration, vertices.Length, BufferUsage.WriteOnly);
- //vertexBuffer.SetData(vertices);
-
+
if (mirror)
{
Vector2 temp = startPosition;
startPosition = endPosition;
endPosition = temp;
}
-
-
- //RuinGeneration.RuinGenerator.Draw(spriteBatch);
-
-
Debug.WriteLine("**********************************************************************************");
Debug.WriteLine("Generated a map with " + sites.Count + " sites in " + sw.ElapsedMilliseconds + " ms");
Debug.WriteLine("Seed: "+seed);
@@ -569,15 +503,26 @@ namespace Barotrauma
if (!limits.Contains(cell.Center)) continue;
+ float closestDist = 0.0f;
+ WayPoint closestWayPoint = null;
+ foreach (WayPoint wp in WayPoint.WayPointList)
+ {
+ if (wp.SpawnType != SpawnType.Path) continue;
+
+ float dist =Math.Abs(cell.Center.X - wp.WorldPosition.X);
+ if (closestWayPoint == null || dist < closestDist)
+ {
+ closestDist = dist;
+ closestWayPoint = wp;
+ }
+ }
+
+ if (closestWayPoint.WorldPosition.Y < cell.Center.Y) continue;
+
toBeRemoved.Add(cell);
}
return toBeRemoved;
-
- //foreach (VoronoiCell cell in toBeRemoved)
- //{
- // cells.Remove(cell);
- //}
}
private void EnlargeMainPath(List pathCells, float minWidth)
@@ -692,22 +637,7 @@ namespace Barotrauma
if (tooClose && !tooCloseCells.Contains(cell)) tooCloseCells.Add(cell);
}
-
- //for (float x = -minDistance; x <= minDistance; x+=siteInterval)
- //{
- // for (float y = -minDistance; y <= minDistance; y += siteInterval)
- // {
- // Vector2 cornerPos = position + new Vector2(x,y);
-
- // int cellIndex = CaveGenerator.FindCellIndex(cornerPos, cells, cellGrid, GridCellSize);
- // if (cellIndex == -1) continue;
- // if (!tooCloseCells.Contains(cells[cellIndex]))
- // {
- // tooCloseCells.Add(cells[cellIndex]);
- // }
- // }
- //}
-
+
return tooCloseCells;
}
@@ -731,6 +661,76 @@ namespace Barotrauma
return newCells;
}
+ private void GenerateRuin(List mainPath)
+ {
+
+ Vector2 ruinSize = new Vector2(Rand.Range(5000.0f, 8000.0f, false), Rand.Range(5000.0f, 8000.0f, false));
+ float ruinRadius = Math.Max(ruinSize.X, ruinSize.Y) * 0.5f;
+
+ Vector2 ruinPos = cells[Rand.Int(cells.Count, false)].Center;
+
+ int iter = 0;
+
+ while (mainPath.Any(p => Vector2.Distance(ruinPos, p.Center) < ruinRadius * 2.0f))
+ {
+ Vector2 weighedPathPos = ruinPos;
+ iter++;
+
+ foreach (VoronoiCell pathCell in mainPath)
+ {
+ float dist = Vector2.Distance(pathCell.Center, ruinPos);
+ if (dist > 10000.0f) continue;
+
+ Vector2 moveAmount = Vector2.Normalize(ruinPos - pathCell.Center) * 100000.0f / dist;
+
+ //if (weighedPathPos.Y + moveAmount.Y > borders.Bottom - ruinSize.X)
+ //{
+ // moveAmount.X = (Math.Abs(moveAmount.Y) + Math.Abs(moveAmount.X))*Math.Sign(moveAmount.X);
+ // moveAmount.Y = 0.0f;
+ //}
+
+ weighedPathPos += moveAmount;
+ }
+
+ ruinPos = weighedPathPos;
+
+ if (iter > 10000) break;
+ }
+
+ VoronoiCell closestPathCell = null;
+ float closestDist = 0.0f;
+ foreach (VoronoiCell pathCell in mainPath)
+ {
+ float dist = Vector2.Distance(pathCell.Center, ruinPos);
+ if (closestPathCell == null || dist < closestDist)
+ {
+ closestPathCell = pathCell;
+ closestDist = dist;
+ }
+ }
+
+ var ruin = new Ruin(closestPathCell, cells, new Rectangle((ruinPos - ruinSize * 0.5f).ToPoint(), ruinSize.ToPoint()));
+
+ ruins = new List();
+ ruins.Add(ruin);
+
+ ruin.RuinShapes.Sort((shape1, shape2) => shape2.DistanceFromEntrance.CompareTo(shape1.DistanceFromEntrance));
+ for (int i = 0; i < 4; i++)
+ {
+ positionsOfInterest.Add(new InterestingPosition(ruin.RuinShapes[i].Rect.Center.ToVector2(), PositionType.Ruin));
+ }
+
+ foreach (RuinShape ruinShape in ruin.RuinShapes)
+ {
+ var tooClose = GetTooCloseCells(ruinShape.Rect.Center.ToVector2(), Math.Max(ruinShape.Rect.Width, ruinShape.Rect.Height));
+
+ tooClose.ForEach(c =>
+ {
+ if (c.edges.Any(e => ruinShape.Rect.Contains(e.point1) || ruinShape.Rect.Contains(e.point2))) c.CellType = CellType.Empty;
+ });
+ }
+ }
+
public Vector2 GetRandomItemPos(PositionType spawnPosType, float randomSpread, float offsetFromWall = 10.0f)
{
if (!positionsOfInterest.Any()) return Size*0.5f;
@@ -889,7 +889,7 @@ namespace Barotrauma
{
for (int i = 0; i < 2; i++)
{
- wrappingWalls[side, i].Dispose();
+ if (wrappingWalls[side, i] != null) wrappingWalls[side, i].Dispose();
}
}
diff --git a/Subsurface/Source/Map/Levels/LevelGenerationParams.cs b/Subsurface/Source/Map/Levels/LevelGenerationParams.cs
new file mode 100644
index 000000000..644c894c6
--- /dev/null
+++ b/Subsurface/Source/Map/Levels/LevelGenerationParams.cs
@@ -0,0 +1,216 @@
+using Microsoft.Xna.Framework;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Xml.Linq;
+
+namespace Barotrauma
+{
+ class LevelGenerationParams : IPropertyObject
+ {
+ private static List presets;
+
+ public string Name
+ {
+ get;
+ private set;
+ }
+
+ private float width, height;
+
+ private Vector2 voronoiSiteInterval;
+ //how much the sites are "scattered" on x- and y-axis
+ //if Vector2.Zero, the sites will just be placed in a regular grid pattern
+ private Vector2 voronoiSiteVariance;
+
+ //how far apart the nodes of the main path can be
+ //x = min interval, y = max interval
+ private Vector2 mainPathNodeIntervalRange;
+
+ private int smallTunnelCount;
+ //x = min length, y = max length
+ private Vector2 smallTunnelLengthRange;
+
+ //how large portion of the bottom of the level should be "carved out"
+ //if 0.0f, the bottom will be completely solid (making the abyss unreachable)
+ //if 1.0f, the bottom will be completely open
+ private float bottomHoleProbability;
+
+ private int ruinCount;
+
+ public Color BackgroundColor
+ {
+ get;
+ set;
+ }
+
+ [HasDefaultValue(1000, false)]
+ public int BackgroundSpriteAmount
+ {
+ get;
+ set;
+ }
+
+ public Dictionary ObjectProperties
+ {
+ get;
+ set;
+ }
+
+ [HasDefaultValue(100000.0f, false)]
+ public float Width
+ {
+ get { return width; }
+ set { width = Math.Max(value, 2000.0f); }
+ }
+
+ [HasDefaultValue(50000.0f, false)]
+ public float Height
+ {
+ get { return height; }
+ set { height = Math.Max(value, 2000.0f); }
+ }
+
+ public Vector2 VoronoiSiteInterval
+ {
+ get { return voronoiSiteInterval; }
+ set {
+ voronoiSiteInterval.X = MathHelper.Clamp(value.X, 100.0f, width/2);
+ voronoiSiteInterval.Y = MathHelper.Clamp(value.Y, 100.0f, height/2);
+ }
+ }
+
+ public Vector2 VoronoiSiteVariance
+ {
+ get { return voronoiSiteVariance; }
+ set
+ {
+ voronoiSiteVariance = new Vector2(
+ MathHelper.Clamp(value.X, 0, voronoiSiteInterval.X),
+ MathHelper.Clamp(value.Y, 0, voronoiSiteInterval.Y));
+ }
+ }
+
+ public Vector2 MainPathNodeIntervalRange
+ {
+ get { return mainPathNodeIntervalRange; }
+ set
+ {
+ mainPathNodeIntervalRange.X = MathHelper.Clamp(value.X, 100.0f, width / 2);
+ mainPathNodeIntervalRange.Y = MathHelper.Clamp(value.Y, mainPathNodeIntervalRange.X, width / 2);
+ }
+ }
+
+ [HasDefaultValue(5, false)]
+ public int SmallTunnelCount
+ {
+ get { return smallTunnelCount; }
+ set { smallTunnelCount = MathHelper.Clamp(value, 0, 100); }
+ }
+
+ public Vector2 SmallTunnelLengthRange
+ {
+ get { return smallTunnelLengthRange; }
+ set
+ {
+ smallTunnelLengthRange.X = MathHelper.Clamp(value.X, 100.0f, width);
+ smallTunnelLengthRange.Y = MathHelper.Clamp(value.Y, smallTunnelLengthRange.X, width);
+ }
+ }
+
+ [HasDefaultValue(1, false)]
+ public int RuinCount
+ {
+ get { return ruinCount; }
+ set { ruinCount = MathHelper.Clamp(value, 0, 10); }
+ }
+
+ [HasDefaultValue(0.4f, false)]
+ public float BottomHoleProbability
+ {
+ get { return bottomHoleProbability; }
+ set { bottomHoleProbability = MathHelper.Clamp(value, 0.0f, 1.0f); }
+ }
+
+ //public LevelGenerationParams()
+ //{
+ // Rand.SetSyncedSeed(ToolBox.StringToInt(seed));
+
+ // width = 100000.0f;
+ // height = 50000.0f;
+
+ // voronoiSiteInterval = 2000.0f;
+ // voronoiSiteVariance = new Vector2(voronoiSiteInterval, voronoiSiteInterval) * 0.4f;
+
+ // mainPathNodeIntervalRange = new Vector2(5000.0f, 10000.0f);
+
+ // float brightness = Rand.Range(1.0f, 1.3f, false);
+ // BackgroundColor = Color.Lerp(new Color(11, 18, 26), new Color(50, 46, 20), Rand.Range(0.0f, 1.0f, false)) * brightness;
+ // BackgroundColor = new Color(BackgroundColor, 1.0f);
+
+ // smallTunnelCount = 5;
+ // smallTunnelLengthRange = new Vector2(5000.0f, 10000.0f);
+
+ // ruinCount = 1;
+
+ // bottomHoleProbability = Rand.Range(0.1f, 0.8f, false);
+
+ // BackgroundSpriteAmount = (int)((new Vector2(width, height)).Length() / 100);
+ //}
+
+ public static LevelGenerationParams GetRandom(string seed)
+ {
+ Rand.SetSyncedSeed(ToolBox.StringToInt(seed));
+
+ if (presets == null || !presets.Any())
+ {
+ DebugConsole.ThrowError("Level generation presets not found - using default presets");
+ return new LevelGenerationParams(null);
+ }
+
+ return presets[Rand.Range(0, presets.Count, false)];
+ }
+
+ private LevelGenerationParams(XElement element)
+ {
+ Name = element==null ? "default" : element.Name.ToString();
+ ObjectProperties = ObjectProperty.InitProperties(this, element);
+
+ Vector3 colorVector = ToolBox.GetAttributeVector3(element, "BackgroundColor", new Vector3(50, 46, 20));
+ BackgroundColor = new Color((int)colorVector.X, (int)colorVector.Y, (int)colorVector.Z);
+
+ VoronoiSiteInterval = ToolBox.GetAttributeVector2(element, "VoronoiSiteInterval", new Vector2(3000, 3000));
+
+ VoronoiSiteVariance = ToolBox.GetAttributeVector2(element, "VoronoiSiteVariance", new Vector2(voronoiSiteInterval.X, voronoiSiteInterval.Y) * 0.4f);
+
+ MainPathNodeIntervalRange = ToolBox.GetAttributeVector2(element, "MainPathNodeIntervalRange", new Vector2(5000.0f, 10000.0f));
+
+ SmallTunnelLengthRange = ToolBox.GetAttributeVector2(element, "SmallTunnelLengthRange", new Vector2(5000.0f, 10000.0f));
+ }
+
+ public static void LoadPresets()
+ {
+ presets = new List();
+
+ var files = GameMain.SelectedPackage.GetFilesOfType(ContentType.LevelGenerationPresets);
+ if (!files.Any())
+ {
+ files.Add("Content/Map/LevelGenerationParameters.xml");
+ }
+
+ foreach (string file in files)
+ {
+
+ XDocument doc = ToolBox.TryLoadXml(file);
+ if (doc == null || doc.Root == null) return;
+
+ foreach (XElement element in doc.Root.Elements())
+ {
+ presets.Add(new LevelGenerationParams(element));
+ }
+ }
+ }
+ }
+}
diff --git a/Subsurface/Source/Map/Levels/WrappingWall.cs b/Subsurface/Source/Map/Levels/WrappingWall.cs
index cd290a1e5..1c200fa6a 100644
--- a/Subsurface/Source/Map/Levels/WrappingWall.cs
+++ b/Subsurface/Source/Map/Levels/WrappingWall.cs
@@ -48,28 +48,16 @@ namespace Barotrauma
get { return midPos; }
}
- public WrappingWall(List pathCells, List mapCells, float maxY, int dir = -1)
+ public WrappingWall(List pathCells, List mapCells, Rectangle ignoredArea, int dir = -1)
{
cells = new List();
- VoronoiCell lowestPathCell = null;
- foreach (VoronoiCell pathCell in pathCells)
- {
- if (lowestPathCell == null || pathCell.Center.Y < lowestPathCell.Center.Y)
- {
- lowestPathCell = pathCell;
- }
- }
-
- float bottomY = Math.Max(lowestPathCell.Center.Y, maxY);
-
VoronoiCell edgeCell = null;
foreach (VoronoiCell cell in mapCells)
{
- if (cell.Center.Y > bottomY) continue;
- if (edgeCell == null
- || (dir < 0 && cell.Center.X < edgeCell.Center.X)
- || (dir > 0 && cell.Center.X > edgeCell.Center.X))
+ if (ignoredArea.Contains(cell.Center)) continue;
+ if (Math.Sign(cell.Center.X - ignoredArea.Center.X) != Math.Sign(dir)) continue;
+ if (edgeCell == null || cell.Center.Y < edgeCell.Center.Y)
{
edgeCell = cell;
}
diff --git a/Subsurface/Source/Utils/ToolBox.cs b/Subsurface/Source/Utils/ToolBox.cs
index 3370e8e84..ab9df09f1 100644
--- a/Subsurface/Source/Utils/ToolBox.cs
+++ b/Subsurface/Source/Utils/ToolBox.cs
@@ -61,8 +61,8 @@ namespace Barotrauma
}
public static object GetAttributeObject(XElement element, string name)
- {
- if (element.Attribute(name) == null) return null;
+ {
+ if (element == null || element.Attribute(name) == null) return null;
return GetAttributeObject(element.Attribute(name));
}
@@ -106,7 +106,7 @@ namespace Barotrauma
public static string GetAttributeString(XElement element, string name, string defaultValue)
{
- if (element.Attribute(name) == null) return defaultValue;
+ if (element == null || element.Attribute(name) == null) return defaultValue;
return GetAttributeString(element.Attribute(name), defaultValue);
}
@@ -119,7 +119,7 @@ namespace Barotrauma
public static float GetAttributeFloat(XElement element, string name, float defaultValue)
{
- if (element.Attribute(name) == null) return defaultValue;
+ if (element == null || element.Attribute(name) == null) return defaultValue;
float val = defaultValue;
@@ -158,7 +158,7 @@ namespace Barotrauma
public static int GetAttributeInt(XElement element, string name, int defaultValue)
{
- if (element.Attribute(name) == null) return defaultValue;
+ if (element == null || element.Attribute(name) == null) return defaultValue;
int val = defaultValue;
@@ -176,10 +176,9 @@ namespace Barotrauma
public static bool GetAttributeBool(XElement element, string name, bool defaultValue)
{
- var attribute = element.Attribute(name);
- if (attribute == null) return defaultValue;
+ if (element == null || element.Attribute(name) == null) return defaultValue;
- return GetAttributeBool(attribute, defaultValue);
+ return GetAttributeBool(element.Attribute(name), defaultValue);
}
public static bool GetAttributeBool(XAttribute attribute, bool defaultValue)
@@ -206,16 +205,25 @@ namespace Barotrauma
public static Vector2 GetAttributeVector2(XElement element, string name, Vector2 defaultValue)
{
- if (element.Attribute(name) == null) return defaultValue;
+ if (element == null || element.Attribute(name) == null) return defaultValue;
string val = element.Attribute(name).Value;
return ParseToVector2(val);
}
+
+ public static Vector3 GetAttributeVector3(XElement element, string name, Vector3 defaultValue)
+ {
+ if (element == null || element.Attribute(name) == null) return defaultValue;
+
+ string val = element.Attribute(name).Value;
+
+ return ParseToVector3(val);
+ }
public static Vector4 GetAttributeVector4(XElement element, string name, Vector4 defaultValue)
{
- if (element.Attribute(name) == null) return defaultValue;
+ if (element == null || element.Attribute(name) == null) return defaultValue;
string val = element.Attribute(name).Value;
@@ -259,6 +267,26 @@ namespace Barotrauma
return vector.X.ToString("G", CultureInfo.InvariantCulture) + "," + vector.Y.ToString("G", CultureInfo.InvariantCulture);
}
+ public static Vector3 ParseToVector3(string stringVector3, bool errorMessages = true)
+ {
+ string[] components = stringVector3.Split(',');
+
+ Vector3 vector = Vector3.Zero;
+
+ if (components.Length!=3)
+ {
+ if (!errorMessages) return vector;
+ DebugConsole.ThrowError("Failed to parse the string ''"+stringVector3+"'' to Vector3");
+ return vector;
+ }
+
+ float.TryParse(components[0], NumberStyles.Any, CultureInfo.InvariantCulture, out vector.X);
+ float.TryParse(components[1], NumberStyles.Any, CultureInfo.InvariantCulture, out vector.Y);
+ float.TryParse(components[2], NumberStyles.Any, CultureInfo.InvariantCulture, out vector.Z);
+
+ return vector;
+ }
+
public static Vector4 ParseToVector4(string stringVector4, bool errorMessages = true)
{
string[] components = stringVector4.Split(',');