Beispiel #1
0
 public virtual IFloorRoomPlan GetRoomHall(RoomHallIndex room)
 {
     if (!room.IsHall)
     {
         return(this.Rooms[room.Index]);
     }
     else
     {
         return(this.Halls[room.Index]);
     }
 }
Beispiel #2
0
        public void EraseRoomHall(RoomHallIndex roomHall)
        {
            if (!roomHall.IsHall)
            {
                this.Rooms.RemoveAt(roomHall.Index);
            }
            else
            {
                this.Halls.RemoveAt(roomHall.Index);
            }

            // go through the rest of the rooms, removing the removed listroomhall from adjacents
            // also correcting their indices
            foreach (var plan in this.Rooms)
            {
                for (int jj = plan.Adjacents.Count - 1; jj >= 0; jj--)
                {
                    RoomHallIndex adj = plan.Adjacents[jj];
                    if (adj.IsHall == roomHall.IsHall)
                    {
                        if (adj.Index == roomHall.Index)
                        {
                            plan.Adjacents.RemoveAt(jj);
                        }
                        else if (adj.Index > roomHall.Index)
                        {
                            plan.Adjacents[jj] = new RoomHallIndex(adj.Index - 1, adj.IsHall);
                        }
                    }
                }
            }

            foreach (var plan in this.Halls)
            {
                for (int jj = plan.Adjacents.Count - 1; jj >= 0; jj--)
                {
                    RoomHallIndex adj = plan.Adjacents[jj];
                    if (adj.IsHall == roomHall.IsHall)
                    {
                        if (adj.Index == roomHall.Index)
                        {
                            plan.Adjacents.RemoveAt(jj);
                        }
                        else if (adj.Index > roomHall.Index)
                        {
                            plan.Adjacents[jj] = new RoomHallIndex(adj.Index - 1, adj.IsHall);
                        }
                    }
                }
            }
        }
Beispiel #3
0
        protected static SpawnList <ListPathTraversalNode> GetPossibleExpansions(FloorPlan floorPlan, List <RoomHallIndex> candList)
        {
            // get all probabilities.
            // the probability of an extension is the distance that the target room is from the start room, in rooms
            var expansions = new SpawnList <ListPathTraversalNode>();

            for (int nn = 0; nn < candList.Count; nn++)
            {
                // find the room to connect to
                // go through all sides of all rooms (randomly)
                RoomHallIndex  chosenFrom = candList[nn];
                IFloorRoomPlan planFrom   = floorPlan.GetRoomHall(chosenFrom);

                // exhausting all possible directions (randomly)
                foreach (Dir4 dir in DirExt.VALID_DIR4)
                {
                    bool forbidExtend = false;
                    foreach (RoomHallIndex adjacent in planFrom.Adjacents)
                    {
                        Rect adjRect = floorPlan.GetRoomHall(adjacent).RoomGen.Draw;
                        if (planFrom.RoomGen.Draw.GetScalar(dir) == adjRect.GetScalar(dir.Reverse()))
                        {
                            forbidExtend = true;
                            break;
                        }
                    }

                    if (!forbidExtend)
                    {
                        // find a rectangle to connect it with
                        ListPathTraversalNode?expandToResult = GetRoomToConnect(floorPlan, chosenFrom, dir);

                        if (expandToResult is ListPathTraversalNode expandTo)
                        {
                            int prb = floorPlan.GetDistance(expandTo.From, expandTo.To);
                            if (prb < 0)
                            {
                                expansions.Add(expandTo, 1);
                            }
                            else if (prb > 0)
                            {
                                expansions.Add(expandTo, prb);
                            }
                        }
                    }
                }
            }

            return(expansions);
        }
Beispiel #4
0
        public virtual bool SpawnInRoom(TGenContext map, RoomHallIndex roomIndex, TSpawnable spawn)
        {
            IRoomGen   room      = map.RoomPlan.GetRoomHall(roomIndex).RoomGen;
            List <Loc> freeTiles = map.GetFreeTiles(room.Draw);

            if (freeTiles.Count > 0)
            {
                int randIndex = map.Rand.Next(freeTiles.Count);
                map.PlaceItem(freeTiles[randIndex], spawn);
                return(true);
            }

            return(false);
        }
