/// <summary>
        /// Determines if a new carpet can be placed at the given point. If a carpet cannot fit because
        /// of Z-index clashes, the Z-index is modified until the carpet can fit.
        /// </summary>
        public bool CanFit(ref Point3D p)
        {
            if (Map == null || Map == Map.Internal || Deleted || Carpet == null || Carpet.Deleted)
            {
                return(false);
            }

            MultiComponentList mcl = MultiData.GetComponents(Carpet.ItemID);
            int topZ = p.Z;

            for (int x = 0; x < mcl.Width; x++)
            {
                for (int y = 0; y < mcl.Height; y++)
                {
                    int tx = (p.X + mcl.Min.X + x);
                    int ty = (p.Y + mcl.Min.Y + y);

                    LandTile     landTile = Map.Tiles.GetLandTile(tx, ty);
                    StaticTile[] statics  = Map.Tiles.GetStaticTiles(tx, ty, true);

                    topZ = Math.Max(topZ, Map.GetAverageZ(tx, ty));

                    for (int i = 0; i < statics.Length; i++)
                    {
                        StaticTile t = statics[i];

                        if (t.Z > p.Z && (p.Z + 12) > t.Z)  //if it's above, and our top would hit its bottom
                        {
                            return(false);
                        }
                        else if (t.Z < p.Z && (t.Z + t.Height) > p.Z)  //if it's below, and its top would hit our bottom
                        {
                            return(false);
                        }
                    }

                    object obj = Map.GetTopSurface(p);

                    if (obj is LandTile)
                    {
                        LandTile t = (LandTile)obj;

                        if (t.Z > p.Z)
                        {
                            return(false);
                        }
                    }
                    else if (obj is StaticTile)
                    {
                        StaticTile t = (StaticTile)obj;

                        if (t.Z > p.Z)
                        {
                            return(false);
                        }
                    }
                    else if (obj is Item)
                    {
                        Item i = obj as Item;

                        if (i.GetWorldTop().Z > p.Z)
                        {
                            return(false);
                        }
                    }

                    if (mcl.Tiles[x][y].Length == 0 || Carpet.Contains(tx, ty))
                    {
                        continue;
                    }

                    if (!Map.CanFit(tx, ty, Z, 12, false, true, false))
                    {
                        return(false);
                    }
                }
            }

            IPooledEnumerable eable = Map.GetItemsInBounds(new Rectangle2D((p.X + mcl.Min.X), (p.Y + mcl.Min.Y), mcl.Width, mcl.Height));

            foreach (Item i in eable)
            {
                if (i.ItemID >= 0x4000 || i.Z < p.Z || !i.Visible)
                {
                    continue;
                }

                int x = (i.X - p.X + mcl.Min.X);
                int y = (i.Y - p.Y + mcl.Min.Y);

                if (x >= 0 && x < mcl.Width && y >= 0 && y < mcl.Height && mcl.Tiles[x][y].Length == 0)
                {
                    continue;
                }
                else if (Carpet.Contains(i))
                {
                    continue;
                }

                eable.Free();
                return(false);
            }

            eable.Free();

            p.Z = topZ + 1;

            return(true);
        }