/// <summary>
        /// Calculates the Manhatten distance on the XY plane between two coordinates
        /// </summary>
        /// <param name="c1"></param>
        /// <param name="c2"></param>
        /// <returns></returns>
        public static int GetManhattenDistanceOnXYPlane(MapCoordinate c1, MapCoordinate c2)
        {
            int deltaX = Math.Abs(c1.X - c2.X);
            int deltaY = Math.Abs(c1.Y - c2.Y);

            return deltaX + deltaY;
        }
        /// <summary>
        /// Gets a path from the startPoint to the endPoint. Or null if there are no possible points
        /// </summary>
        /// <param name="startPoint"></param>
        /// <param name="endPoint"></param>
        /// <returns></returns>
        public static Stack<MapCoordinate> GetPath(MapCoordinate startPoint, MapCoordinate endPoint)
        {
            if (pathFinder == null)
            {
                if (nodes == null)
                {
                    GameState.LocalMap.GeneratePathfindingMap();
                    nodes = GameState.LocalMap.PathfindingMap;
                }

                //Create the new pathfinder with the map - add the settings
                pathFinder = new PathFinderFast(nodes);

                pathFinder.Formula = HeuristicFormula.Manhattan;
                pathFinder.Diagonals = false;
                pathFinder.HeavyDiagonals = false;
                pathFinder.HeuristicEstimate = 2;
                pathFinder.PunishChangeDirection = true;
                pathFinder.TieBreaker = false;
                pathFinder.SearchLimit = 5000;
            }

            List<PathFinderNode> path = pathFinder.FindPath(new Point(startPoint.X, startPoint.Y), new Point(endPoint.X, endPoint.Y));

            Stack<MapCoordinate> coordStack = new Stack<MapCoordinate>();

            if (path == null)
            {
                Console.WriteLine("No path found :(");
                return null;
            }

            //Check that all points are valid
            foreach (var point in path)
            {
                if (nodes[point.X, point.Y] > 100)
                {
                    Console.WriteLine("No path found :( ");
                    return null;

                }
            }

            foreach (PathFinderNode node in path)
            {
                coordStack.Push(new MapCoordinate(node.X, node.Y, 0, startPoint.MapType));
            }

            if (coordStack.Count == 0)
            {
                return null;
            }
            else
            {
                coordStack.Pop(); //remove the start node
                return coordStack;
            }
        }
        public ThrowItemComponent(int x, int y, MapCoordinate targetCoordinate, Actor actor)
        {
            this.locationX = x;
            this.locationY = y;
            this.targetCoordinate = targetCoordinate;
            this.Actor = actor;

            PerformDrag(0, 0);
        }
 /// <summary>
 /// Creates a new Context Menu starting at x,y
 /// </summary>
 /// <param name="x"></param>
 /// <param name="y"></param>
 public ContextMenuComponent(int x, int y,MapCoordinate coordinate)
 {
     this.contextMenuItems = new List<ContextMenuItem>();
     this.drawRectangle = new Rectangle();
     this.drawRectangle.X = x;
     this.drawRectangle.Y = y;
     this.coordinate = coordinate;
     Visible = true;
 }
        /// <summary>
        /// Calculates the Cartisian Displacement between two coordinates on the XY plane
        /// </summary>
        /// <param name="c1"></param>
        /// <param name="c2"></param>
        /// <returns></returns>
        public static double GetCartisianDisplacementOnXYPlane(MapCoordinate c1, MapCoordinate c2)
        {
            //using pythagoras
            //H = sqrt(Delta X ^2 + Delta Y ^ 2)

            int deltaX = Math.Abs(c1.X - c2.X);
            int deltaY = Math.Abs(c1.Y - c2.Y);

            return Math.Sqrt(Math.Pow(deltaX, 2) + Math.Pow(deltaY, 2));
        }
