Ejemplo n.º 1
0
        /// <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;
                }
            }
        }
Ejemplo n.º 2
0
 public VMRectRouter(VMObstacleSet map)
 {
     TreeMap = map;
 }