Exemple #1
0
        /// <summary>
        /// Creates Places list, walking critical path and adding subpaths recursively.
        /// Creates _lockedDoorCandidates list, places on the way to end room and to chest places.
        /// </summary>
        /// <param name="startRoom"></param>
        /// <param name="path"></param>
        private void InitLists(RoomTrait startRoom, List <MazeMove> path)
        {
            var room  = startRoom;
            var depth = 0;

            foreach (var move in path)
            {
                this.Places.Add(new PlaceNode(room, depth, false));
                room.RoomIndex = this.Places.Count - 1;
                room.isOnPath  = true;
                var lockedDoorCandidate = new LockedDoorCandidateNode(room, move.Direction, this.Places.Count - 1);
                _lockedDoorCandidates.AddLast(lockedDoorCandidate);
                for (var direction = 0; direction < 4; direction++)
                {
                    if (move.Direction != direction && room.Links[direction] == LinkType.To)
                    {
                        var nextRoom = room.Neighbor[direction];
                        if (nextRoom != null)
                        {
                            CreateEmptyPlacesRecursive(nextRoom, depth + 1);
                        }
                    }
                }
                room = room.Neighbor[move.Direction];
                depth++;
            }
        }
Exemple #2
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;
		}
Exemple #3
0
		/// <summary>
		/// Creates Places list, walking critical path and adding subpaths recursively.
		/// Creates _lockedDoorCandidates list, places on the way to end room and to chest places.
		/// </summary>
		/// <param name="startRoom"></param>
		/// <param name="path"></param>
		private void InitLists(RoomTrait startRoom, List<MazeMove> path)
		{
			var room = startRoom;
			var depth = 0;
			foreach (var move in path)
			{
				this.Places.Add(new PlaceNode(room, depth, false));
				room.RoomIndex = this.Places.Count - 1;
				room.isOnPath = true;
				var lockedDoorCandidate = new LockedDoorCandidateNode(room, move.Direction, this.Places.Count - 1);
				_lockedDoorCandidates.AddLast(lockedDoorCandidate);
				for (var direction = 0; direction < 4; direction++)
				{
					if (move.Direction != direction && room.Links[direction] == LinkType.To)
					{
						var nextRoom = room.Neighbor[direction];
						if (nextRoom != null)
							CreateEmptyPlacesRecursive(nextRoom, depth + 1);
					}
				}
				room = room.Neighbor[move.Direction];
				depth++;
			}
		}
Exemple #4
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);
        }
Exemple #5
0
        /// <summary>
        /// Gets a node from _lockedDoorCandidates, that will be used to make locked place, and removes it from the list.
        /// </summary>
        /// <param name="lockSelf"></param>
        /// <returns></returns>
        public LockedDoorCandidateNode GetLock(bool lockSelf = false)
        {
            LockedDoorCandidateNode result = null;

            var count = _lockedDoorCandidates.Count;

            if (count == 0)
            {
                throw new PuzzleException("Out of locked door candidates.");
            }

            // Always place locked place before the boss door.
            // todo: always place a locked place at the end of section, add script handler
            if (_placeBossDoor)
            {
                result = _lockedDoorCandidates.FirstOrDefault(x =>
                                                              x.Room.Neighbor[Direction.Up] != null && x.Room.Neighbor[Direction.Up].RoomType == RoomType.End);
            }

            if (result == null)
            {
                var lockedDoor = _lockedDoorCandidates.Last;
                if (lockSelf)
                {
                    while (lockedDoor != null && lockedDoor.Value.Room.isReserved)
                    {
                        lockedDoor = lockedDoor.Previous;
                    }
                }
                else
                {
                    while (lockedDoor != null)
                    {
                        // Test if there is a free room for unlock place before this door
                        var placeIndex = lockedDoor.Value.PlaceIndex;
                        // Get index of room behind lockedPlace door.
                        placeIndex = this.Places[placeIndex].Room.Neighbor[lockedDoor.Value.Direction].RoomIndex;
                        if (placeIndex == 0 || placeIndex == -1)                         // should be last room in section.
                        {
                            placeIndex = this.Places.Count;
                        }
                        --placeIndex;
                        while (placeIndex >= 0 && (placeIndex == lockedDoor.Value.PlaceIndex || this.Places[placeIndex].IsUsed || this.Places[placeIndex].Room.isLocked))
                        {
                            --placeIndex;
                        }
                        if (placeIndex >= 0)
                        {
                            break;
                        }
                        lockedDoor = lockedDoor.Previous;
                    }
                }
                if (lockedDoor == null)
                {
                    if (lockSelf)
                    {
                        throw new PuzzleException("Out of candidates for self lock.");
                    }
                    throw new PuzzleException("None of lock candidates can serve as lock with unlock place.");
                }
                result = lockedDoor.Value;
            }

            if (_placeBossDoor)
            {
                _placeBossDoor = false;
            }

            _lockedDoorCandidates.Remove(result);

            return(result);
        }