コード例 #1
0
        public void GetHallTouchRangeLargeRoom(Dir4 dir, int tier, int rangeMin, int rangeMax)
        {
            // a room that takes up multiple cells
            string[] inGrid =
            {
                "A.A.0.0",
                ". . . .",
                "A.A.0.0",
                ". . . .",
                "A.A.0.0",
                ". . . .",
                "0.0.0.0",
            };

            TestGridFloorPlan floorPlan = TestGridFloorPlan.InitGridToContext(inGrid, 6, 4);
            Mock <IRandom>    testRand  = new Mock <IRandom>(MockBehavior.Strict);
            IRoomGen          testGen   = floorPlan.PublicArrayRooms[0].RoomGen;

            testGen.PrepareSize(testRand.Object, new Loc(5, 10));
            testGen.SetLoc(new Loc(1, 2));
            IntRange bounds        = floorPlan.GetHallTouchRange(testGen, dir, tier);
            IntRange compareBounds = new IntRange(rangeMin, rangeMax);

            Assert.That(bounds, Is.EqualTo(compareBounds));
        }
コード例 #2
0
        public static Rect GetSupportRect(FloorPlan floorPlan, IRoomGen oldGen, IRoomGen newGen, Dir4 dir, List <RoomHallIndex> adjacentsInDir)
        {
            bool vertical    = dir.ToAxis() == Axis4.Vert;
            Rect supportRect = newGen.Draw;

            supportRect.Start += dir.GetLoc() * supportRect.Size.GetScalar(dir.ToAxis());
            supportRect.SetScalar(dir, oldGen.Draw.GetScalar(dir));

            IntRange minMax = newGen.Draw.GetSide(dir.ToAxis());

            foreach (RoomHallIndex adj in adjacentsInDir)
            {
                IRoomGen adjGen    = floorPlan.GetRoomHall(adj).RoomGen;
                IntRange adjMinMax = adjGen.Draw.GetSide(dir.ToAxis());
                minMax = new IntRange(Math.Min(adjMinMax.Min, minMax.Min), Math.Max(adjMinMax.Max, minMax.Max));
            }

            IntRange oldMinMax = oldGen.Draw.GetSide(dir.ToAxis());

            minMax = new IntRange(Math.Max(oldMinMax.Min, minMax.Min), Math.Min(oldMinMax.Max, minMax.Max));

            if (vertical)
            {
                supportRect.SetScalar(Dir4.Left, minMax.Min);
                supportRect.SetScalar(Dir4.Right, minMax.Max);
            }
            else
            {
                supportRect.SetScalar(Dir4.Up, minMax.Min);
                supportRect.SetScalar(Dir4.Down, minMax.Max);
            }

            return(supportRect);
        }
コード例 #3
0
        public void GetSupportRectMultiple()
        {
            // the adjacent tile crosses past the border
            TestFloorPlan floorPlan = TestFloorPlan.InitFloorToContext(
                new Loc(22, 14),
                new Rect[] { new Rect(3, 3, 6, 6), new Rect(3, 9, 2, 2), new Rect(7, 9, 2, 2) },
                Array.Empty <Rect>(),
                new Tuple <char, char>[] { Tuple.Create('A', 'B'), Tuple.Create('A', 'C') });

            IRoomGen oldGen = floorPlan.GetRoom(0);

            Mock <IRoomGen> mockTo = new Mock <IRoomGen>(MockBehavior.Strict);

            mockTo.SetupGet(p => p.Draw).Returns(new Rect(5, 3, 2, 2));

            var adjacentsInDir = new List <RoomHallIndex>
            {
                new RoomHallIndex(1, false),
                new RoomHallIndex(2, false),
            };

            Rect rect = AddSpecialRoomTestStep.GetSupportRect(floorPlan, oldGen, mockTo.Object, Dir4.Down, adjacentsInDir);

            Assert.That(rect, Is.EqualTo(new Rect(3, 5, 6, 4)));
        }
