def test_astar_callback(map_, path_callback): astar = libtcodpy.path_new_using_function( libtcodpy.map_get_width(map_), libtcodpy.map_get_height(map_), path_callback, ) libtcodpy.path_compute(astar, *POINTS_AB) libtcodpy.path_delete(astar)
def generate_map(level): arr = array(MAP_W, MAP_H, lambda: ' ') rooms = [] for i in range(500): w, h = randrange(5,15), randrange(5,10) room = try_put_room(arr, w, h) if room: rooms.append(room) #randomly_place(arr, '<') if level < MAX_DLEVEL: randomly_place(arr, '>') costs = [(5, 40, 1), (5, 1, 2), (5, 40, 40)][3*level//(MAX_DLEVEL+1)] def corridor_path_func(x1, y1, x2, y2, data): if x2 == 0 or x2 == MAP_W-1 or y2 == 0 or y2 == MAP_H-1: return 0 c = arr[x2][y2] if c == ' ': return costs[0] elif c == '#': return costs[1] else: return costs[2] path = T.path_new_using_function( MAP_W, MAP_H, corridor_path_func, None, 0.0) def connect(x1, y1, x2, y2): T.path_compute(path, x1, y1, x2, y2) for i in range(T.path_size(path)): x, y = T.path_get(path, i) c = arr[x][y] if c == '#' or c == ' ': arr[x][y] = '.' for i in range(len(rooms)-1): x1, y1, w1, h1 = rooms[i] x2, y2, w2, h2 = rooms[i+1] connect(x1+w1//2, y1+h1//2, x2+w2//2, y2+h2//2) #print_array(arr) T.path_delete(path) return array_to_tiles(arr)
def move_astar(self, target, entities, game_map): #create FOV map with dimensions of map fov = libtcod.map_new(game_map.width, game_map.height) #scan for and mark walls as blocked for y1 in range(game_map.height): for x1 in range(game_map.width): libtcod.map_set_properties( fov, x1, y1, not game_map.tiles[x1][y1].block_sight, not game_map.tiles[x1][y1].blocked) #scan all obj to see if they must be navigated around #also check obj isn't self or target #AI class handles case if self adj to target for entity in entities: if entity.blocks and entity != self and entity != target: #set tile as wall, so will be moved around libtcod.map_set_properties(fov, entity.x, entity.y, True, False) #Allocate A* path # 1.41 is normal cost of diagonal, 0.0 if prohib my_path = libtcod.path_new_using_map(fov, 1.41) #compute path from self to target libtcod.path_compute(my_path, self.x, self.y, target.x, target.y) #check if path eists, and < 25 tiles #path size matters if alt longer paths wanted if not libtcod.path_is_empty( my_path) and libtcod.path_size(my_path) < 25: x, y, = libtcod.path_walk(my_path, True) if x or y: #set self coord to next tile on path self.x = x self.y = y else: #normal move as fallback self.move_towards(target.x, target.y, game_map, entities) #delete path to free memory libtcod.path_delete(my_path)
def move_astar(self, target, entities, game_map): # Create a FOV map that has the dimensions of the map fov = initialize_fov(game_map) for entity in entities: if entity.blocks and entity != self and entity != target: # Set the tile as a wall so it must be navigated around tcod.map_set_properties(fov, entity.x, entity.y, True, False) my_path = tcod.path_new_using_map(fov, 1) tcod.path_compute(my_path, self.x, self.y, target.x, target.y) if not tcod.path_is_empty(my_path) and tcod.path_size(my_path) < 25: # Find the next coordinates in the computed full path x, y = tcod.path_walk(my_path, True) if x or y: # Set self's coordinates to the next path tile self.x = x self.y = y else: self.move_towards(target.x, target.y, game_map, entities) tcod.path_delete(my_path)
def move_astar(self, target, entities, game_map): # Create a FOV map that has the dimensions of the map fov = tcod.map_new(game_map.width, game_map.height) # Scan the current map each turn and set all the walls as unwalkable for y1 in range(game_map.height): for x1 in range(game_map.width): tcod.map_set_properties(fov, x1, y1, not game_map.tiles[x1][y1].block_sight, not game_map.tiles[x1][y1].blocked) # Scan all the objects to see if there are objects that must be navigated around # Check also that the object isn't self or the target (so that the start and the end points are free) # The AI class handles the situation if self is next to the target so it will not use this A* function anyway for entity in entities: if entity.blocks and entity != self and entity != target: # Set the tile as a wall so it must be navigated around tcod.map_set_properties(fov, entity.x, entity.y, True, False) # Allocate a A* path # The 1.41 is the normal diagonal cost of moving, it can be set as 0.0 if diagonal moves are prohibited my_path = tcod.path_new_using_map(fov, 1.41) # Compute the path between self's coordinates and the target's coordinates tcod.path_compute(my_path, self.x, self.y, target.x, target.y) # Check if the path exists, and in this case, also the path is shorter than 25 tiles # The path size matters if you want the monster to use alternative longer paths (for example through other rooms) if for example the player is in a corridor # It makes sense to keep path size relatively low to keep the monsters from running around the map if there's an alternative path really far away if not tcod.path_is_empty(my_path) and tcod.path_size(my_path) < 25: # Find the next coordinates in the computed full path x, y = tcod.path_walk(my_path, True) if x or y: # Set self's coordinates to the next path tile self.x = x self.y = y else: # Keep the old move function as a backup so that if there are no paths (for example another monster blocks a corridor) # it will still try to move towards the player (closer to the corridor opening) self.move_towards(target.x, target.y, game_map, entities) # Delete the path to free memory tcod.path_delete(my_path)
def move_astar(self, target, entities, game_map): # Create FOV map with dimensions of game map fov = libtcod.map_new(game_map.width, game_map.height) # Scan current map each turn and set all the walls as unwalkable for y1 in range(game_map.height): for x1 in range(game_map.width): libtcod.map_set_properties( fov, x1, y1, not game_map.tiles[x1][y1].block_sight, not game_map.tiles[x1][y1].blocked) # Scan all the objects to see if there are objects that must be navigated around # Check also that the object isn't self or target (so start and end points are free # AI class handles case where self is next to target so no need to worry about that case for entity in entities: if entity != self and entity != target and entity.blocks: libtcod.map_set_properties(fov, entity.x, entity.y, True, False) # Allocate A* path my_path = libtcod.path_new_using_map(fov, 1.41) # Compute path between self and target libtcod.path_compute(my_path, self.x, self.y, target.x, target.y) # Check if path exists, and if the path is shorter than 25 tiles # Makes sense to keep path size low to prevent monsters running around the map if there's an # alternate path far away if not libtcod.path_is_empty( my_path) and libtcod.path_size(my_path) < 25: # Find next coordinates in the path x, y = libtcod.path_walk(my_path, True) if x or y: # Update coordinates to next tile self.x = x self.y = y else: # Kept as backup so that if there are no paths, it will still try to move towards the player self.move_towards(target.x, target.y, game_map, entities) # free memory libtcod.path_delete(my_path)
def find_path(source, target, entities, game_map): # Create a FOV map that has the dimensions of the map fov = tcod.map_new(game_map.width, game_map.height) # Scan the current map each turn and set all the walls as unwalkable for y1 in range(game_map.height): for x1 in range(game_map.width): tcod.map_set_properties( fov, x1, y1, not game_map.tiles[x1][y1].block_sight, not game_map.tiles[x1][y1].blocked, ) # Scan all the objects to see if there are objects that must be navigated around # Check also that the object isn't self or the target (so that the start and the end points are free) # The AI class handles the situation if self is next to the target so it will not use this A* function anyway for entity in entities: if entity.blocks and entity != source and entity != target: # Set the tile as a wall so it must be navigated around tcod.map_set_properties(fov, entity.pos.x, entity.pos.y, True, False) # Allocate a A* path # The 1.41 is the normal diagonal cost of moving, it can be set as 0.0 if diagonal moves are prohibited my_path = tcod.path_new_using_map(fov, 0.0) # Compute the path between self's coordinates and the target's coordinates tcod.path_compute(my_path, source.pos.x, source.pos.y, target.pos.x, target.pos.y) # Check if the path exists, and in this case, also the path is shorter than 25 tiles # The path size matters if you want the monster to use alternative longer paths (for example through other # rooms) if for example the player is in a corridor. It makes sense to keep path size relatively low to keep # the monsters from running around the map if there's an alternative path really far away has_path = not tcod.path_is_empty(my_path) and tcod.path_size(my_path) < 25 # Delete the path to free memory tcod.path_delete(my_path) return has_path
def move_astar(self, target, entities, game_map): # Create a FOV map that has the dimensions of the map fov = libtcod.map_new(game_map.width, game_map.height) # Scan the current map each turn and set all the walls as unwalkable for y1 in range(game_map.height): for x1 in range(game_map.width): libtcod.map_set_properties( fov, x1, y1, not game_map.tiles[x1][y1].block_sight, not game_map.tiles[x1][y1].blocked) # Scan all the objects to see if there are objects that must be navigated around # Check also that the object isn't self or the target (so that the start and the end points are free) # The AI class handles the situation if self is next to the target so it will not use this A* function anyway for entity in entities: if entity.blocks and entity != self and entity != target: # Set the tile as a wall so it must be navigated around libtcod.map_set_properties(fov, entity.x, entity.y, True, False) # Allocate a A* path my_path = libtcod.path_new_using_map(fov, 1.41) # Compute the path between self's coordinates and the target's coordinates libtcod.path_compute(my_path, self.x, self.y, target.x, target.y) # Check if the path exists, and in this case, also the path is shorter than 25 tiles if not libtcod.path_is_empty( my_path) and libtcod.path_size(my_path) < 25: # Find the next coordinates in the computed full path x, y = libtcod.path_walk(my_path, True) if x or y: # Set self's coordinates to the next path tile self.x = x self.y = y else: # Keep the old move function as a backup (for example another monster blocks a corridor) # it will still try to move towards the player (closer to the corridor opening) self.move_towards(target.x, target.y, game_map, entities) # Delete the path to free memory libtcod.path_delete(my_path)
def move_astar(self, target, entities, game_map): fov = tcod.map_new(game_map.width, game_map.height) for y1 in range(game_map.height): for x1 in range(game_map.width): tcod.map_set_properties(fov, x1, y1, not game_map.tiles[x1][y1].block_sight, not game_map.tiles[x1][y1].blocked) for entity in entities: if entity.blocks and entity != self and entity != target: tcod.map_set_properties(fov, entity.x, entity.y, True, False) my_path = tcod.path_new_using_map(fov, 1.41) tcod.path_compute(my_path, self.x, self.y, target.x, target.y) if not tcod.path_is_empty(my_path) and tcod.path_size(my_path) < 25: x, y = tcod.path_walk(my_path, True) if x or y: self.x = x self.y = y else: self.move_towards(target.x, target.y, game_map, entities) tcod.path_delete(my_path)
def move_astar(self, target, entities, game_map): # Create a FOV map that has the dimensions of the map fov = libtcod.map_new(game_map.width, game_map.height) # Scan the current map each turn and set all walls as unwalkable for y1 in range(game_map.height): for x1 in range(game_map.width): libtcod.map_set_properties(fov, x1, y1, not game_map.tiles[x1][y1].block_sight, not game_map.tiles[x1][y1].blocked) # Scan all objects to see if there are objects that must be navigated around # Check also that object itself isn't self or target (so start and end points are free) # AI class handles situation if self is next to target so it will not use thia A* function anyway for entity in entities: if entity.blocks and entity != self and entity !=target: # Set the tile as wall so must be nav'd around libtcod.map_set_properties(fov, entity.x, entity.y, True, False) # Allocate a A* path # The 1.41 is the normal diagonal cost of moving, it can be set as 0.0 if diagonal moves are prohib'd my_path = libtcod.path_new_using_map(fov, 1.41) # Compute the path between self and target's coords libtcod.path_compute(my_path, self.x, self.y, target.x, target.y) # Check if path exists, and in this case if < 25 tiles # Path size matters if you want the monster to use alternative longer paths (eg through other rooms) if eg the player is in a corridor # Makes sense to keep path size low to keep monsters from taking far away alternative if not libtcod.path_is_empty(my_path) and libtcod.path_size(my_path) < 25: # Find next coords in computed full path x, y = libtcod.path_walk(my_path, True) if x or y: # Set self's coords to next path tile self.x = x self.y = y else: # Keep old move function as backup for when no paths exist (eg player blocks corridor) self.move_towards(target.x, target.y, game_map, entities) # Delete path to free mem libtcod.path_delete(my_path)
def move_astar(self, target, entities, game_map): fov = game_map.new_fov_map() for entity in entities: if entity.blocks and entity != self and entity != target: libtcod.map_set_properties(fov, entity.x, entity.y, True, False) my_path = libtcod.path_new_using_map(fov, 1.41) libtcod.path_compute(my_path, self.x, self.y, target.x, target.y) if not libtcod.path_is_empty(my_path) and libtcod.path_size(my_path) < 25: x, y = libtcod.path_walk(my_path, True) if x or y: self.x = x self.y = y else: self.move_towards(target.x, target.y, game_map, entities) libtcod.path_delete(my_path)
def move_astar(self, target, entities, game_map): """ Utilise l'algorithme de recherche de chemin A* pour le déplacement d'un monstre en direction du joueur. Est appelé dans ai.BasicMonster Parametres: ---------- target : Entity entities : list game_map : GameMap Renvoi: ------- Aucun """ fov = libtcod.map_new(game_map.width, game_map.height) for y1 in range(game_map.height): for x1 in range(game_map.width): libtcod.map_set_properties( fov, x1, y1, not game_map.tiles[x1][y1].block_sight, not game_map.tiles[x1][y1].blocked) for entity in entities: if entity.blocks and entity != self and entity != target: libtcod.map_set_properties(fov, entity.x, entity.y, True, False) my_path = libtcod.path_new_using_map(fov, 1.41) libtcod.path_compute(my_path, self.x, self.y, target.x, target.y) if not libtcod.path_is_empty( my_path) and libtcod.path_size(my_path) < 25: x, y = libtcod.path_walk(my_path, True) if x or y: self.x = x self.y = y else: self.move_towards(target.x, target.y, game_map, entities) libtcod.path_delete(my_path)
def move_astar(self, target, fov_map, game_map, entities): fov_map_astar = fov_map # Scan all the objects to see if there are objects that must be navigated around # Check also that the object isn't self or the target (so that the start and the end points are free) # The AI class handles the situation if self is next to the target so it will not use this A* function anyway for entity in entities: if entity.blocks and entity != self and entity != target: # Set the tile as a wall so it must be navigated around libtcod.map_set_properties(fov_map_astar, entity.x, entity.y, True, False) # Allocate a A* path my_path = libtcod.path_new_using_map(fov_map_astar, 1.4) # Compute the path between self's coordinates and the target's coordinates libtcod.path_compute(my_path, self.x, self.y, target.x, target.y) # Check if the path exists, and in this case, also the path is shorter than 25 tiles # The path size matters if you want the monster to use alternative longer paths # (for example through other rooms) if for example the player is in a corridor # It makes sense to keep path size relatively low to keep the monsters from running # around the map if there's an alternative path really far away if not libtcod.path_is_empty( my_path) and libtcod.path_size(my_path) < 10: # Find the next coordinates in the computed full path x, y = libtcod.path_walk(my_path, True) if x or y: # Set self's coordinates to the next path tile self.x = x self.y = y else: # Keep the old move function as a backup so that if there are no paths # (for example another monster blocks a corridor). It will still try # to move towards the player (closer to the corridor opening) self.move_towards(target, game_map, entities) # Delete the path to free memory libtcod.path_delete(my_path)
def move_astar(self, target, entities, game_map): # Create a FOV map that has the dimensions of the map fov = libtcod.map_new(game_map.width, game_map.height) # Scan the current map and set all the walls as unwalkable for y1 in range(game_map.height): for x1 in range(game_map.width): libtcod.map_set_properties(fov, x1, y1, not game_map.tiles[x1][y1].block_sight, not game_map.tiles[x1][y1].blocked) # Scan all the objects to see if there are objects that must be navigated around # Check also that the object isnt self or the target (so that the start and end points are free) # The AI class handles the situation if self is next to the target so it will not use this A* function anyway for entity in entities: if entity.blocks and entity != self and entity != target: # Set the tile as a wall so that it must be navigated around libtcod.map_set_properties(fov, entity.x, entity.y, True, False) # Allocate a A* path # The 1.41 is the normal diagonal cost of moving, it can be set as 0.0 if diagonal moves are prohibited my_path = libtcod.path_new_using_map(fov, 1.41) # Compute the path between self coords and target coords libtcod.path_compute(my_path, self.x, self.y, target.x, target.y) # Check path Exists, then also make sure the path is shorter than 25 tiles # Path size matters if you want the monster to use alternative longer paths # It makes sense to keep path size low here if not libtcod.path_is_empty(my_path) and libtcod.path_size(my_path) < 25: # Find the next coordinates in the computed path x, y = libtcod.path_walk(my_path, True) if x or y: # Set self's coords to the next path tile self.x = x self.y = y else: # Keep the old move function as a backup if there are no paths # It will still try to move towards the player self.move_towards(target.x, target.y, game_map, entities) libtcod.path_delete(my_path)
def move_astar(self, target, entities, game_map): # Create another FOV map fov = libtcod.map_new(game_map.width, game_map.height) # Scan the map and set walls as blocked for y1 in range(game_map.height): for x1 in range(game_map.width): libtcod.map_set_properties( fov, x1, y1, not game_map.tiles[x1][y1].block_sight, not game_map.tiles[x1][y1].blocked) # Scan for entities to path around for entity in entities: if entity.blocks and entity != self and entity != target: libtcod.map_set_properties(fov, entity.x, entity.y, True, False) # Allocate a A* path # NOTE: The diagonal movement cost is defined here, might want to put in a config somewhere my_path = libtcod.path_new_using_map(fov, 1.41) # Compute the path libtcod.path_compute(my_path, self.x, self.y, target.x, target.y) # If the path exists and is not too long, walk along if not libtcod.path_is_empty( my_path) and libtcod.path_size(my_path) < 25: x, y = libtcod.path_walk(my_path, True) if x or y: self.x = x self.y = y # Use dumber pathfinding to just get closer if there is no complete path else: self.move_towards(target.x, target.y, game_map, entities) # Deallocate path libtcod.path_delete(my_path)
def move_astar(self, target, entities, game_map): # Create FOV map that has the deminision of the map fov = libtcod.map_new(game_map.width, game_map.height) # Scan the current map each turn and set all the walls as unwalkable for y1 in range(game_map.height): for x1 in range(game_map.width): libtcod.map_set_properties( fov, x1, y1, not game_map.tiles[x1][y1].block_sight, not game_map.tiles[x1][y1].blocked) # Scan all the objects to see if there are objects that must be navigated around # Check also that the object isn't self or the target (so that the start and the end points are free) # The AI class handles the situation if self is next to the target so it will not use this A* function anyway for entity in entities: if entity.blocks and entity != self and entity != target: libtcod.map_set_properties(fov, entity.x, entity.y, True, False) # Allocate a A* path # The 1.41 is the normal diagonal cost of moving my_path = libtcod.path_new_using_map(fov, 1.41) # Compute the path between self's coordinates and the target's coordinates libtcod.path_compute(my_path, int(self.x), int(self.y), int(target.x), int(target.y)) if not libtcod.path_is_empty( my_path) and libtcod.path_size(my_path) < 25: x, y = libtcod.path_walk(my_path, True) if x or y: self.x = x self.y = y else: # Keep the old move function as a backup, if there are no paths self.move_towards(target.x, target.y, game_map, entities) libtcod.path_delete(my_path)
def test_astar(map_): astar = libtcodpy.path_new_using_map(map_) assert not libtcodpy.path_compute(astar, *POINTS_AC) assert libtcodpy.path_size(astar) == 0 assert libtcodpy.path_compute(astar, *POINTS_AB) assert libtcodpy.path_get_origin(astar) == POINT_A assert libtcodpy.path_get_destination(astar) == POINT_B libtcodpy.path_reverse(astar) assert libtcodpy.path_get_origin(astar) == POINT_B assert libtcodpy.path_get_destination(astar) == POINT_A assert libtcodpy.path_size(astar) != 0 assert libtcodpy.path_size(astar) > 0 assert not libtcodpy.path_is_empty(astar) for i in range(libtcodpy.path_size(astar)): x, y = libtcodpy.path_get(astar, i) while (x, y) != (None, None): x, y = libtcodpy.path_walk(astar, False) libtcodpy.path_delete(astar)
def move_astar( self, target, game_map, entities, ): map_copy = deepcopy(game_map) for entity in entities: if entity.blocks and entity != self and entity != target: map_copy.walkable[entity.x][entity.y] = False astar = tcod.path.AStar(map_copy.walkable) new_path = astar.get_path(self.x, self.y, target.x, target.y) if new_path and len(new_path) < 25: x, y = new_path[0] if x or y: self.x = x self.y = y else: self.move_towards(target.x, target.y, game_map, entities) tcod.path_delete(new_path)
def move_astar(self, target, entities, game_map): # Create a FOV map that has the dimensions of the map fov = libtcod.map_new(game_map.width, game_map.height) # Scan the current map each turn and set all the walls as un-walkable for y1 in range(game_map.height): for x1 in range(game_map.width): libtcod.map_set_properties( fov, x1, y1, not game_map.tiles[x1][y1].block_sight, not game_map.tiles[x1][y1].blocked) # Scan all the objects to see if there are objects that must be navigated around (and obj != self/target) for entity in entities: if entity.blocks and entity != self and entity != target: libtcod.map_set_properties(fov, entity.x, entity.y, True, False) # Allocate an A* path my_path = libtcod.path_new_using_map(fov, 1.41) # Compute the path between self's coordinates and the target's coordinates libtcod.path_compute(my_path, self.x, self.y, target.x, target.y) # Check if the path exists, and in this case, also the path is shorter than 25 if not libtcod.path_is_empty( my_path) and libtcod.path_size(my_path) < 25: # Find the next coordinates in the computed full path x, y = libtcod.path_walk(my_path, True) if x or y: # Set self's coordinates to the next path tile self.x = x self.y = y else: # Keep the old move function as a backup so that if there are no paths self.move_towards(target.x, target.y, game_map, entities) libtcod.path_delete(my_path)
def Entity_Move(self, Self_X, Self_Y, Target_x, Target_y): # Checks for a number of entities which hold specific tags, (Hostile, Alien, etc) are on the current map. # Uses A* pathing fov = tcod.map_new(MAP_WIDTH, MAP_HEIGHT) for y1 in range(MAP_HEIGHT): for x1 in range(MAP_WIDTH): tcod.map_set_properties(fov, x1, y1, not map[x1][y1].block_sight, not map[x1][y1].blocked) for Entity, (Position, Blocks) in self.world.get_components(Components.Position, Components.Move_Through): if Blocks and not self.world.has_component(Entity, Components.Player): tcod.map_set_properties(fov, Position.X, Position.Y, True, False) My_Path = tcod.path_new_using_map(fov, 1.41) tcod.path_compute(My_Path, Self_X, Self_Y, Target_x, Target_y) if not tcod.path_is_empty(My_Path) and tcod.path_size(My_Path) < 25: x, y = tcod.path_walk(My_Path, True) if x or y: tcod.path_delete(My_Path) return x, y else: tcod.path_delete(My_Path) return Self_X, Self_Y
def path_delete(self, path): libtcod.path_delete(path) # path data functions def path_get_cost_movement(self,xFrom,yFrom,xTo,yTo, data):
def act(self, game_map, player, fov_map=None, has_los=None): dist = self.owner.distance_to(player) if dist < 2: # Attack the player, even if the entity can't see return self.owner.fighter.attack_entity(player.fighter, target_is_player=True) results = {} given_fov_map = fov_map is not None if (self.owner.sight and dist <= self.owner.sight.fov_radius or self.remaining_chase_turns > 0): owner_x = self.owner.x owner_y = self.owner.y player_x = player.x player_y = player.y if given_fov_map: tcod.map_set_properties(fov_map, owner_x, owner_y, True, True) tcod.map_set_properties(fov_map, player_x, player_y, True, True) else: # This second variable is necessary as creating another # variable called fov_map might shadow the parameter rather # than changing its value fov_map = game_map.generate_fov_map_with_entities( [self.owner, player]) if self.clairvoyant: # Clairvoyant entities can always sense the player when they're # nearby has_los = True if has_los is None: self.owner.sight.get_fov(fov_map) has_los = tcod.map_is_in_fov(fov_map, owner_x, owner_y) if has_los: # If the entity can see the player, reset the chase timer self.remaining_chase_turns = self.chase_duration chase = has_los if not has_los and self.remaining_chase_turns > 0: # Entities will continue chasing the player for chase_duration, # even if they don't have line of sight chase = True self.remaining_chase_turns -= 1 if chase: # 1.41 approximates sqrt(2), the cost of a diagonal moves path = tcod.path_new_using_map(fov_map, 1.41) tcod.path_compute(path, owner_x, owner_y, player_x, player_y) if not tcod.path_is_empty(path) and tcod.path_size(path) < 25: x, y = tcod.path_walk(path, True) if x or y: self.owner.move_to(x, y, game_map, face=True) else: dx = player_x - owner_x dy = player_y - owner_y dx = int(round(dx / dist)) dy = int(round(dy / dist)) if game_map.is_tile_open(owner_x + dx, owner_y + dy): self.owner.move(dx, dy, game_map) tcod.path_delete(path) if given_fov_map: tcod.map_set_properties(fov_map, self.owner.x, self.owner.y, True, False) tcod.map_set_properties(fov_map, player.x, player.y, True, False) else: tcod.map_delete(fov_map) else: if given_fov_map: # Remove the entity from the given FOV map tcod.map_set_properties(fov_map, self.owner.x, self.owner.y, True, True) # Wander around aimlessly self.owner.move(randint(-1, 1), randint(-1, 1), game_map) if given_fov_map: # Add the entity to the given FOV map tcod.map_set_properties(fov_map, self.owner.x, self.owner.y, True, False) return results