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); }
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; }
private List <RuinShape> GenerateStructures(List <VoronoiCell> caveCells, Rectangle ruinArea, bool mirror) { List <RuinShape> shapes = new List <RuinShape>(rooms); shapes.AddRange(corridors); if (mirror) { foreach (RuinShape shape in shapes) { shape.MirrorX(ruinArea.Center.ToVector2()); } } 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, Rand.RandSync.Server) > 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) { ShouldBeSaved = false }; 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) { ShouldBeSaved = false }; var submarineBlocker = BodyFactory.CreateRectangle(GameMain.World, ConvertUnits.ToSimUnits(leaf.Rect.Width), ConvertUnits.ToSimUnits(leaf.Rect.Height), 1, ConvertUnits.ToSimUnits(leaf.Center)); submarineBlocker.IsStatic = true; submarineBlocker.CollisionCategories = Physics.CollisionWall; submarineBlocker.CollidesWith = Physics.CollisionWall; } List <RuinShape> doorlessRooms = new List <RuinShape>(shapes); //generate doors & sensors that close them ------------------------------------------------------------- var sensorPrefab = MapEntityPrefab.Find("Alien Motion Sensor") as ItemPrefab; var wirePrefab = MapEntityPrefab.Find("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; } doorlessRooms.Remove(corridor); Vector2 doorPos = corridor.Center; //choose a random wall to place the door next to var wall = suitableWalls[Rand.Int(suitableWalls.Count, Rand.RandSync.Server)]; 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) { ShouldBeSaved = false }; door.GetComponent <Items.Components.Door>().IsOpen = Rand.Range(0.0f, 1.0f, Rand.RandSync.Server) < 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, Rand.RandSync.Server), Rand.Range(sensorRoom.Rect.Y, sensorRoom.Rect.Bottom, Rand.RandSync.Server)), null) { ShouldBeSaved = false }; var wire = new Item(wirePrefab, sensorRoom.Center, null).GetComponent <Items.Components.Wire>(); wire.Item.ShouldBeSaved = 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); } //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, Rand.RandSync.Server)]); if (prop == null) { continue; } Vector2 size = (prop.Prefab is StructurePrefab) ? ((StructurePrefab)prop.Prefab).Size : Vector2.Zero; //if the prop is placed at the center of the room, we have to use a room without a door (because they're also placed at the center) var shape = prop.Alignment.HasFlag(Alignment.Center) ? doorlessRooms[Rand.Int(doorlessRooms.Count, Rand.RandSync.Server)] : shapes[Rand.Int(shapes.Count, Rand.RandSync.Server)]; 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, Rand.RandSync.Server), 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, Rand.RandSync.Server), 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, Rand.RandSync.Server)); } 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, Rand.RandSync.Server)); } if (prop.Prefab is ItemPrefab) { new Item((ItemPrefab)prop.Prefab, position, null); } 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) { ShouldBeSaved = false }; } } return(shapes); }