Beispiel #5
0
        public virtual List <int> GetAdjacentRooms(int roomIndex)
        {
            RoomHallIndex fullIndex = new RoomHallIndex(roomIndex, false);

            // skips halls
            // every listroomplan keeps a list of adjacents for easy traversal
            // just because two rooms are next to each other doesn't mean they will be adjacents
            // their openings may not align and therefore have free reign to block the path off from each other
            // the rules of this generator only say that if you park two rooms next to each other,
            // you must prepare for the possibility that they become connected.
            // once again, the philosophy that some setups may be cheesable,
            // but all setups are completable.
            List <int> returnList = new List <int>();

            void NodeAct(RoomHallIndex nodeIndex, int distance)
            {
                // only add nodes that are
                if (nodeIndex.IsHall)
                {
                    return; // Not a hall node
                }
                if (nodeIndex == fullIndex)
                {
                    return; // Not the start node
                }
                returnList.Add(nodeIndex.Index);
            }

            List <RoomHallIndex> GetAdjacents(RoomHallIndex nodeIndex)
            {
                // do not add adjacents if we arrive on a room
                // unless it's the first one.
                if (nodeIndex == fullIndex)
                {
                    return(this.Rooms[roomIndex].Adjacents);
                }
                else if (nodeIndex.IsHall)
                {
                    return(this.Halls[nodeIndex.Index].Adjacents);
                }

                return(new List <RoomHallIndex>());
            }

            Graph.TraverseBreadthFirst(fullIndex, NodeAct, GetAdjacents);

            return(returnList);
        }
Beispiel #6
0
        public int GetDistance(RoomHallIndex roomFrom, RoomHallIndex roomTo)
        {
            int returnValue = -1;

            void NodeAct(RoomHallIndex nodeIndex, int distance)
            {
                if (nodeIndex == roomTo)
                {
                    returnValue = distance;
                }
            }

            Graph.TraverseBreadthFirst(roomFrom, NodeAct, this.GetAdjacents);

            return(returnValue);
        }
Beispiel #7
0
        public void TransferBorderToAdjacents(RoomHallIndex from)
        {
            IFloorRoomPlan       basePlan  = this.GetRoomHall(from);
            IRoomGen             roomGen   = basePlan.RoomGen;
            List <RoomHallIndex> adjacents = basePlan.Adjacents;

            foreach (RoomHallIndex adjacent in adjacents)
            {
                // first determine if this adjacent should be receiving info
                if ((!from.IsHall && adjacent.IsHall) ||
                    (from.IsHall == adjacent.IsHall && from.Index < adjacent.Index))
                {
                    IRoomGen adjacentGen = this.GetRoomHall(adjacent).RoomGen;
                    adjacentGen.ReceiveOpenedBorder(roomGen, GetDirAdjacent(adjacentGen, roomGen));
                }
            }
        }
Beispiel #8
0
        public int GetDistance(RoomHallIndex roomFrom, RoomHallIndex roomTo)
        {
            int returnValue = -1;
            int startIndex  = roomFrom.Index + (roomFrom.IsHall ? this.Rooms.Count : 0);
            int endIndex    = roomTo.Index + (roomTo.IsHall ? this.Rooms.Count : 0);

            void NodeAct(int nodeIndex, int distance)
            {
                if (nodeIndex == endIndex)
                {
                    returnValue = distance;
                }
            }

            Graph.TraverseBreadthFirst(this.Rooms.Count + this.Halls.Count, startIndex, NodeAct, this.GetBreadthFirstAdjacents);

            return(returnValue);
        }
