Unstable 0.1500.5.0 (almost forgor edition 💀)
This commit is contained in:
@@ -1,190 +0,0 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma.RuinGeneration
|
||||
{
|
||||
/// <summary>
|
||||
/// nodes of a binary tree used for generating underwater "dungeons"
|
||||
/// </summary>
|
||||
class BTRoom : RuinShape
|
||||
{
|
||||
private BTRoom[] subRooms;
|
||||
|
||||
public BTRoom Parent
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public Corridor Corridor
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public BTRoom[] SubRooms
|
||||
{
|
||||
get { return subRooms; }
|
||||
}
|
||||
|
||||
public BTRoom Adjacent
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public BTRoom(Rectangle rect)
|
||||
{
|
||||
this.rect = rect;
|
||||
}
|
||||
|
||||
public void Split(float minDivRatio, float verticalProbability = 0.5f, int minWidth = 200, int minHeight = 200)
|
||||
{
|
||||
bool verticalSplit = Rand.Range(0.0f, rect.Height / (float)rect.Width, Rand.RandSync.Server) < verticalProbability;
|
||||
if (rect.Width * minDivRatio < minWidth && rect.Height * minDivRatio < minHeight)
|
||||
{
|
||||
minDivRatio = 0.5f;
|
||||
}
|
||||
else if (rect.Width * minDivRatio < minWidth)
|
||||
{
|
||||
verticalSplit = false;
|
||||
}
|
||||
else if (rect.Height * minDivRatio < minHeight)
|
||||
{
|
||||
verticalSplit = true;
|
||||
}
|
||||
|
||||
subRooms = new BTRoom[2];
|
||||
if (verticalSplit)
|
||||
{
|
||||
SplitVertical(minDivRatio);
|
||||
}
|
||||
else
|
||||
{
|
||||
SplitHorizontal(minDivRatio);
|
||||
}
|
||||
|
||||
subRooms[0].Parent = this;
|
||||
subRooms[1].Parent = this;
|
||||
|
||||
subRooms[0].Adjacent = subRooms[1];
|
||||
subRooms[1].Adjacent = subRooms[0];
|
||||
}
|
||||
|
||||
private void SplitHorizontal(float minDivRatio)
|
||||
{
|
||||
float div = Rand.Range(minDivRatio, 1.0f - minDivRatio, Rand.RandSync.Server);
|
||||
subRooms[0] = new BTRoom(new Rectangle(rect.X, rect.Y, rect.Width, (int)(rect.Height * div)));
|
||||
subRooms[1] = new BTRoom(new Rectangle(rect.X, rect.Y + subRooms[0].rect.Height, rect.Width, rect.Height - subRooms[0].rect.Height));
|
||||
|
||||
}
|
||||
|
||||
private void SplitVertical(float minDivRatio)
|
||||
{
|
||||
float div = Rand.Range(minDivRatio, 1.0f - minDivRatio, Rand.RandSync.Server);
|
||||
subRooms[0] = new BTRoom(new Rectangle(rect.X, rect.Y, (int)(rect.Width * div), rect.Height));
|
||||
subRooms[1] = new BTRoom(new Rectangle(rect.X + subRooms[0].rect.Width, rect.Y, rect.Width - subRooms[0].rect.Width, rect.Height));
|
||||
}
|
||||
|
||||
public override void CreateWalls()
|
||||
{
|
||||
Walls = new List<Line>
|
||||
{
|
||||
new Line(new Vector2(Rect.X, Rect.Y), new Vector2(Rect.Right, Rect.Y)),
|
||||
new Line(new Vector2(Rect.X, Rect.Bottom), new Vector2(Rect.Right, Rect.Bottom)),
|
||||
new Line(new Vector2(Rect.X, Rect.Y), new Vector2(Rect.X, Rect.Bottom)),
|
||||
new Line(new Vector2(Rect.Right, Rect.Y), new Vector2(Rect.Right, Rect.Bottom))
|
||||
};
|
||||
}
|
||||
|
||||
public void Scale(Vector2 scale)
|
||||
{
|
||||
rect.Inflate((scale.X - 1.0f) * 0.5f * rect.Width, (scale.Y - 1.0f) * 0.5f * rect.Height);
|
||||
}
|
||||
|
||||
public List<BTRoom> GetLeaves()
|
||||
{
|
||||
return GetLeaves(new List<BTRoom>());
|
||||
}
|
||||
|
||||
private List<BTRoom> GetLeaves(List<BTRoom> leaves)
|
||||
{
|
||||
if (subRooms == null)
|
||||
{
|
||||
leaves.Add(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
subRooms[0].GetLeaves(leaves);
|
||||
subRooms[1].GetLeaves(leaves);
|
||||
}
|
||||
|
||||
return leaves;
|
||||
}
|
||||
|
||||
public void GenerateCorridors(int minWidth, int maxWidth, List<Corridor> corridors)
|
||||
{
|
||||
if (Adjacent != null && Corridor == null)
|
||||
{
|
||||
Corridor = new Corridor(this, Rand.Range(minWidth, maxWidth, Rand.RandSync.Server), corridors);
|
||||
}
|
||||
|
||||
if (subRooms != null)
|
||||
{
|
||||
subRooms[0].GenerateCorridors(minWidth, maxWidth, corridors);
|
||||
subRooms[1].GenerateCorridors(minWidth, maxWidth, corridors);
|
||||
}
|
||||
}
|
||||
|
||||
public static void CalculateDistancesFromEntrance(BTRoom entrance, List<BTRoom> rooms, List<Corridor> corridors)
|
||||
{
|
||||
entrance.CalculateDistanceFromEntrance(0, rooms, new List<Corridor>(corridors));
|
||||
}
|
||||
|
||||
private void CalculateDistanceFromEntrance(int currentDist, List<BTRoom> rooms, List<Corridor> corridors)
|
||||
{
|
||||
DistanceFromEntrance = DistanceFromEntrance == 0 ? currentDist : Math.Min(currentDist, DistanceFromEntrance);
|
||||
|
||||
currentDist++;
|
||||
|
||||
var roomRect = Rect;
|
||||
roomRect.Inflate(5, 5);
|
||||
foreach (var corridor in corridors)
|
||||
{
|
||||
var corridorRect = corridor.Rect;
|
||||
corridorRect.Inflate(5, 5);
|
||||
if (!corridorRect.Intersects(roomRect)) continue;
|
||||
|
||||
corridor.DistanceFromEntrance = corridor.DistanceFromEntrance == 0 ?
|
||||
DistanceFromEntrance + 1 :
|
||||
Math.Min(corridor.DistanceFromEntrance, DistanceFromEntrance + 1);
|
||||
|
||||
|
||||
List<BTRoom> connectedRooms = new List<BTRoom>();
|
||||
foreach (var otherRoom in rooms)
|
||||
{
|
||||
if (otherRoom == this) continue;
|
||||
if (otherRoom.DistanceFromEntrance > 0 && otherRoom.DistanceFromEntrance < currentDist) continue;
|
||||
|
||||
var otherRoomRect = otherRoom.Rect;
|
||||
otherRoomRect.Inflate(5, 5);
|
||||
if (corridorRect.Intersects(otherRoomRect)) { connectedRooms.Add(otherRoom); }
|
||||
}
|
||||
|
||||
connectedRooms.Sort((r1, r2) =>
|
||||
{
|
||||
return
|
||||
(Math.Abs(r1.Rect.Center.X - Rect.Center.X) + Math.Abs(r1.Rect.Center.Y - Rect.Center.Y)) -
|
||||
(Math.Abs(r2.Rect.Center.X - Rect.Center.X) + Math.Abs(r2.Rect.Center.Y - Rect.Center.Y));
|
||||
});
|
||||
|
||||
for (int i = 0; i < connectedRooms.Count; i++)
|
||||
{
|
||||
connectedRooms[i].CalculateDistanceFromEntrance(currentDist + 1 + i, rooms, corridors);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,210 +0,0 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Barotrauma.RuinGeneration
|
||||
{
|
||||
|
||||
class Corridor : RuinShape
|
||||
{
|
||||
private readonly bool isHorizontal;
|
||||
|
||||
public bool IsHorizontal
|
||||
{
|
||||
get { return isHorizontal; }
|
||||
}
|
||||
|
||||
public BTRoom[] ConnectedRooms
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public Corridor(Rectangle rect)
|
||||
{
|
||||
this.rect = rect;
|
||||
|
||||
isHorizontal = rect.Width > rect.Height;
|
||||
}
|
||||
|
||||
public Corridor(BTRoom room, int width, List<Corridor> corridors)
|
||||
{
|
||||
System.Diagnostics.Debug.Assert(room.Adjacent != null);
|
||||
|
||||
ConnectedRooms = new BTRoom[2];
|
||||
ConnectedRooms[0] = room;
|
||||
ConnectedRooms[1] = room.Adjacent;
|
||||
|
||||
Rectangle room1, room2;
|
||||
|
||||
room1 = room.Rect;
|
||||
room2 = room.Adjacent.Rect;
|
||||
|
||||
isHorizontal = (room1.Right <= room2.X || room2.Right <= room1.X);
|
||||
|
||||
//use the leaves as starting points for the corridor
|
||||
if (room.SubRooms != null)
|
||||
{
|
||||
var leaves1 = room.GetLeaves();
|
||||
var leaves2 = room.Adjacent.GetLeaves();
|
||||
|
||||
var suitableLeaves = GetSuitableLeafRooms(leaves1, leaves2, width, isHorizontal);
|
||||
if (suitableLeaves == null || suitableLeaves.Length < 2)
|
||||
{
|
||||
// No suitable leaves found due to intersections
|
||||
//DebugConsole.ThrowError("Error while generating ruins. Could not find a suitable position for a corridor. The width of the corridors may be too large compared to the sizes of the rooms.");
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
ConnectedRooms[0] = suitableLeaves[0];
|
||||
ConnectedRooms[1] = suitableLeaves[1];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rect = CalculateRectangle(room1, room2, width, isHorizontal);
|
||||
if (rect.Width <= 0 || rect.Height <= 0)
|
||||
{
|
||||
DebugConsole.ThrowError("Error while generating ruins. Attempted to create a corridor with a width or height of <= 0");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
room.Corridor = this;
|
||||
room.Adjacent.Corridor = this;
|
||||
|
||||
for (int i = corridors.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var corridor = corridors[i];
|
||||
|
||||
if (corridor.rect.Intersects(this.rect))
|
||||
{
|
||||
if (isHorizontal && corridor.isHorizontal)
|
||||
{
|
||||
if (this.rect.Width < corridor.rect.Width)
|
||||
return;
|
||||
else
|
||||
corridors.RemoveAt(i);
|
||||
}
|
||||
else if (!isHorizontal && !corridor.isHorizontal)
|
||||
{
|
||||
if (this.rect.Height < corridor.rect.Height)
|
||||
return;
|
||||
else
|
||||
corridors.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
corridors.Add(this);
|
||||
}
|
||||
|
||||
public override void CreateWalls()
|
||||
{
|
||||
Walls = new List<Line>();
|
||||
if (IsHorizontal)
|
||||
{
|
||||
Walls.Add(new Line(new Vector2(Rect.X, Rect.Y), new Vector2(Rect.Right, Rect.Y)));
|
||||
Walls.Add(new Line(new Vector2(Rect.X, Rect.Bottom), new Vector2(Rect.Right, Rect.Bottom)));
|
||||
}
|
||||
else
|
||||
{
|
||||
Walls.Add(new Line(new Vector2(Rect.X, Rect.Y), new Vector2(Rect.X, Rect.Bottom)));
|
||||
Walls.Add(new Line(new Vector2(Rect.Right, Rect.Y), new Vector2(Rect.Right, Rect.Bottom)));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find two rooms which have two face-two-face walls that we can place a corridor in between
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private BTRoom[] GetSuitableLeafRooms(List<BTRoom> leaves1, List<BTRoom> leaves2, int width, bool isHorizontal)
|
||||
{
|
||||
int iOffset = Rand.Int(leaves1.Count, Rand.RandSync.Server);
|
||||
int jOffset = Rand.Int(leaves2.Count, Rand.RandSync.Server);
|
||||
|
||||
for (int iCount = 0; iCount < leaves1.Count; iCount++)
|
||||
{
|
||||
int i = (iCount + iOffset) % leaves1.Count;
|
||||
|
||||
for (int jCount = 0; jCount < leaves2.Count; jCount++)
|
||||
{
|
||||
int j = (jCount + jOffset) % leaves2.Count;
|
||||
|
||||
if (isHorizontal)
|
||||
{
|
||||
if (leaves1[i].Rect.Y > leaves2[j].Rect.Bottom - width) continue;
|
||||
if (leaves1[i].Rect.Bottom < leaves2[j].Rect.Y + width) continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (leaves1[i].Rect.X > leaves2[j].Rect.Right - width) continue;
|
||||
if (leaves1[i].Rect.Right < leaves2[j].Rect.X + width) continue;
|
||||
}
|
||||
|
||||
// Check if the given corridor rect would intersect over a third room
|
||||
if (CheckForIntersection(leaves1[i], leaves2[j], leaves1, leaves2, width, isHorizontal)) continue;
|
||||
|
||||
return new BTRoom[] { leaves1[i], leaves2[j] };
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private bool CheckForIntersection(BTRoom potential1, BTRoom potential2, List<BTRoom> leaves1, List<BTRoom> leaves2, int width, bool isHorizontal)
|
||||
{
|
||||
Rectangle potentialCorridorRectangle = CalculateRectangle(potential1.Rect, potential2.Rect, width, isHorizontal);
|
||||
|
||||
if (potentialCorridorRectangle.Width <= 0 || potentialCorridorRectangle.Height <= 0) return true; // Invalid rectangle
|
||||
|
||||
for (int i = 0; i < leaves1.Count; i++)
|
||||
{
|
||||
if (leaves1[i] == potential1) continue;
|
||||
if (potentialCorridorRectangle.Intersects(leaves1[i].Rect)) return true;
|
||||
}
|
||||
|
||||
for (int i = 0; i < leaves2.Count; i++)
|
||||
{
|
||||
if (leaves2[i] == potential2) continue;
|
||||
if (potentialCorridorRectangle.Intersects(leaves2[i].Rect)) return true;
|
||||
}
|
||||
|
||||
rect = potentialCorridorRectangle; // Save the rectangle that passes the test
|
||||
return false;
|
||||
}
|
||||
|
||||
private Rectangle CalculateRectangle(Rectangle rect1, Rectangle rect2, int width, bool isHorizontal)
|
||||
{
|
||||
if (isHorizontal)
|
||||
{
|
||||
int left = Math.Min(rect1.Right, rect2.Right);
|
||||
int right = Math.Max(rect1.X, rect2.X);
|
||||
|
||||
int top = Math.Max(rect1.Y, rect2.Y);
|
||||
//int bottom = Math.Min(room1.Bottom, room2.Bottom);
|
||||
int yPos = top;//Rand.Range(top, bottom - width, Rand.RandSync.Server);
|
||||
|
||||
return new Rectangle(left, yPos, right - left, width);
|
||||
}
|
||||
else if (rect1.Y > rect2.Bottom || rect2.Y > rect1.Bottom)
|
||||
{
|
||||
int left = Math.Max(rect1.X, rect2.X);
|
||||
int right = Math.Min(rect1.Right, rect2.Right);
|
||||
|
||||
int top = Math.Min(rect1.Bottom, rect2.Bottom);
|
||||
int bottom = Math.Max(rect1.Y, rect2.Y);
|
||||
|
||||
int xPos = Rand.Range(left, right - width, Rand.RandSync.Server);
|
||||
|
||||
return new Rectangle(xPos, top, width, bottom - top);
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.ThrowError("wat");
|
||||
return new Rectangle();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+26
-407
@@ -18,9 +18,9 @@ namespace Barotrauma.RuinGeneration
|
||||
Wall, Back, Door, Hatch, Prop
|
||||
}
|
||||
|
||||
class RuinGenerationParams : ISerializableEntity
|
||||
class RuinGenerationParams : OutpostGenerationParams
|
||||
{
|
||||
public static List<RuinGenerationParams> List
|
||||
public static List<RuinGenerationParams> RuinParams
|
||||
{
|
||||
get
|
||||
{
|
||||
@@ -34,102 +34,14 @@ namespace Barotrauma.RuinGeneration
|
||||
|
||||
private static List<RuinGenerationParams> paramsList;
|
||||
|
||||
private string filePath;
|
||||
|
||||
private readonly List<RuinRoom> roomTypeList;
|
||||
|
||||
public string Name => "RuinGenerationParams";
|
||||
private readonly string filePath;
|
||||
|
||||
public override string Name => "RuinGenerationParams";
|
||||
|
||||
[Serialize("5000,5000", false), Editable]
|
||||
public Point SizeMin
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
[Serialize("8000,8000", false), Editable]
|
||||
public Point SizeMax
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(3, false, description: "The ruin generation algorithm \"splits\" the ruin area into two, splits these areas again, repeats this for some number of times and creates a room at each of the final split areas. This is value determines the minimum number of times the split is done."), Editable(MinValueInt = 1, MaxValueInt = 10)]
|
||||
public int RoomDivisionIterationsMin
|
||||
private RuinGenerationParams(XElement element, string filePath) : base(element, filePath)
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(4, false, description: "The ruin generation algorithm \"splits\" the ruin area into two, splits these areas again, repeats this for some number of times and creates a room at each of the final split areas. This is value determines the maximum number of times the split is done."), Editable(MinValueInt = 1, MaxValueInt = 10)]
|
||||
public int RoomDivisionIterationsMax
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(0.5f, false, description: "The probability for the split algorithm to split the area vertically. High values tend to create tall, vertical rooms, and low values wide, horizontal rooms."), Editable(MinValueFloat = 0.1f, MaxValueFloat = 0.9f)]
|
||||
public float VerticalSplitProbability
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(400, false, description: "The splitting algorithm attempts to keep the width of the split areas larger than this. If the width of the split areas would be smaller than this after a vertical split, the algorithm would do a horizontal split."), Editable]
|
||||
public int MinSplitWidth
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
[Serialize(400, false, description: "The splitting algorithm attempts to keep the height of the split areas larger than this. If the height of the split areas would be smaller than this after a vertical split, the algorithm would do a horizontal split."), Editable]
|
||||
public int MinSplitHeight
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize("0.5,0.9", false, description: "The minimum and maximum width of a room relative to the areas created by the split algorithm."), Editable]
|
||||
public Vector2 RoomWidthRange
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
[Serialize("0.5,0.9", false, description: "The minimum and maximum height of a room relative to the areas created by the split algorithm."), Editable]
|
||||
public Vector2 RoomHeightRange
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize("200,256", false, description: "The minimum and maximum width of the corridors between rooms."), Editable]
|
||||
public Point CorridorWidthRange
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public Dictionary<string, SerializableProperty> SerializableProperties
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
} = new Dictionary<string, SerializableProperty>();
|
||||
|
||||
public IEnumerable<RuinRoom> RoomTypeList
|
||||
{
|
||||
get { return roomTypeList; }
|
||||
}
|
||||
|
||||
private RuinGenerationParams(XElement element)
|
||||
{
|
||||
roomTypeList = new List<RuinRoom>();
|
||||
|
||||
if (element != null)
|
||||
{
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
roomTypeList.Add(new RuinRoom(subElement));
|
||||
}
|
||||
}
|
||||
SerializableProperties = SerializableProperty.DeserializeProperties(this, element);
|
||||
this.filePath = filePath;
|
||||
}
|
||||
|
||||
public static RuinGenerationParams GetRandom()
|
||||
@@ -139,7 +51,7 @@ namespace Barotrauma.RuinGeneration
|
||||
if (paramsList.Count == 0)
|
||||
{
|
||||
DebugConsole.ThrowError("No ruin configuration files found in any content package.");
|
||||
return new RuinGenerationParams(null);
|
||||
return new RuinGenerationParams(null, null);
|
||||
}
|
||||
|
||||
return paramsList[Rand.Int(paramsList.Count, Rand.RandSync.Server)];
|
||||
@@ -151,23 +63,24 @@ namespace Barotrauma.RuinGeneration
|
||||
foreach (ContentFile configFile in GameMain.Instance.GetFilesOfType(ContentType.RuinConfig))
|
||||
{
|
||||
XDocument doc = XMLExtensions.TryLoadXml(configFile.Path);
|
||||
if (doc == null) { continue; }
|
||||
var mainElement = doc.Root;
|
||||
if (doc.Root.IsOverride())
|
||||
if (doc?.Root == null) { continue; }
|
||||
|
||||
foreach (XElement subElement in doc.Root.Elements())
|
||||
{
|
||||
mainElement = doc.Root.FirstElement();
|
||||
paramsList.Clear();
|
||||
DebugConsole.NewMessage($"Overriding all ruin generation parameters using the file {configFile.Path}.", Color.Yellow);
|
||||
var mainElement = subElement;
|
||||
if (subElement.IsOverride())
|
||||
{
|
||||
mainElement = subElement.FirstElement();
|
||||
paramsList.Clear();
|
||||
DebugConsole.NewMessage($"Overriding all ruin generation parameters using the file {configFile.Path}.", Color.Yellow);
|
||||
}
|
||||
else if (paramsList.Any())
|
||||
{
|
||||
DebugConsole.NewMessage($"Adding additional ruin generation parameters from file '{configFile.Path}'");
|
||||
}
|
||||
var newParams = new RuinGenerationParams(mainElement, configFile.Path);
|
||||
paramsList.Add(newParams);
|
||||
}
|
||||
else if (paramsList.Any())
|
||||
{
|
||||
DebugConsole.NewMessage($"Adding additional ruin generation parameters from file '{configFile.Path}'");
|
||||
}
|
||||
var newParams = new RuinGenerationParams(mainElement)
|
||||
{
|
||||
filePath = configFile.Path
|
||||
};
|
||||
paramsList.Add(newParams);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -185,11 +98,11 @@ namespace Barotrauma.RuinGeneration
|
||||
NewLineOnAttributes = true
|
||||
};
|
||||
|
||||
foreach (RuinGenerationParams generationParams in List)
|
||||
foreach (RuinGenerationParams generationParams in RuinParams)
|
||||
{
|
||||
foreach (ContentFile configFile in GameMain.Instance.GetFilesOfType(ContentType.RuinConfig))
|
||||
{
|
||||
if (configFile.Path != generationParams.filePath) continue;
|
||||
if (configFile.Path != generationParams.filePath) { continue; }
|
||||
|
||||
XDocument doc = XMLExtensions.TryLoadXml(configFile.Path);
|
||||
if (doc == null) { continue; }
|
||||
@@ -205,298 +118,4 @@ namespace Barotrauma.RuinGeneration
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class RuinRoom : ISerializableEntity
|
||||
{
|
||||
public enum RoomPlacement
|
||||
{
|
||||
Any,
|
||||
First,
|
||||
Last
|
||||
}
|
||||
|
||||
public string Name
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
[Serialize(1.0f, false), Editable(MinValueFloat = 0.0f, MaxValueFloat = 10.0f)]
|
||||
public float Commonness { get; private set; }
|
||||
|
||||
public Dictionary<string, SerializableProperty> SerializableProperties
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
} = new Dictionary<string, SerializableProperty>();
|
||||
|
||||
[Serialize(RoomPlacement.Any, false), Editable]
|
||||
public RoomPlacement Placement
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(0, false), Editable]
|
||||
public int PlacementOffset
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(false, false), Editable]
|
||||
public bool IsCorridor
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(1.0f, false), Editable]
|
||||
public float MinWaterAmount
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
[Serialize(1.0f, false), Editable]
|
||||
public float MaxWaterAmount
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
private List<RuinEntityConfig> entityList = new List<RuinEntityConfig>();
|
||||
|
||||
public RuinRoom(XElement element)
|
||||
{
|
||||
SerializableProperties = SerializableProperty.DeserializeProperties(this, element);
|
||||
|
||||
Name = element.GetAttributeString("name", "");
|
||||
|
||||
if (element != null)
|
||||
{
|
||||
int groupIndex = 0;
|
||||
LoadEntities(element, ref groupIndex);
|
||||
}
|
||||
|
||||
void LoadEntities(XElement element2, ref int groupIndex)
|
||||
{
|
||||
foreach (XElement subElement in element2.Elements())
|
||||
{
|
||||
if (subElement.Name.ToString().Equals("chooseone", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
groupIndex++;
|
||||
LoadEntities(subElement, ref groupIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
entityList.Add(new RuinEntityConfig(subElement) { SingleGroupIndex = groupIndex });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public RuinEntityConfig GetRandomEntity(RuinEntityType type, Alignment alignment)
|
||||
{
|
||||
var matchingEntities = entityList.FindAll(rs =>
|
||||
rs.Type == type &&
|
||||
rs.Alignment.HasFlag(alignment));
|
||||
|
||||
if (!matchingEntities.Any()) return null;
|
||||
|
||||
return ToolBox.SelectWeightedRandom(
|
||||
matchingEntities,
|
||||
matchingEntities.Select(s => s.Commonness).ToList(),
|
||||
Rand.RandSync.Server);
|
||||
}
|
||||
|
||||
public List<RuinEntityConfig> GetPropList(RuinShape room, Rand.RandSync randSync)
|
||||
{
|
||||
Dictionary<int, List<RuinEntityConfig>> propGroups = new Dictionary<int, List<RuinEntityConfig>>();
|
||||
foreach (RuinEntityConfig entityConfig in entityList)
|
||||
{
|
||||
if (entityConfig.Type != RuinEntityType.Prop) { continue; }
|
||||
if (room.Rect.Width < entityConfig.MinRoomSize.X || room.Rect.Height < entityConfig.MinRoomSize.Y) { continue; }
|
||||
if (room.Rect.Width > entityConfig.MaxRoomSize.X || room.Rect.Height > entityConfig.MaxRoomSize.Y) { continue; }
|
||||
if (!propGroups.ContainsKey(entityConfig.SingleGroupIndex))
|
||||
{
|
||||
propGroups[entityConfig.SingleGroupIndex] = new List<RuinEntityConfig>();
|
||||
}
|
||||
propGroups[entityConfig.SingleGroupIndex].Add(entityConfig);
|
||||
}
|
||||
|
||||
List<RuinEntityConfig> props = new List<RuinEntityConfig>();
|
||||
foreach (KeyValuePair<int, List<RuinEntityConfig>> propGroup in propGroups)
|
||||
{
|
||||
if (propGroup.Key == 0)
|
||||
{
|
||||
props.AddRange(propGroup.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
props.Add(propGroup.Value[Rand.Int(propGroup.Value.Count, randSync)]);
|
||||
}
|
||||
}
|
||||
return props;
|
||||
}
|
||||
}
|
||||
|
||||
class RuinEntityConfig : ISerializableEntity
|
||||
{
|
||||
public readonly MapEntityPrefab Prefab;
|
||||
|
||||
public enum RelativePlacement
|
||||
{
|
||||
SameRoom,
|
||||
NextRoom,
|
||||
NextCorridor,
|
||||
PreviousRoom,
|
||||
PreviousCorridor,
|
||||
FirstRoom,
|
||||
FirstCorridor,
|
||||
LastRoom,
|
||||
LastCorridor
|
||||
}
|
||||
|
||||
public class EntityConnection
|
||||
{
|
||||
//which type of room to search for the item to connect to
|
||||
//sameroom, nextroom, previousroom, firstroom and lastroom are also valid
|
||||
public string RoomName
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public string TargetEntityIdentifier
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
//Identifier of the item to run the wire from. Only needed in item assemblies to determine which item in the assembly to use.
|
||||
public string SourceEntityIdentifier
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
//if set, the connection is done by running a wire from
|
||||
//(Pair.First = the name of the connection in this item) to (Pair.Second = the name of the connection in the target item)
|
||||
public Pair<string, string> WireConnection
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public EntityConnection(XElement element)
|
||||
{
|
||||
RoomName = element.GetAttributeString("roomname", "");
|
||||
TargetEntityIdentifier = element.GetAttributeString("targetentity", "");
|
||||
SourceEntityIdentifier = element.GetAttributeString("sourceentity", "");
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
if (subElement.Name.ToString().Equals("wire", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
WireConnection = new Pair<string, string>(
|
||||
subElement.GetAttributeString("from", ""),
|
||||
subElement.GetAttributeString("to", ""));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Serialize(Alignment.Bottom, false), Editable]
|
||||
public Alignment Alignment { get; private set; }
|
||||
|
||||
[Serialize("0,0", false, description: "Minimum offset from the anchor position, relative to the size of the room." +
|
||||
" For example, a value of { -0.5,0 } with a Bottom alignment would mean the entity can be placed anywhere between the bottom-left corner of the room and bottom-center."), Editable]
|
||||
public Vector2 MinOffset { get; private set; }
|
||||
[Serialize("0,0", false, description: "Maximum offset from the anchor position, relative to the size of the room." +
|
||||
" For example, a value of { 0.5,0 } with a Bottom alignment would mean the entity can be placed anywhere between the bottom-right corner of the room and bottom-center."), Editable]
|
||||
public Vector2 MaxOffset { get; private set; }
|
||||
|
||||
[Serialize(RuinEntityType.Prop, false), Editable]
|
||||
public RuinEntityType Type { get; private set; }
|
||||
|
||||
[Serialize(false, false), Editable]
|
||||
public bool Expand { get; private set; }
|
||||
|
||||
[Serialize(RelativePlacement.SameRoom, false), Editable]
|
||||
public RelativePlacement PlacementRelativeToParent { get; private set; }
|
||||
|
||||
[Serialize(1.0f, false), Editable(MinValueFloat = 0.0f, MaxValueFloat = 10.0f)]
|
||||
public float Commonness { get; private set; }
|
||||
|
||||
[Serialize(1, false)]
|
||||
public int MinAmount { get; private set; }
|
||||
[Serialize(1, false)]
|
||||
public int MaxAmount { get; private set; }
|
||||
|
||||
[Serialize("0,0", false)]
|
||||
public Point MinRoomSize { get; private set; }
|
||||
|
||||
[Serialize("100000,100000", false)]
|
||||
public Point MaxRoomSize { get; private set; }
|
||||
|
||||
[Serialize("", false)]
|
||||
public string TargetContainer { get; private set; }
|
||||
|
||||
public List<EntityConnection> EntityConnections { get; private set; } = new List<EntityConnection>();
|
||||
|
||||
|
||||
public int SingleGroupIndex;
|
||||
|
||||
private readonly List<RuinEntityConfig> childEntities = new List<RuinEntityConfig>();
|
||||
|
||||
public IEnumerable<RuinEntityConfig> ChildEntities
|
||||
{
|
||||
get { return childEntities; }
|
||||
}
|
||||
|
||||
public string Name => Prefab == null ? "null" : Prefab.Name;
|
||||
|
||||
public Dictionary<string, SerializableProperty> SerializableProperties
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
} = new Dictionary<string, SerializableProperty>();
|
||||
|
||||
public RuinEntityConfig(XElement element)
|
||||
{
|
||||
string name = element.GetAttributeString("prefab", "");
|
||||
Prefab = MapEntityPrefab.Find(name: null, identifier: name);
|
||||
|
||||
if (Prefab == null)
|
||||
{
|
||||
DebugConsole.ThrowError("Loading ruin entity config failed - map entity prefab \"" + name + "\" not found.");
|
||||
return;
|
||||
}
|
||||
|
||||
SerializableProperties = SerializableProperty.DeserializeProperties(this, element);
|
||||
|
||||
int gIndex = 0;
|
||||
LoadChildren(element, ref gIndex);
|
||||
|
||||
void LoadChildren(XElement element2, ref int groupIndex)
|
||||
{
|
||||
foreach (XElement subElement in element2.Elements())
|
||||
{
|
||||
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||
{
|
||||
case "connection":
|
||||
case "entityconnection":
|
||||
EntityConnections.Add(new EntityConnection(subElement));
|
||||
break;
|
||||
case "chooseone":
|
||||
groupIndex++;
|
||||
LoadChildren(subElement, ref groupIndex);
|
||||
break;
|
||||
default:
|
||||
childEntities.Add(new RuinEntityConfig(subElement) { SingleGroupIndex = groupIndex });
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user