Compare commits
4 Commits
master
...
map_genera
Author | SHA1 | Date |
---|---|---|
Charles Peyrat | ebca28930c | |
Charles Peyrat | bcfde6fa49 | |
Charles Peyrat | 5981927dac | |
Charles Peyrat | 38878687c4 |
|
@ -21,36 +21,38 @@ DEFAULT_PARAMS = {
|
||||||
"large_circular_room": .10,
|
"large_circular_room": .10,
|
||||||
"circular_holes": .5,
|
"circular_holes": .5,
|
||||||
"loop_tries": 40,
|
"loop_tries": 40,
|
||||||
"loop_max": 5,
|
"loop_max": 8,
|
||||||
"loop_threshold": 15,
|
"loop_threshold": 15,
|
||||||
"spawn_per_region": [1, 2],
|
"spawn_per_region": [1, 2],
|
||||||
"room_chances" : {
|
"room_chances" : {
|
||||||
"circular" : 5,
|
"circular" : 1,
|
||||||
"chunks" : 1,
|
"chunks" : 1,
|
||||||
|
"rectangle" : 1,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
def dist(level, y1, x1, y2, x2):
|
def test_dist(level, y1, x1, y2, x2, threshold):
|
||||||
"""
|
"""
|
||||||
Compute the minimum walking distance between points (y1, x1) and (y2, x2) on a Tile grid
|
Returns whether the minimum walking distance between points (y1, x1) and
|
||||||
|
(y2, x2) on the Tile grid level is greater than threshold
|
||||||
"""
|
"""
|
||||||
# simple breadth first search
|
# simple breadth first search
|
||||||
copy = [[t for t in row] for row in level]
|
copy = [[t for t in row] for row in level]
|
||||||
dist = -1
|
dist = -1
|
||||||
queue, next_queue = [[y1, x1]], [0]
|
queue, next_queue = [[y1, x1]], [0]
|
||||||
while next_queue:
|
while next_queue and dist < threshold:
|
||||||
next_queue = []
|
next_queue = []
|
||||||
dist += 1
|
dist += 1
|
||||||
while queue:
|
while queue:
|
||||||
y, x = queue.pop()
|
y, x = queue.pop()
|
||||||
copy[y][x] = Tile.EMPTY
|
copy[y][x] = Tile.EMPTY
|
||||||
if y == y2 and x == x2:
|
if y == y2 and x == x2:
|
||||||
return dist
|
return False
|
||||||
for y, x in Map.neighbourhood(copy, y, x):
|
for y, x in Map.neighbourhood(copy, y, x):
|
||||||
if copy[y][x].can_walk():
|
if copy[y][x].can_walk():
|
||||||
next_queue.append([y, x])
|
next_queue.append([y, x])
|
||||||
queue = next_queue
|
queue = next_queue
|
||||||
return -1
|
return True
|
||||||
|
|
||||||
|
|
||||||
class Generator:
|
class Generator:
|
||||||
|
@ -147,7 +149,7 @@ class Generator:
|
||||||
return True
|
return True
|
||||||
# if adding the path would make the two tiles significantly closer
|
# if adding the path would make the two tiles significantly closer
|
||||||
# and its sides don't touch already placed terrain, build it
|
# and its sides don't touch already placed terrain, build it
|
||||||
if dist(level, y1, x1, y2, x2) < 20 and verify_sides():
|
if test_dist(level, y1, x1, y2, x2, 20) and verify_sides():
|
||||||
y, x = y1 + dy, x1 + dx
|
y, x = y1 + dy, x1 + dx
|
||||||
while level[y][x] == Tile.EMPTY:
|
while level[y][x] == Tile.EMPTY:
|
||||||
level[y][x] = Tile.FLOOR
|
level[y][x] = Tile.FLOOR
|
||||||
|
@ -216,7 +218,8 @@ class Generator:
|
||||||
return False
|
return False
|
||||||
# see if the path ahead is clear. needed in the case of non convex room
|
# see if the path ahead is clear. needed in the case of non convex room
|
||||||
for i in range(length + 1):
|
for i in range(length + 1):
|
||||||
if room[y + i * dy][x + i * dx] != Tile.EMPTY:
|
if not(0 <= y + i * dy < rh and 0 <= x + i * dx < rw) \
|
||||||
|
or room[y + i * dy][x + i * dx] != Tile.EMPTY:
|
||||||
return False
|
return False
|
||||||
for i in range(length):
|
for i in range(length):
|
||||||
room[y + i * dy][x + i * dx] = Tile.FLOOR
|
room[y + i * dy][x + i * dx] = Tile.FLOOR
|
||||||
|
@ -252,17 +255,15 @@ class Generator:
|
||||||
if room[y][x] == Tile.EMPTY and \
|
if room[y][x] == Tile.EMPTY and \
|
||||||
Generator.build_door(room, y, x, dy, dx, length):
|
Generator.build_door(room, y, x, dy, dx, length):
|
||||||
break
|
break
|
||||||
else:
|
|
||||||
return None, None
|
|
||||||
|
|
||||||
return y + length * dy, x + length * dx, dy, dx
|
return y + length * dy, x + length * dx, dy, dx
|
||||||
|
|
||||||
def create_chunk_room(self, spawnable: bool = True) \
|
def create_chunk_room(self, spawnable: bool = True) \
|
||||||
-> Tuple[List[List[Tile]], int, int, int, int]:
|
-> Tuple[List[List[Tile]], int, int, int, int]:
|
||||||
"""
|
"""
|
||||||
Create and return as a tile grid a room that is composed of multiple
|
create and return as a tile grid a room that is composed of multiple
|
||||||
overlapping circles of the same radius
|
overlapping circles of the same radius
|
||||||
Also return door info so we know how to place the room in the level
|
also return door info so we know how to place the room in the level
|
||||||
"""
|
"""
|
||||||
height, width = 15, 15
|
height, width = 15, 15
|
||||||
nb_chunks, r = 6, 3
|
nb_chunks, r = 6, 3
|
||||||
|
@ -341,6 +342,42 @@ class Generator:
|
||||||
|
|
||||||
return room, door_y, door_x, dy, dx
|
return room, door_y, door_x, dy, dx
|
||||||
|
|
||||||
|
def create_rectangle_room(self, spawnable: bool = True) \
|
||||||
|
-> Tuple[List[List[Tile]], int, int, int, int]:
|
||||||
|
"""
|
||||||
|
create and return as a tile grid a rectangular room
|
||||||
|
also return door info so we know how to place the room in the level
|
||||||
|
"""
|
||||||
|
|
||||||
|
shrt, lng = randint(3, 6), randint(6, 12)
|
||||||
|
if random() < .5:
|
||||||
|
height, width = shrt, lng
|
||||||
|
else:
|
||||||
|
height, width = lng, shrt
|
||||||
|
|
||||||
|
room = []
|
||||||
|
|
||||||
|
h_sup, w_sup, h_off, w_off = self.corr_meta_info()
|
||||||
|
min_w, max_w = w_off + 1, width + w_off
|
||||||
|
min_h, max_h = h_off + 1, height + h_off
|
||||||
|
for i in range(height + h_sup + 2):
|
||||||
|
room.append([])
|
||||||
|
for j in range(width + w_sup + 2):
|
||||||
|
if min_h <= i <= max_h and min_w <= j <= max_w:
|
||||||
|
room[-1].append(Tile.FLOOR)
|
||||||
|
else:
|
||||||
|
room[-1].append(Tile.EMPTY)
|
||||||
|
|
||||||
|
# log all placed tiles as spawn positions
|
||||||
|
if spawnable:
|
||||||
|
self.register_spawn_area(room)
|
||||||
|
|
||||||
|
# attach exit
|
||||||
|
door_y, door_x, dy, dx = self.attach_door(room, h_sup, w_sup,
|
||||||
|
h_off, w_off)
|
||||||
|
|
||||||
|
return room, door_y, door_x, dy, dx
|
||||||
|
|
||||||
def create_random_room(self, spawnable: bool = True) \
|
def create_random_room(self, spawnable: bool = True) \
|
||||||
-> Tuple[List[list], int, int, int, int]:
|
-> Tuple[List[list], int, int, int, int]:
|
||||||
"""
|
"""
|
||||||
|
@ -361,6 +398,8 @@ class Generator:
|
||||||
return self.create_circular_room(spawnable = spawnable)
|
return self.create_circular_room(spawnable = spawnable)
|
||||||
elif key == "chunks":
|
elif key == "chunks":
|
||||||
return self.create_chunk_room(spawnable = spawnable)
|
return self.create_chunk_room(spawnable = spawnable)
|
||||||
|
elif key == "rectangle":
|
||||||
|
return self.create_rectangle_room(spawnable = spawnable)
|
||||||
|
|
||||||
def register_spawn_area(self, area: List[List[Tile]]) -> None:
|
def register_spawn_area(self, area: List[List[Tile]]) -> None:
|
||||||
"""
|
"""
|
||||||
|
@ -450,7 +489,6 @@ class Generator:
|
||||||
tries += 1
|
tries += 1
|
||||||
|
|
||||||
# post-processing
|
# post-processing
|
||||||
self.place_walls(level)
|
|
||||||
|
|
||||||
# because when a room is placed, it leads to exactly one previously
|
# because when a room is placed, it leads to exactly one previously
|
||||||
# placed room, the level has a tree like structure with the starting
|
# placed room, the level has a tree like structure with the starting
|
||||||
|
@ -464,6 +502,9 @@ class Generator:
|
||||||
y, x = randint(0, height - 1), randint(0, width - 1)
|
y, x = randint(0, height - 1), randint(0, width - 1)
|
||||||
loops += self.add_loop(level, y, x)
|
loops += self.add_loop(level, y, x)
|
||||||
|
|
||||||
|
# surround the floor with walls
|
||||||
|
self.place_walls(level)
|
||||||
|
|
||||||
# place an exit ladder
|
# place an exit ladder
|
||||||
y, x = randint(0, height - 1), randint(0, width - 1)
|
y, x = randint(0, height - 1), randint(0, width - 1)
|
||||||
while level[y][x] != Tile.FLOOR or \
|
while level[y][x] != Tile.FLOOR or \
|
||||||
|
|
Loading…
Reference in New Issue