class CA_CaveFactory: def __init__(self, width, height, initial_open=0.60): self.__height = height self.__width = width self.__area = height * width self.__CAmap = [] self.__rooms = [] self.__leveldata = {} self.__ds = DisjointSet() self.__up_loc = 0 self.center_pt = (int(self.__height/2), int(self.__width/2)) self.__gen_initial_map(width, height, initial_open) # Performs the CA operation, then joins separate rooms. Returns the map, consisting of a grid of ints. def gen_map(self): loops = random.randrange(2, 4) while loops > 0: for r in range(1, self.__height-1): for c in range(1, self.__width-1): if not self.__CAmap[c][r].permanent: wall_count = self.__adj_wall_count(r, c) if not self.__CAmap[c][r].blocked: if wall_count > 5: self.__CAmap[c][r].blocked = True self.__CAmap[c][r].block_sight = True elif wall_count < 4: self.__CAmap[c][r].blocked = False self.__CAmap[c][r].block_sight = False loops -= 1 self.__join_rooms() return self.__CAmap def get_rooms(self): return self.__rooms def create_room(self, room, layout): # go through the tiles in the defined rectangle and construct them according to the layout x = room.x1 + 1 y = room.y1 for char in layout: if char == ".": self.__CAmap[x][y].permanent = True self.__CAmap[x][y].blocked = False self.__CAmap[x][y].block_sight = False if char == ",": self.__CAmap[x][y].permanent = False self.__CAmap[x][y].blocked = False self.__CAmap[x][y].block_sight = False if char == "X": self.__CAmap[x][y].permanent = True self.__CAmap[x][y].blocked = True self.__CAmap[x][y].block_sight = True if char == "x": self.__CAmap[x][y].permanent = False self.__CAmap[x][y].blocked = True self.__CAmap[x][y].block_sight = True x += 1 if char == "\n": x = room.x1 + 1 y += 1 def create_room_features(self, room, layout): # Start with an empty set to put level data in leveldata = {} # go through the tiles in the defined rectangle and construct them according to the layout x = room.x1 + 1 y = room.y1 for char in layout: element = None if char == "=": element = "monastery doorway" if char == "b": element = "brazier" if element: leveldata.update({(x,y):element}) x += 1 if char == "\n": x = room.x1 + 1 y += 1 return leveldata def __set_border(self): # make all border squares walls # This could be moved to a superclass for j in range(0,self.__width-1): self.__CAmap[j][0].permanent = True self.__CAmap[j][self.__height-1].permanent = True for j in range(0,self.__height-1): self.__CAmap[0][j].permanent = True self.__CAmap[self.__width-1][j].permanent = True def __gen_initial_map(self,width,height,initial_open): # Create an initial map with random tiles removed, plus rooms and fixtures. self.__CAmap = map_init(height,width) open_count = int(self.__area * initial_open) self.__set_border() for r in range(MAX_ROOMS): # Pick a random selection from our options. roomselection = random.choice(roommaking.templefurniture.keys()) layoutselection = roommaking.templefurniture[roomselection] # Get the width and height w, h = roommaking.measurements(layoutselection) # Find a spot without going off the edge of the map x = random.randrange(0, self.__width - w - 1) y = random.randrange(0, self.__height - h - 1) # Build rooms as Chambers new_room = Chamber(x, y, w, h, 'temple') # Check against other rooms to ensure this new room overlaps none of the others failed = False for other_room in self.__rooms: if new_room.intersect(other_room): failed = True break if not failed: # i.e., no intersections, so paint a room self.create_room(new_room, layoutselection) # Give it some features new_room_features = self.create_room_features(new_room, layoutselection) self.__leveldata.update(new_room_features) print self.__leveldata self.__rooms.append(new_room) (new_x, new_y) = new_room.center() # Previously used for player placement (center of first room) tree = bspmaking.Leaf(20,20,20,10) tree.branch() leaves = tree.gatherleaves() for leaf in leaves: print "Leaf:", leaf.w, leaf.y # Chew out a certain amount of 'noise' for the CA function to work over. while open_count > 0: rand_r = random.randrange(1,self.__height-1) rand_c = random.randrange(1,self.__width-1) if self.__CAmap[rand_c][rand_r].blocked and not self.__CAmap[rand_c][rand_r].permanent: self.__CAmap[rand_c][rand_r].blocked = False self.__CAmap[rand_c][rand_r].block_sight = False open_count -= 1 def __adj_wall_count(self,sr,sc): # How many walls are surrounding a tile? count = 0 for r in (-1,0,1): for c in (-1,0,1): if self.__CAmap[(sc + c)][sr + r].blocked and not(c == 0 and r == 0): count += 1 return count def __join_rooms(self): # divide the square into equivalence classes for r in range(1,self.__height-1): for c in range(1,self.__width-1): if not self.__CAmap[c][r].blocked: self.__union_adj_sqr(c,r) all_caves = self.__ds.split_sets() for cave in all_caves.keys(): self.__join_points(all_caves[cave][0]) def __join_points(self,pt1): next_pt = pt1 while 1: dir = self.__get_tunnel_dir(pt1,self.center_pt) ### This determines the next point to 'drill' to. Unfortunately it will still drill through 'permanent' tiles. How to fix? We could, possibly, use a pathfinding algorithm to get to work our way to the center point. That should work but might be overkill. Let's see how often it happens first while I work on cave building. if (dir[0] == 0) or (dir[1] == 0): next_pt = (pt1[0] + dir[0],pt1[1] + dir[1]) else: if random.randrange(0,1): next_pt = (pt1[0] + dir[0],pt1[1]) else: next_pt = (pt1[0],pt1[1] + dir[1]) if self.__CAmap[next_pt[0]][next_pt[1]].permanent: print "Uh oh, permanent tile at", next_pt[0], next_pt[1] if self.__stop_drawing(pt1,next_pt,self.center_pt): return root1 = self.__ds.find(next_pt) root2 = self.__ds.find(pt1) if root1 != root2: self.__ds.union(root1,root2) self.__CAmap[next_pt[0]][next_pt[1]].blocked = False self.__CAmap[next_pt[0]][next_pt[1]].block_sight = False self.__CAmap[next_pt[0]][next_pt[1]].debug = True # DEBUG pt1 = next_pt def __stop_drawing(self,pt,npt,cpt): if self.__ds.find(npt) == self.__ds.find(cpt): return 1 if self.__ds.find(pt) != self.__ds.find(npt) and not self.__CAmap[npt[0]][npt[1]].blocked: return 1 else: return 0 def __get_tunnel_dir(self,pt1,pt2): if pt1[0] < pt2[0]: h_dir = +1 elif pt1[0] > pt2[0]: h_dir = -1 else: h_dir = 0 if pt1[1] < pt2[1]: v_dir = +1 elif pt1[1] > pt2[1]: v_dir = -1 else: v_dir = 0 return (h_dir,v_dir) def __union_adj_sqr(self,sr,sc): loc = (sr,sc) for r in (-1,0): for c in (-1,0): nloc = (sr+r,sc+c) if not self.__CAmap[nloc[0]][nloc[1]].blocked and (r+c != -2): root1 = self.__ds.find(loc) root2 = self.__ds.find(nloc) if root1 != root2: self.__ds.union(root1,root2)
class CA_CaveFactory: def __init__(self, length, width, initial_open=0.40): self.__length = length self.__width = width self.__area = length * width self.__map = [] self.__ds = DisjointSet() self.__up_loc = 0 self.center_pt = (int(self.__length / 2), int(self.__width / 2)) self.__gen_initial_map(initial_open) def print_grid(self): x = 0 row = "" for r in range(0, self.__length): for c in range(0, self.__width): if self.__map[r][c] in (WALL, PERM_WALL): print '#', else: print '.', print def gen_map(self): for r in range(1, self.__length - 1): for c in range(1, self.__width - 1): wall_count = self.__adj_wall_count(r, c) if self.__map[r][c] == FLOOR: if wall_count > 5: self.__map[r][c] = WALL elif wall_count < 4: self.__map[r][c] = FLOOR self.__join_rooms() return self.__map # make all border squares walls # This could be moved to a superclass def __set_border(self): for j in range(0, self.__length): self.__map[j][0] = PERM_WALL self.__map[j][self.__width - 1] = PERM_WALL for j in range(0, self.__width): self.__map[0][j] = PERM_WALL self.__map[self.__length - 1][j] = PERM_WALL def __gen_initial_map(self, initial_open): for r in range(0, self.__length): row = [] for c in range(0, self.__width): row.append(WALL) self.__map.append(row) open_count = int(self.__area * initial_open) self.__set_border() while open_count > 0: rand_r = randrange(1, self.__length - 1) rand_c = randrange(1, self.__width - 1) if self.__map[rand_r][rand_c] == WALL: self.__map[rand_r][rand_c] = FLOOR open_count -= 1 def __adj_wall_count(self, sr, sc): count = 0 for r in (-1, 0, 1): for c in (-1, 0, 1): if self.__map[(sr + r)][sc + c] != FLOOR and not(r == 0 and c == 0): count += 1 return count def __join_rooms(self): # divide the square into equivalence classes for r in range(1, self.__length - 1): for c in range(1, self.__width - 1): if self.__map[r][c] == FLOOR: self.__union_adj_sqr(r, c) all_caves = self.__ds.split_sets() for cave in all_caves.keys(): self.__join_points(all_caves[cave][0]) def __join_points(self, pt1): next_pt = pt1 while 1: dir = self.__get_tunnel_dir(pt1, self.center_pt) move = randrange(0, 3) if move == 0: next_pt = (pt1[0] + dir[0], pt1[1]) elif move == 1: next_pt = (pt1[0], pt1[1] + dir[1]) else: next_pt = (pt1[0] + dir[0], pt1[1] + dir[1]) if self.__stop_drawing(pt1, next_pt, self.center_pt): return root1 = self.__ds.find(next_pt) root2 = self.__ds.find(pt1) if root1 != root2: self.__ds.union(root1, root2) self.__map[next_pt[0]][next_pt[1]] = FLOOR pt1 = next_pt def __stop_drawing(self, pt, npt, cpt): if self.__ds.find(npt) == self.__ds.find(cpt): return 1 if self.__ds.find(pt) != self.__ds.find(npt) and self.__map[npt[0]][npt[1]] == FLOOR: return 1 else: return 0 def __get_tunnel_dir(self, pt1, pt2): if pt1[0] < pt2[0]: h_dir = +1 elif pt1[0] > pt2[0]: h_dir = -1 else: h_dir = 0 if pt1[1] < pt2[1]: v_dir = +1 elif pt1[1] > pt2[1]: v_dir = -1 else: v_dir = 0 return (h_dir, v_dir) def __union_adj_sqr(self, sr, sc): loc = (sr, sc) for r in (-1, 0): for c in (-1, 0): nloc = (sr + r, sc + c) if self.__map[nloc[0]][nloc[1]] == FLOOR: root1 = self.__ds.find(loc) root2 = self.__ds.find(nloc) if root1 != root2: self.__ds.union(root1, root2)
class CA_CaveFactory: def __init__(self, length, width, initial_open=0.40): self.__length = length self.__width = width self.__area = length * width self.__map = [] self.__ds = DisjointSet() self.__up_loc = 0 self.center_pt = (int(self.__length / 2), int(self.__width / 2)) self.__gen_initial_map(initial_open) def intialize_frmt_ar(self, ar): for r in range(0, self.__length): ar.append([]) def format_grid(self): x = 0 row = "" local_ar = [] self.intialize_frmt_ar(local_ar) for r in range(0, len(local_ar)): for c in range(0, self.__width): if self.__map[r][c] in (WALL, PERM_WALL): local_ar[r].append(1) else: local_ar[r].append(0) return local_ar def gen_map(self): for r in range(1, self.__length - 1): for c in range(1, self.__width - 1): wall_count = self.__adj_wall_count(r, c) if self.__map[r][c] == FLOOR: if wall_count > 5: self.__map[r][c] = WALL elif wall_count < 4: self.__map[r][c] = FLOOR self.__join_rooms() return self.__map # make all border squares walls # This could be moved to a superclass def __set_border(self): for j in range(0, self.__length): self.__map[j][0] = PERM_WALL self.__map[j][self.__width - 1] = PERM_WALL for j in range(0, self.__width): self.__map[0][j] = PERM_WALL self.__map[self.__length - 1][j] = PERM_WALL def __gen_initial_map(self, initial_open): for r in range(0, self.__length): row = [] for c in range(0, self.__width): row.append(WALL) self.__map.append(row) open_count = int(self.__area * initial_open) self.__set_border() while open_count > 0: rand_r = randrange(1, self.__length - 1) rand_c = randrange(1, self.__width - 1) if self.__map[rand_r][rand_c] == WALL: self.__map[rand_r][rand_c] = FLOOR open_count -= 1 def __adj_wall_count(self, sr, sc): count = 0 for r in (-1, 0, 1): for c in (-1, 0, 1): if self.__map[(sr + r)][sc + c] != FLOOR and not (r == 0 and c == 0): count += 1 return count def __join_rooms(self): # divide the square into equivalence classes for r in range(1, self.__length - 1): for c in range(1, self.__width - 1): if self.__map[r][c] == FLOOR: self.__union_adj_sqr(r, c) all_caves = self.__ds.split_sets() for cave in all_caves.keys(): self.__join_points(all_caves[cave][0]) def __join_points(self, pt1): next_pt = pt1 while 1: dir = self.__get_tunnel_dir(pt1, self.center_pt) move = randrange(0, 3) if move == 0: next_pt = (pt1[0] + dir[0], pt1[1]) elif move == 1: next_pt = (pt1[0], pt1[1] + dir[1]) else: next_pt = (pt1[0] + dir[0], pt1[1] + dir[1]) if self.__stop_drawing(pt1, next_pt, self.center_pt): return root1 = self.__ds.find(next_pt) root2 = self.__ds.find(pt1) if root1 != root2: self.__ds.union(root1, root2) self.__map[next_pt[0]][next_pt[1]] = FLOOR pt1 = next_pt def __stop_drawing(self, pt, npt, cpt): if self.__ds.find(npt) == self.__ds.find(cpt): return 1 if self.__ds.find(pt) != self.__ds.find(npt) and self.__map[npt[0]][ npt[1]] == FLOOR: return 1 else: return 0 def __get_tunnel_dir(self, pt1, pt2): if pt1[0] < pt2[0]: h_dir = +1 elif pt1[0] > pt2[0]: h_dir = -1 else: h_dir = 0 if pt1[1] < pt2[1]: v_dir = +1 elif pt1[1] > pt2[1]: v_dir = -1 else: v_dir = 0 return (h_dir, v_dir) def __union_adj_sqr(self, sr, sc): loc = (sr, sc) for r in (-1, 0): for c in (-1, 0): nloc = (sr + r, sc + c) if self.__map[nloc[0]][nloc[1]] == FLOOR: root1 = self.__ds.find(loc) root2 = self.__ds.find(nloc) if root1 != root2: self.__ds.union(root1, root2)
class CA_CaveFactory: def __init__(self, width, height, initial_open=0.60): self.__height = height self.__width = width self.__area = height * width self.__CAmap = [] self.__rooms = [] self.__leveldata = {} self.__ds = DisjointSet() self.__up_loc = 0 self.center_pt = (int(self.__height / 2), int(self.__width / 2)) self.__gen_initial_map(width, height, initial_open) # Performs the CA operation, then joins separate rooms. Returns the map, consisting of a grid of ints. def gen_map(self): loops = random.randrange(2, 4) while loops > 0: for r in range(1, self.__height - 1): for c in range(1, self.__width - 1): if not self.__CAmap[c][r].permanent: wall_count = self.__adj_wall_count(r, c) if not self.__CAmap[c][r].blocked: if wall_count > 5: self.__CAmap[c][r].blocked = True self.__CAmap[c][r].block_sight = True elif wall_count < 4: self.__CAmap[c][r].blocked = False self.__CAmap[c][r].block_sight = False loops -= 1 self.__join_rooms() return self.__CAmap def get_rooms(self): return self.__rooms def create_room(self, room, layout): # go through the tiles in the defined rectangle and construct them according to the layout x = room.x1 + 1 y = room.y1 for char in layout: if char == ".": self.__CAmap[x][y].permanent = True self.__CAmap[x][y].blocked = False self.__CAmap[x][y].block_sight = False if char == ",": self.__CAmap[x][y].permanent = False self.__CAmap[x][y].blocked = False self.__CAmap[x][y].block_sight = False if char == "X": self.__CAmap[x][y].permanent = True self.__CAmap[x][y].blocked = True self.__CAmap[x][y].block_sight = True if char == "x": self.__CAmap[x][y].permanent = False self.__CAmap[x][y].blocked = True self.__CAmap[x][y].block_sight = True x += 1 if char == "\n": x = room.x1 + 1 y += 1 def create_room_features(self, room, layout): # Start with an empty set to put level data in leveldata = {} # go through the tiles in the defined rectangle and construct them according to the layout x = room.x1 + 1 y = room.y1 for char in layout: element = None if char == "=": element = "monastery doorway" if char == "b": element = "brazier" if element: leveldata.update({(x, y): element}) x += 1 if char == "\n": x = room.x1 + 1 y += 1 return leveldata def __set_border(self): # make all border squares walls # This could be moved to a superclass for j in range(0, self.__width - 1): self.__CAmap[j][0].permanent = True self.__CAmap[j][self.__height - 1].permanent = True for j in range(0, self.__height - 1): self.__CAmap[0][j].permanent = True self.__CAmap[self.__width - 1][j].permanent = True def __gen_initial_map(self, width, height, initial_open): # Create an initial map with random tiles removed, plus rooms and fixtures. self.__CAmap = map_init(height, width) open_count = int(self.__area * initial_open) self.__set_border() for r in range(MAX_ROOMS): # Pick a random selection from our options. roomselection = random.choice(roommaking.templefurniture.keys()) layoutselection = roommaking.templefurniture[roomselection] # Get the width and height w, h = roommaking.measurements(layoutselection) # Find a spot without going off the edge of the map x = random.randrange(0, self.__width - w - 1) y = random.randrange(0, self.__height - h - 1) # Build rooms as Chambers new_room = Chamber(x, y, w, h, 'temple') # Check against other rooms to ensure this new room overlaps none of the others failed = False for other_room in self.__rooms: if new_room.intersect(other_room): failed = True break if not failed: # i.e., no intersections, so paint a room self.create_room(new_room, layoutselection) # Give it some features new_room_features = self.create_room_features( new_room, layoutselection) self.__leveldata.update(new_room_features) print self.__leveldata self.__rooms.append(new_room) (new_x, new_y) = new_room.center( ) # Previously used for player placement (center of first room) tree = bspmaking.Leaf(20, 20, 20, 10) tree.branch() leaves = tree.gatherleaves() for leaf in leaves: print "Leaf:", leaf.w, leaf.y # Chew out a certain amount of 'noise' for the CA function to work over. while open_count > 0: rand_r = random.randrange(1, self.__height - 1) rand_c = random.randrange(1, self.__width - 1) if self.__CAmap[rand_c][rand_r].blocked and not self.__CAmap[ rand_c][rand_r].permanent: self.__CAmap[rand_c][rand_r].blocked = False self.__CAmap[rand_c][rand_r].block_sight = False open_count -= 1 def __adj_wall_count(self, sr, sc): # How many walls are surrounding a tile? count = 0 for r in (-1, 0, 1): for c in (-1, 0, 1): if self.__CAmap[(sc + c)][sr + r].blocked and not (c == 0 and r == 0): count += 1 return count def __join_rooms(self): # divide the square into equivalence classes for r in range(1, self.__height - 1): for c in range(1, self.__width - 1): if not self.__CAmap[c][r].blocked: self.__union_adj_sqr(c, r) all_caves = self.__ds.split_sets() for cave in all_caves.keys(): self.__join_points(all_caves[cave][0]) def __join_points(self, pt1): next_pt = pt1 while 1: dir = self.__get_tunnel_dir( pt1, self.center_pt ) ### This determines the next point to 'drill' to. Unfortunately it will still drill through 'permanent' tiles. How to fix? We could, possibly, use a pathfinding algorithm to get to work our way to the center point. That should work but might be overkill. Let's see how often it happens first while I work on cave building. if (dir[0] == 0) or (dir[1] == 0): next_pt = (pt1[0] + dir[0], pt1[1] + dir[1]) else: if random.randrange(0, 1): next_pt = (pt1[0] + dir[0], pt1[1]) else: next_pt = (pt1[0], pt1[1] + dir[1]) if self.__CAmap[next_pt[0]][next_pt[1]].permanent: print "Uh oh, permanent tile at", next_pt[0], next_pt[1] if self.__stop_drawing(pt1, next_pt, self.center_pt): return root1 = self.__ds.find(next_pt) root2 = self.__ds.find(pt1) if root1 != root2: self.__ds.union(root1, root2) self.__CAmap[next_pt[0]][next_pt[1]].blocked = False self.__CAmap[next_pt[0]][next_pt[1]].block_sight = False self.__CAmap[next_pt[0]][next_pt[1]].debug = True # DEBUG pt1 = next_pt def __stop_drawing(self, pt, npt, cpt): if self.__ds.find(npt) == self.__ds.find(cpt): return 1 if self.__ds.find(pt) != self.__ds.find(npt) and not self.__CAmap[ npt[0]][npt[1]].blocked: return 1 else: return 0 def __get_tunnel_dir(self, pt1, pt2): if pt1[0] < pt2[0]: h_dir = +1 elif pt1[0] > pt2[0]: h_dir = -1 else: h_dir = 0 if pt1[1] < pt2[1]: v_dir = +1 elif pt1[1] > pt2[1]: v_dir = -1 else: v_dir = 0 return (h_dir, v_dir) def __union_adj_sqr(self, sr, sc): loc = (sr, sc) for r in (-1, 0): for c in (-1, 0): nloc = (sr + r, sc + c) if not self.__CAmap[nloc[0]][nloc[1]].blocked and (r + c != -2): root1 = self.__ds.find(loc) root2 = self.__ds.find(nloc) if root1 != root2: self.__ds.union(root1, root2)
class FullMap: # A map using CA to build caves but also pre-set rooms. def __init__(self, width, height, levelnum, initial_open=0.60): self.__height = height self.__width = width self.__area = height * width self.__map = [] self.__levelnum = levelnum self.__rooms = [] self.__ds = DisjointSet() self.__up_loc = 0 self.center_pt = (int(self.__height / 2), int(self.__width / 2)) self.objects = [] self.eventdict = {} self.gen_map(initial_open) def gen_map(self, initial_open): # Create an initial map self.__map = map_init(self.__height, self.__width) # make all border squares walls for j in range(0, self.__width - 1): self.__map[j][0].permanent = True self.__map[j][self.__height - 1].permanent = True for j in range(0, self.__height - 1): self.__map[0][j].permanent = True self.__map[self.__width - 1][j].permanent = True # Chew out randomized spots on the map self.randomize(initial_open) # Make a list of level features to make levellist = levelmaking.choose_levelset(self.__levelnum) # Init a counter for events currentevent = 1 # For each item, get the features to make a Chamber out of. Make a chamber and dig a proper room out of it. for item in levellist: # Select an item from the possible ones, given the type. itemselection = levelmaking.select_elements(item) # Want to look until a placement is found. placed = False while not placed: # Given this item, what arguments do we need to actually make the room? args = levelmaking.set_element_values(item, itemselection, self.__width, self.__height) new_room = Chamber(*args) # Check against other rooms to ensure this new room overlaps none of the others # This needs to go somewhere else! intersected = False for other_room in self.__rooms: if new_room.intersect(other_room): intersected = True print "Failed intersection test!" break # In cases of intersection, note the failure, and try again (another loop). Otherwise, perform the # dig-a-room operations and make a note to finish the loop. if intersected: print "Failed making", new_room.style else: # i.e., no intersections, so paint a room levelmaking.dig_room(self.__map, new_room, itemselection) roomobjects = levelmaking.collect_features( self.__map, new_room, itemselection) self.objects += roomobjects print "Successfully dug", new_room.style self.__rooms.append(new_room) placed = True (new_x, new_y) = new_room.center( ) # Previously used for player placement (center of first room) # Perform CA operation - how many loops to perform? loops = random.randrange(4, 5) self.ca_operation(loops) # Check for other room-making operations # Join the areas of the level self.__join_rooms() def finalize_map(self): return self.__map def finalize_obects(self): return self.objects def get_rooms(self): return self.__rooms def is_map_blocked(self, x, y): if self.__map[x][y].is_blocked: return True else: return False def randomize(self, initial_open): open_count = int(self.__width * self.__height * initial_open) while open_count > 0: rand_r = random.randrange(1, self.__height - 1) rand_c = random.randrange(1, self.__width - 1) if self.__map[rand_c][rand_r].blocked and not self.__map[rand_c][ rand_r].permanent: self.__map[rand_c][rand_r].blocked = False self.__map[rand_c][rand_r].block_sight = False open_count -= 1 def check_open(self): count = 0 for x in range(1, self.__width): for y in range(1, self.__height): if self.__map[x][y].blocked: count += 1 print 'open tiles: ', count def ca_operation(self, loops): # For non-permanent tiles, grow or kill depending on their surroundings. while loops > 0: for r in range(1, self.__height - 1): for c in range(1, self.__width - 1): if not self.__map[c][r].permanent: wall_count = self.__adj_wall_count(r, c) if not self.__map[c][r].blocked: if wall_count > 5: self.__map[c][r].blocked = True self.__map[c][r].block_sight = True elif wall_count < 4: self.__map[c][r].blocked = False self.__map[c][r].block_sight = False loops -= 1 def __adj_wall_count(self, sr, sc): # How many walls are surrounding a tile? count = 0 for r in (-1, 0, 1): for c in (-1, 0, 1): if self.__map[(sc + c)][sr + r].blocked and not (c == 0 and r == 0): count += 1 return count def __join_rooms(self): all_caves = self.__determine_areas() # Build a tunneling map for pathing - use the permanent state check to determine passability. tunnelingmap = libtcod.map_new(self.__width, self.__height) for x in range(1, self.__width - 1): for y in range(1, self.__height - 1): perm_wall = (self.__map[x][y].permanent and self.__map[x][y].blocked) libtcod.map_set_properties(tunnelingmap, x, y, True, not perm_wall) # The tunneling path will let us move from the origin to the center. tunnelingpath = libtcod.dijkstra_new(tunnelingmap, 0.0) # The center needs to be non-permanent, otherwise we can't path to it. center_x, center_y = self.__find_good_center(self.center_pt) for cave in all_caves.keys(): # This comment used to run the joining. The function is still usable! #self.__join_points(all_caves[cave][0]) origin_x = all_caves[cave][0][0] origin_y = all_caves[cave][0][1] libtcod.dijkstra_compute(tunnelingpath, origin_x, origin_y) if not libtcod.dijkstra_path_set(tunnelingpath, center_x, center_y): print "Could not path! Center point permanent:", self.__map[ center_x][center_y].permanent prev_pt = (origin_x, origin_y) while not libtcod.dijkstra_is_empty(tunnelingpath): x, y = libtcod.dijkstra_path_walk(tunnelingpath) next_pt = (x, y) if x is not None: root1 = self.__ds.find(next_pt) root2 = self.__ds.find(prev_pt) if root1 != root2: self.__ds.union(root1, root2) self.__map[next_pt[0]][next_pt[1]].blocked = False self.__map[next_pt[0]][next_pt[1]].block_sight = False self.__map[next_pt[0]][next_pt[1]].debug = True # DEBUG if self.__stop_drawing(prev_pt, next_pt, self.center_pt): print "Done cave", cave break prev_pt = next_pt all_caves = self.__determine_areas() if len(all_caves.keys()) > 1: self.__join_rooms() def __determine_areas(self): # divide the square into equivalence classes for r in range(1, self.__height - 1): for c in range(1, self.__width - 1): if not self.__map[c][r].blocked: self.__union_adj_sqr(c, r) # Get a list of areas to work on, then remove small caves before returning areas = self.__ds.split_sets() zones = areas.keys() for zone in zones: if len(areas[zone]) < 9: for location in areas[zone]: x = location[0] y = location[1] self.__map[x][y].permanent = False self.__map[x][y].blocked = True self.__map[x][y].block_sight = True areas.pop(zone) print "Number of areas is", len(areas) return areas def __find_good_center(self, pt): # This function randomly moves the center to find a good 'end' point for cave joining function. # That is, the center can't be permanent. x = pt[0] y = pt[1] while self.__map[x][y].permanent: x += random.randrange(-1, 1) y += random.randrange(-1, 1) pt = (x, y) return pt def __stop_drawing(self, pt, npt, cpt): if self.__ds.find(npt) == self.__ds.find(cpt): return 1 if self.__ds.find(pt) != self.__ds.find(npt) and not self.__map[ npt[0]][npt[1]].blocked: return 1 else: return 0 def __get_tunnel_dir(self, pt1, pt2): if pt1[0] < pt2[0]: h_dir = +1 elif pt1[0] > pt2[0]: h_dir = -1 else: h_dir = 0 if pt1[1] < pt2[1]: v_dir = +1 elif pt1[1] > pt2[1]: v_dir = -1 else: v_dir = 0 return h_dir, v_dir def __union_adj_sqr(self, sr, sc): loc = (sr, sc) for r in (-1, 0): for c in (-1, 0): nloc = (sr + r, sc + c) if not self.__map[nloc[0]][nloc[1]].blocked and (r + c != -2): root1 = self.__ds.find(loc) root2 = self.__ds.find(nloc) if root1 != root2: self.__ds.union(root1, root2)
class FullMap: # A map using CA to build caves but also pre-set rooms. def __init__(self, width, height, levelnum, initial_open=0.60): self.__height = height self.__width = width self.__area = height * width self.__map = [] self.__levelnum = levelnum self.__rooms = [] self.__ds = DisjointSet() self.__up_loc = 0 self.center_pt = (int(self.__height/2), int(self.__width/2)) self.objects = [] self.eventdict = {} self.gen_map(initial_open) def gen_map(self, initial_open): # Create an initial map self.__map = map_init(self.__height, self.__width) # make all border squares walls for j in range(0, self.__width-1): self.__map[j][0].permanent = True self.__map[j][self.__height-1].permanent = True for j in range(0, self.__height-1): self.__map[0][j].permanent = True self.__map[self.__width-1][j].permanent = True # Chew out randomized spots on the map self.randomize(initial_open) # Make a list of level features to make levellist = levelmaking.choose_levelset(self.__levelnum) # Init a counter for events currentevent = 1 # For each item, get the features to make a Chamber out of. Make a chamber and dig a proper room out of it. for item in levellist: # Select an item from the possible ones, given the type. itemselection = levelmaking.select_elements(item) # Want to look until a placement is found. placed = False while not placed: # Given this item, what arguments do we need to actually make the room? args = levelmaking.set_element_values(item, itemselection, self.__width, self.__height) new_room = Chamber(*args) # Check against other rooms to ensure this new room overlaps none of the others # This needs to go somewhere else! intersected = False for other_room in self.__rooms: if new_room.intersect(other_room): intersected = True print "Failed intersection test!" break # In cases of intersection, note the failure, and try again (another loop). Otherwise, perform the # dig-a-room operations and make a note to finish the loop. if intersected: print "Failed making", new_room.style else: # i.e., no intersections, so paint a room levelmaking.dig_room(self.__map, new_room, itemselection) roomobjects = levelmaking.collect_features(self.__map, new_room, itemselection) self.objects += roomobjects print "Successfully dug", new_room.style self.__rooms.append(new_room) placed = True (new_x, new_y) = new_room.center() # Previously used for player placement (center of first room) # Perform CA operation - how many loops to perform? loops = random.randrange(4, 5) self.ca_operation(loops) # Check for other room-making operations # Join the areas of the level self.__join_rooms() def finalize_map(self): return self.__map def finalize_obects(self): return self.objects def get_rooms(self): return self.__rooms def is_map_blocked(self, x, y): if self.__map[x][y].is_blocked: return True else: return False def randomize(self, initial_open): open_count = int(self.__width * self.__height * initial_open) while open_count > 0: rand_r = random.randrange(1, self.__height-1) rand_c = random.randrange(1, self.__width-1) if self.__map[rand_c][rand_r].blocked and not self.__map[rand_c][rand_r].permanent: self.__map[rand_c][rand_r].blocked = False self.__map[rand_c][rand_r].block_sight = False open_count -= 1 def check_open(self): count = 0 for x in range(1, self.__width): for y in range(1, self.__height): if self.__map[x][y].blocked: count += 1 print 'open tiles: ', count def ca_operation(self, loops): # For non-permanent tiles, grow or kill depending on their surroundings. while loops > 0: for r in range(1, self.__height-1): for c in range(1, self.__width-1): if not self.__map[c][r].permanent: wall_count = self.__adj_wall_count(r, c) if not self.__map[c][r].blocked: if wall_count > 5: self.__map[c][r].blocked = True self.__map[c][r].block_sight = True elif wall_count < 4: self.__map[c][r].blocked = False self.__map[c][r].block_sight = False loops -= 1 def __adj_wall_count(self, sr, sc): # How many walls are surrounding a tile? count = 0 for r in (-1, 0, 1): for c in (-1, 0, 1): if self.__map[(sc + c)][sr + r].blocked and not(c == 0 and r == 0): count += 1 return count def __join_rooms(self): all_caves = self.__determine_areas() # Build a tunneling map for pathing - use the permanent state check to determine passability. tunnelingmap = libtcod.map_new(self.__width, self.__height) for x in range(1, self.__width-1): for y in range(1, self.__height-1): perm_wall = (self.__map[x][y].permanent and self.__map[x][y].blocked) libtcod.map_set_properties(tunnelingmap, x, y, True, not perm_wall) # The tunneling path will let us move from the origin to the center. tunnelingpath = libtcod.dijkstra_new(tunnelingmap, 0.0) # The center needs to be non-permanent, otherwise we can't path to it. center_x, center_y = self.__find_good_center(self.center_pt) for cave in all_caves.keys(): # This comment used to run the joining. The function is still usable! #self.__join_points(all_caves[cave][0]) origin_x = all_caves[cave][0][0] origin_y = all_caves[cave][0][1] libtcod.dijkstra_compute(tunnelingpath, origin_x, origin_y) if not libtcod.dijkstra_path_set(tunnelingpath, center_x, center_y): print "Could not path! Center point permanent:", self.__map[center_x][center_y].permanent prev_pt = (origin_x, origin_y) while not libtcod.dijkstra_is_empty(tunnelingpath): x, y = libtcod.dijkstra_path_walk(tunnelingpath) next_pt = (x, y) if x is not None: root1 = self.__ds.find(next_pt) root2 = self.__ds.find(prev_pt) if root1 != root2: self.__ds.union(root1, root2) self.__map[next_pt[0]][next_pt[1]].blocked = False self.__map[next_pt[0]][next_pt[1]].block_sight = False self.__map[next_pt[0]][next_pt[1]].debug = True # DEBUG if self.__stop_drawing(prev_pt, next_pt, self.center_pt): print "Done cave", cave break prev_pt = next_pt all_caves = self.__determine_areas() if len(all_caves.keys())>1: self.__join_rooms() def __determine_areas(self): # divide the square into equivalence classes for r in range(1, self.__height-1): for c in range(1, self.__width-1): if not self.__map[c][r].blocked: self.__union_adj_sqr(c, r) # Get a list of areas to work on, then remove small caves before returning areas = self.__ds.split_sets() zones = areas.keys() for zone in zones: if len(areas[zone])<9: for location in areas[zone]: x = location[0] y = location[1] self.__map[x][y].permanent = False self.__map[x][y].blocked = True self.__map[x][y].block_sight = True areas.pop(zone) print "Number of areas is", len(areas) return areas def __find_good_center(self, pt): # This function randomly moves the center to find a good 'end' point for cave joining function. # That is, the center can't be permanent. x = pt[0] y = pt[1] while self.__map[x][y].permanent: x += random.randrange(-1, 1) y += random.randrange(-1, 1) pt = (x, y) return pt def __stop_drawing(self, pt, npt, cpt): if self.__ds.find(npt) == self.__ds.find(cpt): return 1 if self.__ds.find(pt) != self.__ds.find(npt) and not self.__map[npt[0]][npt[1]].blocked: return 1 else: return 0 def __get_tunnel_dir(self, pt1, pt2): if pt1[0] < pt2[0]: h_dir = +1 elif pt1[0] > pt2[0]: h_dir = -1 else: h_dir = 0 if pt1[1] < pt2[1]: v_dir = +1 elif pt1[1] > pt2[1]: v_dir = -1 else: v_dir = 0 return h_dir, v_dir def __union_adj_sqr(self, sr, sc): loc = (sr, sc) for r in (-1, 0): for c in (-1, 0): nloc = (sr+r, sc+c) if not self.__map[nloc[0]][nloc[1]].blocked and (r+c != -2): root1 = self.__ds.find(loc) root2 = self.__ds.find(nloc) if root1 != root2: self.__ds.union(root1, root2)