Example #1
0
        private void AddRoomEdgeConnectors(Connector connector, Rect edge, Direction dir)
        {
            bool skip = Rng.OneIn(2);

            foreach (Vec pos in edge)
            {
                // don't place connectors close to the incoming connector
                if (connector != null)
                {
                    if (Vec.IsDistanceWithin(connector.Position, pos, 1))
                    {
                        continue;
                    }
                }

                if (!skip && (Rng.Int(100) < mWriter.Options.ChanceOfRoomConnector))
                {
                    mWriter.AddRoomConnector(pos, dir);
                    skip = true;
                }
                else
                {
                    skip = false;
                }
            }
        }
Example #2
0
        protected override bool WillUseMove(Monster monster, Entity target, BreedMoveInfo info)
        {
            // the odds of breeding decays exponentially
            int chance = info.Generation * info.Generation;

            // random chance to breed
            return(Rng.OneIn(chance));
        }
Example #3
0
        /// <summary>
        /// Tries to find a tile reachable from the starting tile that has as few items as possible.
        /// </summary>
        /// <param name="startPos"></param>
        /// <returns></returns>
        public Vec GetOpenItemPosition(Vec startPos)
        {
            Vec currentPos = startPos;

            bool changed = true;

            while (changed)
            {
                int currentCount = Items.CountAt(currentPos);
                changed = false;

                // short-circuit if we hit an empty tile
                if (currentCount == 0)
                {
                    break;
                }

                int found   = 0;
                Vec fromPos = currentPos;
                foreach (Direction dir in Direction.Clockwise)
                {
                    Vec pos = fromPos + dir;

                    // make sure it's a valid tile
                    if (Bounds.Contains(pos) && Tiles[pos].IsPassable)
                    {
                        int count = Items.CountAt(pos);

                        // if we found a square just as good, randomly choose between
                        // it and all of the previously found ones in this loop
                        if ((count == currentCount) && (found > 0))
                        {
                            if (Rng.OneIn(found + 1))
                            {
                                // pick this new one
                                currentCount++;
                            }
                            else
                            {
                                // still consider it found even if it was skipped
                                found++;
                            }
                        }

                        if (count < currentCount)
                        {
                            found++;
                            currentPos   = pos;
                            currentCount = count;
                            changed      = true;
                        }
                    }
                }
            }

            return(currentPos);
        }
Example #4
0
        public void Init(Content content)
        {
            // add the buildings
            List <Rect> maxSizes = new List <Rect>();

            // see if it's a horizontal or vertical layout
            if (Rng.OneIn(2))
            {
                // horizontal
                Vec maxSize = new Vec(Bounds.Width / 3, Bounds.Height / 2);

                maxSizes.Add(new Rect(Bounds.Left, Bounds.Top, maxSize).Inflate(-2));
                maxSizes.Add(new Rect(Bounds.Left + maxSize.X, Bounds.Top, maxSize).Inflate(-2));
                maxSizes.Add(new Rect(Bounds.Left + maxSize.X + maxSize.X, Bounds.Top, maxSize).Inflate(-2));
                maxSizes.Add(new Rect(Bounds.Left, Bounds.Top + maxSize.Y, maxSize).Inflate(-2));
                maxSizes.Add(new Rect(Bounds.Left + maxSize.X, Bounds.Top + maxSize.Y, maxSize).Inflate(-2));
                maxSizes.Add(new Rect(Bounds.Left + maxSize.X + maxSize.X, Bounds.Top + maxSize.Y, maxSize).Inflate(-2));
            }
            else
            {
                // vertical
                Vec maxSize = new Vec(Bounds.Width / 2, Bounds.Height / 3);

                maxSizes.Add(new Rect(Bounds.Left, Bounds.Top, maxSize).Inflate(-2));
                maxSizes.Add(new Rect(Bounds.Left + maxSize.X, Bounds.Top, maxSize).Inflate(-2));
                maxSizes.Add(new Rect(Bounds.Left, Bounds.Top + maxSize.Y, maxSize).Inflate(-2));
                maxSizes.Add(new Rect(Bounds.Left + maxSize.X, Bounds.Top + maxSize.Y, maxSize).Inflate(-2));
                maxSizes.Add(new Rect(Bounds.Left, Bounds.Top + maxSize.Y + maxSize.Y, maxSize).Inflate(-2));
                maxSizes.Add(new Rect(Bounds.Left + maxSize.X, Bounds.Top + maxSize.Y + maxSize.Y, maxSize).Inflate(-2));
            }

            InitBuildings(content, maxSizes);

            // add the down stairs
            bool foundOpen = false;

            while (!foundOpen)
            {
                mStairsPos = Rng.Vec(Bounds.Inflate(-1));

                foundOpen = true;

                foreach (Building building in mBuildings)
                {
                    // see if the stairs are overlapping a building
                    if (building.Bounds.Contains(mStairsPos))
                    {
                        foundOpen = false;
                        break;
                    }
                }
            }
        }
