ParseMapletFromTag() public method

public ParseMapletFromTag ( string tag, GlobalBiome biome = null ) : Maplet
tag string
biome GlobalBiome
return DRObjects.LocalMapGeneratorObjects.Maplet
Esempio n. 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;
        }
Esempio n. 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;
        }
Esempio n. 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);
        }
Esempio n. 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;
        }