コード例 #4
0
        public void GetSupportRect(int x, int y, Dir4 dir, int expectX, int expectY, int expectW, int expectH)
        {
            // the adjacent tile lines up perfectly
            // 2x2 rooms here
            TestFloorPlan floorPlan = TestFloorPlan.InitFloorToContext(
                new Loc(22, 14),
                new Rect[] { new Rect(3, 3, 6, 6), new Rect(5, 9, 2, 2), new Rect(1, 5, 2, 2), new Rect(5, 1, 2, 2), new Rect(9, 5, 2, 2) },
                Array.Empty <Rect>(),
                new Tuple <char, char>[] { Tuple.Create('A', 'B'), Tuple.Create('A', 'C'), Tuple.Create('A', 'D'), Tuple.Create('A', 'E') });

            IRoomGen oldGen = floorPlan.GetRoom(0);

            Mock <IRoomGen> mockTo = new Mock <IRoomGen>(MockBehavior.Strict);

            mockTo.SetupGet(p => p.Draw).Returns(new Rect(x, y, 2, 2));

            var indexLookup = new Dictionary <Dir4, int> {
                { Dir4.Down, 1 }, { Dir4.Left, 2 }, { Dir4.Up, 3 }, { Dir4.Right, 4 }
            };
            var adjacentsInDir = new List <RoomHallIndex> {
                new RoomHallIndex(indexLookup[dir], false)
            };

            Rect rect = AddSpecialRoomTestStep.GetSupportRect(floorPlan, oldGen, mockTo.Object, dir, adjacentsInDir);

            Assert.That(rect, Is.EqualTo(new Rect(expectX, expectY, expectW, expectH)));
        }
コード例 #5
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);
            IRoomGen oldGen = floorPlan.GetRoomHall(oldRoomHall).RoomGen;

            // 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) == oldGen.Draw.GetScalar(dir))
                {
                    newAdjacents.AddRange(adjacentsByDir[dir]);
                }
                else if (adjacentsByDir[dir].Count > 0)
                {
                    Rect supportRect = GetSupportRect(floorPlan, oldGen, 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);

            floorPlan.AddRoom(newGen, true, 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]);
                    floorPlan.AddHall(supportHalls[dir], adjToAdd.ToArray());
                }
            }
        }
コード例 #6
0
 public virtual int GetSideBorderMatch(IRoomGen newGen, Dictionary <Dir4, List <IRoomGen> > adjacentsByDir, Loc loc, Dir4 dir, int matchValue)
 {
     foreach (IRoomGen adj in adjacentsByDir[dir])
     {
         matchValue = Math.Min(matchValue, FloorPlan.GetBorderMatch(adj, newGen, loc, dir.Reverse()));
     }
     return(matchValue);
 }
コード例 #7
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);
        }
コード例 #8
0
        protected override List <Loc> getAllFreeTiles(getOpen func)
        {
            List <Loc> freeTiles = new List <Loc>();

            //get all places that items are eligible
            for (int ii = 0; ii < RoomPlan.RoomCount; ii++)
            {
                IRoomGen room = RoomPlan.GetRoom(ii);

                List <Loc> tiles = func(room.Draw);

                freeTiles.AddRange(tiles);
            }
            return(freeTiles);
        }
コード例 #9
0
        public void AddRoom(Rect rect, IRoomGen gen, ComponentCollection components, bool preferHall)
        {
            Rect floorRect = new Rect(0, 0, this.GridWidth, this.GridHeight);

            if (!floorRect.Contains(rect))
            {
                throw new ArgumentOutOfRangeException(nameof(rect), "Cannot add room out of bounds!");
            }

            for (int xx = rect.Start.X; xx < rect.End.X; xx++)
            {
                for (int yy = rect.Start.Y; yy < rect.End.Y; yy++)
                {
                    if (this.Rooms[xx][yy] != -1)
                    {
                        throw new InvalidOperationException("Tried to add on top of an existing room!");
                    }
                    if (xx > rect.Start.X && this.HHalls[xx - 1][yy].MainHall != null)
                    {
                        throw new InvalidOperationException("Tried to add on top of an existing hall!");
                    }
                    if (yy > rect.Start.Y && this.VHalls[xx][yy - 1].MainHall != null)
                    {
                        throw new InvalidOperationException("Tried to add on top of an existing hall!");
                    }
                }
            }

            if (preferHall && !(gen is IPermissiveRoomGen))
            {
                throw new InvalidOperationException("Cannot prefer hall for a non-permissive gen!");
            }

            var room = new GridRoomPlan(rect, gen.Copy(), components)
            {
                PreferHall = preferHall,
            };

            this.ArrayRooms.Add(room);
            for (int xx = rect.Start.X; xx < rect.End.X; xx++)
            {
                for (int yy = rect.Start.Y; yy < rect.End.Y; yy++)
                {
                    this.Rooms[xx][yy] = this.ArrayRooms.Count - 1;
                }
            }
        }