Beispiel #9
0
        public bool IsChokePoint(RoomHallIndex room)
        {
            int roomsHit = 0;
            int hallsHit = 0;

            void NodeAct(RoomHallIndex nodeIndex, int distance)
            {
                if (!nodeIndex.IsHall)
                {
                    roomsHit++;
                }
                else
                {
                    hallsHit++;
                }
            }

            Graph.TraverseBreadthFirst(room, NodeAct, this.GetAdjacents);

            int totalRooms = roomsHit;
            int totalHalls = hallsHit;

            roomsHit = 0;
            hallsHit = 0;
            if (!room.IsHall)
            {
                roomsHit++;
            }
            else
            {
                hallsHit++;
            }

            List <RoomHallIndex> GetChokeAdjacents(RoomHallIndex nodeIndex)
            {
                List <RoomHallIndex> adjacents     = new List <RoomHallIndex>();
                List <RoomHallIndex> roomAdjacents = this.GetRoomHall(nodeIndex).Adjacents;

                // do not add adjacents if we arrive on a room
                // unless it's the first one.
                foreach (RoomHallIndex adjacentRoom in roomAdjacents)
                {
                    // do not count the origin room
                    if (adjacentRoom == room)
                    {
                        continue;
                    }
                    adjacents.Add(adjacentRoom);
                }

                return(adjacents);
            }

            IFloorRoomPlan plan = this.GetRoomHall(room);

            if (plan.Adjacents.Count > 0)
            {
                Graph.TraverseBreadthFirst(plan.Adjacents[0], NodeAct, GetChokeAdjacents);
            }

            return((roomsHit != totalRooms) || (hallsHit != totalHalls));
        }
Beispiel #10
0
        private static Dictionary <Dir4, List <RoomHallIndex> > GetDirectionAdjacents(FloorPlan floorPlan, RoomHallIndex oldRoomHall)
        {
            var            adjacentsByDir = new Dictionary <Dir4, List <RoomHallIndex> >();
            IFloorRoomPlan oldPlan        = floorPlan.GetRoomHall(oldRoomHall);

            foreach (Dir4 dir in DirExt.VALID_DIR4)
            {
                adjacentsByDir[dir] = new List <RoomHallIndex>();
                foreach (RoomHallIndex adjacent in oldPlan.Adjacents)
                {
                    IFloorRoomPlan adjPlan = floorPlan.GetRoomHall(adjacent);
                    if (oldPlan.RoomGen.Draw.GetScalar(dir) ==
                        adjPlan.RoomGen.Draw.GetScalar(dir.Reverse()))
                    {
                        adjacentsByDir[dir].Add(adjacent);
                    }
                }
            }

            return(adjacentsByDir);
        }
Beispiel #11
0
        public override void ApplyToPath(IRandom rand, FloorPlan floorPlan)
        {
            // choose certain rooms in the list to be special rooms
            // special rooms are required; so make sure they don't overlap
            IRoomGen newGen = this.Rooms.Pick(rand).Copy();
            Loc      size   = newGen.ProposeSize(rand);

            newGen.PrepareSize(rand, size);
            int factor = floorPlan.DrawRect.Area / newGen.Draw.Area;

            // TODO: accept smaller rooms to replace
            // bulldozing the surrounding rooms to get the space
            var room_indices = new SpawnList <RoomHallIndex>();

            for (int ii = 0; ii < floorPlan.RoomCount; ii++)
            {
                FloorRoomPlan plan = floorPlan.GetRoomPlan(ii);
                if (!plan.Immutable &&
                    plan.RoomGen.Draw.Width >= newGen.Draw.Width &&
                    plan.RoomGen.Draw.Height >= newGen.Draw.Height)
                {
                    room_indices.Add(new RoomHallIndex(ii, false), ComputeRoomChance(factor, plan.RoomGen.Draw, newGen.Draw));
                }
            }

            for (int ii = 0; ii < floorPlan.HallCount; ii++)
            {
                var            roomHall = new RoomHallIndex(ii, true);
                IFloorRoomPlan plan     = floorPlan.GetRoomHall(roomHall);
                if (plan.RoomGen.Draw.Width >= newGen.Draw.Width &&
                    plan.RoomGen.Draw.Height >= newGen.Draw.Height)
                {
                    room_indices.Add(roomHall, ComputeRoomChance(factor, plan.RoomGen.Draw, newGen.Draw));
                }
            }

            while (room_indices.Count > 0)
            {
                int           ind         = room_indices.PickIndex(rand);
                RoomHallIndex oldRoomHall = room_indices.GetSpawn(ind);
                Dictionary <Dir4, List <RoomHallIndex> > adjacentIndicesByDir = GetDirectionAdjacents(floorPlan, oldRoomHall);
                var adjacentsByDir = new Dictionary <Dir4, List <IRoomGen> >();
                foreach (Dir4 dir in DirExt.VALID_DIR4)
                {
                    adjacentsByDir[dir] = new List <IRoomGen>();
                    foreach (RoomHallIndex adj in adjacentIndicesByDir[dir])
                    {
                        adjacentsByDir[dir].Add(floorPlan.GetRoomHall(adj).RoomGen);
                    }
                }

                Loc placement = this.FindPlacement(rand, adjacentsByDir, newGen, floorPlan.GetRoomHall(oldRoomHall).RoomGen);
                if (placement != new Loc(-1))
                {
                    newGen.SetLoc(placement);
                    this.PlaceRoom(rand, floorPlan, newGen, oldRoomHall);
                    GenContextDebug.DebugProgress("Set Special Room");
                    return;
                }

                room_indices.RemoveAt(ind);
            }
        }
