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
1 changed files with 43 additions and 7 deletions

View File

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