From 12e19759aa808892236f3509e9b8df7783b98d91 Mon Sep 17 00:00:00 2001 From: Charles Peyrat Date: Sun, 10 Jan 2021 21:49:39 +0100 Subject: [PATCH] Implement populate method, so map generation also handles entity spawn --- squirrelbattle/mapgeneration/broguelike.py | 50 +++++++++++++++++++--- 1 file changed, 43 insertions(+), 7 deletions(-) diff --git a/squirrelbattle/mapgeneration/broguelike.py b/squirrelbattle/mapgeneration/broguelike.py index d5be37f..7fe9f88 100644 --- a/squirrelbattle/mapgeneration/broguelike.py +++ b/squirrelbattle/mapgeneration/broguelike.py @@ -1,10 +1,10 @@ # Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse # SPDX-License-Identifier: GPL-3.0-or-later -from random import random, randint, shuffle +from random import random, randint, shuffle, choice, choices from typing import List, Tuple -from ..interfaces import Map, Tile +from ..interfaces import Map, Tile, Entity DEFAULT_PARAMS = { "width": 120, @@ -23,6 +23,7 @@ DEFAULT_PARAMS = { "loop_tries" : 40, "loop_max" : 5, "loop_threshold" : 15, + "spawn_per_region" : [1, 2], } def dist(level, y1, x1, y2, x2): @@ -46,6 +47,8 @@ def dist(level, y1, x1, y2, x2): class Generator: def __init__(self, params: dict = None): self.params = params or DEFAULT_PARAMS + self.spawn_areas = [] + self.queued_area = None @staticmethod def room_fits(level: List[List[Tile]], y: int, x: int, @@ -186,8 +189,8 @@ class Generator: return y + length * dy, x + length * dx, dy, dx - def create_circular_room(self) -> Tuple[List[List[Tile]], int, int, - int, int]: + def create_circular_room(self, spawnable: bool = True) \ + -> Tuple[List[List[Tile]], int, int, int, int]: if random() < self.params["large_circular_room"]: r = randint(5, 10) else: @@ -214,21 +217,49 @@ class Generator: else: room[-1].append(Tile.EMPTY) + if spawnable: + self.register_spawn_area(room) 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) -> Tuple[List[list], int, int, int, int]: + def create_random_room(self, spawnable: bool = True) \ + -> Tuple[List[list], int, int, int, int]: return self.create_circular_room() + def register_spawn_area(self, area:List[List[Tile]]): + spawn_positions = [] + for y, line in enumerate(area): + for x, tile in enumerate(line): + if tile == Tile.FLOOR: + spawn_positions.append([y, x]) + self.queued_area = spawn_positions + + def update_spawnable(self, y, x): + if self.queued_area != None: + translated_area = [[y+ry, x+rx] for ry, rx in self.queued_area] + self.spawn_areas.append(translated_area) + self.queued_area = None + + def populate(self, rv): + min_c, max_c = self.params["spawn_per_region"] + for region in self.spawn_areas: + entity_count = randint(min_c, max_c) + for _dummy in range(entity_count): + entity = choices(Entity.get_all_entity_classes(), + weights=Entity.get_weights(), k=1)[0]() + y, x = choice(region) + entity.move(y, x) + rv.add_entity(entity) + def run(self) -> Map: height, width = self.params["height"], self.params["width"] level = [width * [Tile.EMPTY] for _ignored in range(height)] # the starting room must have no corridor mem, self.params["corridor_chance"] = self.params["corridor_chance"], 0 - starting_room, _, _, _, _ = self.create_random_room() + starting_room, _, _, _, _ = self.create_random_room(spawnable = False) dim_v, dim_h = len(starting_room), len(starting_room[0]) pos_y, pos_x = randint(0, height - dim_v - 1),\ randint(0, width - dim_h - 1) @@ -254,6 +285,7 @@ class Generator: for pos in positions: y, x = pos // width, pos % width if self.room_fits(level, y, x, room, door_y, door_x, dy, dx): + self.update_spawnable(y - door_y, x - door_x) self.place_room(level, y, x, room, door_y, door_x) rooms_built += 1 break @@ -276,4 +308,8 @@ class Generator: y, x = randint(0, height - 1), randint(0, width - 1) level[y][x] = Tile.LADDER - return Map(width, height, level, sy, sx) + # spawn entities + rv = Map(width, height, level, sy, sx) + self.populate(rv) + + return rv