Beispiel #12
0
 public ListPathBranchExpansion(RoomHallIndex from, IRoomGen room, IPermissiveRoomGen hall)
 {
     this.From = from;
     this.Room = room;
     this.Hall = hall;
 }
Beispiel #13
0
        public static void AddLegalPlacements(SpawnList <Loc> possiblePlacements, FloorPlan floorPlan, RoomHallIndex indexFrom, IRoomGen roomFrom, IRoomGen room, Dir4 expandTo)
        {
            bool vertical = expandTo.ToAxis() == Axis4.Vert;

            // this scaling factor equalizes the chances of long sides vs short sides
            int reverseSideMult = vertical ? roomFrom.Draw.Width * room.Draw.Width : roomFrom.Draw.Height * room.Draw.Height;

            IntRange side = roomFrom.Draw.GetSide(expandTo.ToAxis());

            // subtract the room's original size, not the inflated trialrect size
            side.Min -= (vertical ? room.Draw.Size.X : room.Draw.Size.Y) - 1;

            Rect tryRect = room.Draw;

            // expand in every direction
            // this will create a one-tile buffer to check for collisions
            tryRect.Inflate(1, 1);
            int currentScalar = side.Min;

            while (currentScalar < side.Max)
            {
                // compute the location
                Loc trialLoc = roomFrom.GetEdgeRectLoc(expandTo, room.Draw.Size, currentScalar);
                tryRect.Start = trialLoc + new Loc(-1, -1);

                // check for collisions (not counting the rectangle from)
                List <RoomHallIndex> collisions = floorPlan.CheckCollision(tryRect);

                // find the first tile in which no collisions will be found
                int  maxCollideScalar = currentScalar;
                bool collided         = false;
                foreach (RoomHallIndex collision in collisions)
                {
                    if (collision != indexFrom)
                    {
                        IRoomGen collideRoom = floorPlan.GetRoomHall(collision).RoomGen;

                        // this is the point at which the new room will barely touch the collided room
                        // the +1 at the end will move it into the safe zone
                        maxCollideScalar = Math.Max(maxCollideScalar, vertical ? collideRoom.Draw.Right : collideRoom.Draw.Bottom);
                        collided         = true;
                    }
                }

                // if no collisions were hit, do final checks and add the room
                if (!collided)
                {
                    Loc locTo = roomFrom.GetEdgeRectLoc(expandTo, room.Draw.Size, currentScalar);

                    // must be within the borders of the floor!
                    if (floorPlan.DrawRect.Contains(new Rect(locTo, room.Draw.Size)))
                    {
                        // check the border match and if add to possible placements
                        int chanceTo = FloorPlan.GetBorderMatch(roomFrom, room, locTo, expandTo);
                        if (chanceTo > 0)
                        {
                            possiblePlacements.Add(locTo, chanceTo * reverseSideMult);
                        }
                    }
                }

                currentScalar = maxCollideScalar + 1;
            }
        }
