/// <summary> /// Generates the room map for the specified walls array. /// </summary> public void GenerateMap(WallTile[] Walls, FloorTile[] Floors, int width, int height, List <VMRoom> rooms, sbyte floor, VMContext context) //for first floor gen, curRoom should be 1. For floors above, it should be the last genmap result { Map = new uint[width * height]; //although 0 is the base of the array, room 1 is known to simantics as room 0. //values of 0 indicate the room has not been chosen in that location yet. bool noFloorBad = (rooms.Count > 1); this.Width = width; this.Height = height; //flood fill recursively. Each time choose find and choose the first "0" as the base. //The first recursion (outside) cannot fill into diagonals. bool remaining = true; bool outside = true; int i = 0; while (remaining) { var spread = new Stack <SpreadItem>(); remaining = false; while (i < Map.Length) { remaining = true; //get the wall on this tile. var wall = Walls[i]; var segs = wall.Segments; var room = (uint)rooms.Count; if (Map[i] == 0 && (segs & (WallSegments.AnyDiag)) == 0) { //normal tile - no diagonal ExpectedTile = Floors[i].Pattern; Map[i] = room | (room << 16); spread.Push(new SpreadItem(new Point(i % width, i / width), WallSegments.AnyAdj)); break; } else if ((Map[i] & 0xFFFF) == 0) { //start spreading from this side of the diagonal WallSegments validSpread; if ((segs & WallSegments.HorizontalDiag) > 0) { validSpread = WallSegments.TopLeft | WallSegments.TopRight; ExpectedTile = wall.TopLeftStyle; Map[i] |= 0x80000000; } else { validSpread = WallSegments.TopRight | WallSegments.BottomRight; ExpectedTile = wall.TopLeftPattern; } Map[i] |= room; spread.Push(new SpreadItem(new Point(i % width, i / width), validSpread)); break; } else if ((Map[i] & 0x7FFF0000) == 0) { //start spreading the other side WallSegments validSpread; if ((segs & WallSegments.HorizontalDiag) > 0) { validSpread = WallSegments.BottomLeft | WallSegments.BottomRight; ExpectedTile = wall.TopLeftPattern; Map[i] |= 0x80000000; } else { validSpread = WallSegments.TopLeft | WallSegments.BottomLeft; ExpectedTile = wall.TopLeftStyle; } Map[i] |= (room << 16); spread.Push(new SpreadItem(new Point(i % width, i / width), validSpread)); i++; break; } else { remaining = false; } i++; } if (remaining) { int rminX = spread.Peek().Pt.X; int rmaxX = rminX; int rminY = spread.Peek().Pt.Y; int rmaxY = rminY; var wallObs = new List <VMObstacle>(); var wallLines = (VM.UseWorld)?new VMWallLineBuilder():null; var fenceLines = (VM.UseWorld) ? new VMWallLineBuilder() : null; var wallDict = new Dictionary <uint, Vector2[]>(); var adjRooms = new HashSet <ushort>(); ushort area = 0; while (spread.Count > 0) { area++; var itemT = spread.Pop(); var item = itemT.Pt; if (item.X > rmaxX) { rmaxX = item.X; } if (item.X < rminX) { rminX = item.X; } if (item.Y > rmaxY) { rmaxY = item.Y; } if (item.Y < rminY) { rminY = item.Y; } var plusX = (item.X + 1) % width; var minX = (item.X + width - 1) % width; var plusY = (item.Y + 1) % height; var minY = (item.Y + height - 1) % height; var mainWalls = Walls[item.X + item.Y * width]; int obsX = item.X << 4; int obsY = item.Y << 4; if ((mainWalls.Segments & WallSegments.HorizontalDiag) > 0) { wallObs.Add(new VMObstacle(obsX + 11, obsY - 1, obsX + 17, obsY + 5)); wallObs.Add(new VMObstacle(obsX + 7, obsY + 3, obsX + 13, obsY + 9)); wallObs.Add(new VMObstacle(obsX + 3, obsY + 7, obsX + 9, obsY + 13)); wallObs.Add(new VMObstacle(obsX - 1, obsY + 11, obsX + 5, obsY + 17)); if (mainWalls.TopRightStyle == 1) { wallLines?.AddLine(obsX, obsY, 2); } else { fenceLines?.AddLine(obsX, obsY, 2); } } if ((mainWalls.Segments & WallSegments.VerticalDiag) > 0) { wallObs.Add(new VMObstacle(obsX - 1, obsY - 1, obsX + 5, obsY + 5)); wallObs.Add(new VMObstacle(obsX + 3, obsY + 3, obsX + 9, obsY + 9)); wallObs.Add(new VMObstacle(obsX + 7, obsY + 7, obsX + 13, obsY + 13)); wallObs.Add(new VMObstacle(obsX + 11, obsY + 11, obsX + 17, obsY + 17)); if (mainWalls.TopRightStyle == 1) { wallLines?.AddLine(obsX, obsY, 3); } else { fenceLines?.AddLine(obsX, obsY, 3); } } var PXWalls = Walls[plusX + item.Y * width]; var PYWalls = Walls[item.X + plusY * width]; if ((mainWalls.Segments & WallSegments.TopLeft) > 0) { if (!mainWalls.TopLeftDoor) { wallObs.Add(new VMObstacle(obsX - 3, obsY - 3, obsX + 6, obsY + 19)); } if (mainWalls.TopLeftThick) { wallLines?.AddLine(obsX, obsY, 0); } else { fenceLines?.AddLine(obsX, obsY, 0); } } if ((mainWalls.Segments & WallSegments.TopRight) > 0) { if (!mainWalls.TopRightDoor) { wallObs.Add(new VMObstacle(obsX - 3, obsY - 3, obsX + 19, obsY + 6)); } if (mainWalls.TopRightThick) { wallLines?.AddLine(obsX, obsY, 1); } else { fenceLines?.AddLine(obsX, obsY, 1); } } if ((mainWalls.Segments & WallSegments.BottomLeft) > 0) { if (!PYWalls.TopRightDoor) { wallObs.Add(new VMObstacle(obsX - 3, obsY + 13, obsX + 19, obsY + 19)); } if (PYWalls.TopRightThick) { wallLines?.AddLine(obsX, obsY + 16, 1); } else { fenceLines?.AddLine(obsX, obsY + 16, 1); } } if ((mainWalls.Segments & WallSegments.BottomRight) > 0) { if (!PXWalls.TopLeftDoor) { wallObs.Add(new VMObstacle(obsX + 13, obsY - 3, obsX + 19, obsY + 19)); } if (PXWalls.TopLeftThick) { wallLines?.AddLine(obsX + 16, obsY, 0); } else { fenceLines?.AddLine(obsX + 16, obsY, 0); } } bool segAllow = ((PXWalls.Segments & WallSegments.TopLeft) == 0); if ((segAllow || PXWalls.TopLeftStyle != 1) && ((itemT.Dir & WallSegments.BottomRight) > 0)) { SpreadOnto(Walls, Floors, plusX, item.Y, 0, Map, width, height, spread, (ushort)rooms.Count, ExpectedTile, noFloorBad, adjRooms, !segAllow); } segAllow = ((mainWalls.Segments & WallSegments.TopLeft) == 0); if ((segAllow || mainWalls.TopLeftStyle != 1) && ((itemT.Dir & WallSegments.TopLeft) > 0)) { SpreadOnto(Walls, Floors, minX, item.Y, 2, Map, width, height, spread, (ushort)rooms.Count, ExpectedTile, noFloorBad, adjRooms, !segAllow); } segAllow = ((PYWalls.Segments & WallSegments.TopRight) == 0); if ((segAllow || PYWalls.TopRightStyle != 1) && ((itemT.Dir & WallSegments.BottomLeft) > 0)) { SpreadOnto(Walls, Floors, item.X, plusY, 1, Map, width, height, spread, (ushort)rooms.Count, ExpectedTile, noFloorBad, adjRooms, !segAllow); } segAllow = ((mainWalls.Segments & WallSegments.TopRight) == 0); if ((segAllow || mainWalls.TopRightStyle != 1) && ((itemT.Dir & WallSegments.TopRight) > 0)) { SpreadOnto(Walls, Floors, item.X, minY, 3, Map, width, height, spread, (ushort)rooms.Count, ExpectedTile, noFloorBad, adjRooms, !segAllow); } } var bounds = new Rectangle(rminX, rminY, (rmaxX - rminX) + 1, (rmaxY - rminY) + 1); var roomObs = GenerateRoomObs((ushort)rooms.Count, (sbyte)(floor + 1), bounds, context); OptimizeObstacles(wallObs); OptimizeObstacles(roomObs); var supportRooms = new List <ushort>(); ushort myRoom = (ushort)rooms.Count; ushort minRoom = myRoom; bool deferredLit = false; foreach (var roomN in adjRooms) { var room = rooms[roomN]; if (minRoom > room.LightBaseRoom) { deferredLit = true; minRoom = room.LightBaseRoom; } room.AdjRooms.Add(myRoom); if (outside) { MakeOutside(rooms, room); } else if (room.IsOutside) { outside = true; } } if (deferredLit) { rooms[minRoom].SupportRooms.Add(myRoom); } else { supportRooms.Add(myRoom); } if (VM.UseWorld && minRoom != rooms.Count) { rooms[minRoom].WallLines.AddRange(wallLines.Lines); rooms[minRoom].FenceLines.AddRange(fenceLines.Lines); } rooms.Add(new VMRoom { IsOutside = outside, IsPool = ExpectedTile > 65533, Bounds = bounds, WallObs = wallObs, RoomObs = roomObs, RoutingObstacles = VMObstacleSet.RoughBalanced(wallObs.Concat(roomObs).ToList()), WallLines = (deferredLit) ? null : wallLines?.Lines, FenceLines = (deferredLit) ? null : fenceLines?.Lines, AdjRooms = adjRooms, RoomID = myRoom, LightBaseRoom = minRoom, Area = area, Floor = floor, SupportRooms = supportRooms }); foreach (var roomN in adjRooms) { var room = rooms[roomN]; TrySwitchBaseRoom(rooms, room, minRoom); } outside = false; } } }
public VMRectRouter(VMObstacleSet map) { TreeMap = map; }