38f1ddb...178a853: v0.8.9.1, removed content folder
This commit is contained in:
@@ -44,7 +44,7 @@ namespace Barotrauma.RuinGeneration
|
||||
{
|
||||
subRooms = new BTRoom[2];
|
||||
|
||||
if (Rand.Range(0.0f, 1.0f, Rand.RandSync.Server) < verticalProbability &&
|
||||
if (Rand.Range(0.0f, rect.Height / (float)rect.Width, Rand.RandSync.Server) < verticalProbability &&
|
||||
rect.Width * minDivRatio >= minWidth)
|
||||
{
|
||||
SplitVertical(minDivRatio);
|
||||
@@ -78,13 +78,13 @@ namespace Barotrauma.RuinGeneration
|
||||
|
||||
public override void CreateWalls()
|
||||
{
|
||||
Walls = new List<Line>();
|
||||
|
||||
Walls.Add(new Line(new Vector2(Rect.X, Rect.Y), new Vector2(Rect.Right, Rect.Y), RuinStructureType.Wall));
|
||||
Walls.Add(new Line(new Vector2(Rect.X, Rect.Bottom), new Vector2(Rect.Right, Rect.Bottom), RuinStructureType.Wall));
|
||||
|
||||
Walls.Add(new Line(new Vector2(Rect.X, Rect.Y), new Vector2(Rect.X, Rect.Bottom), RuinStructureType.Wall));
|
||||
Walls.Add(new Line(new Vector2(Rect.Right, Rect.Y), new Vector2(Rect.Right, Rect.Bottom), RuinStructureType.Wall));
|
||||
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)
|
||||
@@ -126,33 +126,52 @@ namespace Barotrauma.RuinGeneration
|
||||
}
|
||||
}
|
||||
|
||||
public static void CalculateDistancesFromEntrance(BTRoom entrance, List<Corridor> corridors)
|
||||
public static void CalculateDistancesFromEntrance(BTRoom entrance, List<BTRoom> rooms, List<Corridor> corridors)
|
||||
{
|
||||
entrance.CalculateDistanceFromEntrance(1, new List<Corridor>(corridors));
|
||||
entrance.CalculateDistanceFromEntrance(0, rooms, new List<Corridor>(corridors));
|
||||
}
|
||||
|
||||
private void CalculateDistanceFromEntrance(int currentDist, List<Corridor> corridors)
|
||||
private void CalculateDistanceFromEntrance(int currentDist, List<BTRoom> rooms, List<Corridor> corridors)
|
||||
{
|
||||
if (DistanceFromEntrance == 0)
|
||||
{
|
||||
DistanceFromEntrance = currentDist;
|
||||
}
|
||||
else
|
||||
{
|
||||
DistanceFromEntrance = Math.Min(currentDist, DistanceFromEntrance);
|
||||
}
|
||||
DistanceFromEntrance = DistanceFromEntrance == 0 ? currentDist : Math.Min(currentDist, DistanceFromEntrance);
|
||||
|
||||
currentDist++;
|
||||
|
||||
for (int i = corridors.Count - 1; i >= 0; i = Math.Min(i - 1, corridors.Count - 1))
|
||||
var roomRect = Rect;
|
||||
roomRect.Inflate(5, 5);
|
||||
foreach (var corridor in corridors)
|
||||
{
|
||||
var corridor = corridors[i];
|
||||
var corridorRect = corridor.Rect;
|
||||
corridorRect.Inflate(5, 5);
|
||||
if (!corridorRect.Intersects(roomRect)) continue;
|
||||
|
||||
if (!corridor.ConnectedRooms.Contains(this)) continue;
|
||||
corridor.DistanceFromEntrance = corridor.DistanceFromEntrance == 0 ?
|
||||
DistanceFromEntrance + 1 :
|
||||
Math.Min(corridor.DistanceFromEntrance, DistanceFromEntrance + 1);
|
||||
|
||||
corridors.RemoveAt(i);
|
||||
|
||||
List<BTRoom> connectedRooms = new List<BTRoom>();
|
||||
foreach (var otherRoom in rooms)
|
||||
{
|
||||
if (otherRoom == this) continue;
|
||||
if (otherRoom.DistanceFromEntrance > 0 && otherRoom.DistanceFromEntrance < currentDist) continue;
|
||||
|
||||
corridor.ConnectedRooms[corridor.ConnectedRooms[0] == this ? 1 : 0].CalculateDistanceFromEntrance(currentDist, corridors);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,13 +8,7 @@ namespace Barotrauma.RuinGeneration
|
||||
class Corridor : RuinShape
|
||||
{
|
||||
private bool isHorizontal;
|
||||
|
||||
// TODO: fix implicit hiding
|
||||
public Rectangle Rect
|
||||
{
|
||||
get { return rect; }
|
||||
}
|
||||
|
||||
|
||||
public bool IsHorizontal
|
||||
{
|
||||
get { return isHorizontal; }
|
||||
@@ -55,40 +49,28 @@ namespace Barotrauma.RuinGeneration
|
||||
var leaves2 = room.Adjacent.GetLeaves();
|
||||
|
||||
var suitableLeaves = GetSuitableLeafRooms(leaves1, leaves2, width, isHorizontal);
|
||||
room1 = suitableLeaves[0].Rect;
|
||||
room2 = suitableLeaves[1].Rect;
|
||||
|
||||
ConnectedRooms[0] = suitableLeaves[0];
|
||||
ConnectedRooms[1] = suitableLeaves[1];
|
||||
}
|
||||
|
||||
if (isHorizontal)
|
||||
{
|
||||
int left = Math.Min(room1.Right, room2.Right);
|
||||
int right = Math.Max(room1.X, room2.X);
|
||||
|
||||
int top = Math.Max(room1.Y, room2.Y);
|
||||
int bottom = Math.Min(room1.Bottom, room2.Bottom);
|
||||
|
||||
int yPos = Rand.Range(top, bottom - width, Rand.RandSync.Server);
|
||||
|
||||
rect = new Rectangle(left, yPos, right - left, width);
|
||||
}
|
||||
else if (room1.Y > room2.Bottom || room2.Y > room1.Bottom)
|
||||
{
|
||||
int left = Math.Max(room1.X, room2.X);
|
||||
int right = Math.Min(room1.Right, room2.Right);
|
||||
|
||||
int top = Math.Min(room1.Bottom, room2.Bottom);
|
||||
int bottom = Math.Max(room1.Y, room2.Y);
|
||||
|
||||
int xPos = Rand.Range(left, right - width, Rand.RandSync.Server);
|
||||
|
||||
rect = new Rectangle(xPos, top, width, bottom - top);
|
||||
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
|
||||
{
|
||||
room1 = suitableLeaves[0].Rect;
|
||||
room2 = suitableLeaves[1].Rect;
|
||||
ConnectedRooms[0] = suitableLeaves[0];
|
||||
ConnectedRooms[1] = suitableLeaves[1];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.ThrowError("wat");
|
||||
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;
|
||||
@@ -122,24 +104,21 @@ namespace Barotrauma.RuinGeneration
|
||||
|
||||
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), RuinStructureType.CorridorWall));
|
||||
Walls.Add(new Line(new Vector2(Rect.X, Rect.Bottom), new Vector2(Rect.Right, Rect.Bottom), RuinStructureType.CorridorWall));
|
||||
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), RuinStructureType.CorridorWall));
|
||||
Walls.Add(new Line(new Vector2(Rect.Right, Rect.Y), new Vector2(Rect.Right, Rect.Bottom), RuinStructureType.CorridorWall));
|
||||
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
|
||||
/// 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)
|
||||
@@ -147,7 +126,6 @@ namespace Barotrauma.RuinGeneration
|
||||
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;
|
||||
@@ -158,21 +136,17 @@ namespace Barotrauma.RuinGeneration
|
||||
|
||||
if (isHorizontal)
|
||||
{
|
||||
//if (Math.Min(leaves1[i].Rect.Bottom, leaves2[i].Rect.Bottom) - Math.Max(leaves1[i].Rect.Y, leaves2[j].Rect.Y) < width) continue;
|
||||
|
||||
|
||||
if (leaves1[i].Rect.Y > leaves2[j].Rect.Bottom-width) continue;
|
||||
if (leaves1[i].Rect.Bottom < leaves2[j].Rect.Y+width) continue;
|
||||
if (leaves1[i].Rect.Y > leaves2[j].Rect.Bottom - width) continue;
|
||||
if (leaves1[i].Rect.Bottom < leaves2[j].Rect.Y + width) continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
//if (Math.Min(leaves1[i].Rect.Right, leaves2[i].Rect.Right) - Math.Max(leaves1[i].Rect.X, leaves2[j].Rect.X) < width) continue;
|
||||
|
||||
|
||||
if (leaves1[i].Rect.X > leaves2[j].Rect.Right-width) continue;
|
||||
if (leaves1[i].Rect.Right < leaves2[j].Rect.X+width) continue;
|
||||
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] };
|
||||
}
|
||||
@@ -181,7 +155,60 @@ namespace Barotrauma.RuinGeneration
|
||||
return null;
|
||||
}
|
||||
|
||||
private bool CheckForIntersection(BTRoom potential1, BTRoom potential2, List<BTRoom> leaves1, List<BTRoom> leaves2, int width, bool isHorizontal)
|
||||
{
|
||||
Rectangle potential1Rect = potential1.Rect;
|
||||
Rectangle potential2Rect = potential2.Rect;
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,474 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.RuinGeneration
|
||||
{
|
||||
[Flags]
|
||||
enum RuinEntityType
|
||||
{
|
||||
Wall, Back, Door, Hatch, Prop
|
||||
}
|
||||
|
||||
class RuinGenerationParams : ISerializableEntity
|
||||
{
|
||||
public static List<RuinGenerationParams> List
|
||||
{
|
||||
get
|
||||
{
|
||||
if (paramsList == null)
|
||||
{
|
||||
LoadAll();
|
||||
}
|
||||
return paramsList;
|
||||
}
|
||||
}
|
||||
|
||||
private static List<RuinGenerationParams> paramsList;
|
||||
|
||||
private string filePath;
|
||||
|
||||
private List<RuinRoom> roomTypeList;
|
||||
|
||||
public 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), Editable(MinValueInt = 1, MaxValueInt = 10, ToolTip = "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.")]
|
||||
public int RoomDivisionIterationsMin
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(4, false), Editable(MinValueInt = 1, MaxValueInt = 10, ToolTip = "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.")]
|
||||
public int RoomDivisionIterationsMax
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(0.5f, false), Editable(MinValueFloat = 0.1f, MaxValueFloat = 0.9f, ToolTip = "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.")]
|
||||
public float VerticalSplitProbability
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(400, false), Editable(ToolTip = "The splitting algorithm attempts to keep the dimensions the split areas larger than this. For example, if the width of the split areas would be smaller than this after a vertical split, the algorithm will do a horizontal split.")]
|
||||
public int MinSplitWidth
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize("0.5,0.9", false), Editable(ToolTip = "The minimum and maximum width of a room relative to the areas created by the split algorithm.")]
|
||||
public Vector2 RoomWidthRange
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
[Serialize("0.5,0.9", false), Editable(ToolTip = "The minimum and maximum height of a room relative to the areas created by the split algorithm.")]
|
||||
public Vector2 RoomHeightRange
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize("200,256", false), Editable(ToolTip = "The minimum and maximum width of the corridors between rooms.")]
|
||||
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);
|
||||
}
|
||||
|
||||
public static RuinGenerationParams GetRandom()
|
||||
{
|
||||
if (paramsList == null) { LoadAll(); }
|
||||
|
||||
if (paramsList.Count == 0)
|
||||
{
|
||||
DebugConsole.ThrowError("No ruin configuration files found in any content package.");
|
||||
return new RuinGenerationParams(null);
|
||||
}
|
||||
|
||||
return paramsList[Rand.Int(paramsList.Count, Rand.RandSync.Server)];
|
||||
}
|
||||
|
||||
private static void LoadAll()
|
||||
{
|
||||
paramsList = new List<RuinGenerationParams>();
|
||||
foreach (string configFile in GameMain.Instance.GetFilesOfType(ContentType.RuinConfig))
|
||||
{
|
||||
XDocument doc = XMLExtensions.TryLoadXml(configFile);
|
||||
if (doc?.Root == null) continue;
|
||||
var newParams = new RuinGenerationParams(doc.Root)
|
||||
{
|
||||
filePath = configFile
|
||||
};
|
||||
paramsList.Add(newParams);
|
||||
}
|
||||
}
|
||||
|
||||
public static void SaveAll()
|
||||
{
|
||||
XmlWriterSettings settings = new XmlWriterSettings
|
||||
{
|
||||
Indent = true,
|
||||
NewLineOnAttributes = true
|
||||
};
|
||||
|
||||
foreach (RuinGenerationParams generationParams in List)
|
||||
{
|
||||
foreach (string configFile in GameMain.Instance.GetFilesOfType(ContentType.RuinConfig))
|
||||
{
|
||||
if (configFile != generationParams.filePath) continue;
|
||||
|
||||
XDocument doc = XMLExtensions.TryLoadXml(configFile);
|
||||
if (doc?.Root == null) continue;
|
||||
|
||||
SerializableProperty.SerializeProperties(generationParams, doc.Root);
|
||||
|
||||
using (var writer = XmlWriter.Create(configFile, settings))
|
||||
{
|
||||
doc.WriteTo(writer);
|
||||
writer.Flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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().ToLowerInvariant() == "chooseone")
|
||||
{
|
||||
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().ToLowerInvariant() == "wire")
|
||||
{
|
||||
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), Editable(ToolTip = "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.")]
|
||||
public Vector2 MinOffset { get; private set; }
|
||||
[Serialize("0,0", false), Editable(ToolTip = "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.")]
|
||||
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
@@ -1,100 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.RuinGeneration
|
||||
{
|
||||
[Flags]
|
||||
enum RuinStructureType
|
||||
{
|
||||
Wall = 1, CorridorWall = 2, Prop = 4, Back = 8, Door=16, Hatch=32, HeavyWall=64
|
||||
}
|
||||
|
||||
class RuinStructure
|
||||
{
|
||||
private static List<RuinStructure> list;
|
||||
|
||||
public readonly MapEntityPrefab Prefab;
|
||||
|
||||
public readonly Alignment Alignment;
|
||||
|
||||
public readonly RuinStructureType Type;
|
||||
|
||||
private int commonness;
|
||||
|
||||
private RuinStructure(XElement element)
|
||||
{
|
||||
string name = element.GetAttributeString("prefab", "");
|
||||
Prefab = MapEntityPrefab.Find(name);
|
||||
|
||||
if (Prefab == null)
|
||||
{
|
||||
DebugConsole.ThrowError("Loading ruin structure failed - structure prefab \"" + name + " not found");
|
||||
return;
|
||||
}
|
||||
|
||||
string alignmentStr = element.GetAttributeString("alignment", "Bottom");
|
||||
if (!Enum.TryParse(alignmentStr, true, out Alignment))
|
||||
{
|
||||
DebugConsole.ThrowError("Error in ruin structure \"" + name + "\" - " + alignmentStr + " is not a valid alignment");
|
||||
}
|
||||
|
||||
|
||||
string typeStr = element.GetAttributeString("type", "");
|
||||
if (!Enum.TryParse(typeStr, true, out Type))
|
||||
{
|
||||
DebugConsole.ThrowError("Error in ruin structure \"" + name + "\" - " + typeStr + " is not a valid type");
|
||||
return;
|
||||
}
|
||||
|
||||
commonness = element.GetAttributeInt("commonness", 1);
|
||||
|
||||
list.Add(this);
|
||||
}
|
||||
|
||||
private static void Load()
|
||||
{
|
||||
list = new List<RuinStructure>();
|
||||
foreach (string configFile in GameMain.Config.SelectedContentPackage.GetFilesOfType(ContentType.RuinConfig))
|
||||
{
|
||||
XDocument doc = XMLExtensions.TryLoadXml(configFile);
|
||||
if (doc == null || doc.Root == null) continue;
|
||||
|
||||
foreach (XElement element in doc.Root.Elements())
|
||||
{
|
||||
new RuinStructure(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static RuinStructure GetRandom(RuinStructureType type, Alignment alignment)
|
||||
{
|
||||
if (list == null)
|
||||
{
|
||||
DebugConsole.Log("Loading ruin structures...");
|
||||
Load();
|
||||
}
|
||||
|
||||
var matchingStructures = list.FindAll(rs => rs.Type.HasFlag(type) && rs.Alignment.HasFlag(alignment));
|
||||
|
||||
if (!matchingStructures.Any()) return null;
|
||||
|
||||
int totalCommonness = matchingStructures.Sum(m => m.commonness);
|
||||
|
||||
int randomNumber = Rand.Int(totalCommonness + 1, Rand.RandSync.Server);
|
||||
|
||||
foreach (RuinStructure ruinStructure in matchingStructures)
|
||||
{
|
||||
if (randomNumber <= ruinStructure.commonness)
|
||||
{
|
||||
return ruinStructure;
|
||||
}
|
||||
|
||||
randomNumber -= ruinStructure.commonness;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user