private void GenerateWall(int x, int y, WallState state, RoomState room, RoomFacing facing, bool isExterior)
    {
        room.wallStates[facing] = state;
        if (state == WallState.None)
        {
            return;
        }
        var rotation = facing == RoomFacing.East || facing == RoomFacing.West ? Quaternion.Euler(0, 90, 0) : Quaternion.identity;
        var prefab   = state == WallState.Solid ? solidWallPrefab : openWallPrefab;
        var offset   = RoomFacingUtil.GetOffset(facing);
        var position = new Vector3(x * unitWorldSize, 0, y * unitWorldSize) + (new Vector3(offset.x, 0, offset.y) * (unitWorldSize / 2));
        var wall     = GameObject.Instantiate(prefab, position, rotation, startingRoomAnchor.transform);
        var blocker  = wall.GetComponent <MotorBlocker>();

        if (blocker != null)
        {
            motorController.AddBlocker(blocker);
        }

        var dimmer = wall.GetComponent <MeshDimmer>();

        if (dimmer != null)
        {
            dimmer.Init(wallDimSpeed, wallDimLevel, room.neverDim || facing == RoomFacing.East || facing == RoomFacing.West || (isExterior && facing == RoomFacing.North));
        }
    }
    public List <Vector2Int> GetConnectedPositions(Vector2Int housePosition)
    {
        var state     = rooms[housePosition.x][housePosition.y];
        var connected = new List <Vector2Int>();

        foreach (var direction in  state.wallStates.Keys)
        {
            var wallState = state.wallStates[direction];
            if (wallState == WallState.Open || wallState == WallState.None)
            {
                connected.Add(housePosition + RoomFacingUtil.GetOffset(direction));
            }
        }
        return(connected);
    }
    private RoomState AddRoom(RoomProvider roomPrefab, int x, int y, RoomFacing orientation)
    {
        var myPosition = new Vector2Int(x, y);
        var room       = GameObject.Instantiate(roomPrefab.GetRoom(), Vector3.zero, RoomFacingUtil.GetRotation(orientation), startingRoomAnchor.transform);

        var blockers = room.GetBlockers();

        foreach (var blocker in blockers)
        {
            motorController.AddBlocker(blocker);
        }

        var hauntProviders = room.GetHauntProviders();

        foreach (var hauntProvider in hauntProviders)
        {
            hauntController.AddHauntable(hauntProvider.GetHauntable());
        }

        rooms[x][y] = new RoomState()
        {
            orientation = orientation, x = x, y = y, room = room
        };
        room.orientation = orientation;
        room.gameObject.transform.localPosition = new Vector3(x * unitWorldSize, 0, y * unitWorldSize);
        pathController.AddLinks(room.path.links);
        foreach (var anchor in room.anchors)
        {
            if (!anchor.allowAttachment)
            {
                continue;
            }
            var anchorFacingOrientated       = RoomFacingUtil.GetOrientated(anchor.facing, orientation);
            var anchorFacingOrientedOpposite = RoomFacingUtil.GetOpposite(anchorFacingOrientated);
            var offset   = RoomFacingUtil.GetOffset(anchorFacingOrientated);
            var position = getValidatedPosition(offset.x + x, offset.y + y);
            if (position == INVALID_POS)
            {
                continue;
            }
            var roomAtFacing = rooms[position.x][position.y];
            if (roomAtFacing == null)
            {
                var existingFree = freePositions.FindIndex((item) => item.position == position);
                if (existingFree >= 0)
                {
                    continue;
                }
                freePositions.Add(new FreePosition()
                {
                    position = position, from = anchorFacingOrientedOpposite
                });
            }
        }
        var myFreeIndex = freePositions.FindIndex((item) => item.position == myPosition);

        if (myFreeIndex < 0)
        {
            return(rooms[x][y]);
        }
        freePositions.RemoveAt(myFreeIndex);
        return(rooms[x][y]);
    }
    public void Generate()
    {
        freePositions = new List <FreePosition>();
        rooms         = new RoomState[maxX][];
        for (int x = 0; x < maxX; x++)
        {
            rooms[x] = new RoomState[maxY];
        }

        var startingRoom = AddRoom(startingRoomPrefabFront, maxX / 2 + maxX % 2, 0, RoomFacing.South);

        startingRoom.neverDim = true;
        var startingRoomComp = startingRoom.room.gameObject.GetComponent <StartingRoom>();

        startingPoint = startingRoomComp.startingPoint;
        entrancePoint = startingRoomComp.entrancePoint;
        var backStartingRoom = AddRoom(startingRoomPrefabBack, maxX / 2 + maxX % 2, 1, RoomFacing.South);

        startingRoom.isStarting     = true;
        backStartingRoom.isStarting = true;

        List <Room> roomShuffle = null;

        for (var index = 0; index < targetRoomCount; index++)
        {
            if (freePositions.Count <= 0)
            {
                break;
            }
            var positionIndex = UnityEngine.Random.Range(0, freePositions.Count);
            var orientation   = (RoomFacing)UnityEngine.Random.Range(0, (int)RoomFacing.West + 1);
            var position      = freePositions[positionIndex];
            if (roomShuffle == null || roomShuffle.Count == 0)
            {
                roomShuffle = GetShuffledPrefabs();
            }
            var roomPrefab = roomShuffle[roomShuffle.Count - 1];
            roomShuffle.RemoveAt(roomShuffle.Count - 1);

            var mustRotate = true;
            while (mustRotate)
            {
                var orientatedFrom = RoomFacingUtil.GetInverseOrientated(position.from, orientation);
                var fromAnchor     = roomPrefab.anchors.Find(anchor => anchor.facing == orientatedFrom);
                if (!fromAnchor.allowAttachment)
                {
                    orientation = RoomFacingUtil.IncrementWrapped(orientation, 1);
                    continue;
                }
                //Debug.Log(position.position + " from " + position.from + " oks anchor " + orientatedFrom + " for " + orientation);
                mustRotate = false;
            }
            AddRoom(roomPrefab, position.position.x, position.position.y, orientation);
        }

        for (var x = 0; x < maxX; x++)
        {
            for (var y = 0; y < maxY; y++)
            {
                var roomState = rooms[x][y];
                if (roomState == null)
                {
                    continue;
                }

                foreach (var facing in RoomFacingUtil.ALL)
                {
                    if (roomState.wallStates[facing] == WallState.Unknown)
                    {
                        var offset          = RoomFacingUtil.GetOffset(facing);
                        var position        = getValidatedPosition(offset.x + x, offset.y + y);
                        var facingOriented  = RoomFacingUtil.GetInverseOrientated(facing, roomState.orientation);
                        var anchorForFacing = roomState.room.anchors.Find((anchor) => anchor.facing == facingOriented);
                        if (position == INVALID_POS)
                        {
                            GenerateWall(x, y, WallState.Solid, roomState, facing, true);
                            anchorForFacing.exitPathPoint.isDeactivated = true;
                            continue;
                        }

                        var oppositeRoom = rooms[position.x][position.y];
                        if (oppositeRoom == null)
                        {
                            GenerateWall(x, y, WallState.Solid, roomState, facing, true);
                            anchorForFacing.exitPathPoint.isDeactivated = true;
                            continue;
                        }

                        var oppositeFacing          = RoomFacingUtil.GetOpposite(facing);
                        var oppositeFacingOriented  = RoomFacingUtil.GetInverseOrientated(oppositeFacing, oppositeRoom.orientation);
                        var anchorForOppositeFacing = oppositeRoom.room.anchors.Find((anchor) => anchor.facing == oppositeFacingOriented);
                        if (!anchorForFacing.allowAttachment)
                        {
                            GenerateWall(x, y, WallState.Solid, roomState, facing, false);
                            oppositeRoom.wallStates[oppositeFacing]             = WallState.Solid;
                            anchorForFacing.exitPathPoint.isDeactivated         = true;
                            anchorForOppositeFacing.exitPathPoint.isDeactivated = true;
                            continue;
                        }

                        if (!anchorForOppositeFacing.allowAttachment)
                        {
                            GenerateWall(x, y, WallState.Solid, roomState, facing, false);
                            oppositeRoom.wallStates[oppositeFacing]             = WallState.Solid;
                            anchorForFacing.exitPathPoint.isDeactivated         = true;
                            anchorForOppositeFacing.exitPathPoint.isDeactivated = true;
                            continue;
                        }

                        if (anchorForOppositeFacing.allowNoWall && anchorForFacing.allowNoWall)
                        {
                            GenerateWall(x, y, WallState.None, roomState, facing, false);
                            oppositeRoom.wallStates[oppositeFacing] = WallState.None;
                            continue;
                        }
                        GenerateWall(x, y, WallState.Open, roomState, facing, false);
                        var isHorizontal = facing == RoomFacing.North || facing == RoomFacing.South;
                        var barrierPoint = new BarrierPoint()
                        {
                            anchor = anchorForFacing.exitPathPoint.transform, isHorizontal = isHorizontal
                        };
                        barrierController.AddPoint(barrierPoint);
                        oppositeRoom.wallStates[oppositeFacing] = WallState.Open;
                    }
                }
            }
        }
    }