Beispiel #14
0
        public void PlaceRoom(IRandom rand, FloorPlan floorPlan, IRoomGen newGen, RoomHallIndex oldRoomHall)
        {
            // first get the adjacents of the removed room
            Dictionary <Dir4, List <RoomHallIndex> > adjacentsByDir = GetDirectionAdjacents(floorPlan, oldRoomHall);
            IRoomPlan oldPlan = floorPlan.GetRoomHall(oldRoomHall);

            // remove the room; update the adjacents too
            floorPlan.EraseRoomHall(oldRoomHall);
            foreach (Dir4 dir in DirExt.VALID_DIR4)
            {
                for (int jj = 0; jj < adjacentsByDir[dir].Count; jj++)
                {
                    RoomHallIndex adjRoomHall = adjacentsByDir[dir][jj];
                    if (adjRoomHall.IsHall == oldRoomHall.IsHall &&
                        adjRoomHall.Index > oldRoomHall.Index)
                    {
                        adjacentsByDir[dir][jj] = new RoomHallIndex(adjRoomHall.Index - 1, adjRoomHall.IsHall);
                    }
                }
            }

            var newAdjacents = new List <RoomHallIndex>();
            var supportHalls = new Dictionary <Dir4, IPermissiveRoomGen>();

            foreach (Dir4 dir in DirExt.VALID_DIR4)
            {
                if (newGen.Draw.GetScalar(dir) == oldPlan.RoomGen.Draw.GetScalar(dir))
                {
                    newAdjacents.AddRange(adjacentsByDir[dir]);
                }
                else if (adjacentsByDir[dir].Count > 0)
                {
                    Rect supportRect = GetSupportRect(floorPlan, oldPlan.RoomGen, newGen, dir, adjacentsByDir[dir]);
                    var  supportHall = (IPermissiveRoomGen)this.Halls.Pick(rand).Copy();
                    supportHall.PrepareSize(rand, supportRect.Size);
                    supportHall.SetLoc(supportRect.Start);
                    supportHalls[dir] = supportHall;
                }
            }

            // add the new room
            var newRoomInd = new RoomHallIndex(floorPlan.RoomCount, false);
            ComponentCollection newCollection = oldPlan.Components.Clone();

            foreach (RoomComponent component in this.RoomComponents)
            {
                newCollection.Set(component.Clone());
            }
            floorPlan.AddRoom(newGen, newCollection, newAdjacents.ToArray());

            // add supporting halls
            foreach (Dir4 dir in DirExt.VALID_DIR4)
            {
                if (supportHalls.ContainsKey(dir))
                {
                    // include an attachment to the newly added room
                    List <RoomHallIndex> adjToAdd = new List <RoomHallIndex> {
                        newRoomInd
                    };
                    adjToAdd.AddRange(adjacentsByDir[dir]);
                    ComponentCollection newHallCollection = oldPlan.Components.Clone();
                    foreach (RoomComponent component in this.HallComponents)
                    {
                        newHallCollection.Set(component.Clone());
                    }
                    floorPlan.AddHall(supportHalls[dir], newHallCollection.Clone(), adjToAdd.ToArray());
                }
            }
        }
