static public InstalledObject PlaceInstance(InstalledObject proto, Vector3Int tile_position)
    {
        if (proto.funcPositionValidation(tile_position.x, tile_position.y) == false)
        {
            Debug.Log("Tile position:" + tile_position.x + "_" + tile_position.y);
            Debug.LogError("Invalid Function Position");
            return(null);
        }
        InstalledObject obj = proto.Clone();

        obj.tile = tile_position;
        return(obj);
    }
    // Install object in tile
    static public InstalledObject PlaceInstance(InstalledObject proto, Tile tile)
    {
        if (proto.funcPositionValidation(tile) == false)
        {
            Debug.LogError("PlaceInstance - Position Validity Function Returned False");
            return(null);
        }

        InstalledObject obj = new InstalledObject();

        obj.objectType       = proto.objectType;
        obj.movementCost     = proto.movementCost;
        obj.width            = proto.width;
        obj.height           = proto.height;
        obj.linksToNeighbour = proto.linksToNeighbour;
        obj.tile             = tile;

        if (tile.PlaceObject(obj) == false)
        {
            //Werent able to place object in this tile
            return(null);
        }

        if (obj.linksToNeighbour)
        {
            //This type of object or furniture links itself to its neighbours and may affect them. We tell the nighbours that they have a new neighbour. Trigger their OnChangedCallback.
            Tile t;
            t = tile.world.GetTileAt(obj.tile.X, obj.tile.Y + 1);
            if (t != null && t.installedObject != null && t.installedObject.objectType == obj.objectType)
            {
                t.installedObject.cbInstalledObjectChanged(t.installedObject);
            }
            t = tile.world.GetTileAt(obj.tile.X + 1, obj.tile.Y);
            if (t != null && t.installedObject != null && t.installedObject.objectType == obj.objectType)
            {
                t.installedObject.cbInstalledObjectChanged(t.installedObject);
            }
            t = tile.world.GetTileAt(obj.tile.X, obj.tile.Y - 1);
            if (t != null && t.installedObject != null && t.installedObject.objectType == obj.objectType)
            {
                t.installedObject.cbInstalledObjectChanged(t.installedObject);
            }
            t = tile.world.GetTileAt(obj.tile.X - 1, obj.tile.Y);
            if (t != null && t.installedObject != null && t.installedObject.objectType == obj.objectType)
            {
                t.installedObject.cbInstalledObjectChanged(t.installedObject);
            }
        }

        return(obj);
    }
    public static InstalledObject PlaceInstance(InstalledObject proto, Tile tile)
    {
        if (!proto.funcPositionValidation(tile))
        {
            Debug.LogError("PlaceInstance -- Position Validity Function returned FALSE!");
            return(null);
        }

        InstalledObject obj = proto.Clone();

        obj._tile = tile;

        if (!tile.AssignInstalledObject(obj))
        {
            return(null);
        }

        if (obj.LinksToNeighbor)
        {
            Tile t;
            int  x = tile.X;
            int  y = tile.Y;

            t = tile.World.GetTileAt(x, y + 1);
            if (t != null && t.InstalledObject != null && t.InstalledObject.ObjectType.Equals(obj.ObjectType) && t.InstalledObject._cbOnInstalledObjectChanged != null)
            {
                t.InstalledObject._cbOnInstalledObjectChanged(t.InstalledObject);
            }

            t = tile.World.GetTileAt(x + 1, y);
            if (t != null && t.InstalledObject != null && t.InstalledObject.ObjectType.Equals(obj.ObjectType) && t.InstalledObject._cbOnInstalledObjectChanged != null)
            {
                t.InstalledObject._cbOnInstalledObjectChanged(t.InstalledObject);
            }

            t = tile.World.GetTileAt(x, y - 1);
            if (t != null && t.InstalledObject != null && t.InstalledObject.ObjectType.Equals(obj.ObjectType) && t.InstalledObject._cbOnInstalledObjectChanged != null)
            {
                t.InstalledObject._cbOnInstalledObjectChanged(t.InstalledObject);
            }

            t = tile.World.GetTileAt(x - 1, y);
            if (t != null && t.InstalledObject != null && t.InstalledObject.ObjectType.Equals(obj.ObjectType) && t.InstalledObject._cbOnInstalledObjectChanged != null)
            {
                t.InstalledObject._cbOnInstalledObjectChanged(t.InstalledObject);
            }
        }

        return(obj);
    }
    /// <summary>
    /// Create full fletched InstalledObject
    /// </summary>
    /// <param name="baseObject">baseObject</param>
    /// <param name="tile">The tile, this InstalledObject will 'sit' on.</param>
    /// <returns>InstalledObject</returns>
    static public InstalledObject PlaceObject(InstalledObject baseObject, Tile tile)
    {
        // Don't place installedObject if it's not allowed
        if (baseObject.funcPositionValidation(tile) == false)
        {
            Debug.LogError("InstalledObject::PlaceObject -- Position invalid!");
            return(null);
        }

        // Create new InstalledObject from baseObject using a cloning method
        InstalledObject installedObject = baseObject.Clone();

        // Set its Tile
        installedObject.Tile = tile;

        // FIXME: Only works for 1x1 objects!

        // Can't place the object. Spot was likely already occupied. Don't return the created Object!
        if (tile.PlaceInstalledObject(installedObject) == false)
        {
            return(null);
        }

        // TODO: Can this code get cleaner? Simular bit of code in 'GetSpriteForInstalledObject' in WorldController
        // This installedObject is links itself to neighbours
        // Tell other neighbouring InstalledObject of the same type to change/update
        // Triggering it's OnChangeCallbackFunction
        if (installedObject.IsLinkedToNeighbour)
        {
            Tile tileToCheck;
            int  x = tile.X;
            int  y = tile.Y;

            // Check all 4 sides, not sure if this does the same as the monster chunk of code underneath it
            for (int _x = (x - 1); _x <= (x + 1); _x++)
            {
                for (int _y = (y - 1); _y <= (y + 1); _y++)
                {
                    // If North, East, South or West => run check
                    // Remove this if statement to also check diagonal neighbours
                    if ((_x == (x - 1) && _y == y) || (_x == (x + 1) && _y == y) || (_x == x && _y == (y - 1)) || (_x == x && _y == (y + 1)))
                    {
                        tileToCheck = tile.World.GetTileAt(_x, _y);
                        if (tileToCheck != null && tileToCheck.InstalledObject != null &&
                            tileToCheck.InstalledObject.cb_OnChanged != null &&
                            tileToCheck.InstalledObject.ObjectType == installedObject.ObjectType)
                        {
                            tileToCheck.InstalledObject.cb_OnChanged(tileToCheck.InstalledObject);
                        }
                    }
                }
            }

            /*
             * // Check North
             * tileToCheck = tile.World.GetTileAt(x, (y + 1));
             * if (tileToCheck != null && tileToCheck.InstalledObject != null
             *  && tileToCheck.InstalledObject.cb_OnChanged != null
             *  && tileToCheck.InstalledObject.ObjectType == installedObject.ObjectType)
             *  tileToCheck.InstalledObject.cb_OnChanged(tileToCheck.InstalledObject);
             *
             * // Check East
             * tileToCheck = tile.World.GetTileAt((x + 1), y);
             * if (tileToCheck != null && tileToCheck.InstalledObject != null
             *  && tileToCheck.InstalledObject.cb_OnChanged != null
             *  && tileToCheck.InstalledObject.ObjectType == installedObject.ObjectType)
             *  tileToCheck.InstalledObject.cb_OnChanged(tileToCheck.InstalledObject);
             *
             * // Check South
             * tileToCheck = tile.World.GetTileAt(x, (y - 1));
             * if (tileToCheck != null && tileToCheck.InstalledObject != null
             *  && tileToCheck.InstalledObject.cb_OnChanged != null
             *  && tileToCheck.InstalledObject.ObjectType == installedObject.ObjectType)
             *  tileToCheck.InstalledObject.cb_OnChanged(tileToCheck.InstalledObject);
             *
             * // Check West
             * tileToCheck = tile.World.GetTileAt((x - 1), y);
             * if (tileToCheck != null && tileToCheck.InstalledObject != null
             *  && tileToCheck.InstalledObject.cb_OnChanged != null
             *  && tileToCheck.InstalledObject.ObjectType == installedObject.ObjectType)
             *  tileToCheck.InstalledObject.cb_OnChanged(tileToCheck.InstalledObject);
             */
        }

        return(installedObject);
    }
    //takes the prototype and a tile and creates the actual object
    static public InstalledObject PlaceInstance(InstalledObject _proto, Tile _tile)
    {
        if (_proto.funcPositionValidation(_tile) == false)
        {
            Debug.LogError("PlaceInstance -- Position Validity function returned FALSE.");
            return(null);
        }
        //We now know that the placement is valid

        //create object
        InstalledObject inObj = _proto.Clone();

        inObj.Tile = _tile;

        if (inObj.Tile.PlaceObject(inObj) == false)
        {
            //For some reason, we weren't able to place the object on the tile, it was probaly occupied already

            //Do not return the object, it will be garbage collected
            return(null);
        }

        if (inObj.LinksToNeighbour)
        {
            //this type of InstalledObject links to neighbors so we need to inform its new neighbors when it is made

            Tile t;

            int x = inObj.Tile.X;
            int y = inObj.Tile.Y;

            t = inObj.Tile.World.GetTileAt(x, y + 1);
            //if there is a tile above us, it has an object on it, and that object matches ours
            if (t != null && t.InstalledObject != null && t.InstalledObject.cbOnChanged != null && t.InstalledObject.ObjectType == inObj.ObjectType)
            {
                t.InstalledObject.cbOnChanged(t.InstalledObject);
            }

            t = inObj.Tile.World.GetTileAt(x + 1, y);
            //if there is a tile to the right, it has an object on it, and that object matches ours
            if (t != null && t.InstalledObject != null && t.InstalledObject.cbOnChanged != null && t.InstalledObject.ObjectType == inObj.ObjectType)
            {
                t.InstalledObject.cbOnChanged(t.InstalledObject);
            }

            t = inObj.Tile.World.GetTileAt(x, y - 1);
            //if there is a tile below us, it has an object on it, and that object matches ours
            if (t != null && t.InstalledObject != null && t.InstalledObject.cbOnChanged != null && t.InstalledObject.ObjectType == inObj.ObjectType)
            {
                t.InstalledObject.cbOnChanged(t.InstalledObject);
            }

            t = inObj.Tile.World.GetTileAt(x - 1, y);
            //if there is a tile to the left, it has an object on it, and that object matches ours
            if (t != null && t.InstalledObject != null && t.InstalledObject.cbOnChanged != null && t.InstalledObject.ObjectType == inObj.ObjectType)
            {
                t.InstalledObject.cbOnChanged(t.InstalledObject);
            }
        }

        return(inObj);
    }