Exemple #6
0
 /// <summary>
 /// Constructor. Sets the default values for this tile at a particular coordinate
 /// </summary>
 public Air(MapCoordinate coord)
     : base(coord)
 {
     this.Description = "";
     this.Graphic = null;
     this.MayContainItems = false;
     this.Name = "";
     this.InternalName = "Air";
     this.IsActive = true;
 }
 public object ConvertValueWhenRead(object inputValue)
 {
     var coordStr = inputValue as string;
     var mapCoordinate = new MapCoordinate {Latitude = 0, Longitude = 0, Zoom = 12};
     if (coordStr != null)
     {
         var vals = coordStr.Split(new[] {','});
         if (vals.Length == 3)
         {
             mapCoordinate = new MapCoordinate
             {
                 Latitude = float.Parse(vals[0]),
                 Longitude = float.Parse(vals[1]),
                 Zoom = int.Parse(vals[2])
             };
         }
     }
     return mapCoordinate;
 }
 /// <summary>
 /// Gets a graphical block whch exists on a particular point, with a global overlay
 /// </summary>
 /// <param name="point"></param>
 /// <param name="globalOverlay"></param>
 /// <returns></returns>
 public static GraphicalBlock GetBlockAtPoint(MapCoordinate point, GlobalOverlay globalOverlay)
 {
     switch (point.MapType)
     {
         case (DRObjects.Enums.MapType.GLOBAL)
         :
             try
             {
                 return GameState.GlobalMap.GetBlockAtCoordinate(point).ConvertToGraphicalBlock(globalOverlay);
             }
             catch
             {//send an empty one
                 GraphicalBlock block = new GraphicalBlock();
                 block.MapCoordinate = point;
                 return block;
             }
         case (DRObjects.Enums.MapType.LOCAL)
         :
             return GameState.LocalMap.GetBlockAtCoordinate(point).ConvertToGraphicalBlock();
         default:
             throw new NotImplementedException("There is no map manager for that type");
     }
 }
        public List<MapCoordinate> GetOutletMap(Guid distrubutrId, Guid? routeId)
        {
            IQueryable<tblCostCentre> data = _ctx.tblCostCentre.Where(s => s.CostCentreType == 5 && s.ParentCostCentreId == distrubutrId);
            if(routeId.HasValue)
            {
                data = data.Where(s => s.RouteId == routeId.Value);
            }
            var mapdata= new List<MapCoordinate>();
            foreach (var outlet in data)
            {
                float longi = 0, lati = 0;
                float.TryParse(outlet.StandardWH_Latitude,out lati);
                float.TryParse(outlet.StandardWH_Longtitude, out longi);
                var item = new MapCoordinate();
                item.Name = outlet.Name;
                item.Description = outlet.Name;
                item.Latitude = lati;
                item.Longitude = longi;
                mapdata.Add(item);

            }
            return mapdata;
        }
        public bool HandleKeyboard(Microsoft.Xna.Framework.Input.KeyboardState keyboard, out ActionType? actionType, out object[] args, out MapCoordinate coord, out bool destroy)
        {
            //This component doesn't handle any keyboard
            actionType = null;
            args = null;
            coord = null;
            //But because we're moving, destroy it
            destroy = false;

            return false;
        }
        public bool HandleClick(int x, int y, MouseActionEnum mouseAction, out ActionType? actionType, out InternalActionEnum? internalActionType, out object[] args, out MapItem itm, out MapCoordinate coord, out bool destroy)
        {
            itm = null;
            internalActionType = null;

            //We only handle left clicks properly
            if (mouseAction.Equals(MouseActionEnum.LEFT_CLICK))
            {
                //check whether x and y was within a context menu item
                foreach (ContextMenuItem item in this.contextMenuItems)
                {
                    if (item.Rect.Contains(new Point(x, y)))
                    {
                        actionType = item.Action;
                        args = item.Args;
                        coord = this.coordinate;

                        //destroy the component
                        destroy = true;

                        return true;
                    }

                }
                args = null;
                actionType = null;
                coord = null;
                destroy = false;

                return false;
            }
            else
            {
                actionType = null;
                args = null;
                coord = null;
                //destroy it
                destroy = true;

                return false;
            }
        }
        /// <summary>
        /// Performs the action and handles feedback
        /// </summary>
        /// <param name="?"></param>
        public void PerformAction(MapCoordinate coord, MapItem item, DRObjects.Enums.ActionType actionType, object[] args)
        {
            //remove any viewtiletext components or contextmenu components
            for (int i = 0; i < interfaceComponents.Count; i++)
            {
                var type = interfaceComponents[i].GetType();
                if (type.Equals(typeof(ViewTileTextComponent)) || type.Equals(typeof(ContextMenuComponent)))
                {
                    //delete
                    interfaceComponents.RemoveAt(i);
                    i--;
                }
            }

            ActionFeedback[] fb = UserInterfaceManager.PerformAction(coord, item, actionType, args);

            //go through all the feedback

            for (int i = 0; i < fb.Length; i++)
            {
                ActionFeedback feedback = fb[i];

                if (feedback == null)
                {
                    continue;
                }

                if (feedback.GetType().Equals(typeof(AttackFeedback)))
                {
                    AttackFeedback af = feedback as AttackFeedback;

                    var combatAf = CombatManager.Attack(af.Attacker, af.Defender, AttackLocation.CHEST); //always attack the chest

                    var tempFBList = fb.ToList();
                    tempFBList.AddRange(combatAf);

                    fb = tempFBList.ToArray();

                }
                else if (feedback.GetType().Equals(typeof(OpenInterfaceFeedback)))
                {
                    OpenInterfaceFeedback oif= feedback as OpenInterfaceFeedback;

                    //Generate one
                    if (oif.Interface.GetType() == typeof(CombatManualInterface))
                    {
                        var cmi = oif.Interface as CombatManualInterface;

                        CombatManualComponent cmc = new CombatManualComponent(GraphicsDevice.Viewport.Width / 2 - 200, GraphicsDevice.Viewport.Height / 2 - 150, cmi.Manual);

                        interfaceComponents.Add(cmc);
                    }
                    else if (oif.Interface.GetType() == typeof(ThrowItemInterface))
                    {
                        var tii = oif.Interface as ThrowItemInterface;

                        //Do we have LoS to that point?
                        if (GameState.LocalMap.HasDirectPath(GameState.PlayerCharacter.MapCharacter.Coordinate,tii.Coordinate))
                        {
                            ThrowItemComponent tic = new ThrowItemComponent(Mouse.GetState().X, Mouse.GetState().Y, tii.Coordinate, GameState.PlayerCharacter);
                            interfaceComponents.Add(tic);
                        }
                        else
                        {
                            var tempFBList = fb.ToList();
                            tempFBList.Add(new TextFeedback("You can't see there"));

                            fb = tempFBList.ToArray();
                        }
                    }
                }
                else
                if (feedback.GetType().Equals(typeof(TextFeedback)))
                {
                    MouseState mouse = Mouse.GetState();

                    //Display it
                    interfaceComponents.Add(new ViewTileTextComponent(mouse.X + 15, mouse.Y, (feedback as TextFeedback).Text));
                }
                else if (feedback.GetType().Equals(typeof(LogFeedback)))
                {
                    GameState.NewLog.Add(feedback as LogFeedback);
                }
                else if (feedback.GetType().Equals(typeof(InterfaceToggleFeedback)))
                {
                    InterfaceToggleFeedback iop = feedback as InterfaceToggleFeedback;

                    if (iop.InterfaceComponent == InternalActionEnum.OPEN_ATTACK && iop.Open)
                    {
                        //Open the attack interface for a particular actor. If one is not open already
                        //Identify the actor in question
                        var actorMapItem = iop.Argument as LocalCharacter;

                        //Locate the actual actor
                        Actor actor = GameState.LocalMap.Actors.Where(lm => lm.MapCharacter == actorMapItem).FirstOrDefault(); //Yep, it's a pointer equals

                        bool openAlready = false;

                        //Do we have one open already?
                        foreach (AttackActorComponent aac in interfaceComponents.Where(ic => ic.GetType().Equals(typeof(AttackActorComponent))))
                        {
                            if (aac.TargetActor.Equals(actor))
                            {
                                openAlready = true;
                                break;
                            }
                        }

                        if (!openAlready)
                        {
                            //Open it. Otherwise don't do anything
                            interfaceComponents.Add(new AttackActorComponent(150, 150, GameState.PlayerCharacter, actor) { Visible = true });
                        }

                    }
                    else if (iop.InterfaceComponent == InternalActionEnum.OPEN_ATTACK && !iop.Open)
                    {
                        //Close it
                        var actor = iop.Argument as Actor;

                        AttackActorComponent component = null;

                        foreach (AttackActorComponent aac in interfaceComponents.Where(ic => ic.GetType().Equals(typeof(AttackActorComponent))))
                        {
                            if (aac.TargetActor.Equals(actor))
                            {
                                component = aac;
                            }
                        }

                        //Did we have a match?
                        if (component != null)
                        {
                            //remove it
                            interfaceComponents.Remove(component);
                        }

                    }
                    else if (iop.InterfaceComponent == InternalActionEnum.OPEN_TRADE && iop.Open)
                    {
                        //Open trade
                        var arguments = iop.Argument as object[];

                        TradeDisplayComponent tdc = new TradeDisplayComponent(100, 100, arguments[1] as Actor, arguments[0] as Actor);

                        interfaceComponents.Add(tdc);
                    }
                    else if (iop.InterfaceComponent == InternalActionEnum.OPEN_LOOT)
                    {
                        //Open Loot
                        TreasureChest lootContainer = (iop.Argument as object[])[0] as TreasureChest;

                        LootComponent lc = new LootComponent(100, 100, lootContainer);

                        interfaceComponents.Add(lc);
                    }
                }
                else if (feedback.GetType().Equals(typeof(CreateEventFeedback)))
                {
                    CreateEventFeedback eventFeedback = feedback as CreateEventFeedback;

                    var gameEvent = EventHandlingManager.CreateEvent(eventFeedback.EventName);

                    //Create the actual control
                    interfaceComponents.Add(new DecisionPopupComponent(PlayableWidth / 2 - 150, PlayableHeight / 2 - 150, gameEvent));

                }
                else if (feedback.GetType().Equals(typeof(ReceiveEffectFeedback)))
                {
                    ReceiveEffectFeedback recFeed = feedback as ReceiveEffectFeedback;

                    EffectsManager.PerformEffect(recFeed.Effect.Actor, recFeed.Effect);
                }
                else if (feedback.GetType().Equals(typeof(ReceiveBlessingFeedback)))
                {
                    ReceiveBlessingFeedback blessFeedback = feedback as ReceiveBlessingFeedback;

                    LogFeedback lg = null;

                    //Bless him!
                    //Later we're going to want to do this properly so other characters can get blessed too
                    BlessingManager.GetAndApplyBlessing(GameState.PlayerCharacter, out lg);

                    if (lg != null)
                    {
                        //Log it
                        GameState.NewLog.Add(lg);
                    }
                }
                else if (feedback.GetType().Equals(typeof(ReceiveItemFeedback)))
                {
                    ReceiveItemFeedback receiveFeedback = feedback as ReceiveItemFeedback;

                    //Determine which item we're going to generate
                    InventoryItemManager iim = new InventoryItemManager();

                    InventoryItem itm = iim.GetBestCanAfford(receiveFeedback.Category.ToString(), receiveFeedback.MaxValue);

                    if (itm != null)
                    {
                        itm.InInventory = true;

                        GameState.PlayerCharacter.Inventory.Inventory.Add(itm.Category, itm);

                        GameState.NewLog.Add(new LogFeedback(InterfaceSpriteName.SUN, Color.DarkGreen, "You throw in your offering. You then see something glimmer and take it out"));
                    }
                    else
                    {
                        GameState.NewLog.Add(new LogFeedback(InterfaceSpriteName.MOON, Color.DarkBlue, "You throw in your offering. Nothing appears to be there. Hmm..."));
                    }

                }
                else if (feedback.GetType().Equals(typeof(LocationChangeFeedback)))
                {
                    //Remove settlement button and interface
                    var locDetails = this.interfaceComponents.Where(ic => ic.GetType().Equals(typeof(LocationDetailsComponent))).FirstOrDefault();

                    if (locDetails != null)
                    {
                        this.interfaceComponents.Remove(locDetails);
                    }

                    var button = this.menuButtons.Where(mb => (mb as AutoSizeGameButton).Action == InternalActionEnum.TOGGLE_SETTLEMENT).FirstOrDefault();

                    if (button != null)
                    {
                        this.menuButtons.Remove(button);
                    }

                    LocationChangeFeedback lce = feedback as LocationChangeFeedback;

                    if (lce.Location != null)
                    {
                        LoadLocation(lce.Location);

                        if (lce.Location is Settlement)
                        {

                            //Makde the components visible
                            LocationDetailsComponent ldc = new LocationDetailsComponent(GameState.LocalMap.Location as Settlement, PlayableWidth - 170, 0);
                            ldc.Visible = true;
                            interfaceComponents.Add(ldc);
                            menuButtons.Add(new AutoSizeGameButton(" Settlement ", this.game.Content, InternalActionEnum.TOGGLE_SETTLEMENT, new object[] { }, 270, GraphicsDevice.Viewport.Height - 35));
                            Window_ClientSizeChanged(null, null); //button is in the wrong position for some reason
                        }

                        GameState.LocalMap.IsGlobalMap = false;
                    }
                    else if (lce.VisitMainMap)
                    {
                        //If it's a bandit camp or a site, update the values of the members
                        if (GameState.LocalMap.Location as MapSite != null || GameState.LocalMap.Location as BanditCamp != null)
                        {
                            if (GameState.LocalMap.Location as BanditCamp != null)
                            {
                                var banditCamp = GameState.LocalMap.Location as BanditCamp;

                                banditCamp.BanditTotal = GameState.LocalMap.Actors.Count(a => a.IsActive && a.IsAlive && !a.IsPlayerCharacter
                                    && a.EnemyData != null && a.EnemyData.Profession == ActorProfession.WARRIOR);

                                //Has it been cleared?
                                if (banditCamp.BanditTotal == 0)
                                {
                                    //Find the item
                                    var campItem = GameState.GlobalMap.CampItems.FirstOrDefault(ci => ci.Camp == (GameState.LocalMap.Location as BanditCamp));

                                    if (campItem != null)
                                    {
                                        campItem.IsActive = false;

                                        GameState.GlobalMap.CampItems.Remove(campItem);

                                        //Also find the coordinate of the camp, grab a circle around it and remove the owner
                                        var mapblocks = GameState.GlobalMap.GetBlocksAroundPoint(campItem.Coordinate, WorldGenerationManager.BANDIT_CLAIMING_RADIUS);

                                        foreach (var block in mapblocks)
                                        {
                                            var tile = (block.Tile as GlobalTile);

                                            //Owned by bandit
                                            if (tile.Owner == 50)
                                            {
                                                tile.RemoveOwner();
                                            }
                                        }

                                        //Yes. Let's clear the camp
                                        GameState.NewLog.Add(new LogFeedback(InterfaceSpriteName.SWORD, Color.Black, "You drive the bandits away from the camp"));
                                    }

                                }

                            }
                            else if (GameState.LocalMap.Location as MapSite != null)
                            {
                                var site = GameState.LocalMap.Location as MapSite;

                                site.SiteData.ActorCounts.Clear();

                                foreach (var actorProfession in (ActorProfession[])Enum.GetValues(typeof(ActorProfession)))
                                {
                                    int count = GameState.LocalMap.Actors.Count(a => a.IsActive && a.IsAlive && !a.IsPlayerCharacter
                                    && a.EnemyData != null && a.EnemyData.Profession == actorProfession);

                                    site.SiteData.ActorCounts.Add(actorProfession, count);
                                }

                                if (site.SiteData.ActorCounts[ActorProfession.WARRIOR] == 0)
                                {
                                    //Out of warriors, abandon it. We'll decide who really owns it later
                                    site.SiteData.OwnerChanged = true;
                                    site.SiteData.MapRegenerationRequired = true;
                                    site.SiteData.Owners = OwningFactions.ABANDONED;
                                    site.SiteData.ActorCounts = new Dictionary<ActorProfession, int>();
                                }
                            }
                        }
                        //Serialise the old map
                        GameState.LocalMap.SerialiseLocalMap();

                        //Clear the stored location items
                        GameState.LocalMap.Location = null;

                        LoadGlobalMap(GameState.PlayerCharacter.GlobalCoordinates);

                        GameState.LocalMap.IsGlobalMap = true;

                    }
                    else if (lce.RandomEncounter != null)
                    {
                        //Get the biome
                        LoadRandomEncounter(lce.RandomEncounter.Value);
                    }
                }
                else if (feedback.GetType().Equals(typeof(DropItemFeedback)))
                {
                    DropItemFeedback dif = feedback as DropItemFeedback;

                    //Drop the item underneath the player
                    GameState.LocalMap.GetBlockAtCoordinate(dif.ItemToDrop.Coordinate).PutItemUnderneathOnBlock(dif.ItemToDrop);

                    //Remove from inventory
                    dif.ItemToDrop.InInventory = false;

                    GameState.PlayerCharacter.Inventory.Inventory.Remove(dif.ItemToDrop.Category, dif.ItemToDrop);
                }
                else if (feedback.GetType().Equals(typeof(TimePassFeedback)))
                {
                    TimePassFeedback tpf = feedback as TimePassFeedback;

                    //Move time forth
                    GameState.IncrementGameTime(DRTimeComponent.MINUTE, tpf.TimePassInMinutes);

                    //Is the character dead?
                    if (!GameState.PlayerCharacter.IsAlive)
                    {
                        var gameEvent = EventHandlingManager.CreateEvent("Hunger Death");

                        //Create the actual control
                        interfaceComponents.Add(new DecisionPopupComponent(PlayableWidth / 2 - 150, PlayableHeight / 2 - 150, gameEvent));
                    }
                }
                else if (feedback.GetType().Equals(typeof(VisitedBlockFeedback)))
                {
                    VisitedBlockFeedback vbf = feedback as VisitedBlockFeedback;

                    //Visit a region equal to the line of sight of the player character -
                    var blocks = GameState.LocalMap.GetBlocksAroundPoint(vbf.Coordinate, GameState.PlayerCharacter.LineOfSight);

                    //Only do the ones which can be ray traced
                    foreach (var block in RayTracingHelper.RayTraceForExploration(blocks, GameState.PlayerCharacter.MapCharacter.Coordinate))
                    {
                        block.WasVisited = true;
                    }
                }
                else if (feedback.GetType().Equals(typeof(DescendDungeonFeedback)))
                {
                    DescendDungeonFeedback ddf = feedback as DescendDungeonFeedback;

                    (GameState.LocalMap.Location as Dungeon).DifficultyLevel++;

                    this.LoadLocation(GameState.LocalMap.Location, true);
                }

            }

            //Update the log control
            log.UpdateLog();
        }
        public override void Update(GameTime gameTime)
        {
            //This fixes an issue in monogame with resizing
            graphics.ApplyChanges();

            //Is the user asking to quit?
            if (saveAndQuit)
            {
                //Go to loading. It'll open the main menu when it's done
                BaseGame.requestedInternalAction = InternalActionEnum.CONTINUE;
                BaseGame.requestedArgs = new object[1] { "Save" };

                saveAndQuit = false;
            }

            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                game.Exit();

            //Only check if the game is actually active and not busy
            if (Game.IsActive && !GameState.IsRunningHeavyProcessing)
            {

                //Lets see if there are any keyboard keys being pressed

                KeyboardState keyboardState = Keyboard.GetState();

                //Has the user pressed esc?
                if (keyboardState.IsKeyDown(Keys.Escape))
                {
                    GameState.NewLog.Add(new LogFeedback(InterfaceSpriteName.BANNER_GREEN, Color.White, "Saving Game Please Wait..."));

                    saveAndQuit = true;
                }

                bool shiftHeld = keyboardState.IsKeyDown(Keys.LeftShift) || keyboardState.IsKeyDown(Keys.RightShift);

                //has the user pressed one of the directional keys?
                //If yes, try to move

                //If shift was held, then we wait for less, so game moves faster
                if (gameTime.TotalGameTime.TotalMilliseconds - previousGameTime < GAMEINPUTDELAY / (shiftHeld ? 2 : 1))
                {
                    //do nothing
                }
                else
                {
                    //is there a component which wants to handle the keyboard movement?
                    ActionType? kAction = null;
                    object[] kArgs = null;
                    MapCoordinate kTargetCoord = null;

                    bool keyHandled = false;
                    bool destroy = false;

                    //Do it upside down, so the stuff which appears on top happens first
                    for (int i = interfaceComponents.Count - 1; i >= 0; i--)
                    {
                        var interfaceComponent = interfaceComponents[i];

                        keyHandled = interfaceComponent.HandleKeyboard(keyboardState, out kAction, out kArgs, out kTargetCoord, out destroy);

                        //do we destroy?

                        if (destroy)
                        {
                            interfaceComponents.RemoveAt(i);
                        }

                        if (keyHandled)
                        {
                            //Break out of the loop - someone handled it
                            break;
                        }
                    }

                    if (kAction != null)
                    {
                        this.PerformAction(kTargetCoord, null, kAction.Value, kArgs);
                    }

                    //did we do anything?
                    if (keyHandled)
                    {

                    }
                    else
                    {
                        //Lets see if tab is held down
                        if (keyboardState.IsKeyDown(Keys.Tab))
                        {
                            //Zoom out a bit
                            TILEWIDTH = MINTILEWIDTH;
                            TILEHEIGHT = MINTILEHEIGHT;
                        }
                        else
                        {
                            //Let's animate it :)

                            //Leave it zoomed in
                            TILEWIDTH = MAXTILEWIDTH;
                            TILEHEIGHT = MAXTILEHEIGHT;
                        }

                        //not handled, lets walk
                        //where is the user?
                        MapCoordinate coord = UserInterfaceManager.GetPlayerActor().MapCharacter.Coordinate;
                        MapCoordinate difference = new MapCoordinate(0, 0, 0, coord.MapType);
                        //we will either increase or decrease it by an amount depending on the directional key pressed

                        if (keyboardState.IsKeyDown(Keys.OemPeriod))
                        {
                            //Just waste time
                            this.PerformAction(null, null, ActionType.IDLE, null);
                        }
                        else if (keyboardState.IsKeyDown(Keys.Up))
                        {
                            difference = new MapCoordinate(0, 1, 0, coord.MapType);
                        }
                        else if (keyboardState.IsKeyDown(Keys.Down))
                        {
                            difference = new MapCoordinate(0, -1, 0, coord.MapType);
                        }
                        else if (keyboardState.IsKeyDown(Keys.Left))
                        {
                            difference = new MapCoordinate(-1, 0, 0, coord.MapType);
                        }
                        else if (keyboardState.IsKeyDown(Keys.Right))
                        {
                            difference = new MapCoordinate(1, 0, 0, coord.MapType);
                        }

                        //The fact that they'er not the same means the user pressed a key, lets move
                        if (!difference.Equals(new MapCoordinate(0, 0, 0, coord.MapType)))
                        {
                            //add the difference to the coordinate
                            coord += difference;

                            //send a move message to that coordinate
                            this.PerformAction(coord, null, DRObjects.Enums.ActionType.MOVE, null);

                        }

                    }
                    //mark the current time
                    previousGameTime = (int)gameTime.TotalGameTime.TotalMilliseconds;
                }

                #region Mouse Handling

                //See what the mouse is doing
                MouseState mouse = Mouse.GetState();

                MouseActionEnum? mouseAction = this.DetermineMouseAction(mouse);

                //this is a potential mouse action
                ActionType? action = null;
                object[] args = null;
                MapCoordinate targetCoord = null;
                MapItem item = null;

                //see if there is a component which will handle it instead

                //Is the mouse over a particular component ?
                foreach (var component in interfaceComponents.Where(ic => ic.Visible))
                {
                    if (component.ReturnLocation().Contains(mouse.X, mouse.Y))
                    {
                        //Mouse over trigger
                        component.HandleMouseOver(mouse.X, mouse.Y);
                    }
                }

                if (mouseAction != null)
                {
                    bool mouseHandled = false;

                    InternalActionEnum? internalAction = null;
                    object[] arg = null;

                    foreach (var menuButton in menuButtons)
                    {
                        if (menuButton.ReturnLocation().Contains(new Point(mouse.X, mouse.Y)) && mouseAction == MouseActionEnum.LEFT_CLICK && menuButton.HandleClick(mouse.X, mouse.Y, out internalAction, out arg))
                        {
                            mouseHandled = true; //don't get into the other loop
                            break; //break out
                        }
                    }

                    //Are we dragging something?

                    if (isDragging)
                    {
                        //Check the location we're at
                        int deltaX = mouse.X - dragPointX;
                        int deltaY = mouse.Y - dragPointY;

                        //Drag it
                        dragItem.PerformDrag(deltaX, deltaY);

                        //Update the dragpoints

                        dragPointX = deltaX;
                        dragPointY = deltaY;

                        //are we still dragging?
                        if (mouseAction.Value != MouseActionEnum.DRAG)
                        {
                            //Nope
                            isDragging = false;
                        }
                    }

                    //Do we have a MODAL interface component?
                    var modalComponent = interfaceComponents.Where(ic => ic.IsModal()).FirstOrDefault();

                    if (modalComponent != null)
                    {
                        //Force it to handle it
                        bool destroy = false;

                        modalComponent.HandleClick(mouse.X, mouse.Y, mouseAction.Value, out action, out internalAction, out args, out item, out targetCoord, out destroy);

                        if (destroy)
                        {
                            //Destroy it
                            interfaceComponents.Remove(modalComponent);
                        }

                        //It's handled
                        mouseHandled = true;
                    }

                    for (int i = interfaceComponents.Count - 1; i >= 0; i--)
                    {
                        if (mouseHandled)
                        {
                            break;
                        }

                        var interfaceComponent = interfaceComponents[i];

                        //is the click within this interface's scope? or is it modal?

                        Point mousePoint = new Point(mouse.X, mouse.Y);

                        if (interfaceComponent.IsModal() || interfaceComponent.ReturnLocation().Contains(mousePoint) && interfaceComponent.Visible)
                        {
                            bool destroy;

                            //Are we dragging?
                            if (mouseAction.Value == MouseActionEnum.DRAG)
                            {
                                //Yes
                                this.dragPointX = mouse.X;
                                this.dragPointY = mouse.Y;
                                isDragging = true;
                                dragItem = interfaceComponent;

                                mouseHandled = true;

                                //insert the item again
                                interfaceComponents.RemoveAt(i);

                                interfaceComponents.Add(interfaceComponent);

                                break; //break out
                            }

                            //see if the component can handle it
                            mouseHandled = interfaceComponent.HandleClick(mouse.X, mouse.Y, mouseAction.Value, out action, out internalAction, out args, out item, out targetCoord, out destroy);

                            if (destroy)
                            {
                                //destroy the component
                                interfaceComponents.RemoveAt(i);
                                i++;
                            }

                            if (mouseHandled)
                            {
                                //Get out of the loop - someone has handled it
                                break;
                            }
                        }
                    }

                    //dispatch the action, if any
                    if (action.HasValue)
                    {
                        this.PerformAction(targetCoord, item, action.Value, args);
                    }

                    //Dispatch the internal action, if any
                    if (internalAction.HasValue)
                    {
                        //Let's do it here
                        switch (internalAction.Value)
                        {
                            case InternalActionEnum.OPEN_HEALTH:
                                //Toggle the health
                                var health = this.interfaceComponents.Where(ic => ic.GetType().Equals(typeof(HealthDisplayComponent))).FirstOrDefault();

                                health.Visible = !health.Visible;

                                break;
                            case InternalActionEnum.OPEN_ATTRIBUTES:
                                //Toggle the attributes
                                var att = this.interfaceComponents.Where(ic => ic.GetType().Equals(typeof(CharacterSheetComponent))).FirstOrDefault();
                                att.Visible = !att.Visible;

                                break;

                            case InternalActionEnum.TOGGLE_SETTLEMENT:
                                //Toggle the settlements
                                var loc = this.interfaceComponents.Where(ic => ic.GetType().Equals(typeof(LocationDetailsComponent))).FirstOrDefault();
                                loc.Visible = !loc.Visible;

                                break;

                            case InternalActionEnum.OPEN_LOG:
                                //Toggle the log
                                var log = this.interfaceComponents.Where(ic => ic.GetType().Equals(typeof(TextLogComponent))).FirstOrDefault();
                                log.Visible = !log.Visible;
                                break;

                            case InternalActionEnum.OPEN_INVENTORY:
                                //Toggle inventory
                                var inv = this.interfaceComponents.Where(ic => ic.GetType().Equals(typeof(InventoryDisplayComponent))).FirstOrDefault();
                                inv.Visible = !inv.Visible;
                                break;

                            case InternalActionEnum.LOSE:
                                //For now, just go back to the main menu
                                BaseGame.requestedInternalAction = InternalActionEnum.EXIT;
                                BaseGame.requestedArgs = new object[0];
                                break;
                            case InternalActionEnum.MULTIDECISION:
                                //The only thing that has multidecisions right now is char creation
                                //So let's do it dirty for now
                                CharacterCreation.ProcessParameters(args[1] as List<string>);
                                break;

                            //TODO: THE REST
                        }
                    }

                    //do we continue?
                    if (mouseHandled)
                    {

                    }
                    else
                    {
                        //the grid will handle it

                        //determine where we clicked
                        int xCord = (int)(mouse.X / TILEWIDTH);
                        int yCord = (int)(mouse.Y / TILEHEIGHT);

                        //get the game coordinate from the interface coordinate

                        InterfaceBlock iBlock = blocks.FirstOrDefault(b => b.InterfaceX.Equals(xCord) && b.InterfaceY.Equals(yCord));

                        //if it was a left click, we look

                        if (mouseAction.Value == MouseActionEnum.LEFT_CLICK)
                        {
                            if (iBlock != null)
                            {
                                this.PerformAction(iBlock.MapCoordinate, null, DRObjects.Enums.ActionType.LOOK, null);
                            }
                        }
                        else if (mouseAction.Value == MouseActionEnum.RIGHT_CLICK)
                        {
                            if (iBlock != null)
                            {
                                ActionType[] actions = UserInterfaceManager.GetPossibleActions(iBlock.MapCoordinate);

                                //we are going to get a context menu

                                //Check for other context menus and remove them - we can only have one
                                for (int i = 0; i < interfaceComponents.Count; i++)
                                {
                                    if (interfaceComponents[i].GetType().Equals(typeof(ContextMenuComponent)))
                                    {
                                        //remove it
                                        interfaceComponents.RemoveAt(i);
                                        i--;
                                    }
                                }

                                ContextMenuComponent comp = new ContextMenuComponent(mouse.X + 10, mouse.Y, iBlock.MapCoordinate);

                                foreach (ActionType act in actions)
                                {
                                    comp.AddContextMenuItem(act, null, this.game.Content);
                                }

                                //And add it
                                interfaceComponents.Add(comp);
                            }
                        }
                    }

                } //end mouse handling

                this.lastLeftButtonClicked = (mouse.LeftButton == ButtonState.Pressed);
                this.lastRightButtonClicked = (mouse.RightButton == ButtonState.Pressed);
                #endregion
            }
        }
        /// <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;
        }
        /// <summary>
        /// Performs an action on a particular or a particular item.
        /// If item is not null, will use the item. Otherwise will use the coordinate
        /// </summary>
        /// <param name="coordinate"></param>
        /// <param name="actionType"></param>
        /// <param name="args"></param>
        public static ActionFeedback[] PerformAction(MapCoordinate coordinate,MapItem item, ActionType actionType, object[] args)
        {
            List<ActionFeedback> feedback = new List<ActionFeedback>();

            bool validAttack = false;

            if (actionType == ActionType.ATTACK)
            {
                //Handle this seperatly
                //Argument 0 - attacker
                //Argument 1 - target
                //Argument 2 - Body part to attack
                //Argument 3 - Special attack if there

                //Are we in the right place?
                Actor attacker = args[0] as Actor;
                Actor defender = args[1] as Actor;
                AttackLocation location = (AttackLocation) args[2];

                int distance = attacker.MapCharacter.Coordinate - defender.MapCharacter.Coordinate;

                if (defender.MapCharacter == null)
                {
                    //Something went wrong
                    validAttack = false;

                }

                if ( distance < 2)
                {
                    //Hand to hand

                    if (args.Length > 3)
                    {
                        //Special attack!
                        feedback.AddRange(CombatManager.PerformSpecialAttack(attacker, defender, args[3] as SpecialAttack));
                    }
                    else
                    {
                        feedback.AddRange(CombatManager.Attack(attacker, defender, location));
                    }
                    validAttack = true; //perform the tick
                }
                else
                {
                    //Is the attacker armed properly?
                    if (attacker.Inventory.EquippedItems.ContainsKey(EquipmentLocation.BOW))
                    {
                        //Do they have line of sight?
                        if (GameState.LocalMap.HasDirectPath(attacker.MapCharacter.Coordinate, defender.MapCharacter.Coordinate))
                        {
                            //Are they within a reasonable distance?
                            if (distance <= attacker.LineOfSight)
                            {
                                //Yes!
                                if (args.Length > 3)
                                {
                                    //Special attack!
                                    feedback.AddRange(CombatManager.PerformSpecialAttack(attacker, defender, args[3] as SpecialAttack));
                                }
                                else
                                {
                                    feedback.AddRange(CombatManager.Attack(attacker, defender, location));
                                }
                                validAttack = true;
                            }
                            else
                            {
                                validAttack = false;
                                return new ActionFeedback[] { new LogFeedback(InterfaceSpriteName.PERC,Color.Black, "This target is outside of your range") };
                            }
                        }
                        else
                        {
                            validAttack = false;
                            return new ActionFeedback[] { new LogFeedback(null, Color.Black, "You don't have a clear line of sight to the target") };
                        }

                    }
                    else
                    {
                        validAttack = false;
                        //Invalid - no tick
                        return new ActionFeedback[] { new LogFeedback(null, Color.Black, "You are too far away to hit your target") };
                    }
                }
            }
            else if (actionType == ActionType.THROW_ITEM)
            {
                //Throw it
                Potion potion = args[2] as Potion;
                Actor attacker = args[0] as Actor;
                List<Actor> victims = args[1] as List<Actor>;

                //Also create a temporary icon to show what was done
                foreach(var victim in victims)
                {
                    TemporaryGraphic tg = new TemporaryGraphic()
                    {
                        Coord = victim.MapCharacter.Coordinate,
                        Graphic = SpriteManager.GetSprite(InterfaceSpriteName.POTION_BREAK),
                        LifeTime = 2
                    };

                    GameState.LocalMap.TemporaryGraphics.Add(tg);
                }

                feedback.AddRange(potion.ThrowUpon(attacker, victims));
            }
            else if (actionType == ActionType.IDLE)
            {
                //Do nothing
            }
            else
            {
                if (item == null)
                {
                    switch (coordinate.MapType)
                    {
                        case MapType.LOCAL:
                            feedback.AddRange(GameState.LocalMap.GetBlockAtCoordinate(coordinate).PerformAction(actionType, GameState.PlayerCharacter, args));
                            break;
                        case MapType.GLOBAL:
                            feedback.AddRange(GameState.GlobalMap.GetBlockAtCoordinate(coordinate).PerformAction(actionType, GameState.PlayerCharacter, args));
                            break;
                        default:
                            throw new NotImplementedException("There is no support for that particular maptype");
                    }
                }
                else
                {
                    //Perform it on the item
                    feedback.AddRange(item.PerformAction(actionType, GameState.PlayerCharacter, args));
                }
            }

            if (actionType == ActionType.EXAMINE || actionType == ActionType.THROW_ITEM || actionType == ActionType.MOVE || (actionType == ActionType.ATTACK && validAttack) || actionType == ActionType.IDLE)
            {
                //Perform a tick
                //Clear the Log
                GameState.NewLog.Clear();
                feedback.AddRange(UserInterfaceManager.PerformLocalTick());
            }

            //Is the player stunned?
            while (GameState.PlayerCharacter.IsStunned && GameState.PlayerCharacter.IsAlive)
            {
                feedback.AddRange(UserInterfaceManager.PerformLocalTick());
            }

            return feedback.ToArray();
        }
        /// <summary>
        /// Gets a number of graphical blocks around a particular point.
        /// The order will be as follows:
        /// first max z, then max x, then max y.
        /// </summary>
        /// <param name="centrePoint">The center point around which the tiles will be calculated</param>
        /// <param name="xRange">How many tiles away from the centre point on the x axis will be obtained</param>
        /// <param name="yCount">How many tiles away from the centre point on the y axis will be obtained</param>
        /// <param name="zCount">How many tiles away from the centre point on the y axis will be obtained</param>
        /// <param name="overlay">If its a global map, the overlay to apply on it</param>
        /// <returns></returns>
        public static GraphicalBlock[] GetBlocksAroundPoint(MapCoordinate centrePoint, int xRange, int yRange, int zRange,GlobalOverlay overlay = GlobalOverlay.NONE)
        {
            int minZ = centrePoint.Z - Math.Abs(zRange);
            int maxZ = centrePoint.Z + Math.Abs(zRange);

            int minY = centrePoint.Y - Math.Abs(yRange);
            int maxY = centrePoint.Y + Math.Abs(yRange);

            int minX = centrePoint.X - Math.Abs(xRange);
            int maxX = centrePoint.X + Math.Abs(xRange);

            List<GraphicalBlock> returnList = new List<GraphicalBlock>();

            //go through all of them

            for (int zLoop = maxZ; zLoop >= minZ; zLoop--)
            {
                for (int yLoop = maxY; yLoop >= minY; yLoop--)
                {
                    for (int xLoop = minX; xLoop <= maxX; xLoop++)
                    {
                        MapCoordinate coord = new MapCoordinate(xLoop, yLoop, zLoop, centrePoint.MapType);
                        if (overlay != GlobalOverlay.NONE)
                        {
                            returnList.Add(GetBlockAtPoint(coord, overlay));
                        }
                        else
                        {
                            returnList.Add(GetBlockAtPoint(coord));
                        }
                    }
                }

            }

            return returnList.ToArray();
        }
        /// <summary>
        /// Puts settlement items on a particular location pertianing to a particular settlement.
        /// </summary>
        /// <param name="capital">Whether it's the capital or not</param>
        /// <param name="settlement">The settlement which it represents</param>
        /// <param name="block">The block making up the center</param>
        private static SettlementItem CreateSettlement(bool capital, Settlement settlement, MapBlock block, int owner)
        {
            //Put an entire group of SettlementItems on it
            MapCoordinate[] settlementCoordinates = new MapCoordinate[10];

            SettlementItem retItem = null;

            settlementCoordinates[7] = new MapCoordinate(block.Tile.Coordinate.X - 1, block.Tile.Coordinate.Y - 1, 0, MapType.GLOBAL);
            settlementCoordinates[8] = new MapCoordinate(block.Tile.Coordinate.X, block.Tile.Coordinate.Y - 1, 0, MapType.GLOBAL);
            settlementCoordinates[9] = new MapCoordinate(block.Tile.Coordinate.X + 1, block.Tile.Coordinate.Y - 1, 0, MapType.GLOBAL);
            settlementCoordinates[4] = new MapCoordinate(block.Tile.Coordinate.X - 1, block.Tile.Coordinate.Y, 0, MapType.GLOBAL);
            settlementCoordinates[5] = new MapCoordinate(block.Tile.Coordinate.X, block.Tile.Coordinate.Y, 0, MapType.GLOBAL);
            settlementCoordinates[6] = new MapCoordinate(block.Tile.Coordinate.X + 1, block.Tile.Coordinate.Y, 0, MapType.GLOBAL);
            settlementCoordinates[1] = new MapCoordinate(block.Tile.Coordinate.X - 1, block.Tile.Coordinate.Y + 1, 0, MapType.GLOBAL);
            settlementCoordinates[2] = new MapCoordinate(block.Tile.Coordinate.X, block.Tile.Coordinate.Y + 1, 0, MapType.GLOBAL);
            settlementCoordinates[3] = new MapCoordinate(block.Tile.Coordinate.X + 1, block.Tile.Coordinate.Y + 1, 0, MapType.GLOBAL);

            //Block the radius around it from colonising
            MapBlock[] regionalBlocks = GetBlocksAroundPoint(block.Tile.Coordinate, HUMAN_COLONY_BLOCKING_RADIUS);

            foreach (MapBlock rblock in regionalBlocks)
            {
                (rblock.Tile as GlobalTile).IsBlockedForColonisation = true;
            }

            //Claim the land around it
            MapBlock[] claimedBlocks = GetBlocksAroundPoint(block.Tile.Coordinate, HUMAN_COLONY_CLAIMING_RADIUS);

            foreach (MapBlock rblock in claimedBlocks)
            {
                //This is a disputed region. For now let's not allow creep.
                //Later this might be cause for war
                if (!(rblock.Tile as GlobalTile).Owner.HasValue)
                {
                    (rblock.Tile as GlobalTile).Owner = owner;
                }
            }

            for (int corner = 1; corner < 10; corner++)
            {
                var cornerBlock = GameState.GlobalMap.GetBlockAtCoordinate(settlementCoordinates[corner]);

                //Cut any forests down
                switch ((cornerBlock.Tile as GlobalTile).Biome)
                {
                    case GlobalBiome.DENSE_FOREST:
                        (cornerBlock.Tile as GlobalTile).Biome = GlobalBiome.GRASSLAND;
                        break;
                    case GlobalBiome.WOODLAND:
                        (cornerBlock.Tile as GlobalTile).Biome = GlobalBiome.GRASSLAND;
                        break;
                    case GlobalBiome.POLAR_FOREST:
                        (cornerBlock.Tile as GlobalTile).Biome = GlobalBiome.POLAR_DESERT;
                        break;
                }

                var settlementItem = new SettlementItem()
                {
                    Coordinate = settlementCoordinates[corner],
                    IsCapital = capital,
                    MayContainItems = true,
                    SettlementCorner = corner,
                    SettlementSize = settlement.SettlementSize,
                    Description = (capital ? "the capital of " + settlement.Name : "the settlement of " + settlement.Name) + " owned by " + settlement.Civilisation.Name,
                    Name = settlement.Name,
                    Settlement = settlement,
                    OwnerID = owner
                };

                GameState.GlobalMap.GetBlockAtCoordinate(settlementCoordinates[corner])
                .ForcePutItemOnBlock(settlementItem);

                if (settlementItem.SettlementCorner == 5) //center
                {
                    retItem = settlementItem;
                }
            }

               return retItem;
        }