コード例 #10
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));
                }
            }
        }
コード例 #11
0
ファイル: GridPlan.cs プロジェクト: ejbelt/RogueElements
        /// <summary>
        ///
        /// </summary>
        /// <param name="room"></param>
        /// <param name="dir">Direction from room to hall.</param>
        /// <param name="tier"></param>
        /// <returns></returns>
        public virtual IntRange GetHallTouchRange(IRoomGen room, Dir4 dir, int tier)
        {
            bool vertical = dir.ToAxis() == Axis4.Vert;

            // The hall will touch the entire side of each room under normal circumstances.
            // Things get tricky for a target room that occupies more than one cell.
            // First, try to cover only the part of the target room that's in the cell.
            // If that's not possible, try to extend the hall until it covers one tile of the target room.
            IntRange startRange = room.Draw.GetSide(dir.ToAxis());

            // factor possibletiles into this calculation
            int borderLength = room.GetBorderLength(dir);

            for (int ii = 0; ii < borderLength; ii++)
            {
                if (room.GetFulfillableBorder(dir, ii))
                {
                    startRange.Min += ii;
                    break;
                }
            }

            for (int ii = 0; ii < borderLength; ii++)
            {
                if (room.GetFulfillableBorder(dir, borderLength - 1 - ii))
                {
                    startRange.Max -= ii;
                    break;
                }
            }

            int      tierStart  = vertical ? tier * (this.WidthPerCell + this.CellWall) : tier * (this.HeightPerCell + this.CellWall);
            int      tierLength = vertical ? this.WidthPerCell : this.HeightPerCell;
            IntRange newRange   = new IntRange(Math.Max(startRange.Min, tierStart), Math.Min(startRange.Max, tierStart + tierLength));

            if (newRange.Max <= newRange.Min)
            {
                // try to extend the hall until it covers one tile of the target room.
                // first, note that the current end range is covering the zone between the tier and the edge of the room (inverted)
                // un-invert this and inflate by 1, and you will have a zone that covers 1 tile with the room
                // get the intersection of this zone and the room.
                newRange = new IntRange(Math.Max(startRange.Min, newRange.Max - 1), Math.Min(startRange.Max, newRange.Min + 1));
            }

            return(newRange);
        }
コード例 #12
0
        public void DrawOnMap(ITiledGenContext map)
        {
            GenContextDebug.StepIn("Main Rooms");
            for (int ii = 0; ii < this.Rooms.Count; ii++)
            {
                // take in the broad fulfillables from adjacent rooms that have not yet drawn
                IFloorRoomPlan plan = this.Rooms[ii];
                foreach (RoomHallIndex adj in plan.Adjacents)
                {
                    if (adj.IsHall || adj.Index > ii)
                    {
                        IRoomGen adjacentGen = this.GetRoomHall(adj).RoomGen;
                        plan.RoomGen.ReceiveFulfillableBorder(adjacentGen, GetDirAdjacent(plan.RoomGen, adjacentGen));
                    }
                }

                plan.RoomGen.DrawOnMap(map);
                this.TransferBorderToAdjacents(new RoomHallIndex(ii, false));
                GenContextDebug.DebugProgress("Draw Room");
            }

            GenContextDebug.StepOut();

            GenContextDebug.StepIn("Connecting Halls");
            for (int ii = 0; ii < this.Halls.Count; ii++)
            {
                // take in the broad fulfillables from adjacent rooms that have not yet drawn
                IFloorRoomPlan plan = this.Halls[ii];
                foreach (RoomHallIndex adj in plan.Adjacents)
                {
                    if (adj.IsHall && adj.Index > ii)
                    {
                        IRoomGen adjacentGen = this.GetRoomHall(adj).RoomGen;
                        plan.RoomGen.ReceiveFulfillableBorder(adjacentGen, GetDirAdjacent(plan.RoomGen, adjacentGen));
                    }
                }

                plan.RoomGen.DrawOnMap(map);
                this.TransferBorderToAdjacents(new RoomHallIndex(ii, true));
                GenContextDebug.DebugProgress("Draw Hall");
            }

            GenContextDebug.StepOut();
        }
