def generate(width: int, height: int) -> GameMap: ROOMS = {'min_size': 7, 'max_size': 10, 'max': 30} gm = GameMap(width, height) gm.tiles[...] = WALL rooms: List[Room] = [] for _ in range(ROOMS['max']): w = randint(ROOMS['min_size'], ROOMS['max_size']) h = randint(ROOMS['min_size'], ROOMS['max_size']) x = randint(0, width - w - 1) y = randint(0, height - h - 1) new_room = Room(x, y, w, h) if any(new_room.intersects(other) for other in rooms): continue gm.tiles[new_room.inner] = FLOOR if rooms: other_room = rooms[-1] t_start = new_room.center t_end = other_room.center t_middle = t_start[0], t_end[1] gm.tiles[tcod.line_where(*t_start, *t_middle)] = FLOOR gm.tiles[tcod.line_where(*t_middle, *t_end)] = FLOOR rooms.append(new_room) for room in rooms: room.place_entities(gm) gm.player = spawn_entity(entities_db.player(), gm[rooms[0].center]) gm.entities.append(gm.player) gm.update_fov() return gm
def generate(width: int, height: int) -> gamemap.GameMap: """Return a randomly generated GameMap.""" room_max_size = 10 room_min_size = 6 max_rooms = 30 AREA_BORDER = 20 gm = gamemap.GameMap(width, height) gm.tiles[...] = FLOOR rooms: List[Room] = [] for i in range(max_rooms): # random width and height w = random.randint(room_min_size, room_max_size) h = random.randint(room_min_size, room_max_size) # random position without going out of the boundaries of the map x = random.randint(AREA_BORDER, width - AREA_BORDER - w) y = random.randint(AREA_BORDER, height - AREA_BORDER - h) new_room = Room(x, y, w, h) if any(new_room.intersects(other) for other in rooms): continue # This room intersects with a previous room. # Mark room inner area as open. gm.tiles[new_room.outer] = WALL gm.tiles[new_room.inner] = FLOOR if rooms: # Open a tunnel between rooms. if random.randint(0, 99) < 80: # 80% of tunnels are to the nearest room. other_room = min(rooms, key=new_room.distance_to) else: # 20% of tunnels are to the previous generated room. other_room = rooms[-1] t_start = new_room.center t_end = other_room.center if random.randint(0, 1): t_middle = t_start[0], t_end[1] else: t_middle = t_end[0], t_start[1] gm.tiles[tcod.line_where(*t_start, *t_middle)] = FLOOR gm.tiles[tcod.line_where(*t_middle, *t_end)] = FLOOR rooms.append(new_room) # Add player to the first room. gm.player = fighter.Player.spawn(gm[5, height - 5], ai_cls=ai.PlayerControl) gm.actors.append(gm.player) for room in rooms: room.place_entities(gm) gm.update_fov() return gm
def build_meta_map(self, build_data): if not build_data.rooms: print( f'Room based spawning only work after rooms have been created.' ) raise ProcessLookupError else: rooms = deepcopy(build_data.rooms) connected = dict() corridors = list() for i, room in enumerate(rooms): room_distance = list() room_x, room_y = room.center() for j, other_room in enumerate(rooms): if i != j and not connected.get(j): other_x, other_y = other_room.center() distance = distance_to(room_x, room_y, other_x, other_y) room_distance.append((j, distance)) if room_distance: room_distance = sorted( room_distance, key=lambda room_to_sort: room_to_sort[1]) dest_center_x, dest_center_y = rooms[room_distance[0] [0]].center() lines = tcod.line_where(room_x, room_y, dest_center_x, dest_center_y) cell_x = lines[0] cell_y = lines[1] last_x = cell_x[0] last_y = cell_y[0] corridor = list() for cell in range(0, len(cell_y) - 1): if last_x != cell_x[cell] and last_y != cell_y[cell]: if randint(1, 2) == 1: idx = build_data.map.xy_idx( cell_x[cell], last_y) build_data.map.tiles[idx] = TileType.FLOOR else: idx = build_data.map.xy_idx( last_x, cell_y[cell]) build_data.map.tiles[idx] = TileType.FLOOR idx = int( build_data.map.xy_idx(cell_x[cell], cell_y[cell])) build_data.map.tiles[idx] = TileType.FLOOR last_x = cell_x[cell] last_y = cell_y[cell] corridor.append(idx) corridors.append(corridor) connected[i] = True build_data.take_snapshot() build_data.corridors = corridors
def draw(self, pad): line = np.array( tcod.line_where(round(self.pos[0]), round(self.pos[1]), round(self.pos[0] + self.speed[0]), round(self.pos[1] + self.speed[1]))).T[:-1].T line = line.T[line[0] < HEIGHT * 2].T line = line.T[line[1] < WIDTH * 2].T line = line.T[line[0] >= 0].T line = line.T[line[1] >= 0].T if not line.size: return vis = 255 pad[tuple(line)] |= np.linspace(vis // 2, vis, line.shape[1], dtype=np.uint8)[:, np.newaxis]
def render(self, console): if not self.render_next: return self.target_tiles = [] if self.mode == MapMode.TARGETING: if self.target_mode == AbilityTargeting.LOS: line = line_where(self.player.entity.x, self.player.entity.y, self.target_x, self.target_y, False) for _ in range(len(line[0])): self.target_tiles.append( self.game_map.field[line[0][_]][line[1][_]]) dx = -(self.player.entity.x - int(field_console_width / 2)) dy = -(self.player.entity.y - int(field_console_height / 2)) if self.fov_recompute: recompute_fov(self.game_map.fov_map, self.player.entity.x, self.player.entity.y, 10) for x in range(self.game_map.width): for y in range(self.game_map.height): if x < self.player.entity.x - int(field_console_width / 2) \ or x > self.player.entity.x + int(field_console_width / 2) \ or y < self.player.entity.y - int(field_console_height / 2) \ or y > self.player.entity.y + int(field_console_height / 2): continue visible = tcod.map_is_in_fov(self.game_map.fov_map, x, y) if visible: tcod.console_set_char_background( self.field_console, x + dx, y + dy, self.game_map.field[x][y].background_color, tcod.BKGND_SET) if self.mode == MapMode.TARGETING: if abs(x - self.player.entity.x) > self.target_distance \ or abs(y - self.player.entity.y) > self.target_distance: tcod.console_set_char_background( self.field_console, x + dx, y + dy, (60, 60, 60), tcod.BKGND_DARKEN) if self.game_map.field[x][y] in self.target_tiles: tcod.console_set_char_background( self.field_console, x + dx, y + dy, (60, 40, 40), tcod.BKGND_ADD) if x == self.target_x and y == self.target_y: tcod.console_set_char_background( self.field_console, x + dx, y + dy, (60, 40, 20), tcod.BKGND_ADD) self.game_map.field[x][y].explored = True elif self.game_map.field[x][y].explored: tcod.console_set_char_background( self.field_console, x + dx, y + dy, self.game_map.field[x][y].background_color_dark, tcod.BKGND_SET) else: tcod.console_set_char_background( self.field_console, x + dx, y + dy, tcod.black, tcod.BKGND_SET) if (visible or self.game_map.field[x][y].explored ) and self.game_map.field[x][y].stairs: tcod.console_put_char(self.field_console, x + dx, y + dy, '>', tcod.BKGND_NONE) for x in range(field_console_width): for y in range(field_console_height): if x < (int(field_console_width / 2) - self.player.entity.x) \ or x > (self.game_map.width - 1 - self.player.entity.x + int(field_console_width / 2)) \ or y < (int(field_console_height / 2) - self.player.entity.y) \ or y > (self.game_map.height - 1 - self.player.entity.y + int(field_console_height / 2)): tcod.console_set_char_background(self.field_console, x, y, tcod.black, tcod.BKGND_SET) for entity in self.game_map.entities: if entity.x < self.player.entity.x - int(field_console_width / 2) \ or entity.x > self.player.entity.x + int(field_console_width / 2) \ or entity.y < self.player.entity.y - int(field_console_height / 2) \ or entity.y > self.player.entity.y + int(field_console_height / 2): continue if not tcod.map_is_in_fov(self.game_map.fov_map, entity.x, entity.y): continue # Don't render an item entity if there's already one on this tile if isinstance(entity, ItemEntity) and self.game_map.get_monster_at( entity.x, entity.y) is not None: continue # Don't render a dead entity if there's already one on this tile if isinstance(entity, MonsterEntity) \ and entity.dead \ and self.game_map.get_monster_at(entity.x, entity.y) is not None: continue tcod.console_set_default_foreground(self.field_console, entity.get_color()) tcod.console_put_char(self.field_console, entity.x + dx, entity.y + dy, entity.get_char(), tcod.BKGND_NONE) tcod.console_blit(self.field_console, 0, 0, field_console_width, field_console_height, 0, 0, 0) self.render_stats() self.render_log()
def build_initial_map(self, build_data): # starting point x, y = build_data.map.width // 2, build_data.map.height // 2 start_idx = build_data.map.xy_idx(x, y) build_data.take_snapshot() build_data.map.tiles[start_idx] = TileType.FLOOR build_data.map.tiles[start_idx - 1] = TileType.FLOOR build_data.map.tiles[start_idx + 1] = TileType.FLOOR build_data.map.tiles[start_idx - build_data.map.width] = TileType.FLOOR build_data.map.tiles[start_idx + build_data.map.width] = TileType.FLOOR build_data.take_snapshot() # random walker total_tiles = build_data.map.width * build_data.map.height desired_floor_tiles = int(self.floor_percent * total_tiles) floor_tile_count = build_data.map.tiles.count(TileType.FLOOR) while floor_tile_count < desired_floor_tiles: if self.algorithm == DLAAlgorithm.WALK_INWARDS: digger_x = randint(1, build_data.map.width - 3) + 1 digger_y = randint(1, build_data.map.height - 3) + 1 digger_idx = build_data.map.xy_idx(digger_x, digger_y) prev_x = digger_x prev_y = digger_y while build_data.map.tiles[digger_idx] == TileType.WALL: prev_x = digger_x prev_y = digger_y stagger_direction = randint(1, 4) if stagger_direction == 1 and digger_x > 2: digger_x -= 1 elif stagger_direction == 2 and digger_x < build_data.map.width - 2: digger_x += 1 elif stagger_direction == 3 and digger_y > 2: digger_y -= 1 elif stagger_direction == 4 and digger_y < build_data.map.height - 2: digger_y += 1 digger_idx = build_data.map.xy_idx(digger_x, digger_y) paint(prev_x, prev_y, build_data.map, self.symmetry, self.brush_size) elif self.algorithm == DLAAlgorithm.WALK_OUTWARDS: digger_x = x digger_y = y digger_idx = build_data.map.xy_idx(digger_x, digger_y) while build_data.map.tiles[digger_idx] == TileType.FLOOR: stagger_direction = randint(1, 4) if stagger_direction == 1 and digger_x > 2: digger_x -= 1 elif stagger_direction == 2 and digger_x < build_data.map.width - 2: digger_x += 1 elif stagger_direction == 3 and digger_y > 2: digger_y -= 1 elif stagger_direction == 4 and digger_y < build_data.map.height - 2: digger_y += 1 digger_idx = build_data.map.xy_idx(digger_x, digger_y) paint(digger_x, digger_y, build_data.map, self.symmetry, self.brush_size) elif self.algorithm == DLAAlgorithm.CENTRAL_ATTRACTOR: digger_x = randint(1, build_data.map.width - 3) + 1 digger_y = randint(1, build_data.map.height - 3) + 1 digger_idx = build_data.map.xy_idx(digger_x, digger_y) prev_x = digger_x prev_y = digger_y where = tcod.line_where(digger_x, digger_y, x, y, inclusive=False) count = 0 while build_data.map.tiles[ digger_idx] == TileType.WALL and where: prev_x = digger_x prev_y = digger_y digger_x = where[0][count] digger_y = where[1][count] digger_idx = build_data.map.xy_idx(digger_x, digger_y) count += 1 paint(prev_x, prev_y, build_data.map, self.symmetry, self.brush_size) else: print(f'Algorithm {self.algorithm} not implemented.') raise NotImplementedError floor_tile_count = build_data.map.tiles.count(TileType.FLOOR) if randint(0, 10) == 1: build_data.take_snapshot()