Example #5
0
        public override Action NextAction()
        {
            Entity target   = Monster.Dungeon.Game.Hero;
            Vec    distance = target.Position - Monster.Position;

            // wake up or fall asleep
            if (!mIsAwake)
            {
                // if close enough to the hero, attempt to wake up
                if ((distance.KingLength < WakeUpDistance) && Rng.OneIn(WakeUpChance))
                {
                    WakeUp();
                }
            }
            else
            {
                // if far enough, try to fall back asleep
                if ((distance.KingLength > FallAsleepDistance) && Rng.OneIn(FallAsleepChance))
                {
                    FallAsleep();
                }
            }

            if (mIsAwake)
            {
                // consider performing a move
                foreach (Move move in Monster.Race.Moves)
                {
                    // see if it's possible and the odds match
                    if (move.WillUseMove(Monster, target) && move.ShouldAttempt())
                    {
                        // use this move
                        return(move.GetAction(Monster, target));
                    }
                }

                // walk
                Direction direction = mPathfinder.GetDirection(Monster, target);

                return(new WalkAction(Monster, direction));
            }

            // otherwise, just stand still
            return(new WalkAction(Monster, Direction.None));
        }
Example #6
0
        /// <summary>
        /// Randomly walks the given level using a... unique distribution. The
        /// goal is to return a value that approximates a bell curve centered
        /// on the start level whose wideness increases as the level increases.
        /// Thus, starting at a low start level will only walk a short distance,
        /// while starting at a higher level can wander a lot farther.
        /// </summary>
        /// <returns></returns>
        public static int WalkLevel(int level)
        {
            int result = level;

            // stack a few triangles to approximate a bell
            for (int i = 0; i < Math.Min(5, level); i++)
            {
                // the width of the triangle is based on the level
                result += Rng.TriangleInt(0, 1 + (level / 20));
            }

            // also have an exponentially descreasing change of going out of depth
            while (Rng.OneIn(10))
            {
                result += 1 + Rng.Int(2 + (level / 5));
            }

            return(result);
        }
Example #7
0
        /// <summary>
        /// Chooses a random item of the given level from the set of items that
        /// match the given predicate.
        /// </summary>
        protected T Random(int level, Func <T, bool> predicate)
        {
            // exponential chance of reducing the chosen level
            while ((level > 1) && Rng.OneIn(3))
            {
                level--;
            }

            // chance of increasing the chosen level
            while ((level <= Game.MaxDepth) && Rng.OneIn(5))
            {
                level++;
            }

            // choose a matching item from the level
            return(Random((rareObj) =>
                          (rareObj.MinLevel <= level) &&
                          (rareObj.MaxLevel >= level) &&
                          predicate(rareObj.Object)));
        }