コード例 #13
0
ファイル: DueSpawnStep.cs プロジェクト: ejbelt/RogueElements
        public override void DistributeSpawns(TGenContext map, List <TSpawnable> spawns)
        {
            // gather up all rooms and put in a spawn list
            // rooms that are farther from the start are more likely to have items
            var spawningRooms = new SpawnList <RoomHallIndex>();

            int[] roomWeights = new int[map.RoomPlan.RoomCount];

            // get the start room
            int startRoom = 0;

            for (int ii = 0; ii < map.RoomPlan.RoomCount; ii++)
            {
                IRoomGen room = map.RoomPlan.GetRoom(ii);
                if (Collision.InBounds(room.Draw, map.GetLoc(0)))
                {
                    startRoom = ii;
                    break;
                }
            }

            int maxVal = 1;

            void NodeAct(int nodeIndex, int distance)
            {
                roomWeights[nodeIndex] = distance + 1;
                maxVal = Math.Max(maxVal, roomWeights[nodeIndex]);
            }

            List <int> GetAdjacents(int nodeIndex) => map.RoomPlan.GetAdjacentRooms(nodeIndex);

            Graph.TraverseBreadthFirst(roomWeights.Length, startRoom, NodeAct, GetAdjacents);

            int multFactor = int.MaxValue / maxVal / roomWeights.Length;

            for (int ii = 0; ii < roomWeights.Length; ii++)
            {
                spawningRooms.Add(new RoomHallIndex(ii, false), roomWeights[ii] * multFactor);
            }

            this.SpawnRandInCandRooms(map, spawningRooms, spawns, this.SuccessPercent);
        }
コード例 #14
0
        protected static bool HasBorderOpening(IRoomGen roomFrom, Rect rectTo, Dir4 expandTo)
        {
            Loc diff   = roomFrom.Draw.Start - rectTo.Start; // how far ahead the start of source is to dest
            int offset = diff.GetScalar(expandTo.ToAxis().Orth());

            // Traverse the region that both borders touch
            int sourceLength = roomFrom.GetBorderLength(expandTo);
            int destLength   = rectTo.Size.GetScalar(expandTo.ToAxis().Orth());

            for (int ii = Math.Max(0, offset); ii - offset < sourceLength && ii < destLength; ii++)
            {
                bool sourceFulfill = roomFrom.GetFulfillableBorder(expandTo, ii - offset);
                if (sourceFulfill)
                {
                    return(true);
                }
            }

            return(false);
        }
コード例 #15
0
        public static Dir4 GetDirAdjacent(IRoomGen roomGenFrom, IRoomGen roomGenTo)
        {
            Dir4 result = Dir4.None;

            foreach (Dir4 dir in DirExt.VALID_DIR4)
            {
                if (roomGenFrom.Draw.GetScalar(dir) == roomGenTo.Draw.GetScalar(dir.Reverse()))
                {
                    if (result == Dir4.None)
                    {
                        result = dir;
                    }
                    else
                    {
                        return(Dir4.None);
                    }
                }
            }

            return(result);
        }
コード例 #16
0
        public override void ApplyToPath(IRandom rand, GridPlan floorPlan)
        {
            IRoomGen newGen = this.Rooms.Pick(rand).Copy();
            Loc      size   = newGen.ProposeSize(rand);

            // choose certain rooms in the list to be special rooms
            // special rooms are required; so make sure they don't overlap
            List <int> room_indices = new List <int>();

            for (int ii = 0; ii < floorPlan.RoomCount; ii++)
            {
                GridRoomPlan plan = floorPlan.GetRoomPlan(ii);
                if (!BaseRoomFilter.PassesAllFilters(plan, this.Filters))
                {
                    continue;
                }
                if (plan.PreferHall)
                {
                    continue;
                }
                Loc boundsSize = GetBoundsSize(floorPlan, plan);
                if (boundsSize.X >= size.X && boundsSize.Y >= size.Y)
                {
                    room_indices.Add(ii);
                }
            }

            if (room_indices.Count > 0)
            {
                int          ind  = rand.Next(room_indices.Count);
                GridRoomPlan plan = floorPlan.GetRoomPlan(room_indices[ind]);
                plan.RoomGen = newGen;
                foreach (RoomComponent component in this.RoomComponents)
                {
                    plan.Components.Set(component.Clone());
                }
                room_indices.RemoveAt(ind);
                GenContextDebug.DebugProgress("Set Special Room");
            }
        }
