diff --git a/actions.py b/actions.py index 3667daa..293bede 100644 --- a/actions.py +++ b/actions.py @@ -92,6 +92,21 @@ class WaitAction(Action): pass +class TakeStairsAction(Action): + def perform(self) -> None: + """ + Take the stairs, if any exist at the entity's location. + """ + if (self.entity.x, self.entity.y) == self.engine.game_map.downstairs_location: + self.engine.game_world.generate_floor() + self.engine.message_log.add_message( + "You descent the staircase.", + color.descend + ) + else: + raise exceptions.Impossible("There are no stairs here.") + + class ActionWithDirection(Action): def __init__(self, entity: Actor, dx: int, dy: int): super().__init__(entity) diff --git a/color.py b/color.py index d7d0b5c..1bda85b 100644 --- a/color.py +++ b/color.py @@ -6,6 +6,7 @@ player_atk = (0xE0, 0xE0, 0xE0) enemy_atk = (0xFF, 0xC0, 0xC0) needs_target = (0x3F, 0xFF, 0xFF) status_effect_applied = (0x3F, 0xFF, 0x3F) +descend = (0x9F, 0x3F, 0xFF) player_die = (0xFF, 0x30, 0x30) enemy_die = (0xFF, 0xA0, 0x30) diff --git a/engine.py b/engine.py index 9f9127b..c59feff 100644 --- a/engine.py +++ b/engine.py @@ -13,11 +13,12 @@ from render_functions import render_bar, render_names_at_mouse_location if TYPE_CHECKING: from entity import Actor - from game_map import GameMap + from game_map import GameMap, GameWorld class Engine: game_map: GameMap + game_world: GameWorld def __init__(self, player: Actor): self.message_log = MessageLog() diff --git a/game_map.py b/game_map.py index ed69b82..e39d6f3 100644 --- a/game_map.py +++ b/game_map.py @@ -37,6 +37,8 @@ class GameMap: order="F" ) # Tiles the player has seen before + self.downstairs_location = (0, 0) + @property def gamemap(self) -> GameMap: return self @@ -109,3 +111,53 @@ class GameMap: string=entity.char, fg=entity.color ) + + +class GameWorld: + """ + Holds the settings for the GameMap, and generates new maps when moving down the stairs. + """ + + def __init__( + self, + *, + engine: Engine, + map_width: int, + map_height: int, + max_rooms: int, + room_min_size: int, + room_max_size: int, + max_monsters_per_room: int, + max_items_per_room: int, + current_floor: int = 0 + ): + self.engine = engine + + self.map_width = map_width + self.map_height = map_height + + self.max_rooms = max_rooms + + self.room_min_size = room_min_size + self.room_max_size = room_max_size + + self.max_monsters_per_room = max_monsters_per_room + self.max_items_per_room = max_items_per_room + + self.current_floor = current_floor + + def generate_floor(self) -> None: + from procgen import generate_dungeon + + self.current_floor += 1 + + self.engine.game_map = generate_dungeon( + max_rooms=self.max_rooms, + room_min_size=self.room_min_size, + room_max_size=self.room_max_size, + map_width=self.map_width, + map_height=self.map_height, + max_monsters_per_room=self.max_monsters_per_room, + max_items_per_room=self.max_items_per_room, + engine=self.engine, + ) diff --git a/procgen.py b/procgen.py index d5147ab..f80e0d4 100644 --- a/procgen.py +++ b/procgen.py @@ -113,6 +113,8 @@ def generate_dungeon( rooms: List[RectangularRoom] = [] + center_of_last_room = (0, 0) + for r in range(max_rooms): room_width = random.randint(room_min_size, room_max_size) room_height = random.randint(room_min_size, room_max_size) @@ -139,8 +141,13 @@ def generate_dungeon( for x, y in tunnel_between(rooms[-1].center, new_room.center): dungeon.tiles[x, y] = tile_types.floor + center_of_last_room = new_room.center + place_entities(new_room, dungeon, max_monsters_per_room, max_items_per_room) + dungeon.tiles[center_of_last_room] = tile_types.down_stairs + dungeon.downstairs_location = center_of_last_room + # Finally, append the new room to the list. rooms.append(new_room) diff --git a/setup_game.py b/setup_game.py index 1d69175..3636288 100644 --- a/setup_game.py +++ b/setup_game.py @@ -12,8 +12,8 @@ import tcod import color from engine import Engine import entity_factories +from game_map import GameWorld import input_handlers -from procgen import generate_dungeon # Load the background image and remove the alpha channel. background_image = tcod.image.load("menu_background.png")[:, :, :3] @@ -35,7 +35,7 @@ def new_game() -> Engine: engine = Engine(player) - engine.game_map = generate_dungeon( + engine.game_world = GameWorld( max_rooms=max_rooms, room_min_size=room_min_size, room_max_size=room_max_size, @@ -43,8 +43,8 @@ def new_game() -> Engine: map_height=map_height, max_monsters_per_room=max_monsters_per_room, max_items_per_room=max_items_per_room, - engine=engine, ) + engine.game_world.generate_floor() engine.update_fov() engine.message_log.add_message( diff --git a/tile_types.py b/tile_types.py index a90c550..3172f8b 100644 --- a/tile_types.py +++ b/tile_types.py @@ -49,3 +49,9 @@ wall = new_tile( dark=(ord(" "), (255, 255, 255), (0, 0, 100)), light=(ord(" "), (255, 255, 255), (130, 110, 50)), ) +down_stairs = new_tile( + walkable=True, + transparent=True, + dark=(ord(">"), (0, 0, 100), (50, 50, 150)), + light=(ord(">"), (255, 255, 255), (200, 180, 50)), +)