Implement populate method, so map generation also handles entity spawn
This commit is contained in:
		@@ -1,10 +1,10 @@
 | 
				
			|||||||
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
 | 
					# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
 | 
				
			||||||
# SPDX-License-Identifier: GPL-3.0-or-later
 | 
					# 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 typing import List, Tuple
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from ..interfaces import Map, Tile
 | 
					from ..interfaces import Map, Tile, Entity
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEFAULT_PARAMS = {
 | 
					DEFAULT_PARAMS = {
 | 
				
			||||||
    "width": 120,
 | 
					    "width": 120,
 | 
				
			||||||
@@ -23,6 +23,7 @@ DEFAULT_PARAMS = {
 | 
				
			|||||||
    "loop_tries" : 40,
 | 
					    "loop_tries" : 40,
 | 
				
			||||||
    "loop_max" : 5,
 | 
					    "loop_max" : 5,
 | 
				
			||||||
    "loop_threshold" : 15,
 | 
					    "loop_threshold" : 15,
 | 
				
			||||||
 | 
					    "spawn_per_region" : [1, 2],
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def dist(level, y1, x1, y2, x2):
 | 
					def dist(level, y1, x1, y2, x2):
 | 
				
			||||||
@@ -46,6 +47,8 @@ def dist(level, y1, x1, y2, x2):
 | 
				
			|||||||
class Generator:
 | 
					class Generator:
 | 
				
			||||||
    def __init__(self, params: dict = None):
 | 
					    def __init__(self, params: dict = None):
 | 
				
			||||||
        self.params = params or DEFAULT_PARAMS
 | 
					        self.params = params or DEFAULT_PARAMS
 | 
				
			||||||
 | 
					        self.spawn_areas = []
 | 
				
			||||||
 | 
					        self.queued_area = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @staticmethod
 | 
					    @staticmethod
 | 
				
			||||||
    def room_fits(level: List[List[Tile]], y: int, x: int,
 | 
					    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
 | 
					        return y + length * dy, x + length * dx, dy, dx
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def create_circular_room(self) -> Tuple[List[List[Tile]], int, int,
 | 
					    def create_circular_room(self, spawnable: bool = True) \
 | 
				
			||||||
                                            int, int]:
 | 
					            -> Tuple[List[List[Tile]], int, int, int, int]:
 | 
				
			||||||
        if random() < self.params["large_circular_room"]:
 | 
					        if random() < self.params["large_circular_room"]:
 | 
				
			||||||
            r = randint(5, 10)
 | 
					            r = randint(5, 10)
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
@@ -214,21 +217,49 @@ class Generator:
 | 
				
			|||||||
                else:
 | 
					                else:
 | 
				
			||||||
                    room[-1].append(Tile.EMPTY)
 | 
					                    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,
 | 
					        door_y, door_x, dy, dx = self.attach_door(room, h_sup, w_sup,
 | 
				
			||||||
                                                  h_off, w_off)
 | 
					                                                  h_off, w_off)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return room, door_y, door_x, dy, dx
 | 
					        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()
 | 
					        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:
 | 
					    def run(self) -> Map:
 | 
				
			||||||
        height, width = self.params["height"], self.params["width"]
 | 
					        height, width = self.params["height"], self.params["width"]
 | 
				
			||||||
        level = [width * [Tile.EMPTY] for _ignored in range(height)]
 | 
					        level = [width * [Tile.EMPTY] for _ignored in range(height)]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # the starting room must have no corridor
 | 
					        # the starting room must have no corridor
 | 
				
			||||||
        mem, self.params["corridor_chance"] = self.params["corridor_chance"], 0
 | 
					        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])
 | 
					        dim_v, dim_h = len(starting_room), len(starting_room[0])
 | 
				
			||||||
        pos_y, pos_x = randint(0, height - dim_v - 1),\
 | 
					        pos_y, pos_x = randint(0, height - dim_v - 1),\
 | 
				
			||||||
            randint(0, width - dim_h - 1)
 | 
					            randint(0, width - dim_h - 1)
 | 
				
			||||||
@@ -254,6 +285,7 @@ class Generator:
 | 
				
			|||||||
            for pos in positions:
 | 
					            for pos in positions:
 | 
				
			||||||
                y, x = pos // width, pos % width
 | 
					                y, x = pos // width, pos % width
 | 
				
			||||||
                if self.room_fits(level, y, x, room, door_y, door_x, dy, dx):
 | 
					                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)
 | 
					                    self.place_room(level, y, x, room, door_y, door_x)
 | 
				
			||||||
                    rooms_built += 1
 | 
					                    rooms_built += 1
 | 
				
			||||||
                    break
 | 
					                    break
 | 
				
			||||||
@@ -276,4 +308,8 @@ class Generator:
 | 
				
			|||||||
            y, x = randint(0, height - 1), randint(0, width - 1)
 | 
					            y, x = randint(0, height - 1), randint(0, width - 1)
 | 
				
			||||||
        level[y][x] = Tile.LADDER
 | 
					        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
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user