Implement populate method, so map generation also handles entity spawn

This commit is contained in:
Charles Peyrat 2021-01-10 21:49:39 +01:00
parent e639ad6255
commit 12e19759aa

View File

@ -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