Example #8
0
        /// <summary>
        /// Randomly walks the given starting value repeatedly up and/or down
        /// with the given probabilities. Will only walk in one direction.
        /// </summary>
        /// <param name="start">Value to start at.</param>
        public static int Walk(int start, int chanceOfDec, int chanceOfInc)
        {
            // make sure we won't get stuck in an infinite loop
            if (chanceOfDec == 1)
            {
                throw new ArgumentOutOfRangeException("chanceOfDec must be zero or greater than one.");
            }
            if (chanceOfInc == 1)
            {
                throw new ArgumentOutOfRangeException("chanceOfInc must be zero greater than one.");
            }

            // decide if walking up or down
            int direction = Int(chanceOfDec + chanceOfInc);

            if (direction < chanceOfDec)
            {
                // exponential chance of decrementing
                int sanity = 10000;
                while (Rng.OneIn(chanceOfDec) && (sanity-- > 0))
                {
                    start--;
                }
            }
            else if (direction < chanceOfDec + chanceOfInc)
            {
                // exponential chance of incrementing
                int sanity = 10000;
                while (Rng.OneIn(chanceOfInc) && (sanity-- > 0))
                {
                    start++;
                }
            }

            return(start);
        }
Example #9
0
        public void AddLoops(int chance)
        {
            if (chance > 0)
            {
                foreach (Vec cell in new Rect(0, 0, Bounds.Width - 1, Bounds.Height - 1))
                {
                    if (Rng.OneIn(chance))
                    {
                        if (IsOpen(cell) && IsOpen(cell + Direction.E))
                        {
                            Carve(cell, Direction.E);
                        }
                    }

                    if (Rng.OneIn(chance))
                    {
                        if (IsOpen(cell) && IsOpen(cell + Direction.S))
                        {
                            Carve(cell, Direction.S);
                        }
                    }
                }
            }
        }
        public Direction GetDirection(Monster monster, Entity target)
        {
            Vec relative = target.Position - monster.Position;

            // walk towards player
            Direction direction = Direction.Towards(relative);

            // move erratically
            switch (mPursue)
            {
            case Pursue.Closely:
                // do nothing
                break;

            case Pursue.SlightlyErratically:
                while (Rng.OneIn(3))
                {
                    if (Rng.OneIn(2))
                    {
                        direction = direction.Next;
                    }
                    else
                    {
                        direction = direction.Previous;
                    }
                }
                break;

            case Pursue.Erratically:
                while (Rng.OneIn(2))
                {
                    if (Rng.OneIn(2))
                    {
                        direction = direction.Next;
                    }
                    else
                    {
                        direction = direction.Previous;
                    }
                }
                break;

            case Pursue.VeryErratically:
                int turns = Rng.Int(3);
                for (int i = 0; i < turns; i++)
                {
                    if (Rng.OneIn(2))
                    {
                        direction = direction.Next;
                    }
                    else
                    {
                        direction = direction.Previous;
                    }
                }
                break;
            }

            // don't walk through walls
            if (!monster.CanMove(direction) || monster.IsOccupiedByOtherMonster(direction.Offset, target))
            {
                // try to go around obstacle
                Direction firstTry  = direction.Previous;
                Direction secondTry = direction.Next;

                // don't always try the same order
                if (Rng.OneIn(2))
                {
                    Obj.Swap(ref firstTry, ref secondTry);
                }

                if (monster.CanMove(firstTry) && !monster.IsOccupiedByOtherMonster(firstTry.Offset, target))
                {
                    direction = firstTry;
                }
                else if (monster.CanMove(secondTry) && !monster.IsOccupiedByOtherMonster(secondTry.Offset, target))
                {
                    direction = secondTry;
                }
                else
                {
                    // give up
                    direction = Direction.None;
                }
            }

            return(direction);
        }
