X-Git-Url: https://git.ctpug.org.za/?a=blobdiff_plain;f=koperkapel%2Fgenerators%2Fmaps.py;h=164d27fb90bcbae767aa576996368f85884c80da;hb=6c6770561fb358f59b4755ba362a65f60c7a1162;hp=51aae6500f4ed313707fbb5353d185eae3f2ea77;hpb=3f18bba4fc135cf788409155711e5d53eb14148d;p=koperkapel.git diff --git a/koperkapel/generators/maps.py b/koperkapel/generators/maps.py index 51aae65..164d27f 100644 --- a/koperkapel/generators/maps.py +++ b/koperkapel/generators/maps.py @@ -2,15 +2,31 @@ import random import math +import json +import os -i = random.randint(0,100) +ATTRIBUTE_MAP = { + ' ': {'floor': {'base': 'floor', + 'behaviour': ['walk', 'fly'], + }, + }, + 'o': {'tunnels': {'base': 'underground', + 'behaviour': [], + } + }, + '-': {'tunnels': {'base': 'tunnel', + 'behaviour': ['walk', ], + }, + }, +} class Room: - def __init__(self, region): + def __init__(self, coordinates, region): """ """ - self.regions = [region] + self.coordinates = [coordinates] + self.region = region self.max_connections = 1 self.passages = [] self.tunnels = [] @@ -22,21 +38,13 @@ class Room: """ return len(self.passages) + len(self.tunnels) > 0 - def add_passage(self, room_region, new_region): - """ Add a passage link between rooms - :param room_region: coordinate of region from which we are linking - :param new_region: coordinate of region to which we are linking - :return: - """ - pass - - def add_region(self, region): + def add_coords(self, coordinates): """ Add a new region into an existing room - :param region: region coordinates to be added to room + :param coordinates: region coordinates to be added to room :return: """ - self.regions.append(region) + self.coordinates.append(coordinates) def connect_rooms(self, other_rooms): """ Find the nearest rooms to this room @@ -47,16 +55,16 @@ class Room: other_tile = [] this_tile = [] target_rooms = [] - for local_region in self.regions: + for coord in self.coordinates: for room in other_rooms: if self == room: continue - for new_region in room.regions: + for new_coord in room.coordinates: distance.append( - math.sqrt((local_region[0] - new_region[0]) ** 2 + - (local_region[1] - new_region[1]) ** 2)) - other_tile.append(new_region) - this_tile.append(local_region) + math.sqrt((coord[0] - new_coord[0]) ** 2 + + (coord[1] - new_coord[1]) ** 2)) + other_tile.append(new_coord) + this_tile.append(coord) target_rooms.append(room) sorted_indices = [i[0] for i in sorted(enumerate(distance), @@ -69,13 +77,69 @@ class Room: target_rooms[index].link_passage( other_tile[index], this_tile[index]) - def link_passage(self, local_tile, foriegn_tile): + def link_passage(self, local_tile, foreign_tile): """ Link a passage between two rooms :param local_tile: tile in this room to which we wish to link - :param foriegn_tile: tile in another room to which we wish to link + :param foreign_tile: tile in another room to which we wish to link :return: """ - self.passages.append([local_tile, foriegn_tile]) + self.passages.append([local_tile, foreign_tile]) + + def render_region(self, coords, room_dist, region_size, tile_map, x, y): + """ Check if a region is in this room and return the required tiles + :param coords: Coordinates of the region that we wish to render + :param room_dist: Tile separation distance from other rooms + :param region_size: Region size in tiles + :param tile_map: Tile map to update + :param x: X coordinate + :param y: Y coordinate + :return: + """ + if coords in self.coordinates: + x_pre_room_dist = room_dist + x_post_room_dist = region_size - room_dist + y_pre_room_dist = room_dist + y_post_room_dist = region_size - room_dist + if [x - 1, y] in self.coordinates: + y_pre_room_dist = 0 + if [x + 1, y] in self.coordinates: + y_post_room_dist = region_size + if [x, y - 1] in self.coordinates: + x_pre_room_dist = 0 + if [x, y + 1] in self.coordinates: + x_post_room_dist = region_size + + for ht in range(y_pre_room_dist, y_post_room_dist): + for wt in range(x_pre_room_dist, x_post_room_dist): + tile_map[(x * region_size) + ht][(y * region_size) + wt] =\ + str(self.region) + for p in self.passages: + print(p) + x_regions = p[0][0] - p[1][0] + y_regions = p[0][1] - p[1][1] + if p[0][0] < p[1][0]: + x_direction = -1 + elif p[0][0] < p[1][0]: + x_direction = 0 + else: + x_direction = 1 + if p[0][1] < p[1][1]: + y_direction = -1 + elif p[0][1] < p[1][1]: + y_direction = 0 + else: + y_direction = 1 + for ht in range(0, region_size, x_direction): + tile_map[(p[0][0] * region_size) + int(region_size / 2)]\ + [(p[0][1] * region_size) + int(region_size / 2) + ht] = 'p' + for wt in range(0, y_regions, y_direction): + tile_map[(p[0][0] * region_size) + int(region_size / 2) + wt]\ + [(p[0][1] * region_size) + int(region_size / 2)] = 'p' + + +def random_cardinal(): + """Return a random cardinal direction for random walks.""" + return random.choice([(0, 1), (0, -1), (1, 0), (-1, 0)]) class LevelGenerator: @@ -84,26 +148,22 @@ class LevelGenerator: no_rooms = 0 rooms = [] map = None - min_room_size = 0 - max_room_size = 0 - dist_from_edge = 0 + map2 = None dist_from_other_rooms = 0 region_map = None regions = 0 region_size = 0 - def __init__(self, width, height, no_rooms, min_room_size, max_room_size, - dist_from_edge, dist_from_other_rooms, region_size): + def __init__(self, width, height, no_rooms, dist_from_other_rooms, + region_size): """ Initialize the level parameters """ self.width = width self.height = height self.no_rooms = no_rooms - self.min_room_size = min_room_size - self.max_room_size = max_room_size - self.dist_from_edge = dist_from_edge self.dist_from_other_rooms = dist_from_other_rooms self.region_size = region_size + self.region_coordinates = [] def generate(self): """ Generate a random level map @@ -113,11 +173,17 @@ class LevelGenerator: min(self.regions, self.no_rooms)) row = ['#' for x in range(self.width * self.region_size)] self.map = [row[:] for x in range(self.height * self.region_size)] - print('Regions: %s' % str(regions_selected)) + self.map2 = [row[:] for x in range(self.height * self.region_size)] for region in regions_selected: self.rooms[region].connect_rooms( [self.rooms[i] for i in regions_selected]) - self.generate_tiles(region) + region_coordinates_selected = [p for p in self.region_coordinates if + p[0] in regions_selected] + for coord in region_coordinates_selected: + self.rooms[coord[0]].render_region( + coord[1], self.dist_from_other_rooms, self.region_size, + self.map2, coord[1][0], coord[1][1]) + # self.generate_underlayer() def generate_rooms(self): """ Generate a random level region map @@ -129,101 +195,123 @@ class LevelGenerator: random_number = random.randint(0, 2) increment_region = False if w == h == 0: - self.region_map[h][w] = self.regions + update_value = self.regions increment_region = True elif h == 0: if random_number > 1: - self.region_map[h][w] = self.region_map[h][w - 1] + update_value = self.region_map[h][w - 1] else: - self.region_map[h][w] = self.regions + update_value = self.regions increment_region = True elif w == 0: if random_number > 1: - self.region_map[h][w] = self.region_map[h - 1][w] + update_value = self.region_map[h - 1][w] else: - self.region_map[h][w] = self.regions + update_value = self.regions increment_region = True else: if random_number > 1: - self.region_map[h][w] = self.region_map[h - 1][w] - + update_value = self.region_map[h - 1][w] elif random_number > 0: - self.region_map[h][w] = self.region_map[h][w - 1] + update_value = self.region_map[h][w - 1] else: - self.region_map[h][w] = self.regions + update_value = self.regions increment_region = True + self.region_map[h][w] = update_value if increment_region: - self.regions += 1 - r = Room([h, w]) + r = Room([h, w], update_value) self.rooms.append(r) + self.region_coordinates.append([update_value, [h, w]]) + self.regions += 1 else: - self.rooms[-1].add_region([h,w]) - - def generate_tiles(self, region_selected): - """ - :param region_selected: - :return: - """ - for h in range(self.height): - for w in range(self.width): - if self.region_map[h][w] == region_selected: - if w == 0: - w_dist = self.dist_from_other_rooms - elif self.region_map[h][w-1] == region_selected: - w_dist = 0 - else: - w_dist = self.dist_from_other_rooms - - if w + 1 == self.width: - e_dist = self.region_size - self.dist_from_other_rooms - elif self.region_map[h][w+1] == region_selected: - e_dist = self.region_size - else: - e_dist = self.region_size - self.dist_from_other_rooms - - if h == 0: - n_dist = self.dist_from_other_rooms - elif self.region_map[h-1][w] == region_selected: - n_dist = 0 - else: - n_dist = self.dist_from_other_rooms - - if h + 1 == self.height: - s_dist = self.region_size - self.dist_from_other_rooms - elif self.region_map[h+1][w] == region_selected: - s_dist = self.region_size - else: - s_dist = self.region_size - self.dist_from_other_rooms - - for wt in range(w_dist, e_dist): - for ht in range(n_dist, s_dist): - self.map[h * self.region_size + ht]\ - [w * self.region_size + wt] = ' ' - - def generate_passage_tiles(self): - """ Generate the tiles that form the passages between the rooms - :return: - """ + for r in self.rooms: + if r.region == update_value: + r.add_coords([h, w]) + self.region_coordinates.append([update_value, [h, w]]) + def generate_underlayer(self): + """Generate a small mess of tunnels to have something.""" + width = len(self.map[0]) + height = len(self.map) + row = ['o' for x in range(width)] + self.underlayer = [row[:] for x in range(height)] + # we create a set of biased random walks to create the tunnel network + for walk in range(random.randint(3, 6)): + x = width // 2 + random.randint(-8, 8) + y = height // 2 + random.randint(-8, 8) + dir_x, dir_y = random_cardinal() + max_steps = random.randint(40, width * height // 4) + for step in range(20, max_steps): + if 0 < x < width - 1: + if 0 < y < height - 1: + self.underlayer[y][x] = '-' + if random.random() > 0.7: + dir_x, dir_y = random_cardinal() + x += dir_x + y += dir_y + def generate_tiles(self, region_selected): + """Generate a small mess of tunnels to have something.""" + width = len(self.map[0]) + height = len(self.map) + row = ['o' for x in range(width)] + self.underlayer = [row[:] for x in range(height)] + # we create a set of biased random walks to create the tunnel network + for walk in range(random.randint(3, 6)): + x = width // 2 + random.randint(-8, 8) + y = height // 2 + random.randint(-8, 8) + dir_x, dir_y = random_cardinal() + max_steps = random.randint(40, width * height // 4) + for step in range(20, max_steps): + if 0 < x < width - 1: + if 0 < y < height - 1: + self.underlayer[y][x] = '-' + if random.random() > 0.7: + dir_x, dir_y = random_cardinal() + x += dir_x + y += dir_y def display(self): file = open('map.txt', 'w') - for l in self.map: + print('-----------------') + for l in self.map2: print(''.join(l)) file.write(''.join(l)) file.write('\n') + print('-----------------') + try: + for l in self.underlayer: + print(''.join(l)) + file.write(''.join(l)) + file.write('\n') + except AttributeError: + pass file.close() for l in self.region_map: + # self._to_json() print(l) + def _to_json(self): + level = {} + level['tileset'] = 'bunker' + level['tiles'] = [] + for l, lu in zip(self.map, self.underlayer): + row = [] + for t1, t2 in zip(l, lu): + tile = ATTRIBUTE_MAP[t1].copy() + tile.update(ATTRIBUTE_MAP[t2]) + row.append(tile) + level['tiles'].append(row) + # FIXME: Do a lot better here + # Crude hack so the level is written into the levels folder + name = os.path.join(os.path.dirname(__file__), '..', 'levels', 'map.json') + f = open(name, 'w') + json.dump(level, f) + f.close() + if __name__ == '__main__': - while True: - level = LevelGenerator(width=4, height=3, no_rooms=4, - min_room_size=5, max_room_size=20, - dist_from_edge=1, dist_from_other_rooms=1, - region_size=5) - level.generate() - level.display() - input("Press Enter to continue...") + level = LevelGenerator(width=4, height=3, no_rooms=4, + dist_from_other_rooms=1, region_size=5) + level.generate() + level.display()