Renamed project folders from Subsurface to Barotrauma

This commit is contained in:
Regalis
2017-06-04 15:00:53 +03:00
parent ad03c8bf0d
commit 94c6a8ea1b
697 changed files with 157 additions and 211 deletions
@@ -0,0 +1,161 @@
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
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)
{
subRooms = new BTRoom[2];
if (Rand.Range(0.0f, 1.0f, false) < verticalProbability &&
rect.Width * minDivRatio >= minWidth)
{
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, false);
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, false);
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>();
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));
}
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, false), corridors);
}
if (subRooms != null)
{
subRooms[0].GenerateCorridors(minWidth, maxWidth, corridors);
subRooms[1].GenerateCorridors(minWidth, maxWidth, corridors);
}
}
public static void CalculateDistancesFromEntrance(BTRoom entrance, List<Corridor> corridors)
{
entrance.CalculateDistanceFromEntrance(1, new List<Corridor>(corridors));
}
private void CalculateDistanceFromEntrance(int currentDist, List<Corridor> corridors)
{
if (DistanceFromEntrance == 0)
{
DistanceFromEntrance = currentDist;
}
else
{
DistanceFromEntrance = Math.Min(currentDist, DistanceFromEntrance);
}
currentDist++;
for (int i = corridors.Count - 1; i >= 0; i = Math.Min(i - 1, corridors.Count - 1))
{
var corridor = corridors[i];
if (!corridor.ConnectedRooms.Contains(this)) continue;
corridors.RemoveAt(i);
corridor.ConnectedRooms[corridor.ConnectedRooms[0] == this ? 1 : 0].CalculateDistanceFromEntrance(currentDist, corridors);
}
}
}
}
@@ -0,0 +1,189 @@
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Barotrauma.RuinGeneration
{
class Corridor : RuinShape
{
private bool isHorizontal;
public Rectangle Rect
{
get { return rect; }
}
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);
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, false);
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, false);
rect = new Rectangle(xPos, top, width, bottom - top);
}
else
{
DebugConsole.ThrowError("wat");
}
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), RuinStructureType.CorridorWall));
Walls.Add(new Line(new Vector2(Rect.X, Rect.Bottom), new Vector2(Rect.Right, Rect.Bottom), RuinStructureType.CorridorWall));
}
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));
}
}
/// <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, false);
int jOffset = Rand.Int(leaves2.Count, false);
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 (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;
}
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;
}
return new BTRoom[] { leaves1[i], leaves2[j] };
}
}
return null;
}
}
}
@@ -0,0 +1,472 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Voronoi2;
namespace Barotrauma.RuinGeneration
{
abstract class RuinShape
{
protected Rectangle rect;
public Rectangle Rect
{
get { return rect; }
}
public int DistanceFromEntrance
{
get;
protected set;
}
public Vector2 Center
{
get { return rect.Center.ToVector2(); }
}
public List<Line> Walls;
public virtual void CreateWalls() { }
public Alignment GetLineAlignment(Line line)
{
if (line.A.Y == line.B.Y)
{
if (line.A.Y > rect.Center.Y && line.B.Y > rect.Center.Y)
{
return Alignment.Bottom;
}
else if (line.A.Y < rect.Center.Y && line.B.Y < rect.Center.Y)
{
return Alignment.Top;
}
}
else
{
if (line.A.X < rect.Center.X && line.B.X < rect.Center.X)
{
return Alignment.Left;
}
else if (line.A.X > rect.Center.X && line.B.X > rect.Center.X)
{
return Alignment.Right;
}
}
return Alignment.Center;
}
/// <summary>
/// Goes through a list of line segments and "clips off" all parts of the lines that are inside the rectangle
/// </summary>
public void SplitLines(Rectangle rectangle)
{
List<Line> newLines = new List<Line>();
foreach (Line line in Walls)
{
if (line.A.X == line.B.X) //vertical line
{
//line doesn't intersect the rectangle
if (rectangle.X > line.A.X || rectangle.Right < line.A.X ||
rectangle.Y > line.B.Y || rectangle.Bottom < line.A.Y)
{
newLines.Add(line);
}
else if (line.A.Y > rectangle.Y && line.B.Y < rectangle.Bottom)
{
continue;
}
//point A is within the rectangle -> cut a portion from the top of the line
else if (line.A.Y >= rectangle.Y && line.A.Y <= rectangle.Bottom)
{
newLines.Add(new Line(new Vector2(line.A.X, rectangle.Bottom), line.B, line.Type));
}
//point B is within the rectangle -> cut a portion from the bottom of the line
else if (line.B.Y >= rectangle.Y && line.B.Y <= rectangle.Bottom)
{
newLines.Add(new Line(line.A, new Vector2(line.A.X, rectangle.Y), line.Type));
}
//rect is in between the lines -> split the line into two
else
{
newLines.Add(new Line(line.A, new Vector2(line.A.X, rectangle.Y), line.Type));
newLines.Add(new Line(new Vector2(line.A.X, rectangle.Bottom), line.B, line.Type));
}
}
else if (line.A.Y == line.B.Y) //horizontal line
{
//line doesn't intersect the rectangle
if (rectangle.X > line.B.X || rectangle.Right < line.A.X ||
rectangle.Y > line.A.Y || rectangle.Bottom < line.A.Y)
{
newLines.Add(line);
}
else if (line.A.X > rectangle.X && line.B.X < rectangle.Right)
{
continue;
}
//point A is within the rectangle -> cut a portion from the left side of the line
else if (line.A.X >= rectangle.X && line.A.X <= rectangle.Right)
{
newLines.Add(new Line(new Vector2(rectangle.Right, line.A.Y), line.B, line.Type));
}
//point B is within the rectangle -> cut a portion from the right side of the line
else if (line.B.X >= rectangle.X && line.B.X <= rectangle.Right)
{
newLines.Add(new Line(line.A, new Vector2(rectangle.X, line.A.Y), line.Type));
}
//rect is in between the lines -> split the line into two
else
{
newLines.Add(new Line(line.A, new Vector2(rectangle.X, line.A.Y), line.Type));
newLines.Add(new Line(new Vector2(rectangle.Right, line.A.Y), line.B, line.Type));
}
}
else
{
DebugConsole.ThrowError("Error in StructureGenerator.SplitLines - lines must be axis aligned");
}
}
Walls = newLines;
}
}
struct Line
{
public readonly Vector2 A, B;
public readonly RuinStructureType Type;
public Line(Vector2 a, Vector2 b, RuinStructureType type)
{
Debug.Assert(a.X <= b.X);
Debug.Assert(a.Y <= b.Y);
A = a;
B = b;
Type = type;
}
}
class Ruin
{
private List<BTRoom> rooms;
private List<Corridor> corridors;
private List<Line> walls;
private List<RuinShape> allShapes;
public List<RuinShape> RuinShapes
{
get { return allShapes; }
}
public List<Line> Walls
{
get { return walls; }
}
public Rectangle Area
{
get;
private set;
}
public Ruin(VoronoiCell closestPathCell, List<VoronoiCell> caveCells, Rectangle area)
{
Area = area;
corridors = new List<Corridor>();
rooms = new List<BTRoom>();
walls = new List<Line>();
allShapes = new List<RuinShape>();
Generate(closestPathCell, caveCells, area);
}
public void Generate(VoronoiCell closestPathCell, List<VoronoiCell> caveCells, Rectangle area)
{
corridors.Clear();
rooms.Clear();
//area = new Rectangle(area.X, area.Y - area.Height, area.Width, area.Height);
int iterations = Rand.Range(3, 4, false);
float verticalProbability = Rand.Range(0.4f, 0.6f, false);
BTRoom baseRoom = new BTRoom(area);
rooms = new List<BTRoom> { baseRoom };
for (int i = 0; i < iterations; i++)
{
rooms.ForEach(l => l.Split(0.3f, verticalProbability, 300));
rooms = baseRoom.GetLeaves();
}
foreach (BTRoom leaf in rooms)
{
leaf.Scale
(
new Vector2(Rand.Range(0.5f, 0.9f, false), Rand.Range(0.5f, 0.9f, false))
);
}
baseRoom.GenerateCorridors(200, 256, corridors);
walls = new List<Line>();
rooms.ForEach(leaf =>
{
leaf.CreateWalls();
//walls.AddRange(leaf.Walls);
});
//---------------------------
BTRoom entranceRoom = null;
float shortestDistance = 0.0f;
foreach (BTRoom leaf in rooms)
{
float distance = Vector2.Distance(leaf.Rect.Center.ToVector2(), closestPathCell.Center);
if (entranceRoom == null || distance < shortestDistance)
{
entranceRoom = leaf;
shortestDistance = distance;
}
}
rooms.Remove(entranceRoom);
//---------------------------
foreach (BTRoom leaf in rooms)
{
foreach (Corridor corridor in corridors)
{
leaf.SplitLines(corridor.Rect);
}
walls.AddRange(leaf.Walls);
}
foreach (Corridor corridor in corridors)
{
corridor.CreateWalls();
foreach (BTRoom leaf in rooms)
{
corridor.SplitLines(leaf.Rect);
}
foreach (Corridor corridor2 in corridors)
{
if (corridor == corridor2) continue;
corridor.SplitLines(corridor2.Rect);
}
walls.AddRange(corridor.Walls);
}
//leaves.Remove(entranceRoom);
BTRoom.CalculateDistancesFromEntrance(entranceRoom, corridors);
allShapes = GenerateStructures(caveCells);
}
private List<RuinShape> GenerateStructures(List<VoronoiCell> caveCells)
{
List<RuinShape> shapes = new List<RuinShape>(rooms);
shapes.AddRange(corridors);
foreach (RuinShape leaf in shapes)
{
RuinStructureType wallType = RuinStructureType.Wall;
if (!(leaf is BTRoom))
{
wallType = RuinStructureType.CorridorWall;
}
//rooms further from the entrance are more likely to have hard-to-break walls
else if (Rand.Range(0.0f, leaf.DistanceFromEntrance, false) > 1.5f)
{
wallType = RuinStructureType.HeavyWall;
}
//generate walls --------------------------------------------------------------
foreach (Line wall in leaf.Walls)
{
var structurePrefab = RuinStructure.GetRandom(wallType, leaf.GetLineAlignment(wall));
if (structurePrefab == null) continue;
float radius = (wall.A.X == wall.B.X) ?
(structurePrefab.Prefab as StructurePrefab).Size.X * 0.5f :
(structurePrefab.Prefab as StructurePrefab).Size.Y * 0.5f;
Rectangle rect = new Rectangle(
(int)(wall.A.X - radius),
(int)(wall.B.Y + radius),
(int)((wall.B.X - wall.A.X) + radius*2.0f),
(int)((wall.B.Y - wall.A.Y) + radius*2.0f));
//cut a section off from both ends of a horizontal wall to get nicer looking corners
if (wall.A.Y == wall.B.Y)
{
rect.Inflate(-32, 0);
if (rect.Width < Submarine.GridSize.X) continue;
}
var structure = new Structure(rect, structurePrefab.Prefab as StructurePrefab, null);
structure.MoveWithLevel = true;
structure.SetCollisionCategory(Physics.CollisionLevel);
}
//generate backgrounds --------------------------------------------------------------
var background = RuinStructure.GetRandom(RuinStructureType.Back, Alignment.Center);
if (background == null) continue;
Rectangle backgroundRect = new Rectangle(leaf.Rect.X, leaf.Rect.Y + leaf.Rect.Height, leaf.Rect.Width, leaf.Rect.Height);
new Structure(backgroundRect, (background.Prefab as StructurePrefab), null).MoveWithLevel = true;
}
//generate props --------------------------------------------------------------
for (int i = 0; i < shapes.Count*2; i++ )
{
Alignment[] alignments = new Alignment[] { Alignment.Top, Alignment.Bottom, Alignment.Right, Alignment.Left, Alignment.Center };
var prop = RuinStructure.GetRandom(RuinStructureType.Prop, alignments[Rand.Int(alignments.Length, false)]);
Vector2 size = (prop.Prefab is StructurePrefab) ? ((StructurePrefab)prop.Prefab).Size : Vector2.Zero;
var shape = shapes[Rand.Int(shapes.Count, false)];
Vector2 position = shape.Rect.Center.ToVector2();
if (prop.Alignment.HasFlag(Alignment.Top))
{
position = new Vector2(Rand.Range(shape.Rect.X+size.X, shape.Rect.Right - size.X, false), shape.Rect.Bottom - 64);
}
else if (prop.Alignment.HasFlag(Alignment.Bottom))
{
position = new Vector2(Rand.Range(shape.Rect.X + size.X, shape.Rect.Right - size.X, false), shape.Rect.Top + 64);
}
else if (prop.Alignment.HasFlag(Alignment.Right))
{
position = new Vector2(shape.Rect.Right - 64, Rand.Range(shape.Rect.Y + size.X, shape.Rect.Bottom - size.Y, false));
}
else if (prop.Alignment.HasFlag(Alignment.Left))
{
position = new Vector2(shape.Rect.X + 64, Rand.Range(shape.Rect.Y + size.X, shape.Rect.Bottom - size.Y, false));
}
if (prop.Prefab is ItemPrefab)
{
var item = new Item((ItemPrefab)prop.Prefab, position, null);
item.MoveWithLevel = true;
}
else
{
new Structure(new Rectangle(
(int)(position.X - size.X/2.0f), (int)(position.Y + size.Y/2.0f),
(int)size.X, (int)size.Y),
prop.Prefab as StructurePrefab, null).MoveWithLevel = true;
}
}
//generate doors & sensors that close them -------------------------------------------------------------
var sensorPrefab = ItemPrefab.list.Find(ip => ip.Name == "Alien Motion Sensor") as ItemPrefab;
var wirePrefab = ItemPrefab.list.Find(ip => ip.Name == "Wire") as ItemPrefab;
foreach (Corridor corridor in corridors)
{
var doorPrefab = RuinStructure.GetRandom(corridor.IsHorizontal ? RuinStructureType.Door : RuinStructureType.Hatch, Alignment.Center);
if (doorPrefab == null) continue;
//find all walls that are parallel to the corridor
var suitableWalls = corridor.IsHorizontal ?
corridor.Walls.FindAll(c => c.A.Y == c.B.Y) : corridor.Walls.FindAll(c => c.A.X == c.B.X);
if (!suitableWalls.Any()) continue;
Vector2 doorPos = corridor.Center;
//choose a random wall to place the door next to
var wall = suitableWalls[Rand.Int(suitableWalls.Count, false)];
if (corridor.IsHorizontal)
{
doorPos.X = (wall.A.X + wall.B.X) / 2.0f;
}
else
{
doorPos.Y = (wall.A.Y + wall.B.Y) / 2.0f;
}
var door = new Item(doorPrefab.Prefab as ItemPrefab, doorPos, null);
door.MoveWithLevel = true;
door.GetComponent<Items.Components.Door>().IsOpen = Rand.Range(0.0f, 1.0f, false) < 0.8f;
if (sensorPrefab == null || wirePrefab == null) continue;
var sensorRoom = corridor.ConnectedRooms.FirstOrDefault(r => r != null && rooms.Contains(r));
if (sensorRoom == null) continue;
var sensor = new Item(sensorPrefab, new Vector2(
Rand.Range(sensorRoom.Rect.X, sensorRoom.Rect.Right, false),
Rand.Range(sensorRoom.Rect.Y, sensorRoom.Rect.Bottom,false)), null);
sensor.MoveWithLevel = true;
var wire = new Item(wirePrefab, sensorRoom.Center, null).GetComponent<Items.Components.Wire>();
wire.Item.MoveWithLevel = false;
var conn1 = door.Connections.Find(c => c.Name == "set_state");
conn1.AddLink(0, wire);
wire.Connect(conn1, false);
var conn2 = sensor.Connections.Find(c => c.Name == "state_out");
conn2.AddLink(0, wire);
wire.Connect(conn2, false);
}
return shapes;
}
public void Draw(SpriteBatch spriteBatch)
{
//foreach (BTRoom room in leaves)
//{
// GUI.DrawRectangle(spriteBatch, room.Rect, Color.White);
//}
//foreach (Corridor corr in corridors)
//{
// GUI.DrawRectangle(spriteBatch, corr.Rect, Color.Blue);
//}
foreach (Line line in walls)
{
GUI.DrawLine(spriteBatch, new Vector2(line.A.X, -line.A.Y), new Vector2(line.B.X, -line.B.Y), Color.Red, 0.0f, 10);
}
}
}
}
@@ -0,0 +1,102 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
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
{
const string ConfigFile = "Content/Map/RuinConfig.xml";
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 prefab = ToolBox.GetAttributeString(element, "prefab", "").ToLowerInvariant();
Prefab = MapEntityPrefab.list.Find(s => s.Name.ToLowerInvariant() == prefab);
if (Prefab == null)
{
DebugConsole.ThrowError("Loading ruin structure failed - structure prefab \""+prefab+" not found");
return;
}
string alignmentStr = ToolBox.GetAttributeString(element,"alignment","Bottom");
if (!Enum.TryParse<Alignment>(alignmentStr, true, out Alignment))
{
DebugConsole.ThrowError("Error in ruin structure \""+prefab+"\" - "+alignmentStr+" is not a valid alignment");
}
string typeStr = ToolBox.GetAttributeString(element,"type","");
if (!Enum.TryParse<RuinStructureType>(typeStr,true, out Type))
{
DebugConsole.ThrowError("Error in ruin structure \"" + prefab + "\" - " + typeStr + " is not a valid type");
return;
}
commonness = ToolBox.GetAttributeInt(element, "commonness", 1);
list.Add(this);
}
private static void Load()
{
list = new List<RuinStructure>();
XDocument doc = ToolBox.TryLoadXml(ConfigFile);
if (doc == null || doc.Root == null) return;
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, false);
foreach (RuinStructure ruinStructure in matchingStructures)
{
if (randomNumber <= ruinStructure.commonness)
{
return ruinStructure;
}
randomNumber -= ruinStructure.commonness;
}
return null;
}
}
}