Example #11
0
        private bool MakeMaze(Connector connector)
        {
            // in maze units (i.e. thin walls), not tiles
            int width  = Rng.Int(mWriter.Options.MazeSizeMin, mWriter.Options.MazeSizeMax);
            int height = Rng.Int(mWriter.Options.MazeSizeMin, mWriter.Options.MazeSizeMax);

            int  tileWidth  = width * 2 + 3;
            int  tileHeight = height * 2 + 3;
            Rect bounds     = CreateRectRoom(connector, tileWidth, tileHeight);

            // bail if we failed
            if (bounds == Rect.Empty)
            {
                return(false);
            }

            // the hallway around the maze
            foreach (Vec pos in bounds.Trace())
            {
                mWriter.SetTile(pos, TileType.Floor);
            }

            // sometimes make the walls low
            if (Rng.OneIn(2))
            {
                foreach (Vec pos in bounds.Inflate(-1))
                {
                    mWriter.SetTile(pos, TileType.LowWall);
                }
            }

            // add an opening in one corner
            Vec doorway;

            switch (Rng.Int(8))
            {
            case 0: doorway = bounds.TopLeft.Offset(2, 1); break;

            case 1: doorway = bounds.TopLeft.Offset(1, 2); break;

            case 2: doorway = bounds.TopRight.Offset(-3, 1); break;

            case 3: doorway = bounds.TopRight.Offset(-2, 2); break;

            case 4: doorway = bounds.BottomRight.Offset(-3, -2); break;

            case 5: doorway = bounds.BottomRight.Offset(-2, -3); break;

            case 6: doorway = bounds.BottomLeft.Offset(2, -2); break;

            case 7: doorway = bounds.BottomLeft.Offset(1, -3); break;

            default: throw new Exception();
            }
            PlaceDoor(doorway);

            // carve the maze
            Maze maze = new Maze(width, height);

            maze.GrowTree();

            Vec offset = bounds.Position.Offset(1, 1);

            maze.Draw(pos => mWriter.SetTile(pos + offset, TileType.Floor));

            mWriter.LightRect(bounds, mDepth);

            // populate it
            int boostedDepth = mDepth + Rng.Int(mDepth / 5) + 2;

            Populate(bounds.Inflate(-2), 200, 300, boostedDepth);

            // place the connectors
            AddRoomConnectors(connector, bounds);

            return(true);
        }
Example #12
0
        private bool MakeJunction(Connector connector)
        {
            // create a random junction
            Vec center = connector.Position + connector.Direction;

            bool left     = false;
            bool right    = false;
            bool straight = false;

            int choice = Rng.Int(100);

            if (choice < mWriter.Options.ChanceOfTurn)
            {
                if (Rng.OneIn(2))
                {
                    left = true;
                }
                else
                {
                    right = true;
                }
            }
            else if (choice - mWriter.Options.ChanceOfTurn < mWriter.Options.ChanceOfFork)
            {
                if (Rng.OneIn(2))
                {
                    left = true;
                }
                else
                {
                    right = true;
                }
                straight = true;
            }
            else if (choice - mWriter.Options.ChanceOfTurn
                     - mWriter.Options.ChanceOfFork < mWriter.Options.ChanceOfTee)
            {
                left  = true;
                right = true;
            }
            else if (choice - mWriter.Options.ChanceOfTurn
                     - mWriter.Options.ChanceOfFork
                     - mWriter.Options.ChanceOfTee < mWriter.Options.ChanceOfFourWay)
            {
                left     = true;
                right    = true;
                straight = true;
            }
            else
            {
                straight = true;
            }

            // check to see if we can place it
            Rect rect = new Rect(center.Offset(-1, -1), 3, 3);

            if (!mWriter.IsOpen(rect, center + connector.Direction.Rotate180))
            {
                return(false);
            }

            // place the junction
            mWriter.SetTile(center, TileType.Floor);

            // add the connectors
            if (left)
            {
                mWriter.AddRoomConnector(center + connector.Direction.RotateLeft90, connector.Direction.RotateLeft90);
            }
            if (right)
            {
                mWriter.AddRoomConnector(center + connector.Direction.RotateRight90, connector.Direction.RotateRight90);
            }
            if (straight)
            {
                mWriter.AddRoomConnector(center + connector.Direction, connector.Direction);
            }

            return(true);
        }