Beispiel #15
0
        /// <summary>
        /// Chooses a node to expand the path from based on the specified branch setting.
        /// </summary>
        /// <param name="availableExpansions">todo: describe availableExpansions parameter on ChooseRoomExpansion</param>
        /// <param name="prepareRoom">todo: describe prepareRoom parameter on ChooseRoomExpansion</param>
        /// <param name="hallPercent">todo: describe hallPercent parameter on ChooseRoomExpansion</param>
        /// <param name="rand"></param>
        /// <param name="floorPlan"></param>
        /// <returns>A set of instructions on how to expand the path.</returns>
        public static ListPathBranchExpansion?ChooseRoomExpansion(RoomPrep prepareRoom, int hallPercent, IRandom rand, FloorPlan floorPlan, List <RoomHallIndex> availableExpansions)
        {
            if (availableExpansions.Count == 0)
            {
                return(null);
            }

            for (int ii = 0; ii < 30; ii++)
            {
                // choose the next room to add to
                RoomHallIndex firstExpandFrom = availableExpansions[rand.Next(availableExpansions.Count)];
                RoomHallIndex expandFrom      = firstExpandFrom;
                IRoomGen      roomFrom        = floorPlan.GetRoomHall(firstExpandFrom).RoomGen;

                // choose the next room to add
                // choose room size/fulfillables
                // note: by allowing halls to be picked as extensions, we run the risk of adding dead-end halls
                // halls should always terminate at rooms?
                // this means... doubling up with hall+room?
                bool     addHall = rand.Next(100) < hallPercent;
                IRoomGen hall    = null;
                if (addHall)
                {
                    hall = prepareRoom(rand, floorPlan, true);

                    // randomly choose a perimeter to assign this to
                    SpawnList <Loc> possibleHallPlacements = new SpawnList <Loc>();
                    foreach (Dir4 dir in DirExt.VALID_DIR4)
                    {
                        AddLegalPlacements(possibleHallPlacements, floorPlan, expandFrom, roomFrom, hall, dir);
                    }

                    // at this point, all possible factors for whether a placement is legal or not is accounted for
                    // therefor just pick one
                    if (possibleHallPlacements.Count == 0)
                    {
                        continue;
                    }

                    // randomly choose one
                    Loc hallCandLoc = possibleHallPlacements.Pick(rand);

                    // set location
                    hall.SetLoc(hallCandLoc);

                    // change the roomfrom for the upcoming room
                    expandFrom = new RoomHallIndex(-1, false);
                    roomFrom   = hall;
                }

                IRoomGen room = prepareRoom(rand, floorPlan, false);

                // randomly choose a perimeter to assign this to
                SpawnList <Loc> possiblePlacements = new SpawnList <Loc>();
                foreach (Dir4 dir in DirExt.VALID_DIR4)
                {
                    AddLegalPlacements(possiblePlacements, floorPlan, expandFrom, roomFrom, room, dir);
                }

                // at this point, all possible factors for whether a placement is legal or not is accounted for
                // therefore just pick one
                if (possiblePlacements.Count > 0)
                {
                    // randomly choose one
                    Loc candLoc = possiblePlacements.Pick(rand);

                    // set location
                    room.SetLoc(candLoc);
                    return(new ListPathBranchExpansion(firstExpandFrom, room, (IPermissiveRoomGen)hall));
                }
            }

            return(null);
        }
Beispiel #16
0
 public virtual List <RoomHallIndex> GetAdjacents(RoomHallIndex nodeIndex)
 {
     return(this.GetRoomHall(nodeIndex).Adjacents);
 }
Beispiel #17
0
 public ListPathTraversalNode(RoomHallIndex from, RoomHallIndex to)
 {
     this.From      = from;
     this.To        = to;
     this.Connector = Rect.Empty;
 }
Beispiel #18
0
        public bool IsChokePoint(RoomHallIndex room)
        {
            int roomsHit = 0;
            int hallsHit = 0;

            void NodeAct(int nodeIndex, int distance)
            {
                if (nodeIndex < this.Rooms.Count)
                {
                    roomsHit++;
                }
                else
                {
                    hallsHit++;
                }
            }

            int startIndex = room.Index + (room.IsHall ? this.Rooms.Count : 0);

            Graph.TraverseBreadthFirst(this.Rooms.Count + this.Halls.Count, startIndex, NodeAct, this.GetBreadthFirstAdjacents);

            int totalRooms = roomsHit;
            int totalHalls = hallsHit;

            roomsHit = 0;
            hallsHit = 0;
            if (!room.IsHall)
            {
                roomsHit++;
            }
            else
            {
                hallsHit++;
            }

            List <int> GetChokeAdjacents(int nodeIndex)
            {
                List <int>           adjacents     = new List <int>();
                List <RoomHallIndex> roomAdjacents = new List <RoomHallIndex>();

                // do not add adjacents if we arrive on a room
                // unless it's the first one.
                if (nodeIndex < this.Rooms.Count)
                {
                    roomAdjacents = this.Rooms[nodeIndex].Adjacents;
                }
                else
                {
                    roomAdjacents = this.Halls[nodeIndex - this.Rooms.Count].Adjacents;
                }

                foreach (RoomHallIndex adjacentRoom in roomAdjacents)
                {
                    // do not count the origin room
                    if (adjacentRoom == room)
                    {
                        continue;
                    }
                    if (adjacentRoom.IsHall)
                    {
                        adjacents.Add(adjacentRoom.Index + this.Rooms.Count);
                    }
                    else
                    {
                        adjacents.Add(adjacentRoom.Index);
                    }
                }

                return(adjacents);
            }

            IFloorRoomPlan plan = this.GetRoomHall(room);

            if (plan.Adjacents.Count > 0)
            {
                int adjIndex = plan.Adjacents[0].Index + (plan.Adjacents[0].IsHall ? this.Rooms.Count : 0);

                Graph.TraverseBreadthFirst(this.Rooms.Count + this.Halls.Count, adjIndex, NodeAct, GetChokeAdjacents);
            }

            return((roomsHit != totalRooms) || (hallsHit != totalHalls));
        }