コード例 #17
0
        public void AddRoom(IRoomGen gen, ComponentCollection components, params RoomHallIndex[] attached)
        {
            // check against colliding on other rooms (and not halls)
            foreach (var room in this.Rooms)
            {
                if (Collision.Collides(room.RoomGen.Draw, gen.Draw))
                {
                    throw new InvalidOperationException("Tried to add on top of an existing room!");
                }
            }

            foreach (var hall in this.Halls)
            {
                if (Collision.Collides(hall.RoomGen.Draw, gen.Draw))
                {
                    throw new InvalidOperationException("Tried to add on top of an existing hall!");
                }
            }

            // check against rooms that go out of bounds
            if (!this.DrawRect.Contains(gen.Draw))
            {
                throw new InvalidOperationException("Tried to add out of range!");
            }

            // we expect that the room has already been given a size
            // and that its fulfillables match up with its adjacent's fulfillables.
            var plan = new FloorRoomPlan(gen, components);

            // attach everything
            plan.Adjacents.AddRange(attached);
            foreach (RoomHallIndex fromRoom in attached)
            {
                IFloorRoomPlan fromPlan = this.GetRoomHall(fromRoom);
                fromPlan.Adjacents.Add(new RoomHallIndex(this.Rooms.Count, false));
            }

            this.Rooms.Add(plan);
        }
コード例 #18
0
        public static int GetBorderMatch(IRoomGen roomFrom, IRoomGen room, Loc candLoc, Dir4 expandTo)
        {
            int totalMatch = 0;

            Loc diff   = roomFrom.Draw.Start - candLoc; // how far ahead the start of source is to dest
            int offset = diff.GetScalar(expandTo.ToAxis().Orth());

            // Traverse the region that both borders touch
            int sourceLength = roomFrom.GetBorderLength(expandTo);
            int destLength   = room.GetBorderLength(expandTo.Reverse());

            for (int ii = Math.Max(0, offset); ii - offset < sourceLength && ii < destLength; ii++)
            {
                bool sourceFulfill = roomFrom.GetFulfillableBorder(expandTo, ii - offset);
                bool destFulfill   = room.GetFulfillableBorder(expandTo.Reverse(), ii);
                if (sourceFulfill && destFulfill)
                {
                    totalMatch++;
                }
            }

            return(totalMatch);
        }
コード例 #19
0
 public void AddRoom(Loc loc, IRoomGen gen, ComponentCollection components, bool preferHall)
 {
     this.AddRoom(new Rect(loc, new Loc(1)), gen, components, preferHall);
 }
