public DestructableTile(Tile tile, World world, int x, int y, float maxHealth, List<IDestructionEffect> destructionEffects)
     : base(tile)
 {
     this.world = world;
     this.x = x;
     this.y = y;
     this.maxHealth = maxHealth;
     this.destructionEffects = destructionEffects;
 }
 public Tile(Tile other)
 {
     this.initialEdges = new bool[4];
     other.InitialEdges.CopyTo(this.initialEdges, 0);
     this.edges = new bool[4];
     this.initialEdges.CopyTo(this.edges, 0);
     this.textures = new SubTexture[other.Textures.GetLength(0), other.Textures.GetLength(1)];
     for (int i = 0; i < other.Textures.GetLength(0); ++i)
         for (int j = 0; j < other.Textures.GetLength(1); ++j)
             this.textures[i,j] = other.Textures[i,j];
 }
        private XElement TileToXElement(Tile tile, Dictionary<string, int> sheetIndex)
        {
            // Empty tiles are represented as having -1 edges. (nonsense)
            if (tile == null)
            {
                return new XElement("T", new XAttribute("e", -1));
            }

            // TODO: - add Type attribute (Solid, Empty, or Custom)
            //         and Top/Bottom/Left/RighEdge attributes when Type="Custom"
            //       - optimize for space/time so saving/loading isn't too slow.
            //         perhaps return a binary string (base64 or the like)
            int power = 0;
            int edges = 0;

            // We save the InitialEdges and let the TileMap take care of the rest.
            foreach (bool edge in tile.InitialEdges)
            {
                if (edge)
                {
                    edges |= (int)Math.Pow(2, power);
                }
                ++power;
            }

            XElement returnVal = new XElement("T", new XAttribute("e", edges));

            int z = 0; // The index into the Tile.Textures array where this SubTexture belongs.
            foreach (SubTexture sub in tile.Textures)
            {
                // Note: Texture2D.Name is useless normally, but the TextureService will
                //       automatically set the Name parameter to be the asset name so they can
                //       easily be retrieved.
                // "z" attribute: the index into the tile's Textures[,] array. Converted to single int to save space.
                // "s" attribute: the SubTextureSheet number to use. Each tilemap keeps a list of these.
                // "i" attribute: the index into the SubTextureSheet representing a SubTexture of this tile.
                if (sub != null)
                {
                    returnVal.Add(new XElement("x", new XAttribute("z", z), new XAttribute("s", sheetIndex[sub.Sheet.Name]), new XAttribute("i", sub.Index)));
                }
                ++z;
            }

            // Check for special types of tiles:
            if (tile is DestructableTile)
                returnVal.Add(new XAttribute("d", ((DestructableTile)tile).MaxHealth));

            return returnVal;
        }
        private Tile TileFromXElement(XElement xelement, SubTextureSheet[] sheets, int x, int y, World world)
        {
            if (xelement.Attribute("e").Value == "-1")
            {
                return null;
            }

            Tile returnVal;

            SubTexture[,] subTexturesArray = new SubTexture[layerCount, subLayerCount];

            IEnumerable<XElement> subTextureElements = xelement.Descendants("x");

            int i = 0, j = 0;
            //int index = 0; // Was needed when changing format.
            foreach( XElement subTextureElement in subTextureElements)
            {
                i = Int32.Parse(subTextureElement.Attribute("z").Value) / SubLayerCount;
                j = Int32.Parse(subTextureElement.Attribute("z").Value) % SubLayerCount;
                SubTexture subTex = new SubTexture(sheets[Int32.Parse(subTextureElement.Attribute("s").Value)], Int32.Parse(subTextureElement.Attribute("i").Value));
                subTexturesArray[i, j] = subTex;
            }

            int edgeInt;
            edgeInt = Int32.Parse(xelement.Attribute("e").Value);

            bool[] edges = new bool[4];
            for (int k = 0; k < 4; ++k)
            {
                edges[k] = (edgeInt & (int)Math.Pow(2, k)) != 0;
            }

            returnVal = new Tile(subTexturesArray, edges);

            // Check for special tile types:
            bool isDestructable = (from att in xelement.Attributes() where att.Name == "d" select att).Count() > 0;

            if (isDestructable)
            {
                List<IDestructionEffect> effects = new List<IDestructionEffect>();
                effects.Add(new ExplosionEffect());
                effects.Add(new ShatterEffect());
                returnVal = new DestructableTile(returnVal, world, x, y, float.Parse(xelement.Attribute("d").Value), effects);
            }

            return returnVal;
        }
        /// <summary>
        /// Sets the tile at given x,y.
        /// Automatically removes edges of adjacent tiles.
        /// </summary>
        public void SetTile(Tile tile, int x, int y)
        {
            // Prevent useless tiles from being added:
            if (tile != null && tile.IsEmpty())
                tile = null;

            Tile above = y > 0 ? tiles[x, (y - 1)] : null;
            Tile left = x > 0 ? tiles[(x - 1), y] : null;
            Tile below = y < Height - 1 ? tiles[x, (y + 1)] : null;
            Tile right = x < Width - 1 ? tiles[(x + 1), y] : null;

            // We're "removing" a tile, so we restore
            //  adjacent tiles' adjacent edges to their initial values.
            if (tile == null)
            {
                if (above != null)
                    above.BottomEdge = above.InitialBottomEdge;
                if (left != null)
                    left.RightEdge = left.InitialRightEdge;
                if (below != null)
                    below.TopEdge = below.InitialTopEdge;
                if (right != null)
                    right.LeftEdge = right.InitialLeftEdge;
            }
            else
            {
                // Special edge cases (no pun intended):
                if (x == 0) // left edge of the map
                {
                    tile.LeftEdge = false;
                }
                else if (x == (Width - 1)) // right edge of the map
                {
                    tile.RightEdge = false;
                }

                if (y == 0) // top edge of the map
                {
                    tile.TopEdge = false;
                }
                else if (y == (Height - 1)) // bottom edge of the map
                {
                    tile.BottomEdge = false;
                }

                // Else, we're adding a tile, so we clear all adjacent
                //  edges that we have solid edges for.
                if (above != null)
                {
                    if (tile.InitialTopEdge && above.InitialBottomEdge)
                    {
                        tile.TopEdge = false;
                        above.BottomEdge = false;
                    }
                    else
                    {
                        above.BottomEdge = above.InitialBottomEdge;
                    }
                }

                if (left != null)
                {
                    if (tile.InitialLeftEdge && left.InitialRightEdge)
                    {
                        tile.LeftEdge = false;
                        left.RightEdge = false;
                    }
                    else
                    {
                        left.RightEdge = left.InitialRightEdge;
                    }
                }

                if (below != null)
                {
                    if (tile.InitialBottomEdge && below.InitialTopEdge)
                    {
                        tile.BottomEdge = false;
                        below.TopEdge = false;
                    }
                    else
                    {
                        below.TopEdge = below.InitialTopEdge;
                    }
                }

                if (right != null)
                {
                    if (tile.InitialRightEdge && right.InitialLeftEdge)
                    {
                        tile.RightEdge = false;
                        right.LeftEdge = false;
                    }
                    else
                    {
                        right.LeftEdge = right.InitialLeftEdge;
                    }
                }

            }
            tiles[x, y] = tile;
        }
 public void SetSolid(bool solidOrNot, int x, int y)
 {
     if (tiles[x, y] != null)
     {
         tiles[x, y].SetSolid(solidOrNot);
     }
     else
     {
         tiles[x, y] = new Tile(layerCount, subLayerCount);
     }
     SetTile(tiles[x, y], x, y);
 }
        /// <summary>
        /// Crop this tilemap down to the minimal size needed to contain all non-null tiles in it.
        /// </summary>
        /// <returns>A Rectangle which represents the cropping area, in tile-coordinates.</returns>
        public Rectangle Minimize()
        {
            int xMin, xMax, yMin, yMax;
            xMax = yMax = 0;
            xMin = Width - 1;
            yMin = Height - 1;

            // Find the minimal and maximal tiles that aren't null:
            for (int x = 0; x < Width; ++x)
            {
                for (int y = 0; y < Height; ++y)
                {
                    if (tiles[x, y] != null)
                    {
                        if (x > xMax)
                            xMax = x;
                        if (x < xMin)
                            xMin = x;
                        if (y > yMax)
                            yMax = y;
                        if (y < yMin)
                            yMin = y;
                    }
                }
            }

            // Create a new tilemap that will fit all of them:
            Tile[,] newTiles = new Tile[xMax - xMin+1, yMax - yMin+1];

            // And copy all tiles into the new array:
            //  NOTE: SetTile doesn't need to be used here because each tile's
            //         edge data should be the same since we're only cropping
            //         out nulls, which have no effect on edges.
            for (int xOffset = 0; xOffset < newTiles.GetLength(0); ++xOffset)
            {
                for (int yOffset = 0; yOffset < newTiles.GetLength(1); ++yOffset)
                {
                    newTiles[xOffset, yOffset] = this[xMin + xOffset, yMin + yOffset];
                }
            }
            tiles = newTiles;

            return new Rectangle(xMin, yMin, Width, Height);
        }
        /// <summary>
        /// Set Textures[layerIndex, subLayerIndex] of all selected tiles to the SubTexture passed in.
        /// </summary>
        /// <param name="subTexture">The SubTexture to set the tiles to (null will clear the texture).</param>
        /// <param name="layerIndex">The first index into each tile's Textures array; the layer index.</param>
        /// <param name="subLayerIndex">The second index into each tile's Textures array; the sub-layer index.</param>
        public void SetSubTexture(SubTexture subTexture, int layerIndex, int subLayerIndex)
        {
            foreach (int[] tileCoord in selectedTileCoordinates)
            {
                Tile tile = TileMap[tileCoord[0], tileCoord[1]];
                if (tile == null)
                {
                    // We have an empty tile...
                    if (subTexture != null)
                    {
                        // We need to make a new one to hold this subTexture
                        SubTexture[,] textures = new SubTexture[TileMap.LayerCount, TileMap.SubLayerCount];
                        textures[layerIndex, subLayerIndex] = subTexture;
                        tile = new Tile(textures); // TODO: set the edges to what the edge toggler says the tile's edges should be?
                    }
                    // Otherwise we do nothing.
                }
                else
                {
                    // We have a non-empty tile, so we simply set it's subTexture directly:
                    tile.Textures[layerIndex, subLayerIndex] = subTexture;
                }

                // Finally, we set our tile so the tileMap's edges are properly updated.
                TileMap.SetTile(tile, tileCoord[0], tileCoord[1]);
            }
            notifyTilePropertyComponents();
        }
 /// <summary>
 /// Set all selected tile's edges to be the list of edges passed in.
 /// A copy will be made so their edges aren't actually linked.
 /// </summary>
 /// <param name="edges"></param>
 public void SetEdges(bool[] edges)
 {
     foreach (int[] tileCoord in selectedTileCoordinates)
     {
         Tile tile = TileMap[tileCoord[0], tileCoord[1]];
         if (tile == null)
         {
             if (edges[0] || edges[1] || edges[2] || edges[3])
             {
                 tile = new Tile(new SubTexture[TileMap.LayerCount, TileMap.SubLayerCount], edges);
             }
         }
         else
         {
             edges.CopyTo(tile.InitialEdges, 0);
             edges.CopyTo(tile.Edges, 0);
         }
         TileMap.SetTile(tile, tileCoord[0], tileCoord[1]);
     }
     notifyTilePropertyComponents();
 }
        /// <summary>
        /// Set all selected tiles to being either destructable or non-destructable
        /// based on the bool passed in.
        /// </summary>
        /// <param name="destructable">
        /// Whether or not the tile is destructable; true if so, false if not. Duh.
        /// </param>
        public void SetDestructable(bool destructable)
        {
            foreach (int[] tileCoord in selectedTileCoordinates)
            {
                int x, y;

                x = tileCoord[0];
                y = tileCoord[1];

                Tile tile = TileMap[x, y];

                if (tile == null)
                {
                    if (destructable)
                    {
                        tile = new Tile(new SubTexture[TileMap.LayerCount, TileMap.SubLayerCount],
                                        new bool[] { false, false, false, false });

                        tile = new DestructableTile(tile, EditorScreen.World, tileCoord[0], tileCoord[1], 10.0f);
                    }
                }
                else if (tile is DestructableTile)
                {
                    if (!destructable)
                    {
                        tile = new Tile(tile); // A plain-vanilla tile, we're only extracting the texture and edge data.
                    }
                }
                else
                {
                    if (destructable)
                    {
                        tile = new DestructableTile(tile, EditorScreen.World, tileCoord[0], tileCoord[1], 10.0f);
                    }
                }

                TileMap.SetTile(tile, x, y);
            }
            notifyTilePropertyComponents();
        }