Move map modules to their own directory

This commit is contained in:
Eryn Wells 2023-02-08 08:36:00 -08:00
parent a4f4584ffd
commit 1df7cea2ad
2 changed files with 47 additions and 17 deletions

View file

@ -7,21 +7,22 @@ from typing import Iterator, List, Optional
import numpy as np import numpy as np
import tcod import tcod
from . import log from .. import log
from .geometry import Direction, Point, Rect, Size from ..geometry import Direction, Point, Rect, Size
from .tile import Empty, Floor, Shroud, Wall from .tile import Empty, Floor, Shroud, Wall
class Map: class Map:
def __init__(self, size: Size): def __init__(self, size: Size, room_generator_class=RoomsAndCorridorsGenerator):
self.size = size self.size = size
self.generator = RoomsAndCorridorsGenerator(size=size) self.generator = room_generator_class(size=size)
self.tiles = self.generator.generate() self.tiles = self.generator.generate()
# Map tiles that are currently visible to the player # Map tiles that are currently visible to the player
self.visible = np.full(tuple(self.size), fill_value=False, order='F') self.visible = np.full(tuple(self.size), fill_value=True, order='F')
# Map tiles that the player has explored # Map tiles that the player has explored
self.explored = np.full(tuple(self.size), fill_value=False, order='F') self.explored = np.full(tuple(self.size), fill_value=True, order='F')
@property @property
def rooms(self) -> List['Room']: def rooms(self) -> List['Room']:
@ -54,6 +55,7 @@ class Map:
choicelist=[self.tiles['light'], self.tiles['dark']], choicelist=[self.tiles['light'], self.tiles['dark']],
default=Shroud) default=Shroud)
class MapGenerator: class MapGenerator:
def __init__(self, *, size: Size): def __init__(self, *, size: Size):
self.size = size self.size = size
@ -73,6 +75,7 @@ class MapGenerator:
''' '''
raise NotImplementedError() raise NotImplementedError()
class RoomsAndCorridorsGenerator(MapGenerator): class RoomsAndCorridorsGenerator(MapGenerator):
'''Generate a rooms-and-corridors style map with BSP.''' '''Generate a rooms-and-corridors style map with BSP.'''
@ -82,8 +85,8 @@ class RoomsAndCorridorsGenerator(MapGenerator):
maximum_room_size: Size maximum_room_size: Size
DefaultConfiguration = Configuration( DefaultConfiguration = Configuration(
minimum_room_size=Size(5, 5), minimum_room_size=Size(7, 7),
maximum_room_size=Size(15, 15), maximum_room_size=Size(20, 20),
) )
def __init__(self, *, size: Size, config: Optional[Configuration] = None): def __init__(self, *, size: Size, config: Optional[Configuration] = None):
@ -104,11 +107,16 @@ class RoomsAndCorridorsGenerator(MapGenerator):
# Recursively divide the map into squares of various sizes to place rooms in. # Recursively divide the map into squares of various sizes to place rooms in.
bsp = tcod.bsp.BSP(x=0, y=0, width=self.size.width, height=self.size.height) bsp = tcod.bsp.BSP(x=0, y=0, width=self.size.width, height=self.size.height)
# Add 2 to the minimum width and height to account for walls
gap_for_walls = 2
bsp.split_recursive( bsp.split_recursive(
depth=4, depth=4,
# Add 2 to the minimum width and height to account for walls min_width=minimum_room_size.width + gap_for_walls,
min_width=minimum_room_size.width + 2, min_height=minimum_room_size.height + 2, min_height=minimum_room_size.height + gap_for_walls,
max_horizontal_ratio=3, max_vertical_ratio=3) max_horizontal_ratio=1.1,
max_vertical_ratio=1.1
)
tiles = np.full(tuple(self.size), fill_value=Empty, order='F') tiles = np.full(tuple(self.size), fill_value=Empty, order='F')
@ -141,7 +149,8 @@ class RoomsAndCorridorsGenerator(MapGenerator):
else: else:
corner = Point(start_point.x, end_point.y) corner = Point(start_point.x, end_point.y)
log.MAP.debug('Digging a tunnel between %s and %s with corner %s', start_point, end_point, corner) log.MAP.debug(
'Digging a tunnel between %s and %s with corner %s', start_point, end_point, corner)
log.MAP.debug('|-> start: %s', left_room_bounds) log.MAP.debug('|-> start: %s', left_room_bounds)
log.MAP.debug('`-> end: %s', right_room_bounds) log.MAP.debug('`-> end: %s', right_room_bounds)
@ -155,10 +164,19 @@ class RoomsAndCorridorsGenerator(MapGenerator):
# Generate a room size between minimum_room_size and maximum_room_size. The minimum value is # Generate a room size between minimum_room_size and maximum_room_size. The minimum value is
# straight-forward, but the maximum value needs to be clamped between minimum_room_size and the size of # straight-forward, but the maximum value needs to be clamped between minimum_room_size and the size of
# the node. # the node.
width_range = (minimum_room_size.width, min(maximum_room_size.width, max(minimum_room_size.width, node.width - 2))) width_range = (
height_range = (minimum_room_size.height, min(maximum_room_size.height, max(minimum_room_size.height, node.height - 2))) minimum_room_size.width,
min(maximum_room_size.width, max(
minimum_room_size.width, node.width - 2))
)
height_range = (
minimum_room_size.height,
min(maximum_room_size.height, max(
minimum_room_size.height, node.height - 2))
)
size = Size(self.rng.randint(*width_range), self.rng.randint(*height_range)) size = Size(self.rng.randint(*width_range),
self.rng.randint(*height_range))
origin = Point(node.x + self.rng.randint(1, max(1, node.width - size.width - 1)), origin = Point(node.x + self.rng.randint(1, max(1, node.width - size.width - 1)),
node.y + self.rng.randint(1, max(1, node.height - size.height - 1))) node.y + self.rng.randint(1, max(1, node.height - size.height - 1)))
bounds = Rect(origin, size) bounds = Rect(origin, size)
@ -193,7 +211,8 @@ class RoomsAndCorridorsGenerator(MapGenerator):
bounds = room.bounds bounds = room.bounds
# The range of a numpy array slice is [a, b). # The range of a numpy array slice is [a, b).
floor_rect = bounds.inset_rect(top=1, right=1, bottom=1, left=1) floor_rect = bounds.inset_rect(top=1, right=1, bottom=1, left=1)
tiles[floor_rect.min_x:floor_rect.max_x + 1, floor_rect.min_y:floor_rect.max_y + 1] = Floor tiles[floor_rect.min_x:floor_rect.max_x + 1,
floor_rect.min_y:floor_rect.max_y + 1] = Floor
for y in range(self.size.height): for y in range(self.size.height):
for x in range(self.size.width): for x in range(self.size.width):
@ -215,6 +234,16 @@ class RoomsAndCorridorsGenerator(MapGenerator):
'''Create a Rect from the given BSP node object''' '''Create a Rect from the given BSP node object'''
return Rect(Point(node.x, node.y), Size(node.width, node.height)) return Rect(Point(node.x, node.y), Size(node.width, node.height))
class ElbowCorridorGenerator:
...
class NetHackCorridorGenerator:
'''A corridor generator that produces doors and corridors that look like Nethack's Dungeons of Doom levels.'''
...
class Room: class Room:
'''An abstract room. It can be any size or shape.''' '''An abstract room. It can be any size or shape.'''
@ -222,6 +251,7 @@ class Room:
def walkable_tiles(self) -> Iterator[Point]: def walkable_tiles(self) -> Iterator[Point]:
raise NotImplementedError() raise NotImplementedError()
class RectangularRoom(Room): class RectangularRoom(Room):
'''A rectangular room defined by a Rect. '''A rectangular room defined by a Rect.
@ -241,7 +271,7 @@ class RectangularRoom(Room):
return self.bounds.midpoint return self.bounds.midpoint
@property @property
def walkable_tiles(self) -> Rect: def walkable_tiles(self) -> Iterator[Point]:
floor_rect = self.bounds.inset_rect(top=1, right=1, bottom=1, left=1) floor_rect = self.bounds.inset_rect(top=1, right=1, bottom=1, left=1)
for y in range(floor_rect.min_y, floor_rect.max_y + 1): for y in range(floor_rect.min_y, floor_rect.max_y + 1):
for x in range(floor_rect.min_x, floor_rect.max_x + 1): for x in range(floor_rect.min_x, floor_rect.max_x + 1):