コード例 #20
0
        public override void Apply(T map)
        {
            int chosenAmount = Amount.Pick(map.Rand);

            if (chosenAmount > 0)
            {
                SpawnList <int> spawningRooms = new SpawnList <int>();

                //get all places that spawnings are eligible
                for (int ii = 0; ii < map.RoomPlan.RoomCount; ii++)
                {
                    IRoomGen room = map.RoomPlan.GetRoom(ii);

                    if (!BaseRoomFilter.PassesAllFilters(map.RoomPlan.GetRoomPlan(ii), this.Filters))
                    {
                        continue;
                    }

                    spawningRooms.Add(ii, 10000);
                }

                int trials = 10 * chosenAmount;
                for (int ii = 0; ii < trials && chosenAmount > 0; ii++)
                {
                    if (spawningRooms.SpawnTotal == 0)//check to make sure there's still spawn choices left
                    {
                        break;
                    }
                    int  spawnIndex = spawningRooms.PickIndex(map.Rand);
                    int  roomNum    = spawningRooms.GetSpawn(spawnIndex);
                    Team newTeam    = Spawn.GetSpawn(map);
                    if (newTeam == null)
                    {
                        continue;
                    }

                    List <Loc> freeTiles = Grid.FindTilesInBox(map.RoomPlan.GetRoom(roomNum).Draw.Start, map.RoomPlan.GetRoom(roomNum).Draw.Size,
                                                               (Loc testLoc) =>
                    {
                        return(((IGroupPlaceableGenContext <Team>)map).CanPlaceItem(testLoc));
                    });

                    //this actually places the members of the team in random scattered locations, leaving them to group together via wandering
                    if (freeTiles.Count >= newTeam.Players.Count)
                    {
                        Loc[] locs = new Loc[newTeam.Players.Count];
                        for (int jj = 0; jj < newTeam.Players.Count; jj++)
                        {
                            int randIndex = map.Rand.Next(freeTiles.Count);
                            locs[jj] = freeTiles[randIndex];
                            freeTiles.RemoveAt(randIndex);
                        }
                        ((IGroupPlaceableGenContext <Team>)map).PlaceItems(newTeam, locs);
                        chosenAmount--;
                    }

                    if (freeTiles.Count == 0)//if spawningRooms is now impossible there, remove the room entirely
                    {
                        spawningRooms.RemoveAt(spawnIndex);
                    }
                    else //otherwise decrease spawn rate for room
                    {
                        spawningRooms.SetSpawnRate(spawnIndex, Math.Max(spawningRooms.GetSpawnRate(spawnIndex) * ClumpFactor / 100, 1));
                    }
                }
            }
        }
コード例 #21
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);
            }
        }
コード例 #22
0
        public virtual int GetAllBorderMatch(Dictionary <Dir4, List <IRoomGen> > adjacentsByDir, IRoomGen newGen, IRoomGen oldGen, Loc loc)
        {
            // TODO: Currently fails the loc if a single adjacent in a given direction is not met.
            // Perhaps allow the halls to cover the un-met required adjacent
            int matchValue = newGen.Draw.Perimeter;

            if (loc.X == oldGen.Draw.Left)
            {
                matchValue = Math.Min(matchValue, this.GetSideBorderMatch(newGen, adjacentsByDir, loc, Dir4.Left, matchValue));
                if (matchValue == 0)
                {
                    return(0);
                }
            }

            if (loc.X == oldGen.Draw.Right - newGen.Draw.Width)
            {
                matchValue = Math.Min(matchValue, this.GetSideBorderMatch(newGen, adjacentsByDir, loc, Dir4.Right, matchValue));
                if (matchValue == 0)
                {
                    return(0);
                }
            }

            if (loc.Y == oldGen.Draw.Top)
            {
                matchValue = Math.Min(matchValue, this.GetSideBorderMatch(newGen, adjacentsByDir, loc, Dir4.Up, matchValue));
                if (matchValue == 0)
                {
                    return(0);
                }
            }

            if (loc.Y == oldGen.Draw.Bottom - newGen.Draw.Height)
            {
                matchValue = Math.Min(matchValue, this.GetSideBorderMatch(newGen, adjacentsByDir, loc, Dir4.Down, matchValue));
                if (matchValue == 0)
                {
                    return(0);
                }
            }

            return(matchValue);
        }