Beispiel #19
0
 public ListPathTraversalNode(RoomHallIndex from, RoomHallIndex to, Rect connector)
 {
     this.From      = from;
     this.To        = to;
     this.Connector = connector;
 }
Beispiel #20
0
        protected static ListPathTraversalNode?GetRoomToConnect(FloorPlan floorPlan, RoomHallIndex chosenFrom, Dir4 dir)
        {
            // extend a rectangle to the border of the floor in the chosen direction
            bool     vertical   = dir.ToAxis() == Axis4.Vert;
            int      dirSign    = dir.GetLoc().GetScalar(dir.ToAxis());
            IRoomGen genFrom    = floorPlan.GetRoomHall(chosenFrom).RoomGen;
            Rect     sampleRect = genFrom.Draw;

            // expand from the start of that border direction to the borders of the floor
            sampleRect.Start += dir.GetLoc() * sampleRect.Size.GetScalar(dir.ToAxis());

            // it doesn't have to be exactly the borders so just add the total size to be sure
            sampleRect.Expand(dir, vertical ? floorPlan.Size.Y : floorPlan.Size.X);

            // find the closest room.
            var chosenTo = new RoomHallIndex(-1, false);

            foreach (RoomHallIndex collision in floorPlan.CheckCollision(sampleRect))
            {
                Rect collidedRect = floorPlan.GetRoomHall(collision).RoomGen.Draw;

                // limit the expansion by direction
                int  sampleScalar   = sampleRect.GetScalar(dir);
                int  collidedScalar = collidedRect.GetScalar(dir.Reverse());
                bool limit          = dirSign == Math.Sign(sampleScalar - collidedScalar);
                if (limit)
                {
                    // update the boundaries
                    sampleRect.SetScalar(dir, collidedScalar);
                    chosenTo = collision;
                }
            }

            // if it didn't collide with ANYTHING, then quit
            if (chosenTo.Index == -1)
            {
                return(null);
            }

            IRoomGen genTo = floorPlan.GetRoomHall(chosenTo).RoomGen;

            // narrow the rectangle if touching something on the side
            // widen the rectangle by width
            Rect widthRect = sampleRect;

            widthRect.Inflate(vertical ? 1 : 0, vertical ? 0 : 1);
            bool retractLeft  = false;
            bool retractRight = false;
            Dir4 leftDir      = DirExt.AddAngles(dir, Dir4.Left);
            Dir4 rightDir     = DirExt.AddAngles(dir, Dir4.Right);

            foreach (RoomHallIndex collision in floorPlan.CheckCollision(widthRect))
            {
                Rect collidedRect = floorPlan.GetRoomHall(collision).RoomGen.Draw;
                if (!retractLeft)
                {
                    if (collidedRect.GetScalar(leftDir.Reverse()) == sampleRect.GetScalar(leftDir))
                    {
                        retractLeft = true;
                    }
                }

                if (!retractRight)
                {
                    if (collidedRect.GetScalar(rightDir.Reverse()) == sampleRect.GetScalar(rightDir))
                    {
                        retractRight = true;
                    }
                }
            }

            // retract the rectangle
            if (retractLeft)
            {
                sampleRect.Expand(leftDir, -1);
            }
            if (retractRight)
            {
                sampleRect.Expand(rightDir, -1);
            }

            // if the rectangle has been retracted too much, we can't go on
            if (sampleRect.Area <= 0)
            {
                return(null);
            }

            // check for border availability between start and end
            bool foundFrom = HasBorderOpening(genFrom, sampleRect, dir);
            bool foundTo   = HasBorderOpening(genTo, sampleRect, dir.Reverse());

            // return the expansion if one is found
            if (foundFrom && foundTo)
            {
                return(new ListPathTraversalNode(chosenFrom, chosenTo, sampleRect));
            }
            else
            {
                return(null);
            }
        }