Пример #1
0
        /// <summary>
        /// Finds appropriate place to use as unlock place for given locked place.
        /// </summary>
        /// <param name="lockedPlace"></param>
        /// <returns>Index of unlock place in Places list</returns>
        public int GetUnlock(PuzzlePlace lockedPlace)
        {
            var lockedPlaceIndex = lockedPlace.PlaceIndex;

            // Get index of room behind lockedPlace door.
            lockedPlaceIndex = this.Places[lockedPlaceIndex].Room.Neighbor[lockedPlace.DoorDirection].RoomIndex;
            if (lockedPlaceIndex == 0 || lockedPlaceIndex == -1)             // should be last room in section.
            {
                lockedPlaceIndex = this.Places.Count;
            }

            List <int> possiblePlacesOnPath    = new List <int>();
            List <int> possiblePlacesNotOnPath = new List <int>();
            var        deadEnd      = -1;
            var        deadEndDepth = 0;
            RoomTrait  room;

            // places before lockedPlaceIndex are always behind it.
            for (var i = 0; i < lockedPlaceIndex; ++i)
            {
                room = this.Places[i].Room;
                if (!this.Places[i].IsUsed && !room.isLocked && room.RoomType != RoomType.Start)
                {
                    // Check is this place have locked doors.
                    // Locked places tend to not reserve themselves, so they could share place with some puzzle, like another locked place.
                    // But they couldn't be shared with unlock places, because they have to control all doors.
                    var haveLockedDoors = false;
                    for (var j = 0; j < 4; ++j)
                    {
                        if (room.DoorType[j] == (int)DungeonBlockType.DoorWithLock && room.Links[j] == LinkType.To)
                        {
                            haveLockedDoors = true;
                            break;
                        }
                    }
                    if (!haveLockedDoors)
                    {
                        var emptyNeighborCount = 0;
                        for (var dir = 0; dir < 4; ++dir)
                        {
                            if (room.IsLinked(dir) && !room.Neighbor[dir].isReserved)
                            {
                                emptyNeighborCount++;
                            }
                        }
                        if (emptyNeighborCount < 2)
                        {
                            if (deadEndDepth < this.Places[i].Depth)
                            {
                                deadEnd = i;
                            }
                        }
                        if (room.isOnPath)
                        {
                            possiblePlacesOnPath.Add(i);
                        }
                        else
                        {
                            possiblePlacesNotOnPath.Add(i);
                        }
                    }
                }
            }

            // Chance to not use deepest corner for unlock place.
            if (_rng.GetUInt32(100) < 40)
            {
                deadEnd = -1;
            }

            if (possiblePlacesOnPath.Count == 0 && possiblePlacesNotOnPath.Count == 0)
            {
                // Convert locked place room back to alley if there are no more locked doors.
                room = this.Places[lockedPlace.PlaceIndex].Room;
                room.SetDoorType(lockedPlace.DoorDirection, (int)DungeonBlockType.Alley);
                room.SetPuzzleDoor(null, lockedPlace.DoorDirection);
                var isLockedRoom = room.DoorType.Any(x => (x == (int)DungeonBlockType.DoorWithLock || x == (int)DungeonBlockType.BossDoor));
                if (!isLockedRoom)
                {
                    room.isLocked = false;
                    room.RoomType = RoomType.Alley;
                }

                // Return locked place door to list on available doors.
                var lockedDoorCandidate = new LockedDoorCandidateNode(room, lockedPlace.DoorDirection, room.RoomIndex);
                _lockedDoorCandidates.AddFirst(lockedDoorCandidate);
                throw new PuzzleException("Out of unlock places.");
            }

            var possiblePlaces = (possiblePlacesNotOnPath.Count > 0 ? possiblePlacesNotOnPath : possiblePlacesOnPath);

            var placeIndex = deadEnd != -1 ? deadEnd : possiblePlaces[(int)_rng.GetUInt32((uint)possiblePlaces.Count)];

            // Walk down from current place to our path and add new possible doors to this._lockedDoorCandidates
            room = this.Places[placeIndex].Room;
            while (room.RoomType != RoomType.Start)
            {
                if (room.isOnPath)
                {
                    break;
                }
                var dir = room.GetIncomingDirection();
                room.isOnPath = true;
                room          = room.Neighbor[dir];

                // skip reserved doors
                //if (room.ReservedDoor[Direction.GetOppositeDirection(dir)]) continue;
                // skip reserved places
                if (room.isReserved)
                {
                    continue;
                }

                var lockedDoorCandidate = new LockedDoorCandidateNode(room, Direction.GetOppositeDirection(dir), room.RoomIndex);
                _lockedDoorCandidates.AddFirst(lockedDoorCandidate);
            }
            return(placeIndex);
        }