Example #1
0
        /// <summary>
        /// Rolls the dice, returning the sum.
        /// </summary>
        /// <param name="rng">The RNG to use for rolling,</param>
        /// <returns>The sum of the roll.</returns>
        public int GetResult(IEnhancedRandom rng)
        {
            _diceResults.Clear();
            var sum = 0;

            LastMultiplicity = Multiplicity.GetResult(rng);
            LastSidedness    = Sides.GetResult(rng);

            if (LastMultiplicity < 0)
            {
                throw new InvalidMultiplicityException();
            }

            if (LastSidedness <= 0)
            {
                throw new ImpossibleDieException();
            }

            for (var i = 0; i < LastMultiplicity; i++)
            {
                var diceVal = rng.NextInt(1, LastSidedness + 1);
                sum += diceVal;
                _diceResults.Add(diceVal);
            }

            return(sum);
        }
Example #2
0
        private static int GetDirectionIndex(bool[] validDirections, IEnhancedRandom rng)
        {
            // 10 tries to find random ok valid
            var randomSuccess      = false;
            var tempDirectionIndex = 0;

            for (var randomCounter = 0; randomCounter < 10; randomCounter++)
            {
                tempDirectionIndex = rng.NextInt(4);
                if (!validDirections[tempDirectionIndex])
                {
                    continue;
                }

                randomSuccess = true;
                break;
            }

            if (randomSuccess)
            {
                return(tempDirectionIndex);
            }

            // Couldn't find an active valid, so just run through each one
            if (validDirections[0])
            {
                tempDirectionIndex = 0;
            }
            else if (validDirections[1])
            {
                tempDirectionIndex = 1;
            }
            else if (validDirections[2])
            {
                tempDirectionIndex = 2;
            }
            else
            {
                tempDirectionIndex = 3;
            }

            return(tempDirectionIndex);
        }
Example #3
0
        /// <inheritdoc />
        protected override IEnumerator <object?> OnPerform(GenerationContext context)
        {
            // Validate configuration
            if (MinRooms > MaxRooms)
            {
                throw new InvalidConfigurationException(this, nameof(MinRooms),
                                                        $"The value must be less than or equal to the value of {nameof(MaxRooms)}.");
            }

            if (RoomMinSize > RoomMaxSize)
            {
                throw new InvalidConfigurationException(this, nameof(RoomMinSize),
                                                        $"The value must be less than or equal to the value of ${nameof(RoomMaxSize)}.");
            }

            if (RoomSizeRatioX <= 0f)
            {
                throw new InvalidConfigurationException(this, nameof(RoomSizeRatioX),
                                                        "The value must be greater than 0.");
            }

            if (RoomSizeRatioY <= 0f)
            {
                throw new InvalidConfigurationException(this, nameof(RoomSizeRatioY),
                                                        "The value must be greater than 0.");
            }

            // Get or create/add a wall-floor context component
            var wallFloorContext = context.GetFirstOrNew <ISettableGridView <bool> >(
                () => new ArrayView <bool>(context.Width, context.Height),
                WallFloorComponentTag
                );

            // Determine how many rooms to generate
            var roomCounter = RNG.NextInt(MinRooms, MaxRooms + 1);

            // Get or create/add a rooms context component
            var roomsContext = context.GetFirstOrNew(
                () => new ItemList <Rectangle>(roomCounter),
                RoomsComponentTag
                );

            // Try to place all the rooms
            while (roomCounter != 0)
            {
                var tryCounterCreate = MaxCreationAttempts;
                var placed           = false;

                // Attempt to create the room until either we reach max attempts or we create and place a room in a valid location
                while (tryCounterCreate != 0)
                {
                    var roomSize = RNG.NextInt(RoomMinSize, RoomMaxSize + 1);
                    var width    =
                        (int)(roomSize * RoomSizeRatioX); // This helps with non square fonts. So rooms don't look odd
                    var height = (int)(roomSize * RoomSizeRatioY);

                    // When accounting for font ratios, these adjustments help prevent all rooms
                    // having the same looking square format
                    var adjustmentBase = roomSize / 4;

                    if (adjustmentBase != 0)
                    {
                        var adjustment       = RNG.NextInt(-adjustmentBase, adjustmentBase + 1);
                        var adjustmentChance = RNG.NextInt(0, 2);

                        if (adjustmentChance == 0)
                        {
                            width += (int)(adjustment * RoomSizeRatioX);
                        }
                        else if (adjustmentChance == 1)
                        {
                            height += (int)(adjustment * RoomSizeRatioY);
                        }
                    }

                    width  = Math.Max(RoomMinSize, width);
                    height = Math.Max(RoomMinSize, height);

                    // Keep room interior odd, helps with placement + tunnels around the outside.
                    if (width % 2 == 0)
                    {
                        width += 1;
                    }

                    if (height % 2 == 0)
                    {
                        height += 1;
                    }

                    var roomInnerRect = new Rectangle(0, 0, width, height);

                    var tryCounterPlace = MaxPlacementAttempts;

                    // Try to place the room we've created until either it doesn't intersect any other rooms, or we reach max retries (in which case, we will scrap the room entirely, create a new one, and try again)
                    while (tryCounterPlace != 0)
                    {
                        int xPos = 0, yPos = 0;

                        // Generate the rooms at odd positions, to make door/tunnel placement easier
                        while (xPos % 2 == 0)
                        {
                            xPos = RNG.NextInt(3, wallFloorContext.Width - roomInnerRect.Width - 3);
                        }
                        while (yPos % 2 == 0)
                        {
                            yPos = RNG.NextInt(3, wallFloorContext.Height - roomInnerRect.Height - 3);
                        }

                        // Record a rectangle for the inner and outer bounds of the room we've created
                        roomInnerRect = roomInnerRect.WithPosition(new Point(xPos, yPos));
                        var roomBounds = roomInnerRect.Expand(3, 3);

                        // Check if the room intersects with any floor tile on the map already.  We do it this way instead of checking against only the rooms list
                        // to ensure that if some other map generation step placed things before we did, we don't intersect those.
                        var intersected = false;
                        foreach (var point in roomBounds.Positions())
                        {
                            if (wallFloorContext[point])
                            {
                                intersected = true;
                                break;
                            }
                        }

                        // If we intersected floor tiles, try to place the room again
                        if (intersected)
                        {
                            tryCounterPlace--;
                            continue;
                        }

                        // Once we place it in a valid location, update the wall/floor context, and add the room to the list of rooms.
                        foreach (var point in roomInnerRect.Positions())
                        {
                            wallFloorContext[point] = true;
                        }

                        placed = true;
                        roomsContext.Add(roomInnerRect, Name);
                        break;
                    }

                    if (placed)
                    {
                        yield return(null);

                        break;
                    }

                    tryCounterCreate--;
                }

                roomCounter--;
            }
        }