GenerateMap() 공개 메소드

Generates a map based on the maplet assigned
public GenerateMap ( int parentTileID, int parentWallID, Maplet maplet, bool preferSides, string actorType, OwningFactions owner, Actor &actors, MapletActorWanderArea &wAreas, MapletPatrolPoint &patrolRoutes, MapletFootpathNode &footpathNodes ) : ].MapBlock[
parentTileID int The ID of the tiles used in the parent maplet item
parentWallID int The wall that the parent has
maplet DRObjects.LocalMapGeneratorObjects.Maplet The maplet to generate
preferSides bool
actorType string The type of actors to generate
owner OwningFactions The owner of the map. Any maplet items which don't belong will be hidden
actors DRObjects.Actor The actors which we have generated
wAreas DRObjects.LocalMapGeneratorObjects.MapletActorWanderArea
patrolRoutes DRObjects.LocalMapGeneratorObjects.MapletPatrolPoint
footpathNodes DRObjects.LocalMapGeneratorObjects.MapletFootpathNode
리턴 ].MapBlock[
예제 #1
0
        /// <summary>
        /// Generates a site
        /// </summary>
        /// <param name="siteType"></param>
        /// <param name="biomeType"></param>
        /// <param name="owner"></param>
        /// <param name="startPoint"></param>
        /// <param name="actors"></param>
        /// <returns></returns>
        public static MapBlock[,] GenerateSite(SiteData siteData, out Actor[] actors)
        {
            MapCoordinate startPoint = null;

            //First we generate some empty wilderness of the right type
            MapBlock[,] map = WildernessGenerator.GenerateMap(siteData.Biome, 0, 0, out actors, out startPoint);

            //Now, clear the tiles from between 5,5 till 25,25
            for (int x = 5; x < 26; x++)
            {
                for (int y = 5; y < 26; y++)
                {
                    MapBlock block = map[x, y];
                    block.RemoveAllItems();
                }
            }

            ItemFactory.ItemFactory itemFactory = new ItemFactory.ItemFactory();

            int waterID = 0;

            MapItem waterTile = itemFactory.CreateItem(Archetype.TILES, "water", out waterID);

            //If it's a fishing village, put some water in
            if (siteData.SiteTypeData.SiteType == SiteType.FISHING_VILLAGE)
            {
                for (int x = 0; x < map.GetLength(0); x++)
                {
                    for (int y = map.GetLength(1) - 10; y < map.GetLength(1); y++)
                    {
                        MapBlock block = map[x, y];
                        block.RemoveAllItems();

                        //Set the tile to water
                        block.Tile = itemFactory.CreateItem("tiles", waterID);
                        block.Tile.Coordinate = new MapCoordinate(x, y, 0, MapType.LOCAL);
                    }
                }
            }

            LocalMapGenerator lmg = new LocalMapGenerator();

            LocalMapXMLParser parser = new LocalMapXMLParser();

            Maplet maplet = parser.ParseMapletFromTag(siteData.SiteTypeData.SiteType.ToString().Replace("_", " ").ToLower(),siteData.Biome);

            var tileID = DatabaseHandling.GetItemIdFromTag(Archetype.TILES, WildernessGenerator.details[siteData.Biome].BaseTileTag);

            MapletActorWanderArea[] wanderAreas = null;
            MapletPatrolPoint[] patrolPoints = null;
            MapletFootpathNode[] footPath = null;

            //Now generate the actual map
            MapBlock[,] siteMap = lmg.GenerateMap(tileID, null, maplet, false, "", siteData.Owners, out actors, out wanderAreas, out patrolPoints, out footPath);

            //Now lets fuse the maps
            map = lmg.JoinMaps(map, siteMap, 5, 5);

            foreach (var actor in actors)
            {
                if (actor.CurrentMission == null)
                {
                    actor.CurrentMission = actor.MissionStack.Count > 0 ? actor.MissionStack.Pop() : null;
                }

                if (actor.CurrentMission != null && actor.CurrentMission.GetType() == typeof(WanderMission))
                {
                    WanderMission wMiss = actor.CurrentMission as WanderMission;

                    wMiss.WanderPoint.X += 5;
                    wMiss.WanderPoint.Y += 5;

                    wMiss.WanderRectangle = new Rectangle(wMiss.WanderRectangle.X + 5, wMiss.WanderRectangle.Y + 5, wMiss.WanderRectangle.Width, wMiss.WanderRectangle.Height);
                }
            }

            //Fix the patrol points

            foreach (var point in patrolPoints)
            {
                point.Point.X += 5;
                point.Point.Y += 5;
            }

            //Let's fix the patrol points, we need to merge them into PatrolRoutes
            var patrolRoutes = PatrolRoute.GetPatrolRoutes(patrolPoints);

            foreach (var area in wanderAreas)
            {
                area.WanderRect = new Rectangle(area.WanderRect.X + 5, area.WanderRect.Y + 5, area.WanderRect.Width, area.WanderRect.Height);
            }

            //And fix the path nodes
            foreach (var pn in footPath)
            {
                pn.Point.X += 5;
                pn.Point.Y += 5;
            }

            //If the map already has any actors in it, make the characters prone
            foreach (var actor in actors)
            {
                actor.IsProne = true;
            }

            //Now generate the pathfinding map
            PathfinderInterface.Nodes = GeneratePathfindingMap(map);

            int pathTileID = -1;

            var dummy = itemFactory.CreateItem(Archetype.TILES, "stone", out pathTileID);

            //Go through each footpath node. Attempt to connect the node with the other primary nodes
            foreach (var fp in footPath)
            {
                foreach (var primary in footPath.Where(p => p.IsPrimary))
                {
                    //Join them up
                    var path = PathfinderInterface.GetPath(fp.Point, primary.Point);
                    if (path != null)
                    {
                        foreach (var coord in path)
                        {
                            MapBlock block = map[coord.X, coord.Y];

                            //Only do this if the tile isn't wood, or stone
                            if (!block.Tile.InternalName.ToUpper().Contains("STONE") && !block.Tile.InternalName.ToUpper().Contains("WOOD"))
                            {
                                block.Tile = itemFactory.CreateItem("tiles", pathTileID);
                                block.Tile.Coordinate = new MapCoordinate(coord);
                            }

                        }
                    }
                }
            }

            List<Actor> actorList = new List<Actor>();

            actorList.AddRange(actors); //And add the actors

            //Let's generate a number of actors then
            foreach (ActorProfession profession in Enum.GetValues(typeof(ActorProfession)))
            {
                //So do we have any wander areas for them ?
                var possibleAreas = wanderAreas.Where(wa => wa.Factions.HasFlag(siteData.Owners) && wa.Profession.Equals(profession));
                var possibleRoutes = patrolRoutes.Where(pr => pr.Owners.HasFlag(siteData.Owners) && pr.Profession.Equals(profession));

                //Any actors?
                if (siteData.ActorCounts.ContainsKey(profession))
                {
                    //Yes, how many
                    int total = siteData.ActorCounts[profession];

                    var a = ActorGeneration.CreateActors(siteData.Owners, profession, total);

                    foreach(var ac in a)
                    {
                        ac.SiteMember = true;
                    }

                    actorList.AddRange(a);

                    foreach (var actor in a)
                    {
                        //So, where we going to drop them off ? Randomly
                        int tries = 0;

                        for (; ; )
                        {
                            int randomX = GameState.Random.Next(map.GetLength(0));
                            int randomY = GameState.Random.Next(map.GetLength(1));

                            if (map[randomX, randomY].MayContainItems)
                            {
                                //Plop it on there
                                actor.MapCharacter.Coordinate = new MapCoordinate(randomX, randomY, 0, MapType.LOCAL);
                                map[randomX, randomY].ForcePutItemOnBlock(actor.MapCharacter);
                                tries = 0;
                                break;
                            }
                            else
                            {
                                tries++;
                            }

                            if (tries >= 150)
                            {
                                //give up
                                break;
                            }
                        }

                        //Go through each actor, and either tell them to wander in the whole map, or within any possible area which matches
                        //Any possible area avaialble?
                        List<object> possibleMissions = new List<object>(); //I know :( But Using an interface or trying to mangle together an inheritance was worse

                        possibleMissions.AddRange(possibleAreas.Where(pa => pa.MaxAmount > pa.CurrentAmount));
                        possibleMissions.AddRange(possibleRoutes);

                        var chosenArea = possibleMissions.OrderBy(pa => GameState.Random.Next(100)).FirstOrDefault();

                        if (chosenArea == null)
                        {
                            //Wander around the whole map
                            actor.CurrentMission = new WanderMission() { LoiterPercentage = 25, WanderPoint = new MapCoordinate(map.GetLength(0) / 2, map.GetLength(1) / 2, 0, MapType.LOCAL), WanderRectangle = new Rectangle(0, 0, map.GetLength(0), map.GetLength(1)) };
                        }
                        else
                        {
                            //Is this a patrol or a wander ?
                            if (chosenArea.GetType().Equals(typeof(PatrolRoute)))
                            {
                                var patrolDetails = chosenArea as PatrolRoute;

                                PatrolRouteMission pm = new PatrolRouteMission();
                                pm.PatrolRoute.AddRange(patrolDetails.Route);

                                actor.CurrentMission = pm;
                            }
                            else if (chosenArea.GetType().Equals(typeof(MapletActorWanderArea)))
                            {
                                var wanderDetails = chosenArea as MapletActorWanderArea;

                                //Wander around in that area
                                actor.CurrentMission = new WanderMission() { LoiterPercentage = 25, WanderPoint = new MapCoordinate(wanderDetails.WanderPoint), WanderRectangle = wanderDetails.WanderRect };
                                wanderDetails.CurrentAmount++;
                            }
                        }

                    }

                }

            }

            actors = actorList.ToArray();

            siteData.PatrolRoutes = patrolRoutes.ToList();
            siteData.WanderAreas = wanderAreas.ToList();

            return map;
        }
예제 #2
0
        /// <summary>
        /// Generates a camp
        /// </summary>
        /// <returns></returns>
        public static MapBlock[,] GenerateCamp(int enemies, out MapCoordinate startPoint, out DRObjects.Actor[] enemyArray)
        {
            MapBlock[,] map = new MapBlock[MAP_EDGE, MAP_EDGE];

            Random random = new Random();

            ItemFactory.ItemFactory factory = new ItemFactory.ItemFactory();

            int grassTileID = 0;

            factory.CreateItem(Archetype.TILES, "grass", out grassTileID);

            //Create a new map which is edge X edge in dimensions and made of grass
            for (int x = 0; x < MAP_EDGE; x++)
            {
                for (int y = 0; y < MAP_EDGE; y++)
                {
                    MapBlock block = new MapBlock();
                    map[x, y] = block;
                    block.Tile = factory.CreateItem("tile", grassTileID);
                    block.Tile.Coordinate = new MapCoordinate(x, y, 0, MapType.LOCAL);
                }
            }

            //Now created a wall
            int pallisadeID = 0;

            factory.CreateItem(Archetype.MUNDANEITEMS, "pallisade wall lr", out pallisadeID);

            //Create a square of pallisade wall

            int startCoord = (MAP_EDGE - FORTIFICATION_EDGE) / 2;
            int endCoord = MAP_EDGE - ((MAP_EDGE - FORTIFICATION_EDGE) / 2);

            for (int x = startCoord + 1; x < endCoord; x++)
            {
                MapBlock block = map[x, startCoord];
                MapItem item = factory.CreateItem("mundaneitems", pallisadeID);

                block.ForcePutItemOnBlock(item);

                block = map[x, endCoord];
                item = factory.CreateItem("mundaneitems", pallisadeID);

                block.ForcePutItemOnBlock(item);
            }

            pallisadeID = 0;

            for (int y = startCoord + 1; y < endCoord; y++)
            {
                factory.CreateItem(Archetype.MUNDANEITEMS, "pallisade wall tb", out pallisadeID);

                MapBlock block = map[startCoord, y];
                MapItem item = factory.CreateItem("mundaneitems", pallisadeID);

                block.ForcePutItemOnBlock(item);

                factory.CreateItem(Archetype.MUNDANEITEMS, "pallisade wall bt", out pallisadeID);

                block = map[endCoord, y];
                item = factory.CreateItem("mundaneitems", pallisadeID);

                block.ForcePutItemOnBlock(item);
            }

            //We need to poke a hole in wall as an entrance
            //Let's poke one at the top and one at the bottom
            int center = MAP_EDGE / 2;

            int rValue = GameState.Random.Next(2);

            for (int x = -1; x < 2; x++)
            {
                if (rValue == 1)
                {
                    MapBlock block = map[center + x, startCoord];

                    block.RemoveTopItem();
                }
                else
                {
                    MapBlock block = map[center + x, endCoord];

                    block.RemoveTopItem();
                }
            }

            rValue = GameState.Random.Next(2);

            for (int y = -1; y < 2; y++)
            {
                if (rValue == 1)
                {
                    MapBlock block = map[startCoord, y + center];
                    block.RemoveTopItem();
                }
                else
                {
                    MapBlock block = map[endCoord, y + center];
                    block.RemoveTopItem();
                }
            }

            //Now, let's create some maplets in there

            //There's a single maplet containing the other maplets - let's get it
            LocalMapXMLParser lm = new LocalMapXMLParser();
            Maplet maplet = lm.ParseMapletFromTag("camp");

            LocalMapGenerator gen = new LocalMapGenerator();
            //TODO: LATER THE OWNER MIGHT NOT BE A BANDIT
            MapletActorWanderArea[] wanderAreas = null;
            MapletPatrolPoint[] patrolPoints = null;
            MapletFootpathNode[] footPath = null;

            var gennedMap = gen.GenerateMap(grassTileID, null, maplet, false, "", OwningFactions.BANDITS, out enemyArray, out wanderAreas, out patrolPoints,out footPath);

            gen.JoinMaps(map, gennedMap, startCoord + 1, startCoord + 1);

            //Let's add some trees and stuff
            int decorCount = (int)(map.GetLength(1) * 0.50);

            //Just find as many random points and if it happens to be grass, drop them
            int itemID = 0;

            for (int i = 0; i < decorCount; i++)
            {
                //Just trees
                MapItem decorItem = factory.CreateItem(Archetype.MUNDANEITEMS, "tree", out itemID);

                //Pick a random point
                MapBlock randomBlock = map[random.Next(map.GetLength(0)), random.Next(map.GetLength(1))];

                //Make sure its not inside the camp
                if (randomBlock.Tile.Coordinate.X >= startCoord && randomBlock.Tile.Coordinate.X <= endCoord && randomBlock.Tile.Coordinate.Y >= startCoord && randomBlock.Tile.Coordinate.Y <= endCoord)
                {
                    //Not within the camp
                    i--;
                    continue; //try again
                }

                if (randomBlock.MayContainItems && randomBlock.Tile.Name == "Grass")
                {
                    //Yes, can support it
                    randomBlock.ForcePutItemOnBlock(decorItem);
                }
                //Otherwise forget all about it
            }

            //Now select all the border tiles and put in a "Exit here" border
            for (int x = 0; x < map.GetLength(0); x++)
            {
                MapCoordinate coo = new MapCoordinate(x, 0, 0, MapType.LOCAL);

                LeaveTownItem lti = new LeaveTownItem();
                lti.Coordinate = coo;
                lti.Description = "path outside the town";
                lti.Name = "Leave Town";

                lti.Coordinate = coo;

                map[x, 0].ForcePutItemOnBlock(lti);

                coo = new MapCoordinate(x, map.GetLength(1) - 1, 0, MapType.LOCAL);

                lti = new LeaveTownItem();
                lti.Coordinate = coo;
                lti.Description = "path outside the town";
                lti.Name = "Leave Town";

                lti.Coordinate = coo;

                map[x, map.GetLength(1) - 1].ForcePutItemOnBlock(lti);

            }

            for (int y = 0; y < map.GetLength(1); y++)
            {
                MapCoordinate coo = new MapCoordinate(0, y, 0, MapType.LOCAL);

                LeaveTownItem lti = new LeaveTownItem();
                lti.Coordinate = coo;
                lti.Description = "path outside the town";
                lti.Name = "Leave Town";

                lti.Coordinate = coo;

                map[0, y].ForcePutItemOnBlock(lti);

                coo = new MapCoordinate(map.GetLength(0) - 1, y, 0, MapType.LOCAL);

                lti = new LeaveTownItem();
                lti.Coordinate = coo;
                lti.Description = "path outside the town";
                lti.Name = "Town Borders";

                lti.Coordinate = coo;

                map[map.GetLength(0) - 1, y].ForcePutItemOnBlock(lti);
            }

            #region Treasure Room

            //This is a bit naughty. We need to locate where the tiles become soil

            MapCoordinate soilStart = null;

            bool breakOut = false;

            for (int x = 0; x < map.GetLength(0); x++)
            {
                for (int y = 0; y < map.GetLength(1); y++)
                {
                    if (map[x, y].Tile.Name.ToLower().Equals("soil"))
                    {
                        soilStart = new MapCoordinate(x, y, 0, MapType.LOCAL);
                        breakOut = true;
                        break;
                    }
                }

                if (breakOut)
                {
                    break;
                }
            }

            //Also naughty, we know it's 5x5

            #region Inner Wall

            for (int x = 0; x < 5; x++)
            {
                factory.CreateItem(Archetype.MUNDANEITEMS, "pallisade wall lr", out pallisadeID);

                MapItem item = factory.CreateItem("mundaneitems", pallisadeID);

                if (x != 2) //hole in the top
                {
                    map[soilStart.X + x, soilStart.Y].ForcePutItemOnBlock(item);
                }

                factory.CreateItem(Archetype.MUNDANEITEMS, "pallisade wall lr", out pallisadeID);

                item = factory.CreateItem("mundaneitems", pallisadeID);

                map[soilStart.X + x, soilStart.Y + 5].ForcePutItemOnBlock(item);

            }

            for (int y = 0; y < 5; y++)
            {
                factory.CreateItem(Archetype.MUNDANEITEMS, "pallisade wall tb", out pallisadeID);

                MapItem item = factory.CreateItem("mundaneitems", pallisadeID);

                map[soilStart.X - 1, soilStart.Y + y].ForcePutItemOnBlock(item);

                factory.CreateItem(Archetype.MUNDANEITEMS, "pallisade wall bt", out pallisadeID);

                item = factory.CreateItem("mundaneitems", pallisadeID);

                map[soilStart.X + 5, soilStart.Y + y].ForcePutItemOnBlock(item);
            }

            #endregion

            #endregion

            #region Patrol Points

            //Now let's collect the patrol points. We're going to have two possible patrols - one around each of the entrances - and another on the outside corners of the map

            List<MapCoordinate> outsidePatrol = new List<MapCoordinate>();

            outsidePatrol.Add(new MapCoordinate(startCoord - 2, startCoord, 0, MapType.LOCAL));
            outsidePatrol.Add(new MapCoordinate(endCoord + 2, startCoord, 0, MapType.LOCAL));
            outsidePatrol.Add(new MapCoordinate(endCoord + 2, endCoord, 0, MapType.LOCAL));
            outsidePatrol.Add(new MapCoordinate(startCoord - 2, endCoord, 0, MapType.LOCAL));

            List<MapCoordinate> insidePatrol = new List<MapCoordinate>();

            insidePatrol.Add(new MapCoordinate(center, startCoord + 1, 0, MapType.LOCAL));
            insidePatrol.Add(new MapCoordinate(center, endCoord - 1, 0, MapType.LOCAL));
            insidePatrol.Add(new MapCoordinate(startCoord + 1, center, 0, MapType.LOCAL));
            insidePatrol.Add(new MapCoordinate(endCoord - 1, center, 0, MapType.LOCAL));

            //Go through all of those and make sure they're clear of anything that wouldn't let them walk upon them
            foreach (var coordinate in outsidePatrol)
            {
                map[coordinate.X, coordinate.Y].RemoveTopItem();
            }

            foreach (var coordinate in insidePatrol)
            {
                map[coordinate.X, coordinate.Y].RemoveTopItem();
            }

            #endregion

            #region Actors

            enemyArray = CreateBandits(enemies, outsidePatrol.Select(op => new PatrolPoint() { AcceptableRadius = 2, Coordinate = op }).ToList(), insidePatrol.Select(op => new PatrolPoint() { AcceptableRadius = 2, Coordinate = op }).ToList());

            int tries = 0;

            //Put them on the mappity map
            for (int i = 0; i < enemyArray.Length; i++)
            {
                Actor actor = enemyArray[i];

                int randomX = random.Next(map.GetLength(0));
                int randomY = random.Next(map.GetLength(1));

                if (map[randomX, randomY].MayContainItems)
                {
                    //Plop it on there
                    actor.MapCharacter.Coordinate = new MapCoordinate(randomX, randomY, 0, MapType.LOCAL);
                    map[randomX, randomY].ForcePutItemOnBlock(actor.MapCharacter);
                    tries = 0;

                    ////If they are wandering, make them wander in the right place
                    //var mission = actor.MissionStack.Peek();

                    //if (mission.MissionType == ActorMissionType.WANDER)
                    //{
                    //    var wander = mission as WanderMission;

                    //    wander.WanderPoint = new MapCoordinate(actor.MapCharacter.Coordinate);
                    //    wander.WanderRectangle = new Rectangle(startCoord, startCoord, FORTIFICATION_EDGE, FORTIFICATION_EDGE);
                    //}

                }
                else
                {
                    tries++;
                    i--;
                }

                if (tries >= 50)
                {
                    //give up
                    continue;
                }
            }

            #endregion

            startPoint = new MapCoordinate(map.GetLength(0) / 2, 0, 0, MapType.LOCAL);

            return map;
        }
예제 #3
0
        /// <summary>
        /// Creates and puts a particular room in a particular rectangle
        /// </summary>
        /// <param name="roomType"></param>
        /// <param name="rect"></param>
        /// <param name="circle">When the room is a Summoning Room, there's the circle</param>
        private static void PutRoom(MapBlock[,] map, int tileID, int level, DungeonRoomType roomType, Rectangle rect, out SummoningCircle circle)
        {
            circle = null;

            string tagName = roomType.ToString().ToLower().Replace("_", " ") + " room";

            LocalMapXMLParser parser = new LocalMapXMLParser();
            var maplet = parser.ParseMapletFromTag(tagName);

            //Change the width and height to match the rectangle we're fitting it in
            //Leave a rim of 1
            maplet.SizeX = rect.Width - 2;
            maplet.SizeY = rect.Height - 2;

            LocalMapGenerator lmg = new LocalMapGenerator();

            Actor[] actors = null;
            MapletActorWanderArea[] areas = null;
            MapletPatrolPoint[] patrolRoutes = null;
            MapletFootpathNode[] footpathNodes = null;

            var gennedMap = lmg.GenerateMap(tileID, null, maplet, false, "", OwningFactions.UNDEAD, out actors, out areas, out patrolRoutes, out footpathNodes);

            //Is this a summoning room?
            if (roomType == DungeonRoomType.SUMMONING)
            {
                //Go through each map block and see if we find a summoning circle
                for (int x = 0; x < gennedMap.GetLength(0); x++)
                {
                    for (int y = 0; y < gennedMap.GetLength(1); y++)
                    {
                        var block = gennedMap[x, y];
                        if (block.GetTopMapItem() != null && block.GetTopMapItem().GetType().Equals(typeof(SummoningCircle)))
                        {
                            circle = block.GetTopMapItem() as SummoningCircle;
                        }
                    }
                }
            }

            if (roomType == DungeonRoomType.COMBAT_PIT)
            {
                int docLevel = (int) level/4;
                docLevel = docLevel < 1 ? 1 : docLevel;
                docLevel = docLevel > 5 ? 5 : docLevel;
                //Generate a combat manual - Level [1..5] will be determined by floor of Dungeon Level /4
                CombatManual cm = new CombatManual(SpecialAttacksGenerator.GenerateSpecialAttack(docLevel));

                //Now place it, somewhere (or at least try 50 times)
                for(int i=0; i < 50; i++)
                {
                    MapBlock randomBlock = gennedMap[GameState.Random.Next(gennedMap.GetLength(0)), GameState.Random.Next(gennedMap.GetLength(1))];

                    if (randomBlock.MayContainItems)
                    {
                        randomBlock.ForcePutItemOnBlock(cm);
                        break;
                    }
                }
            }

            //Do we have any treasure chests?
            for (int x = 0; x < gennedMap.GetLength(0); x++)
            {
                for (int y = 0; y < gennedMap.GetLength(1); y++)
                {
                    var block = gennedMap[x, y];
                    if (block.GetTopMapItem() != null && block.GetTopMapItem().GetType().Equals(typeof(TreasureChest)))
                    {
                        TreasureChest chest = block.GetTopMapItem() as TreasureChest;

                        InventoryItemManager iim = new InventoryItemManager();

                        //Fill em up
                        chest.Contents = iim.FillTreasureChest((InventoryCategory[])Enum.GetValues(typeof(InventoryCategory)), 300 + (50 * level));
                    }
                }
            }

            //Now fit one into the other
            lmg.JoinMaps(map, gennedMap, rect.X + 1, rect.Y + 1);
        }
예제 #4
0
        /// <summary>
        /// Generates a dungeon having a particular amount of tiers, trap rooms, guard rooms and treasure rooms
        /// </summary>
        /// <param name="tiers">How many 'layers' the dungeon contains</param>
        /// <param name="enemyArray">A list of enemy actors</param>
        /// <param name="guardRooms">The maximum amount of guardrooms contained in the dungeon</param>
        /// <param name="maxOwnedPopulation">For each owned room which generates enemies, the maximum amount GENERATED in each room (does not preclude patrols from entering the same room)</param>
        /// <param name="maxWildPopulation">For each wild room which generates enemies, the maximum amount GENERATED in each room.</param>
        /// <param name="ownerType">For each owned room, the type of the enemies to create</param>
        /// <param name="percentageOwned">The percentage of the rooms which are owned as opposed to being wild. Bear in mind that wild rooms can spawn quite a bit of enemies</param>
        /// <param name="pointsOfInterest">The points of interest (ie guard and treasure rooms for instance) which have been generated. Used for patrols</param>
        /// <param name="startPoint">The entrance start point</param>
        /// <param name="utilityRooms">The maximum amount of Utility rooms to generate - these might contain civilian orcs which ignore the maxOwnedPopulation value</param>
        /// <param name="treasureRooms">The maximum amount of teasure rooms to generate</param>
        /// <returns></returns>
        public MapBlock[,] GenerateDungeon(int tiers, int utilityRooms, int guardRooms, int treasureRooms, string ownerType,
            decimal percentageOwned, int maxWildPopulation, int maxOwnedPopulation,
            out MapCoordinate startPoint, out DRObjects.Actor[] enemyArray, out List<PointOfInterest> pointsOfInterest)
        {
            startPoint = new MapCoordinate(0, 0, 0, MapType.LOCAL);
            pointsOfInterest = new List<PointOfInterest>();

            List<DRObjects.Actor> enemies = new List<DRObjects.Actor>();
            List<CitadelRoom> rooms = new List<CitadelRoom>();
            int uniqueID = 0;

            //Start with the root node
            CitadelRoom root = new CitadelRoom();
            root.SquareNumber = (int)Math.Ceiling((double)WIDTH / 2);
            root.TierNumber = 0;
            root.UniqueID = uniqueID++;
            root.Connections.Add(-1); //this is a special id. We'll use it to create a start point

            rooms.Add(root);

            int currentTier = 1;
            int square = (int)Math.Ceiling((double)WIDTH / 2);
            CitadelRoom focusNode = root;

            Random random = new Random(DateTime.UtcNow.Millisecond);

            while (currentTier < tiers)
            {
                //Create a new node
                CitadelRoom newNode = new CitadelRoom();

                newNode.SquareNumber = square;
                newNode.TierNumber = currentTier;
                newNode.UniqueID = uniqueID++;
                newNode.CitadelRoomType = CitadelRoomType.EMPTY_ROOM;
                //connect the focus node to this node
                focusNode.Connections.Add(newNode.UniqueID);
                newNode.Connections.Add(focusNode.UniqueID);

                //change the focus node
                focusNode = newNode;
                //aaaand add it to the list
                rooms.Add(newNode);

                //Now we decide whether to stay in the same tier - or increase the tier
                int randomNumber = random.Next(100);

                int siblings = rooms.Where(r => r.TierNumber.Equals(currentTier)).Count();
                int treshold = 0;

                switch (siblings)
                {
                    case 1: treshold = PROB_2; break;
                    case 2: treshold = PROB_3; break;
                    case 3: treshold = PROB_4; break;
                    case 4: treshold = PROB_5; break;
                    default: treshold = 0; break; //NEVER
                }

                if (randomNumber < treshold)
                {
                    //then stay in the same place - go either left or right. Can we go in that direction?
                    bool canGoRight = !rooms.Any(r => (r.SquareNumber.Equals(square + 1) && r.TierNumber.Equals(currentTier)) || square + 1 > WIDTH);
                    bool canGoLeft = !rooms.Any(r => (r.SquareNumber.Equals(square - 1) && r.TierNumber.Equals(currentTier)) || square - 1 < 0);

                    if (canGoLeft && canGoRight)
                    {
                        //pick one at random
                        square += random.Next(2) == 1 ? 1 : -1;
                    }
                    else if (canGoLeft)
                    {
                        square -= 1;
                    }
                    else if (canGoRight)
                    {
                        square += 1;
                    }
                    else
                    {
                        //We've done it all
                        currentTier++;
                    }
                }
                else
                {
                    currentTier++;
                }
            }

            //Now that that part is done, lets add some more paths so we turn this into a graph
            foreach (CitadelRoom room in rooms)
            {
                //For each room, check who is a sibling or immediatly under him. There is a 50% chance of forming a link
                CitadelRoom[] potentialRooms = GetPathableRooms(rooms, room.TierNumber, room.SquareNumber);

                foreach (CitadelRoom potentialRoom in potentialRooms)
                {
                    //Is there a connection already?
                    if (!potentialRoom.Connections.Contains(room.UniqueID))
                    {
                        if (random.Next(2) == 1)
                        {
                            //add a connection
                            room.Connections.Add(potentialRoom.UniqueID);
                            potentialRoom.Connections.Add(room.UniqueID);
                        }
                    }
                }
            }

            //go through the rooms and set some as wild rooms already
            foreach (var room in rooms)
            {
                if (random.Next(100) > percentageOwned)
                {
                    //Wild room
                    room.CitadelRoomType = CitadelRoomType.WILD_ROOM;
                }
            }

            //Lets assign the rooms based on the maximum amount.

            //Some rooms have more probability in certain regions.

            //So lets divide the rooms in 3
            //Favoured - x3
            //Other - x2
            //Unfavoured - x1

            int lowerBoundary = rooms.Count / 3;
            int upperBoundary = 2 * rooms.Count / 3;

            var orderedUtilities = rooms.Where
                (o => o.CitadelRoomType == CitadelRoomType.EMPTY_ROOM).OrderByDescending(o => random.Next(100) *
                (o.UniqueID > upperBoundary ? 1 : o.UniqueID > lowerBoundary ? 2 : 3)).Where(r => r.CitadelRoomType == CitadelRoomType.EMPTY_ROOM
                    ).ToArray().Take(utilityRooms);

            foreach (var room in orderedUtilities)
            {
                room.CitadelRoomType = CitadelRoomType.UTILITY_ROOM;
            }

            //Same thing for treasure rooms
            var orderedTreasure = rooms.Where
                (o => o.CitadelRoomType == CitadelRoomType.EMPTY_ROOM).OrderByDescending(o => random.Next(100) *
                (o.UniqueID > upperBoundary ? 3 : o.UniqueID > lowerBoundary ? 2 : 1)).Where(r => r.CitadelRoomType == CitadelRoomType.EMPTY_ROOM
                    ).Take(treasureRooms);

            foreach (var room in orderedTreasure)
            {
                room.CitadelRoomType = CitadelRoomType.TREASURE_ROOM;
            }

            //And guard rooms
            var orderedGuard = rooms.Where
                (o => o.CitadelRoomType == CitadelRoomType.EMPTY_ROOM).OrderByDescending(o => random.Next(100) *
                (o.UniqueID > upperBoundary ? 1 : o.UniqueID > lowerBoundary ? 3 : 2)).Where(r => r.CitadelRoomType == CitadelRoomType.EMPTY_ROOM
                    ).Take(guardRooms);

            foreach (var room in orderedGuard)
            {
                room.CitadelRoomType = CitadelRoomType.GUARD_ROOM;
            }

            //Now that that part is done, we put them on the actual grid.

            //We go for a 15x15 room and connect the items in it.

            //15x15 - with a gap of 7 between them for tunnels
            int mapWidth = ((WIDTH + 7) * 20);
            int mapHeight = ((tiers + 7) * 20);

            //Create new blocks
            MapBlock[,] map = new MapBlock[mapWidth, mapHeight];

            for (int x = 0; x < map.GetLength(0); x++)
            {
                for (int y = 0; y < map.GetLength(1); y++)
                {
                    map[x, y] = new MapBlock()
                        {
                            Tile = new MapItem()
                            {
                                Coordinate = new MapCoordinate(x, y, 0, DRObjects.Enums.MapType.LOCAL),
                                MayContainItems = false
                            }
                        };
                }
            }

            LocalMapGenerator gen = new LocalMapGenerator();
            LocalMapXMLParser xmlGen = new LocalMapXMLParser();

            //Start generating the maps and then stitch them upon the main map
            foreach (CitadelRoom room in rooms)
            {
                MapBlock[,] gennedMap = null;
                string tag = String.Empty;

                switch (room.CitadelRoomType)
                {
                    case CitadelRoomType.EMPTY_ROOM: tag = "Empty Dungeon"; break;
                    case CitadelRoomType.GUARD_ROOM: tag = "Guard Dungeon"; break;
                    case CitadelRoomType.UTILITY_ROOM: tag = "Utility Dungeon"; break;
                    case CitadelRoomType.TREASURE_ROOM: tag = "Treasure Dungeon"; break;
                    case CitadelRoomType.WILD_ROOM: tag = "Empty Dungeon"; break;
                    default:
                        throw new NotImplementedException("Dungeon Room " + room.CitadelRoomType + " not planned for yet.");
                }

                //Generate it :)
                Maplet maplet = xmlGen.ParseMapletFromTag(tag);

                Actor[] acts = null;
                MapletActorWanderArea[] wanderAreas = null;
                MapletPatrolPoint[] patrolPoints = null;
                MapletFootpathNode[] footPath = null;

                gennedMap = gen.GenerateMap(25, null, maplet, true, "", OwningFactions.ORCS ,out acts,out wanderAreas,out patrolPoints,out footPath);

                enemies.AddRange(acts);

                //Is it a treasure room?
                if (room.CitadelRoomType == CitadelRoomType.TREASURE_ROOM)
                {
                    //Generate some loot
                    GenerateLoot(gennedMap, room.TierNumber);
                }

                PointOfInterest mapletInterest = null;

                if (room.CitadelRoomType == CitadelRoomType.GUARD_ROOM || room.CitadelRoomType == CitadelRoomType.TREASURE_ROOM)
                {
                    //This will be a point of interest. Select a random walkable point in the room and mark the place as such
                    for (int tryAmount = 0; tryAmount < 50; tryAmount++)
                    {
                        //Try for a maximum of 50 times
                        int x = random.Next(gennedMap.GetLength(0));
                        int y = random.Next(gennedMap.GetLength(1));

                        if (gennedMap[x, y].Tile.MayContainItems)
                        {
                            //Put this as the point
                            PointOfInterest interest = new PointOfInterest();
                            interest.Coordinate = new MapCoordinate(x, y, 0, MapType.LOCAL);

                            if (room.CitadelRoomType == CitadelRoomType.GUARD_ROOM)
                            {
                                interest.Type = PointOfInterestType.GUARD_ROOM;
                            }
                            else if (room.CitadelRoomType == CitadelRoomType.TREASURE_ROOM)
                            {
                                interest.Type = PointOfInterestType.TREASURE;
                            }

                            pointsOfInterest.Add(interest);
                            mapletInterest = interest;
                            break;
                        }
                    }
                }

                DRObjects.Actor[] roomEnemies = new DRObjects.Actor[] { };

                if (room.CitadelRoomType == CitadelRoomType.GUARD_ROOM || room.CitadelRoomType == CitadelRoomType.TREASURE_ROOM)
                {
                    //Create an amount of enemies - level doesn't matter, we'll regen later
                    gennedMap = gen.GenerateEnemies(gennedMap, random.Next(maxOwnedPopulation), ownerType, out roomEnemies, 10);

                    enemies.AddRange(roomEnemies);
                }

                if (room.CitadelRoomType == CitadelRoomType.WILD_ROOM)
                {
                    //Create an amount of wild enemies - let's get a random type for this room. This will be of level 5. Later we'll have proper wildlife
                    string type = ActorGeneration.GetEnemyType(false);

                    gennedMap = gen.GenerateEnemies(gennedMap, random.Next(maxWildPopulation), type, out roomEnemies, 5);

                    //go through all of room enemies and set them to idle
                    foreach (var enemy in roomEnemies)
                    {
                        enemy.MissionStack.Clear();
                        enemy.MissionStack.Push(new IdleMission());
                    }

                    enemies.AddRange(roomEnemies);

                }

                //fit her onto the main map

                int xIncreaser = room.SquareNumber * 20;
                int yIncreaser = (room.TierNumber * 20) + 3;

                //Fix the patrol points of any enemies
                foreach (Actor enemy in roomEnemies.Union(acts))
                {
                    if (enemy.MissionStack.Count != 0 && enemy.MissionStack.Peek().MissionType == DRObjects.ActorHandling.ActorMissionType.WANDER)
                    {
                        //Change patrol point
                        MapCoordinate point = (enemy.MissionStack.Peek() as WanderMission).WanderPoint;
                        point.X += xIncreaser;
                        point.Y += yIncreaser;

                        //Change the rectangle x and y too
                        Rectangle rect = (enemy.MissionStack.Peek() as WanderMission).WanderRectangle;
                        rect.X = xIncreaser;
                        rect.Y = yIncreaser;

                        (enemy.MissionStack.Peek() as WanderMission).WanderRectangle = rect; //apparently rectangles are immutable or something
                    }
                }
                //Update the point of interest if there is one
                if (mapletInterest != null)
                {
                    mapletInterest.Coordinate.X += xIncreaser;
                    mapletInterest.Coordinate.Y += yIncreaser;
                }

                for (int x = 0; x < gennedMap.GetLength(0); x++)
                {
                    for (int y = 0; y < gennedMap.GetLength(1); y++)
                    {
                        map[x + xIncreaser, y + yIncreaser] = gennedMap[x, y];
                        map[x + xIncreaser, y + yIncreaser].Tile.Coordinate = new MapCoordinate(x + xIncreaser, y + yIncreaser, 0, DRObjects.Enums.MapType.LOCAL);

                        foreach (var item in map[x + xIncreaser, y + yIncreaser].GetItems())
                        {
                            item.Coordinate = new MapCoordinate(x + xIncreaser, y + yIncreaser, 0, DRObjects.Enums.MapType.LOCAL);
                        }
                    }
                }

                //Lets draw the connections - only the ones who's rooms we've drawn yet

                ItemFactory.ItemFactory factory = new ItemFactory.ItemFactory();

                foreach (var connection in room.Connections.Where(c => c < room.UniqueID))
                {
                    if (connection == -1)
                    {
                        //Entrance hall!
                        //Create a line of 3 at the bottom and return the coordinates
                        int topEdgeY = yIncreaser;
                        int bottomEdgeXMin = 0 + xIncreaser;
                        int bottomEdgeXMax = gennedMap.GetLength(0) + xIncreaser;

                        //Find the start
                        int xStart = (bottomEdgeXMax - bottomEdgeXMin) / 2 + bottomEdgeXMin;

                        //Set the start point
                        startPoint = new MapCoordinate(xStart + 1, topEdgeY - 2, 0, MapType.LOCAL);
                        //Put the 'leave town' item on it

                        map[startPoint.X, startPoint.Y].ForcePutItemOnBlock(new LeaveTownItem());

                        int x = xStart;
                        int y = topEdgeY;

                        //go 3 steps down
                        for (int a = 0; a < 3; a++)
                        {
                            for (int x1 = 0; x1 < 3; x1++)
                            {
                                //Draw!
                                map[x + x1, y].Tile = factory.CreateItem("TILES", 25);
                                map[x + x1, y].Tile.Coordinate = new MapCoordinate(x + x1, y, 0, MapType.LOCAL);
                            }

                            y--; //move down
                        }

                        y = topEdgeY;

                        //Walk back
                        do
                        {
                            for (int x1 = 0; x1 < 3; x1++)
                            {
                                //Draw!
                                map[x + x1, y].Tile = factory.CreateItem("TILES", 25);
                                map[x + x1, y].Tile.Coordinate = new MapCoordinate(x + x1, y, 0, MapType.LOCAL);
                            }

                            y++; //move up
                        } while (x >= 0 && y < map.GetLength(1) && !map[x, y].Tile.MayContainItems);

                        //Put the spikes at the entrance
                        int dummy = -1;

                        map[xStart, topEdgeY - 2].ForcePutItemOnBlock(factory.CreateItem(Archetype.MUNDANEITEMS, "spikes", out dummy));
                        map[xStart + 2, topEdgeY - 2].ForcePutItemOnBlock(factory.CreateItem(Archetype.MUNDANEITEMS, "spikes", out dummy));

                        continue;
                    }

                    //Identify the room to be connected with
                    var roomToBeConnected = rooms.Where(r => r.UniqueID.Equals(connection)).FirstOrDefault();

                    //Determine the direction relative to the current room
                    if (roomToBeConnected.SquareNumber > room.SquareNumber)
                    {
                        //RIGHT
                        //Find the rightmost edge of the room and start... somewhere

                        int rightEdgeX = gennedMap.GetLength(0) + xIncreaser;
                        int rightEdgeYMin = 0 + yIncreaser;
                        int rightEdgeYMax = gennedMap.GetLength(1) + yIncreaser;

                        //Pick a start at random
                        int yStart = random.Next(rightEdgeYMax - rightEdgeYMin - 2) + rightEdgeYMin;

                        //Now 'walk' from ystart-ystart+3 until you hit on something which has a block in it

                        int x = rightEdgeX;
                        int y = yStart;

                        while (x < map.GetLength(0) && y < map.GetLength(1) && !map[x, y].Tile.MayContainItems)
                        {
                            for (int y1 = 0; y1 < 3; y1++)
                            {
                                //Draw!
                                map[x, y + y1].Tile = factory.CreateItem("TILES", 25);
                                map[x, y + y1].Tile.Coordinate = new MapCoordinate(x, y + y1, 0, MapType.LOCAL);
                            }

                            x++; //increment x
                        }

                        x = rightEdgeX - 1;

                        //now lets walk backwards too
                        while (x >= 0 && x < map.GetLength(0) && y >= 0 && y < map.GetLength(1) && !map[x, y].Tile.MayContainItems)
                        {
                            for (int y1 = 0; y1 < 3; y1++)
                            {
                                //Draw!
                                map[x, y + y1].Tile = factory.CreateItem("TILES", 25);
                                map[x, y + y1].Tile.Coordinate = new MapCoordinate(x, y + y1, 0, MapType.LOCAL);
                            }

                            x--; //walk back
                        }

                    }
                    else if (roomToBeConnected.SquareNumber < room.SquareNumber)
                    {
                        //LEFT
                        //Find the leftMose edge of the room and start... somewhere

                        int leftEdgeX = xIncreaser;
                        int leftEdgeYMin = 0 + yIncreaser;
                        int leftEdgeYMax = gennedMap.GetLength(1) + yIncreaser;

                        //Pick a start at random
                        int yStart = random.Next(leftEdgeYMax - leftEdgeYMin - 2) + leftEdgeYMin;

                        //Now 'walk' from ystart-ystart+3 until you hit on something which has a block in it

                        int x = leftEdgeX;
                        int y = yStart;

                        do
                        {

                            for (int y1 = 0; y1 < 3; y1++)
                            {
                                //Draw!
                                map[x, y + y1].Tile = factory.CreateItem("TILES", 25);
                                map[x, y + y1].Tile.Coordinate = new MapCoordinate(x, y + y1, 0, MapType.LOCAL);
                            }

                            x--; //decrement x
                        } while (x >= 0 && x < map.GetLength(0) && y >= 0 && y < map.GetLength(1) && !map[x, y].Tile.MayContainItems);

                        x = leftEdgeX + 1;
                        //walk backwards
                        do
                        {
                            for (int y1 = 0; y1 < 3; y1++)
                            {
                                //Draw!
                                map[x, y + y1].Tile = factory.CreateItem("TILES", 25);
                                map[x, y + y1].Tile.Coordinate = new MapCoordinate(x, y + y1, 0, MapType.LOCAL);
                            }

                            x++; //walk back
                        } while (x >= 0 && x < map.GetLength(0) && y >= 0 && y < map.GetLength(1) && !map[x, y].Tile.MayContainItems);

                    }
                    else if (roomToBeConnected.TierNumber < room.TierNumber)
                    {
                        //BOTTOM
                        //Find the bottommost edge of the room and start... somewhere

                        int bottomEdgeY = yIncreaser;
                        int bottomEdgeXMin = 0 + xIncreaser;
                        int bottomEdgeXMax = gennedMap.GetLength(0) + xIncreaser;

                        //Pick a start at random
                        int xStart = random.Next(bottomEdgeXMax - bottomEdgeXMin - 2) + bottomEdgeXMin;

                        //Now 'walk' from xstart-xstart+3 until you hit on something which has a block in it

                        int x = xStart;
                        int y = bottomEdgeY;

                        do
                        {
                            for (int x1 = 0; x1 < 3; x1++)
                            {

                                //Draw!
                                map[x + x1, y].Tile = factory.CreateItem("TILES", 25);
                                map[x + x1, y].Tile.Coordinate = new MapCoordinate(x + x1, y, 0, MapType.LOCAL);
                            }

                            y--; //decrement y
                        } while (x >= 0 && x < map.GetLength(0) && y >= 0 && y < map.GetLength(1) && !map[x, y].Tile.MayContainItems);

                        y = bottomEdgeY + 1;

                        //Walk backwards
                        do
                        {
                            for (int x1 = 0; x1 < 3; x1++)
                            {
                                //Draw!
                                map[x + x1, y].Tile = factory.CreateItem("TILES", 25);
                                map[x + x1, y].Tile.Coordinate = new MapCoordinate(x + x1, y, 0, MapType.LOCAL);
                            }

                            y++; //walk back
                        } while (x >= 0 && x < map.GetLength(0) && y >= 0 && y < map.GetLength(1) && !map[x, y].Tile.MayContainItems);

                    }
                    else if (roomToBeConnected.TierNumber > room.TierNumber)
                    {
                        //TOP - Won't ever happen - but sure
                        //Find the topmost edge of the room and start... somewhere

                        int topEdgeY = yIncreaser + gennedMap.GetLength(1);
                        int bottomEdgeXMin = 0 + xIncreaser;
                        int bottomEdgeXMax = gennedMap.GetLength(0) + xIncreaser;

                        //Pick a start at random
                        int xStart = random.Next(bottomEdgeXMax - bottomEdgeXMin - 2) + bottomEdgeXMin;

                        //Now 'walk' from xstart-xstart+3 until you hit on something which has a block in it

                        int x = xStart;
                        int y = topEdgeY;

                        do
                        {
                            bool holed = false;

                            for (int x1 = 0; x1 < 3; x1++)
                            {

                                if (!holed)
                                {
                                    //Have a chance of putting in a hole
                                    if (random.Next(8) == 0)
                                    {
                                        holed = true;
                                        continue; //don't put in a tile
                                    }
                                }

                                //Draw!
                                map[x + x1, y].Tile = factory.CreateItem("TILES", 25);
                                map[x + x1, y].Tile.Coordinate = new MapCoordinate(x + x1, y, 0, MapType.LOCAL);
                            }

                            y++; //move up
                        } while (x >= 0 && x < map.GetLength(0) && y >= 0 && y < map.GetLength(1) && !map[x, y].Tile.MayContainItems);

                        //walk back
                        y = topEdgeY + 1;

                        do
                        {
                            for (int x1 = 0; x1 < 3; x1++)
                            {
                                //Draw!
                                map[x + x1, y].Tile = factory.CreateItem("TILES", 25);
                                map[x + x1, y].Tile.Coordinate = new MapCoordinate(x + x1, y, 0, MapType.LOCAL);
                            }

                            y--; //move down
                        } while (x >= 0 && x < map.GetLength(0) && y >= 0 && y < map.GetLength(1) && !map[x, y].Tile.MayContainItems);
                    }
                }
            }

            //We need to fix the enemies to conform to the standards
            ConformEnemies(enemies);

            enemyArray = enemies.ToArray();

            return map;
        }