Implement populate method, so map generation also handles entity spawn
This commit is contained in:
parent
e639ad6255
commit
12e19759aa
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue