def generate(self): self.map_canvas.clear(Floor) # So what I want here is to have a cave system with a room in the # middle, then decay the room. # Some constraints: # - the room must have a wall where the entrance could go, which faces # empty space # - a wall near the entrance must be destroyed # - the player must start in a part of the cave connected to the # destroyed entrance # - none of the decay applied to the room may block off any of its # interesting features # TODO it would be nice if i could really write all this without ever # having to hardcode a specific direction, so the logic could always be # rotated freely side = random.choice([Direction.left, Direction.right]) # TODO assert region is big enough room_size = Size( random_normal_range(9, int(self.region.width * 0.4)), random_normal_range(9, int(self.region.height * 0.4)), ) room_position = self.region.center() - room_size // 2 room_position += Point( random_normal_int(0, self.region.width * 0.1), random_normal_int(0, self.region.height * 0.1), ) room_rect = Rectangle(room_position, room_size) self.room_region = room_rect room = Room(room_rect) cave_area = ( Blob.from_rectangle(self.region) - Blob.from_rectangle(room_rect) ) self.cave_region = cave_area walls = [point for (point, _) in self.region.iter_border()] floors = [] for point, edge in room_rect.iter_border(): if edge is side or edge.adjacent_to(side): floors.append(point) floors.append(point + side) generate_caves( self.map_canvas, cave_area, CaveWall, force_walls=walls, force_floors=floors, ) room.draw_to_canvas(self.map_canvas) # OK, now draw a gate in the middle of the side wall if side is Direction.left: x = room_rect.left else: x = room_rect.right mid_y = room_rect.top + room_rect.height // 2 if room_rect.height % 2 == 1: min_y = mid_y - 1 max_y = mid_y + 1 else: min_y = mid_y - 2 max_y = mid_y + 1 for y in range(min_y, max_y + 1): self.map_canvas.set_architecture(Point(x, y), KadathGate) # Beat up the border of the room near the gate y = random.choice( tuple(range(room_rect.top, min_y)) + tuple(range(max_y + 1, room_rect.bottom)) ) for dx in range(-2, 3): for dy in range(-2, 3): point = Point(x + dx, y + dy) # TODO i think what i may want is to have the cave be a # "Feature", where i can check whether it has already claimed a # tile, or draw it later, or whatever. if self.map_canvas._arch_grid[point] is not CaveWall: distance = abs(dx) + abs(dy) ruination = random_normal_range(0, 0.2) + distance * 0.2 self.map_canvas.set_architecture( point, e.Rubble(Breakable(ruination))) # And apply some light ruination to the inside of the room border = list(room_rect.iter_border()) # TODO don't do this infinitely; give up after x tries while True: point, edge = random.choice(border) if self.map_canvas._arch_grid[point + edge] is CaveWall: break self.map_canvas.set_architecture(point, CaveWall) self.map_canvas.set_architecture(point - edge, CaveWall) # TODO this would be neater if it were a slightly more random pattern for direction in ( Direction.up, Direction.down, Direction.left, Direction.right): self.map_canvas.set_architecture( point - edge + direction, CaveWall)