コード例 #23
0
        public override void ApplyToPath(IRandom rand, FloorPlan floorPlan)
        {
            for (int ii = 0; ii < 10; ii++)
            {
                // always clear before trying
                floorPlan.Clear();

                int tilesToOpen = floorPlan.DrawRect.Area * this.FillPercent.Pick(rand) / 100;
                if (tilesToOpen < 1)
                {
                    tilesToOpen = 1;
                }
                int addBranch = this.BranchRatio.Pick(rand);
                int tilesLeft = tilesToOpen;

                // choose a room
                IRoomGen room = this.PrepareRoom(rand, floorPlan, false);

                // place in a random location
                room.SetLoc(new Loc(
                                rand.Next(floorPlan.DrawRect.Left, floorPlan.DrawRect.Right - room.Draw.Width + 1),
                                rand.Next(floorPlan.DrawRect.Top, floorPlan.DrawRect.Bottom - room.Draw.Height + 1)));
                floorPlan.AddRoom(room, this.RoomComponents.Clone());
                GenContextDebug.DebugProgress("Start Room");

                tilesLeft -= room.Draw.Area;

                // repeat this process until the requisite room amount is met
                int pendingBranch = 0;
                while (tilesLeft > 0)
                {
                    (int area, int rooms)terminalResult = this.ExpandPath(rand, floorPlan, false);
                    (int area, int rooms)branchResult   = (0, 0);
                    if (terminalResult.area > 0)
                    {
                        tilesLeft -= terminalResult.area;

                        // add branch PER ROOM when we add over the min threshold
                        for (int jj = 0; jj < terminalResult.rooms; jj++)
                        {
                            if (floorPlan.RoomCount + floorPlan.HallCount - terminalResult.rooms + jj + 1 > 2)
                            {
                                pendingBranch += addBranch;
                            }
                        }
                    }
                    else if (this.NoForcedBranches)
                    {
                        break;
                    }
                    else
                    {
                        pendingBranch = 100;
                    }

                    while (pendingBranch >= 100 && tilesLeft > 0)
                    {
                        branchResult = this.ExpandPath(rand, floorPlan, true);
                        if (branchResult.area == 0)
                        {
                            break;
                        }
                        pendingBranch -= 100;

                        // if we add any more than one room, that also counts as a branchable node
                        pendingBranch += (branchResult.rooms - 1) * addBranch;
                        tilesLeft     -= branchResult.area;
                    }

                    if (terminalResult.area == 0 && branchResult.area == 0)
                    {
                        break;
                    }
                }

                if (tilesLeft <= 0)
                {
                    break;
                }
            }
        }
コード例 #24
0
        public Loc FindPlacement(IRandom rand, Dictionary <Dir4, List <IRoomGen> > adjacentsByDir, IRoomGen newGen, IRoomGen oldGen)
        {
            SpawnList <Loc> possiblePlacements = this.GetPossiblePlacements(adjacentsByDir, newGen, oldGen);

            return(possiblePlacements.SpawnTotal == 0 ? new Loc(-1) : possiblePlacements.Pick(rand));
        }
コード例 #25
0
        public SpawnList <Loc> GetPossiblePlacements(Dictionary <Dir4, List <IRoomGen> > adjacentsByDir, IRoomGen newGen, IRoomGen oldGen)
        {
            // test all positions around perimeter
            Rect            oldRect            = oldGen.Draw;
            SpawnList <Loc> possiblePlacements = new SpawnList <Loc>();

            // top and bottom
            for (int xx = oldRect.Left; xx < oldRect.Right - newGen.Draw.Width + 1; xx++)
            {
                Loc topLoc   = new Loc(xx, oldRect.Top);
                int topMatch = this.GetAllBorderMatch(adjacentsByDir, newGen, oldGen, topLoc);
                if (topMatch > 0)
                {
                    possiblePlacements.Add(topLoc, topMatch);
                }

                Loc bottomLoc = new Loc(xx, oldRect.Bottom - newGen.Draw.Height);
                if (bottomLoc != topLoc)
                {
                    int bottomMatch = this.GetAllBorderMatch(adjacentsByDir, newGen, oldGen, bottomLoc);
                    if (bottomMatch > 0)
                    {
                        possiblePlacements.Add(bottomLoc, bottomMatch);
                    }
                }
            }

            // left and right
            for (int yy = oldRect.Top + 1; yy < oldRect.Bottom - newGen.Draw.Height; yy++)
            {
                Loc leftLoc   = new Loc(oldRect.Left, yy);
                int leftMatch = this.GetAllBorderMatch(adjacentsByDir, newGen, oldGen, leftLoc);
                if (leftMatch > 0)
                {
                    possiblePlacements.Add(leftLoc, leftMatch);
                }

                Loc rightLoc = new Loc(oldRect.Right - newGen.Draw.Width, yy);
                if (rightLoc != leftLoc)
                {
                    int rightMatch = this.GetAllBorderMatch(adjacentsByDir, newGen, oldGen, rightLoc);
                    if (rightMatch > 0)
                    {
                        possiblePlacements.Add(rightLoc, rightMatch);
                    }
                }
            }

            if (possiblePlacements.SpawnTotal == 0)
            {
                if (oldRect.Width >= newGen.Draw.Width + 2 &&
                    oldRect.Height >= newGen.Draw.Height + 2)
                {
                    for (int xx = oldRect.Left + 1; xx < oldRect.Right - newGen.Draw.Width; xx++)
                    {
                        for (int yy = oldRect.Top + 1; yy < oldRect.Bottom - newGen.Draw.Height; yy++)
                        {
                            possiblePlacements.Add(new Loc(xx, yy), 1);
                        }
                    }
                }
            }

            return(possiblePlacements);
        }