Exemple #18
0
 /// <summary>
 /// Creates a default map item at a current location
 /// </summary>
 /// <param name="coordinate"></param>
 public MapItem(MapCoordinate coordinate)
 {
     this.Coordinate = coordinate;
     this.Graphics = new List<SpriteData>();
 }
        /// <summary>
        /// Generates a map with a particular biome
        /// </summary>
        /// <param name="herdAmount">The total amount of herds to generate</param>
        /// <param name="BanditAmount">The total amount of bandits to generate.</param>
        /// <param name="actors"></param>
        /// <returns></returns>
        public static MapBlock[,] GenerateMap(GlobalBiome biome, int herdAmount, int banditAmount, out Actor[] actors, out MapCoordinate startPoint)
        {
            MapBlock[,] map = new MapBlock[MAP_EDGE, MAP_EDGE];

            Random random = new Random();

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

            int tileID = 0;

            factory.CreateItem(Archetype.TILES, details[biome].BaseTileTag, out tileID);

            //Create a new map which is edge X edge in dimensions and made of the base tile
            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", tileID);
                    block.Tile.Coordinate = new MapCoordinate(x, y, 0, MapType.LOCAL);
                }
            }

            #region Leave Town Item

            //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 = "continue on your journey";
                lti.Name = "Leave Area";

                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 = "continue on your journey";
                lti.Name = "Leave Area";

                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 = "continue on your journey";
                lti.Name = "Leave Area";

                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 = "continue on your journey";
                lti.Name = "Leave Area";

                lti.Coordinate = coo;

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

            #endregion

            #region Desert Oasis
            if (biome == GlobalBiome.ARID_DESERT)
            {
                //Let's create a pool of water towards one of the corners.
                int randomNumber = random.Next(2);

                int rXCoord = 0;

                if (randomNumber == 1)
                {
                    //Lower
                    rXCoord = random.Next(0, MAP_EDGE / 3);
                }
                else
                {
                    rXCoord = random.Next(2 * MAP_EDGE / 3, MAP_EDGE);
                }

                randomNumber = random.Next(2);

                int rYCoord = 0;

                if (randomNumber == 1)
                {
                    //Lower
                    rYCoord = random.Next(0, MAP_EDGE / 3);
                }
                else
                {
                    rYCoord = random.Next(2 * MAP_EDGE / 3, MAP_EDGE);
                }

                //The pool will have a radius of 3

                MapCoordinate coo = new MapCoordinate(rXCoord, rYCoord, 0, MapType.LOCAL);

                //Go through the blocks with a radius of 3
                var oasisBlocks = map.Cast<MapBlock>().ToArray().Where(b => Math.Abs(b.Tile.Coordinate - coo) <= 3).ToArray();

                int waterTile = -1;

                factory.CreateItem(Archetype.TILES, "water", out waterTile);

                foreach (var block in oasisBlocks)
                {
                    var coord = block.Tile.Coordinate;
                    block.Tile = factory.CreateItem("tile", waterTile);
                    block.Tile.Coordinate = coord;
                }

                var aroundOasis = map.Cast<MapBlock>().ToArray().Where(b => Math.Abs(b.Tile.Coordinate - coo) <= 4 && Math.Abs(b.Tile.Coordinate - coo) > 3).ToArray();

                int dummy;

                int grassTile = 0;

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

                foreach (var block in aroundOasis)
                {
                    var coord = block.Tile.Coordinate;
                    block.Tile = factory.CreateItem("tile", grassTile);
                    block.Tile.Coordinate = coord;
                }

                //Put in some trees around the pool
                for (int i = 0; i < 3; i++)
                {
                    MapItem tree = factory.CreateItem(Archetype.MUNDANEITEMS, "jungle tree", out dummy);

                    var block = aroundOasis[random.Next(aroundOasis.Length)];

                    if (block.MayContainItems)
                    {
                        //Drop it
                        block.ForcePutItemOnBlock(tree);
                    }
                }

            }
            #endregion

            #region Wetland Splotches

            if (biome == GlobalBiome.WETLAND)
            {
                int waterTile = -1;

                factory.CreateItem(Archetype.TILES, "water", out waterTile);

                for (int i=0; i < 7; i++)
                {
                    MapBlock rBlock = map[random.Next(map.GetLength(0)), random.Next(map.GetLength(1))];

                    Rectangle safeRect = new Rectangle( MAP_EDGE/2 - 5,MAP_EDGE/2 -5,10,10);

                    if (safeRect.Contains(rBlock.Tile.Coordinate.X,rBlock.Tile.Coordinate.Y))
                    {
                        continue; //Not here!
                    }

                    int size = random.Next(1, 3);

                    //Get all the tiles around the block for a particular size
                    var pool = map.Cast<MapBlock>().ToArray().Where(b => Math.Abs(b.Tile.Coordinate - rBlock.Tile.Coordinate) <= size).ToArray();

                    foreach(var block in pool)
                    {
                        MapCoordinate coo = block.Tile.Coordinate;
                        block.Tile = factory.CreateItem("tiles", waterTile);
                        block.Tile.Coordinate = coo;
                    }
                }
            }

            #endregion

            for (int i = 0; i < details[biome].TreeCount; i++)
            {
                int treeID = 0;
                MapItem item = null;

                item = factory.CreateItem(Archetype.MUNDANEITEMS, details[biome].TreeTag, out treeID);

                //try 50 times to put it somewhere
                int tries = 0;

                while (tries < 50)
                {
                    MapBlock randomBlock = map[random.Next(map.GetLength(0)), random.Next(map.GetLength(1))];

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

                    tries++;
                }
            }

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

            //There, now that's done, lets generate some animals
            if (herdAmount + banditAmount > 0)
            {
                var herds = ActorGeneration.CreateAnimalHerds(biome, false, null, herdAmount);
                var bandits = CampGenerator.CreateBandits(banditAmount);

                var actorGroups = herds.Union(bandits);

                //Each actor group will be placed in a random 3 radius circle

                foreach (var actorGroup in actorGroups)
                {
                    MapBlock randomBlock = map[random.Next(map.GetLength(0)), random.Next(map.GetLength(1))];

                    Rectangle wanderRect = new Rectangle(randomBlock.Tile.Coordinate.X - 2, randomBlock.Tile.Coordinate.Y - 2, 4, 4);

                    //Put the actor groups somewhere around that block
                    var blocks = map.Cast<MapBlock>().ToArray().Where(b => Math.Abs(b.Tile.Coordinate - randomBlock.Tile.Coordinate) < 4).ToArray();

                    //Pick a number of random blocks

                    foreach (var newActor in actorGroup)
                    {
                        int tries = 0;

                        while (tries < 50)
                        {
                            var actorBlock = blocks[random.Next(blocks.Length)];

                            if (actorBlock.MayContainItems)
                            {
                                //Put it there
                                newActor.MapCharacter.Coordinate = actorBlock.Tile.Coordinate;
                                actorBlock.ForcePutItemOnBlock(newActor.MapCharacter);

                                //Make them wander
                                newActor.MissionStack.Push(new WanderMission() { LoiterPercentage = 50, WanderPoint = actorBlock.Tile.Coordinate, WanderRectangle = wanderRect });

                                actorList.Add(newActor);

                                break;
                            }

                            tries++;
                        }
                    }
                }

            }

            //Drop the player in the thick of it
            MapBlock center = map[map.GetLength(0) / 2, map.GetLength(1) / 2];

            center.RemoveTopItem(); //Remove it if someone else wanted it

            startPoint = center.Tile.Coordinate;

            actors = actorList.ToArray();

            return map;
        }
        public static ActionFeedback[] WanderMission(WanderMission mission, Actor actor)
        {
            MapCoordinate playerLocation = GameState.PlayerCharacter.MapCharacter.Coordinate;

            if (actor.UsesRanged)
            {
                //Is he a ranged user and seeing the player character
                if (actor.IsAggressive && actor.MapCharacter.Coordinate - playerLocation <= actor.LineOfSight)
                {
                    //Attack!
                    actor.MissionStack.Push(actor.CurrentMission);

                    actor.CurrentMission = new AttackMission(GameState.PlayerCharacter);
                }

            }
            else
            {
                //Is he seeing the player character?
                if (actor.IsAggressive && Math.Abs(actor.MapCharacter.Coordinate - playerLocation) <= 1)
                {
                    //He's there. Push the current mission into the stack and go on the attack
                    actor.MissionStack.Push(actor.CurrentMission);
                    actor.CurrentMission = new AttackMission(GameState.PlayerCharacter);
                    return new ActionFeedback[] { };
                }
                else if (actor.IsAggressive && Math.Abs(actor.MapCharacter.Coordinate - playerLocation) < actor.LineOfSight)
                {
                    //He's there. Push the current mission into the stack and follow him
                    actor.MissionStack.Push(actor.CurrentMission);
                    actor.CurrentMission = new HuntDownMission()
                    {
                        Target = GameState.PlayerCharacter,
                        TargetCoordinate = GameState.PlayerCharacter.MapCharacter.Coordinate
                    };

                    return new ActionFeedback[] { };
                }
            }

            //Perform an action accordingly
            //Is he outside of the patrol area?
            if (!mission.WanderRectangle.Contains(actor.MapCharacter.Coordinate.X, actor.MapCharacter.Coordinate.Y))
            {
                //Send him back.
                WalkToMission walkMission = new WalkToMission();
                walkMission.TargetCoordinate = mission.WanderPoint;

                //Push it
                actor.MissionStack.Push(mission);
                actor.CurrentMission = walkMission;
            }
            else
            {
                int randomNumber = GameState.Random.Next(100);
                //Do we wander?
                if (mission.LoiterPercentage != 0 && randomNumber < mission.LoiterPercentage)
                {
                    //Nope, we loiter
                }
                else
                {
                    //Walk somewhere randomly
                    int direction = GameState.Random.Next(4);

                    MapCoordinate coord = actor.MapCharacter.Coordinate;
                    //Copy it
                    MapCoordinate newCoord = new MapCoordinate(coord.X, coord.Y, coord.Z, coord.MapType);

                    switch (direction)
                    {
                        case 0: //Top
                            newCoord.Y++;
                            break;
                        case 1: //Bottom
                            newCoord.Y--;
                            break;
                        case 2: //Right
                            newCoord.X++;
                            break;
                        case 3: //Left
                            newCoord.X--;
                            break;
                    }

                    //Can we go there?
                    if (GameState.LocalMap.GetBlockAtCoordinate(newCoord).MayContainItems && mission.WanderRectangle.Contains(newCoord.X, newCoord.Y))
                    {
                        //Do it
                        GameState.LocalMap.GetBlockAtCoordinate(newCoord).PutItemOnBlock(actor.MapCharacter);
                        actor.MapCharacter.Coordinate = newCoord;

                        //And that's done
                    }
                }
                //Otherwise do nothing. Stay there
            }

            return new ActionFeedback[] { };
        }
        public static IEnumerable<ActionFeedback> PerformActions(Actor actor, IEnumerable<Actor> actors, MapCoordinate playerLocation)
        {
            if (GameState.LocalMap.PathfindingMap == null)
            {
                GameState.LocalMap.GeneratePathfindingMap();
            }

            List<ActionFeedback> feedback = new List<ActionFeedback>();

            //First check whether they have a mission
            while (actor.CurrentMission == null)
            {
                //Try to pop a new one
                if (actor.MissionStack.Count() == 0)
                {
                    //no mission. ah well
                    return new ActionFeedback[] { };
                }

                actor.CurrentMission = actor.MissionStack.Pop();

                if (actor.CurrentMission == null)
                {
                    //Just idle then
                    actor.CurrentMission = new IdleMission();
                }

                if (!actor.CurrentMission.IsRetainable)
                {
                    //Discard!
                    actor.CurrentMission = null; //grab another
                }

            }

            //Update the graphic
            if (actor.IsProne)
            {
                (actor.MapCharacter as LocalCharacter).EnemyThought = EnemyThought.PRONE;
            }
            else
            {
                (actor.MapCharacter as LocalCharacter).EnemyThought = actor.CurrentMission.EnemyThought;
            }

            if (actor.IsStunned) //Do nothing
            {
                return new ActionFeedback[] { };
            }

            if (actor.IsProne)
            {
                //Can we get up?
                if (GameState.LocalMap.GetBlockAtCoordinate(actor.MapCharacter.Coordinate).MayContainItems)
                {
                    //Yes we can
                    actor.IsProne = false;
                }
                else
                {
                    return new ActionFeedback[] { }; //Do nothing
                }
            }

            if (actor.CurrentMission.MissionType == DRObjects.ActorHandling.ActorMissionType.IDLE)
            {
                if (actor.IsAggressive && Math.Abs(actor.MapCharacter.Coordinate - playerLocation) < actor.LineOfSight)
                {
                    //He's there. Push the current mission into the stack and follow him
                    actor.MissionStack.Push(actor.CurrentMission);
                    actor.CurrentMission = new HuntDownMission()
                    {
                        Target = actors.Where(a => a.IsPlayerCharacter).FirstOrDefault(),
                        TargetCoordinate = actors.Where(a => a.IsPlayerCharacter).FirstOrDefault().MapCharacter.Coordinate
                    };

                    return new ActionFeedback[] { };
                }
            }
            else if (actor.CurrentMission.MissionType == DRObjects.ActorHandling.ActorMissionType.WAIT)
            {
                return WaitMission(actor.CurrentMission as WaitMission, actor);
            }
            else if (actor.CurrentMission.MissionType == DRObjects.ActorHandling.ActorMissionType.WANDER)
            {
                return WanderMission(actor.CurrentMission as WanderMission, actor);
            }
            else if (actor.IsAggressive && actor.CurrentMission.MissionType == DRObjects.ActorHandling.ActorMissionType.ATTACK)
            {
                return AttackMission(actor.CurrentMission as AttackMission, actor);
            }
            else if (actor.IsAggressive && actor.CurrentMission.MissionType == DRObjects.ActorHandling.ActorMissionType.HUNTDOWN)
            {
                return HuntDownMission(actor.CurrentMission as HuntDownMission, actor);
            }
            else if (actor.CurrentMission.MissionType == DRObjects.ActorHandling.ActorMissionType.WALKTO)
            {
                return WalkToMission(actor.CurrentMission as WalkToMission, actor);
            }
            else if (actor.CurrentMission.MissionType == DRObjects.ActorHandling.ActorMissionType.PATROL)
            {
                return PatrolMission(actor.CurrentMission as PatrolMission, actor);
            }
            else if (actor.CurrentMission.MissionType == ActorMissionType.PATROL_ROUTE)
            {
                return PatrolRouteMission(actor.CurrentMission as PatrolRouteMission, actor);
            }

            return feedback;
        }
        public static MapBlock[,] GenerateDungeonLevel(int level, int percentCovered, out MapCoordinate startPoint, out Actor[] enemies, out Dungeon dungeon)
        {
            startPoint = new MapCoordinate();
            List<Actor> ens = new List<Actor>();
            List<Rectangle> rectangles = null;
            Stack<Rectangle> unusedRectangles = null;
            ItemFactory.ItemFactory fact = new ItemFactory.ItemFactory();
            List<SummoningCircle> summoningCircles = new List<SummoningCircle>();

            int tileID = -1;

            MapBlock[,] map = GenerateBaseMap(level, percentCovered, out rectangles, out tileID);

            //Copy the rectangles
            unusedRectangles = new Stack<Rectangle>();

            foreach (var rectangle in rectangles)
            {
                unusedRectangles.Push(rectangle);
            }

            //Put the tiles

            SummoningCircle dummyCircle = null;

            //Each rectangle is going to contain a room

            //First pick two to be the start and end rooms
            PutRoom(map, tileID, level, DungeonRoomType.ENTRANCE, unusedRectangles.Pop(), out dummyCircle);

            startPoint = new MapCoordinate(rectangles[rectangles.Count - 1].Center.X, rectangles[rectangles.Count - 1].Center.Y, 0, MapType.LOCAL);

            PutRoom(map, tileID, level, DungeonRoomType.EXIT, unusedRectangles.Pop(), out dummyCircle);

            //Then pick d6 + level as summoning rooms. Ensuring they are less than half the rooms
            int summoningRooms = GameState.Random.Next(1, 6) + level;

            summoningRooms = summoningRooms > rectangles.Count / 2 ? rectangles.Count / 2 : summoningRooms;

            for (int i = 0; i < summoningRooms; i++)
            {
                SummoningCircle circle = null;

                PutRoom(map, tileID, level, DungeonRoomType.SUMMONING, unusedRectangles.Pop(), out circle); //Create them

                //Grab references to the summoning circle as we'll need them later

                summoningCircles.Add(circle);
            }

            int treasureRooms = GameState.Random.Next((int)Math.Ceiling((double)(level / 2 > 5 ? 5 : level / 2)));

            if (treasureRooms > unusedRectangles.Count)
            {
                treasureRooms = unusedRectangles.Count - 1;
            }
            else if (treasureRooms < 1)
            {
                treasureRooms = 1; //At least one
            }

            //Create some treasure rooms
            for (int i = 0; i < treasureRooms; i++)
            {
                PutRoom(map, tileID, level, DungeonRoomType.TREASURE, unusedRectangles.Pop(), out dummyCircle);
            }

            //Then we can pick some of the rooms as being the other room types
            List<DungeonRoomType> roomTypes = ((DungeonRoomType[])Enum.GetValues(typeof(DungeonRoomType))).ToList();

            roomTypes.Remove(DungeonRoomType.ENTRANCE);
            roomTypes.Remove(DungeonRoomType.EXIT);

            for(int i=0; i < 7; i++)
            {
                roomTypes.Add(DungeonRoomType.EMPTY);
            }

            //Make the remaining rectangles into rooms

            while (unusedRectangles.Count > 0)
            {
                //Pick a room type at random
                PutRoom(map, tileID, level, roomTypes.GetRandom(), unusedRectangles.Pop(), out dummyCircle);
            }

            //Package it all into a Dungeon object
            dungeon = new Dungeon();
            dungeon.DifficultyLevel = level;
            dungeon.Rooms = rectangles;
            dungeon.SummoningCircles = summoningCircles;
            enemies = ens.ToArray();

            return map;
        }
        /// <summary>
        /// Part 1 - Generate the base map
        /// </summary>
        /// <param name="level"></param>
        /// <param name="percentCovered"></param>
        /// <returns></returns>
        private static MapBlock[,] GenerateBaseMap(int level, int percentCovered, out List<Rectangle> rectangles, out int tileID)
        {
            MapBlock[,] map = new MapBlock[SIZE, SIZE];

            ItemFactory.ItemFactory fact = new ItemFactory.ItemFactory();

            //Put the tiles
            tileID = -1;
            var dummy = fact.CreateItem("tiles", "cave", out tileID);

            for (int x = 0; x < SIZE; x++)
            {
                for (int y = 0; y < SIZE; y++)
                {
                    map[x, y] = new MapBlock(); //Start with air :)
                    map[x, y].Tile = new Air();
                    map[x, y].Tile.Coordinate = (new MapCoordinate(x, y, 0, MapType.LOCAL));
                }
            }

            //Now we need to drop particular shapes on the map, with a minimum area of MINIMUM_AREA until we reach a particular percentage covered
            int totalCovered = 0;
            //Or until we run out of attempts
            int attempts = 0;

            rectangles = new List<Rectangle>();

            while (totalCovered < AREA && attempts < 50)
            {
                attempts++;
                //Pick a random spot to drop it in
                Random random = GameState.Random;

                Point p = new Point(random.Next(SIZE), random.Next(SIZE));

                //From this point, draw a rectangle with a random size from Edge to Edge
                Rectangle rect = new Rectangle(p.X, p.Y, random.Next(MINIMUM_EDGE, MAXIMUM_EDGE), random.Next(MINIMUM_EDGE, MAXIMUM_EDGE));

                //Does it have a valid area? Is it within the current map
                if ((rect.Width * rect.Height) >= MINIMUM_AREA && rect.Right < SIZE && rect.Bottom < SIZE)
                {
                    //Does it intersect or is contained within another rectangle ?
                    //(This will not preclude two rectangles next to each other, as long as they don't intersect)

                    if (rectangles.Any(r => r.Intersects(rect) || r.Contains(rect) || rect.Contains(r)))
                    {
                        //invalid
                        continue;
                    }

                    rectangles.Add(rect); //Valid
                    totalCovered += (rect.Width * rect.Height);
                    attempts = 0;
                }
                else
                {
                    //invalid
                    continue;
                }
            }

            //Now we should have a number of rectangles, let's turn those into actual rooms
            foreach (var rect in rectangles)
            {
                for (int x = 0; x < rect.Width; x++)
                {
                    for (int y = 0; y < rect.Height; y++)
                    {
                        MapCoordinate coord = new MapCoordinate(rect.X + x, rect.Y + y, 0, MapType.LOCAL);

                        MapBlock b = map[coord.X, coord.Y];
                        b.Tile = fact.CreateItem("tiles", tileID);
                        b.Tile.Coordinate = coord;
                    }
                }
            }
            int pathTile = -1;
            dummy = fact.CreateItem("tiles", "pavement", out pathTile);

            //Let's connect each room with each other room
            for (int i = 0; i < rectangles.Count; i++)
            {
                Rectangle curr = rectangles[i];
                Rectangle next = i == rectangles.Count - 1 ? rectangles[0] : rectangles[i + 1];  //Next rectangle is either the one in the list, or the first one

                PathfinderInterface.Nodes = GeneratePathfindingMapConnector(map);

                //Path from the center of the rectangles

                var path = PathfinderInterface.GetPath(new MapCoordinate(curr.Center.X, curr.Center.Y, 0, MapType.LOCAL), new MapCoordinate(next.Center.Y, next.Center.Y, 0, MapType.LOCAL));

                if (path != null)
                {
                    //Path it!
                    foreach (var p in path)
                    {
                        if (!map[p.X, p.Y].MayContainItems)
                        {
                            MapCoordinate coord = new MapCoordinate(p.X, p.Y, 0, MapType.LOCAL);

                            MapBlock b = map[coord.X, coord.Y];
                            b.Tile = fact.CreateItem("tiles", pathTile);
                            b.Tile.Coordinate = coord;
                        }
                    }
                }
            }

            //Now we can go through the blocks and put walls around the border

            int borderID = -1;
            dummy = fact.CreateItem("mundaneitems", "dungeon wall", out borderID);

            for (int x = 0; x < SIZE; x++)
            {
                for (int y = 0; y < SIZE; y++)
                {
                    MapBlock current = map[x, y];

                    if (!current.MayContainItems)
                    {
                        //Are we near one which can contain items?
                        if (GetBlocksAroundPoint(map, current.Tile.Coordinate, 1).Any(b => b.MayContainItems))
                        {
                            //Yep - put a wall there
                            current.ForcePutItemOnBlock(fact.CreateItem("mundaneitems", borderID));
                        }
                    }
                }
            }

            return map;
        }
        /// <summary>
        /// Load the location
        /// </summary>
        /// <param name="location"></param>
        /// <param name="forceRegenerate">If set to true, will regenerate the item anyway</param>
        private void LoadLocation(Location location, bool forceRegenerate = false)
        {
            if (LocalMap.MapGenerated(location.UniqueGUID) && !forceRegenerate)
            {
                //Reload the map
                var savedMap = LocalMap.DeserialiseLocalMap(location.UniqueGUID);

                GameState.LocalMap = new LocalMap(savedMap.localGameMap.GetLength(0), savedMap.localGameMap.GetLength(1), 1, 0);

                GameState.LocalMap.Location = savedMap.Location;

                //GameState.LocalMap.Location = location;

                if (GameState.LocalMap.Location is MapSite && (GameState.LocalMap.Location as MapSite).SiteData.MapRegenerationRequired)
                {
                    Actor[] newActors = null;

                    //Before we do anything, check that we don't need to regenerate it
                    MapBlock[,] savedMap2D = new MapBlock[savedMap.localGameMap.GetLength(0), savedMap.localGameMap.GetLength(1)];

                    for (int x = 0; x < savedMap.localGameMap.GetLength(0); x++)
                    {
                        for (int y = 0; y < savedMap.localGameMap.GetLength(1); y++)
                        {
                            savedMap2D[x, y] = savedMap.localGameMap[x, y, 0]; //NB: CHANGE IF WE GO 3D
                        }
                    }

                    var blocks = SiteGenerator.RegenerateSite((GameState.LocalMap.Location as MapSite).SiteData, savedMap2D, savedMap.Actors.ToArray(), out newActors);

                    List<MapBlock> cM = new List<MapBlock>();

                    foreach (MapBlock block in blocks)
                    {
                        cM.Add(block);
                    }

                    GameState.LocalMap.AddToLocalMap(cM.ToArray());
                    GameState.LocalMap.Actors = newActors.ToList();

                    GameState.LocalMap.Tick(); //Tick to remove the dead actors
                }

                GameState.LocalMap.Actors = new List<Actor>();

                List<MapBlock> collapsedMap = new List<MapBlock>();

                foreach (MapBlock block in savedMap.localGameMap)
                {
                    collapsedMap.Add(block);
                }

                GameState.LocalMap.AddToLocalMap(collapsedMap.ToArray());
                GameState.LocalMap.PathfindingMap = savedMap.PathfindingMap;
                GameState.LocalMap.PointsOfInterest = savedMap.PointsOfInterest;
                GameState.LocalMap.IsUnderground = savedMap.IsUnderground;

                GameState.LocalMap.Actors = savedMap.Actors;

                LocalMapGenerator lmg = new LocalMapGenerator();

                //Go through the actors
                foreach (var actor in GameState.LocalMap.Actors)
                {
                    //Do we have any vendors ?
                    if (actor.VendorDetails != null)
                    {
                        if (Math.Abs((actor.VendorDetails.GenerationTime - GameState.UniverseTime).GetTimeComponent(DRTimeComponent.MONTH)) > 1)
                        {
                            //More than a month old
                            //Regenerate it
                            lmg.UpdateVendorStock(actor);
                        }
                    }
                }

                //Find the player character item
                var playerActor = GameState.LocalMap.Actors.Where(a => a.IsPlayerCharacter).FirstOrDefault();

                GameState.PlayerCharacter.MapCharacter.Coordinate = playerActor.MapCharacter.Coordinate;
                GameState.PlayerCharacter.MapCharacter = playerActor.MapCharacter;

                //GameState.LocalMap.Location = location;
            }
            else
            {
                Actor[] actors = null;

                MapCoordinate startPoint = null;
                List<PointOfInterest> pointsOfInterest = null;

                MapBlock[,] gennedMap = null;

                if (location is BanditCamp)
                {
                    gennedMap = CampGenerator.GenerateCamp((location as BanditCamp).BanditTotal, out startPoint, out actors);
                }
                else if (location is Citadel)
                {
                    var citadel = location as Citadel;

                    CitadelGenerator gen = new CitadelGenerator();
                    gennedMap = gen.GenerateDungeon(citadel.TierCount, citadel.TrapRooms, citadel.GuardRooms, citadel.TreasureRoom, citadel.OwnerCreatureType, (decimal)citadel.PercentageOwned, citadel.MaxWildPopulation, citadel.MaxOwnedPopulation, out startPoint, out actors, out pointsOfInterest);
                }
                else if (location is MapSite)
                {
                    var mapSite = location as MapSite;

                    gennedMap = SiteGenerator.GenerateSite(mapSite.SiteData, out actors);
                    startPoint = new MapCoordinate(gennedMap.GetLength(0) / 2, 0, 0, MapType.LOCAL);
                }
                else if (location is Settlement)
                {
                    List<Actor> settlementActors = null;
                    PointOfInterest sp = null;

                    gennedMap = SettlementGenerator.GenerateMap((location as Settlement), out settlementActors, out sp);

                    actors = settlementActors.ToArray();
                    startPoint = sp.Coordinate;
                }
                else if (location is Dungeon)
                {
                    Dungeon dungeon = null;

                    gennedMap = DungeonGenerator.GenerateDungeonLevel((location as Dungeon).DifficultyLevel, 80, out startPoint, out actors, out dungeon);

                    //Copy the changes, that way we retain the object reference and the guid for serialization
                    (location as Dungeon).Rooms = dungeon.Rooms;
                    (location as Dungeon).SummoningCircles = dungeon.SummoningCircles;

                }

                GameState.LocalMap = new LocalMap(gennedMap.GetLength(0), gennedMap.GetLength(1), 1, 0);
                GameState.LocalMap.Actors = new List<Actor>();

                List<MapBlock> collapsedMap = new List<MapBlock>();

                foreach (MapBlock block in gennedMap)
                {
                    collapsedMap.Add(block);
                }

                GameState.LocalMap.AddToLocalMap(collapsedMap.ToArray());

                GameState.PlayerCharacter.MapCharacter.Coordinate = startPoint;

                MapBlock playerBlock = GameState.LocalMap.GetBlockAtCoordinate(startPoint);
                playerBlock.PutItemOnBlock(GameState.PlayerCharacter.MapCharacter);
                GameState.LocalMap.Actors.AddRange(actors);
                GameState.LocalMap.Actors.Add(GameState.PlayerCharacter);
                GameState.LocalMap.PointsOfInterest = pointsOfInterest;
                GameState.LocalMap.Location = location;

                GameState.LocalMap.IsUnderground = (location is Dungeon);

                if (location is Dungeon) //Spawn at least 10 enemies
                {
                    for (int i = 0; i < 10; i++)
                    {
                        GameState.LocalMap.MinuteChanged(null, null); //Summon!
                    }
                }

            }
        }
        /// <summary>
        /// Creates Citadels on the map
        /// Will colonise areas not claimed by humans.
        /// </summary>
        public static void CreateOrcCitadels()
        {
            //Create the civilisation
            GameState.GlobalMap.Civilisations.Add(new Civilisation() { Faction = OwningFactions.ORCS, ID = 100, Name = "Orc Hoardes" });

            List<MapBlock> blocks = new List<MapBlock>();

            //Collect all the points which aren't claimed
            for (int x = 0; x < WORLDSIZE; x++)
            {
                for (int y = 0; y < WORLDSIZE; y++)
                {
                    MapBlock block = GameState.GlobalMap.GetBlockAtCoordinate(new MapCoordinate(x, y, 0, MapType.GLOBAL));

                    var tile = block.Tile as GlobalTile;

                    if (!tile.HasRiver && !tile.IsBlockedForColonisation && !tile.Owner.HasValue && !tile.HasResource && tile.Elevation > 0 && tile.Elevation < 250)
                    {
                        blocks.Add(block);
                    }
                }
            }

            for (int i = 0; i < CITADEL_TOTAL; i++)
            {
                //Create the actual item - Completly Randomly for now
                var enemyRace = ActorGeneration.GetEnemyType(true);

                MapBlock block = blocks[GameState.Random.Next(blocks.Count)];

                //Still valid?
                if ((block.Tile as GlobalTile).IsBlockedForColonisation || (block.Tile as GlobalTile).Owner.HasValue)
                {
                    //Nope
                    i--;
                    continue;
                }

                Citadel dungeon = new Citadel();
                dungeon.Coordinate = new MapCoordinate(block.Tile.Coordinate);
                dungeon.GuardRooms = GameState.Random.Next(2) + 1;
                dungeon.MaxOwnedPopulation = GameState.Random.Next(10) + 2;
                dungeon.MaxWildPopulation = GameState.Random.Next(4);
                dungeon.OwnerCreatureType = enemyRace;
                dungeon.PercentageOwned = GameState.Random.Next(50) + 50;
                dungeon.TierCount = GameState.Random.Next(4) + 3;
                dungeon.TrapRooms = GameState.Random.Next(5) + 2;
                dungeon.TreasureRoom = GameState.Random.Next(5);

                //Put an entire group of Dungeon Items on it
                MapCoordinate[] dungeonCoordinates = new MapCoordinate[10];

                dungeonCoordinates[7] = new MapCoordinate(block.Tile.Coordinate.X - 1, block.Tile.Coordinate.Y - 1, 0, MapType.GLOBAL);
                dungeonCoordinates[8] = new MapCoordinate(block.Tile.Coordinate.X, block.Tile.Coordinate.Y - 1, 0, MapType.GLOBAL);
                dungeonCoordinates[9] = new MapCoordinate(block.Tile.Coordinate.X + 1, block.Tile.Coordinate.Y - 1, 0, MapType.GLOBAL);
                dungeonCoordinates[4] = new MapCoordinate(block.Tile.Coordinate.X - 1, block.Tile.Coordinate.Y, 0, MapType.GLOBAL);
                dungeonCoordinates[5] = new MapCoordinate(block.Tile.Coordinate.X, block.Tile.Coordinate.Y, 0, MapType.GLOBAL);
                dungeonCoordinates[6] = new MapCoordinate(block.Tile.Coordinate.X + 1, block.Tile.Coordinate.Y, 0, MapType.GLOBAL);
                dungeonCoordinates[1] = new MapCoordinate(block.Tile.Coordinate.X - 1, block.Tile.Coordinate.Y + 1, 0, MapType.GLOBAL);
                dungeonCoordinates[2] = new MapCoordinate(block.Tile.Coordinate.X, block.Tile.Coordinate.Y + 1, 0, MapType.GLOBAL);
                dungeonCoordinates[3] = new MapCoordinate(block.Tile.Coordinate.X + 1, block.Tile.Coordinate.Y + 1, 0, MapType.GLOBAL);

                //Block surrounding tiles
                MapBlock[] regionalBlocks = GetBlocksAroundPoint(block.Tile.Coordinate, 1);

                foreach (MapBlock rblock in regionalBlocks)
                {
                    (rblock.Tile as GlobalTile).IsBlockedForColonisation = true;
                }

                //Also claim the surrounding areas for orcs. Let's give them an owner of 100
                MapBlock[] claimedBlocks = GetBlocksAroundPoint(block.Tile.Coordinate, CITADEL_CLAIMING_RADIUS);

                foreach (MapBlock rblock in claimedBlocks)
                {
                    (rblock.Tile as GlobalTile).Owner = 100;
                }

                for (int corner = 1; corner < 10; corner++)
                {
                    var cornerBlock = GameState.GlobalMap.GetBlockAtCoordinate(dungeonCoordinates[corner]);

                    //Cut any forests down
                    switch ((cornerBlock.Tile as GlobalTile).Biome)
                    {
                        case GlobalBiome.DENSE_FOREST:
                            (cornerBlock.Tile as GlobalTile).Biome = GlobalBiome.GRASSLAND;
                            break;
                        case GlobalBiome.WOODLAND:
                            (cornerBlock.Tile as GlobalTile).Biome = GlobalBiome.GRASSLAND;
                            break;
                        case GlobalBiome.POLAR_FOREST:
                            (cornerBlock.Tile as GlobalTile).Biome = GlobalBiome.POLAR_DESERT;
                            break;
                    }

                    //Create a new dungeon
                    CitadelItem item = new CitadelItem(corner);
                    item.Coordinate = new MapCoordinate(cornerBlock.Tile.Coordinate);
                    item.Name = "Orc Citadel";
                    item.Description = "a dark dungeon owned by Orcs";
                    item.Citadel = dungeon;

                    cornerBlock.ForcePutItemOnBlock(item);

                    blocks.Remove(block);
                }
            }
        }
        /// <summary>
        /// Returns a filled square around a particular point
        /// </summary>
        /// <param name="centre"></param>
        /// <param name="radius"></param>
        /// <returns></returns>
        public static MapBlock[] GetBlocksAroundPoint(MapCoordinate centre, int radius)
        {
            int minY = centre.Y - Math.Abs(radius);
            int maxY = centre.Y + Math.Abs(radius);

            int minX = centre.X - Math.Abs(radius);
            int maxX = centre.X + Math.Abs(radius);

            List<MapBlock> returnList = new List<MapBlock>();

            //go through all of them

            for (int yLoop = maxY; yLoop >= minY; yLoop--)
            {
                for (int xLoop = minX; xLoop <= maxX; xLoop++)
                {
                    MapCoordinate coord = new MapCoordinate(xLoop, yLoop, 0, MapType.GLOBAL);

                    if (xLoop >= 0 && xLoop < WORLDSIZE && yLoop >= 0 && yLoop < WORLDSIZE)
                    { //make sure they're in the map
                        returnList.Add(GameState.GlobalMap.GetBlockAtCoordinate(coord));
                    }
                }
            }

            return returnList.ToArray();
        }
 /// <summary>
 /// Gets possible actions for a particular block
 /// </summary>
 /// <param name="coordinate"></param>
 /// <returns></returns>
 public static ActionType[] GetPossibleActions(MapCoordinate coordinate)
 {
     switch (coordinate.MapType)
     {
         case MapType.LOCAL:
             return GameState.LocalMap.GetBlockAtCoordinate(coordinate).GetActions(GameState.PlayerCharacter);
         case MapType.GLOBAL:
             return GameState.GlobalMap.GetBlockAtCoordinate(coordinate).GetActions(GameState.PlayerCharacter);
         default:
             throw new NotImplementedException("There is no support for that particular maptype");
     }
 }
        /// <summary>
        /// Generates a map based on the maplet assigned
        /// </summary>
        /// <param name="maplet">The maplet to generate</param>
        /// <param name="parentWallID">The wall that the parent has</param>
        /// <param name="parentTileID">The ID of the tiles used in the parent maplet item</param>
        /// <param name="enemyType">The type of actor which is dominant in this map</param>
        /// <param name="owner">The owner of the map. Any maplet items which don't belong will be hidden</param>
        /// <param name="actors">The actors which we have generated</param>
        /// <param name="actorType">The type of actors to generate</param>
        /// <returns></returns>
        public MapBlock[,] GenerateMap(int parentTileID, int? parentWallID, Maplet maplet, bool preferSides, string actorType, OwningFactions owner,
            out Actor[] actors, out MapletActorWanderArea[] wAreas, out MapletPatrolPoint[] patrolRoutes, out MapletFootpathNode[] footpathNodes)
        {
            List<Actor> actorList = new List<Actor>();
            List<MapletActorWanderArea> wanderAreas = new List<MapletActorWanderArea>();
            List<MapletPatrolPoint> patrolRouteList = new List<MapletPatrolPoint>();
            List<MapletFootpathNode> footpathNodeList = new List<MapletFootpathNode>();

            PlanningMapItemType[,] planningMap = new PlanningMapItemType[maplet.SizeX, maplet.SizeY];

            //Step 1: Plan how the map will look

            //Step 1a: Set all tiles to available, and set the frame to walls if there's a wall
            planningMap = this.CreateBlueprint(maplet);

            //Step 1b: Put in the tiles in the actual map, and the walls if they are present
            MapBlock[,] generatedMap = new MapBlock[maplet.SizeX, maplet.SizeY];
            ItemFactory.ItemFactory factory = new ItemFactory.ItemFactory();

            int tileID = 0;

            if (maplet.Tiled)
            {
                if (maplet.TileID.HasValue)
                {
                    tileID = maplet.TileID.Value;
                }
                else
                {
                    //Load the tileID from the factory
                    factory.CreateItem(Archetype.TILES, maplet.TileTag, out tileID);
                }

            }
            else
            {
                tileID = parentTileID;
            }

            //That's the tiles done
            for (int x = 0; x < generatedMap.GetLength(0); x++)
            {
                for (int y = 0; y < generatedMap.GetLength(1); y++)
                {
                    MapItem tile = factory.CreateItem("tile", tileID);
                    tile.Coordinate = new MapCoordinate(x, y, 0, DRObjects.Enums.MapType.LOCAL);

                    MapBlock block = new MapBlock();
                    block.Tile = tile;

                    generatedMap[x, y] = block;
                }
            }

            //Do the walls now if they are required
            int? wallID = null;
            int tempWallID = -1;

            if (parentWallID.HasValue)
            {
                MapItem wall = factory.CreateItem("MUNDANEITEMS", parentWallID.Value);
                wallID = parentWallID;
            }
            else
            {
                MapItem wall = factory.CreateItem(DRObjects.Enums.Archetype.MUNDANEITEMS, "wall", out tempWallID);
                wallID = tempWallID;
            }

            if (maplet.Walled && wallID.HasValue)
            {
                //wall the edge tiles
                for (int x = 0; x < maplet.SizeX; x++)
                {
                    generatedMap[x, 0].PutItemOnBlock(factory.CreateItem("mundaneitems", wallID.Value));
                    generatedMap[x, maplet.SizeY - 1].PutItemOnBlock(factory.CreateItem("mundaneitems", wallID.Value));

                    if (maplet.WindowProbability.HasValue && maplet.WindowProbability.Value > 0)
                    {
                        if (random.Next(100) < maplet.WindowProbability.Value)
                        {
                            int itemID;
                            //Put a window :)
                            generatedMap[x, 0].ForcePutItemOnBlock(factory.CreateItem(DRObjects.Enums.Archetype.MUNDANEITEMS, "window", out itemID));
                        }
                        else if (random.Next(100) < maplet.WindowProbability.Value)
                        {
                            int itemID;
                            //Put a window :)
                            generatedMap[x, maplet.SizeY - 1].ForcePutItemOnBlock(factory.CreateItem(DRObjects.Enums.Archetype.MUNDANEITEMS, "window", out itemID));
                        }
                    }
                }

                for (int y = 0; y < maplet.SizeY; y++)
                {
                    generatedMap[0, y].PutItemOnBlock(factory.CreateItem("mundaneitems", wallID.Value));
                    generatedMap[maplet.SizeX - 1, y].PutItemOnBlock(factory.CreateItem("mundaneitems", wallID.Value));

                    if (maplet.WindowProbability.HasValue && maplet.WindowProbability.Value > 0)
                    {
                        if (random.Next(100) < maplet.WindowProbability.Value)
                        {
                            int itemID;
                            //Put a window :)
                            generatedMap[0, y].ForcePutItemOnBlock(factory.CreateItem(DRObjects.Enums.Archetype.MUNDANEITEMS, "window", out itemID));
                        }
                        else if (random.Next(100) < maplet.WindowProbability.Value)
                        {
                            int itemID;
                            //Put a window :)
                            generatedMap[maplet.SizeX - 1, y].ForcePutItemOnBlock(factory.CreateItem(DRObjects.Enums.Archetype.MUNDANEITEMS, "window", out itemID));
                        }
                    }
                }

            }

            //Step 1c: Determine where we'll put the maplets
            foreach (MapletContentsMaplet childMaplet in maplet.MapletContents.Where(mc => (mc is MapletContentsMaplet)).OrderByDescending(mc => mc.ProbabilityPercentage).ThenBy(mc => random.Next()))
            {
                //Calculate the probability of putting the item in, and how many items we're putting
                for (int i = 0; i < childMaplet.MaxAmount; i++)
                {
                    if (random.NextDouble() * 100 <= childMaplet.ProbabilityPercentage)
                    {
                        //Does it fit?
                        int x = -1;
                        int y = -1;
                        PlanningMapItemType[,] newMap;

                        //Convert the child maplet into a planning map
                        PlanningMapItemType[,] childMapletBlueprint = this.CreateBlueprint(childMaplet.Maplet);
                        //mark the areas covered by the blueprint as being held by that blueprint

                        if (childMaplet.Position == PositionAffinity.FIXED)
                        {
                            if (Fits(planningMap, childMapletBlueprint, childMaplet.x.Value, childMaplet.y.Value, out newMap))
                            {
                                //it fits, generate it - <3 Recursion
                                Actor[] childActors = null;

                                MapletActorWanderArea[] wanderA = null;
                                MapletPatrolPoint[] patrolPoints = null;
                                MapletFootpathNode[] fpNodes = null;

                                MapBlock[,] childMap = this.GenerateMap(tileID, wallID.Value, childMaplet.Maplet, childMaplet.Position == DRObjects.LocalMapGeneratorObjects.Enums.PositionAffinity.SIDES, actorType, owner, out childActors, out wanderA, out patrolPoints, out fpNodes);

                                //Add the child actors
                                actorList.AddRange(childActors);

                                //Update any actors's locations should they have any
                                foreach (var actor in childActors)
                                {
                                    if (actor.MissionStack.Count() > 0)
                                    {
                                        var wander = actor.MissionStack.Peek() as WanderMission;

                                        if (wander != null)
                                        {
                                            wander.WanderPoint.X += childMaplet.x.Value;
                                            wander.WanderPoint.Y += childMaplet.y.Value;

                                            wander.WanderRectangle = new Rectangle(wander.WanderRectangle.X + childMaplet.x.Value, wander.WanderRectangle.Y + childMaplet.y.Value, wander.WanderRectangle.Width, wander.WanderRectangle.Height);
                                        }

                                    }
                                }

                                //Update any wander areas too
                                foreach (var area in wanderA)
                                {
                                    area.WanderRect = new Rectangle(area.WanderRect.X + childMaplet.x.Value, area.WanderRect.Y + childMaplet.y.Value, area.WanderRect.Width, area.WanderRect.Height);
                                    area.WanderPoint.X += childMaplet.x.Value;
                                    area.WanderPoint.Y += childMaplet.y.Value;
                                }

                                //and patrol points
                                foreach (var point in patrolPoints)
                                {
                                    point.Point.X += childMaplet.x.Value;
                                    point.Point.Y += childMaplet.y.Value;
                                }

                                foreach (var n in fpNodes)
                                {
                                    n.Point.X += childMaplet.x.Value;
                                    n.Point.Y += childMaplet.y.Value;
                                }

                                //And add them
                                wanderAreas.AddRange(wanderA);
                                patrolRouteList.AddRange(patrolPoints);
                                footpathNodeList.AddRange(fpNodes);

                                //Join the two maps together
                                generatedMap = this.JoinMaps(generatedMap, childMap, childMaplet.x.Value, childMaplet.y.Value);
                            }
                        }
                        else
                        {
                            if (Fits(planningMap, childMapletBlueprint, childMaplet.Position == DRObjects.LocalMapGeneratorObjects.Enums.PositionAffinity.SIDES, childMaplet.FirstFit, childMaplet.Padding, out x, out y, out newMap))
                            {
                                //it fits, generate it - <3 Recursion
                                Actor[] childActors = null;
                                MapletActorWanderArea[] wanderA = null;
                                MapletPatrolPoint[] patrolPoints = null;
                                MapletFootpathNode[] fpNodes = null;

                                MapBlock[,] childMap = this.GenerateMap(tileID, wallID.Value, childMaplet.Maplet, childMaplet.Position == DRObjects.LocalMapGeneratorObjects.Enums.PositionAffinity.SIDES, actorType, owner, out childActors, out wanderA, out patrolPoints, out fpNodes);

                                //Add the child actors
                                actorList.AddRange(childActors);

                                //Update any actors's locations should they have any
                                foreach (var actor in childActors)
                                {
                                    if (actor.MissionStack.Count() > 0)
                                    {
                                        var wander = actor.MissionStack.Peek() as WanderMission;

                                        if (wander != null)
                                        {
                                            wander.WanderPoint.X += x;
                                            wander.WanderPoint.Y += y;

                                            wander.WanderRectangle = new Rectangle(wander.WanderRectangle.X + x, wander.WanderRectangle.Y + y, wander.WanderRectangle.Width, wander.WanderRectangle.Height);
                                        }

                                    }
                                }

                                //Update any wander areas too
                                foreach (var area in wanderA)
                                {
                                    area.WanderRect = new Rectangle(area.WanderRect.X + x, area.WanderRect.Y + y, area.WanderRect.Width, area.WanderRect.Height);
                                    area.WanderPoint.X += x;
                                    area.WanderPoint.Y += y;
                                }

                                //and patrol routes
                                foreach (var point in patrolPoints)
                                {
                                    point.Point.X += x;
                                    point.Point.Y += y;
                                }

                                foreach (var n in fpNodes)
                                {
                                    n.Point.X += x;
                                    n.Point.Y += y;
                                }

                                //And add them
                                wanderAreas.AddRange(wanderA);
                                patrolRouteList.AddRange(patrolPoints);
                                footpathNodeList.AddRange(fpNodes);

                                //Join the two maps together
                                generatedMap = this.JoinMaps(generatedMap, childMap, x, y);
                            }
                        }
                    }
                }
            }

            //Step 2: Put the items into the map

            //Lets list places we can put it in
            List<MapBlock> candidateBlocks = new List<MapBlock>();

            for (int x = 0; x < planningMap.GetLength(0); x++)
            {
                for (int y = 0; y < planningMap.GetLength(1); y++)
                {
                    if (planningMap[x, y] == PlanningMapItemType.FREE)
                    {
                        candidateBlocks.Add(generatedMap[x, y]);
                    }

                }
            }
            List<MapBlock> edgeBlocks = new List<MapBlock>();

            //Lets also get the edge mapblocks - for those who prefer being on the edge
            for (int x = 0; x < planningMap.GetLength(0); x++)
            {
                if (!maplet.Walled)
                {
                    if (planningMap[x, 0] == PlanningMapItemType.FREE)
                    {
                        edgeBlocks.Add(generatedMap[x, 0]);
                    }

                    if (planningMap[x, planningMap.GetLength(1) - 1] == PlanningMapItemType.FREE)
                    {
                        edgeBlocks.Add(generatedMap[x, planningMap.GetLength(1) - 1]);
                    }
                }
                else
                {
                    if (planningMap[x, 1] == PlanningMapItemType.FREE)
                    {
                        edgeBlocks.Add(generatedMap[x, 1]);
                    }

                    if (planningMap[x, planningMap.GetLength(1) - 2] == PlanningMapItemType.FREE)
                    {
                        edgeBlocks.Add(generatedMap[x, planningMap.GetLength(1) - 2]);
                    }
                }

            }

            //Doing the y parts
            for (int y = 0; y < planningMap.GetLength(1); y++)
            {
                if (!maplet.Walled)
                {
                    if (planningMap[0, y] == PlanningMapItemType.FREE)
                    {
                        edgeBlocks.Add(generatedMap[0, y]);
                    }

                    if (planningMap[planningMap.GetLength(0) - 1, y] == PlanningMapItemType.FREE)
                    {
                        edgeBlocks.Add(generatedMap[planningMap.GetLength(0) - 1, y]);
                    }
                }
                else
                {
                    if (planningMap[1, y] == PlanningMapItemType.FREE)
                    {
                        edgeBlocks.Add(generatedMap[1, y]);
                    }

                    if (planningMap[planningMap.GetLength(0) - 2, y] == PlanningMapItemType.FREE)
                    {
                        edgeBlocks.Add(generatedMap[planningMap.GetLength(0) - 2, y]);
                    }

                }

            }

            //go through the maplet contents

            //Get the smallest x and y coordinate in the candidate blocks so we can use it for fixed things

            int smallestX = -1;
            int smallestY = -1;

            try
            {
                smallestX = candidateBlocks.Select(b => b.Tile.Coordinate.X).Min();
                smallestY = candidateBlocks.Select(b => b.Tile.Coordinate.Y).Min();
            }
            catch
            {
                //No space :(

            }

            foreach (MapletContents contents in maplet.MapletContents.Where(mc => mc is MapletContentsItem || mc is MapletContentsItemTag || mc is MapletContentsItemSpecial).OrderByDescending(mc => mc.ProbabilityPercentage))
            {
                //We'll see if we even put this at all
                MapItem itemPlaced = null;

                for (int i = 0; i < contents.MaxAmount; i++)
                {
                    //lets see what the probability of putting it in is
                    if ((random.NextDouble() * 100) <= contents.ProbabilityPercentage)
                    {
                        //Put it in
                        if (contents is MapletContentsItem)
                        {
                            MapletContentsItem mapletContent = (MapletContentsItem)contents;
                            itemPlaced = factory.CreateItem(mapletContent.ItemCategory, mapletContent.ItemID);
                        }
                        else
                            if (contents is MapletContentsItemTag)
                            {
                                MapletContentsItemTag mapletContent = (MapletContentsItemTag)contents;
                                int tempInt;
                                itemPlaced = factory.CreateItem(mapletContent.Category, mapletContent.Tag, out tempInt);
                                //I CHANGED THIS
                                itemPlaced.OwnedBy = mapletContent.Factions;
                            }
                            else
                                if (contents is MapletContentsItemSpecial)
                                {
                                    //what type is it
                                    switch ((contents as MapletContentsItemSpecial).Type)
                                    {
                                        case "StairsUp":
                                            itemPlaced = new DungeonStairs(true); break;
                                        case "StairsDown":
                                            itemPlaced = new DungeonStairs(false); break;
                                        case "SummoningCircle":
                                            itemPlaced = new SummoningCircle(); break;
                                        case "TreasureChest":
                                            itemPlaced = new TreasureChest(); break;
                                        case "Altar":
                                            itemPlaced = new Altar(); break;
                                        case "WishingWell":
                                            itemPlaced = new WishingWell(); break;
                                        case "Potion":
                                            var potionType = (PotionType[]) Enum.GetValues(typeof(PotionType));
                                            var potion = potionType.GetRandom();
                                            itemPlaced = new Potion(potion);
                                            break;
                                        default:
                                            throw new NotImplementedException("No code for " + (contents as MapletContentsItemSpecial).Type + " can be found");
                                    }
                                }

                        if (candidateBlocks.Count != 0)
                        {
                            //Lets decide where to put it

                            if (contents.Position == DRObjects.LocalMapGeneratorObjects.Enums.PositionAffinity.SIDES && edgeBlocks.Count != 0)
                            {
                                //pick a place at random and add it to the maplet
                                int position = random.Next(edgeBlocks.Count);

                                edgeBlocks[position].PutItemOnBlock(itemPlaced);

                                if (!contents.AllowItemsOnTop)
                                {
                                    //remove it from both
                                    candidateBlocks.Remove(edgeBlocks[position]);
                                    edgeBlocks.RemoveAt(position);
                                }
                            }

                            if (contents.Position == DRObjects.LocalMapGeneratorObjects.Enums.PositionAffinity.MIDDLE && candidateBlocks.Except(edgeBlocks).Count() != 0)
                            {
                                //pick a place at random and add it to the maplet
                                int position = random.Next(candidateBlocks.Except(edgeBlocks).Count());

                                MapBlock block = candidateBlocks.Except(edgeBlocks).ToArray()[position];

                                block.PutItemOnBlock(itemPlaced);

                                if (!contents.AllowItemsOnTop)
                                {
                                    //remove it from both
                                    candidateBlocks.Remove(block);
                                    edgeBlocks.Remove(block);
                                }
                            }

                            if (contents.Position == DRObjects.LocalMapGeneratorObjects.Enums.PositionAffinity.ANYWHERE)
                            {
                                //pick a place at random and add it to the maplet
                                int position = random.Next(candidateBlocks.Count);

                                candidateBlocks[position].PutItemOnBlock(itemPlaced);

                                if (!contents.AllowItemsOnTop)
                                {
                                    //remove it from both
                                    edgeBlocks.Remove(candidateBlocks[position]);
                                    candidateBlocks.RemoveAt(position);
                                }
                            }

                            if (contents.Position == DRObjects.LocalMapGeneratorObjects.Enums.PositionAffinity.FIXED)
                            {
                                //Fix it in a particular position.
                                MapCoordinate coordinate = new MapCoordinate(smallestX + contents.x.Value, smallestY + contents.y.Value, 0, DRObjects.Enums.MapType.LOCAL);

                                var selectedBlock = candidateBlocks.Where(cb => cb.Tile.Coordinate.Equals(coordinate)).FirstOrDefault();

                                if (selectedBlock != null)
                                { //maybe someone put something there already
                                    selectedBlock.PutItemOnBlock(itemPlaced);
                                }

                                if (!contents.AllowItemsOnTop)
                                {
                                    //and remoev it from both
                                    candidateBlocks.Remove(selectedBlock);
                                    edgeBlocks.Remove(selectedBlock);
                                }
                            }
                        }
                    }
                }

            }

            //Step 3: Stripe through the map except for the current maplet's walls - work out where the walls are, and for each wall segment, put a door in
            #region Wall Segments
            List<Line> wallSegments = new List<Line>();

            for (int x = 1; x < planningMap.GetLength(0) - 1; x++)
            {
                //lets see if we find a wall Segment
                Line wallSegment = null;

                for (int y = 1; y < planningMap.GetLength(1) - 1; y++)
                {
                    if (planningMap[x, y] == PlanningMapItemType.WALL)
                    {
                        //Three possibilities exist. Either this is the start of a wall segment
                        //Or this is a continuation of a wall segment
                        //Or this is the end of a wall segment
                        // -> Because there is an intersection
                        // -> Because there was an active wall segment and there is no wall in this one
                        if (wallSegment == null)
                        {
                            //Its a start
                            wallSegment = new Line(new MapCoordinate(x, y, 0, DRObjects.Enums.MapType.LOCAL), null);
                        }
                        else
                        {
                            //Continuation or end
                            //Check if there's an interesection
                            //Go up one and down one. If there is the maplet's walls there won't be a door - but then there'll be a double wall anyway which makes no sense
                            if (planningMap[x + 1, y] == PlanningMapItemType.WALL || planningMap[x - 1, y] == PlanningMapItemType.WALL)
                            {
                                //terminate the wall - and start a new one
                                wallSegment.End = new MapCoordinate(x, y, 0, DRObjects.Enums.MapType.LOCAL);
                                wallSegments.Add(wallSegment);

                                wallSegment = new Line(new MapCoordinate(x, y, 0, DRObjects.Enums.MapType.LOCAL), null);
                            }
                            else
                            {
                                //do nothing, its a continuation
                            }
                        }

                    }
                    else
                    {
                        //Mayhaps a line has stopped?
                        if (wallSegment != null)
                        {
                            //It has - lets terminate it
                            wallSegment.End = new MapCoordinate(x, y - 1, 0, DRObjects.Enums.MapType.LOCAL);
                            wallSegments.Add(wallSegment);

                            wallSegment = null;
                        }

                    }

                }

                //Check if there's an active line - maybe it reaches till the end of the maplet
                if (wallSegment != null)
                {
                    wallSegment.End = new MapCoordinate(x, (planningMap.GetLength(1) - 1), 0, DRObjects.Enums.MapType.LOCAL);
                    wallSegments.Add(wallSegment);
                    wallSegment = null;
                }
            }

            //Now stripe in the other direction
            for (int y = 1; y < planningMap.GetLength(1) - 1; y++)
            {
                //lets see if we find a wall Segment
                Line wallSegment = null;

                for (int x = 1; x < planningMap.GetLength(0) - 1; x++)
                {
                    if (planningMap[x, y] == PlanningMapItemType.WALL)
                    {
                        //Three possibilities exist. Either this is the start of a wall segment
                        //Or this is a continuation of a wall segment
                        //Or this is the end of a wall segment
                        // -> Because there is an intersection
                        // -> Because there was an active wall segment and there is no wall in this one
                        if (wallSegment == null)
                        {
                            //Its a start
                            wallSegment = new Line(new MapCoordinate(x, y, 0, DRObjects.Enums.MapType.LOCAL), null);
                        }
                        else
                        {
                            //Continuation or end
                            //Check if there's an interesection
                            //Go up one and down one. If there is the maplet's walls there won't be a door - but then there'll be a double wall anyway which makes no sense
                            if (planningMap[x, y + 1] == PlanningMapItemType.WALL || planningMap[x, y - 1] == PlanningMapItemType.WALL)
                            {
                                //terminate the wall - and start a new one
                                wallSegment.End = new MapCoordinate(x, y, 0, DRObjects.Enums.MapType.LOCAL);
                                wallSegments.Add(wallSegment);

                                wallSegment = new Line(new MapCoordinate(x, y, 0, DRObjects.Enums.MapType.LOCAL), null);
                            }
                            else
                            {
                                //do nothing, its a continuation
                            }
                        }

                    }
                    else
                    {
                        //Mayhaps a line has stopped?
                        if (wallSegment != null)
                        {
                            //It has - lets terminate it
                            wallSegment.End = new MapCoordinate(x - 1, y, 0, DRObjects.Enums.MapType.LOCAL);
                            wallSegments.Add(wallSegment);

                            wallSegment = null;
                        }

                    }

                }

                //Check if there's an active line - maybe it reaches till the end of the maplet
                if (wallSegment != null)
                {
                    wallSegment.End = new MapCoordinate(planningMap.GetLength(0) - 1, y, 0, DRObjects.Enums.MapType.LOCAL);
                    wallSegments.Add(wallSegment);
                    wallSegment = null;
                }
            }

            #endregion Wall Segments

            #region Doors

            //Get all wall segments larger than 0, and we can put a door there

            foreach (Line segment in wallSegments.Where(ws => ws.Length() > 1))
            {
                //Put a door somewhere, as long as its not the start or end
                //Oh and remove the wall

                MapBlock block = null;

                if (segment.Start.X == segment.End.X)
                {
                    //Get the entirety of the segment
                    List<int> possibleYs = new List<int>();

                    int smallerY = Math.Min(segment.Start.Y, segment.End.Y);
                    int largerY = Math.Max(segment.Start.Y, segment.End.Y);

                    //Check in the real map whether the tile next to it is free for walking in
                    for (int y = smallerY + 1; y <= largerY; y++)
                    {
                        if (generatedMap[segment.Start.X - 1, y].MayContainItems && generatedMap[segment.Start.X + 1, y].MayContainItems)
                        {
                            possibleYs.Add(y);
                        }
                    }

                    //Now check whether there's a possible y, and pick a random one from it
                    if (possibleYs.Count != 0)
                    {
                        block = generatedMap[segment.Start.X, possibleYs[random.Next(possibleYs.Count - 1)]];
                    }
                    else
                    {
                        //nothing to do - take smallest
                        block = generatedMap[segment.Start.X, segment.Start.Y + 1];
                    }
                }
                else
                {
                    List<int> possibleXs = new List<int>();

                    int smallerX = Math.Min(segment.Start.X, segment.End.X);
                    int largerX = Math.Max(segment.Start.X, segment.End.X);

                    //Check in the real map whether the tile next to it is free for walking in
                    for (int x = smallerX + 1; x <= largerX; x++)
                    {
                        if (generatedMap[x, segment.Start.Y - 1].MayContainItems && generatedMap[x, segment.Start.Y + 1].MayContainItems)
                        {
                            possibleXs.Add(x);
                        }
                    }

                    //Now check whether there's a possible x, and pick a random one from it
                    if (possibleXs.Count != 0)
                    {
                        block = generatedMap[possibleXs[random.Next(possibleXs.Count - 1)], segment.Start.Y];
                    }
                    else
                    {
                        //nothing to do - take the smallest one
                        block = generatedMap[segment.Start.X + 1, segment.Start.Y];
                    }

                }

                try
                {
                    if (block != null)
                    {
                        block.RemoveTopItem();
                        int doorID = -1;
                        block.PutItemOnBlock(factory.CreateItem(DRObjects.Enums.Archetype.MUNDANEITEMS, "door", out doorID));
                    }
                }
                catch { }
            }

            #endregion

            #region Enemies

            //Now lets create enemies :)
            foreach (var mc in maplet.MapletContents.Where(mc => mc.GetType().Equals(typeof(MapletActor))).OrderByDescending(o => o.ProbabilityPercentage))
            {
                var actor = mc as MapletActor;

                for (int i = 0; i < actor.MaxAmount; i++)
                {
                    //Check the random
                    if (random.Next(100) < actor.ProbabilityPercentage)
                    {
                        int actorID = 0;

                        string enemyType = actor.UseLocalType ? actorType : actor.EnemyType;

                        //For now set gear cost to 0
                        Actor newActor = ActorGeneration.CreateActor(enemyType, actor.EnemyTag, null, 10, 0, null, out actorID);

                        if (actor.VendorType.HasValue)
                        {
                            GenerateVendor(newActor, actor);
                        }

                        //Generate the map character
                        var mapCharacter = factory.CreateItem("enemies", actorID);

                        newActor.MapCharacter = mapCharacter;

                        if (!actor.Factions.HasFlag(owner))
                        {
                            //inactive character
                            newActor.MapCharacter.IsActive = false;
                        }

                        (mapCharacter as LocalCharacter).Actor = newActor;

                        //Lets position them randomly
                        for (int attempt = 0; attempt < 150; attempt++)
                        {
                            //Try 150 times
                            int x = random.Next(maplet.SizeX);
                            int y = random.Next(maplet.SizeY);

                            if (generatedMap[x, y].MayContainItems)
                            {
                                //Put it there
                                mapCharacter.Coordinate = new MapCoordinate(x, y, 0, MapType.LOCAL);
                                generatedMap[x, y].ForcePutItemOnBlock(mapCharacter);
                                actorList.Add(newActor);

                                //What mission does he have?
                                if (actor.EnemyMission == ActorMissionType.WANDER)
                                {
                                    newActor.MissionStack.Push(new WanderMission()
                                        {
                                            LoiterPercentage = 80,
                                            WanderPoint = new MapCoordinate(mapCharacter.Coordinate),
                                            WanderRectangle = new Rectangle(0, 0, generatedMap.GetLength(0), generatedMap.GetLength(1))
                                        });
                                }

                                break;
                            }
                        }
                    }
                }
            }

            #endregion

            #region Wander Areas

            foreach (var mc in maplet.MapletContents.Where(mc => mc.GetType().Equals(typeof(MapletActorWanderArea))))
            {
                var wander = mc as MapletActorWanderArea;

                //The area of this is going to be the entire maplet (so if we're in a submaplet, they'll wander in there - Awesome no ?)
                wander.WanderRect = new Rectangle(0, 0, generatedMap.GetLength(0), generatedMap.GetLength(1));

                //Pick the wander point to be the middle of the rectangle. If the point isn't valid we might have a problem
                wander.WanderPoint = new MapCoordinate(generatedMap.GetLength(0) / 2, generatedMap.GetLength(1) / 2, 0, MapType.LOCAL);

                MapletActorWanderArea clone = new MapletActorWanderArea();
                clone.WanderPoint = new MapCoordinate(wander.WanderPoint);
                clone.WanderRect = new Rectangle(wander.WanderRect.X, wander.WanderRect.Y, wander.WanderRect.Width, wander.WanderRect.Height);
                clone.Profession = wander.Profession;
                clone.OwnerFactions = wander.OwnerFactions;

                wanderAreas.Add(clone);
            }

            wAreas = wanderAreas.ToArray();

            #endregion

            #region Patrol Points & Paths

            foreach (var mc in maplet.MapletContents.Where(mc => mc.GetType().Equals(typeof(MapletPatrolPoint))))
            {
                var point = mc as MapletPatrolPoint;

                //The point is going to be in the middle of the entire maplet
                point.Point = new MapCoordinate(generatedMap.GetLength(0) / 2, generatedMap.GetLength(1) / 2, 0, MapType.LOCAL);

                MapletPatrolPoint clone = new MapletPatrolPoint();
                clone.Point = new MapCoordinate(point.Point);
                clone.OwnerFactions = point.OwnerFactions;
                clone.Profession = point.Profession;
                clone.PointRadius = point.PointRadius;

                patrolRouteList.Add(clone);
            }

            patrolRoutes = patrolRouteList.ToArray();

            foreach (var n in maplet.MapletContents.Where(mc => mc.GetType().Equals(typeof(MapletFootpathNode))))
            {
                var node = n as MapletFootpathNode;

                //Point is going to be in the middle of the entire maplet
                node.Point = new MapCoordinate(generatedMap.GetLength(0) / 2, generatedMap.GetLength(1) / 2, 0, MapType.LOCAL);

                //Better create a new one
                MapletFootpathNode clone = new MapletFootpathNode();
                clone.Point = new MapCoordinate(node.Point);
                clone.IsPrimary = node.IsPrimary;

                footpathNodeList.Add(clone);
            }

            footpathNodes = footpathNodeList.ToArray();

            #endregion

            #region Aniamls

            //Now lets create enemies :)
            foreach (var mc in maplet.MapletContents.Where(mc => mc.GetType().Equals(typeof(MapletHerd))).OrderByDescending(o => o.ProbabilityPercentage))
            {
                var herd = mc as MapletHerd;

                for (int i = 0; i < herd.MaxAmount; i++)
                {
                    //Check the random
                    if (random.Next(100) < herd.ProbabilityPercentage)
                    {
                        var herds = ActorGeneration.CreateAnimalHerds(herd.Biome, herd.Domesticated, herd.HerdTag, 1);

                        foreach (var animalHerd in herds)
                        {
                            foreach (var animal in animalHerd)
                            {
                                //Position them on the map
                                for (int attempt = 0; attempt < 150; attempt++)
                                {
                                    //Try 150 times
                                    int x = random.Next(maplet.SizeX);
                                    int y = random.Next(maplet.SizeY);

                                    if (generatedMap[x, y].MayContainItems)
                                    {
                                        //Put it there
                                        animal.MapCharacter.Coordinate = new MapCoordinate(x, y, 0, MapType.LOCAL);
                                        generatedMap[x, y].ForcePutItemOnBlock(animal.MapCharacter);
                                        actorList.Add(animal);

                                        //Wander around does he have?
                                        animal.MissionStack.Push(new WanderMission()
                                        {
                                            LoiterPercentage = 80,
                                            WanderPoint = new MapCoordinate(animal.MapCharacter.Coordinate),
                                            WanderRectangle = new Rectangle(0, 0, generatedMap.GetLength(0), generatedMap.GetLength(1))
                                        });

                                        break;
                                    }
                                }
                            }
                        }

                    }
                }
            }

            #endregion

            actors = actorList.ToArray();

            #region Ownership

            //Go through all map items - If they're not valid for this particular owner, make them inactive.
            foreach (var mapBlock in generatedMap)
            {
                foreach (var item in mapBlock.GetItems())
                {
                    if (!item.OwnedBy.HasFlag(owner))
                    {
                        item.IsActive = false;
                    }
                }
            }

            #endregion

            //we're done
            return generatedMap;
        }
        /// <summary>
        /// Assigns each location to a different region
        /// </summary>
        private static void AssignRegions()
        {
            Random random = new Random();

            lock (GlobalMap.lockMe)
            {

                //setting the region centres - 0 doesn't count
                for (int i = 1; i < regions.Length; i++)
                {
                    int x = random.Next(WORLDSIZE - 1);
                    int y = random.Next(WORLDSIZE - 1);

                    if ((GameState.GlobalMap.GetBlockAtCoordinate(new MapCoordinate(x, y, 0, MapType.GLOBAL)).Tile as GlobalTile).Region == -1)
                    {
                        //not assigned

                        //set this location as the centre
                        regions[i].Center = new MapCoordinate(x, y, 0, MapType.GLOBAL);
                        regions[i].Blocks.Add(GameState.GlobalMap.GetBlockAtCoordinate(new MapCoordinate(x, y, 0, MapType.GLOBAL)));
                        (GameState.GlobalMap.GetBlockAtCoordinate(new MapCoordinate(x, y, 0, MapType.GLOBAL)).Tile as GlobalTile).Region = i;
                    }
                    else
                    {
                        i--; //try again
                    }

                }
            }

            for (int x = 0; x < WORLDSIZE; x++)
            {
                int assignedRegion = -1;

                for (int y = 0; y < WORLDSIZE; y++)
                {
                    //populate the regions
                    lock (GlobalMap.lockMe)
                    {
                        //Is this tile already in a region?

                        MapCoordinate currentCoordinate = new MapCoordinate(x, y, 0, MapType.GLOBAL);

                        MapBlock block = GameState.GlobalMap.GetBlockAtCoordinate(currentCoordinate);
                        //Find the closest region to the current unassigned block

                        if ((block.Tile as GlobalTile).Region.Equals(-1))
                        {
                            double minDistance = WORLDSIZE * WORLDSIZE;

                            for (int i = 1; i <= REGIONSIZE; i++)
                            {
                                double distance = Math.Abs(currentCoordinate - regions[i].Center);

                                if (distance <= minDistance)
                                {
                                    minDistance = distance;
                                    assignedRegion = i;
                                    //this is the smallest region
                                }

                            }
                            regions[assignedRegion].Blocks.Add(block);
                            (block.Tile as GlobalTile).Region = assignedRegion;
                        }
                    }
                }
            }
        }
        /// <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;
        }