コード例 #26
0
 public ListPathBranchExpansion(RoomHallIndex from, IRoomGen room, IPermissiveRoomGen hall)
 {
     this.From = from;
     this.Room = room;
     this.Hall = hall;
 }
コード例 #27
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;
            }
        }
コード例 #28
0
        /// <summary>
        /// Gets the minimum range along the side of a room that includes all of its fulfillable borders.
        /// Special cases arise if the room is multi-cell.
        /// </summary>
        /// <param name="room"></param>
        /// <param name="dir">Direction from room to hall.</param>
        /// <param name="tier"></param>
        /// <returns></returns>
        public virtual IntRange GetHallTouchRange(IRoomGen room, Dir4 dir, int tier)
        {
            bool vertical = dir.ToAxis() == Axis4.Vert;

            // The hall will touch the whole fulfillable side of each room under normal circumstances.
            // Things get tricky for a target room that occupies more than one cell.
            // First, try to cover only the part of the target room that's in the cell.
            int      tierStart  = vertical ? tier * (this.WidthPerCell + this.CellWall) : tier * (this.HeightPerCell + this.CellWall);
            int      tierLength = vertical ? this.WidthPerCell : this.HeightPerCell;
            IntRange tierRange  = new IntRange(tierStart, tierStart + tierLength);
            IntRange roomRange  = room.Draw.GetSide(dir.ToAxis());

            // factor possibletiles into this calculation
            int borderStart = tierStart - roomRange.Min;

            if (borderStart < 0)
            {
                tierRange.Min -= borderStart;
                borderStart    = 0;
            }

            for (int ii = borderStart; ii < roomRange.Length; ii++)
            {
                if (room.GetFulfillableBorder(dir, ii))
                {
                    break;
                }
                else
                {
                    tierRange.Min += 1;
                }
            }

            int borderEnd = tierStart + tierLength - roomRange.Min;

            if (borderEnd > roomRange.Length)
            {
                tierRange.Max += roomRange.Length - borderEnd;
                borderEnd      = roomRange.Length;
            }

            for (int ii = borderEnd - 1; ii >= 0; ii--)
            {
                if (room.GetFulfillableBorder(dir, ii))
                {
                    break;
                }
                else
                {
                    tierRange.Max -= 1;
                }
            }

            if (tierRange.Max > tierRange.Min)
            {
                return(tierRange);
            }

            // If that's not possible, then it means that the room must have fulfillable tiles outside of the current bound.
            // Try to extend the hall until it covers one fulfillable tile of the target room.
            // Easy method: note that the current tierRange range is covering the zone between the tier and the edge of the room (inverted)
            // There will be either a workable range at the start or a workable range at the end, never neither.
            IntRange startRange = new IntRange(tierRange.Max - 1, tierStart + 1);
            IntRange endRange   = new IntRange(tierStart + tierLength - 1, tierRange.Min + 1);

            bool chooseStart = true;
            bool chooseEnd   = true;

            // if tierRanges reached the absolute limits of the roomRange, then there is no fulfillable tile on that side
            if (startRange.Min < roomRange.Min)
            {
                chooseStart = false;
            }
            else if (endRange.Length > startRange.Length)
            {
                chooseEnd = false;
            }

            if (endRange.Max > roomRange.Max)
            {
                chooseEnd = false;
            }
            else if (startRange.Length > endRange.Length)
            {
                chooseStart = false;
            }

            if (!chooseStart && !chooseEnd)
            {
                throw new ArgumentException("PrepareFulfillableBorders did not open at least one open tile for each direction!");
            }

            if (chooseStart)
            {
                return(startRange);
            }
            return(endRange);
        }
コード例 #29
0
 public void AddRoom(Loc loc, IRoomGen gen, ComponentCollection components)
 {
     this.AddRoom(new Rect(loc, new Loc(1)), gen, components, false);
 }
コード例 #30
0
 public void AddRoom(Rect rect, IRoomGen gen, ComponentCollection components)
 {
     this.AddRoom(rect, gen, components, false);
 }